summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--babeld/babel_interface.c2
-rw-r--r--babeld/babeld.c6
-rw-r--r--babeld/kernel.c8
-rw-r--r--babeld/message.c16
-rw-r--r--babeld/route.c2
-rw-r--r--babeld/util.c9
-rw-r--r--babeld/util.h8
-rw-r--r--bfdd/bfdd_cli.c52
-rw-r--r--bgpd/bgp_attr.c327
-rw-r--r--bgpd/bgp_attr.h13
-rw-r--r--bgpd/bgp_attr_evpn.c15
-rw-r--r--bgpd/bgp_attr_evpn.h1
-rw-r--r--bgpd/bgp_bmp.c38
-rw-r--r--bgpd/bgp_btoa.c2
-rw-r--r--bgpd/bgp_clist.c4
-rw-r--r--bgpd/bgp_community.c7
-rw-r--r--bgpd/bgp_damp.c3
-rw-r--r--bgpd/bgp_debug.c4
-rw-r--r--bgpd/bgp_ecommunity.c63
-rw-r--r--bgpd/bgp_ecommunity.h4
-rw-r--r--bgpd/bgp_evpn.c298
-rw-r--r--bgpd/bgp_evpn_mh.c163
-rw-r--r--bgpd/bgp_evpn_vty.c37
-rw-r--r--bgpd/bgp_flowspec.c2
-rw-r--r--bgpd/bgp_flowspec_util.c44
-rw-r--r--bgpd/bgp_fsm.c31
-rw-r--r--bgpd/bgp_label.c4
-rw-r--r--bgpd/bgp_mac.c9
-rw-r--r--bgpd/bgp_main.c32
-rw-r--r--bgpd/bgp_memory.c2
-rw-r--r--bgpd/bgp_memory.h2
-rw-r--r--bgpd/bgp_mpath.c465
-rw-r--r--bgpd/bgp_mpath.h29
-rw-r--r--bgpd/bgp_mplsvpn.c395
-rw-r--r--bgpd/bgp_mplsvpn.h2
-rw-r--r--bgpd/bgp_network.c9
-rw-r--r--bgpd/bgp_network.h1
-rw-r--r--bgpd/bgp_nexthop.h1
-rw-r--r--bgpd/bgp_nht.c131
-rw-r--r--bgpd/bgp_open.c10
-rw-r--r--bgpd/bgp_packet.c21
-rw-r--r--bgpd/bgp_pbr.c200
-rw-r--r--bgpd/bgp_route.c400
-rw-r--r--bgpd/bgp_route.h38
-rw-r--r--bgpd/bgp_routemap.c33
-rw-r--r--bgpd/bgp_rpki.c83
-rw-r--r--bgpd/bgp_script.h5
-rw-r--r--bgpd/bgp_snmp_bgp4v2.c3
-rw-r--r--bgpd/bgp_updgrp.c11
-rw-r--r--bgpd/bgp_updgrp_packet.c34
-rw-r--r--bgpd/bgp_vty.c162
-rw-r--r--bgpd/bgp_zebra.c575
-rw-r--r--bgpd/bgp_zebra.h7
-rw-r--r--bgpd/bgpd.c213
-rw-r--r--bgpd/bgpd.h32
-rw-r--r--bgpd/rfapi/rfapi_import.c4
-rw-r--r--bgpd/rfapi/rfapi_rib.c2
-rw-r--r--bgpd/rfapi/rfapi_vty.c6
-rw-r--r--bgpd/rfapi/vnc_export_bgp.c46
-rw-r--r--bgpd/rfapi/vnc_import_bgp.c18
-rw-r--r--configure.ac8
-rw-r--r--doc/developer/bgpd.rst1
-rw-r--r--doc/developer/conf.py7
-rw-r--r--doc/developer/mgmtd-dev.rst2
-rw-r--r--doc/developer/northbound/yang-tools.rst4
-rw-r--r--doc/developer/scripting.rst5
-rw-r--r--doc/developer/topotests.rst11
-rw-r--r--doc/developer/workflow.rst59
-rw-r--r--doc/manpages/bfd-options.rst2
-rw-r--r--doc/user/bfd.rst2
-rw-r--r--doc/user/bgp.rst17
-rw-r--r--doc/user/conf.py10
-rw-r--r--doc/user/pim.rst112
-rw-r--r--doc/user/pimv6.rst44
-rw-r--r--doc/user/zebra.rst16
-rw-r--r--isisd/isis_cli.c6
-rw-r--r--isisd/isis_lsp.c17
-rw-r--r--isisd/isis_mt.c14
-rw-r--r--isisd/isis_nb.c1
-rw-r--r--isisd/isis_nb.h2
-rw-r--r--isisd/isis_nb_config.c176
-rw-r--r--isisd/isis_nb_state.c2
-rw-r--r--isisd/isis_spf.c13
-rw-r--r--isisd/isis_sr.c52
-rw-r--r--isisd/isis_srv6.c2
-rw-r--r--isisd/isis_te.c6
-rw-r--r--isisd/isis_tlvs.c827
-rw-r--r--isisd/isis_tlvs.h1
-rw-r--r--lib/bfd.h6
-rw-r--r--lib/command.c6
-rw-r--r--lib/command.h6
-rw-r--r--lib/debug.c63
-rw-r--r--lib/debug.h49
-rw-r--r--lib/elf_py.c2
-rw-r--r--lib/frrlua.c85
-rw-r--r--lib/frrlua.h3
-rw-r--r--lib/frrscript.c3
-rw-r--r--lib/grammar_sandbox_main.c2
-rw-r--r--lib/hash.c2
-rw-r--r--lib/libfrr.c25
-rw-r--r--lib/libfrr.h5
-rw-r--r--lib/log.c1
-rw-r--r--lib/memory.c1
-rw-r--r--lib/memory.h1
-rw-r--r--lib/mgmt_be_client.c32
-rw-r--r--lib/mgmt_be_client.h5
-rw-r--r--lib/mgmt_fe_client.c30
-rw-r--r--lib/mgmt_fe_client.h5
-rw-r--r--lib/mgmt_msg_native.h11
-rw-r--r--lib/nexthop.c39
-rw-r--r--lib/nexthop.h4
-rw-r--r--lib/nexthop_group.c21
-rw-r--r--lib/nexthop_group.h5
-rw-r--r--lib/northbound.c40
-rw-r--r--lib/northbound.h21
-rw-r--r--lib/northbound_cli.c106
-rw-r--r--lib/northbound_oper.c48
-rw-r--r--lib/northbound_sysrepo.c26
-rw-r--r--lib/routemap_cli.c2
-rw-r--r--lib/srv6.h15
-rw-r--r--lib/termtable.c2
-rw-r--r--lib/termtable.h2
-rw-r--r--lib/vty.c30
-rw-r--r--lib/vty.h7
-rw-r--r--lib/yang.c16
-rw-r--r--lib/yang.h13
-rw-r--r--lib/yang_translator.c4
-rw-r--r--lib/zclient.h1
-rw-r--r--mgmtd/mgmt.c16
-rw-r--r--mgmtd/mgmt_be_adapter.c4
-rw-r--r--mgmtd/mgmt_fe_adapter.c66
-rw-r--r--mgmtd/mgmt_fe_adapter.h12
-rw-r--r--mgmtd/mgmt_main.c2
-rw-r--r--mgmtd/mgmt_txn.c22
-rw-r--r--mgmtd/mgmt_txn.h28
-rw-r--r--mgmtd/mgmt_vty.c42
-rw-r--r--nhrpd/nhrp_peer.c6
-rw-r--r--nhrpd/nhrp_route.c4
-rw-r--r--nhrpd/nhrp_shortcut.c94
-rw-r--r--nhrpd/nhrp_vty.c11
-rw-r--r--nhrpd/nhrpd.h7
-rw-r--r--ospf6d/ospf6_abr.c25
-rw-r--r--ospf6d/ospf6_abr.h16
-rw-r--r--ospf6d/ospf6_asbr.c27
-rw-r--r--ospf6d/ospf6_asbr.h11
-rw-r--r--ospf6d/ospf6_flood.c1
-rw-r--r--ospf6d/ospf6_gr.c13
-rw-r--r--ospf6d/ospf6_gr.h53
-rw-r--r--ospf6d/ospf6_gr_helper.c31
-rw-r--r--ospf6d/ospf6_interface.c3
-rw-r--r--ospf6d/ospf6_intra.c260
-rw-r--r--ospf6d/ospf6_intra.h76
-rw-r--r--ospf6d/ospf6_lsa.c83
-rw-r--r--ospf6d/ospf6_lsa.h102
-rw-r--r--ospf6d/ospf6_lsdb.c3
-rw-r--r--ospf6d/ospf6_message.c12
-rw-r--r--ospf6d/ospf6_neighbor.c1
-rw-r--r--ospf6d/ospf6_nssa.c21
-rw-r--r--ospf6d/ospf6_proto.h5
-rw-r--r--ospf6d/ospf6_snmp.c4
-rw-r--r--ospf6d/ospf6_spf.c8
-rw-r--r--ospf6d/ospf6_tlv.h55
-rw-r--r--ospf6d/ospf6_top.c1
-rw-r--r--ospf6d/ospf6_zebra.c1
-rw-r--r--ospf6d/ospf6d.c1
-rw-r--r--ospf6d/subdir.am1
-rw-r--r--ospfclient/subdir.am3
-rw-r--r--ospfd/ospf_abr.c9
-rw-r--r--ospfd/ospf_asbr.c5
-rw-r--r--ospfd/ospf_flood.c26
-rw-r--r--ospfd/ospf_packet.c18
-rw-r--r--ospfd/ospf_ri.c11
-rw-r--r--ospfd/ospf_sr.c3
-rw-r--r--ospfd/ospf_vty.c16
-rw-r--r--ospfd/ospf_zebra.c188
-rw-r--r--ospfd/ospfd.c9
-rw-r--r--pathd/path_cli.c34
-rw-r--r--pathd/path_pcep.c7
-rw-r--r--pathd/path_pcep.h35
-rw-r--r--pathd/path_pcep_cli.c118
-rw-r--r--pathd/path_ted.c42
-rw-r--r--pathd/path_ted.h24
-rw-r--r--pathd/pathd.c18
-rw-r--r--pathd/pathd.h3
-rw-r--r--pbrd/pbr_debug.c55
-rw-r--r--pbrd/pbr_debug.h22
-rw-r--r--pbrd/pbr_vty.c27
-rw-r--r--pimd/pim6_cmd.c229
-rw-r--r--pimd/pim6_main.c1
-rw-r--r--pimd/pim6_mld.c12
-rw-r--r--pimd/pim_autorp.c1163
-rw-r--r--pimd/pim_autorp.h158
-rw-r--r--pimd/pim_bsm.c870
-rw-r--r--pimd/pim_bsm.h187
-rw-r--r--pimd/pim_bsr_rpdb.c634
-rw-r--r--pimd/pim_cmd.c683
-rw-r--r--pimd/pim_cmd.h1
-rw-r--r--pimd/pim_cmd_common.c376
-rw-r--r--pimd/pim_cmd_common.h25
-rw-r--r--pimd/pim_iface.c373
-rw-r--r--pimd/pim_iface.h13
-rw-r--r--pimd/pim_igmp.c8
-rw-r--r--pimd/pim_igmp.h9
-rw-r--r--pimd/pim_instance.c9
-rw-r--r--pimd/pim_instance.h3
-rw-r--r--pimd/pim_main.c1
-rw-r--r--pimd/pim_memory.c1
-rw-r--r--pimd/pim_memory.h1
-rw-r--r--pimd/pim_msg.h2
-rw-r--r--pimd/pim_nb.c169
-rw-r--r--pimd/pim_nb.h79
-rw-r--r--pimd/pim_nb_config.c909
-rw-r--r--pimd/pim_nht.c8
-rw-r--r--pimd/pim_pim.c97
-rw-r--r--pimd/pim_pim.h5
-rw-r--r--pimd/pim_rp.c7
-rw-r--r--pimd/pim_rp.h6
-rw-r--r--pimd/pim_sock.c30
-rw-r--r--pimd/pim_sock.h3
-rw-r--r--pimd/pim_tib.c31
-rw-r--r--pimd/pim_tib.h3
-rw-r--r--pimd/pim_tlv.c6
-rw-r--r--pimd/pim_vty.c63
-rw-r--r--pimd/pim_zebra.c9
-rw-r--r--pimd/pimd.h4
-rw-r--r--pimd/subdir.am9
-rw-r--r--staticd/static_debug.c71
-rw-r--r--staticd/static_debug.h16
-rw-r--r--staticd/static_vty.c10
-rw-r--r--tests/bgpd/subdir.am11
-rw-r--r--tests/bgpd/test_mpath.c482
-rw-r--r--tests/bgpd/test_mpath.py10
-rw-r--r--tests/bgpd/test_peer_attr.c4
-rw-r--r--tests/helpers/c/main.c4
-rw-r--r--tests/isisd/test_fuzz_isis_tlv_tests.h.gzbin221814 -> 221875 bytes
-rw-r--r--tests/isisd/test_isis_spf.c2
-rw-r--r--tests/lib/cli/common_cli.c4
-rw-r--r--tests/lib/cli/test_cli.refout.in2
-rw-r--r--tests/lib/cli/test_commands.c4
-rw-r--r--tests/lib/northbound/test_oper_data.c4
-rw-r--r--tests/lib/test_frrlua.c16
-rw-r--r--tests/lib/test_grpc.cpp5
-rw-r--r--tests/lib/test_ttable.c36
-rw-r--r--tests/ospf6d/test_lsdb.c1
-rw-r--r--tests/topotests/all_protocol_startup/r1/ip_nht.ref32
-rw-r--r--tests/topotests/all_protocol_startup/r1/ipv4_routes.ref40
-rw-r--r--tests/topotests/all_protocol_startup/r1/ipv6_nht.ref12
-rw-r--r--tests/topotests/all_protocol_startup/r1/ipv6_routes.ref62
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/h1/zebra.conf4
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/h2/zebra.conf8
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgp_summary.json13
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgp_vrf_ipv6.json116
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgpd.conf32
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe1/ipv6_routes_vrf.json142
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe1/isisd.conf23
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe1/zebra.conf11
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgp_summary.json13
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgp_vrf_ipv6.json116
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgpd.conf31
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/pe2/zebra.conf15
-rw-r--r--tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py178
-rw-r--r--tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py289
-rw-r--r--tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py11
-rw-r--r--tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py137
-rw-r--r--tests/topotests/bgp_default_originate/test_default_orginate_vrf.py8
-rw-r--r--tests/topotests/bgp_dual_as/__init__.py (renamed from tests/topotests/bgp_6vpe_ebgp_topo1/__init__.py)0
-rw-r--r--tests/topotests/bgp_dual_as/r1/frr.conf11
-rw-r--r--tests/topotests/bgp_dual_as/r2/frr.conf10
-rw-r--r--tests/topotests/bgp_dual_as/test_bgp_dual_as.py92
-rw-r--r--tests/topotests/bgp_features/r1/ip_route.json8
-rw-r--r--tests/topotests/bgp_features/r1/ip_route_norib.json8
-rwxr-xr-xtests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py6
-rw-r--r--tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json4
-rw-r--r--tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json2
-rw-r--r--tests/topotests/bgp_match_peer/__init__.py (renamed from tests/topotests/bgp_nexthop_mp_ipv4_6/__init__.py)0
-rw-r--r--tests/topotests/bgp_match_peer/r1/frr.conf37
-rw-r--r--tests/topotests/bgp_match_peer/r2/frr.conf14
-rw-r--r--tests/topotests/bgp_match_peer/r3/frr.conf14
-rw-r--r--tests/topotests/bgp_match_peer/r4/frr.conf14
-rw-r--r--tests/topotests/bgp_match_peer/test_bgp_match_peer.py88
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf6
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf6
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf6
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json70
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json90
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json90
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf23
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf16
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json46
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json53
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json53
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf11
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf24
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf12
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json46
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json53
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json53
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf11
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf24
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf12
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json46
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json49
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json49
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf13
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf26
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf12
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json46
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json49
-rwxr-xr-xtests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json49
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf13
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf26
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf12
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json46
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json48
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json48
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf17
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf31
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf16
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json46
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json48
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json48
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf21
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf12
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json46
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json48
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json48
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf21
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf12
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json58
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json62
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json62
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf26
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf40
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf21
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf21
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf36
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf8
-rw-r--r--tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py282
-rw-r--r--tests/topotests/bgp_peer_group_solo/__init__.py0
-rw-r--r--tests/topotests/bgp_peer_group_solo/r1/frr.conf21
-rw-r--r--tests/topotests/bgp_peer_group_solo/r2/frr.conf10
-rw-r--r--tests/topotests/bgp_peer_group_solo/r3/frr.conf10
-rw-r--r--tests/topotests/bgp_peer_group_solo/test_bgp_peer_group_solo.py102
-rw-r--r--tests/topotests/bgp_self_prefix/__init__.py0
-rw-r--r--tests/topotests/bgp_self_prefix/r1/frr.conf19
-rw-r--r--tests/topotests/bgp_self_prefix/r2/frr.conf20
-rw-r--r--tests/topotests/bgp_self_prefix/r3/frr.conf20
-rw-r--r--tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py111
-rw-r--r--tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py35
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2_notification/r2/bgpd.conf18
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2_notification/r2/snmpd.conf17
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2_notification/r2/zebra.conf4
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2_notification/rr/bgpd.conf19
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2_notification/rr/zebra.conf4
-rwxr-xr-xtests/topotests/bgp_snmp_bgp4v2_notification/test_bgp_snmp_bgp4v2_notification.py118
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py2
-rw-r--r--tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py8
-rw-r--r--tests/topotests/bgp_vpn_import_nexthop_default_vrf/__init__.py0
-rw-r--r--tests/topotests/bgp_vpn_import_nexthop_default_vrf/r1/frr.conf29
-rw-r--r--tests/topotests/bgp_vpn_import_nexthop_default_vrf/r2/frr.conf34
-rw-r--r--tests/topotests/bgp_vpn_import_nexthop_default_vrf/test_bgp_vpn_import_nexthop_default_vrf.py145
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_init.json6
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r1_vrf1.json6
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf2.json9
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf3.json9
-rw-r--r--tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json7
-rw-r--r--tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json7
-rw-r--r--tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py8
-rwxr-xr-xtests/topotests/conftest.py40
-rw-r--r--tests/topotests/dump_of_bgp/r1/frr.conf12
-rw-r--r--tests/topotests/dump_of_bgp/r2/frr.conf17
-rw-r--r--tests/topotests/dump_of_bgp/test_dump_of_bgp.py102
-rw-r--r--tests/topotests/example_munet/r1/frr.conf2
-rw-r--r--tests/topotests/example_munet/r2/frr.conf4
-rw-r--r--tests/topotests/example_munet/r3/frr.conf2
-rw-r--r--tests/topotests/example_munet/test_munet.py18
-rw-r--r--tests/topotests/forwarding_on_off/r1/frr.conf14
-rw-r--r--tests/topotests/forwarding_on_off/r2/frr.conf19
-rw-r--r--tests/topotests/forwarding_on_off/r3/frr.conf15
-rw-r--r--tests/topotests/forwarding_on_off/test_forwarding_on_off.py104
-rw-r--r--tests/topotests/isis_topo1/test_isis_topo1.py2
-rw-r--r--tests/topotests/kinds.yaml3
-rw-r--r--tests/topotests/lib/common_config.py14
-rwxr-xr-xtests/topotests/lib/grpc-query.py1
-rw-r--r--tests/topotests/lib/pim.py240
-rw-r--r--tests/topotests/lib/topogen.py17
-rw-r--r--tests/topotests/lib/topotest.py18
-rw-r--r--tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json49
-rw-r--r--tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json96
-rw-r--r--tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json48
-rw-r--r--tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json48
-rw-r--r--tests/topotests/mgmt_oper/oper-results/result-lib.json96
-rw-r--r--tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json12
-rw-r--r--tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json48
-rw-r--r--tests/topotests/mgmt_oper/oper.py17
-rw-r--r--tests/topotests/mgmt_oper/r1/frr-yanglib.conf10
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-state-mtu.json1
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-state.json1
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json12
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json24
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json12
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json12
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json12
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-lib.json24
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-ribs-rib-ipv4-unicast.json6
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json12
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-nokey.json6
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-prefix.json3
-rw-r--r--tests/topotests/mgmt_oper/test_simple.py2
-rw-r--r--tests/topotests/mgmt_oper/test_yanglib.py45
-rwxr-xr-xtests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_transit_router_topo3.py64
-rw-r--r--tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json2
-rw-r--r--tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json2
-rw-r--r--tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json2
-rw-r--r--tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json1
-rw-r--r--tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json2
-rw-r--r--tests/topotests/multicast_pim_uplink_topo4/multicast_pim_uplink_topo4.json295
-rw-r--r--tests/topotests/multicast_pim_uplink_topo4/test_multicast_pim_uplink_topo4.py893
-rw-r--r--tests/topotests/munet/cli.py56
-rwxr-xr-xtests/topotests/munet/mutini.py56
-rw-r--r--tests/topotests/munet/native.py8
-rw-r--r--tests/topotests/munet/testing/util.py26
-rw-r--r--tests/topotests/nhrp_redundancy/host/frr.conf4
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/frr.conf25
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_cache.json (renamed from tests/topotests/nhrp_redundancy/r4/nhrp_cache.json)16
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_cache_nhs1_down.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_route.json (renamed from tests/topotests/nhrp_redundancy/r5/nhrp_route.json)18
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_route_nhs1_down.json49
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut.json (renamed from tests/topotests/nhrp_redundancy/r4/nhrp_route_shortcut.json)32
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut_nhs1_down.json96
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_absent.json5
-rw-r--r--tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_present.json9
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/frr.conf25
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/nhrp_cache.json (renamed from tests/topotests/nhrp_redundancy/r5/nhrp_cache.json)16
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/nhrp_cache_nhs1_down.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/nhrp_route.json (renamed from tests/topotests/nhrp_redundancy/r4/nhrp_route.json)18
-rw-r--r--tests/topotests/nhrp_redundancy/nhc2/nhrp_route_nhs1_down.json49
-rw-r--r--tests/topotests/nhrp_redundancy/nhs1/frr.conf19
-rw-r--r--tests/topotests/nhrp_redundancy/nhs1/nhrp_cache.json (renamed from tests/topotests/nhrp_redundancy/r1/nhrp_cache.json)12
-rw-r--r--tests/topotests/nhrp_redundancy/nhs1/nhrp_route.json (renamed from tests/topotests/nhrp_redundancy/r3/nhrp_route.json)12
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/frr.conf19
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/nhrp_cache.json (renamed from tests/topotests/nhrp_redundancy/r2/nhrp_cache.json)12
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/nhrp_cache_nhs1_down.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/nhrp_route.json (renamed from tests/topotests/nhrp_redundancy/r1/nhrp_route.json)12
-rw-r--r--tests/topotests/nhrp_redundancy/nhs2/nhrp_route_nhs1_down.json48
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/frr.conf19
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/nhrp_cache.json (renamed from tests/topotests/nhrp_redundancy/r3/nhrp_cache.json)12
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/nhrp_cache_nhs1_down.json40
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/nhrp_route.json (renamed from tests/topotests/nhrp_redundancy/r2/nhrp_route.json)12
-rw-r--r--tests/topotests/nhrp_redundancy/nhs3/nhrp_route_nhs1_down.json48
-rw-r--r--tests/topotests/nhrp_redundancy/r1/nhrpd.conf9
-rw-r--r--tests/topotests/nhrp_redundancy/r1/zebra.conf12
-rw-r--r--tests/topotests/nhrp_redundancy/r2/nhrpd.conf9
-rw-r--r--tests/topotests/nhrp_redundancy/r2/zebra.conf12
-rw-r--r--tests/topotests/nhrp_redundancy/r3/nhrpd.conf9
-rw-r--r--tests/topotests/nhrp_redundancy/r3/zebra.conf12
-rw-r--r--tests/topotests/nhrp_redundancy/r4/nhrpd.conf11
-rw-r--r--tests/topotests/nhrp_redundancy/r4/zebra.conf16
-rw-r--r--tests/topotests/nhrp_redundancy/r5/nhrpd.conf11
-rw-r--r--tests/topotests/nhrp_redundancy/r5/zebra.conf16
-rw-r--r--tests/topotests/nhrp_redundancy/r7/zebra.conf4
-rw-r--r--tests/topotests/nhrp_redundancy/router/frr.conf (renamed from tests/topotests/nhrp_redundancy/r6/zebra.conf)4
-rw-r--r--tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot38
-rw-r--r--tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py378
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt10
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt8
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt10
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt10
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt8
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt8
-rw-r--r--tests/topotests/ospf_netns_vrf/r1/zebraroute.txt8
-rw-r--r--tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt8
-rw-r--r--tests/topotests/ospf_netns_vrf/r2/zebraroute.txt8
-rw-r--r--tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt8
-rw-r--r--tests/topotests/ospf_netns_vrf/r3/zebraroute.txt8
-rw-r--r--tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt4
-rw-r--r--tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py2
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py65
-rwxr-xr-xtests/topotests/pim_autorp/__init__.py0
-rw-r--r--tests/topotests/pim_autorp/r1/frr.conf16
-rw-r--r--tests/topotests/pim_autorp/r2/frr.conf16
-rw-r--r--tests/topotests/pim_autorp/test_pim_autorp.py341
-rw-r--r--tests/topotests/pim_basic_igmp_proxy/r1/frr.conf29
-rw-r--r--tests/topotests/pim_basic_igmp_proxy/r2/frr.conf19
-rw-r--r--tests/topotests/pim_basic_igmp_proxy/r3/frr.conf8
-rw-r--r--tests/topotests/pim_basic_igmp_proxy/rp/frr.conf16
-rw-r--r--tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py319
-rwxr-xr-xtests/topotests/pim_cand_rp_bsr/__init__.py0
-rw-r--r--tests/topotests/pim_cand_rp_bsr/r1/frr.conf25
-rw-r--r--tests/topotests/pim_cand_rp_bsr/r2/frr.conf22
-rw-r--r--tests/topotests/pim_cand_rp_bsr/r3/frr.conf32
-rw-r--r--tests/topotests/pim_cand_rp_bsr/r4/frr.conf37
-rw-r--r--tests/topotests/pim_cand_rp_bsr/r5/frr.conf17
-rw-r--r--tests/topotests/pim_cand_rp_bsr/r6/frr.conf22
-rw-r--r--tests/topotests/pim_cand_rp_bsr/test_pim_cand_rp_bsr.py324
-rw-r--r--tests/topotests/pytest.ini3
-rw-r--r--tests/topotests/route_scale/scale_test_common.py27
-rw-r--r--tests/topotests/srv6_encap_src_addr/r1/zebra.conf1
-rw-r--r--tests/topotests/srv6_sid_manager/ce1/bgpd.conf8
-rw-r--r--tests/topotests/srv6_sid_manager/ce1/ipv6_rib.json58
-rw-r--r--tests/topotests/srv6_sid_manager/ce1/zebra.conf14
-rw-r--r--tests/topotests/srv6_sid_manager/ce2/bgpd.conf8
-rw-r--r--tests/topotests/srv6_sid_manager/ce2/ipv6_rib.json58
-rw-r--r--tests/topotests/srv6_sid_manager/ce2/zebra.conf14
-rw-r--r--tests/topotests/srv6_sid_manager/ce3/bgpd.conf8
-rw-r--r--tests/topotests/srv6_sid_manager/ce3/ipv6_rib.json58
-rw-r--r--tests/topotests/srv6_sid_manager/ce3/zebra.conf14
-rw-r--r--tests/topotests/srv6_sid_manager/ce4/bgpd.conf8
-rw-r--r--tests/topotests/srv6_sid_manager/ce4/ipv6_rib.json58
-rw-r--r--tests/topotests/srv6_sid_manager/ce4/zebra.conf14
-rw-r--r--tests/topotests/srv6_sid_manager/ce5/bgpd.conf8
-rw-r--r--tests/topotests/srv6_sid_manager/ce5/ipv6_rib.json58
-rw-r--r--tests/topotests/srv6_sid_manager/ce5/zebra.conf14
-rw-r--r--tests/topotests/srv6_sid_manager/ce6/bgpd.conf8
-rw-r--r--tests/topotests/srv6_sid_manager/ce6/ipv6_rib.json58
-rw-r--r--tests/topotests/srv6_sid_manager/ce6/zebra.conf14
-rw-r--r--tests/topotests/srv6_sid_manager/dst/sharpd.conf0
-rw-r--r--tests/topotests/srv6_sid_manager/dst/zebra.conf22
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/bgpd.conf66
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/isisd.conf35
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/sharpd.conf0
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/show_ip_route.ref276
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/show_ipv6_route.ref314
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/show_srv6_locator_table.ref15
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/show_yang_interface_isis_adjacencies.ref32
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/vpnv6_rib.ref169
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/vrf10_rib.ref86
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/vrf20_rib.ref92
-rw-r--r--tests/topotests/srv6_sid_manager/rt1/zebra.conf37
-rw-r--r--tests/topotests/srv6_sid_manager/rt2/isisd.conf48
-rw-r--r--tests/topotests/srv6_sid_manager/rt2/show_ip_route.ref320
-rw-r--r--tests/topotests/srv6_sid_manager/rt2/show_ipv6_route.ref346
-rw-r--r--tests/topotests/srv6_sid_manager/rt2/show_srv6_locator_table.ref15
-rw-r--r--tests/topotests/srv6_sid_manager/rt2/show_yang_interface_isis_adjacencies.ref70
-rw-r--r--tests/topotests/srv6_sid_manager/rt2/zebra.conf34
-rw-r--r--tests/topotests/srv6_sid_manager/rt3/isisd.conf48
-rw-r--r--tests/topotests/srv6_sid_manager/rt3/show_ip_route.ref320
-rw-r--r--tests/topotests/srv6_sid_manager/rt3/show_ipv6_route.ref346
-rw-r--r--tests/topotests/srv6_sid_manager/rt3/show_srv6_locator_table.ref15
-rw-r--r--tests/topotests/srv6_sid_manager/rt3/show_yang_interface_isis_adjacencies.ref70
-rw-r--r--tests/topotests/srv6_sid_manager/rt3/zebra.conf33
-rw-r--r--tests/topotests/srv6_sid_manager/rt4/isisd.conf56
-rw-r--r--tests/topotests/srv6_sid_manager/rt4/show_ip_route.ref296
-rw-r--r--tests/topotests/srv6_sid_manager/rt4/show_ipv6_route.ref346
-rw-r--r--tests/topotests/srv6_sid_manager/rt4/show_srv6_locator_table.ref15
-rw-r--r--tests/topotests/srv6_sid_manager/rt4/show_yang_interface_isis_adjacencies.ref82
-rw-r--r--tests/topotests/srv6_sid_manager/rt4/zebra.conf36
-rw-r--r--tests/topotests/srv6_sid_manager/rt5/isisd.conf56
-rw-r--r--tests/topotests/srv6_sid_manager/rt5/show_ip_route.ref296
-rw-r--r--tests/topotests/srv6_sid_manager/rt5/show_ipv6_route.ref346
-rw-r--r--tests/topotests/srv6_sid_manager/rt5/show_srv6_locator_table.ref15
-rw-r--r--tests/topotests/srv6_sid_manager/rt5/show_yang_interface_isis_adjacencies.ref82
-rw-r--r--tests/topotests/srv6_sid_manager/rt5/zebra.conf36
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/bgpd.conf67
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/isisd.conf42
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/sharpd.conf0
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/show_ip_route.ref273
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/show_ipv6_route.ref312
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/show_srv6_locator_table.ref15
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/show_yang_interface_isis_adjacencies.ref44
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/vpnv6_rib.ref169
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/vrf10_rib.ref92
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/vrf20_rib.ref86
-rw-r--r--tests/topotests/srv6_sid_manager/rt6/zebra.conf45
-rw-r--r--tests/topotests/srv6_sid_manager/test_srv6_sid_manager.py421
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/__init__.py0
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r1/bgpd.conf24
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r1/ospfd.conf.after25
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r1/zebra.conf13
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r2/bgpd.conf23
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r2/isisd.conf25
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r2/ospfd.conf.after32
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r2/zebra.conf16
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r3/bgpd.conf23
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r3/isisd.conf25
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r3/ospfd.conf.after26
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r3/zebra.conf19
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r4/bgpd.conf24
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r4/isisd.conf31
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r4/ospfd.conf19
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r4/zebra.conf16
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r5/bgpd.conf23
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r5/isisd.conf (renamed from tests/topotests/bgp_6vpe_ebgp_topo1/pe2/isisd.conf)16
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r5/ospfd.conf.after26
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r5/zebra.conf19
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r6/ospfd.conf.after32
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r6/zebra.conf22
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r7/bgpd.conf24
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r7/ospfd.conf.after26
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/r7/zebra.conf14
-rw-r--r--tests/topotests/zebra_fec_nexthop_resolution/test_zebra_fec_nexthop_resolution.py259
-rw-r--r--tests/topotests/zebra_multiple_connected/r1/ip_route_connected.json24
-rw-r--r--tests/topotests/zebra_multiple_connected/r1/ip_route_kernel.json24
-rw-r--r--tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py43
-rw-r--r--tests/topotests/zebra_rib/test_zebra_rib.py2
-rw-r--r--tests/topotests/zebra_seg6local_route/r1/routes.json73
-rwxr-xr-xtests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py2
-rwxr-xr-xtools/frr-reload.py31
-rw-r--r--tools/gen_northbound_callbacks.c2
-rw-r--r--tools/gen_yang_deviations.c2
-rw-r--r--tools/subdir.am11
-rw-r--r--vrrpd/vrrp_debug.c88
-rw-r--r--vrrpd/vrrp_debug.h8
-rw-r--r--vrrpd/vrrp_packet.c2
-rw-r--r--vrrpd/vrrp_vty.c14
-rw-r--r--vtysh/vtysh.c17
-rw-r--r--vtysh/vtysh.h2
-rw-r--r--vtysh/vtysh_config.c15
-rw-r--r--yang/frr-bgp-common.yang13
-rw-r--r--yang/frr-bgp-route-map.yang16
-rw-r--r--yang/frr-gmp.yang28
-rw-r--r--yang/frr-pim-candidate.yang174
-rw-r--r--yang/frr-pim-rp.yang71
-rw-r--r--yang/frr-zebra.yang10
-rw-r--r--yang/ietf/ietf-bgp-types.yang2
-rw-r--r--yang/subdir.am1
-rw-r--r--zebra/connected.c1
-rw-r--r--zebra/dplane_fpm_nl.c23
-rw-r--r--zebra/if_ioctl.c2
-rw-r--r--zebra/if_netlink.c214
-rw-r--r--zebra/if_netlink.h3
-rw-r--r--zebra/if_sysctl.c2
-rw-r--r--zebra/interface.c2
-rw-r--r--zebra/kernel_netlink.c15
-rw-r--r--zebra/kernel_netlink.h8
-rw-r--r--zebra/kernel_socket.c2
-rw-r--r--zebra/redistribute.c5
-rw-r--r--zebra/rib.h17
-rw-r--r--zebra/rt_netlink.c12
-rw-r--r--zebra/rtadv.c2
-rw-r--r--zebra/tc_netlink.c40
-rw-r--r--zebra/tc_netlink.h2
-rw-r--r--zebra/zapi_msg.c33
-rw-r--r--zebra/zebra_cli.c38
-rw-r--r--zebra/zebra_dplane.c180
-rw-r--r--zebra/zebra_evpn.c3
-rw-r--r--zebra/zebra_evpn_mac.c857
-rw-r--r--zebra/zebra_gr.c2
-rw-r--r--zebra/zebra_mpls.c134
-rw-r--r--zebra/zebra_mpls.h8
-rw-r--r--zebra/zebra_nb.c7
-rw-r--r--zebra/zebra_nb.h4
-rw-r--r--zebra/zebra_nb_config.c53
-rw-r--r--zebra/zebra_netns_notify.c4
-rw-r--r--zebra/zebra_nhg.c279
-rw-r--r--zebra/zebra_nhg.h24
-rw-r--r--zebra/zebra_rib.c287
-rw-r--r--zebra/zebra_rnh.c12
-rw-r--r--zebra/zebra_router.c2
-rw-r--r--zebra/zebra_snmp.c30
-rw-r--r--zebra/zebra_srv6_vty.c2
-rw-r--r--zebra/zebra_trace.h14
-rw-r--r--zebra/zebra_vrf.h1
-rw-r--r--zebra/zebra_vty.c35
-rw-r--r--zebra/zserv.c14
662 files changed, 25138 insertions, 10271 deletions
diff --git a/.clang-format b/.clang-format
index 7aefafa58f..72018d5a82 100644
--- a/.clang-format
+++ b/.clang-format
@@ -55,7 +55,7 @@ BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
-ColumnLimit: 80
+ColumnLimit: 100
# Linux: CommentPragmas: '^ IWYU pragma:'
CommentPragmas: '\$(FRR|clippy)'
CompactNamespaces: false
diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c
index 943ae9def1..b83c7b1908 100644
--- a/babeld/babel_interface.c
+++ b/babeld/babel_interface.c
@@ -1351,7 +1351,7 @@ babel_interface_allocate (void)
/* All flags are unset */
babel_ifp->bucket_time = babel_now.tv_sec;
babel_ifp->bucket = BUCKET_TOKENS_MAX;
- babel_ifp->hello_seqno = (frr_weak_random() & 0xFFFF);
+ babel_ifp->hello_seqno = CHECK_FLAG(frr_weak_random(), 0xFFFF);
babel_ifp->rtt_decay = BABEL_DEFAULT_RTT_DECAY;
babel_ifp->rtt_min = BABEL_DEFAULT_RTT_MIN;
babel_ifp->rtt_max = BABEL_DEFAULT_RTT_MAX;
diff --git a/babeld/babeld.c b/babeld/babeld.c
index 73deb1dd92..b562f0b70c 100644
--- a/babeld/babeld.c
+++ b/babeld/babeld.c
@@ -204,7 +204,7 @@ static void babel_read_protocol(struct event *thread)
making these inits have sense. */
static void babel_init_routing_process(struct event *thread)
{
- myseqno = (frr_weak_random() & 0xFFFF);
+ myseqno = CHECK_FLAG(frr_weak_random(), 0xFFFF);
babel_get_myid();
babel_load_state_file();
debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
@@ -443,8 +443,8 @@ babel_fill_with_next_timeout(struct timeval *tv)
#if (defined NO_DEBUG)
#define printIfMin(a,b,c,d)
#else
-#define printIfMin(a, b, c, d) \
- if (unlikely(debug & BABEL_DEBUG_TIMEOUT)) { \
+#define printIfMin(a, b, c, d) \
+ if (unlikely(CHECK_FLAG(debug, BABEL_DEBUG_TIMEOUT))) { \
printIfMin(a, b, c, d); \
}
diff --git a/babeld/kernel.c b/babeld/kernel.c
index aed6dc9c4f..4957b04e77 100644
--- a/babeld/kernel.c
+++ b/babeld/kernel.c
@@ -92,13 +92,9 @@ kernel_route(enum babel_kernel_routes operation, const unsigned char *pref,
case ROUTE_MODIFY:
if(newmetric == metric && memcmp(newgate, gate, 16) == 0 &&
newifindex == ifindex)
- return 0;
- debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new.");
- rc = zebra_route(0, family, pref, plen, gate, ifindex, metric);
- if (rc < 0)
- return -1;
+ return 0;
- rc = zebra_route(1, family, pref, plen, newgate, newifindex,
+ rc = zebra_route(1, family, pref, plen, newgate, newifindex,
newmetric);
return rc;
}
diff --git a/babeld/message.c b/babeld/message.c
index 1b83eb9ebb..5a33d5c288 100644
--- a/babeld/message.c
+++ b/babeld/message.c
@@ -324,8 +324,8 @@ parse_request_subtlv(int ae, const unsigned char *a, int alen,
have_src_prefix = 1;
} else {
debugf(BABEL_DEBUG_COMMON,"Received unknown%s Route Request sub-TLV %d.",
- ((type & 0x80) != 0) ? " mandatory" : "", type);
- if((type & 0x80) != 0)
+ (CHECK_FLAG(type, 0x80) != 0) ? " mandatory" : "", type);
+ if(CHECK_FLAG(type, 0x80) != 0)
return -1;
}
@@ -588,7 +588,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
else
rc = -1;
if(rc < 0) {
- if(message[3] & 0x80)
+ if(CHECK_FLAG(message[3], 0x80))
have_v4_prefix = have_v6_prefix = 0;
goto fail;
}
@@ -596,7 +596,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
plen = message[4] + (message[2] == 1 ? 96 : 0);
- if(message[3] & 0x80) {
+ if(CHECK_FLAG(message[3], 0x80)) {
if(message[2] == 1) {
memcpy(v4_prefix, prefix, 16);
have_v4_prefix = 1;
@@ -605,7 +605,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
have_v6_prefix = 1;
}
}
- if(message[3] & 0x40) {
+ if(CHECK_FLAG(message[3], 0x40)) {
if(message[2] == 1) {
memset(router_id, 0, 4);
memcpy(router_id + 4, prefix + 12, 4);
@@ -620,8 +620,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
goto fail;
}
debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.",
- (message[3] & 0x80) ? "/prefix" : "",
- (message[3] & 0x40) ? "/id" : "",
+ ((CHECK_FLAG(message[3], 0x80)) ? "/prefix" : ""),
+ ((CHECK_FLAG(message[3], 0x40)) ? "/id" : ""),
format_prefix(prefix, plen),
format_address(from), ifp->name);
@@ -1059,7 +1059,7 @@ void send_hello_noupdate(struct interface *ifp, unsigned interval)
babel_ifp->hello_seqno, interval, ifp->name);
start_message(ifp, MESSAGE_HELLO,
- (babel_ifp->flags & BABEL_IF_TIMESTAMPS) ? 12 : 6);
+ (CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS) ? 12 : 6));
babel_ifp->buffered_hello = babel_ifp->buffered - 2;
accumulate_short(ifp, 0);
accumulate_short(ifp, babel_ifp->hello_seqno);
diff --git a/babeld/route.c b/babeld/route.c
index 2c7e923748..466f41383c 100644
--- a/babeld/route.c
+++ b/babeld/route.c
@@ -352,7 +352,7 @@ route_stream_done(struct route_stream *stream)
static int
metric_to_kernel(int metric)
{
- return metric < INFINITY ? kernel_metric : KERNEL_INFINITY;
+ return metric < INFINITY ? metric : KERNEL_INFINITY;
}
/* This is used to maintain the invariant that the installed route is at
diff --git a/babeld/util.c b/babeld/util.c
index 4facdabbc6..f5edb0ed1f 100644
--- a/babeld/util.c
+++ b/babeld/util.c
@@ -211,8 +211,8 @@ mask_prefix(unsigned char *restrict ret,
memset(ret, 0, 16);
memcpy(ret, prefix, plen / 8);
if(plen % 8 != 0)
- ret[plen / 8] =
- (prefix[plen / 8] & ((0xFF << (8 - (plen % 8))) & 0xFF));
+ ret[plen / 8] = CHECK_FLAG(prefix[plen / 8],
+ CHECK_FLAG((0xFF << (8 - (plen % 8))), 0xFF));
return ret;
}
@@ -353,12 +353,13 @@ martian_prefix(const unsigned char *prefix, int plen)
{
return
(plen >= 8 && prefix[0] == 0xFF) ||
- (plen >= 10 && prefix[0] == 0xFE && (prefix[1] & 0xC0) == 0x80) ||
+ (plen >= 10 && prefix[0] == 0xFE &&
+ (CHECK_FLAG(prefix[1], 0xC0) == 0x80)) ||
(plen >= 128 && memcmp(prefix, zeroes, 15) == 0 &&
(prefix[15] == 0 || prefix[15] == 1)) ||
(plen >= 96 && v4mapped(prefix) &&
((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) ||
- (plen >= 100 && (prefix[12] & 0xE0) == 0xE0)));
+ (plen >= 100 && CHECK_FLAG(prefix[12], 0xE0) == 0xE0)));
}
int
diff --git a/babeld/util.h b/babeld/util.h
index ddc6a70d43..2242032c4b 100644
--- a/babeld/util.h
+++ b/babeld/util.h
@@ -47,19 +47,19 @@ seqno_compare(unsigned short s1, unsigned short s2)
if(s1 == s2)
return 0;
else
- return ((s2 - s1) & 0x8000) ? 1 : -1;
+ return (CHECK_FLAG((s2 - s1), 0x8000)) ? 1 : -1;
}
static inline short
seqno_minus(unsigned short s1, unsigned short s2)
{
- return (short)((s1 - s2) & 0xFFFF);
+ return (short)(CHECK_FLAG((s1 - s2), 0xFFFF));
}
static inline unsigned short
seqno_plus(unsigned short s, int plus)
{
- return ((s + plus) & 0xFFFF);
+ return CHECK_FLAG((s + plus), 0xFFFF);
}
/* Returns a time in microseconds on 32 bits (thus modulo 2^32,
@@ -130,7 +130,7 @@ is_default(const unsigned char *prefix, int plen)
#define debugf(level, ...) \
do { \
- if (unlikely(debug & level)) \
+ if (unlikely(CHECK_FLAG(debug, level))) \
zlog_debug(__VA_ARGS__); \
} while (0)
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index 75034d220c..2e213a2237 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -338,11 +338,12 @@ void bfd_cli_show_minimum_ttl(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG(
bfd_peer_mult, bfd_peer_mult_cmd,
- "detect-multiplier (2-255)$multiplier",
+ "[no] detect-multiplier ![(2-255)$multiplier]",
+ NO_STR
"Configure peer detection multiplier\n"
"Configure peer detection multiplier value\n")
{
- nb_cli_enqueue_change(vty, "./detection-multiplier", NB_OP_MODIFY,
+ nb_cli_enqueue_change(vty, "./detection-multiplier", no ? NB_OP_DESTROY : NB_OP_MODIFY,
multiplier_str);
return nb_cli_apply_changes(vty, NULL);
}
@@ -356,14 +357,15 @@ void bfd_cli_show_mult(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG(
bfd_peer_rx, bfd_peer_rx_cmd,
- "receive-interval (10-60000)$interval",
+ "[no] receive-interval ![(10-60000)$interval]",
+ NO_STR
"Configure peer receive interval\n"
"Configure peer receive interval value in milliseconds\n")
{
char value[32];
snprintf(value, sizeof(value), "%ld", interval * 1000);
- nb_cli_enqueue_change(vty, "./required-receive-interval", NB_OP_MODIFY,
+ nb_cli_enqueue_change(vty, "./required-receive-interval", no ? NB_OP_DESTROY : NB_OP_MODIFY,
value);
return nb_cli_apply_changes(vty, NULL);
@@ -379,7 +381,8 @@ void bfd_cli_show_rx(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG(
bfd_peer_tx, bfd_peer_tx_cmd,
- "transmit-interval (10-60000)$interval",
+ "[no] transmit-interval ![(10-60000)$interval]",
+ NO_STR
"Configure peer transmit interval\n"
"Configure peer transmit interval value in milliseconds\n")
{
@@ -387,7 +390,7 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./desired-transmission-interval",
- NB_OP_MODIFY, value);
+ no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
}
@@ -436,7 +439,8 @@ void bfd_cli_show_echo(struct vty *vty, const struct lyd_node *dnode,
DEFPY_YANG(
bfd_peer_echo_interval, bfd_peer_echo_interval_cmd,
- "echo-interval (10-60000)$interval",
+ "[no] echo-interval ![(10-60000)$interval]",
+ NO_STR
"Configure peer echo intervals\n"
"Configure peer echo rx/tx intervals value in milliseconds\n")
{
@@ -449,16 +453,17 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
- NB_OP_MODIFY, value);
+ no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
- NB_OP_MODIFY, value);
+ no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
}
DEFPY_YANG(
bfd_peer_echo_transmit_interval, bfd_peer_echo_transmit_interval_cmd,
- "echo transmit-interval (10-60000)$interval",
+ "[no] echo transmit-interval ![(10-60000)$interval]",
+ NO_STR
"Configure peer echo intervals\n"
"Configure desired transmit interval\n"
"Configure interval value in milliseconds\n")
@@ -472,7 +477,7 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "%ld", interval * 1000);
nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
- NB_OP_MODIFY, value);
+ no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
}
@@ -487,7 +492,8 @@ void bfd_cli_show_desired_echo_transmission_interval(
DEFPY_YANG(
bfd_peer_echo_receive_interval, bfd_peer_echo_receive_interval_cmd,
- "echo receive-interval <disabled$disabled|(10-60000)$interval>",
+ "[no] echo receive-interval ![<disabled$disabled|(10-60000)$interval>]",
+ NO_STR
"Configure peer echo intervals\n"
"Configure required receive interval\n"
"Disable echo packets receive\n"
@@ -504,9 +510,9 @@ DEFPY_YANG(
snprintf(value, sizeof(value), "0");
else
snprintf(value, sizeof(value), "%ld", interval * 1000);
-
+
nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
- NB_OP_MODIFY, value);
+ no ? NB_OP_DESTROY : NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
}
@@ -571,17 +577,20 @@ void bfd_cli_show_profile(struct vty *vty, const struct lyd_node *dnode,
}
ALIAS_YANG(bfd_peer_mult, bfd_profile_mult_cmd,
- "detect-multiplier (2-255)$multiplier",
+ "[no] detect-multiplier ![(2-255)$multiplier]",
+ NO_STR
"Configure peer detection multiplier\n"
"Configure peer detection multiplier value\n")
ALIAS_YANG(bfd_peer_tx, bfd_profile_tx_cmd,
- "transmit-interval (10-60000)$interval",
+ "[no] transmit-interval ![(10-60000)$interval]",
+ NO_STR
"Configure peer transmit interval\n"
"Configure peer transmit interval value in milliseconds\n")
ALIAS_YANG(bfd_peer_rx, bfd_profile_rx_cmd,
- "receive-interval (10-60000)$interval",
+ "[no] receive-interval ![(10-60000)$interval]",
+ NO_STR
"Configure peer receive interval\n"
"Configure peer receive interval value in milliseconds\n")
@@ -612,20 +621,23 @@ ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd,
"Configure echo mode\n")
ALIAS_YANG(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd,
- "echo-interval (10-60000)$interval",
+ "[no] echo-interval ![(10-60000)$interval]",
+ NO_STR
"Configure peer echo interval\n"
"Configure peer echo interval value in milliseconds\n")
ALIAS_YANG(
bfd_peer_echo_transmit_interval, bfd_profile_echo_transmit_interval_cmd,
- "echo transmit-interval (10-60000)$interval",
+ "[no] echo transmit-interval ![(10-60000)$interval]",
+ NO_STR
"Configure peer echo intervals\n"
"Configure desired transmit interval\n"
"Configure interval value in milliseconds\n")
ALIAS_YANG(
bfd_peer_echo_receive_interval, bfd_profile_echo_receive_interval_cmd,
- "echo receive-interval <disabled$disabled|(10-60000)$interval>",
+ "[no] echo receive-interval ![<disabled$disabled|(10-60000)$interval>]",
+ NO_STR
"Configure peer echo intervals\n"
"Configure required receive interval\n"
"Disable echo packets receive\n"
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index ac5d08b6fe..7cdf98cba7 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -198,6 +198,7 @@ static struct hash *vnc_hash = NULL;
#endif
static struct hash *srv6_l3vpn_hash;
static struct hash *srv6_vpn_hash;
+static struct hash *evpn_overlay_hash;
struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
{
@@ -549,6 +550,81 @@ static bool bgp_attr_aigp_valid(uint8_t *pnt, int length)
return true;
}
+static void *evpn_overlay_hash_alloc(void *p)
+{
+ return p;
+}
+
+void evpn_overlay_free(struct bgp_route_evpn *bre)
+{
+ XFREE(MTYPE_BGP_EVPN_OVERLAY, bre);
+}
+
+static struct bgp_route_evpn *evpn_overlay_intern(struct bgp_route_evpn *bre)
+{
+ struct bgp_route_evpn *find;
+
+ find = hash_get(evpn_overlay_hash, bre, evpn_overlay_hash_alloc);
+ if (find != bre)
+ evpn_overlay_free(bre);
+ find->refcnt++;
+ return find;
+}
+
+static void evpn_overlay_unintern(struct bgp_route_evpn **brep)
+{
+ struct bgp_route_evpn *bre = *brep;
+
+ if (!*brep)
+ return;
+
+ if (bre->refcnt)
+ bre->refcnt--;
+
+ if (bre->refcnt == 0) {
+ hash_release(evpn_overlay_hash, bre);
+ evpn_overlay_free(bre);
+ *brep = NULL;
+ }
+}
+
+static uint32_t evpn_overlay_hash_key_make(const void *p)
+{
+ const struct bgp_route_evpn *bre = p;
+ uint32_t key = 0;
+
+ if (IS_IPADDR_V4(&bre->gw_ip))
+ key = jhash_1word(bre->gw_ip.ipaddr_v4.s_addr, 0);
+ else
+ key = jhash2(bre->gw_ip.ipaddr_v6.s6_addr32,
+ array_size(bre->gw_ip.ipaddr_v6.s6_addr32), 0);
+
+ key = jhash_1word(bre->type, key);
+ key = jhash(bre->eth_s_id.val, sizeof(bre->eth_s_id.val), key);
+ return key;
+}
+
+static bool evpn_overlay_hash_cmp(const void *p1, const void *p2)
+{
+ const struct bgp_route_evpn *bre1 = p1;
+ const struct bgp_route_evpn *bre2 = p2;
+
+ return bgp_route_evpn_same(bre1, bre2);
+}
+
+static void evpn_overlay_init(void)
+{
+ evpn_overlay_hash = hash_create(evpn_overlay_hash_key_make,
+ evpn_overlay_hash_cmp,
+ "BGP EVPN Overlay");
+}
+
+static void evpn_overlay_finish(void)
+{
+ hash_clean_and_free(&evpn_overlay_hash,
+ (void (*)(void *))evpn_overlay_free);
+}
+
static void *srv6_l3vpn_hash_alloc(void *p)
{
return p;
@@ -788,6 +864,8 @@ unsigned int attrhash_key_make(const void *p)
MIX(encap_hash_key_make(attr->encap_subtlvs));
if (attr->srv6_l3vpn)
MIX(srv6_l3vpn_hash_key_make(attr->srv6_l3vpn));
+ if (bgp_attr_get_evpn_overlay(attr))
+ MIX(evpn_overlay_hash_key_make(bgp_attr_get_evpn_overlay(attr)));
if (attr->srv6_vpn)
MIX(srv6_vpn_hash_key_make(attr->srv6_vpn));
#ifdef ENABLE_BGP_VNC
@@ -814,19 +892,16 @@ bool attrhash_cmp(const void *p1, const void *p2)
const struct attr *attr1 = p1;
const struct attr *attr2 = p2;
- if (attr1->flag == attr2->flag && attr1->origin == attr2->origin
- && attr1->nexthop.s_addr == attr2->nexthop.s_addr
- && attr1->aspath == attr2->aspath
- && bgp_attr_get_community(attr1)
- == bgp_attr_get_community(attr2)
- && attr1->med == attr2->med
- && attr1->local_pref == attr2->local_pref
- && attr1->rmap_change_flags == attr2->rmap_change_flags) {
+ if (attr1->flag == attr2->flag && attr1->origin == attr2->origin &&
+ attr1->nexthop.s_addr == attr2->nexthop.s_addr &&
+ attr1->aspath == attr2->aspath &&
+ bgp_attr_get_community(attr1) == bgp_attr_get_community(attr2) &&
+ attr1->med == attr2->med && attr1->local_pref == attr2->local_pref &&
+ attr1->rmap_change_flags == attr2->rmap_change_flags) {
if (attr1->aggregator_as == attr2->aggregator_as &&
attr1->aggregator_addr.s_addr ==
attr2->aggregator_addr.s_addr &&
- attr1->weight == attr2->weight &&
- attr1->tag == attr2->tag &&
+ attr1->weight == attr2->weight && attr1->tag == attr2->tag &&
attr1->label_index == attr2->label_index &&
attr1->mp_nexthop_len == attr2->mp_nexthop_len &&
bgp_attr_get_ecommunity(attr1) ==
@@ -835,10 +910,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
bgp_attr_get_ipv6_ecommunity(attr2) &&
bgp_attr_get_lcommunity(attr1) ==
bgp_attr_get_lcommunity(attr2) &&
- bgp_attr_get_cluster(attr1) ==
- bgp_attr_get_cluster(attr2) &&
- bgp_attr_get_transit(attr1) ==
- bgp_attr_get_transit(attr2) &&
+ bgp_attr_get_cluster(attr1) == bgp_attr_get_cluster(attr2) &&
+ bgp_attr_get_transit(attr1) == bgp_attr_get_transit(attr2) &&
bgp_attr_get_aigp_metric(attr1) ==
bgp_attr_get_aigp_metric(attr2) &&
attr1->rmap_table_id == attr2->rmap_table_id &&
@@ -870,8 +943,7 @@ bool attrhash_cmp(const void *p1, const void *p2)
srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) &&
attr1->srte_color == attr2->srte_color &&
attr1->nh_type == attr2->nh_type &&
- attr1->bh_type == attr2->bh_type &&
- attr1->otc == attr2->otc)
+ attr1->bh_type == attr2->bh_type && attr1->otc == attr2->otc)
return true;
}
@@ -961,6 +1033,7 @@ struct attr *bgp_attr_intern(struct attr *attr)
struct ecommunity *ipv6_ecomm = NULL;
struct lcommunity *lcomm = NULL;
struct community *comm = NULL;
+ struct bgp_route_evpn *bre = NULL;
/* Intern referenced structure. */
if (attr->aspath) {
@@ -1027,6 +1100,16 @@ struct attr *bgp_attr_intern(struct attr *attr)
else
attr->encap_subtlvs->refcnt++;
}
+
+ bre = bgp_attr_get_evpn_overlay(attr);
+ if (bre) {
+ if (!bre->refcnt)
+ bgp_attr_set_evpn_overlay(attr,
+ evpn_overlay_intern(bre));
+ else
+ bre->refcnt++;
+ }
+
if (attr->srv6_l3vpn) {
if (!attr->srv6_l3vpn->refcnt)
attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
@@ -1072,14 +1155,14 @@ struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp,
memset(attr, 0, sizeof(struct attr));
attr->origin = origin;
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN));
attr->aspath = aspath_empty(bgp->asnotation);
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
attr->tag = 0;
attr->label_index = BGP_INVALID_LABEL_INDEX;
attr->label = MPLS_INVALID_LABEL;
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
attr->local_pref = bgp->default_local_pref;
@@ -1101,18 +1184,18 @@ struct attr *bgp_attr_aggregate_intern(
/* Origin attribute. */
attr.origin = origin;
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
+ SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN));
/* MED */
attr.med = 0;
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
+ SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC));
/* AS path attribute. */
if (aspath)
attr.aspath = aspath_intern(aspath);
else
attr.aspath = aspath_empty(bgp->asnotation);
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
+ SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
if (community) {
uint32_t gshut = COMMUNITY_GSHUT;
@@ -1142,8 +1225,8 @@ struct attr *bgp_attr_aggregate_intern(
attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
if (!aggregate->as_set || atomic_aggregate)
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
+ SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE));
+ SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
attr.aggregator_as = bgp->confed_id;
else
@@ -1161,7 +1244,7 @@ struct attr *bgp_attr_aggregate_intern(
*/
if (p->family == AF_INET) {
/* Next hop attribute. */
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
attr.mp_nexthop_len = IPV4_MAX_BYTELEN;
}
@@ -1216,6 +1299,7 @@ void bgp_attr_unintern_sub(struct attr *attr)
struct lcommunity *lcomm = NULL;
struct community *comm = NULL;
struct transit *transit;
+ struct bgp_route_evpn *bre;
/* aspath refcount shoud be decrement. */
aspath_unintern(&attr->aspath);
@@ -1257,6 +1341,10 @@ void bgp_attr_unintern_sub(struct attr *attr)
srv6_l3vpn_unintern(&attr->srv6_l3vpn);
srv6_vpn_unintern(&attr->srv6_vpn);
+
+ bre = bgp_attr_get_evpn_overlay(attr);
+ evpn_overlay_unintern(&bre);
+ bgp_attr_set_evpn_overlay(attr, NULL);
}
/* Free bgp attribute and aspath. */
@@ -1289,6 +1377,7 @@ void bgp_attr_flush(struct attr *attr)
struct cluster_list *cluster;
struct lcommunity *lcomm;
struct community *comm;
+ struct bgp_route_evpn *bre;
if (attr->aspath && !attr->aspath->refcnt) {
aspath_free(attr->aspath);
@@ -1347,6 +1436,11 @@ void bgp_attr_flush(struct attr *attr)
bgp_attr_set_vnc_subtlvs(attr, NULL);
}
#endif
+ bre = bgp_attr_get_evpn_overlay(attr);
+ if (bre && !bre->refcnt) {
+ evpn_overlay_free(bre);
+ bgp_attr_set_evpn_overlay(attr, NULL);
+ }
}
/* Implement draft-scudder-idr-optional-transitive behaviour and
@@ -1467,8 +1561,8 @@ bgp_attr_flags_diagnose(struct bgp_attr_parser_args *args,
uint8_t real_flags = args->flags;
const uint8_t attr_code = args->type;
- desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
- real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
+ UNSET_FLAG(desired_flags, BGP_ATTR_FLAG_EXTLEN);
+ UNSET_FLAG(real_flags, BGP_ATTR_FLAG_EXTLEN);
for (i = 0; i <= 2; i++) /* O,T,P, but not E */
if (CHECK_FLAG(desired_flags, attr_flag_str[i].key)
!= CHECK_FLAG(real_flags, attr_flag_str[i].key)) {
@@ -1582,7 +1676,7 @@ static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args *args)
&& CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS))
SET_FLAG(mask, BGP_ATTR_FLAG_PARTIAL);
- if ((flags & ~mask) == attr_flags_values[attr_code])
+ if (CHECK_FLAG(flags, ~mask) == attr_flags_values[attr_code])
return false;
bgp_attr_flags_diagnose(args, attr_flags_values[attr_code]);
@@ -1624,7 +1718,7 @@ bgp_attr_origin(struct bgp_attr_parser_args *args)
}
/* Set oring attribute flag. */
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN));
return 0;
}
@@ -1674,7 +1768,7 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
}
/* Set aspath attribute flag. */
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
return BGP_ATTR_PARSE_PROCEED;
}
@@ -1778,7 +1872,7 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
}
/* Set aspath attribute flag. */
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH));
return BGP_ATTR_PARSE_PROCEED;
}
@@ -1828,7 +1922,7 @@ bgp_attr_nexthop(struct bgp_attr_parser_args *args)
}
attr->nexthop.s_addr = stream_get_ipv4(peer->curr);
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
return BGP_ATTR_PARSE_PROCEED;
}
@@ -1851,7 +1945,7 @@ static enum bgp_attr_parse_ret bgp_attr_med(struct bgp_attr_parser_args *args)
attr->med = stream_getl(peer->curr);
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC));
return BGP_ATTR_PARSE_PROCEED;
}
@@ -1889,7 +1983,7 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args)
STREAM_GETL(peer->curr, attr->local_pref);
/* Set the local-pref flag. */
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF));
return BGP_ATTR_PARSE_PROCEED;
@@ -1918,7 +2012,7 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
goto atomic_ignore;
/* Set atomic aggregate flag. */
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE));
return BGP_ATTR_PARSE_PROCEED;
@@ -1976,7 +2070,7 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
zlog_debug("%s: attributes: %s", __func__, attr_str);
}
} else {
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
}
return BGP_ATTR_PARSE_PROCEED;
@@ -2027,7 +2121,7 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
zlog_debug("%s: attributes: %s", __func__, attr_str);
}
} else {
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR));
}
return BGP_ATTR_PARSE_PROCEED;
@@ -2066,12 +2160,13 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
* should not send them
*/
if (BGP_DEBUG(as4, AS4)) {
- if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
+ if (CHECK_FLAG(attr->flag,
+ (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))))
zlog_debug("[AS4] %s %s AS4_PATH", peer->host,
"AS4 capable peer, yet it sent");
- if (attr->flag
- & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
+ if (CHECK_FLAG(attr->flag,
+ (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))))
zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
peer->host,
"AS4 capable peer, yet it sent");
@@ -2083,8 +2178,9 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
/* We have a asn16 peer. First, look for AS4_AGGREGATOR
* because that may override AS4_PATH
*/
- if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) {
- if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
+ if (CHECK_FLAG(attr->flag, (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))) {
+ if (CHECK_FLAG(attr->flag,
+ (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)))) {
/* received both.
* if the as_number in aggregator is not AS_TRANS,
* then AS4_AGGREGATOR and AS4_PATH shall be ignored
@@ -2124,13 +2220,14 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
attr->aggregator_as = as4_aggregator;
/* sweep it under the carpet and simulate a "good"
* AGGREGATOR */
- attr->flag |= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
+ SET_FLAG(attr->flag,
+ (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)));
}
}
/* need to reconcile NEW_AS_PATH and AS_PATH */
- if (!ignore_as4_path
- && (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) {
+ if (!ignore_as4_path &&
+ (CHECK_FLAG(attr->flag, (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))))) {
newpath = aspath_reconcile_as4(attr->aspath, as4_path);
if (!newpath)
return BGP_ATTR_PARSE_ERROR;
@@ -2215,7 +2312,7 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args)
attr->originator_id.s_addr = stream_get_ipv4(peer->curr);
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID));
return BGP_ATTR_PARSE_PROCEED;
@@ -2473,7 +2570,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
stream_forward_getp(s, nlri_len);
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI));
return BGP_ATTR_PARSE_PROCEED;
#undef LEN_LEFT
@@ -2525,7 +2622,7 @@ int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
stream_forward_getp(s, withdraw_len);
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI));
return BGP_ATTR_PARSE_PROCEED;
}
@@ -2585,10 +2682,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
args->total);
}
- ecomm = ecommunity_parse(
- stream_pnt(peer->curr), length,
- CHECK_FLAG(peer->flags,
- PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
+ ecomm = ecommunity_parse(stream_pnt(peer->curr), length,
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
bgp_attr_set_ecommunity(attr, ecomm);
/* XXX: fix ecommunity_parse to use stream API */
stream_forward_getp(peer->curr, length);
@@ -2619,7 +2715,7 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
/* Check EVPN Neighbor advertisement flags, R-bit */
bgp_attr_evpn_na_flag(attr, &proxy);
if (proxy)
- attr->es_flags |= ATTR_ES_PROXY_ADVERT;
+ SET_FLAG(attr->es_flags, ATTR_ES_PROXY_ADVERT);
/* Extract the Rmac, if any */
if (bgp_attr_rmac(attr, &attr->rmac)) {
@@ -2690,6 +2786,9 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args)
uint8_t type = args->type;
uint8_t flag = args->flags;
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
+ goto encap_ignore;
+
if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
|| !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
zlog_err("Tunnel Encap attribute flag isn't optional and transitive %d",
@@ -2808,7 +2907,14 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args)
args->total);
}
- return 0;
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ENCAP));
+
+ return BGP_ATTR_PARSE_PROCEED;
+
+encap_ignore:
+ stream_forward_getp(peer->curr, length);
+
+ return bgp_attr_ignore(peer, type);
}
@@ -3200,6 +3306,9 @@ enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args)
size_t headersz = sizeof(type) + sizeof(length);
size_t psid_parsed_length = 0;
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
+ goto prefix_sid_ignore;
+
while (STREAM_READABLE(peer->curr) > 0
&& psid_parsed_length < args->length) {
@@ -3247,6 +3356,11 @@ enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args)
SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID));
return BGP_ATTR_PARSE_PROCEED;
+
+prefix_sid_ignore:
+ stream_forward_getp(peer->curr, args->length);
+
+ return bgp_attr_ignore(peer, args->type);
}
/* PMSI tunnel attribute (RFC 6514)
@@ -3261,6 +3375,9 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
uint8_t tnl_type;
int attr_parse_len = 2 + BGP_LABEL_BYTES;
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
+ goto pmsi_tunnel_ignore;
+
/* Verify that the receiver is expecting "ingress replication" as we
* can only support that.
*/
@@ -3289,7 +3406,7 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
}
}
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL));
bgp_attr_set_pmsi_tnl_type(attr, tnl_type);
stream_get(&attr->label, peer->curr, BGP_LABEL_BYTES);
@@ -3297,6 +3414,11 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
stream_forward_getp(peer->curr, length - attr_parse_len);
return BGP_ATTR_PARSE_PROCEED;
+
+pmsi_tunnel_ignore:
+ stream_forward_getp(peer->curr, length);
+
+ return bgp_attr_ignore(peer, args->type);
}
/* AIGP attribute (rfc7311) */
@@ -3367,7 +3489,7 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
args->total);
}
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_OTC);
+ SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC));
return BGP_ATTR_PARSE_PROCEED;
@@ -3564,18 +3686,17 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
* unused. They MUST be zero when sent and MUST be ignored when
* received.
*/
- flag = 0xF0 & stream_getc(BGP_INPUT(peer));
+ flag = CHECK_FLAG(0xF0, stream_getc(BGP_INPUT(peer)));
type = stream_getc(BGP_INPUT(peer));
/* Check whether Extended-Length applies and is in bounds */
if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN)
&& ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) {
- flog_warn(
- EC_BGP_EXT_ATTRIBUTE_TOO_SMALL,
- "%s: Extended length set, but just %lu bytes of attr header",
- peer->host,
- (unsigned long)(endp
- - stream_pnt(BGP_INPUT(peer))));
+ flog_warn(EC_BGP_EXT_ATTRIBUTE_TOO_SMALL,
+ "%s: Extended length set, but just %lu bytes of attr header",
+ peer->host,
+ (unsigned long)(endp -
+ stream_pnt(BGP_INPUT(peer))));
if (peer->sort != BGP_PEER_EBGP) {
bgp_notify_send(peer->connection,
@@ -3922,7 +4043,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
* Finally do the checks on the aspath we did not do yet
* because we waited for a potentially synthesized aspath.
*/
- if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) {
+ if (CHECK_FLAG(attr->flag, (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))) {
ret = bgp_attr_aspath_check(peer, attr);
if (ret != BGP_ATTR_PARSE_PROCEED)
goto done;
@@ -4100,8 +4221,8 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
case SAFI_MULTICAST:
case SAFI_LABELED_UNICAST:
case SAFI_EVPN: {
- if (attr->mp_nexthop_len
- == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
+ if (attr->mp_nexthop_len ==
+ BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
stream_putc(s,
BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL);
stream_put(s, &attr->mp_nexthop_global,
@@ -4322,12 +4443,12 @@ static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer,
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, attrtype);
- stream_putw(s, attrlenfield & 0xffff);
+ stream_putw(s, CHECK_FLAG(attrlenfield, 0xffff));
} else {
/* 1-octet length field */
stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL);
stream_putc(s, attrtype);
- stream_putc(s, attrlenfield & 0xff);
+ stream_putc(s, CHECK_FLAG(attrlenfield, 0xff));
}
if (attrtype == BGP_ATTR_ENCAP) {
@@ -4569,15 +4690,15 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
&& !peer_cap_enhe(peer, afi, safi)) {
afi_t nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))) {
stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_NEXT_HOP);
bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
attr);
stream_putc(s, 4);
stream_put_ipv4(s, attr->nexthop.s_addr);
- } else if (peer_cap_enhe(from, afi, safi)
- || (nh_afi == AFI_IP6)) {
+ } else if (peer_cap_enhe(from, afi, safi) ||
+ (nh_afi == AFI_IP6)) {
/*
* Likely this is the case when an IPv4 prefix was
* received with Extended Next-hop capability in this
@@ -4599,8 +4720,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
/* MED attribute. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)
- || bgp->maxmed_active) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) ||
+ bgp->maxmed_active) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
stream_putc(s, 4);
@@ -4618,14 +4739,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
/* Atomic aggregate. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) {
stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
stream_putc(s, 0);
}
/* Aggregator. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
/* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_AGGREGATOR);
@@ -4656,8 +4777,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
/* Community attribute. */
- if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
- && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) &&
+ CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
struct community *comm = NULL;
comm = bgp_attr_get_community(attr);
@@ -4681,8 +4802,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
* Large Community attribute.
*/
if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_SEND_LARGE_COMMUNITY)
- && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
+ PEER_FLAG_SEND_LARGE_COMMUNITY) &&
+ CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
stream_putc(s,
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
@@ -4712,7 +4833,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_putc(s, BGP_ATTR_ORIGINATOR_ID);
stream_putc(s, 4);
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+ if (CHECK_FLAG(attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))
stream_put_in_addr(s, &attr->originator_id);
else
stream_put_in_addr(s, &from->remote_id);
@@ -4725,7 +4847,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_putc(s, cluster->length + 4);
/* If this peer configuration's parent BGP has
* cluster_id. */
- if (bgp->config & BGP_CONFIG_CLUSTER_ID)
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID))
stream_put_in_addr(s, &bgp->cluster_id);
else
stream_put_in_addr(s, &bgp->router_id);
@@ -4734,7 +4856,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_putc(s, 4);
/* If this peer configuration's parent BGP has
* cluster_id. */
- if (bgp->config & BGP_CONFIG_CLUSTER_ID)
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID))
stream_put_in_addr(s, &bgp->cluster_id);
else
stream_put_in_addr(s, &bgp->router_id);
@@ -4902,7 +5024,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
/* PMSI Tunnel */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PMSI_TUNNEL);
stream_putc(s, 9); // Length
@@ -4915,7 +5037,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
/* OTC */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_OTC);
stream_putc(s, 4);
@@ -4923,7 +5045,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
/* AIGP */
- if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
+ if (bpi && CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) &&
(CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
peer->sub_sort == BGP_PEER_EBGP_OAD ||
peer->sort != BGP_PEER_EBGP)) {
@@ -5006,6 +5128,7 @@ void bgp_attr_init(void)
transit_init();
encap_init();
srv6_init();
+ evpn_overlay_init();
}
void bgp_attr_finish(void)
@@ -5019,6 +5142,7 @@ void bgp_attr_finish(void)
transit_finish();
encap_finish();
srv6_finish();
+ evpn_overlay_finish();
}
/* Make attribute packet. */
@@ -5064,7 +5188,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
}
/* MED attribute. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
stream_putc(s, 4);
@@ -5072,7 +5196,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
}
/* Local preference. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) {
stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_LOCAL_PREF);
stream_putc(s, 4);
@@ -5080,14 +5204,14 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
}
/* Atomic aggregate. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) {
stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
stream_putc(s, 0);
}
/* Aggregator. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_AGGREGATOR);
stream_putc(s, 8);
@@ -5096,7 +5220,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
}
/* Community attribute. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
struct community *comm = NULL;
comm = bgp_attr_get_community(attr);
@@ -5107,9 +5231,8 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putw(s, comm->size * 4);
} else {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putc(s, comm->size * 4);
}
@@ -5117,7 +5240,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
}
/* Large Community attribute. */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
stream_putc(s,
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
@@ -5126,9 +5249,8 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
stream_putw(s,
lcom_length(bgp_attr_get_lcommunity(attr)));
} else {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putc(s,
lcom_length(bgp_attr_get_lcommunity(attr)));
@@ -5172,11 +5294,10 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
}
/* Prefix SID */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID))) {
if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PREFIX_SID);
stream_putc(s, 10);
stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
@@ -5188,7 +5309,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
}
/* OTC */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_OTC))) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_OTC);
stream_putc(s, 4);
@@ -5196,7 +5317,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
}
/* AIGP */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP)) {
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP))) {
/* At the moment only AIGP Metric TLV exists for AIGP
* attribute. If more comes in, do not forget to update
* attr_len variable to include new ones.
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 561024e7c8..a8ca8c1fa6 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -278,7 +278,7 @@ struct attr {
struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */
#endif
/* EVPN */
- struct bgp_route_evpn evpn_overlay;
+ struct bgp_route_evpn *evpn_overlay;
/* EVPN MAC Mobility sequence number, if any. */
uint32_t mm_seqnum;
@@ -353,7 +353,7 @@ struct transit {
__builtin_choose_expr((X) >= 1 && (X) <= 64, 1ULL << ((X)-1), (void)0)
#define BGP_CLUSTER_LIST_LENGTH(attr) \
- (((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) \
+ (CHECK_FLAG((attr)->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) \
? bgp_attr_get_cluster((attr))->length \
: 0)
@@ -614,16 +614,16 @@ static inline void bgp_attr_set_cluster(struct attr *attr,
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST));
}
-static inline const struct bgp_route_evpn *
+static inline struct bgp_route_evpn *
bgp_attr_get_evpn_overlay(const struct attr *attr)
{
- return &attr->evpn_overlay;
+ return attr->evpn_overlay;
}
static inline void bgp_attr_set_evpn_overlay(struct attr *attr,
- struct bgp_route_evpn *eo)
+ struct bgp_route_evpn *bre)
{
- memcpy(&attr->evpn_overlay, eo, sizeof(struct bgp_route_evpn));
+ attr->evpn_overlay = bre;
}
static inline struct bgp_attr_encap_subtlv *
@@ -646,5 +646,6 @@ bgp_attr_set_vnc_subtlvs(struct attr *attr,
}
extern bool route_matches_soo(struct bgp_path_info *pi, struct ecommunity *soo);
+extern void evpn_overlay_free(struct bgp_route_evpn *bre);
#endif /* _QUAGGA_BGP_ATTR_H */
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c
index 086c36f36c..a3ffe61eb8 100644
--- a/bgpd/bgp_attr_evpn.c
+++ b/bgpd/bgp_attr_evpn.c
@@ -24,6 +24,13 @@
bool bgp_route_evpn_same(const struct bgp_route_evpn *e1,
const struct bgp_route_evpn *e2)
{
+ if (!e1 && e2)
+ return false;
+ if (!e2 && e1)
+ return false;
+ if (!e1 && !e2)
+ return true;
+
return (e1->type == e2->type &&
!memcmp(&(e1->eth_s_id), &(e2->eth_s_id), sizeof(esi_t)) &&
!ipaddr_cmp(&(e1->gw_ip), &(e2->gw_ip)));
@@ -211,7 +218,8 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr)
continue;
flags = *pnt++;
- if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
+ if (CHECK_FLAG(flags,
+ ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY))
SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
else
UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY);
@@ -251,11 +259,12 @@ void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy)
sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) {
val = *pnt++;
- if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)
+ if (CHECK_FLAG(val,
+ ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG))
SET_FLAG(attr->evpn_flags,
ATTR_EVPN_FLAG_ROUTER);
- if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG)
+ if (CHECK_FLAG(val, ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG))
*proxy = true;
break;
diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h
index e12fc3a86c..cc0e3e4400 100644
--- a/bgpd/bgp_attr_evpn.h
+++ b/bgpd/bgp_attr_evpn.h
@@ -23,6 +23,7 @@ enum overlay_index_type {
* MAC overlay index is stored in the RMAC attribute.
*/
struct bgp_route_evpn {
+ unsigned long refcnt;
enum overlay_index_type type;
esi_t eth_s_id;
struct ipaddr gw_ip;
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 43f8006e2d..9d99c2c7fd 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -1047,7 +1047,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
{
- uint8_t bpi_num_labels;
+ uint8_t bpi_num_labels, adjin_num_labels;
afi_t afi;
safi_t safi;
@@ -1221,7 +1221,7 @@ afibreak:
(safi == SAFI_MPLS_VPN))
prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos);
- bpi_num_labels = bgp_path_info_num_labels(bpi);
+ bpi_num_labels = BGP_PATH_INFO_NUM_LABELS(bpi);
if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) &&
CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_LOC_RIB)) {
@@ -1241,11 +1241,12 @@ afibreak:
bpi_num_labels ? bpi->extra->labels->label : NULL,
bpi_num_labels);
- if (adjin)
- /* TODO: set label here when adjin supports labels */
- bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE,
- bn_p, prd, adjin->attr, afi, safi, adjin->uptime,
- NULL, 0);
+ if (adjin) {
+ adjin_num_labels = adjin->labels ? adjin->labels->num_labels : 0;
+ bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd,
+ adjin->attr, afi, safi, adjin->uptime,
+ adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels);
+ }
if (bn)
bgp_dest_unlock_node(bn);
@@ -1356,7 +1357,7 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr)
break;
}
- bpi_num_labels = bgp_path_info_num_labels(bpi);
+ bpi_num_labels = BGP_PATH_INFO_NUM_LABELS(bpi);
bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, &bqe->p, prd,
bpi ? bpi->attr : NULL, afi, safi,
@@ -1382,7 +1383,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
struct peer *peer;
struct bgp_dest *bn = NULL;
bool written = false;
- uint8_t bpi_num_labels;
+ uint8_t bpi_num_labels, adjin_num_labels;
bqe = bmp_pull(bmp);
if (!bqe)
@@ -1434,7 +1435,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
break;
}
- bpi_num_labels = bgp_path_info_num_labels(bpi);
+ bpi_num_labels = BGP_PATH_INFO_NUM_LABELS(bpi);
bmp_monitor(bmp, peer, BMP_PEER_FLAG_L,
BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd,
@@ -1453,10 +1454,11 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
if (adjin->peer == peer)
break;
}
- /* TODO: set label here when adjin supports labels */
- bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE,
- &bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi,
- adjin ? adjin->uptime : monotime(NULL), NULL, 0);
+ adjin_num_labels = adjin && adjin->labels ? adjin->labels->num_labels : 0;
+ bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd,
+ adjin ? adjin->attr : NULL, afi, safi,
+ adjin ? adjin->uptime : monotime(NULL),
+ adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels);
written = true;
}
@@ -2543,9 +2545,9 @@ DEFPY(bmp_monitor_cfg, bmp_monitor_cmd,
prev = bt->afimon[afi][safi];
if (no)
- bt->afimon[afi][safi] &= ~flag;
+ UNSET_FLAG(bt->afimon[afi][safi], flag);
else
- bt->afimon[afi][safi] |= flag;
+ SET_FLAG(bt->afimon[afi][safi], flag);
if (prev == bt->afimon[afi][safi])
return CMD_SUCCESS;
@@ -2743,7 +2745,7 @@ DEFPY(show_bmp,
}
out = ttable_dump(tt, "\n");
vty_out(vty, "%s", out);
- XFREE(MTYPE_TMP, out);
+ XFREE(MTYPE_TMP_TTABLE, out);
ttable_del(tt);
vty_out(vty, "\n %zu connected clients:\n",
@@ -2770,7 +2772,7 @@ DEFPY(show_bmp,
}
out = ttable_dump(tt, "\n");
vty_out(vty, "%s", out);
- XFREE(MTYPE_TMP, out);
+ XFREE(MTYPE_TMP_TTABLE, out);
ttable_del(tt);
vty_out(vty, "\n");
}
diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c
index 1d5034efd2..32823cc376 100644
--- a/bgpd/bgp_btoa.c
+++ b/bgpd/bgp_btoa.c
@@ -69,7 +69,7 @@ static void attr_parse(struct stream *s, uint16_t len)
flag = stream_getc(s);
type = stream_getc(s);
- if (flag & BGP_ATTR_FLAG_EXTLEN)
+ if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN))
length = stream_getw(s);
else
length = stream_getc(s);
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 153cbd6e50..ad154e638b 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -496,8 +496,8 @@ static char *community_str_get(struct community *com, int i)
break;
default:
str = XSTRDUP(MTYPE_COMMUNITY_STR, "65536:65535");
- as = (comval >> 16) & 0xFFFF;
- val = comval & 0xFFFF;
+ as = CHECK_FLAG((comval >> 16), 0xFFFF);
+ val = CHECK_FLAG(comval, 0xFFFF);
snprintf(str, strlen(str), "%u:%d", as, val);
break;
}
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index 8e4c430555..602c1437af 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -416,13 +416,12 @@ static void set_community_string(struct community *com, bool make_json,
}
break;
default:
- as = (comval >> 16) & 0xFFFF;
- val = comval & 0xFFFF;
+ as = CHECK_FLAG((comval >> 16), 0xFFFF);
+ val = CHECK_FLAG(comval, 0xFFFF);
char buf[32];
snprintf(buf, sizeof(buf), "%u:%d", as, val);
const char *com2alias =
- translate_alias ? bgp_community2alias(buf)
- : buf;
+ translate_alias ? bgp_community2alias(buf) : buf;
strlcat(str, com2alias, len);
if (make_json) {
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 339bfae56d..93f5a19902 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -779,7 +779,8 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
bgp = bgp_get_default();
- if (bgp == NULL) {
+
+ if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "No BGP process is configured\n");
return CMD_WARNING;
}
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 6228432bd2..97c3e5740f 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -2558,7 +2558,7 @@ static int bgp_debug_per_prefix(const struct prefix *p,
struct bgp_debug_filter *filter;
struct listnode *node, *nnode;
- if (term_bgp_debug_type & BGP_DEBUG_TYPE) {
+ if (CHECK_FLAG(term_bgp_debug_type, BGP_DEBUG_TYPE)) {
/* We are debugging all prefixes so return true */
if (!per_prefix_list || list_isempty(per_prefix_list))
return 1;
@@ -2591,7 +2591,7 @@ static bool bgp_debug_per_peer(char *host, const struct prefix *p,
struct bgp_debug_filter *filter;
struct listnode *node, *nnode;
- if (term_bgp_debug_type & BGP_DEBUG_TYPE) {
+ if (CHECK_FLAG(term_bgp_debug_type, BGP_DEBUG_TYPE)) {
/* We are debugging all peers so return true */
if (!per_peer_list || list_isempty(per_peer_list))
return true;
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 1beb0307d2..547dcdf7f3 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -515,7 +515,7 @@ static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type,
/* Fill in the values. */
eval->val[0] = type;
if (!trans)
- eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
+ SET_FLAG(eval->val[0], ECOMMUNITY_FLAG_NON_TRANSITIVE);
eval->val[1] = sub_type;
if (type == ECOMMUNITY_ENCODE_AS) {
encode_route_target_as(as, val, eval, trans);
@@ -1293,11 +1293,12 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
== ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL) {
uint8_t flags = *++pnt;
- snprintf(encbuf,
- sizeof(encbuf), "ESI-label-Rt:%s",
- (flags &
- ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG) ?
- "SA":"AA");
+ snprintf(encbuf, sizeof(encbuf),
+ "ESI-label-Rt:%s",
+ CHECK_FLAG(flags,
+ ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG)
+ ? "SA"
+ : "AA");
} else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION) {
uint8_t alg;
@@ -1337,38 +1338,37 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
char buf[ECOMMUNITY_STRLEN];
memset(buf, 0, sizeof(buf));
- ecommunity_rt_soo_str_internal(buf, sizeof(buf),
- (const uint8_t *)pnt,
- type &
- ~ECOMMUNITY_ENCODE_TRANS_EXP,
- ECOMMUNITY_ROUTE_TARGET,
- format,
- ecom->unit_size);
+ ecommunity_rt_soo_str_internal(
+ buf, sizeof(buf), (const uint8_t *)pnt,
+ CHECK_FLAG(type,
+ ~ECOMMUNITY_ENCODE_TRANS_EXP),
+ ECOMMUNITY_ROUTE_TARGET, format,
+ ecom->unit_size);
snprintf(encbuf, sizeof(encbuf), "%s", buf);
} else if (sub_type ==
ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) {
char buf[64];
memset(buf, 0, sizeof(buf));
- ecommunity_rt_soo_str_internal(buf, sizeof(buf),
- (const uint8_t *)pnt,
- type &
- ~ECOMMUNITY_ENCODE_TRANS_EXP,
- ECOMMUNITY_ROUTE_TARGET,
- ECOMMUNITY_FORMAT_DISPLAY,
- ecom->unit_size);
+ ecommunity_rt_soo_str_internal(
+ buf, sizeof(buf), (const uint8_t *)pnt,
+ CHECK_FLAG(type,
+ ~ECOMMUNITY_ENCODE_TRANS_EXP),
+ ECOMMUNITY_ROUTE_TARGET,
+ ECOMMUNITY_FORMAT_DISPLAY,
+ ecom->unit_size);
snprintf(encbuf, sizeof(encbuf),
"FS:redirect VRF %s", buf);
} else if (sub_type == ECOMMUNITY_REDIRECT_VRF) {
char buf[16];
memset(buf, 0, sizeof(buf));
- ecommunity_rt_soo_str(buf, sizeof(buf),
- (const uint8_t *)pnt,
- type &
- ~ECOMMUNITY_ENCODE_TRANS_EXP,
- ECOMMUNITY_ROUTE_TARGET,
- ECOMMUNITY_FORMAT_DISPLAY);
+ ecommunity_rt_soo_str(
+ buf, sizeof(buf), (const uint8_t *)pnt,
+ CHECK_FLAG(type,
+ ~ECOMMUNITY_ENCODE_TRANS_EXP),
+ ECOMMUNITY_ROUTE_TARGET,
+ ECOMMUNITY_FORMAT_DISPLAY);
snprintf(encbuf, sizeof(encbuf),
"FS:redirect VRF %s", buf);
snprintf(encbuf, sizeof(encbuf),
@@ -1640,12 +1640,13 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
} else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_ACTION) {
api->action = ACTION_TRAFFIC_ACTION;
/* else distribute code is set by default */
- if (ecom_eval->val[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL))
- api->u.za.filter |= TRAFFIC_ACTION_TERMINATE;
+ if (CHECK_FLAG(ecom_eval->val[5],
+ (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL)))
+ SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_TERMINATE);
else
- api->u.za.filter |= TRAFFIC_ACTION_DISTRIBUTE;
+ SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_DISTRIBUTE);
if (ecom_eval->val[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE)
- api->u.za.filter |= TRAFFIC_ACTION_SAMPLE;
+ SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_SAMPLE);
} else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_MARKING) {
api->action = ACTION_MARKING;
@@ -1940,7 +1941,7 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
return new;
type = *eval;
- if (type & ECOMMUNITY_FLAG_NON_TRANSITIVE)
+ if (CHECK_FLAG(type, ECOMMUNITY_FLAG_NON_TRANSITIVE))
return new;
/* Transitive link-bandwidth exists, replace with the passed
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 929e4e60be..67c16aeb9e 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -155,12 +155,12 @@ struct ecommunity_ip6 {
/* Extended community value is eight octet. */
struct ecommunity_val {
- char val[ECOMMUNITY_SIZE];
+ uint8_t val[ECOMMUNITY_SIZE];
};
/* IPv6 Extended community value is eight octet. */
struct ecommunity_val_ipv6 {
- char val[IPV6_ECOMMUNITY_SIZE];
+ uint8_t val[IPV6_ECOMMUNITY_SIZE];
};
#define ecom_length_size(X, Y) ((X)->size * (Y))
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 55896ee7ea..fb7d2f47fb 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -117,7 +117,7 @@ int vni_list_cmp(void *p1, void *p2)
static unsigned int vrf_import_rt_hash_key_make(const void *p)
{
const struct vrf_irt_node *irt = p;
- const char *pnt = irt->rt.val;
+ const uint8_t *pnt = irt->rt.val;
return jhash(pnt, 8, 0x5abc1234);
}
@@ -229,7 +229,7 @@ static int is_vrf_present_in_irt_vrfs(struct list *vrfs, struct bgp *bgp_vrf)
static unsigned int import_rt_hash_key_make(const void *p)
{
const struct irt_node *irt = p;
- const char *pnt = irt->rt.val;
+ const uint8_t *pnt = irt->rt.val;
return jhash(pnt, 8, 0xdeadbeef);
}
@@ -621,7 +621,7 @@ static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl,
struct listnode *node;
if (bgp->advertise_autort_rfc8365)
- vni |= EVPN_AUTORT_VXLAN;
+ SET_FLAG(vni, EVPN_AUTORT_VXLAN);
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true);
ecomadd = ecommunity_new();
@@ -1314,12 +1314,11 @@ enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn
* flag set install the local entry as a router entry
*/
if (is_evpn_prefix_ipaddr_v6(p) &&
- (pi->attr->es_flags &
- ATTR_ES_PEER_ROUTER))
+ CHECK_FLAG(pi->attr->es_flags, ATTR_ES_PEER_ROUTER))
SET_FLAG(flags,
ZEBRA_MACIP_TYPE_ROUTER_FLAG);
- if (!(pi->attr->es_flags & ATTR_ES_PEER_ACTIVE))
+ if (!CHECK_FLAG(pi->attr->es_flags, ATTR_ES_PEER_ACTIVE))
SET_FLAG(flags,
ZEBRA_MACIP_TYPE_PROXY_ADVERT);
}
@@ -1611,12 +1610,16 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
struct bgp_labels bgp_labels = {};
struct bgp_path_info *local_pi = NULL;
struct bgp_path_info *tmp_pi = NULL;
+ struct aspath *new_aspath;
+ struct attr static_attr = { 0 };
*route_changed = 0;
/* See if this is an update of an existing route, or a new add. */
local_pi = bgp_evpn_route_get_local_path(bgp_evpn, dest);
+ static_attr = *attr;
+
/*
* create a new route entry if one doesn't exist.
* Otherwise see if route attr has changed
@@ -1626,8 +1629,19 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
/* route has changed as this is the first entry */
*route_changed = 1;
+ /*
+ * if the asn values are different, copy the as of
+ * source vrf to the target entry
+ */
+ if (bgp_vrf->as != bgp_evpn->as) {
+ new_aspath = aspath_dup(static_attr.aspath);
+ new_aspath = aspath_add_seq(new_aspath, bgp_vrf->as);
+ static_attr.aspath = new_aspath;
+ }
+
/* Add (or update) attribute to hash. */
- attr_new = bgp_attr_intern(attr);
+ attr_new = bgp_attr_intern(&static_attr);
+ bgp_attr_flush(&static_attr);
/* create the route info from attribute */
pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
@@ -1741,20 +1755,30 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) {
if (src_attr &&
!IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) {
- attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
- SET_IPADDR_V6(&attr.evpn_overlay.gw_ip);
- memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6,
+ struct bgp_route_evpn *bre =
+ XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
+ sizeof(struct bgp_route_evpn));
+
+ bre->type = OVERLAY_INDEX_GATEWAY_IP;
+ SET_IPADDR_V6(&bre->gw_ip);
+ memcpy(&bre->gw_ip.ipaddr_v6,
&src_attr->mp_nexthop_global,
sizeof(struct in6_addr));
+ bgp_attr_set_evpn_overlay(&attr, bre);
}
} else if (src_afi == AFI_IP &&
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) {
if (src_attr && src_attr->nexthop.s_addr != 0) {
- attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
- SET_IPADDR_V4(&attr.evpn_overlay.gw_ip);
- memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4,
- &src_attr->nexthop, sizeof(struct in_addr));
+ struct bgp_route_evpn *bre =
+ XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
+ sizeof(struct bgp_route_evpn));
+
+ bre->type = OVERLAY_INDEX_GATEWAY_IP;
+ SET_IPADDR_V4(&bre->gw_ip);
+ memcpy(&bre->gw_ip.ipaddr_v4, &src_attr->nexthop,
+ sizeof(struct in_addr));
+ bgp_attr_set_evpn_overlay(&attr, bre);
}
}
@@ -1887,42 +1911,44 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp,
mac);
attr->mm_sync_seqnum = max_sync_seq;
if (active_on_peer)
- attr->es_flags |= ATTR_ES_PEER_ACTIVE;
+ SET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE);
else
- attr->es_flags &= ~ATTR_ES_PEER_ACTIVE;
+ UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE);
if (proxy_from_peer)
- attr->es_flags |= ATTR_ES_PEER_PROXY;
+ SET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY);
else
- attr->es_flags &= ~ATTR_ES_PEER_PROXY;
+ UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY);
if (peer_router)
- attr->es_flags |= ATTR_ES_PEER_ROUTER;
+ SET_FLAG(attr->es_flags, ATTR_ES_PEER_ROUTER);
else
- attr->es_flags &= ~ATTR_ES_PEER_ROUTER;
+ UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ROUTER);
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) {
char esi_buf[ESI_STR_LEN];
- zlog_debug(
- "setup sync info for %pFX es %s max_seq %d %s%s%s",
- evp,
- esi_to_str(esi, esi_buf,
- sizeof(esi_buf)),
- max_sync_seq,
- (attr->es_flags & ATTR_ES_PEER_ACTIVE)
- ? "peer-active "
- : "",
- (attr->es_flags & ATTR_ES_PEER_PROXY)
- ? "peer-proxy "
- : "",
- (attr->es_flags & ATTR_ES_PEER_ROUTER)
- ? "peer-router "
- : "");
+ zlog_debug("setup sync info for %pFX es %s max_seq %d %s%s%s",
+ evp,
+ esi_to_str(esi, esi_buf,
+ sizeof(esi_buf)),
+ max_sync_seq,
+ CHECK_FLAG(attr->es_flags,
+ ATTR_ES_PEER_ACTIVE)
+ ? "peer-active "
+ : "",
+ CHECK_FLAG(attr->es_flags,
+ ATTR_ES_PEER_PROXY)
+ ? "peer-proxy "
+ : "",
+ CHECK_FLAG(attr->es_flags,
+ ATTR_ES_PEER_ROUTER)
+ ? "peer-router "
+ : "");
}
}
} else {
attr->mm_sync_seqnum = 0;
- attr->es_flags &= ~ATTR_ES_PEER_ACTIVE;
- attr->es_flags &= ~ATTR_ES_PEER_PROXY;
+ UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE);
+ UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY);
}
}
@@ -2114,22 +2140,18 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp,
}
}
- if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP
- && (curr_select->sub_type == BGP_ROUTE_IMPORTED ||
- bgp_evpn_attr_is_sync(curr_select->attr)))
- if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP &&
- (curr_select->sub_type == BGP_ROUTE_IMPORTED ||
- bgp_evpn_attr_is_sync(curr_select->attr))) {
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
- evpn_zebra_install(bgp, vpn,
- (const struct prefix_evpn *)
- bgp_dest_get_prefix(
- dest),
- curr_select);
- else
- bgp_zebra_route_install(dest, curr_select, bgp,
- true, vpn, false);
- }
+ if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP &&
+ (curr_select->sub_type == BGP_ROUTE_IMPORTED ||
+ bgp_evpn_attr_is_sync(curr_select->attr))) {
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
+ evpn_zebra_install(bgp, vpn,
+ (const struct prefix_evpn *)
+ bgp_dest_get_prefix(dest),
+ curr_select);
+ else
+ bgp_zebra_route_install(dest, curr_select, bgp, true,
+ vpn, false);
+ }
}
/*
@@ -2211,16 +2233,16 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER);
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
- attr.es_flags |= ATTR_ES_PROXY_ADVERT;
+ SET_FLAG(attr.es_flags, ATTR_ES_PROXY_ADVERT);
if (esi && bgp_evpn_is_esi_valid(esi)) {
memcpy(&attr.esi, esi, sizeof(esi_t));
- attr.es_flags |= ATTR_ES_IS_LOCAL;
+ SET_FLAG(attr.es_flags, ATTR_ES_IS_LOCAL);
}
/* PMSI is only needed for type-3 routes */
if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
+ SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL));
bgp_attr_set_pmsi_tnl_type(&attr, PMSI_TNLTYPE_INGR_REPL);
}
@@ -2252,8 +2274,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
* IPv4 or IPv6 global addresses and we're advertising L3VNI with
* these routes.
*/
- add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok(
- vpn, p, (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL);
+ add_l3_ecomm =
+ bgp_evpn_route_add_l3_ecomm_ok(vpn, p,
+ CHECK_FLAG(attr.es_flags,
+ ATTR_ES_IS_LOCAL)
+ ? &attr.esi
+ : NULL);
if (bgp->evpn_info)
macvrf_soo = bgp->evpn_info->soo;
@@ -2525,9 +2551,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
/* Add L3 VNI RTs and RMAC for non IPv6 link-local if
* using L3 VNI for type-2 routes also.
*/
- add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok(
- vpn, &evp,
- (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL);
+ add_l3_ecomm =
+ bgp_evpn_route_add_l3_ecomm_ok(vpn, &evp,
+ CHECK_FLAG(attr.es_flags,
+ ATTR_ES_IS_LOCAL)
+ ? &attr.esi
+ : NULL);
if (bgp->evpn_info)
macvrf_soo = bgp->evpn_info->soo;
@@ -3003,7 +3032,7 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi,
if (parent_pi->extra)
pi->extra->igpmetric = parent_pi->extra->igpmetric;
- if (bgp_path_info_num_labels(parent_pi))
+ if (BGP_PATH_INFO_NUM_LABELS(parent_pi))
pi->extra->labels = bgp_labels_intern(parent_pi->extra->labels);
bgp_path_info_add(dest, pi);
@@ -3031,6 +3060,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
bool use_l3nhg = false;
bool is_l3nhg_active = false;
char buf1[INET6_ADDRSTRLEN];
+ struct bgp_route_evpn *bre;
memset(pp, 0, sizeof(struct prefix));
ip_prefix_from_evpn_prefix(evp, pp);
@@ -3064,45 +3094,43 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
* make sure to set the flag for next hop attribute.
*/
attr = *parent_pi->attr;
- if (attr.evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP) {
- if (afi == AFI_IP6)
- evpn_convert_nexthop_to_ipv6(&attr);
- else {
- attr.nexthop = attr.mp_nexthop_global_in;
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
- }
- } else {
-
+ bre = bgp_attr_get_evpn_overlay(&attr);
+ if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
/*
* If gateway IP overlay index is specified in the NLRI of
* EVPN RT-5, this gateway IP should be used as the nexthop
* for the prefix in the VRF
*/
if (bgp_debug_zebra(NULL)) {
- zlog_debug(
- "Install gateway IP %s as nexthop for prefix %pFX in vrf %s",
- inet_ntop(pp->family, &attr.evpn_overlay.gw_ip,
- buf1, sizeof(buf1)), pp,
- vrf_id_to_name(bgp_vrf->vrf_id));
+ zlog_debug("Install gateway IP %s as nexthop for prefix %pFX in vrf %s",
+ inet_ntop(pp->family, &bre->gw_ip, buf1,
+ sizeof(buf1)),
+ pp, vrf_id_to_name(bgp_vrf->vrf_id));
}
if (afi == AFI_IP6) {
- memcpy(&attr.mp_nexthop_global,
- &attr.evpn_overlay.gw_ip.ipaddr_v6,
+ memcpy(&attr.mp_nexthop_global, &bre->gw_ip.ipaddr_v6,
sizeof(struct in6_addr));
attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
} else {
- attr.nexthop = attr.evpn_overlay.gw_ip.ipaddr_v4;
- attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ attr.nexthop = bre->gw_ip.ipaddr_v4;
+ SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
+ }
+ } else {
+ if (afi == AFI_IP6)
+ evpn_convert_nexthop_to_ipv6(&attr);
+ else {
+ attr.nexthop = attr.mp_nexthop_global_in;
+ SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP));
}
}
bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg,
&is_l3nhg_active, NULL);
if (use_l3nhg)
- attr.es_flags |= ATTR_ES_L3_NHG_USE;
+ SET_FLAG(attr.es_flags, ATTR_ES_L3_NHG_USE);
if (is_l3nhg_active)
- attr.es_flags |= ATTR_ES_L3_NHG_ACTIVE;
+ SET_FLAG(attr.es_flags, ATTR_ES_L3_NHG_ACTIVE);
/* Check if route entry is already present. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
@@ -3144,22 +3172,20 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
}
/* Gateway IP nexthop should be resolved */
- if (attr.evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
+ if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
if (bgp_find_or_add_nexthop(bgp_vrf, bgp_vrf, afi, safi, pi,
NULL, 0, NULL))
bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
else {
if (BGP_DEBUG(nht, NHT)) {
- inet_ntop(pp->family,
- &attr.evpn_overlay.gw_ip,
- buf1, sizeof(buf1));
+ inet_ntop(pp->family, &bre->gw_ip, buf1,
+ sizeof(buf1));
zlog_debug("%s: gateway IP NH unresolved",
buf1);
}
bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID);
}
} else {
-
/* as it is an importation, change nexthop */
bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF);
}
@@ -3268,8 +3294,7 @@ static int install_evpn_route_entry_in_vni_common(
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("VNI %d path %pFX chg to %s es",
vpn->vni, &pi->net->rn->p,
- new_local_es ? "local"
- : "non-local");
+ new_local_es ? "local" : "non-local");
bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED);
}
@@ -3632,7 +3657,7 @@ static int is_route_matching_for_vrf(struct bgp *bgp_vrf,
assert(attr);
/* Route should have valid RT to be even considered. */
- if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
+ if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
return 0;
ecom = bgp_attr_get_ecommunity(attr);
@@ -3699,7 +3724,7 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn,
assert(attr);
/* Route should have valid RT to be even considered. */
- if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
+ if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
return 0;
ecom = bgp_attr_get_ecommunity(attr);
@@ -4201,7 +4226,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
return 0;
/* If we don't have Route Target, nothing much to do. */
- if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
+ if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
return 0;
/* EAD prefix in the global table doesn't include the VTEP-IP so
@@ -4690,7 +4715,6 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
{
struct prefix_rd prd;
struct prefix_evpn p = {};
- struct bgp_route_evpn evpn = {};
uint8_t ipaddr_len;
uint8_t macaddr_len;
/* holds the VNI(s) as in packet */
@@ -4732,9 +4756,9 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
STREAM_GET(&attr->esi, pkt, sizeof(esi_t));
if (bgp_evpn_is_esi_local_and_non_bypass(&attr->esi))
- attr->es_flags |= ATTR_ES_IS_LOCAL;
+ SET_FLAG(attr->es_flags, ATTR_ES_IS_LOCAL);
else
- attr->es_flags &= ~ATTR_ES_IS_LOCAL;
+ UNSET_FLAG(attr->es_flags, ATTR_ES_IS_LOCAL);
} else {
STREAM_FORWARD_GETP(pkt, sizeof(esi_t));
}
@@ -4792,11 +4816,11 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
if (attr)
bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
- &label[0], num_labels, 0, &evpn);
+ &label[0], num_labels, 0, NULL);
else
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label[0],
- num_labels, &evpn);
+ num_labels);
goto done;
fail:
@@ -4836,8 +4860,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
* Note: We just simply ignore the values as it is not clear if
* doing anything else is better.
*/
- if (attr &&
- (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
+ if (attr && CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
enum pta_type pmsi_tnl_type = bgp_attr_get_pmsi_tnl_type(attr);
if (pmsi_tnl_type != PMSI_TNLTYPE_INGR_REPL
@@ -4886,8 +4909,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
0, 0, NULL);
else
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
- NULL);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
return 0;
}
@@ -4900,7 +4922,8 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
{
struct prefix_rd prd;
struct prefix_evpn p;
- struct bgp_route_evpn evpn;
+ struct bgp_route_evpn *evpn = XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
+ sizeof(struct bgp_route_evpn));
uint8_t ippfx_len;
uint32_t eth_tag;
mpls_label_t label; /* holds the VNI as in the packet */
@@ -4915,6 +4938,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-5 NLRI with invalid length %d",
peer->bgp->vrf_id, peer->host, psize);
+ evpn_overlay_free(evpn);
return -1;
}
@@ -4930,12 +4954,9 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
p.prefixlen = EVPN_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
- /* Additional information outside of prefix - ESI and GW IP */
- memset(&evpn, 0, sizeof(evpn));
-
/* Fetch ESI overlay index */
if (attr)
- memcpy(&evpn.eth_s_id, pfx, sizeof(esi_t));
+ memcpy(&evpn->eth_s_id, pfx, sizeof(esi_t));
pfx += ESI_BYTES;
/* Fetch Ethernet Tag. */
@@ -4950,6 +4971,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
EC_BGP_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-5 NLRI with invalid IP Prefix length %d",
peer->bgp->vrf_id, peer->host, ippfx_len);
+ evpn_overlay_free(evpn);
return -1;
}
p.prefix.prefix_addr.ip_prefix_length = ippfx_len;
@@ -4962,16 +4984,16 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
SET_IPADDR_V4(&p.prefix.prefix_addr.ip);
memcpy(&p.prefix.prefix_addr.ip.ipaddr_v4, pfx, 4);
pfx += 4;
- SET_IPADDR_V4(&evpn.gw_ip);
- memcpy(&evpn.gw_ip.ipaddr_v4, pfx, 4);
+ SET_IPADDR_V4(&evpn->gw_ip);
+ memcpy(&evpn->gw_ip.ipaddr_v4, pfx, 4);
pfx += 4;
} else {
SET_IPADDR_V6(&p.prefix.prefix_addr.ip);
memcpy(&p.prefix.prefix_addr.ip.ipaddr_v6, pfx,
IPV6_MAX_BYTELEN);
pfx += IPV6_MAX_BYTELEN;
- SET_IPADDR_V6(&evpn.gw_ip);
- memcpy(&evpn.gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN);
+ SET_IPADDR_V6(&evpn->gw_ip);
+ memcpy(&evpn->gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN);
pfx += IPV6_MAX_BYTELEN;
}
@@ -4989,20 +5011,20 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
* An update containing a non-zero gateway IP and a non-zero ESI
* at the same time is should be treated as withdraw
*/
- if (bgp_evpn_is_esi_valid(&evpn.eth_s_id) &&
- !ipaddr_is_zero(&evpn.gw_ip)) {
+ if (bgp_evpn_is_esi_valid(&evpn->eth_s_id) &&
+ !ipaddr_is_zero(&evpn->gw_ip)) {
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
"%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.",
peer->host);
is_valid_update = false;
- } else if (bgp_evpn_is_esi_valid(&evpn.eth_s_id))
- evpn.type = OVERLAY_INDEX_ESI;
- else if (!ipaddr_is_zero(&evpn.gw_ip))
- evpn.type = OVERLAY_INDEX_GATEWAY_IP;
+ } else if (bgp_evpn_is_esi_valid(&evpn->eth_s_id))
+ evpn->type = OVERLAY_INDEX_ESI;
+ else if (!ipaddr_is_zero(&evpn->gw_ip))
+ evpn->type = OVERLAY_INDEX_GATEWAY_IP;
if (attr) {
if (is_zero_mac(&attr->rmac) &&
- !bgp_evpn_is_esi_valid(&evpn.eth_s_id) &&
- ipaddr_is_zero(&evpn.gw_ip) && label == 0) {
+ !bgp_evpn_is_esi_valid(&evpn->eth_s_id) &&
+ ipaddr_is_zero(&evpn->gw_ip) && label == 0) {
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
"%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero",
peer->host);
@@ -5017,7 +5039,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
if (attr && is_valid_update)
bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
- &label, 1, 0, &evpn);
+ &label, 1, 0, evpn);
else {
if (!is_valid_update) {
char attr_str[BUFSIZ] = {0};
@@ -5029,8 +5051,8 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
attr_str);
}
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1,
- &evpn);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1);
+ evpn_overlay_free(evpn);
}
return 0;
@@ -5044,12 +5066,16 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
int len;
char temp[16];
const struct evpn_addr *p_evpn_p;
+ struct bgp_route_evpn *bre = NULL;
memset(&temp, 0, sizeof(temp));
if (p->family != AF_EVPN)
return;
p_evpn_p = &(p->u.prefix_evpn);
+ if (attr)
+ bre = bgp_attr_get_evpn_overlay(attr);
+
/* len denites the total len of IP and GW-IP in the route
IP and GW-IP have to be both ipv4 or ipv6
*/
@@ -5060,7 +5086,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
/* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */
stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
stream_put(s, prd->val, 8);
- if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_ESI)
+ if (attr && bre && bre->type == OVERLAY_INDEX_ESI)
stream_put(s, &attr->esi, sizeof(esi_t));
else
stream_put(s, 0, sizeof(esi_t));
@@ -5070,15 +5096,11 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
stream_put_ipv4(s, p_evpn_p->prefix_addr.ip.ipaddr_v4.s_addr);
else
stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16);
- if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
- const struct bgp_route_evpn *evpn_overlay =
- bgp_attr_get_evpn_overlay(attr);
-
+ if (attr && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
- stream_put_ipv4(s,
- evpn_overlay->gw_ip.ipaddr_v4.s_addr);
+ stream_put_ipv4(s, bre->gw_ip.ipaddr_v4.s_addr);
else
- stream_put(s, &(evpn_overlay->gw_ip.ipaddr_v6), 16);
+ stream_put(s, &(bre->gw_ip.ipaddr_v6), 16);
} else {
if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip))
stream_put_ipv4(s, 0);
@@ -5440,7 +5462,7 @@ void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl,
struct ecommunity_val eval;
if (bgp->advertise_autort_rfc8365)
- vni |= EVPN_AUTORT_VXLAN;
+ SET_FLAG(vni, EVPN_AUTORT_VXLAN);
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true);
@@ -7718,18 +7740,18 @@ static void bgp_evpn_remote_ip_process_nexthops(struct bgpevpn *vpn,
* MAC/IP route or SVI or tenant vrf being added to EVI.
* Set nexthop as valid only if it is already L3 reachable
*/
- if (resolve && bnc->flags & BGP_NEXTHOP_EVPN_INCOMPLETE) {
- bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
- bnc->flags |= BGP_NEXTHOP_VALID;
- bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
+ if (resolve && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) {
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+ SET_FLAG(bnc->change_flags, BGP_NEXTHOP_MACIP_CHANGED);
evaluate_paths(bnc);
}
/* MAC/IP route or SVI or tenant vrf being deleted from EVI */
- if (!resolve && bnc->flags & BGP_NEXTHOP_VALID) {
- bnc->flags &= ~BGP_NEXTHOP_VALID;
- bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE;
- bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
+ if (!resolve && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
+ SET_FLAG(bnc->change_flags, BGP_NEXTHOP_MACIP_CHANGED);
evaluate_paths(bnc);
}
}
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index d723a2b1be..1fb6594557 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -770,8 +770,7 @@ int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi,
0, 0, NULL);
} else {
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
- NULL);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
}
return 0;
}
@@ -1239,8 +1238,7 @@ int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
0, 0, NULL);
} else {
bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
- NULL);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
}
return 0;
}
@@ -1406,8 +1404,8 @@ bgp_zebra_send_remote_es_vtep(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep,
return ZCLIENT_SEND_SUCCESS;
}
- if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
- flags |= ZAPI_ES_VTEP_FLAG_ESR_RXED;
+ if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
+ SET_FLAG(flags, ZAPI_ES_VTEP_FLAG_ESR_RXED);
s = zclient->obuf;
stream_reset(s);
@@ -1966,9 +1964,9 @@ 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))
- || listcount(es->macip_evi_path_list)
- || listcount(es->macip_global_path_list))
+ if (CHECK_FLAG(es->flags, (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) ||
+ listcount(es->macip_evi_path_list) ||
+ listcount(es->macip_global_path_list))
return;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
@@ -1993,8 +1991,8 @@ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es *es)
{
- return (es->flags & BGP_EVPNES_LOCAL)
- && !(es->flags & BGP_EVPNES_BYPASS);
+ return CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL) &&
+ !CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS);
}
/* init local info associated with the ES */
@@ -2076,8 +2074,8 @@ bool bgp_evpn_es_add_l3_ecomm_ok(esi_t *esi)
es = bgp_evpn_es_find(esi);
- return (!es || !(es->flags & BGP_EVPNES_LOCAL)
- || bgp_evpn_local_es_is_active(es));
+ return (!es || !CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL) ||
+ bgp_evpn_local_es_is_active(es));
}
static bool bgp_evpn_is_valid_local_path(struct bgp_path_info *pi)
@@ -2177,9 +2175,9 @@ static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es *es,
attr_tmp = *pi->attr;
if (is_local)
- attr_tmp.es_flags |= ATTR_ES_IS_LOCAL;
+ SET_FLAG(attr_tmp.es_flags, ATTR_ES_IS_LOCAL);
else
- attr_tmp.es_flags &= ~ATTR_ES_IS_LOCAL;
+ UNSET_FLAG(attr_tmp.es_flags, ATTR_ES_IS_LOCAL);
attr_new = bgp_attr_intern(&attr_tmp);
bgp_attr_unintern(&pi->attr);
pi->attr = attr_new;
@@ -2473,9 +2471,9 @@ static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es,
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
vtep_flag_str[0] = '\0';
- if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
+ if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
- if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
+ if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
if (!strlen(vtep_flag_str))
@@ -2507,15 +2505,15 @@ static void bgp_evpn_es_json_vtep_fill(json_object *json_vteps,
json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4",
&es_vtep->vtep_ip);
- if (es_vtep->flags & (BGP_EVPNES_VTEP_ESR |
- BGP_EVPNES_VTEP_ACTIVE)) {
+ if (CHECK_FLAG(es_vtep->flags,
+ (BGP_EVPNES_VTEP_ESR | BGP_EVPNES_VTEP_ACTIVE))) {
json_flags = json_object_new_array();
- if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
+ if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
json_array_string_add(json_flags, "esr");
- if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
+ if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
json_array_string_add(json_flags, "active");
json_object_object_add(json_vtep_entry, "flags", json_flags);
- if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) {
+ if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR)) {
json_object_int_add(json_vtep_entry, "dfPreference",
es_vtep->df_pref);
json_object_string_add(
@@ -2539,9 +2537,9 @@ static void bgp_evpn_es_vteps_show_detail(struct vty *vty,
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
vtep_flag_str[0] = '\0';
- if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
+ if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
- if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
+ if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
if (!strlen(vtep_flag_str))
@@ -2550,7 +2548,7 @@ static void bgp_evpn_es_vteps_show_detail(struct vty *vty,
vty_out(vty, " %pI4 flags: %s", &es_vtep->vtep_ip,
vtep_flag_str);
- if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
+ if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR))
vty_out(vty, " df_alg: %s df_pref: %u\n",
evpn_es_df_alg2str(es_vtep->df_alg, alg_buf,
sizeof(alg_buf)),
@@ -2575,11 +2573,12 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
json_object_string_addf(json, "rd", "%pRDP",
&es->es_base_frag->prd);
- if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) {
+ if (CHECK_FLAG(es->flags,
+ (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))) {
json_types = json_object_new_array();
- if (es->flags & BGP_EVPNES_LOCAL)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
json_array_string_add(json_types, "local");
- if (es->flags & BGP_EVPNES_REMOTE)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
json_array_string_add(json_types, "remote");
json_object_object_add(json, "type", json_types);
}
@@ -2599,11 +2598,11 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
type_str[0] = '\0';
- if (es->flags & BGP_EVPNES_BYPASS)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS))
strlcat(type_str, "B", sizeof(type_str));
- if (es->flags & BGP_EVPNES_LOCAL)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
strlcat(type_str, "L", sizeof(type_str));
- if (es->flags & BGP_EVPNES_REMOTE)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
strlcat(type_str, "R", sizeof(type_str));
if (es->inconsistencies)
strlcat(type_str, "I", sizeof(type_str));
@@ -2630,16 +2629,16 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
/* Add the "brief" info first */
bgp_evpn_es_show_entry(vty, es, json);
- if (es->flags
- & (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI
- | BGP_EVPNES_BYPASS)) {
+ if (CHECK_FLAG(es->flags,
+ (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI |
+ BGP_EVPNES_BYPASS))) {
json_flags = json_object_new_array();
- if (es->flags & BGP_EVPNES_OPER_UP)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP))
json_array_string_add(json_flags, "up");
- if (es->flags & BGP_EVPNES_ADV_EVI)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
json_array_string_add(json_flags,
"advertiseEVI");
- if (es->flags & BGP_EVPNES_BYPASS)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS))
json_array_string_add(json_flags, "bypass");
json_object_object_add(json, "flags", json_flags);
}
@@ -2655,7 +2654,7 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
listcount(es->macip_global_path_list));
json_object_int_add(json, "inconsistentVniVtepCount",
es->incons_evi_vtep_cnt);
- if (es->flags & BGP_EVPNES_LOCAL)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
json_object_int_add(json, "localEsDfPreference",
es->df_pref);
if (listcount(es->es_vtep_list)) {
@@ -2673,7 +2672,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
}
if (es->inconsistencies) {
json_incons = json_object_new_array();
- if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
+ if (CHECK_FLAG(es->inconsistencies,
+ BGP_EVPNES_INCONS_VTEP_LIST))
json_array_string_add(json_incons,
"vni-vtep-mismatch");
json_object_object_add(json, "inconsistencies",
@@ -2684,9 +2684,9 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
char type_str[4];
type_str[0] = '\0';
- if (es->flags & BGP_EVPNES_LOCAL)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
strlcat(type_str, "L", sizeof(type_str));
- if (es->flags & BGP_EVPNES_REMOTE)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
strlcat(type_str, "R", sizeof(type_str));
vty_out(vty, "ESI: %s\n", es->esi_str);
@@ -2694,10 +2694,10 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
vty_out(vty, " RD: %pRDP\n",
es->es_base_frag ? &es->es_base_frag->prd : NULL);
vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip);
- if (es->flags & BGP_EVPNES_LOCAL)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
vty_out(vty, " Local ES DF preference: %u\n",
es->df_pref);
- if (es->flags & BGP_EVPNES_BYPASS)
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS))
vty_out(vty, " LACP bypass: on\n");
vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
vty_out(vty, " Remote VNI Count: %d\n",
@@ -2711,7 +2711,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
es->incons_evi_vtep_cnt);
if (es->inconsistencies) {
incons_str[0] = '\0';
- if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
+ if (CHECK_FLAG(es->inconsistencies,
+ BGP_EVPNES_INCONS_VTEP_LIST))
strlcat(incons_str, "vni-vtep-mismatch",
sizeof(incons_str));
} else {
@@ -2935,7 +2936,7 @@ static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf *es_vrf)
static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf)
{
- if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
+ if (!CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE))
return;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
@@ -2943,7 +2944,7 @@ static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf)
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;
+ UNSET_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE);
/* MAC-IPs can now be installed via the L3NHG */
bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg-deactivate");
}
@@ -2955,7 +2956,7 @@ static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update)
return;
}
- if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) {
+ if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE)) {
if (!update)
return;
} else {
@@ -2963,7 +2964,7 @@ static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update)
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;
+ SET_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE);
/* MAC-IPs can now be installed via the L3NHG */
bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg_activate");
}
@@ -3184,7 +3185,7 @@ void bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi, bool *use_l3nhg,
return;
*use_l3nhg = true;
- if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
+ if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE))
*is_l3nhg_active = true;
if (es_vrf_p)
*es_vrf_p = es_vrf;
@@ -3276,9 +3277,9 @@ static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
json_object_string_add(json, "esi", es->esi_str);
json_object_string_add(json, "vrf", bgp_vrf->name_pretty);
- if (es_vrf->flags & (BGP_EVPNES_VRF_NHG_ACTIVE)) {
+ if (CHECK_FLAG(es_vrf->flags, (BGP_EVPNES_VRF_NHG_ACTIVE))) {
json_types = json_object_new_array();
- if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
+ if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE))
json_array_string_add(json_types, "active");
json_object_object_add(json, "flags", json_types);
}
@@ -3290,7 +3291,7 @@ static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
char flags_str[4];
flags_str[0] = '\0';
- if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
+ if (CHECK_FLAG(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,
@@ -3400,7 +3401,7 @@ static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep *evi_vtep)
{
struct bgp_evpn_es_evi *es_evi = evi_vtep->es_evi;
- if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD))
+ if (CHECK_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD)))
/* as long as there is some reference we can't free it */
return;
@@ -3445,7 +3446,8 @@ bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
/* EAD-per-ES is sufficent to activate the PE */
ead_activity_flags = BGP_EVPN_EVI_VTEP_EAD_PER_ES;
- if ((evi_vtep->flags & ead_activity_flags) == ead_activity_flags)
+ if (CHECK_FLAG(evi_vtep->flags, ead_activity_flags) ==
+ ead_activity_flags)
SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
else
UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
@@ -3602,7 +3604,8 @@ bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi)
/* cannot free the element as long as there is a local or remote
* reference
*/
- if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE))
+ if (CHECK_FLAG(es_evi->flags,
+ (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE)))
return es_evi;
bgp_evpn_es_frag_evi_del(es_evi, false);
bgp_evpn_es_vrf_deref(es_evi);
@@ -3924,8 +3927,8 @@ static void bgp_evpn_remote_es_evi_flush(struct bgp_evpn_es_evi *es_evi)
/* delete all VTEPs */
for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list, node, nnode,
evi_vtep)) {
- evi_vtep->flags &= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES
- | BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
+ UNSET_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
+ BGP_EVPN_EVI_VTEP_EAD_PER_EVI));
bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
bgp_evpn_es_evi_vtep_free(evi_vtep);
}
@@ -3973,9 +3976,9 @@ static char *bgp_evpn_es_evi_vteps_str(char *vtep_str,
vtep_str[0] = '\0';
for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
vtep_flag_str[0] = '\0';
- if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
+ if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES))
strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
- if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
+ if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI))
strlcat(vtep_flag_str, "V", sizeof(vtep_flag_str));
if (!strnlen(vtep_flag_str, sizeof(vtep_flag_str)))
@@ -4006,12 +4009,12 @@ static void bgp_evpn_es_evi_json_vtep_fill(json_object *json_vteps,
json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4",
&evi_vtep->vtep_ip);
- if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
- BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) {
+ if (CHECK_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
+ BGP_EVPN_EVI_VTEP_EAD_PER_EVI))) {
json_flags = json_object_new_array();
- if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
+ if (CHECK_FLAG(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)
+ if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI))
json_array_string_add(json_flags, "ead-per-evi");
json_object_object_add(json_vtep_entry,
"flags", json_flags);
@@ -4035,12 +4038,12 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
if (es_evi->vpn)
json_object_int_add(json, "vni", es_evi->vpn->vni);
- if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL |
- BGP_EVPNES_EVI_REMOTE)) {
+ if (CHECK_FLAG(es_evi->flags, (BGP_EVPNES_EVI_LOCAL |
+ BGP_EVPNES_EVI_REMOTE))) {
json_types = json_object_new_array();
- if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
+ if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
json_array_string_add(json_types, "local");
- if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
+ if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE))
json_array_string_add(json_types, "remote");
json_object_object_add(json, "type", json_types);
}
@@ -4059,11 +4062,11 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
type_str[0] = '\0';
- if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
+ if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
strlcat(type_str, "L", sizeof(type_str));
- if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
+ if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE))
strlcat(type_str, "R", sizeof(type_str));
- if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST)
+ if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST))
strlcat(type_str, "I", sizeof(type_str));
bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
@@ -4090,7 +4093,7 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
json_object_string_addf(json, "esFragmentRd",
BGP_RD_AS_FORMAT(mode),
&es_evi->es_frag->prd);
- if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) {
+ if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST)) {
json_flags = json_object_new_array();
json_array_string_add(json_flags, "es-vtep-mismatch");
json_object_object_add(json, "flags", json_flags);
@@ -4100,9 +4103,9 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
char type_str[4];
type_str[0] = '\0';
- if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
+ if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
strlcat(type_str, "L", sizeof(type_str));
- if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
+ if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE))
strlcat(type_str, "R", sizeof(type_str));
bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
@@ -4119,8 +4122,10 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
vty_out(vty, "\n");
}
vty_out(vty, " Inconsistencies: %s\n",
- (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
- "es-vtep-mismatch":"-");
+ CHECK_FLAG(es_evi->flags,
+ BGP_EVPNES_EVI_INCONS_VTEP_LIST)
+ ? "es-vtep-mismatch"
+ : "-");
vty_out(vty, " VTEPs: %s\n", vtep_str);
vty_out(vty, "\n");
}
@@ -4514,12 +4519,12 @@ static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add)
static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh *nh, bool add)
{
if (add && !is_zero_mac(&nh->rmac)) {
- nh->flags |= BGP_EVPN_NH_READY_FOR_ZEBRA;
+ SET_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA);
bgp_evpn_nh_zebra_update_send(nh, true);
} else {
- if (!(nh->flags & BGP_EVPN_NH_READY_FOR_ZEBRA))
+ if (!CHECK_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA))
return;
- nh->flags &= ~BGP_EVPN_NH_READY_FOR_ZEBRA;
+ UNSET_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA);
bgp_evpn_nh_zebra_update_send(nh, false);
}
}
@@ -4811,7 +4816,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi)
/* if NHG is not being used for this path we don't need to manage the
* nexthops in bgp (they are managed by zebra instead)
*/
- if (!(pi->attr->es_flags & ATTR_ES_L3_NHG_USE)) {
+ if (!CHECK_FLAG(pi->attr->es_flags, ATTR_ES_L3_NHG_USE)) {
if (nh_info)
bgp_evpn_path_nh_unlink(nh_info);
return;
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index c28cdb4a65..958a9c6492 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -2561,7 +2561,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
- NULL, afi, safi, json, false);
+ NULL, afi, safi, json, false, true);
/* Display each path for this prefix. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
@@ -2663,7 +2663,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, dest, (struct prefix *)&p, NULL,
- afi, safi, json, false);
+ afi, safi, json, false, true);
evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
@@ -2798,7 +2798,7 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
- prd, afi, safi, json, false);
+ prd, afi, safi, json, false, false);
if (json)
json_paths = json_object_new_array();
@@ -2820,9 +2820,9 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
path_cnt++;
}
- if (json && path_cnt) {
+ if (json) {
if (path_cnt)
- json_object_object_addf(json, json_paths, "%pFX", &p);
+ json_object_object_add(json, "paths", json_paths);
json_object_int_add(json, "numPaths", path_cnt);
} else {
vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
@@ -2905,9 +2905,10 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
}
/* Prefix and num paths displayed once per prefix. */
- route_vty_out_detail_header(
- vty, bgp, dest, bgp_dest_get_prefix(dest), prd,
- afi, safi, json_prefix, false);
+ route_vty_out_detail_header(vty, bgp, dest,
+ bgp_dest_get_prefix(dest),
+ prd, afi, safi, json_prefix,
+ false, false);
prefix_cnt++;
}
@@ -3042,9 +3043,10 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
p->prefixlen);
} else
/* Prefix and num paths displayed once per prefix. */
- route_vty_out_detail_header(
- vty, bgp, dest, p, (struct prefix_rd *)rd_destp,
- AFI_L2VPN, SAFI_EVPN, json_prefix, false);
+ route_vty_out_detail_header(vty, bgp, dest, p,
+ (struct prefix_rd *)rd_destp,
+ AFI_L2VPN, SAFI_EVPN,
+ json_prefix, false, false);
/* For EVPN, the prefix is displayed for each path (to
* fit in with code that already exists).
@@ -3197,11 +3199,14 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
/* Prefix and num paths displayed once per prefix. */
if (detail)
- route_vty_out_detail_header(
- vty, bgp, dest,
- bgp_dest_get_prefix(dest),
- (struct prefix_rd *)rd_destp, AFI_L2VPN,
- SAFI_EVPN, json_prefix, false);
+ route_vty_out_detail_header(vty, bgp, dest,
+ bgp_dest_get_prefix(
+ dest),
+ (struct prefix_rd *)
+ rd_destp,
+ AFI_L2VPN, SAFI_EVPN,
+ json_prefix, false,
+ false);
/* For EVPN, the prefix is displayed for each path (to
* fit in
diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c
index 6165bf892e..bd04970fd5 100644
--- a/bgpd/bgp_flowspec.c
+++ b/bgpd/bgp_flowspec.c
@@ -195,7 +195,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
NULL, 0, 0, NULL);
} else {
bgp_withdraw(peer, &p, 0, afi, safi, ZEBRA_ROUTE_BGP,
- BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL);
+ BGP_ROUTE_NORMAL, NULL, NULL, 0);
}
XFREE(MTYPE_TMP, temp);
diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c
index 66426ab32f..31e14d41f7 100644
--- a/bgpd/bgp_flowspec_util.c
+++ b/bgpd/bgp_flowspec_util.c
@@ -305,14 +305,14 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
break;
mval->value = value;
if (op[5] == 1)
- mval->compare_operator |=
- OPERATOR_COMPARE_LESS_THAN;
+ SET_FLAG(mval->compare_operator,
+ OPERATOR_COMPARE_LESS_THAN);
if (op[6] == 1)
- mval->compare_operator |=
- OPERATOR_COMPARE_GREATER_THAN;
+ SET_FLAG(mval->compare_operator,
+ OPERATOR_COMPARE_GREATER_THAN);
if (op[7] == 1)
- mval->compare_operator |=
- OPERATOR_COMPARE_EQUAL_TO;
+ SET_FLAG(mval->compare_operator,
+ OPERATOR_COMPARE_EQUAL_TO);
if (op[1] == 1)
mval->unary_operator = OPERATOR_UNARY_AND;
else
@@ -413,16 +413,16 @@ int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
mval->value = value;
if (op[6] == 1) {
/* different from */
- mval->compare_operator |=
- OPERATOR_COMPARE_LESS_THAN;
- mval->compare_operator |=
- OPERATOR_COMPARE_GREATER_THAN;
+ SET_FLAG(mval->compare_operator,
+ OPERATOR_COMPARE_LESS_THAN);
+ SET_FLAG(mval->compare_operator,
+ OPERATOR_COMPARE_GREATER_THAN);
} else
- mval->compare_operator |=
- OPERATOR_COMPARE_EQUAL_TO;
+ SET_FLAG(mval->compare_operator,
+ OPERATOR_COMPARE_EQUAL_TO);
if (op[7] == 1)
- mval->compare_operator |=
- OPERATOR_COMPARE_EXACT_MATCH;
+ SET_FLAG(mval->compare_operator,
+ OPERATOR_COMPARE_EXACT_MATCH);
if (op[1] == 1)
mval->unary_operator =
OPERATOR_UNARY_AND;
@@ -467,11 +467,11 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
case FLOWSPEC_SRC_PREFIX:
bitmask = 0;
if (type == FLOWSPEC_DEST_PREFIX) {
- bitmask |= PREFIX_DST_PRESENT;
+ SET_FLAG(bitmask, PREFIX_DST_PRESENT);
prefix = &bpem->dst_prefix;
prefix_offset = &bpem->dst_prefix_offset;
} else {
- bitmask |= PREFIX_SRC_PRESENT;
+ SET_FLAG(bitmask, PREFIX_SRC_PRESENT);
prefix = &bpem->src_prefix;
prefix_offset = &bpem->src_prefix_offset;
}
@@ -491,14 +491,16 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
*/
if (prefix->family == AF_INET
&& prefix->u.prefix4.s_addr == INADDR_ANY)
- bpem->match_bitmask_iprule |= bitmask;
+ SET_FLAG(bpem->match_bitmask_iprule,
+ bitmask);
else if (prefix->family == AF_INET6
&& !memcmp(&prefix->u.prefix6,
&in6addr_any,
sizeof(struct in6_addr)))
- bpem->match_bitmask_iprule |= bitmask;
+ SET_FLAG(bpem->match_bitmask_iprule,
+ bitmask);
else
- bpem->match_bitmask |= bitmask;
+ SET_FLAG(bpem->match_bitmask, bitmask);
}
offset += ret;
break;
@@ -640,8 +642,8 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
|| bpem->match_dst_port_num || bpem->match_protocol_num
|| bpem->match_bitmask || bpem->match_flowlabel_num)
bpem->type = BGP_PBR_IPSET;
- else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) ||
- (bpem->match_bitmask_iprule & PREFIX_DST_PRESENT))
+ else if (CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_SRC_PRESENT) ||
+ CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_DST_PRESENT))
/* the extracted policy rule may not need an
* iptables/ipset filtering. check this may not be
* a standard ip rule : permit any to any ( eg)
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 98ebf51385..cdd9b7ae4d 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -696,9 +696,8 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
attr = *pi->attr;
bgp_attr_add_llgr_community(&attr);
pi->attr = bgp_attr_intern(&attr);
- bgp_recalculate_afi_safi_bestpaths(
- peer->bgp, afi, safi);
-
+ bgp_process(peer->bgp, rm, pi, afi,
+ safi);
break;
}
}
@@ -724,9 +723,7 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi)
attr = *pi->attr;
bgp_attr_add_llgr_community(&attr);
pi->attr = bgp_attr_intern(&attr);
- bgp_recalculate_afi_safi_bestpaths(peer->bgp,
- afi, safi);
-
+ bgp_process(peer->bgp, dest, pi, afi, safi);
break;
}
}
@@ -1802,18 +1799,14 @@ bgp_connect_fail(struct peer_connection *connection)
*/
static void bgp_connect_in_progress_update_connection(struct peer *peer)
{
- if (bgp_getsockname(peer) < 0) {
- if (!peer->su_remote &&
- !BGP_CONNECTION_SU_UNSPEC(peer->connection)) {
- /* if connect initiated, then dest port and dest addresses are well known */
- peer->su_remote = sockunion_dup(&peer->connection->su);
- if (sockunion_family(peer->su_remote) == AF_INET)
- peer->su_remote->sin.sin_port =
- htons(peer->port);
- else if (sockunion_family(peer->su_remote) == AF_INET6)
- peer->su_remote->sin6.sin6_port =
- htons(peer->port);
- }
+ bgp_updatesockname(peer);
+ if (!peer->su_remote && !BGP_CONNECTION_SU_UNSPEC(peer->connection)) {
+ /* if connect initiated, then dest port and dest addresses are well known */
+ peer->su_remote = sockunion_dup(&peer->connection->su);
+ if (sockunion_family(peer->su_remote) == AF_INET)
+ peer->su_remote->sin.sin_port = htons(peer->port);
+ else if (sockunion_family(peer->su_remote) == AF_INET6)
+ peer->su_remote->sin6.sin6_port = htons(peer->port);
}
}
@@ -2933,7 +2926,7 @@ static inline bool gr_mode_matches(enum peer_mode peer_gr_mode,
unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state,
enum peer_mode new_state)
{
- enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp);
+ enum global_mode global_gr_mode;
bool session_reset = true;
if (old_state == new_state)
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
index 839437e120..af10111600 100644
--- a/bgpd/bgp_label.c
+++ b/bgpd/bgp_label.c
@@ -208,7 +208,7 @@ mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi,
if (!dest || !pi || !to)
return MPLS_INVALID_LABEL;
- remote_label = bgp_path_info_num_labels(pi)
+ remote_label = BGP_PATH_INFO_NUM_LABELS(pi)
? pi->extra->labels->label[0]
: MPLS_INVALID_LABEL;
from = pi->peer;
@@ -576,7 +576,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
} else {
bgp_withdraw(peer, &p, addpath_id, packet->afi,
SAFI_UNICAST, ZEBRA_ROUTE_BGP,
- BGP_ROUTE_NORMAL, NULL, &label, 1, NULL);
+ BGP_ROUTE_NORMAL, NULL, &label, 1);
}
}
diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c
index 31e84d13c4..86d6281ed1 100644
--- a/bgpd/bgp_mac.c
+++ b/bgpd/bgp_mac.c
@@ -143,7 +143,6 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
const struct prefix *p = bgp_dest_get_prefix(dest);
struct prefix_evpn *pevpn = (struct prefix_evpn *)dest;
struct prefix_rd prd;
- struct bgp_route_evpn *evpn;
if (pevpn->family == AF_EVPN
&& pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
@@ -170,7 +169,7 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
&& !dest_affected)
continue;
- num_labels = bgp_path_info_num_labels(pi);
+ num_labels = BGP_PATH_INFO_NUM_LABELS(pi);
label_pnt = num_labels ? &pi->extra->labels->label[0]
: NULL;
@@ -195,12 +194,10 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
continue;
}
- memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
- sizeof(evpn));
bgp_update(peer, p, pi->addpath_rx_id, pi->attr,
AFI_L2VPN, SAFI_EVPN, ZEBRA_ROUTE_BGP,
- BGP_ROUTE_NORMAL, &prd, label_pnt,
- num_labels, 1, evpn);
+ BGP_ROUTE_NORMAL, &prd, label_pnt, num_labels,
+ 1, bgp_attr_get_evpn_overlay(pi->attr));
}
}
}
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 5e6a62c9b9..535d2fc5f4 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -63,18 +63,16 @@ DEFINE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled),
(vrf, enabled));
/* bgpd options, we use GNU getopt library. */
-static const struct option longopts[] = {
- { "bgp_port", required_argument, NULL, 'p' },
- { "listenon", required_argument, NULL, 'l' },
- { "no_kernel", no_argument, NULL, 'n' },
- { "skip_runas", no_argument, NULL, 'S' },
- { "ecmp", required_argument, NULL, 'e' },
- { "int_num", required_argument, NULL, 'I' },
- { "no_zebra", no_argument, NULL, 'Z' },
- { "socket_size", required_argument, NULL, 's' },
- { "v6-with-v4-nexthops", no_argument, NULL, 'v' },
- { 0 }
-};
+static const struct option longopts[] = { { "bgp_port", required_argument, NULL, 'p' },
+ { "listenon", required_argument, NULL, 'l' },
+ { "no_kernel", no_argument, NULL, 'n' },
+ { "skip_runas", no_argument, NULL, 'S' },
+ { "ecmp", required_argument, NULL, 'e' },
+ { "int_num", required_argument, NULL, 'I' },
+ { "no_zebra", no_argument, NULL, 'Z' },
+ { "socket_size", required_argument, NULL, 's' },
+ { "v6-with-v4-nexthops", no_argument, NULL, 'x' },
+ { 0 } };
/* signal definitions */
void sighup(void);
@@ -424,11 +422,12 @@ int main(int argc, char **argv)
int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
char *address;
struct listnode *node;
+ bool v6_with_v4_nexthops = false;
addresses->cmp = (int (*)(void *, void *))strcmp;
frr_preinit(&bgpd_di, argc, argv);
- frr_opt_add("p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts,
+ frr_opt_add("p:l:SnZe:I:s:x" DEPRECATED_OPTIONS, longopts,
" -p, --bgp_port Set BGP listen port number (0 means do not listen).\n"
" -l, --listenon Listen on specified address (implies -n)\n"
" -n, --no_kernel Do not install route to kernel.\n"
@@ -437,7 +436,7 @@ int main(int argc, char **argv)
" -e, --ecmp Specify ECMP to use.\n"
" -I, --int_num Set instance number (label-manager)\n"
" -s, --socket_size Set BGP peer socket send buffer size\n"
- " , --v6-with-v4-nexthop Allow BGP to form v6 neighbors using v4 nexthops\n");
+ " -x, --v6-with-v4-nexthop Allow BGP to form v6 neighbors using v4 nexthops\n");
/* Command line argument treatment. */
while (1) {
@@ -499,8 +498,8 @@ int main(int argc, char **argv)
case 's':
buffer_size = atoi(optarg);
break;
- case 'v':
- bm->v6_with_v4_nexthops = true;
+ case 'x':
+ v6_with_v4_nexthops = true;
break;
default:
frr_help_exit(1);
@@ -513,6 +512,7 @@ int main(int argc, char **argv)
bgp_master_init(frr_init(), buffer_size, addresses);
bm->startup_time = monotime(NULL);
bm->port = bgp_port;
+ bm->v6_with_v4_nexthops = v6_with_v4_nexthops;
if (bgp_port == 0)
bgp_option_set(BGP_OPT_NO_LISTEN);
if (no_fib_flag || no_zebra_flag)
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index c1804fb70a..c2599ade58 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -135,3 +135,5 @@ DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message");
DEFINE_MTYPE(BGPD, BGP_SOFT_VERSION, "Software Version");
+
+DEFINE_MTYPE(BGPD, BGP_EVPN_OVERLAY, "BGP EVPN Overlay");
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index 4ae49a2c17..1f76945da3 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -134,4 +134,6 @@ DECLARE_MTYPE(BGP_NOTIFICATION);
DECLARE_MTYPE(BGP_SOFT_VERSION);
+DECLARE_MTYPE(BGP_EVPN_OVERLAY);
+
#endif /* _QUAGGA_BGP_MEMORY_H */
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index eadd52b8e0..609afa4245 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -2,8 +2,10 @@
/*
* BGP Multipath
* Copyright (C) 2010 Google Inc.
+ * 2024 Nvidia Corporation
+ * Donald Sharp
*
- * This file is part of Quagga
+ * This file is part of FRR
*/
#include <zebra.h>
@@ -191,78 +193,6 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
}
/*
- * bgp_path_info_mpath_cmp
- *
- * This function determines our multipath list ordering. By ordering
- * the list we can deterministically select which paths are included
- * in the multipath set. The ordering also helps in detecting changes
- * in the multipath selection so we can detect whether to send an
- * update to zebra.
- *
- * The order of paths is determined first by received nexthop, and then
- * by peer address if the nexthops are the same.
- */
-static int bgp_path_info_mpath_cmp(void *val1, void *val2)
-{
- struct bgp_path_info *bpi1, *bpi2;
- int compare;
-
- bpi1 = val1;
- bpi2 = val2;
-
- compare = bgp_path_info_nexthop_cmp(bpi1, bpi2);
-
- if (!compare) {
- if (!bpi1->peer->su_remote && !bpi2->peer->su_remote)
- compare = 0;
- else if (!bpi1->peer->su_remote)
- compare = 1;
- else if (!bpi2->peer->su_remote)
- compare = -1;
- else
- compare = sockunion_cmp(bpi1->peer->su_remote,
- bpi2->peer->su_remote);
- }
-
- return compare;
-}
-
-/*
- * bgp_mp_list_init
- *
- * Initialize the mp_list, which holds the list of multipaths
- * selected by bgp_best_selection
- */
-void bgp_mp_list_init(struct list *mp_list)
-{
- assert(mp_list);
- memset(mp_list, 0, sizeof(struct list));
- mp_list->cmp = bgp_path_info_mpath_cmp;
-}
-
-/*
- * bgp_mp_list_clear
- *
- * Clears all entries out of the mp_list
- */
-void bgp_mp_list_clear(struct list *mp_list)
-{
- assert(mp_list);
- list_delete_all_node(mp_list);
-}
-
-/*
- * bgp_mp_list_add
- *
- * Adds a multipath entry to the mp_list
- */
-void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo)
-{
- assert(mp_list && mpinfo);
- listnode_add_sort(mp_list, mpinfo);
-}
-
-/*
* bgp_path_info_mpath_new
*
* Allocate and zero memory for a new bgp_path_info_mpath element
@@ -274,6 +204,7 @@ static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void)
new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
sizeof(struct bgp_path_info_mpath));
+ new_mpath->mp_count = 1;
return new_mpath;
}
@@ -287,6 +218,8 @@ void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath)
if (mpath && *mpath) {
if ((*mpath)->mp_attr)
bgp_attr_unintern(&(*mpath)->mp_attr);
+ (*mpath)->mp_attr = NULL;
+
XFREE(MTYPE_BGP_MPATH_INFO, *mpath);
}
}
@@ -314,58 +247,22 @@ bgp_path_info_mpath_get(struct bgp_path_info *path)
}
/*
- * bgp_path_info_mpath_enqueue
- *
- * Enqueue a path onto the multipath list given the previous multipath
- * list entry
- */
-static void bgp_path_info_mpath_enqueue(struct bgp_path_info *prev_info,
- struct bgp_path_info *path)
-{
- struct bgp_path_info_mpath *prev, *mpath;
-
- prev = bgp_path_info_mpath_get(prev_info);
- mpath = bgp_path_info_mpath_get(path);
- if (!prev || !mpath)
- return;
-
- mpath->mp_next = prev->mp_next;
- mpath->mp_prev = prev;
- if (prev->mp_next)
- prev->mp_next->mp_prev = mpath;
- prev->mp_next = mpath;
-
- SET_FLAG(path->flags, BGP_PATH_MULTIPATH);
-}
-
-/*
- * bgp_path_info_mpath_dequeue
- *
- * Remove a path from the multipath list
- */
-void bgp_path_info_mpath_dequeue(struct bgp_path_info *path)
-{
- struct bgp_path_info_mpath *mpath = path->mpath;
- if (!mpath)
- return;
- if (mpath->mp_prev)
- mpath->mp_prev->mp_next = mpath->mp_next;
- if (mpath->mp_next)
- mpath->mp_next->mp_prev = mpath->mp_prev;
- mpath->mp_next = mpath->mp_prev = NULL;
- UNSET_FLAG(path->flags, BGP_PATH_MULTIPATH);
-}
-
-/*
* bgp_path_info_mpath_next
*
* Given a bgp_path_info, return the next multipath entry
*/
struct bgp_path_info *bgp_path_info_mpath_next(struct bgp_path_info *path)
{
- if (!path->mpath || !path->mpath->mp_next)
- return NULL;
- return path->mpath->mp_next->mp_info;
+ path = path->next;
+
+ while (path) {
+ if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH))
+ return path;
+
+ path = path->next;
+ }
+
+ return NULL;
}
/*
@@ -386,7 +283,8 @@ struct bgp_path_info *bgp_path_info_mpath_first(struct bgp_path_info *path)
uint32_t bgp_path_info_mpath_count(struct bgp_path_info *path)
{
if (!path->mpath)
- return 0;
+ return 1;
+
return path->mpath->mp_count;
}
@@ -411,6 +309,10 @@ static void bgp_path_info_mpath_count_set(struct bgp_path_info *path,
* bgp_path_info_mpath_lb_update
*
* Update cumulative info related to link-bandwidth
+ *
+ * This is only set on the first mpath of the list
+ * as such we should UNSET the flags when removing
+ * to ensure nothing accidently happens
*/
static void bgp_path_info_mpath_lb_update(struct bgp_path_info *path, bool set,
bool all_paths_lb, uint64_t cum_bw)
@@ -472,10 +374,10 @@ bool bgp_path_info_mpath_chkwtd(struct bgp *bgp, struct bgp_path_info *path)
*/
if (bgp->lb_handling != BGP_LINK_BW_SKIP_MISSING &&
bgp->lb_handling != BGP_LINK_BW_DEFWT_4_MISSING)
- return (path->mpath->mp_flags & BGP_MP_LB_ALL);
+ return CHECK_FLAG(path->mpath->mp_flags, BGP_MP_LB_ALL);
/* At least one path should have bandwidth. */
- return (path->mpath->mp_flags & BGP_MP_LB_PRESENT);
+ return CHECK_FLAG(path->mpath->mp_flags, BGP_MP_LB_PRESENT);
}
/*
@@ -511,58 +413,51 @@ static void bgp_path_info_mpath_attr_set(struct bgp_path_info *path,
/*
* bgp_path_info_mpath_update
*
- * Compare and sync up the multipath list with the mp_list generated by
- * bgp_best_selection
+ * Compare and sync up the multipath flags with what was choosen
+ * in best selection
*/
void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
- struct bgp_path_info *new_best,
- struct bgp_path_info *old_best,
- struct list *mp_list,
- struct bgp_maxpaths_cfg *mpath_cfg)
+ struct bgp_path_info *new_best, struct bgp_path_info *old_best,
+ uint32_t num_candidates, struct bgp_maxpaths_cfg *mpath_cfg)
{
uint16_t maxpaths, mpath_count, old_mpath_count;
uint64_t bwval;
uint64_t cum_bw, old_cum_bw;
- struct listnode *mp_node, *mp_next_node;
- struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
- int mpath_changed, debug;
+ struct bgp_path_info *cur_iterator = NULL;
+ bool mpath_changed, debug;
bool all_paths_lb;
char path_buf[PATH_ADDPATH_STR_BUFFER];
+ bool old_mpath, new_mpath;
- mpath_changed = 0;
+ mpath_changed = false;
maxpaths = multipath_num;
mpath_count = 0;
- cur_mpath = NULL;
old_mpath_count = 0;
old_cum_bw = cum_bw = 0;
- prev_mpath = new_best;
- mp_node = listhead(mp_list);
debug = bgp_debug_bestpath(dest);
- if (new_best) {
- mpath_count++;
- if (new_best != old_best)
- bgp_path_info_mpath_dequeue(new_best);
- maxpaths = (new_best->peer->sort == BGP_PEER_IBGP)
- ? mpath_cfg->maxpaths_ibgp
- : mpath_cfg->maxpaths_ebgp;
- }
-
if (old_best) {
- cur_mpath = bgp_path_info_mpath_first(old_best);
old_mpath_count = bgp_path_info_mpath_count(old_best);
+ if (old_mpath_count == 1)
+ SET_FLAG(old_best->flags, BGP_PATH_MULTIPATH);
old_cum_bw = bgp_path_info_mpath_cumbw(old_best);
bgp_path_info_mpath_count_set(old_best, 0);
bgp_path_info_mpath_lb_update(old_best, false, false, 0);
- bgp_path_info_mpath_dequeue(old_best);
+ bgp_path_info_mpath_free(&old_best->mpath);
+ old_best->mpath = NULL;
+ }
+
+ if (new_best) {
+ maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ? mpath_cfg->maxpaths_ibgp
+ : mpath_cfg->maxpaths_ebgp;
+ cur_iterator = new_best;
}
if (debug)
- zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64,
- dest, bgp->name_pretty,
- new_best ? new_best->peer->host : "NONE",
- mp_list ? listcount(mp_list) : 0, old_mpath_count,
- old_cum_bw);
+ zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64
+ " maxpaths set %u",
+ dest, bgp->name_pretty, new_best ? new_best->peer->host : "NONE",
+ num_candidates, old_mpath_count, old_cum_bw, maxpaths);
/*
* We perform an ordered walk through both lists in parallel.
@@ -576,240 +471,106 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
* to skip over it
*/
all_paths_lb = true; /* We'll reset if any path doesn't have LB. */
- while (mp_node || cur_mpath) {
- struct bgp_path_info *tmp_info;
+ while (cur_iterator) {
+ old_mpath = CHECK_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
+ new_mpath = CHECK_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW);
+
+ UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW);
/*
- * We can bail out of this loop if all existing paths on the
- * multipath list have been visited (for cleanup purposes) and
- * the maxpath requirement is fulfulled
+ * If the current mpath count is equal to the number of
+ * maxpaths that can be used then we can bail, after
+ * we clean up the flags associated with the rest of the
+ * bestpaths
*/
- if (!cur_mpath && (mpath_count >= maxpaths))
- break;
+ if (mpath_count >= maxpaths) {
+ while (cur_iterator) {
+ UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
+ UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW);
+
+ cur_iterator = cur_iterator->next;
+ }
- mp_next_node = mp_node ? listnextnode(mp_node) : NULL;
- next_mpath =
- cur_mpath ? bgp_path_info_mpath_next(cur_mpath) : NULL;
- tmp_info = mp_node ? listgetdata(mp_node) : NULL;
+ if (debug)
+ zlog_debug("%pBD(%s): Mpath count %u is equal to maximum paths allowed, finished comparision for MPATHS",
+ dest, bgp->name_pretty, mpath_count);
- if (debug)
- zlog_debug("%pBD(%s): comparing candidate %s with existing mpath %s",
- dest, bgp->name_pretty,
- tmp_info ? tmp_info->peer->host : "NONE",
- cur_mpath ? cur_mpath->peer->host : "NONE");
+ break;
+ }
+ if (debug)
+ zlog_debug("%pBD(%s): Candidate %s old_mpath: %u new_mpath: %u, Nexthop %pI4 current mpath count: %u",
+ dest, bgp->name_pretty, cur_iterator->peer->host, old_mpath,
+ new_mpath, &cur_iterator->attr->nexthop, mpath_count);
/*
- * If equal, the path was a multipath and is still a multipath.
- * Insert onto new multipath list if maxpaths allows.
+ * There is nothing to do if the cur_iterator is neither a old path
+ * or a new path
*/
- if (mp_node && (listgetdata(mp_node) == cur_mpath)) {
- list_delete_node(mp_list, mp_node);
- bgp_path_info_mpath_dequeue(cur_mpath);
- if ((mpath_count < maxpaths) && prev_mpath) {
- mpath_count++;
- if (bgp_path_info_nexthop_cmp(prev_mpath,
- cur_mpath)) {
- if (ecommunity_linkbw_present(
- bgp_attr_get_ecommunity(
- cur_mpath->attr),
- &bwval) ||
- ecommunity_linkbw_present(
- bgp_attr_get_ipv6_ecommunity(
- cur_mpath->attr),
- &bwval))
- cum_bw += bwval;
- else
- all_paths_lb = false;
- if (debug) {
- bgp_path_info_path_with_addpath_rx_str(
- cur_mpath, path_buf,
- sizeof(path_buf));
- zlog_debug("%pBD: %s is still multipath, cur count %d",
- dest, path_buf,
- mpath_count);
- }
- } else {
- if (debug) {
- bgp_path_info_path_with_addpath_rx_str(
- cur_mpath, path_buf,
- sizeof(path_buf));
- zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d",
- dest, path_buf,
- &cur_mpath->attr->nexthop,
- mpath_count);
- }
- }
- bgp_path_info_mpath_enqueue(prev_mpath,
- cur_mpath);
- prev_mpath = cur_mpath;
- } else {
- mpath_changed = 1;
- if (debug) {
- bgp_path_info_path_with_addpath_rx_str(
- cur_mpath, path_buf,
- sizeof(path_buf));
- zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d",
- dest, path_buf,
- &cur_mpath->attr->nexthop,
- mpath_count);
- }
- }
- mp_node = mp_next_node;
- cur_mpath = next_mpath;
+ if (!old_mpath && !new_mpath) {
+ UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
+ cur_iterator = cur_iterator->next;
continue;
}
- if (cur_mpath
- && (!mp_node
- || (bgp_path_info_mpath_cmp(cur_mpath,
- listgetdata(mp_node))
- < 0))) {
- /*
- * If here, we have an old multipath and either the
- * mp_list
- * is finished or the next mp_node points to a later
- * multipath, so we need to purge this path from the
- * multipath list
- */
- bgp_path_info_mpath_dequeue(cur_mpath);
- mpath_changed = 1;
+ if (new_mpath) {
+ mpath_count++;
+
+ if (cur_iterator != new_best)
+ SET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
+
+ if (!old_mpath)
+ mpath_changed = true;
+
+ if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(cur_iterator->attr),
+ &bwval) ||
+ ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(
+ cur_iterator->attr),
+ &bwval))
+ cum_bw += bwval;
+ else
+ all_paths_lb = false;
+
if (debug) {
- bgp_path_info_path_with_addpath_rx_str(
- cur_mpath, path_buf, sizeof(path_buf));
- zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d",
- dest, path_buf,
- &cur_mpath->attr->nexthop,
- mpath_count);
+ bgp_path_info_path_with_addpath_rx_str(cur_iterator, path_buf,
+ sizeof(path_buf));
+ zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d cum_bw: %" PRIu64
+ " all_paths_lb: %u",
+ dest, path_buf, &cur_iterator->attr->nexthop,
+ mpath_count, cum_bw, all_paths_lb);
}
- cur_mpath = next_mpath;
} else {
/*
- * If here, we have a path on the mp_list that was not
- * previously
- * a multipath (due to non-equivalance or maxpaths
- * exceeded),
- * or the matching multipath is sorted later in the
- * multipath
- * list. Before we enqueue the path on the new multipath
- * list,
- * make sure its not on the old_best multipath list or
- * referenced
- * via next_mpath:
- * - If next_mpath points to this new path, update
- * next_mpath to
- * point to the multipath after this one
- * - Dequeue the path from the multipath list just to
- * make sure
+ * We know that old_mpath is true and new_mpath is false in this path
*/
- new_mpath = listgetdata(mp_node);
- list_delete_node(mp_list, mp_node);
- assert(new_mpath);
- assert(prev_mpath);
- if ((mpath_count < maxpaths) && (new_mpath != new_best)) {
- /* keep duplicate nexthop */
- bgp_path_info_mpath_dequeue(new_mpath);
-
- bgp_path_info_mpath_enqueue(prev_mpath,
- new_mpath);
- mpath_changed = 1;
- mpath_count++;
- if (bgp_path_info_nexthop_cmp(prev_mpath,
- new_mpath)) {
- if (ecommunity_linkbw_present(
- bgp_attr_get_ecommunity(
- new_mpath->attr),
- &bwval) ||
- ecommunity_linkbw_present(
- bgp_attr_get_ipv6_ecommunity(
- new_mpath->attr),
- &bwval))
- cum_bw += bwval;
- else
- all_paths_lb = false;
- if (debug) {
- bgp_path_info_path_with_addpath_rx_str(
- new_mpath, path_buf,
- sizeof(path_buf));
- zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d",
- dest, path_buf,
- &new_mpath->attr
- ->nexthop,
- mpath_count);
- }
- } else {
- if (debug) {
- bgp_path_info_path_with_addpath_rx_str(
- new_mpath, path_buf,
- sizeof(path_buf));
- zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d",
- dest, path_buf,
- &new_mpath->attr
- ->nexthop,
- mpath_count);
- }
- }
- prev_mpath = new_mpath;
- }
- mp_node = mp_next_node;
+ mpath_changed = true;
+ UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH);
}
+
+ cur_iterator = cur_iterator->next;
}
if (new_best) {
- bgp_path_info_mpath_count_set(new_best, mpath_count - 1);
- if (mpath_count <= 1 ||
- (!ecommunity_linkbw_present(bgp_attr_get_ecommunity(
- new_best->attr),
- &bwval) &&
- !ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(
- new_best->attr),
- &bwval)))
- all_paths_lb = false;
- else
- cum_bw += bwval;
- bgp_path_info_mpath_lb_update(new_best, true,
- all_paths_lb, cum_bw);
-
+ if (mpath_count > 1 || new_best->mpath) {
+ bgp_path_info_mpath_count_set(new_best, mpath_count);
+ bgp_path_info_mpath_lb_update(new_best, true, all_paths_lb, cum_bw);
+ }
if (debug)
zlog_debug("%pBD(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64,
dest, bgp->name_pretty, mpath_count,
mpath_changed ? "YES" : "NO", all_paths_lb,
cum_bw);
+ if (mpath_count == 1)
+ UNSET_FLAG(new_best->flags, BGP_PATH_MULTIPATH);
if (mpath_changed
|| (bgp_path_info_mpath_count(new_best) != old_mpath_count))
SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG);
- if ((mpath_count - 1) != old_mpath_count ||
- old_cum_bw != cum_bw)
+ if ((mpath_count) != old_mpath_count || old_cum_bw != cum_bw)
SET_FLAG(new_best->flags, BGP_PATH_LINK_BW_CHG);
}
}
/*
- * bgp_mp_dmed_deselect
- *
- * Clean up multipath information for BGP_PATH_DMED_SELECTED path that
- * is not selected as best path
- */
-void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best)
-{
- struct bgp_path_info *mpinfo, *mpnext;
-
- if (!dmed_best)
- return;
-
- for (mpinfo = bgp_path_info_mpath_first(dmed_best); mpinfo;
- mpinfo = mpnext) {
- mpnext = bgp_path_info_mpath_next(mpinfo);
- bgp_path_info_mpath_dequeue(mpinfo);
- }
-
- bgp_path_info_mpath_count_set(dmed_best, 0);
- UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG);
- UNSET_FLAG(dmed_best->flags, BGP_PATH_LINK_BW_CHG);
- assert(bgp_path_info_mpath_first(dmed_best) == NULL);
-}
-
-/*
* bgp_path_info_mpath_aggregate_update
*
* Set the multipath aggregate attribute. We need to see if the
@@ -843,7 +604,7 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
if (!new_best)
return;
- if (!bgp_path_info_mpath_count(new_best)) {
+ if (bgp_path_info_mpath_count(new_best) == 1) {
if ((new_attr = bgp_path_info_mpath_attr(new_best))) {
bgp_attr_unintern(&new_attr);
bgp_path_info_mpath_attr_set(new_best, NULL);
diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h
index 129682d1dc..c5a009a4c8 100644
--- a/bgpd/bgp_mpath.h
+++ b/bgpd/bgp_mpath.h
@@ -2,8 +2,9 @@
/*
* BGP Multipath
* Copyright (C) 2010 Google Inc.
+ * 2024 Nvidia Corporation
*
- * This file is part of Quagga
+ * This file is part of FRR
*/
#ifndef _FRR_BGP_MPATH_H
@@ -13,27 +14,24 @@
* multipath selections, lazily allocated to save memory
*/
struct bgp_path_info_mpath {
- /* Points to the first multipath (on bestpath) or the next multipath */
- struct bgp_path_info_mpath *mp_next;
-
- /* Points to the previous multipath or NULL on bestpath */
- struct bgp_path_info_mpath *mp_prev;
-
/* Points to bgp_path_info associated with this multipath info */
struct bgp_path_info *mp_info;
/* When attached to best path, the number of selected multipaths */
uint16_t mp_count;
- /* Flags - relevant as noted. */
+ /* Flags - relevant as noted, attached to bestpath. */
uint16_t mp_flags;
#define BGP_MP_LB_PRESENT 0x1 /* Link-bandwidth present for >= 1 path */
#define BGP_MP_LB_ALL 0x2 /* Link-bandwidth present for all multipaths */
- /* Aggregated attribute for advertising multipath route */
+ /*
+ * Aggregated attribute for advertising multipath route,
+ * attached to bestpath
+ */
struct attr *mp_attr;
- /* Cumulative bandiwdth of all multipaths - attached to best path. */
+ /* Cumulative bandiwdth of all multipaths - attached to bestpath. */
uint64_t cum_bw;
};
@@ -47,23 +45,16 @@ extern int bgp_maximum_paths_unset(struct bgp *bgp, afi_t afi, safi_t safi,
/* Functions used by bgp_best_selection to record current
* multipath selections
*/
-extern int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
- struct bgp_path_info *bpi2);
-extern void bgp_mp_list_init(struct list *mp_list);
-extern void bgp_mp_list_clear(struct list *mp_list);
-extern void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo);
-extern void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best);
+extern int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, struct bgp_path_info *bpi2);
extern void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *new_best,
- struct bgp_path_info *old_best,
- struct list *mp_list,
+ struct bgp_path_info *old_best, uint32_t num_candidates,
struct bgp_maxpaths_cfg *mpath_cfg);
extern void
bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
struct bgp_path_info *old_best);
/* Unlink and free multipath information associated with a bgp_path_info */
-extern void bgp_path_info_mpath_dequeue(struct bgp_path_info *path);
extern void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath);
/* Walk list of multipaths associated with a best path */
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index b03171b4c8..13da55ffb7 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -34,6 +34,7 @@
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_memory.h"
+#include "bgpd/bgp_aspath.h"
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
@@ -245,7 +246,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
} else {
bgp_withdraw(peer, &p, addpath_id, packet->afi,
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
- BGP_ROUTE_NORMAL, &prd, &label, 1, NULL);
+ BGP_ROUTE_NORMAL, &prd, &label, 1);
}
}
/* Packet length consistency check. */
@@ -304,7 +305,7 @@ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi)
if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) {
ifp = if_get_vrf_loopback(bgp->vrf_id);
- if (ifp && if_is_vrf(ifp) && if_is_up(ifp))
+ if (ifp && if_is_up(ifp))
label = bgp->vpn_policy[afi].tovpn_label;
}
@@ -385,6 +386,18 @@ void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi)
if (!vrf)
return;
+ if (bgp->vpn_policy[afi].tovpn_sid_locator) {
+ ctx.block_len =
+ bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length;
+ ctx.node_len =
+ bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
+ ctx.function_len =
+ bgp->vpn_policy[afi]
+ .tovpn_sid_locator->function_bits_length;
+ ctx.argument_len =
+ bgp->vpn_policy[afi]
+ .tovpn_sid_locator->argument_bits_length;
+ }
ctx.table = vrf->data.l.table_id;
act = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
: ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
@@ -436,6 +449,12 @@ void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp)
if (!vrf)
return;
+ if (bgp->tovpn_sid_locator) {
+ ctx.block_len = bgp->tovpn_sid_locator->block_bits_length;
+ ctx.node_len = bgp->tovpn_sid_locator->node_bits_length;
+ ctx.function_len = bgp->tovpn_sid_locator->function_bits_length;
+ ctx.argument_len = bgp->tovpn_sid_locator->argument_bits_length;
+ }
ctx.table = vrf->data.l.table_id;
act = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx);
@@ -474,6 +493,8 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
+ struct srv6_sid_ctx ctx = {};
+ struct seg6local_context seg6localctx = {};
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
@@ -486,12 +507,30 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
zlog_debug("%s: deleting sid for vrf %s afi (id=%d)", __func__,
bgp->name_pretty, bgp->vrf_id);
+ if (bgp->vpn_policy[afi].tovpn_sid_locator) {
+ seg6localctx.block_len =
+ bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length;
+ seg6localctx.node_len =
+ bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length;
+ seg6localctx.function_len =
+ bgp->vpn_policy[afi]
+ .tovpn_sid_locator->function_bits_length;
+ seg6localctx.argument_len =
+ bgp->vpn_policy[afi]
+ .tovpn_sid_locator->argument_bits_length;
+ }
zclient_send_localsid(zclient,
- bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent,
- bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL);
+ bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent,
+ bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
+ &seg6localctx);
XFREE(MTYPE_BGP_SRV6_SID,
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = NULL;
+
+ ctx.vrf_id = bgp->vrf_id;
+ ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
+ : ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
+ bgp_zebra_release_srv6_sid(&ctx);
}
/*
@@ -501,6 +540,8 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
+ struct srv6_sid_ctx ctx = {};
+ struct seg6local_context seg6localctx = {};
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
@@ -514,11 +555,24 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
zlog_debug("%s: deleting sid for vrf %s (id=%d)", __func__,
bgp->name_pretty, bgp->vrf_id);
+ if (bgp->tovpn_sid_locator) {
+ seg6localctx.block_len =
+ bgp->tovpn_sid_locator->block_bits_length;
+ seg6localctx.node_len = bgp->tovpn_sid_locator->node_bits_length;
+ seg6localctx.function_len =
+ bgp->tovpn_sid_locator->function_bits_length;
+ seg6localctx.argument_len =
+ bgp->tovpn_sid_locator->argument_bits_length;
+ }
zclient_send_localsid(zclient, bgp->tovpn_zebra_vrf_sid_last_sent,
bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
- NULL);
+ &seg6localctx);
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
bgp->tovpn_zebra_vrf_sid_last_sent = NULL;
+
+ ctx.vrf_id = bgp->vrf_id;
+ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
+ bgp_zebra_release_srv6_sid(&ctx);
}
/*
@@ -595,8 +649,8 @@ int vpn_leak_label_callback(
return 0;
}
-static void sid_register(struct bgp *bgp, const struct in6_addr *sid,
- const char *locator_name)
+void sid_register(struct bgp *bgp, const struct in6_addr *sid,
+ const char *locator_name)
{
struct bgp_srv6_function *func;
func = XCALLOC(MTYPE_BGP_SRV6_FUNCTION,
@@ -635,108 +689,97 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
return false;
}
-/*
- * This function generates a new SID based on bgp->srv6_locator_chunks and
- * index. The locator and generated SID are stored in arguments sid_locator
- * and sid, respectively.
+/**
+ * Return the SRv6 SID value obtained by composing the LOCATOR and FUNCTION.
*
- * if index != 0: try to allocate as index-mode
- * else: try to allocate as auto-mode
+ * @param sid_value SRv6 SID value returned
+ * @param locator Parent locator of the SRv6 SID
+ * @param sid_func Function part of the SID
+ * @return True if success, False otherwise
*/
-static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
- struct srv6_locator_chunk *sid_locator_chunk,
- struct in6_addr *sid)
+static bool srv6_sid_compose(struct in6_addr *sid_value,
+ struct srv6_locator *locator, uint32_t sid_func)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
- struct listnode *node;
- struct srv6_locator_chunk *chunk;
- bool alloced = false;
int label = 0;
uint8_t offset = 0;
uint8_t func_len = 0, shift_len = 0;
- uint32_t index_max = 0;
+ uint32_t sid_func_max = 0;
- if (!bgp || !sid_locator_chunk || !sid)
+ if (!locator || !sid_value)
return false;
- for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
- if (chunk->function_bits_length >
- BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
- if (debug)
- zlog_debug(
- "%s: invalid SRv6 Locator chunk (%pFX): Function Length must be less or equal to %d",
- __func__, &chunk->prefix,
- BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH);
- continue;
- }
+ if (locator->function_bits_length >
+ BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
+ if (debug)
+ zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length must be less or equal to %d",
+ __func__, &locator->prefix,
+ BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH);
+ return false;
+ }
- index_max = (1 << chunk->function_bits_length) - 1;
+ /* Max value that can be encoded in the Function part of the SID */
+ sid_func_max = (1 << locator->function_bits_length) - 1;
- if (index > index_max) {
- if (debug)
- zlog_debug(
- "%s: skipped SRv6 Locator chunk (%pFX): Function Length is too short to support specified index (%u)",
- __func__, &chunk->prefix, index);
- continue;
- }
+ if (sid_func > sid_func_max) {
+ if (debug)
+ zlog_debug("%s: invalid SRv6 Locator (%pFX): Function Length is too short to support specified function (%u)",
+ __func__, &locator->prefix, sid_func);
+ return false;
+ }
- *sid = chunk->prefix.prefix;
- *sid_locator_chunk = *chunk;
- offset = chunk->block_bits_length + chunk->node_bits_length;
- func_len = chunk->function_bits_length;
- shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;
+ /**
+ * Let's build the SID value.
+ * sid_value = LOC:FUNC::
+ */
- if (index != 0) {
- label = index << shift_len;
- if (label < MPLS_LABEL_UNRESERVED_MIN) {
- if (debug)
- zlog_debug(
- "%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
- __func__, &chunk->prefix,
- label);
- continue;
- }
+ /* First, we put the locator (LOC) in the most significant bits of sid_value */
+ *sid_value = locator->prefix.prefix;
- transpose_sid(sid, label, offset, func_len);
- if (sid_exist(bgp, sid))
- continue;
- alloced = true;
- break;
- }
+ /*
+ * Then, we compute the offset at which we have to place the function (FUNC).
+ * FUNC will be placed immediately after LOC, i.e. at block_bits_length + node_bits_length
+ */
+ offset = locator->block_bits_length + locator->node_bits_length;
- for (uint32_t i = 1; i < index_max; i++) {
- label = i << shift_len;
- if (label < MPLS_LABEL_UNRESERVED_MIN) {
- if (debug)
- zlog_debug(
- "%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
- __func__, &chunk->prefix,
- label);
- continue;
- }
- transpose_sid(sid, label, offset, func_len);
- if (sid_exist(bgp, sid))
- continue;
- alloced = true;
- break;
- }
+ /*
+ * The FUNC part of the SID is advertised in the label field of SRv6 Service TLV.
+ * (see SID Transposition Scheme, RFC 9252 section #4).
+ * Therefore, we need to encode the FUNC in the most significant bits of the
+ * 20-bit label.
+ */
+ func_len = locator->function_bits_length;
+ shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;
+
+ label = sid_func << shift_len;
+ if (label < MPLS_LABEL_UNRESERVED_MIN) {
+ if (debug)
+ zlog_debug("%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
+ __func__, &locator->prefix, label);
+ return false;
}
- if (!alloced)
- return 0;
+ if (sid_exist(bgp_get_default(), sid_value)) {
+ zlog_warn("%s: skipped to allocate SRv6 SID (%pFX): SID %pI6 already in use",
+ __func__, &locator->prefix, sid_value);
+ return false;
+ }
- sid_register(bgp, sid, bgp->srv6_locator_name);
- return label;
+ /* Finally, we put the FUNC in sid_value at the computed offset */
+ transpose_sid(sid_value, label, offset, func_len);
+
+ return true;
}
void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
- struct srv6_locator_chunk *tovpn_sid_locator;
- struct in6_addr *tovpn_sid;
- uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
+ struct in6_addr tovpn_sid = {};
+ uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false;
+ struct srv6_sid_ctx ctx = {};
+ uint32_t sid_func;
if (debug)
zlog_debug("%s: try to allocate new SID for vrf %s: afi %s",
@@ -748,11 +791,18 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
/*
* skip when bgp vpn instance ins't allocated
- * or srv6 locator chunk isn't allocated
+ * or srv6 locator isn't allocated
*/
- if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks)
+ if (!bgp_vpn || !bgp_vpn->srv6_locator)
return;
+ if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
+ if (debug)
+ zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf SRv6 SID",
+ __func__, bgp_vrf->name_pretty);
+ return;
+ }
+
tovpn_sid_index = bgp_vrf->vpn_policy[afi].tovpn_sid_index;
tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_SID_AUTO);
@@ -768,40 +818,34 @@ void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
return;
}
- tovpn_sid_locator = srv6_locator_chunk_alloc();
- tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
-
- tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
- tovpn_sid_locator, tovpn_sid);
+ if (!tovpn_sid_auto) {
+ if (!srv6_sid_compose(&tovpn_sid, bgp_vpn->srv6_locator,
+ tovpn_sid_index)) {
+ zlog_err("%s: failed to compose sid for vrf %s: afi %s",
+ __func__, bgp_vrf->name_pretty, afi2str(afi));
+ return;
+ }
+ }
- if (tovpn_sid_transpose_label == 0) {
- if (debug)
- zlog_debug(
- "%s: not allocated new sid for vrf %s: afi %s",
- __func__, bgp_vrf->name_pretty, afi2str(afi));
- srv6_locator_chunk_free(&tovpn_sid_locator);
- XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
+ ctx.vrf_id = bgp_vrf->vrf_id;
+ ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
+ : ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
+ if (!bgp_zebra_request_srv6_sid(&ctx, &tovpn_sid,
+ bgp_vpn->srv6_locator_name, &sid_func)) {
+ zlog_err("%s: failed to request sid for vrf %s: afi %s",
+ __func__, bgp_vrf->name_pretty, afi2str(afi));
return;
}
-
- if (debug)
- zlog_debug("%s: new sid %pI6 allocated for vrf %s: afi %s",
- __func__, tovpn_sid, bgp_vrf->name_pretty,
- afi2str(afi));
-
- bgp_vrf->vpn_policy[afi].tovpn_sid = tovpn_sid;
- bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator;
- bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label =
- tovpn_sid_transpose_label;
}
void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
- struct srv6_locator_chunk *tovpn_sid_locator;
- struct in6_addr *tovpn_sid;
- uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
+ struct in6_addr tovpn_sid = {};
+ uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false;
+ struct srv6_sid_ctx ctx = {};
+ uint32_t sid_func;
if (debug)
zlog_debug("%s: try to allocate new SID for vrf %s", __func__,
@@ -813,10 +857,17 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
/*
* skip when bgp vpn instance ins't allocated
- * or srv6 locator chunk isn't allocated
+ * or srv6 locator isn't allocated
*/
- if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks)
+ if (!bgp_vpn || !bgp_vpn->srv6_locator)
+ return;
+
+ if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
+ if (debug)
+ zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf SRv6 SID",
+ __func__, bgp_vrf->name_pretty);
return;
+ }
tovpn_sid_index = bgp_vrf->tovpn_sid_index;
tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO);
@@ -832,28 +883,23 @@ void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
return;
}
- tovpn_sid_locator = srv6_locator_chunk_alloc();
- tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
-
- tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
- tovpn_sid_locator, tovpn_sid);
+ if (!tovpn_sid_auto) {
+ if (!srv6_sid_compose(&tovpn_sid, bgp_vpn->srv6_locator,
+ bgp_vrf->tovpn_sid_index)) {
+ zlog_err("%s: failed to compose new sid for vrf %s",
+ __func__, bgp_vrf->name_pretty);
+ return;
+ }
+ }
- if (tovpn_sid_transpose_label == 0) {
- if (debug)
- zlog_debug("%s: not allocated new sid for vrf %s",
- __func__, bgp_vrf->name_pretty);
- srv6_locator_chunk_free(&tovpn_sid_locator);
- XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
+ ctx.vrf_id = bgp_vrf->vrf_id;
+ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
+ if (!bgp_zebra_request_srv6_sid(&ctx, &tovpn_sid,
+ bgp_vpn->srv6_locator_name, &sid_func)) {
+ zlog_err("%s: failed to request new sid for vrf %s", __func__,
+ bgp_vrf->name_pretty);
return;
}
-
- if (debug)
- zlog_debug("%s: new sid %pI6 allocated for vrf %s", __func__,
- tovpn_sid, bgp_vrf->name_pretty);
-
- bgp_vrf->tovpn_sid = tovpn_sid;
- bgp_vrf->tovpn_sid_locator = tovpn_sid_locator;
- bgp_vrf->tovpn_sid_transpose_label = tovpn_sid_transpose_label;
}
void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
@@ -876,6 +922,7 @@ void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false;
+ struct srv6_sid_ctx ctx = {};
if (debug)
zlog_debug("%s: try to remove SID for vrf %s: afi %s", __func__,
@@ -889,9 +936,22 @@ void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
if (tovpn_sid_index != 0 || tovpn_sid_auto)
return;
- srv6_locator_chunk_free(&bgp_vrf->vpn_policy[afi].tovpn_sid_locator);
+ if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
+ if (debug)
+ zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf label",
+ __func__, bgp_vrf->name_pretty);
+ return;
+ }
+
+ srv6_locator_free(bgp_vrf->vpn_policy[afi].tovpn_sid_locator);
+ bgp_vrf->vpn_policy[afi].tovpn_sid_locator = NULL;
if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
+ ctx.vrf_id = bgp_vrf->vrf_id;
+ ctx.behavior = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4
+ : ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
+ bgp_zebra_release_srv6_sid(&ctx);
+
sid_unregister(bgp_vpn, bgp_vrf->vpn_policy[afi].tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->vpn_policy[afi].tovpn_sid);
}
@@ -903,6 +963,7 @@ void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
uint32_t tovpn_sid_index = 0;
bool tovpn_sid_auto = false;
+ struct srv6_sid_ctx ctx = {};
if (debug)
zlog_debug("%s: try to remove SID for vrf %s", __func__,
@@ -916,9 +977,21 @@ void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
if (tovpn_sid_index != 0 || tovpn_sid_auto)
return;
- srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator);
+ if (bgp_vrf->vrf_id == VRF_UNKNOWN) {
+ if (debug)
+ zlog_debug("%s: vrf %s: vrf_id not set, can't set zebra vrf label",
+ __func__, bgp_vrf->name_pretty);
+ return;
+ }
+
+ srv6_locator_free(bgp_vrf->tovpn_sid_locator);
+ bgp_vrf->tovpn_sid_locator = NULL;
if (bgp_vrf->tovpn_sid) {
+ ctx.vrf_id = bgp_vrf->vrf_id;
+ ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
+ bgp_zebra_release_srv6_sid(&ctx);
+
sid_unregister(bgp_vpn, bgp_vrf->tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
}
@@ -1763,8 +1836,9 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
/* Set SID for SRv6 VPN */
if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
- struct srv6_locator_chunk *locator =
+ struct srv6_locator *locator =
from_bgp->vpn_policy[afi].tovpn_sid_locator;
+
encode_label(
from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
&label);
@@ -1805,8 +1879,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
.tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
} else if (from_bgp->tovpn_sid_locator) {
- struct srv6_locator_chunk *locator =
- from_bgp->tovpn_sid_locator;
+ struct srv6_locator *locator = from_bgp->tovpn_sid_locator;
+
encode_label(from_bgp->tovpn_sid_transpose_label, &label);
static_attr.srv6_l3vpn =
XCALLOC(MTYPE_BGP_SRV6_L3VPN,
@@ -2083,6 +2157,7 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
struct bgp *src_vrf;
struct interface *ifp = NULL;
char rd_buf[RD_ADDRSTRLEN];
+ struct aspath *new_aspath;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
@@ -2140,6 +2215,32 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return;
}
+ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);
+
+ /* Check if leaked route has our asn. If so, don't import it. */
+ if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as)) {
+ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
+ bpi = bpi->next) {
+ if (bpi->extra && bpi->extra->vrfleak &&
+ (struct bgp_path_info *)bpi->extra->vrfleak->parent ==
+ path_vpn) {
+ break;
+ }
+ }
+
+ if (bpi) {
+ if (debug)
+ zlog_debug("%s: blocking import of %p, as-path match",
+ __func__, bpi);
+ bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
+ bgp_path_info_delete(bn, bpi);
+ bgp_process(to_bgp, bn, bpi, afi, safi);
+ }
+ bgp_dest_unlock_node(bn);
+
+ return;
+ }
+
if (debug)
zlog_debug("%s: updating RD %s, %pFX to %s", __func__, rd_buf,
p, to_bgp->name_pretty);
@@ -2292,6 +2393,21 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
nexthop_self_flag = 0;
}
+ /*
+ * if the asn values are different, copy the asn of the source vrf
+ * into the entry before importing. This helps with as-path loop
+ * detection
+ */
+ if (path_vpn->extra && path_vpn->extra->vrfleak &&
+ path_vpn->extra->vrfleak->bgp_orig &&
+ (to_bgp->as != path_vpn->extra->vrfleak->bgp_orig->as)) {
+ new_aspath = aspath_dup(static_attr.aspath);
+ new_aspath =
+ aspath_add_seq(new_aspath,
+ path_vpn->extra->vrfleak->bgp_orig->as);
+ static_attr.aspath = new_aspath;
+ }
+
new_attr = bgp_attr_intern(&static_attr);
bgp_attr_flush(&static_attr);
@@ -2322,7 +2438,7 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
}
num_labels = origin_local ? 0
- : bgp_path_info_num_labels(path_vpn);
+ : BGP_PATH_INFO_NUM_LABELS(path_vpn);
label_pnt = num_labels ? path_vpn->extra->labels->label : NULL;
}
@@ -3793,7 +3909,8 @@ void bgp_vpn_leak_unimport(struct bgp *from_bgp)
bool is_vrf_leak_bind;
int debug;
- if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF &&
+ from_bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
return;
debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
@@ -4212,7 +4329,7 @@ void bgp_mplsvpn_nh_label_bind_register_local_label(struct bgp *bgp,
struct bgp_mplsvpn_nh_label_bind_cache_head *tree;
mpls_label_t label;
- label = bgp_path_info_num_labels(pi)
+ label = BGP_PATH_INFO_NUM_LABELS(pi)
? decode_label(&pi->extra->labels->label[0])
: MPLS_INVALID_LABEL;
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index 92a9fba887..39fed66781 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -419,6 +419,8 @@ struct bgp_mplsvpn_nh_label_bind_cache *bgp_mplsvpn_nh_label_bind_find(
struct bgp_mplsvpn_nh_label_bind_cache_head *tree, struct prefix *p,
mpls_label_t orig_label);
void bgp_mplsvpn_nexthop_init(void);
+extern void sid_register(struct bgp *bgp, const struct in6_addr *sid,
+ const char *locator_name);
extern void sid_unregister(struct bgp *bgp, const struct in6_addr *sid);
#endif /* _QUAGGA_BGP_MPLSVPN_H */
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index e09dbc22af..de57d91806 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -861,8 +861,7 @@ int bgp_connect(struct peer_connection *connection)
htons(peer->port), ifindex);
}
-/* After TCP connection is established. Get local address and port. */
-int bgp_getsockname(struct peer *peer)
+void bgp_updatesockname(struct peer *peer)
{
if (peer->su_local) {
sockunion_free(peer->su_local);
@@ -876,6 +875,12 @@ int bgp_getsockname(struct peer *peer)
peer->su_local = sockunion_getsockname(peer->connection->fd);
peer->su_remote = sockunion_getpeername(peer->connection->fd);
+}
+
+/* After TCP connection is established. Get local address and port. */
+int bgp_getsockname(struct peer *peer)
+{
+ bgp_updatesockname(peer);
if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote,
&peer->nexthop, peer)) {
diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h
index 7a0b3cc67d..ceb6b6f002 100644
--- a/bgpd/bgp_network.h
+++ b/bgpd/bgp_network.h
@@ -23,6 +23,7 @@ extern void bgp_close_vrf_socket(struct bgp *bgp);
extern void bgp_close(void);
extern int bgp_connect(struct peer_connection *connection);
extern int bgp_getsockname(struct peer *peer);
+extern void bgp_updatesockname(struct peer *peer);
extern int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p,
const char *password);
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
index 430c8f17e8..0280960da8 100644
--- a/bgpd/bgp_nexthop.h
+++ b/bgpd/bgp_nexthop.h
@@ -66,6 +66,7 @@ struct bgp_nexthop_cache {
#define BGP_STATIC_ROUTE (1 << 4)
#define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5)
#define BGP_NEXTHOP_LABELED_VALID (1 << 6)
+#define BGP_NEXTHOP_ULTIMATE (1 << 7)
/*
* This flag is added for EVPN gateway IP nexthops.
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 67e7463fe4..49042e8c23 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -320,6 +320,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
afi = BGP_ATTR_MP_NEXTHOP_LEN_IP6(pi->attr) ? AFI_IP6
: AFI_IP;
+ /* Validation for the ipv4 mapped ipv6 nexthop. */
+ if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
+ afi = AFI_IP;
+ }
+
/* This will return true if the global IPv6 NH is a link local
* addr */
if (make_prefix(afi, pi, &p) < 0)
@@ -342,18 +347,15 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
&p.u.prefix6))
ifindex = pi->peer->connection->su.sin6.sin6_scope_id;
- if (!is_bgp_static_route && orig_prefix
- && prefix_same(&p, orig_prefix)) {
+ if (!is_bgp_static_route && orig_prefix && prefix_same(&p, orig_prefix) &&
+ CHECK_FLAG(bgp_route->flags, BGP_FLAG_IMPORT_CHECK)) {
if (BGP_DEBUG(nht, NHT)) {
- zlog_debug(
- "%s(%pFX): prefix loops through itself",
- __func__, &p);
+ zlog_debug("%s(%pFX): prefix loops through itself (import-check enabled)",
+ __func__, &p);
}
return 0;
}
- if (afi == AFI_IP6 && p.family == AF_INET)
- /* IPv4 mapped IPv6 nexthop address */
- afi = AFI_IP;
+
srte_color = bgp_attr_get_color(pi->attr);
} else if (peer) {
@@ -402,12 +404,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
peer);
} else {
if (BGP_DEBUG(nht, NHT))
- zlog_debug(
- "Found existing bnc %pFX(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p",
- &bnc->prefix, bnc->ifindex_ipv6_ll,
- bnc->bgp->name_pretty, bnc->flags,
- bnc->ifindex_ipv6_ll, bnc->path_count,
- bnc->nht_info);
+ zlog_debug("Found existing bnc %pFX(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p, resolved prefix %pFX",
+ &bnc->prefix, bnc->ifindex_ipv6_ll,
+ bnc->bgp->name_pretty, bnc->flags,
+ bnc->ifindex_ipv6_ll, bnc->path_count,
+ bnc->nht_info, &bnc->resolved_prefix);
}
if (pi && is_route_parent_evpn(pi))
@@ -482,6 +483,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
bnc->metric;
else if (bpi_ultimate->extra)
bpi_ultimate->extra->igpmetric = 0;
+
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_ULTIMATE);
} else if (peer) {
/*
* Let's not accidentally save the peer data for a peer
@@ -502,7 +505,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
return 1;
else if (safi == SAFI_UNICAST && pi &&
pi->sub_type == BGP_ROUTE_IMPORTED &&
- bgp_path_info_num_labels(pi) && !bnc->is_evpn_gwip_nexthop)
+ CHECK_FLAG(bnc->flags, BGP_NEXTHOP_ULTIMATE))
+ return bgp_isvalid_nexthop(bnc);
+ else if (safi == SAFI_UNICAST && pi &&
+ pi->sub_type == BGP_ROUTE_IMPORTED &&
+ BGP_PATH_INFO_NUM_LABELS(pi) && !bnc->is_evpn_gwip_nexthop)
return bgp_isvalid_nexthop_for_l3vpn(bnc, pi);
else if (safi == SAFI_MPLS_VPN && pi &&
pi->sub_type != BGP_ROUTE_IMPORTED)
@@ -599,10 +606,10 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
}
if (nhr->metric != bnc->metric)
- bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
+ SET_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED);
if (nhr->nexthop_num != bnc->nexthop_num)
- bnc->change_flags |= BGP_NEXTHOP_CHANGED;
+ SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
if (import_check && (nhr->type == ZEBRA_ROUTE_BGP ||
!prefix_same(&bnc->prefix, &nhr->prefix))) {
@@ -628,11 +635,12 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
if (!bnc->is_evpn_gwip_nexthop)
- bnc->flags |= BGP_NEXTHOP_VALID;
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
bnc->metric = nhr->metric;
bnc->nexthop_num = nhr->nexthop_num;
- bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */
+ UNSET_FLAG(bnc->flags,
+ BGP_NEXTHOP_LABELED_VALID); /* check below */
for (i = 0; i < nhr->nexthop_num; i++) {
int num_labels = 0;
@@ -662,8 +670,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
/* There is at least one label-switched path */
if (nexthop->nh_label &&
nexthop->nh_label->num_labels) {
-
- bnc->flags |= BGP_NEXTHOP_LABELED_VALID;
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID);
num_labels = nexthop->nh_label->num_labels;
}
@@ -687,7 +694,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
* determined
* that there has been a change.
*/
- if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
+ if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
continue;
for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
@@ -695,7 +702,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
break;
if (!oldnh)
- bnc->change_flags |= BGP_NEXTHOP_CHANGED;
+ SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
}
bnc_nexthop_free(bnc);
bnc->nexthop = nhlist_head;
@@ -719,19 +726,22 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
: "failed"));
if (evpn_resolved) {
- bnc->flags |= BGP_NEXTHOP_VALID;
- bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
- bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+ UNSET_FLAG(bnc->flags,
+ BGP_NEXTHOP_EVPN_INCOMPLETE);
+ SET_FLAG(bnc->change_flags,
+ BGP_NEXTHOP_MACIP_CHANGED);
} else {
- bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE;
- bnc->flags &= ~BGP_NEXTHOP_VALID;
+ SET_FLAG(bnc->flags,
+ BGP_NEXTHOP_EVPN_INCOMPLETE);
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
}
}
} else {
memset(&bnc->resolved_prefix, 0, sizeof(bnc->resolved_prefix));
- bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
- bnc->flags &= ~BGP_NEXTHOP_VALID;
- bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID;
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID);
bnc->nexthop_num = nhr->nexthop_num;
/* notify bgp fsm if nbr ip goes from valid->invalid */
@@ -1037,11 +1047,19 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
p->u.prefix4 = p_orig->u.prefix4;
p->prefixlen = p_orig->prefixlen;
} else {
- if (p_orig->family == AF_EVPN)
- p->u.prefix4 = pi->attr->mp_nexthop_global_in;
- else
- p->u.prefix4 = pi->attr->nexthop;
- p->prefixlen = IPV4_MAX_BITLEN;
+ if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
+ ipv4_mapped_ipv6_to_ipv4(
+ &pi->attr->mp_nexthop_global, &ipv4);
+ p->u.prefix4 = ipv4;
+ p->prefixlen = IPV4_MAX_BITLEN;
+ } else {
+ if (p_orig->family == AF_EVPN)
+ p->u.prefix4 =
+ pi->attr->mp_nexthop_global_in;
+ else
+ p->u.prefix4 = pi->attr->nexthop;
+ p->prefixlen = IPV4_MAX_BITLEN;
+ }
}
break;
case AFI_IP6:
@@ -1057,7 +1075,6 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
/* If we receive MP_REACH nexthop with ::(LL)
* or LL(LL), use LL address as nexthop cache.
*/
- p->prefixlen = IPV6_MAX_BITLEN;
if (pi->attr &&
pi->attr->mp_nexthop_len ==
BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL &&
@@ -1072,33 +1089,15 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
pi->attr->mp_nexthop_len ==
BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
if (CHECK_FLAG(pi->attr->nh_flags,
- BGP_ATTR_NH_MP_PREFER_GLOBAL)) {
- if (IS_MAPPED_IPV6(
- &pi->attr->mp_nexthop_global)) {
- ipv4_mapped_ipv6_to_ipv4(
- &pi->attr->mp_nexthop_global,
- &ipv4);
- p->u.prefix4 = ipv4;
- p->prefixlen = IPV4_MAX_BITLEN;
- p->family = AF_INET;
- } else
- p->u.prefix6 =
- pi->attr->mp_nexthop_global;
- } else
- p->u.prefix6 =
- pi->attr->mp_nexthop_local;
- } else {
- if (IS_MAPPED_IPV6(
- &pi->attr->mp_nexthop_global)) {
- ipv4_mapped_ipv6_to_ipv4(&pi->attr->mp_nexthop_global,
- &ipv4);
- p->u.prefix4 = ipv4;
- p->prefixlen = IPV4_MAX_BITLEN;
- p->family = AF_INET;
- } else
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
p->u.prefix6 =
pi->attr->mp_nexthop_global;
- }
+ else
+ p->u.prefix6 =
+ pi->attr->mp_nexthop_local;
+ } else
+ p->u.prefix6 = pi->attr->mp_nexthop_global;
+ p->prefixlen = IPV6_MAX_BITLEN;
}
break;
default:
@@ -1184,7 +1183,7 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
static void register_zebra_rnh(struct bgp_nexthop_cache *bnc)
{
/* Check if we have already registered */
- if (bnc->flags & BGP_NEXTHOP_REGISTERED)
+ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
return;
if (bnc->ifindex_ipv6_ll) {
@@ -1313,11 +1312,13 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
bool bnc_is_valid_nexthop = false;
bool path_valid = false;
+ struct bgp_route_evpn *bre =
+ bgp_attr_get_evpn_overlay(path->attr);
if (safi == SAFI_UNICAST &&
path->sub_type == BGP_ROUTE_IMPORTED &&
- bgp_path_info_num_labels(path) &&
- (path->attr->evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP)) {
+ BGP_PATH_INFO_NUM_LABELS(path) &&
+ !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)) {
bnc_is_valid_nexthop =
bgp_isvalid_nexthop_for_l3vpn(bnc, path)
? true
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 945076709c..6451c7cf38 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -1374,7 +1374,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
* Check that we can read the opt_type and fetch it
*/
if (STREAM_READABLE(s) < 1) {
- zlog_info("%s Option length error", peer->host);
+ zlog_err("%s Option length error", peer->host);
bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
@@ -1387,7 +1387,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
*/
if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)) {
if (STREAM_READABLE(s) < 2) {
- zlog_info("%s Option length error", peer->host);
+ zlog_err("%s Option length error", peer->host);
bgp_notify_send(peer->connection,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR);
@@ -1397,7 +1397,7 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
opt_length = stream_getw(s);
} else {
if (STREAM_READABLE(s) < 1) {
- zlog_info("%s Option length error", peer->host);
+ zlog_err("%s Option length error", peer->host);
bgp_notify_send(peer->connection,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR);
@@ -1409,8 +1409,8 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
/* Option length check. */
if (STREAM_READABLE(s) < opt_length) {
- zlog_info("%s Option length error (%d)", peer->host,
- opt_length);
+ zlog_err("%s Option length error (%d)", peer->host,
+ opt_length);
bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 2a2c9bdba9..62be7ffbf7 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1116,10 +1116,10 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
s = stream_new(peer->max_packet_size);
/* Make BGP update packet. */
- if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_RCV))
- bgp_packet_set_marker(s, BGP_MSG_ROUTE_REFRESH_NEW);
- else
- bgp_packet_set_marker(s, BGP_MSG_ROUTE_REFRESH_OLD);
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_RCV))
+ return;
+
+ bgp_packet_set_marker(s, BGP_MSG_ROUTE_REFRESH_NEW);
/* Encode Route Refresh message. */
stream_putw(s, pkt_afi);
@@ -2702,6 +2702,19 @@ static int bgp_notify_receive(struct peer_connection *connection,
inner.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM)
UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+ /* Resend the next OPEN message with a global AS number if we received
+ * a `Bad Peer AS` notification. This is only valid if `dual-as` is
+ * configured.
+ */
+ if (inner.code == BGP_NOTIFY_OPEN_ERR &&
+ inner.subcode == BGP_NOTIFY_OPEN_BAD_PEER_AS &&
+ CHECK_FLAG(peer->flags, PEER_FLAG_DUAL_AS)) {
+ if (peer->change_local_as != peer->bgp->as)
+ peer->change_local_as = peer->bgp->as;
+ else
+ peer->change_local_as = peer->local_as;
+ }
+
/* If Graceful-Restart N-bit (Notification) is exchanged,
* and it's not a Hard Reset, let's retain the routes.
*/
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 43682de413..2d61c0f00a 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -173,33 +173,33 @@ static int snprintf_bgp_pbr_match_val(char *str, int len,
ptr += delta;
len -= delta;
} else {
- if (mval->unary_operator & OPERATOR_UNARY_OR) {
+ if (CHECK_FLAG(mval->unary_operator, OPERATOR_UNARY_OR)) {
delta = snprintf(ptr, len, ", or ");
ptr += delta;
len -= delta;
}
- if (mval->unary_operator & OPERATOR_UNARY_AND) {
+ if (CHECK_FLAG(mval->unary_operator, OPERATOR_UNARY_AND)) {
delta = snprintf(ptr, len, ", and ");
ptr += delta;
len -= delta;
}
}
- if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN) {
+ if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_LESS_THAN)) {
delta = snprintf(ptr, len, "<");
ptr += delta;
len -= delta;
}
- if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN) {
+ if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_GREATER_THAN)) {
delta = snprintf(ptr, len, ">");
ptr += delta;
len -= delta;
}
- if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO) {
+ if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_EQUAL_TO)) {
delta = snprintf(ptr, len, "=");
ptr += delta;
len -= delta;
}
- if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH) {
+ if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_EXACT_MATCH)) {
delta = snprintf(ptr, len, "match");
ptr += delta;
len -= delta;
@@ -287,9 +287,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite(
{
if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
if (type_entry == FLOWSPEC_TCP_FLAGS) {
- and_valmask->mask |=
- TCP_HEADER_ALL_FLAGS &
- ~(value);
+ SET_FLAG(and_valmask->mask, CHECK_FLAG(TCP_HEADER_ALL_FLAGS, ~(value)));
} else if (type_entry == FLOWSPEC_DSCP ||
type_entry == FLOWSPEC_FLOW_LABEL ||
type_entry == FLOWSPEC_PKT_LEN ||
@@ -302,9 +300,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite(
sizeof(struct bgp_pbr_val_mask));
if (type_entry == FLOWSPEC_TCP_FLAGS) {
and_valmask->val = TCP_HEADER_ALL_FLAGS;
- and_valmask->mask |=
- TCP_HEADER_ALL_FLAGS &
- ~(value);
+ SET_FLAG(and_valmask->mask, CHECK_FLAG(TCP_HEADER_ALL_FLAGS, ~(value)));
} else if (type_entry == FLOWSPEC_DSCP ||
type_entry == FLOWSPEC_FLOW_LABEL ||
type_entry == FLOWSPEC_FRAGMENT ||
@@ -346,14 +342,10 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
if (i != 0 && list[i].unary_operator !=
unary_operator)
return false;
- if (!(list[i].compare_operator &
- OPERATOR_COMPARE_EQUAL_TO) &&
- !(list[i].compare_operator &
- OPERATOR_COMPARE_EXACT_MATCH)) {
- if ((list[i].compare_operator &
- OPERATOR_COMPARE_LESS_THAN) &&
- (list[i].compare_operator &
- OPERATOR_COMPARE_GREATER_THAN)) {
+ if (!CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_EQUAL_TO) &&
+ !CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_EXACT_MATCH)) {
+ if (CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_LESS_THAN) &&
+ CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_GREATER_THAN)) {
ret = bgp_pbr_extract_enumerate_unary_opposite(
unary_operator, and_valmask,
or_valmask, list[i].value,
@@ -366,15 +358,15 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
}
if (unary_operator == OPERATOR_UNARY_AND && and_valmask) {
if (type_entry == FLOWSPEC_TCP_FLAGS)
- and_valmask->mask |=
- TCP_HEADER_ALL_FLAGS & list[i].value;
+ SET_FLAG(and_valmask->mask,
+ CHECK_FLAG(TCP_HEADER_ALL_FLAGS, list[i].value));
} else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) {
and_valmask = XCALLOC(MTYPE_PBR_VALMASK,
sizeof(struct bgp_pbr_val_mask));
if (type_entry == FLOWSPEC_TCP_FLAGS) {
and_valmask->val = TCP_HEADER_ALL_FLAGS;
- and_valmask->mask |=
- TCP_HEADER_ALL_FLAGS & list[i].value;
+ SET_FLAG(and_valmask->mask,
+ CHECK_FLAG(TCP_HEADER_ALL_FLAGS, list[i].value));
} else if (type_entry == FLOWSPEC_DSCP ||
type_entry == FLOWSPEC_FLOW_LABEL ||
type_entry == FLOWSPEC_ICMP_TYPE ||
@@ -402,8 +394,8 @@ static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list[],
uint8_t unary_operator_val;
bool double_check = false;
- if ((unary_operator & OPERATOR_UNARY_OR) &&
- (unary_operator & OPERATOR_UNARY_AND)) {
+ if (CHECK_FLAG(unary_operator, OPERATOR_UNARY_OR) &&
+ CHECK_FLAG(unary_operator, OPERATOR_UNARY_AND)) {
unary_operator_val = OPERATOR_UNARY_AND;
double_check = true;
} else
@@ -431,12 +423,12 @@ static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list[],
for (i = 0; i < num; i++) {
if (i == 0)
continue;
- if (list[i].unary_operator & OPERATOR_UNARY_OR)
+ if (CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_OR))
unary_operator = OPERATOR_UNARY_OR;
- if ((list[i].unary_operator & OPERATOR_UNARY_AND
- && unary_operator == OPERATOR_UNARY_OR) ||
- (list[i].unary_operator & OPERATOR_UNARY_OR
- && unary_operator == OPERATOR_UNARY_AND))
+ if ((CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_AND) &&
+ unary_operator == OPERATOR_UNARY_OR) ||
+ (CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_OR) &&
+ unary_operator == OPERATOR_UNARY_AND))
return 0;
}
return unary_operator;
@@ -723,8 +715,8 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
}
}
- } else if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
- !(api->match_bitmask & PREFIX_DST_PRESENT)) {
+ } else if (!CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT) &&
+ !CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) {
if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api);
zlog_debug("BGP: match actions without src or dst address can not operate. ignoring.");
@@ -775,21 +767,18 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
}
api_action = &api->actions[action_count - 1];
- if ((ecom_eval->val[1] ==
- (char)ECOMMUNITY_REDIRECT_VRF) &&
- (ecom_eval->val[0] ==
- (char)ECOMMUNITY_ENCODE_TRANS_EXP ||
+ if ((ecom_eval->val[1] == ECOMMUNITY_REDIRECT_VRF) &&
+ (ecom_eval->val[0] == ECOMMUNITY_ENCODE_TRANS_EXP ||
ecom_eval->val[0] ==
- (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
+ ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
ecom_eval->val[0] ==
- (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
+ ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
struct ecommunity *eckey = ecommunity_new();
struct ecommunity_val ecom_copy;
memcpy(&ecom_copy, ecom_eval,
sizeof(struct ecommunity_val));
- ecom_copy.val[0] &=
- ~ECOMMUNITY_ENCODE_TRANS_EXP;
+ UNSET_FLAG(ecom_copy.val[0], ECOMMUNITY_ENCODE_TRANS_EXP);
ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
ecommunity_add_val(eckey, &ecom_copy,
false, false);
@@ -800,9 +789,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
eckey);
ecommunity_free(&eckey);
} else if ((ecom_eval->val[0] ==
- (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
+ ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
(ecom_eval->val[1] ==
- (char)ECOMMUNITY_REDIRECT_IP_NH)) {
+ ECOMMUNITY_REDIRECT_IP_NH)) {
/* in case the 2 ecom present,
* do not overwrite
* draft-ietf-idr-flowspec-redirect
@@ -861,10 +850,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
= ecom_eval->val[7];
api_action_redirect_ip = api_action;
}
- } else if ((ecom_eval->val[0] ==
- (char)ECOMMUNITY_ENCODE_IP) &&
+ } else if ((ecom_eval->val[0] == ECOMMUNITY_ENCODE_IP) &&
(ecom_eval->val[1] ==
- (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) {
+ ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) {
/* in case the 2 ecom present,
* overwrite simpson draft
* update redirect ip fields
@@ -888,7 +876,7 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
}
} else {
if (ecom_eval->val[0] !=
- (char)ECOMMUNITY_ENCODE_TRANS_EXP)
+ ECOMMUNITY_ENCODE_TRANS_EXP)
continue;
ret = ecommunity_fill_pbr_action(ecom_eval,
api_action,
@@ -920,9 +908,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
}
api_action = &api->actions[action_count - 1];
if ((ipv6_ecom_eval->val[1] ==
- (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) &&
+ ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) &&
(ipv6_ecom_eval->val[0] ==
- (char)ECOMMUNITY_ENCODE_TRANS_EXP)) {
+ ECOMMUNITY_ENCODE_TRANS_EXP)) {
struct ecommunity *eckey = ecommunity_new();
struct ecommunity_val_ipv6 ecom_copy;
@@ -958,12 +946,12 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
return -1;
/* check inconsistency in the match rule */
- if (api->match_bitmask & PREFIX_SRC_PRESENT) {
+ if (CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT)) {
src = &api->src_prefix;
afi = family2afi(src->family);
valid_prefix = 1;
}
- if (api->match_bitmask & PREFIX_DST_PRESENT) {
+ if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) {
dst = &api->dst_prefix;
if (valid_prefix && afi != family2afi(dst->family)) {
if (BGP_DEBUG(pbr, PBR)) {
@@ -1207,12 +1195,10 @@ bool bgp_pbr_rule_hash_equal(const void *arg1, const void *arg2)
if (r1->action != r2->action)
return false;
- if ((r1->flags & MATCH_IP_SRC_SET) &&
- !prefix_same(&r1->src, &r2->src))
+ if (CHECK_FLAG(r1->flags, MATCH_IP_SRC_SET) && !prefix_same(&r1->src, &r2->src))
return false;
- if ((r1->flags & MATCH_IP_DST_SET) &&
- !prefix_same(&r1->dst, &r2->dst))
+ if (CHECK_FLAG(r1->flags, MATCH_IP_DST_SET) && !prefix_same(&r1->dst, &r2->dst))
return false;
return true;
@@ -1429,7 +1415,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
delta = snprintf(ptr, sizeof(return_string), "MATCH : ");
len -= delta;
ptr += delta;
- if (api->match_bitmask & PREFIX_SRC_PRESENT) {
+ if (CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT)) {
struct prefix *p = &(api->src_prefix);
if (api->src_prefix_offset)
@@ -1441,7 +1427,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
ptr += delta;
INCREMENT_DISPLAY(ptr, nb_items, len);
}
- if (api->match_bitmask & PREFIX_DST_PRESENT) {
+ if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) {
struct prefix *p = &(api->dst_prefix);
INCREMENT_DISPLAY(ptr, nb_items, len);
@@ -1584,21 +1570,18 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
delta = snprintf(ptr, len, "@action ");
len -= delta;
ptr += delta;
- if (api->actions[i].u.za.filter
- & TRAFFIC_ACTION_TERMINATE) {
+ if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_TERMINATE)) {
delta = snprintf(ptr, len,
" terminate (apply filter(s))");
len -= delta;
ptr += delta;
}
- if (api->actions[i].u.za.filter
- & TRAFFIC_ACTION_DISTRIBUTE) {
+ if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_DISTRIBUTE)) {
delta = snprintf(ptr, len, " distribute");
len -= delta;
ptr += delta;
}
- if (api->actions[i].u.za.filter
- & TRAFFIC_ACTION_SAMPLE) {
+ if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_SAMPLE)) {
delta = snprintf(ptr, len, " sample");
len -= delta;
ptr += delta;
@@ -1749,12 +1732,10 @@ static int bgp_pbr_get_same_rule(struct hash_bucket *bucket, void *arg)
if (r1->flags != r2->flags)
return HASHWALK_CONTINUE;
- if ((r1->flags & MATCH_IP_SRC_SET) &&
- !prefix_same(&r1->src, &r2->src))
+ if (CHECK_FLAG(r1->flags, MATCH_IP_SRC_SET) && !prefix_same(&r1->src, &r2->src))
return HASHWALK_CONTINUE;
- if ((r1->flags & MATCH_IP_DST_SET) &&
- !prefix_same(&r1->dst, &r2->dst))
+ if (CHECK_FLAG(r1->flags, MATCH_IP_DST_SET) && !prefix_same(&r1->dst, &r2->dst))
return HASHWALK_CONTINUE;
/* this function is used for two cases:
@@ -1843,11 +1824,11 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
pbr_rule.vrf_id = bpf->vrf_id;
if (bpf->src) {
prefix_copy(&pbr_rule.src, bpf->src);
- pbr_rule.flags |= MATCH_IP_SRC_SET;
+ SET_FLAG(pbr_rule.flags, MATCH_IP_SRC_SET);
}
if (bpf->dst) {
prefix_copy(&pbr_rule.dst, bpf->dst);
- pbr_rule.flags |= MATCH_IP_DST_SET;
+ SET_FLAG(pbr_rule.flags, MATCH_IP_DST_SET);
}
bpr = &pbr_rule;
/* A previous entry may already exist
@@ -1870,32 +1851,32 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
temp.family = bpf->family;
if (bpf->src) {
- temp.flags |= MATCH_IP_SRC_SET;
+ SET_FLAG(temp.flags, MATCH_IP_SRC_SET);
prefix_copy(&temp2.src, bpf->src);
} else
temp2.src.family = bpf->family;
if (bpf->dst) {
- temp.flags |= MATCH_IP_DST_SET;
+ SET_FLAG(temp.flags, MATCH_IP_DST_SET);
prefix_copy(&temp2.dst, bpf->dst);
} else
temp2.dst.family = bpf->family;
if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
if (bpf->protocol == IPPROTO_ICMP)
- temp.flags |= MATCH_ICMP_SET;
- temp.flags |= MATCH_PORT_SRC_SET;
+ SET_FLAG(temp.flags, MATCH_ICMP_SET);
+ SET_FLAG(temp.flags, MATCH_PORT_SRC_SET);
temp2.src_port_min = src_port->min_port;
if (src_port->max_port) {
- temp.flags |= MATCH_PORT_SRC_RANGE_SET;
+ SET_FLAG(temp.flags, MATCH_PORT_SRC_RANGE_SET);
temp2.src_port_max = src_port->max_port;
}
}
if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
if (bpf->protocol == IPPROTO_ICMP)
- temp.flags |= MATCH_ICMP_SET;
- temp.flags |= MATCH_PORT_DST_SET;
+ SET_FLAG(temp.flags, MATCH_ICMP_SET);
+ SET_FLAG(temp.flags, MATCH_PORT_DST_SET);
temp2.dst_port_min = dst_port->min_port;
if (dst_port->max_port) {
- temp.flags |= MATCH_PORT_DST_RANGE_SET;
+ SET_FLAG(temp.flags, MATCH_PORT_DST_RANGE_SET);
temp2.dst_port_max = dst_port->max_port;
}
}
@@ -1907,7 +1888,7 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
temp.pkt_len_max = pkt_len->max_port;
} else if (bpf->pkt_len_val) {
if (bpf->pkt_len_val->mask)
- temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
+ SET_FLAG(temp.flags, MATCH_PKT_LEN_INVERSE_SET);
temp.pkt_len_min = bpf->pkt_len_val->val;
}
if (bpf->tcp_flags) {
@@ -1916,32 +1897,32 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
}
if (bpf->dscp) {
if (bpf->dscp->mask)
- temp.flags |= MATCH_DSCP_INVERSE_SET;
+ SET_FLAG(temp.flags, MATCH_DSCP_INVERSE_SET);
else
- temp.flags |= MATCH_DSCP_SET;
+ SET_FLAG(temp.flags, MATCH_DSCP_SET);
temp.dscp_value = bpf->dscp->val;
}
if (bpf->flow_label) {
if (bpf->flow_label->mask)
- temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
+ SET_FLAG(temp.flags, MATCH_FLOW_LABEL_INVERSE_SET);
else
- temp.flags |= MATCH_FLOW_LABEL_SET;
+ SET_FLAG(temp.flags, MATCH_FLOW_LABEL_SET);
temp.flow_label = bpf->flow_label->val;
}
if (bpf->fragment) {
if (bpf->fragment->mask)
- temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
+ SET_FLAG(temp.flags, MATCH_FRAGMENT_INVERSE_SET);
temp.fragment = bpf->fragment->val;
}
if (bpf->src == NULL || bpf->dst == NULL) {
- if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
+ if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)))
temp.type = IPSET_NET_PORT;
else
temp.type = IPSET_NET;
} else {
- if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
+ if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)))
temp.type = IPSET_NET_PORT_NET;
else
temp.type = IPSET_NET_NET;
@@ -2319,11 +2300,11 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
pbr_rule.vrf_id = bpf->vrf_id;
pbr_rule.priority = 20;
if (bpf->src) {
- pbr_rule.flags |= MATCH_IP_SRC_SET;
+ SET_FLAG(pbr_rule.flags, MATCH_IP_SRC_SET);
prefix_copy(&pbr_rule.src, bpf->src);
}
if (bpf->dst) {
- pbr_rule.flags |= MATCH_IP_DST_SET;
+ SET_FLAG(pbr_rule.flags, MATCH_IP_DST_SET);
prefix_copy(&pbr_rule.dst, bpf->dst);
}
pbr_rule.action = bpa;
@@ -2380,32 +2361,32 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
temp.vrf_id = bpf->vrf_id;
temp.family = bpf->family;
if (bpf->src)
- temp.flags |= MATCH_IP_SRC_SET;
+ SET_FLAG(temp.flags, MATCH_IP_SRC_SET);
if (bpf->dst)
- temp.flags |= MATCH_IP_DST_SET;
+ SET_FLAG(temp.flags, MATCH_IP_DST_SET);
if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
if (bpf->protocol == IPPROTO_ICMP)
- temp.flags |= MATCH_ICMP_SET;
- temp.flags |= MATCH_PORT_SRC_SET;
+ SET_FLAG(temp.flags, MATCH_ICMP_SET);
+ SET_FLAG(temp.flags, MATCH_PORT_SRC_SET);
}
if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) {
if (bpf->protocol == IPPROTO_ICMP)
- temp.flags |= MATCH_ICMP_SET;
- temp.flags |= MATCH_PORT_DST_SET;
+ SET_FLAG(temp.flags, MATCH_ICMP_SET);
+ SET_FLAG(temp.flags, MATCH_PORT_DST_SET);
}
if (src_port && src_port->max_port)
- temp.flags |= MATCH_PORT_SRC_RANGE_SET;
+ SET_FLAG(temp.flags, MATCH_PORT_SRC_RANGE_SET);
if (dst_port && dst_port->max_port)
- temp.flags |= MATCH_PORT_DST_RANGE_SET;
+ SET_FLAG(temp.flags, MATCH_PORT_DST_RANGE_SET);
if (bpf->src == NULL || bpf->dst == NULL) {
- if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
+ if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)))
temp.type = IPSET_NET_PORT;
else
temp.type = IPSET_NET;
} else {
- if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))
+ if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)))
temp.type = IPSET_NET_PORT_NET;
else
temp.type = IPSET_NET_NET;
@@ -2416,7 +2397,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
temp.pkt_len_max = pkt_len->max_port;
} else if (bpf->pkt_len_val) {
if (bpf->pkt_len_val->mask)
- temp.flags |= MATCH_PKT_LEN_INVERSE_SET;
+ SET_FLAG(temp.flags, MATCH_PKT_LEN_INVERSE_SET);
temp.pkt_len_min = bpf->pkt_len_val->val;
}
if (bpf->tcp_flags) {
@@ -2425,26 +2406,26 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
}
if (bpf->dscp) {
if (bpf->dscp->mask)
- temp.flags |= MATCH_DSCP_INVERSE_SET;
+ SET_FLAG(temp.flags, MATCH_DSCP_INVERSE_SET);
else
- temp.flags |= MATCH_DSCP_SET;
+ SET_FLAG(temp.flags, MATCH_DSCP_SET);
temp.dscp_value = bpf->dscp->val;
}
if (bpf->flow_label) {
if (bpf->flow_label->mask)
- temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
+ SET_FLAG(temp.flags, MATCH_FLOW_LABEL_INVERSE_SET);
else
- temp.flags |= MATCH_FLOW_LABEL_SET;
+ SET_FLAG(temp.flags, MATCH_FLOW_LABEL_SET);
temp.flow_label = bpf->flow_label->val;
}
if (bpf->fragment) {
if (bpf->fragment->mask)
- temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
+ SET_FLAG(temp.flags, MATCH_FRAGMENT_INVERSE_SET);
temp.fragment = bpf->fragment->val;
}
if (bpf->protocol) {
temp.protocol = bpf->protocol;
- temp.flags |= MATCH_PROTOCOL_SET;
+ SET_FLAG(temp.flags, MATCH_PROTOCOL_SET);
}
temp.action = bpa;
bpm = hash_get(bgp->pbr_match_hash, &temp,
@@ -2661,13 +2642,13 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
memset(&nh, 0, sizeof(nh));
memset(&bpf, 0, sizeof(bpf));
memset(&bpof, 0, sizeof(bpof));
- if (api->match_bitmask & PREFIX_SRC_PRESENT ||
+ if (CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT) ||
(api->type == BGP_PBR_IPRULE &&
- api->match_bitmask_iprule & PREFIX_SRC_PRESENT))
+ CHECK_FLAG(api->match_bitmask_iprule, PREFIX_SRC_PRESENT)))
src = &api->src_prefix;
- if (api->match_bitmask & PREFIX_DST_PRESENT ||
+ if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT) ||
(api->type == BGP_PBR_IPRULE &&
- api->match_bitmask_iprule & PREFIX_DST_PRESENT))
+ CHECK_FLAG(api->match_bitmask_iprule, PREFIX_DST_PRESENT)))
dst = &api->dst_prefix;
if (api->type == BGP_PBR_IPRULE)
bpf.type = api->type;
@@ -2812,8 +2793,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
}
break;
case ACTION_TRAFFIC_ACTION:
- if (api->actions[i].u.za.filter
- & TRAFFIC_ACTION_SAMPLE) {
+ if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_SAMPLE)) {
if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api);
zlog_warn("PBR: Sample action Ignored");
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 2a9fc6ce0d..8dbb4e3b04 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -327,7 +327,7 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi)
bool bgp_path_info_has_valid_label(const struct bgp_path_info *path)
{
- if (!bgp_path_info_num_labels(path))
+ if (!BGP_PATH_INFO_NUM_LABELS(path))
return false;
return bgp_is_valid_label(&path->extra->labels->label[0]);
@@ -339,27 +339,13 @@ bool bgp_path_info_labels_same(const struct bgp_path_info *bpi,
uint8_t bpi_num_labels;
const mpls_label_t *bpi_label;
- bpi_num_labels = bgp_path_info_num_labels(bpi);
+ bpi_num_labels = BGP_PATH_INFO_NUM_LABELS(bpi);
bpi_label = bpi_num_labels ? bpi->extra->labels->label : NULL;
return bgp_labels_same(bpi_label, bpi_num_labels,
(const mpls_label_t *)label, n);
}
-uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi)
-{
- if (!pi)
- return 0;
-
- if (!pi->extra)
- return 0;
-
- if (!pi->extra->labels)
- return 0;
-
- return pi->extra->labels->num_labels;
-}
-
/* Free bgp route information. */
void bgp_path_info_free_with_caller(const char *name,
struct bgp_path_info *path)
@@ -539,8 +525,6 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
else
bgp_dest_set_bgp_path_info(dest, pi->next);
- bgp_path_info_mpath_dequeue(pi);
-
pi->next = NULL;
pi->prev = NULL;
@@ -555,8 +539,6 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
static struct bgp_dest *bgp_path_info_reap_unsorted(struct bgp_dest *dest,
struct bgp_path_info *pi)
{
- bgp_path_info_mpath_dequeue(pi);
-
pi->next = NULL;
pi->prev = NULL;
@@ -1607,18 +1589,16 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
if (ret == 1) {
*reason = bgp_path_selection_neighbor_ip;
if (debug)
- zlog_debug(
- "%s: %s loses to %s due to Neighor IP comparison",
- pfx_buf, new_buf, exist_buf);
+ zlog_debug("%s: %s loses to %s due to Neighbor IP comparison",
+ pfx_buf, new_buf, exist_buf);
return 0;
}
if (ret == -1) {
*reason = bgp_path_selection_neighbor_ip;
if (debug)
- zlog_debug(
- "%s: %s wins over %s due to Neighor IP comparison",
- pfx_buf, new_buf, exist_buf);
+ zlog_debug("%s: %s wins over %s due to Neighbor IP comparison",
+ pfx_buf, new_buf, exist_buf);
return 1;
}
@@ -2189,8 +2169,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
from = pi->peer;
filter = &peer->filter[afi][safi];
bgp = SUBGRP_INST(subgrp);
- piattr = bgp_path_info_mpath_count(pi) ? bgp_path_info_mpath_attr(pi)
- : pi->attr;
+ piattr = bgp_path_info_mpath_count(pi) > 1 ? bgp_path_info_mpath_attr(pi) : pi->attr;
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT) &&
peer->pmax_out[afi][safi] != 0 &&
@@ -2254,7 +2233,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
* off box as that the RT and RD created are localy
* significant and globaly useless.
*/
- if (safi == SAFI_MPLS_VPN && bgp_path_info_num_labels(pi) &&
+ if (safi == SAFI_MPLS_VPN && BGP_PATH_INFO_NUM_LABELS(pi) &&
pi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK)
return false;
@@ -2488,13 +2467,16 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
if (NEXTHOP_IS_V6) {
attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
if ((CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)
- && IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local))
- || (!reflect && !transparent
- && IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local)
- && peer->shared_network
- && (from == bgp->peer_self
- || peer->sort == BGP_PEER_EBGP))) {
+ PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) &&
+ IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) ||
+ (!reflect && !transparent &&
+ IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) &&
+ peer->shared_network &&
+ ((from == bgp->peer_self && peer->sort == BGP_PEER_EBGP) ||
+ (from == bgp->peer_self && peer->sort != BGP_PEER_EBGP) ||
+ (from != bgp->peer_self &&
+ IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local) &&
+ peer->sort == BGP_PEER_EBGP)))) {
if (safi == SAFI_MPLS_VPN)
attr->mp_nexthop_len =
BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL;
@@ -2867,13 +2849,12 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *pi2;
int paths_eq, do_mpath;
bool debug, any_comparisons;
- struct list mp_list;
char pfx_buf[PREFIX2STR_BUFFER] = {};
char path_buf[PATH_ADDPATH_STR_BUFFER];
enum bgp_path_selection_reason reason = bgp_path_selection_none;
bool unsorted_items = true;
+ uint32_t num_candidates = 0;
- bgp_mp_list_init(&mp_list);
do_mpath =
(mpath_cfg->maxpaths_ebgp > 1 || mpath_cfg->maxpaths_ibgp > 1);
@@ -3248,7 +3229,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
"%pBD(%s): %s is the bestpath, add to the multipath list",
dest, bgp->name_pretty,
path_buf);
- bgp_mp_list_add(&mp_list, pi);
+ SET_FLAG(pi->flags, BGP_PATH_MULTIPATH_NEW);
+ num_candidates++;
continue;
}
@@ -3271,15 +3253,14 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
"%pBD(%s): %s is equivalent to the bestpath, add to the multipath list",
dest, bgp->name_pretty,
path_buf);
- bgp_mp_list_add(&mp_list, pi);
+ SET_FLAG(pi->flags, BGP_PATH_MULTIPATH_NEW);
+ num_candidates++;
}
}
}
- bgp_path_info_mpath_update(bgp, dest, new_select, old_select, &mp_list,
- mpath_cfg);
+ bgp_path_info_mpath_update(bgp, dest, new_select, old_select, num_candidates, mpath_cfg);
bgp_path_info_mpath_aggregate_update(new_select, old_select);
- bgp_mp_list_clear(&mp_list);
bgp_addpath_update_ids(bgp, dest, afi, safi);
@@ -3634,7 +3615,16 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info_pair old_and_new;
int debug = 0;
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {
+ /*
+ * For default bgp instance, which is deleted i.e. marked hidden
+ * we are skipping SAFI_MPLS_VPN route table deletion
+ * in bgp_cleanup_routes.
+ * So, we need to delete routes from VPNV4 table.
+ * Here for !IS_BGP_INSTANCE_HIDDEN,
+ * !(SAFI_MPLS_VPN && AF_IP/AF_IP6),
+ * we ignore the event for the prefix.
+ */
+ if (BGP_INSTANCE_HIDDEN_DELETE_IN_PROGRESS(bgp, afi, safi)) {
if (dest)
debug = bgp_debug_bestpath(dest);
if (debug)
@@ -3773,7 +3763,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
if (old_select || new_select) {
bgp_bump_version(dest);
- if (!bgp->t_rmap_def_originate_eval)
+ if (!bgp->t_rmap_def_originate_eval &&
+ bgp->rmap_def_originate_eval_timer)
event_add_timer(
bm->master,
update_group_refresh_default_originate_route_map,
@@ -4027,8 +4018,9 @@ static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp)
return pqnode;
}
-void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
- struct bgp_path_info *pi, afi_t afi, safi_t safi)
+static void bgp_process_internal(struct bgp *bgp, struct bgp_dest *dest,
+ struct bgp_path_info *pi, afi_t afi,
+ safi_t safi, bool early_process)
{
#define ARBITRARY_PROCESS_QLEN 10000
struct work_queue *wq = bgp->process_queue;
@@ -4091,9 +4083,8 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
struct work_queue_item *item = work_queue_last_item(wq);
pqnode = item->data;
- if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)
- || pqnode->bgp != bgp
- || pqnode->queued >= ARBITRARY_PROCESS_QLEN)
+ if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) ||
+ (pqnode->queued >= ARBITRARY_PROCESS_QLEN && !early_process))
pqnode = bgp_processq_alloc(bgp);
else
pqnode_reuse = 1;
@@ -4107,7 +4098,10 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
/* can't be enqueued twice */
assert(STAILQ_NEXT(dest, pq) == NULL);
- STAILQ_INSERT_TAIL(&pqnode->pqueue, dest, pq);
+ if (early_process)
+ STAILQ_INSERT_HEAD(&pqnode->pqueue, dest, pq);
+ else
+ STAILQ_INSERT_TAIL(&pqnode->pqueue, dest, pq);
pqnode->queued++;
if (!pqnode_reuse)
@@ -4116,6 +4110,18 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
return;
}
+void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
+ struct bgp_path_info *pi, afi_t afi, safi_t safi)
+{
+ bgp_process_internal(bgp, dest, pi, afi, safi, false);
+}
+
+void bgp_process_early(struct bgp *bgp, struct bgp_dest *dest,
+ struct bgp_path_info *pi, afi_t afi, safi_t safi)
+{
+ bgp_process_internal(bgp, dest, pi, afi, safi, true);
+}
+
void bgp_add_eoiu_mark(struct bgp *bgp)
{
struct bgp_process_queue *pqnode;
@@ -4608,10 +4614,10 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
* will not be interned. In which case, it is ok to update the
* attr->evpn_overlay, so that, this can be stored in adj_in.
*/
- if ((afi == AFI_L2VPN) && evpn) {
- memcpy(&attr->evpn_overlay, evpn,
- sizeof(struct bgp_route_evpn));
- }
+ if ((afi == AFI_L2VPN) && evpn)
+ bgp_attr_set_evpn_overlay(attr, evpn);
+ else
+ evpn_overlay_free(evpn);
bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels);
}
@@ -4650,7 +4656,22 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (aspath_get_last_as(attr->aspath) == bgp->as)
do_loop_check = 0;
- if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+ /* When using bgp ipv4 labeled session, the local prefix is
+ * received by a peer, and finds out that the proposed prefix
+ * and its next-hop are the same. To avoid a route loop locally,
+ * no nexthop entry is referenced for that prefix, and the route
+ * will not be selected.
+ *
+ * As it has been done for ipv4-unicast, apply the following fix
+ * for labeled address families: when the received peer is
+ * a route reflector, the prefix has to be selected, even if the
+ * route can not be installed locally.
+ */
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT) ||
+ (safi == SAFI_UNICAST && !peer->afc[afi][safi] &&
+ peer->afc[afi][SAFI_LABELED_UNICAST] &&
+ CHECK_FLAG(peer->af_flags[afi][SAFI_LABELED_UNICAST],
+ PEER_FLAG_REFLECTOR_CLIENT)))
bgp_nht_param_prefix = NULL;
else
bgp_nht_param_prefix = p;
@@ -4773,8 +4794,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
* evpn to new_atr.evpn_overlay before it is interned.
*/
if (soft_reconfig && (afi == AFI_L2VPN) && evpn)
- memcpy(&new_attr.evpn_overlay, evpn,
- sizeof(struct bgp_route_evpn));
+ bgp_attr_set_evpn_overlay(&new_attr, evpn);
+ else
+ evpn_overlay_free(evpn);
/* Apply incoming route-map.
* NB: new_attr may now contain newly allocated values from route-map
@@ -4798,22 +4820,21 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
false);
}
- if (peer->sort == BGP_PEER_EBGP) {
-
- /* rfc7999:
- * A BGP speaker receiving an announcement tagged with the
- * BLACKHOLE community SHOULD add the NO_ADVERTISE or
- * NO_EXPORT community as defined in RFC1997, or a
- * similar community, to prevent propagation of the
- * prefix outside the local AS. The community to prevent
- * propagation SHOULD be chosen according to the operator's
- * routing policy.
- */
- if (bgp_attr_get_community(&new_attr) &&
- community_include(bgp_attr_get_community(&new_attr),
- COMMUNITY_BLACKHOLE))
- bgp_attr_add_no_export_community(&new_attr);
+ /* rfc7999:
+ * A BGP speaker receiving an announcement tagged with the
+ * BLACKHOLE community SHOULD add the NO_ADVERTISE or
+ * NO_EXPORT community as defined in RFC1997, or a
+ * similar community, to prevent propagation of the
+ * prefix outside the local AS. The community to prevent
+ * propagation SHOULD be chosen according to the operator's
+ * routing policy.
+ */
+ if (bgp_attr_get_community(&new_attr) &&
+ community_include(bgp_attr_get_community(&new_attr),
+ COMMUNITY_BLACKHOLE))
+ bgp_attr_add_no_export_community(&new_attr);
+ if (peer->sort == BGP_PEER_EBGP) {
/* If we receive the graceful-shutdown community from an eBGP
* peer we must lower local-preference */
if (bgp_attr_get_community(&new_attr) &&
@@ -5450,7 +5471,7 @@ filtered:
void bgp_withdraw(struct peer *peer, const struct prefix *p,
uint32_t addpath_id, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd, mpls_label_t *label,
- uint8_t num_labels, struct bgp_route_evpn *evpn)
+ uint8_t num_labels)
{
struct bgp *bgp;
char pfx_buf[BGP_PRD_PATH_STRLEN];
@@ -5679,7 +5700,7 @@ static void bgp_soft_reconfig_table_update(struct peer *peer,
struct bgp_path_info *pi;
uint8_t num_labels;
mpls_label_t *label_pnt;
- struct bgp_route_evpn evpn;
+ struct bgp_route_evpn *bre = NULL;
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (pi->peer == peer)
@@ -5687,15 +5708,13 @@ static void bgp_soft_reconfig_table_update(struct peer *peer,
num_labels = ain->labels ? ain->labels->num_labels : 0;
label_pnt = num_labels ? &ain->labels->label[0] : NULL;
+
if (pi)
- memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
- sizeof(evpn));
- else
- memset(&evpn, 0, sizeof(evpn));
+ bre = bgp_attr_get_evpn_overlay(pi->attr);
bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id,
ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd,
- label_pnt, num_labels, 1, &evpn);
+ label_pnt, num_labels, 1, bre);
}
static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
@@ -6431,16 +6450,21 @@ void bgp_cleanup_routes(struct bgp *bgp)
if (afi != AFI_L2VPN) {
safi_t safi;
safi = SAFI_MPLS_VPN;
- for (dest = bgp_table_top(bgp->rib[afi][safi]); dest;
- dest = bgp_route_next(dest)) {
- table = bgp_dest_get_bgp_table_info(dest);
- if (table != NULL) {
- bgp_cleanup_table(bgp, table, afi, safi);
- bgp_table_finish(&table);
- bgp_dest_set_bgp_table_info(dest, NULL);
- dest = bgp_dest_unlock_node(dest);
-
- assert(dest);
+ if (!IS_BGP_INSTANCE_HIDDEN(bgp)) {
+ for (dest = bgp_table_top(bgp->rib[afi][safi]);
+ dest; dest = bgp_route_next(dest)) {
+ table = bgp_dest_get_bgp_table_info(
+ dest);
+ if (table != NULL) {
+ bgp_cleanup_table(bgp, table,
+ afi, safi);
+ bgp_table_finish(&table);
+ bgp_dest_set_bgp_table_info(dest,
+ NULL);
+ dest = bgp_dest_unlock_node(
+ dest);
+ assert(dest);
+ }
}
}
safi = SAFI_ENCAP;
@@ -6614,7 +6638,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
else
bgp_withdraw(peer, &p, addpath_id, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
- NULL, 0, NULL);
+ NULL, 0);
/* Do not send BGP notification twice when maximum-prefix count
* overflow. */
@@ -6745,15 +6769,25 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
if (afi == AFI_L2VPN) {
if (bgp_static->gatewayIp.family == AF_INET) {
- SET_IPADDR_V4(&attr.evpn_overlay.gw_ip);
- memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4,
+ struct bgp_route_evpn *bre =
+ XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
+ sizeof(struct bgp_route_evpn));
+
+ SET_IPADDR_V4(&bre->gw_ip);
+ memcpy(&bre->gw_ip.ipaddr_v4,
&bgp_static->gatewayIp.u.prefix4,
IPV4_MAX_BYTELEN);
+ bgp_attr_set_evpn_overlay(&attr, bre);
} else if (bgp_static->gatewayIp.family == AF_INET6) {
- SET_IPADDR_V6(&attr.evpn_overlay.gw_ip);
- memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6,
+ struct bgp_route_evpn *bre =
+ XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
+ sizeof(struct bgp_route_evpn));
+
+ SET_IPADDR_V6(&bre->gw_ip);
+ memcpy(&bre->gw_ip.ipaddr_v6,
&bgp_static->gatewayIp.u.prefix6,
IPV6_MAX_BYTELEN);
+ bgp_attr_set_evpn_overlay(&attr, bre);
}
memcpy(&attr.esi, bgp_static->eth_s_id, sizeof(esi_t));
if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) {
@@ -6854,7 +6888,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
bgp, p, pi);
}
} else {
- if (bgp_path_info_num_labels(pi))
+ if (BGP_PATH_INFO_NUM_LABELS(pi))
label = decode_label(
&pi->extra->labels->label[0]);
}
@@ -7177,7 +7211,7 @@ int bgp_static_set(struct vty *vty, bool negate, const char *ip_str,
bgp_static->prd = prd;
if (rd_str)
- bgp_static->prd_pretty = XSTRDUP(MTYPE_BGP,
+ bgp_static->prd_pretty = XSTRDUP(MTYPE_BGP_NAME,
rd_str);
if (rmap) {
@@ -9671,7 +9705,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
json_object_string_add(json_nexthop_ll, "scope",
"link-local");
- if (!CHECK_FLAG(attr->nh_flags,
+ if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global,
+ &attr->mp_nexthop_local) !=
+ 0) &&
+ !CHECK_FLAG(attr->nh_flags,
BGP_ATTR_NH_MP_PREFER_GLOBAL))
json_object_boolean_true_add(
json_nexthop_ll, "used");
@@ -10114,6 +10151,7 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
json_object *json_path = NULL;
json_object *json_nexthop = NULL;
json_object *json_overlay = NULL;
+ struct bgp_route_evpn *bre = NULL;
if (!path->extra)
return;
@@ -10179,12 +10217,14 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
}
}
- const struct bgp_route_evpn *eo = bgp_attr_get_evpn_overlay(attr);
-
- if (!json_path)
- vty_out(vty, "/%pIA", &eo->gw_ip);
- else
- json_object_string_addf(json_overlay, "gw", "%pIA", &eo->gw_ip);
+ bre = bgp_attr_get_evpn_overlay(attr);
+ if (bre) {
+ if (!json_path)
+ vty_out(vty, "/%pIA", &bre->gw_ip);
+ else
+ json_object_string_addf(json_overlay, "gw", "%pIA",
+ &bre->gw_ip);
+ }
if (bgp_attr_get_ecommunity(attr)) {
char *mac = NULL;
@@ -10519,6 +10559,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
mpls_label_t label = MPLS_INVALID_LABEL;
struct bgp_path_info *bpi_ultimate =
bgp_get_imported_bpi_ultimate(path);
+ struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr);
if (json_paths) {
json_path = json_object_new_object();
@@ -10526,7 +10567,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_nexthop_global = json_object_new_object();
}
- if (bgp_path_info_num_labels(path)) {
+ if (BGP_PATH_INFO_NUM_LABELS(path)) {
bgp_evpn_label2str(path->extra->labels->label,
path->extra->labels->num_labels, vni_buf,
sizeof(vni_buf));
@@ -10545,12 +10586,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
}
}
- if (safi == SAFI_EVPN
- && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
+ if (safi == SAFI_EVPN && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) {
char gwip_buf[INET6_ADDRSTRLEN];
- ipaddr2str(&attr->evpn_overlay.gw_ip, gwip_buf,
- sizeof(gwip_buf));
+ ipaddr2str(&bre->gw_ip, gwip_buf, sizeof(gwip_buf));
if (json_paths)
json_object_string_add(json_path, "gatewayIP",
@@ -10563,8 +10602,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, "\n");
- if (path->extra && path->extra->vrfleak &&
- path->extra->vrfleak->parent && !json_paths) {
+ if (path->extra && path->extra->vrfleak && path->extra->vrfleak->parent) {
struct bgp_path_info *parent_ri;
struct bgp_dest *dest, *pdest;
@@ -10574,31 +10612,68 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (dest && dest->pdest) {
pdest = dest->pdest;
if (is_pi_family_evpn(parent_ri)) {
- vty_out(vty, " Imported from ");
- vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
- (struct prefix_rd *)bgp_dest_get_prefix(
- pdest));
- vty_out(vty, ":%pFX, VNI %s",
- (struct prefix_evpn *)
- bgp_dest_get_prefix(dest),
- vni_buf);
- if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG))
+ if (json_paths) {
+ json_object_string_addf(
+ json_path, "importedFrom",
+ BGP_RD_AS_FORMAT(bgp->asnotation),
+ (struct prefix_rd *)
+ bgp_dest_get_prefix(
+ pdest));
+ if (safi != SAFI_EVPN)
+ json_object_string_add(json_path,
+ "vni",
+ vni_buf);
+ } else {
+ vty_out(vty, " Imported from ");
+ vty_out(vty,
+ BGP_RD_AS_FORMAT(bgp->asnotation),
+ (struct prefix_rd *)
+ bgp_dest_get_prefix(
+ pdest));
+ vty_out(vty, ":%pFX, VNI %s",
+ (struct prefix_evpn *)
+ bgp_dest_get_prefix(dest),
+ vni_buf);
+ }
+ if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG) &&
+ !json_paths) {
vty_out(vty, ", L3NHG %s",
CHECK_FLAG(
attr->es_flags,
ATTR_ES_L3_NHG_ACTIVE)
? "active"
: "inactive");
- vty_out(vty, "\n");
-
+ vty_out(vty, "\n");
+ } else if (json_paths) {
+ json_object_boolean_add(
+ json_path, "l3nhg",
+ CHECK_FLAG(attr->es_flags,
+ ATTR_ES_L3_NHG));
+ json_object_boolean_add(
+ json_path, "l3nhgActive",
+ CHECK_FLAG(attr->es_flags,
+ ATTR_ES_L3_NHG_ACTIVE));
+ }
} else {
- vty_out(vty, " Imported from ");
- vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
- (struct prefix_rd *)bgp_dest_get_prefix(
- pdest));
- vty_out(vty, ":%pFX\n",
- (struct prefix_evpn *)
- bgp_dest_get_prefix(dest));
+ if (json_paths) {
+ json_object_string_addf(
+ json_path, "importedFrom",
+ BGP_RD_AS_FORMAT(bgp->asnotation),
+ (struct prefix_rd *)
+ bgp_dest_get_prefix(
+ pdest));
+ } else {
+ vty_out(vty, " Imported from ");
+ vty_out(vty,
+ BGP_RD_AS_FORMAT(bgp->asnotation),
+ (struct prefix_rd *)
+ bgp_dest_get_prefix(
+ pdest));
+ vty_out(vty, ":%pFX\n",
+ (struct prefix_evpn *)
+ bgp_dest_get_prefix(
+ dest));
+ }
}
}
}
@@ -11108,9 +11183,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, ", otc %u", attr->otc);
}
- if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH)
- || (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)
- && bgp_path_info_mpath_count(path))) {
+ if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH) ||
+ (CHECK_FLAG(path->flags, BGP_PATH_SELECTED) && bgp_path_info_mpath_count(path) > 1)) {
if (json_paths)
json_object_boolean_true_add(json_path, "multipath");
else
@@ -11885,10 +11959,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa
if (!use_json)
route_vty_out_detail_header(
vty, bgp, dest,
- bgp_dest_get_prefix(
- dest),
+ bgp_dest_get_prefix(dest),
prd, table->afi, safi,
- NULL, false);
+ NULL, false, false);
route_vty_out_detail(
vty, bgp, dest, dest_p, pi,
@@ -11961,10 +12034,12 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa
prd = bgp_rd_from_dest(dest, safi);
- route_vty_out_detail_header(
- vty, bgp, dest,
- bgp_dest_get_prefix(dest), prd,
- table->afi, safi, json_paths, true);
+ route_vty_out_detail_header(vty, bgp, dest,
+ bgp_dest_get_prefix(
+ dest),
+ prd, table->afi,
+ safi, json_paths,
+ true, false);
vty_out(vty, "\"paths\": ");
json_detail_header_used = true;
@@ -12092,7 +12167,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
bgp = bgp_get_default();
}
- if (bgp == NULL) {
+ if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) {
if (!use_json)
vty_out(vty, "No BGP process is configured\n");
else
@@ -12138,6 +12213,8 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
vty_out(vty, "{\n");
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (IS_BGP_INSTANCE_HIDDEN(bgp))
+ continue;
route_output = true;
if (use_json) {
if (!is_first)
@@ -12170,7 +12247,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
struct bgp_dest *dest, const struct prefix *p,
const struct prefix_rd *prd, afi_t afi,
safi_t safi, json_object *json,
- bool incremental_print)
+ bool incremental_print, bool local_table)
{
struct bgp_path_info *pi;
struct peer *peer;
@@ -12388,8 +12465,14 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
json_object_object_add(json, "advertisedTo",
json_adv_to);
} else {
- if (!json && first)
- vty_out(vty, " Not advertised to any peer");
+ if (!json && first) {
+ if (!local_table)
+ vty_out(vty,
+ " Not advertised to any peer");
+ else
+ vty_out(vty,
+ " Local BGP table not advertised");
+ }
vty_out(vty, "\n");
}
}
@@ -12428,10 +12511,10 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
}
if (header) {
- route_vty_out_detail_header(
- vty, bgp, bgp_node,
- bgp_dest_get_prefix(bgp_node), pfx_rd, AFI_IP,
- safi, json_header, false);
+ route_vty_out_detail_header(vty, bgp, bgp_node,
+ bgp_dest_get_prefix(bgp_node),
+ pfx_rd, AFI_IP, safi,
+ json_header, false, false);
header = 0;
}
(*display)++;
@@ -12650,7 +12733,7 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str,
{
if (!bgp) {
bgp = bgp_get_default();
- if (!bgp) {
+ if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) {
if (!use_json)
vty_out(vty, "No BGP process is configured\n");
else
@@ -12901,7 +12984,7 @@ DEFUN (show_ip_bgp_l2vpn_evpn_statistics,
struct json_object *json_afi_safi = NULL, *json = NULL;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
- &bgp, false);
+ &bgp, uj);
if (!idx)
return CMD_WARNING;
@@ -12939,7 +13022,7 @@ DEFUN(show_ip_bgp_afi_safi_statistics, show_ip_bgp_afi_safi_statistics_cmd,
struct json_object *json_afi_safi = NULL, *json = NULL;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
- &bgp, false);
+ &bgp, uj);
if (!idx)
return CMD_WARNING;
@@ -13602,6 +13685,8 @@ enum bgp_stats {
BGP_STATS_ASPATH_MAXSIZE,
BGP_STATS_ASPATH_TOTSIZE,
BGP_STATS_ASN_HIGHEST,
+ BGP_STATS_REDISTRIBUTED,
+ BGP_STATS_LOCAL_AGGREGATES,
BGP_STATS_MAX,
};
@@ -13631,6 +13716,8 @@ static const char *table_stats_strs[][2] = {
[BGP_STATS_ASPATH_TOTSIZE] = {"Average AS-Path size (bytes)",
"averageAsPathSizeBytes"},
[BGP_STATS_ASN_HIGHEST] = {"Highest public ASN", "highestPublicAsn"},
+ [BGP_STATS_REDISTRIBUTED] = {"Redistributed routes", "totalRedistributed"},
+ [BGP_STATS_LOCAL_AGGREGATES] = {"Local aggregates", "totalLocalAggregates"},
[BGP_STATS_MAX] = {NULL, NULL}
};
@@ -13680,6 +13767,15 @@ static void bgp_table_stats_rn(struct bgp_dest *dest, struct bgp_dest *top,
ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)))
ts->counts[BGP_STATS_AGGREGATES]++;
+ if (pi->peer == ts->table->bgp->peer_self) {
+ if (pi->sub_type == BGP_ROUTE_REDISTRIBUTE)
+ ts->counts[BGP_STATS_REDISTRIBUTED]++;
+
+ if ((pi->type == ZEBRA_ROUTE_BGP) &&
+ (pi->sub_type == BGP_ROUTE_AGGREGATE))
+ ts->counts[BGP_STATS_LOCAL_AGGREGATES]++;
+ }
+
/* as-path stats */
if (pi->attr->aspath) {
unsigned int hops = aspath_count_hops(pi->attr->aspath);
@@ -14295,7 +14391,7 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix,
int idx = 0;
char *network = NULL;
struct bgp *bgp = bgp_get_default();
- if (!bgp) {
+ if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "Can't find default instance\n");
return CMD_WARNING;
}
@@ -15797,7 +15893,7 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
/* BGP structure lookup. */
if (view_name) {
bgp = bgp_lookup_by_name(view_name);
- if (bgp == NULL) {
+ if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "%% Can't find BGP instance %s\n",
view_name);
return CMD_WARNING;
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 89449ac5b9..d71bfd3ebc 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -313,6 +313,11 @@ struct bgp_path_info {
#define BGP_PATH_STALE (1 << 8)
#define BGP_PATH_REMOVED (1 << 9)
#define BGP_PATH_COUNTED (1 << 10)
+/*
+ * A BGP_PATH_MULTIPATH flag is not set on the best path
+ * it is set on every other node that is part of ECMP
+ * for that particular dest
+ */
#define BGP_PATH_MULTIPATH (1 << 11)
#define BGP_PATH_MULTIPATH_CHG (1 << 12)
#define BGP_PATH_RIB_ATTR_CHG (1 << 13)
@@ -322,6 +327,15 @@ struct bgp_path_info {
#define BGP_PATH_MPLSVPN_LABEL_NH (1 << 17)
#define BGP_PATH_MPLSVPN_NH_LABEL_BIND (1 << 18)
#define BGP_PATH_UNSORTED (1 << 19)
+/*
+ * BGP_PATH_MULTIPATH_NEW is set on those bgp_path_info
+ * nodes that we have decided should possibly be in the
+ * ecmp path for a particular dest. This flag is
+ * removed when the bgp_path_info's are looked at to
+ * decide on whether or not a bgp_path_info is on
+ * the actual ecmp path.
+ */
+#define BGP_PATH_MULTIPATH_NEW (1 << 20)
/* BGP route type. This can be static, RIP, OSPF, BGP etc. */
uint8_t type;
@@ -561,6 +575,11 @@ struct bgp_aggregate {
/* path PREFIX (addpath rxid NUMBER) */
#define PATH_ADDPATH_STR_BUFFER PREFIX2STR_BUFFER + 32
+#define BGP_PATH_INFO_NUM_LABELS(pi) \
+ ((pi) && (pi)->extra && (pi)->extra->labels \
+ ? (pi)->extra->labels->num_labels \
+ : 0)
+
enum bgp_path_type {
BGP_PATH_SHOW_ALL,
BGP_PATH_SHOW_BESTPATH,
@@ -748,7 +767,6 @@ extern void bgp_path_info_delete(struct bgp_dest *dest,
extern struct bgp_path_info_extra *
bgp_path_info_extra_get(struct bgp_path_info *path);
extern bool bgp_path_info_has_valid_label(const struct bgp_path_info *path);
-extern uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi);
extern void bgp_path_info_set_flag(struct bgp_dest *dest,
struct bgp_path_info *path, uint32_t flag);
extern void bgp_path_info_unset_flag(struct bgp_dest *dest,
@@ -798,13 +816,22 @@ extern void bgp_update(struct peer *peer, const struct prefix *p,
extern void bgp_withdraw(struct peer *peer, const struct prefix *p,
uint32_t addpath_id, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd,
- mpls_label_t *label, uint8_t num_labels,
- struct bgp_route_evpn *evpn);
+ mpls_label_t *label, uint8_t num_labels);
-/* for bgp_nexthop and bgp_damp */
+/*
+ * Add a route to be processed for bgp bestpath through the bgp
+ * workqueue. This route is added to the end of all other routes
+ * queued for processing
+ *
+ * bgp_process_early adds the route for processing at the beginning
+ * of the current queue for processing.
+ */
extern void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info *pi, afi_t afi, safi_t safi);
+extern void bgp_process_early(struct bgp *bgp, struct bgp_dest *dest,
+ struct bgp_path_info *pi, afi_t afi, safi_t safi);
+
/*
* Add an end-of-initial-update marker to the process queue. This is just a
* queue element with NULL bgp node.
@@ -900,7 +927,8 @@ extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
const struct prefix *p,
const struct prefix_rd *prd, afi_t afi,
safi_t safi, json_object *json,
- bool incremental_print);
+ bool incremental_print,
+ bool local_table);
extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
struct bgp_dest *bn, const struct prefix *p,
struct bgp_path_info *path, afi_t afi,
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 3ba368aaf7..583b9e7980 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -251,7 +251,7 @@ route_match_peer(void *rule, const struct prefix *prefix, void *object)
peer = ((struct bgp_path_info *)object)->peer;
if (pc->interface) {
- if (!peer->conf_if || !peer->group)
+ if (!peer->conf_if && !peer->group)
return RMAP_NOMATCH;
if (peer->conf_if && strcmp(peer->conf_if, pc->interface) == 0)
@@ -1081,7 +1081,7 @@ route_match_vni(void *rule, const struct prefix *prefix, void *object)
return RMAP_NOOP;
for (label_cnt = 0; label_cnt < BGP_MAX_LABELS &&
- label_cnt < bgp_path_info_num_labels(path);
+ label_cnt < BGP_PATH_INFO_NUM_LABELS(path);
label_cnt++) {
if (vni == label2vni(&path->extra->labels->label[label_cnt]))
return RMAP_MATCH;
@@ -1236,6 +1236,8 @@ route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
struct ipaddr *gw_ip = rule;
struct bgp_path_info *path;
struct prefix_evpn *evp;
+ struct bgp_route_evpn *bre = XCALLOC(MTYPE_BGP_EVPN_OVERLAY,
+ sizeof(struct bgp_route_evpn));
if (prefix->family != AF_EVPN)
return RMAP_OKAY;
@@ -1251,9 +1253,9 @@ route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
path = object;
/* Set gateway-ip value. */
- path->attr->evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
- memcpy(&path->attr->evpn_overlay.gw_ip, &gw_ip->ip.addr,
- IPADDRSZ(gw_ip));
+ bre->type = OVERLAY_INDEX_GATEWAY_IP;
+ memcpy(&bre->gw_ip, &gw_ip->ip.addr, IPADDRSZ(gw_ip));
+ bgp_attr_set_evpn_overlay(path->attr, bre);
return RMAP_OKAY;
}
@@ -1990,10 +1992,9 @@ route_set_ip_nexthop(void *rule, const struct prefix *prefix, void *object)
SET_FLAG(path->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_UNCHANGED);
} else if (rins->peer_address) {
- if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
- || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT))
- && peer->su_remote
- && sockunion_family(peer->su_remote) == AF_INET) {
+ if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)) &&
+ peer->su_remote &&
+ sockunion_family(peer->su_remote) == AF_INET) {
path->attr->nexthop.s_addr =
sockunion2ip(peer->su_remote);
path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
@@ -2356,7 +2357,7 @@ static void route_aspath_exclude_free(void *rule)
if (ase->exclude_aspath_acl) {
acl = ase->exclude_aspath_acl;
as_list_list_del(&acl->exclude_rule, ase);
- } else {
+ } else if (ase->exclude_aspath_acl_name) {
/* no ref to acl, this aspath exclude is orphan */
as_exclude_remove_orphan(ase);
}
@@ -3219,7 +3220,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
return RMAP_OKAY;
bw_bytes = (peer->bgp->lb_ref_bw * 1000 * 1000) / 8;
- mpath_count = bgp_path_info_mpath_count(path) + 1;
+ mpath_count = bgp_path_info_mpath_count(path);
bw_bytes *= mpath_count;
}
@@ -3948,8 +3949,7 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
path = object;
peer = path->peer;
- if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
- || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) {
+ if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)) {
/* Set next hop preference to global */
SET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL);
SET_FLAG(path->attr->rmap_change_flags,
@@ -4075,10 +4075,8 @@ route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx, void *object)
path = object;
peer = path->peer;
- if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
- || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT))
- && peer->su_remote
- && sockunion_family(peer->su_remote) == AF_INET6) {
+ if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)) &&
+ peer->su_remote && sockunion_family(peer->su_remote) == AF_INET6) {
peer_address = peer->su_remote->sin6.sin6_addr;
/* Set next hop value and length in attribute. */
if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) {
@@ -4093,7 +4091,6 @@ route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx, void *object)
path->attr->mp_nexthop_len =
BGP_ATTR_NHLEN_IPV6_GLOBAL;
}
-
} else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) {
/* The next hop value will be set as part of packet
* rewrite.
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index a487f49e64..347c5d02a1 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -439,7 +439,9 @@ static void rpki_delete_all_cache_nodes(struct rpki_vrf *rpki_vrf)
for (ALL_LIST_ELEMENTS(rpki_vrf->cache_list, cache_node, cache_next,
cache)) {
- rtr_mgr_remove_group(rpki_vrf->rtr_config, cache->preference);
+ if (is_running(rpki_vrf))
+ rtr_mgr_remove_group(rpki_vrf->rtr_config,
+ cache->preference);
listnode_delete(rpki_vrf->cache_list, cache);
}
}
@@ -664,7 +666,7 @@ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi,
struct bgp_path_info *path =
bgp_dest_get_bgp_path_info(bgp_dest);
- num_labels = bgp_path_info_num_labels(path);
+ num_labels = BGP_PATH_INFO_NUM_LABELS(path);
label = num_labels ? path->extra->labels->label : NULL;
(void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest),
@@ -1918,81 +1920,6 @@ DEFUN (no_rpki_retry_interval,
return CMD_SUCCESS;
}
-#if CONFDATE > 20240916
-CPP_NOTICE("Remove rpki_cache_cmd")
-#endif
-DEFPY(rpki_cache, rpki_cache_cmd,
- "rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH]> [source <A.B.C.D>$bindaddr] preference (1-255)",
- RPKI_OUTPUT_STRING
- "Install a cache server to current group\n"
- "IP address of cache server\n"
- "Hostname of cache server\n"
- "TCP port number\n"
- "SSH port number\n"
- "SSH user name\n"
- "Path to own SSH private key\n"
- "Path to the known hosts file\n"
- "Configure source IP address of RPKI connection\n"
- "Define a Source IP Address\n"
- "Preference of the cache server\n"
- "Preference value\n")
-{
- int return_value;
- struct listnode *cache_node;
- struct cache *current_cache;
- struct rpki_vrf *rpki_vrf;
- bool init;
-
- if (vty->node == RPKI_VRF_NODE)
- rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf);
- else
- rpki_vrf = VTY_GET_CONTEXT(rpki_vrf);
-
- if (!rpki_vrf)
- return CMD_WARNING_CONFIG_FAILED;
-
- if (!rpki_vrf || !rpki_vrf->cache_list)
- return CMD_WARNING;
-
- init = !!list_isempty(rpki_vrf->cache_list);
-
- for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node,
- current_cache)) {
- if (current_cache->preference == preference) {
- vty_out(vty,
- "Cache with preference %ld is already configured\n",
- preference);
- return CMD_WARNING;
- }
- }
-
- // use ssh connection
- if (ssh_uname) {
-#if defined(FOUND_SSH)
- return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname,
- ssh_privkey, known_hosts_path,
- preference, bindaddr_str);
-#else
- return_value = SUCCESS;
- vty_out(vty,
- "ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n");
-#endif
- } else { // use tcp connection
- return_value = add_tcp_cache(rpki_vrf, cache, tcpport,
- preference, bindaddr_str);
- }
-
- if (return_value == ERROR) {
- vty_out(vty, "Could not create new rpki cache\n");
- return CMD_WARNING;
- }
-
- if (init)
- start(rpki_vrf);
-
- return CMD_SUCCESS;
-}
-
DEFPY(rpki_cache_tcp, rpki_cache_tcp_cmd,
"rpki cache tcp <A.B.C.D|WORD>$cache TCPPORT [source <A.B.C.D>$bindaddr] preference (1-255)",
RPKI_OUTPUT_STRING
@@ -2818,7 +2745,6 @@ static void install_cli_commands(void)
/* Install rpki cache commands */
install_element(RPKI_NODE, &rpki_cache_tcp_cmd);
install_element(RPKI_NODE, &rpki_cache_ssh_cmd);
- install_element(RPKI_NODE, &rpki_cache_cmd);
install_element(RPKI_NODE, &no_rpki_cache_cmd);
/* RPKI_VRF_NODE commands */
@@ -2842,7 +2768,6 @@ static void install_cli_commands(void)
/* Install rpki cache commands */
install_element(RPKI_VRF_NODE, &rpki_cache_tcp_cmd);
install_element(RPKI_VRF_NODE, &rpki_cache_ssh_cmd);
- install_element(RPKI_VRF_NODE, &rpki_cache_cmd);
install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd);
/* Install show commands */
diff --git a/bgpd/bgp_script.h b/bgpd/bgp_script.h
index f2f47e940d..9feb550135 100644
--- a/bgpd/bgp_script.h
+++ b/bgpd/bgp_script.h
@@ -7,7 +7,6 @@
#define __BGP_SCRIPT__
#include <zebra.h>
-#include "bgpd.h"
#ifdef HAVE_SCRIPTING
@@ -18,6 +17,10 @@
*/
void bgp_script_init(void);
+/* Forward references */
+struct peer;
+struct attr;
+
void lua_pushpeer(lua_State *L, const struct peer *peer);
void lua_pushattr(lua_State *L, const struct attr *attr);
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c
index 70369104a2..e8c3e6513d 100644
--- a/bgpd/bgp_snmp_bgp4v2.c
+++ b/bgpd/bgp_snmp_bgp4v2.c
@@ -340,7 +340,8 @@ static uint8_t *bgpv2PeerErrorsTable(struct variable *v, oid name[],
}
return SNMP_STRING("");
case BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA:
- if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED &&
+ peer->notify.data)
return SNMP_STRING(peer->notify.data);
else
return SNMP_STRING("");
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index b717793a45..90c43b938f 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -783,8 +783,11 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
json_updgrp, "replaceLocalAs",
CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_REPLACE_AS));
+ json_object_boolean_add(json_updgrp, "dualAs",
+ CHECK_FLAG(updgrp->conf->flags,
+ PEER_FLAG_DUAL_AS));
} else {
- vty_out(vty, " Local AS %u%s%s\n",
+ vty_out(vty, " Local AS %u%s%s%s\n",
updgrp->conf->change_local_as,
CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_NO_PREPEND)
@@ -793,6 +796,10 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_REPLACE_AS)
? " replace-as"
+ : "",
+ CHECK_FLAG(updgrp->conf->flags,
+ PEER_FLAG_DUAL_AS)
+ ? " dual-as"
: "");
}
}
@@ -2016,6 +2023,8 @@ int update_group_adjust_soloness(struct peer *peer, int set)
struct peer_group *group;
struct listnode *node, *nnode;
+ peer_flag_set(peer, PEER_FLAG_LONESOUL);
+
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
peer_lonesoul_or_not(peer, set);
if (peer_established(peer->connection))
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 12feac8353..bed00a6640 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -508,9 +508,6 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
gnh_modified = 1;
}
} else if (IN6_IS_ADDR_UNSPECIFIED(&v6nhglobal)) {
- /* the UPDATE is originating from the local router.
- * Build the global nexthop.
- */
mod_v6nhg = &peer->nexthop.v6_global;
gnh_modified = 1;
} else if ((peer->sort == BGP_PEER_EBGP)
@@ -524,32 +521,16 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
*/
mod_v6nhg = &peer->nexthop.v6_global;
gnh_modified = 1;
- } else if (IS_MAPPED_IPV6(&v6nhglobal) &&
- !IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)) {
- /* prefer a IPv6 native global address over
- * an IPv4-mapped IPv6 address as nexthop when
- * forwarding UPDATEs.
- */
- mod_v6nhg = &peer->nexthop.v6_global;
- gnh_modified = 1;
}
- if (peer->nexthop.v4.s_addr != INADDR_ANY &&
- (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg) ||
- (IN6_IS_ADDR_LINKLOCAL(mod_v6nhg) &&
- ((peer->connection->su.sa.sa_family == AF_INET6 &&
- paf->afi == AFI_IP) ||
- (peer->connection->su.sa.sa_family == AF_INET &&
- paf->afi == AFI_IP6))))) {
- ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, peer->nexthop.v4);
- gnh_modified = 1;
+ if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) {
+ if (peer->nexthop.v4.s_addr != INADDR_ANY) {
+ ipv4_to_ipv4_mapped_ipv6(mod_v6nhg,
+ peer->nexthop.v4);
+ }
}
if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) {
- /* If the interface to the peer has no global IPv6
- * address, replace the nexthop in UPDATE with
- * the IPv4-mapped IPv6 address if any.
- */
mod_v6nhg = &peer->nexthop.v6_global;
gnh_modified = 1;
}
@@ -832,7 +813,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
label_pnt = &label;
num_labels = 1;
} else {
- num_labels = bgp_path_info_num_labels(path);
+ num_labels = BGP_PATH_INFO_NUM_LABELS(path);
label_pnt =
num_labels
? &path->extra->labels->label[0]
@@ -880,7 +861,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p,
label_pnt, num_labels,
addpath_capable, addpath_tx_id,
- &adv->baa->attr->evpn_overlay,
+ bgp_attr_get_evpn_overlay(
+ adv->baa->attr),
pfx_buf, sizeof(pfx_buf));
zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
subgrp->update_group->id, subgrp->id,
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index c9c7b80496..e7be2a33d2 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -302,18 +302,11 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
/* unset srv6 locator */
static int bgp_srv6_locator_unset(struct bgp *bgp)
{
- int ret;
struct listnode *node, *nnode;
struct srv6_locator_chunk *chunk;
struct bgp_srv6_function *func;
struct bgp *bgp_vrf;
- /* release chunk notification via ZAPI */
- ret = bgp_zebra_srv6_manager_release_locator_chunk(
- bgp->srv6_locator_name);
- if (ret < 0)
- return -1;
-
/* refresh chunks */
for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk)) {
listnode_delete(bgp->srv6_locator_chunks, chunk);
@@ -352,20 +345,28 @@ static int bgp_srv6_locator_unset(struct bgp *bgp)
continue;
/* refresh vpnv4 tovpn_sid_locator */
- srv6_locator_chunk_free(
- &bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
+ srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator = NULL;
/* refresh vpnv6 tovpn_sid_locator */
- srv6_locator_chunk_free(
- &bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
+ srv6_locator_free(
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator = NULL;
/* refresh per-vrf tovpn_sid_locator */
- srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator);
+ srv6_locator_free(bgp_vrf->tovpn_sid_locator);
+ bgp_vrf->tovpn_sid_locator = NULL;
}
/* clear locator name */
memset(bgp->srv6_locator_name, 0, sizeof(bgp->srv6_locator_name));
+ /* clear SRv6 locator */
+ if (bgp->srv6_locator) {
+ srv6_locator_free(bgp->srv6_locator);
+ bgp->srv6_locator = NULL;
+ }
+
return 0;
}
@@ -878,6 +879,7 @@ int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret)
switch (ret) {
case BGP_SUCCESS:
case BGP_CREATED:
+ case BGP_INSTANCE_EXISTS:
case BGP_GR_NO_OPERATION:
break;
case BGP_ERR_INVALID_VALUE:
@@ -1417,7 +1419,7 @@ DEFUN_HIDDEN (bgp_local_mac,
seq = strtoul(argv[7]->arg, NULL, 10);
bgp = bgp_get_default();
- if (!bgp) {
+ if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "Default BGP instance is not there\n");
return CMD_WARNING;
}
@@ -1457,7 +1459,7 @@ DEFUN_HIDDEN (no_bgp_local_mac,
memset(&ip, 0, sizeof(ip));
bgp = bgp_get_default();
- if (!bgp) {
+ if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "Default BGP instance is not there\n");
return CMD_WARNING;
}
@@ -1600,8 +1602,12 @@ DEFUN_NOSH (router_bgp,
if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT)
vpn_leak_postchange_all();
- if (inst_type == BGP_INSTANCE_TYPE_VRF)
+ if (inst_type == BGP_INSTANCE_TYPE_VRF ||
+ IS_BGP_INSTANCE_HIDDEN(bgp)) {
bgp_vpn_leak_export(bgp);
+ UNSET_FLAG(bgp->flags, BGP_FLAG_INSTANCE_HIDDEN);
+ UNSET_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS);
+ }
/* Pending: handle when user tries to change a view to vrf n vv.
*/
/* for pre-existing bgp instance,
@@ -1673,7 +1679,7 @@ DEFUN (no_router_bgp,
argv[idx_asn]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
- if (argc > 4) {
+ if (argc > 4 && strncmp(argv[4]->arg, "vrf", 3) == 0) {
name = argv[idx_vrf]->arg;
if (strmatch(argv[idx_vrf - 1]->text, "vrf")
&& strmatch(name, VRF_DEFAULT_NAME))
@@ -5450,7 +5456,7 @@ DEFUN (neighbor_local_as,
return CMD_WARNING_CONFIG_FAILED;
}
- ret = peer_local_as_set(peer, as, 0, 0, argv[idx_number]->arg);
+ ret = peer_local_as_set(peer, as, 0, 0, 0, argv[idx_number]->arg);
return bgp_vty_return(vty, ret);
}
@@ -5479,19 +5485,20 @@ DEFUN (neighbor_local_as_no_prepend,
return CMD_WARNING_CONFIG_FAILED;
}
- ret = peer_local_as_set(peer, as, 1, 0, argv[idx_number]->arg);
+ ret = peer_local_as_set(peer, as, 1, 0, 0, argv[idx_number]->arg);
return bgp_vty_return(vty, ret);
}
-DEFUN (neighbor_local_as_no_prepend_replace_as,
+DEFPY (neighbor_local_as_no_prepend_replace_as,
neighbor_local_as_no_prepend_replace_as_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend replace-as",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend replace-as [dual-as$dual_as]",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number expressed in dotted or plain format used as local AS\n"
"Do not prepend local-as to updates from ebgp peers\n"
- "Do not prepend local-as to updates from ibgp peers\n")
+ "Do not prepend local-as to updates from ibgp peers\n"
+ "Allow peering with a global AS number or local-as number\n")
{
int idx_peer = 1;
int idx_number = 3;
@@ -5509,20 +5516,21 @@ DEFUN (neighbor_local_as_no_prepend_replace_as,
return CMD_WARNING_CONFIG_FAILED;
}
- ret = peer_local_as_set(peer, as, 1, 1, argv[idx_number]->arg);
+ ret = peer_local_as_set(peer, as, 1, 1, dual_as, argv[idx_number]->arg);
return bgp_vty_return(vty, ret);
}
DEFUN (no_neighbor_local_as,
no_neighbor_local_as_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [ASNUM [no-prepend [replace-as]]]",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [ASNUM [no-prepend [replace-as] [dual-as]]]",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number expressed in dotted or plain format used as local AS\n"
"Do not prepend local-as to updates from ebgp peers\n"
- "Do not prepend local-as to updates from ibgp peers\n")
+ "Do not prepend local-as to updates from ibgp peers\n"
+ "Allow peering with a global AS number or local-as number\n")
{
int idx_peer = 2;
struct peer *peer;
@@ -8416,7 +8424,7 @@ DEFPY (bgp_condadv_period,
DEFPY (bgp_def_originate_eval,
bgp_def_originate_eval_cmd,
- "[no$no] bgp default-originate timer (0-3600)$timer",
+ "[no$no] bgp default-originate timer (0-65535)$timer",
NO_STR
BGP_STR
"Control default-originate\n"
@@ -8425,8 +8433,7 @@ DEFPY (bgp_def_originate_eval,
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp->rmap_def_originate_eval_timer =
- no ? RMAP_DEFAULT_ORIGINATE_EVAL_TIMER : timer;
+ bgp->rmap_def_originate_eval_timer = no ? 0 : timer;
if (bgp->t_rmap_def_originate_eval)
EVENT_OFF(bgp->t_rmap_def_originate_eval);
@@ -10444,9 +10451,9 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd,
bgp_default = bgp_get_default();
if (!bgp_default) {
int32_t ret;
- as_t as = bgp->as;
+ as_t as = AS_UNSPECIFIED;
- /* Auto-create assuming the same AS */
+ /* Auto-create with AS_UNSPECIFIED, to be filled in later */
ret = bgp_get_vty(&bgp_default, &as, NULL,
BGP_INSTANCE_TYPE_DEFAULT, NULL,
ASNOTATION_UNDEFINED);
@@ -10456,6 +10463,8 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd,
"VRF default is not configured as a bgp instance\n");
return CMD_WARNING;
}
+
+ SET_FLAG(bgp_default->flags, BGP_FLAG_INSTANCE_HIDDEN);
}
vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
@@ -10559,7 +10568,9 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
bgp_default = bgp_get_default();
if (!bgp_default) {
- /* Auto-create assuming the same AS */
+ as = AS_UNSPECIFIED;
+
+ /* Auto-create with AS_UNSPECIFIED, to be filled in later */
ret = bgp_get_vty(&bgp_default, &as, NULL,
BGP_INSTANCE_TYPE_DEFAULT, NULL,
ASNOTATION_UNDEFINED);
@@ -10569,6 +10580,8 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
"VRF default is not configured as a bgp instance\n");
return CMD_WARNING;
}
+
+ SET_FLAG(bgp_default->flags, BGP_FLAG_INSTANCE_HIDDEN);
}
vrf_bgp = bgp_lookup_by_name(import_name);
@@ -10576,9 +10589,19 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) {
vrf_bgp = bgp_default;
} else {
- /* Auto-create assuming the same AS */
+ as = AS_UNSPECIFIED;
+
+ /* Auto-create with AS_UNSPECIFIED, fill in later */
ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type,
NULL, ASNOTATION_UNDEFINED);
+ if (ret) {
+ vty_out(vty,
+ "VRF %s is not configured as a bgp instance\n",
+ import_name);
+ return CMD_WARNING;
+ }
+
+ SET_FLAG(vrf_bgp->flags, BGP_FLAG_INSTANCE_HIDDEN);
/* Auto created VRF instances should be marked
* properly, otherwise we have a state after bgpd
@@ -10586,13 +10609,6 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
*/
SET_FLAG(vrf_bgp->vrf_flags, BGP_VRF_AUTO);
}
-
- if (ret) {
- vty_out(vty,
- "VRF %s is not configured as a bgp instance\n",
- import_name);
- return CMD_WARNING;
- }
}
if (remove) {
@@ -10878,7 +10894,7 @@ DEFPY (bgp_srv6_locator,
snprintf(bgp->srv6_locator_name,
sizeof(bgp->srv6_locator_name), "%s", name);
- ret = bgp_zebra_srv6_manager_get_locator_chunk(name);
+ ret = bgp_zebra_srv6_manager_get_locator(name);
if (ret < 0)
return CMD_WARNING_CONFIG_FAILED;
@@ -10929,6 +10945,17 @@ DEFPY (show_bgp_srv6,
return CMD_SUCCESS;
vty_out(vty, "locator_name: %s\n", bgp->srv6_locator_name);
+ if (bgp->srv6_locator) {
+ vty_out(vty, " prefix: %pFX\n", &bgp->srv6_locator->prefix);
+ vty_out(vty, " block-length: %d\n",
+ bgp->srv6_locator->block_bits_length);
+ vty_out(vty, " node-length: %d\n",
+ bgp->srv6_locator->node_bits_length);
+ vty_out(vty, " func-length: %d\n",
+ bgp->srv6_locator->function_bits_length);
+ vty_out(vty, " arg-length: %d\n",
+ bgp->srv6_locator->argument_bits_length);
+ }
vty_out(vty, "locator_chunks:\n");
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
vty_out(vty, "- %pFX\n", &chunk->prefix);
@@ -11538,7 +11565,7 @@ DEFUN(show_bgp_martian_nexthop_db, show_bgp_martian_nexthop_db_cmd,
else
bgp = bgp_get_default();
- if (!bgp) {
+ if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) {
vty_out(vty, "%% No BGP process is configured\n");
return CMD_WARNING;
}
@@ -12770,6 +12797,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
continue;
+ if (IS_BGP_INSTANCE_HIDDEN(bgp))
+ continue;
+
nbr_output = true;
if (use_json) {
if (!is_first)
@@ -14040,6 +14070,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
if (CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS))
json_object_boolean_true_add(json_neigh,
"localAsReplaceAs");
+
+ json_object_boolean_add(json_neigh, "localAsReplaceAsDualAs",
+ !!CHECK_FLAG(p->flags,
+ PEER_FLAG_DUAL_AS));
} else {
if (p->as_type == AS_SPECIFIED ||
CHECK_FLAG(p->as_type, AS_AUTO) ||
@@ -14054,13 +14088,15 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
vty_out(vty, ASN_FORMAT(bgp->asnotation),
p->change_local_as ? &p->change_local_as
: &p->local_as);
- vty_out(vty, "%s%s, ",
+ vty_out(vty, "%s%s%s, ",
CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
? " no-prepend"
: "",
CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
? " replace-as"
- : "");
+ : "",
+ CHECK_FLAG(p->flags, PEER_FLAG_DUAL_AS) ? " dual-as"
+ : "");
}
/* peer type internal or confed-internal */
if ((p->as == p->local_as) || (CHECK_FLAG(p->as_type, AS_INTERNAL))) {
@@ -16158,6 +16194,9 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
continue;
+ if (IS_BGP_INSTANCE_HIDDEN(bgp))
+ continue;
+
nbr_output = true;
if (use_json) {
if (!(json = json_object_new_object())) {
@@ -16813,6 +16852,9 @@ static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
continue;
+ if (IS_BGP_INSTANCE_HIDDEN(bgp))
+ continue;
+
if (!uj)
vty_out(vty, "\nInstance %s:\n",
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
@@ -16935,7 +16977,7 @@ DEFUN (show_bgp_updgrps_stats,
struct bgp *bgp;
bgp = bgp_get_default();
- if (bgp)
+ if (bgp && !IS_BGP_INSTANCE_HIDDEN(bgp))
update_group_show_stats(bgp, vty);
return CMD_SUCCESS;
@@ -17072,8 +17114,13 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
vty_out(vty, "\nBGP peer-group %s\n", group->name);
}
- if ((group->bgp->as == conf->as) ||
- CHECK_FLAG(conf->as_type, AS_INTERNAL)) {
+ if (CHECK_FLAG(conf->as_type, AS_AUTO)) {
+ if (json)
+ json_object_string_add(json_peer_group, "type", "auto");
+ else
+ vty_out(vty, " Peer-group type is auto\n");
+ } else if ((group->bgp->as == conf->as) ||
+ CHECK_FLAG(conf->as_type, AS_INTERNAL)) {
if (json)
json_object_string_add(json_peer_group, "type",
"internal");
@@ -18647,6 +18694,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " no-prepend");
if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS))
vty_out(vty, " replace-as");
+ if (peergroup_flag_check(peer, PEER_FLAG_DUAL_AS))
+ vty_out(vty, " dual-as");
vty_out(vty, "\n");
}
@@ -18678,11 +18727,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
peer->password);
/* neighbor solo */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)) {
- if (!peer_group_active(peer)) {
- vty_out(vty, " neighbor %s solo\n", addr);
- }
- }
+ if (peergroup_flag_check(peer, PEER_FLAG_LONESOUL))
+ vty_out(vty, " neighbor %s solo\n", addr);
/* BGP port */
if (peer->port != BGP_PORT_DEFAULT) {
@@ -18928,6 +18974,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
char *addr;
bool flag_scomm, flag_secomm, flag_slcomm;
+ /* skip hidden default vrf bgp instance */
+ if (IS_BGP_INSTANCE_HIDDEN(bgp))
+ return;
+
/* Skip dynamic neighbors. */
if (peer_dynamic_neighbor(peer))
return;
@@ -19233,6 +19283,9 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
struct peer_group *group;
struct listnode *node, *nnode;
+ /* skip hidden default vrf bgp instance */
+ if (IS_BGP_INSTANCE_HIDDEN(bgp))
+ return;
vty_frame(vty, " !\n address-family ");
if (afi == AFI_IP) {
@@ -19415,6 +19468,10 @@ int bgp_config_write(struct vty *vty)
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
continue;
+ /* skip hidden default vrf bgp instance */
+ if (IS_BGP_INSTANCE_HIDDEN(bgp))
+ continue;
+
/* Router bgp ASN */
vty_out(vty, "router bgp %s", bgp->as_pretty);
@@ -19778,8 +19835,9 @@ int bgp_config_write(struct vty *vty)
bgp->condition_check_period);
/* default-originate timer configuration */
- if (bgp->rmap_def_originate_eval_timer !=
- RMAP_DEFAULT_ORIGINATE_EVAL_TIMER)
+ if (bgp->rmap_def_originate_eval_timer &&
+ bgp->rmap_def_originate_eval_timer !=
+ RMAP_DEFAULT_ORIGINATE_EVAL_TIMER)
vty_out(vty, " bgp default-originate timer %u\n",
bgp->rmap_def_originate_eval_timer);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 006d46d843..bffa5a0e6b 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -302,12 +302,11 @@ static int bgp_ifp_down(struct interface *ifp)
static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
{
- struct connected *ifc, *connected;
+ struct connected *ifc;
struct bgp *bgp;
struct peer *peer;
struct prefix *addr;
struct listnode *node, *nnode;
- bool v6_ll_in_nh_global;
afi_t afi;
safi_t safi;
@@ -325,70 +324,56 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
if (!bgp)
return 0;
- if (!if_is_operative(ifc->ifp))
- return 0;
-
- bgp_connected_add(bgp, ifc);
+ if (if_is_operative(ifc->ifp)) {
+ bgp_connected_add(bgp, ifc);
- /* If we have learnt of any neighbors on this interface,
- * check to kick off any BGP interface-based neighbors,
- * but only if this is a link-local address.
- */
- if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) &&
- !list_isempty(ifc->ifp->nbr_connected))
- bgp_start_interface_nbrs(bgp, ifc->ifp);
- else if (ifc->address->family == AF_INET6 &&
- !IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) {
- addr = ifc->address;
+ /* If we have learnt of any neighbors on this interface,
+ * check to kick off any BGP interface-based neighbors,
+ * but only if this is a link-local address.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)
+ && !list_isempty(ifc->ifp->nbr_connected))
+ bgp_start_interface_nbrs(bgp, ifc->ifp);
+ else {
+ addr = ifc->address;
- for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- v6_ll_in_nh_global = false;
-
- if (IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)) {
- frr_each (if_connected, ifc->ifp->connected,
- connected) {
- if (connected->address->family !=
- AF_INET6)
- continue;
- if (!IPV6_ADDR_SAME(&connected->address
- ->u.prefix6,
- &peer->nexthop
- .v6_global))
- continue;
- /* peer->nexthop.v6_global contains a link-local address
- * that needs to be replaced by the global address.
- */
- v6_ll_in_nh_global = true;
- break;
- }
- }
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (addr->family == AF_INET)
+ continue;
- /*
- * If the Peer's interface name matches the
- * interface name for which BGP received the
- * update and if the received interface address
- * is a globalV6 and if the peer is currently
- * using a v4-mapped-v6 addr or a link local
- * address, then copy the Rxed global v6 addr
- * into peer's v6_global and send updates out
- * with new nexthop addr.
- */
- if (v6_ll_in_nh_global ||
- (peer->conf_if &&
- strcmp(peer->conf_if, ifc->ifp->name) == 0 &&
- (IS_MAPPED_IPV6(&peer->nexthop.v6_global) ||
- IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)))) {
- if (bgp_debug_zebra(ifc->address)) {
- zlog_debug("Update peer %pBP's current intf global addr from %pI6 to %pI6 and send updates",
- peer,
- &peer->nexthop.v6_global,
- &addr->u.prefix6);
+ /*
+ * If the Peer's interface name matches the
+ * interface name for which BGP received the
+ * update and if the received interface address
+ * is a globalV6 and if the peer is currently
+ * using a v4-mapped-v6 addr or a link local
+ * address, then copy the Rxed global v6 addr
+ * into peer's v6_global and send updates out
+ * with new nexthop addr.
+ */
+ if ((peer->conf_if &&
+ (strcmp(peer->conf_if, ifc->ifp->name) ==
+ 0)) &&
+ !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) &&
+ ((IS_MAPPED_IPV6(
+ &peer->nexthop.v6_global)) ||
+ IN6_IS_ADDR_LINKLOCAL(
+ &peer->nexthop.v6_global))) {
+
+ if (bgp_debug_zebra(ifc->address)) {
+ zlog_debug(
+ "Update peer %pBP's current intf addr %pI6 and send updates",
+ peer,
+ &peer->nexthop
+ .v6_global);
+ }
+ memcpy(&peer->nexthop.v6_global,
+ &addr->u.prefix6,
+ IPV6_MAX_BYTELEN);
+ FOREACH_AFI_SAFI (afi, safi)
+ bgp_announce_route(peer, afi,
+ safi, true);
}
- memcpy(&peer->nexthop.v6_global,
- &addr->u.prefix6, IPV6_MAX_BYTELEN);
- FOREACH_AFI_SAFI (afi, safi)
- bgp_announce_route(peer, afi, safi,
- true);
}
}
}
@@ -399,14 +384,10 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
{
struct listnode *node, *nnode;
- struct connected *ifc, *connected;
+ struct connected *ifc;
struct peer *peer;
struct bgp *bgp;
struct prefix *addr;
- struct in6_addr *v6_global = NULL;
- struct in6_addr *v6_local = NULL;
- afi_t afi;
- safi_t safi;
bgp = bgp_lookup_by_vrf_id(vrf_id);
@@ -425,18 +406,7 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
addr = ifc->address;
- if (bgp && addr->family == AF_INET6 &&
- !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)) {
- /* find another IPv6 global if possible and find the IPv6 link-local */
- frr_each (if_connected, ifc->ifp->connected, connected) {
- if (connected->address->family != AF_INET6)
- continue;
- if (IN6_IS_ADDR_LINKLOCAL(&connected->address->u.prefix6))
- v6_local = &connected->address->u.prefix6;
- else
- v6_global = &connected->address->u.prefix6;
- }
-
+ if (bgp) {
/*
* When we are using the v6 global as part of the peering
* nexthops and we are removing it, then we need to
@@ -445,17 +415,17 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
* we do not want the peering to bounce.
*/
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- if (IPV6_ADDR_SAME(&peer->nexthop.v6_global,
- &addr->u.prefix6)) {
- if (v6_global)
- IPV6_ADDR_COPY(&peer->nexthop.v6_global,
- v6_global);
- else if (v6_local)
- IPV6_ADDR_COPY(&peer->nexthop.v6_global,
- v6_local);
- else
- memset(&peer->nexthop.v6_global, 0,
- IPV6_MAX_BYTELEN);
+ afi_t afi;
+ safi_t safi;
+
+ if (addr->family == AF_INET)
+ continue;
+
+ if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)
+ && memcmp(&peer->nexthop.v6_global,
+ &addr->u.prefix6, 16)
+ == 0) {
+ memset(&peer->nexthop.v6_global, 0, 16);
FOREACH_AFI_SAFI (afi, safi)
bgp_announce_route(peer, afi, safi,
true);
@@ -572,7 +542,7 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS)
/* Now perform the add/update. */
bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex,
- nhtype, bhtype, api.distance, api.metric,
+ nhtype, api.distance, bhtype, api.metric,
api.type, api.instance, api.tag);
} else {
bgp_redistribute_delete(bgp, &api.prefix, api.type,
@@ -1128,6 +1098,8 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
struct attr *attr, bool is_evpn,
struct zapi_nexthop *api_nh)
{
+ struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr);
+
api_nh->gate.ipv4 = *nexthop;
api_nh->vrf_id = nh_bgp->vrf_id;
@@ -1144,7 +1116,7 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
* treat the nexthop as NEXTHOP_TYPE_IPV4
* Else, mark the nexthop as onlink.
*/
- if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP)
+ if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)
api_nh->type = NEXTHOP_TYPE_IPV4;
else {
api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
@@ -1170,9 +1142,11 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
struct zapi_nexthop *api_nh)
{
struct attr *attr;
+ struct bgp_route_evpn *bre;
attr = pi->attr;
api_nh->vrf_id = nh_bgp->vrf_id;
+ bre = bgp_attr_get_evpn_overlay(attr);
if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) {
api_nh->type = attr->nh_type;
@@ -1183,7 +1157,7 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
* treat the nexthop as NEXTHOP_TYPE_IPV4
* Else, mark the nexthop as onlink.
*/
- if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP)
+ if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)
api_nh->type = NEXTHOP_TYPE_IPV6;
else {
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
@@ -1281,6 +1255,7 @@ static void bgp_zebra_announce_parse_nexthop(
uint32_t ttl = 0;
uint32_t bos = 0;
uint32_t exp = 0;
+ struct bgp_route_evpn *bre = NULL;
/* Determine if we're doing weighted ECMP or not */
do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info);
@@ -1336,7 +1311,7 @@ static void bgp_zebra_announce_parse_nexthop(
api_nh->srte_color = bgp_attr_get_color(info->attr);
if (bgp_debug_zebra(&api->prefix)) {
- if (bgp_path_info_num_labels(mpinfo)) {
+ if (BGP_PATH_INFO_NUM_LABELS(mpinfo)) {
zlog_debug("%s: p=%pFX, bgp_is_valid_label: %d",
__func__, p,
bgp_is_valid_label(
@@ -1395,6 +1370,7 @@ static void bgp_zebra_announce_parse_nexthop(
}
is_evpn = !!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN);
+ bre = bgp_attr_get_evpn_overlay(mpinfo->attr);
/* Did we get proper nexthop info to update zebra? */
if (!nh_updated)
@@ -1409,7 +1385,7 @@ static void bgp_zebra_announce_parse_nexthop(
mpinfo->peer->sort == BGP_PEER_CONFED))
*allow_recursion = true;
- num_labels = bgp_path_info_num_labels(mpinfo);
+ num_labels = BGP_PATH_INFO_NUM_LABELS(mpinfo);
labels = num_labels ? mpinfo->extra->labels->label : NULL;
if (num_labels && (is_evpn || bgp_is_valid_label(&labels[0]))) {
@@ -1430,9 +1406,7 @@ static void bgp_zebra_announce_parse_nexthop(
api_nh->labels[0] = nh_label;
}
- if (is_evpn
- && mpinfo->attr->evpn_overlay.type
- != OVERLAY_INDEX_GATEWAY_IP)
+ if (is_evpn && !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP))
memcpy(&api_nh->rmac, &(mpinfo->attr->rmac),
sizeof(struct ethaddr));
@@ -3405,11 +3379,278 @@ static int bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
return 0;
}
+/**
+ * Internal function to process an SRv6 locator
+ *
+ * @param locator The locator to be processed
+ */
+static int bgp_zebra_process_srv6_locator_internal(struct srv6_locator *locator)
+{
+ struct bgp *bgp = bgp_get_default();
+
+ if (!bgp || !bgp->srv6_enabled || !locator)
+ return -1;
+
+ /*
+ * Check if the main BGP instance is configured to use the received
+ * locator
+ */
+ if (strcmp(bgp->srv6_locator_name, locator->name) != 0) {
+ zlog_err("%s: SRv6 Locator name unmatch %s:%s", __func__,
+ bgp->srv6_locator_name, locator->name);
+ return 0;
+ }
+
+ zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u",
+ __func__, locator->name, &locator->prefix,
+ locator->block_bits_length, locator->node_bits_length,
+ locator->function_bits_length, locator->argument_bits_length);
+
+ /* Store the locator in the main BGP instance */
+ bgp->srv6_locator = srv6_locator_alloc(locator->name);
+ srv6_locator_copy(bgp->srv6_locator, locator);
+
+ /*
+ * Process VPN-to-VRF and VRF-to-VPN leaks to advertise new locator
+ * and SIDs.
+ */
+ vpn_leak_postchange_all();
+
+ return 0;
+}
+
+static int bgp_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)
+{
+ struct bgp *bgp = bgp_get_default();
+ struct srv6_locator *locator;
+ struct srv6_sid_ctx ctx;
+ struct in6_addr sid_addr;
+ enum zapi_srv6_sid_notify note;
+ struct bgp *bgp_vrf;
+ struct vrf *vrf;
+ struct listnode *node, *nnode;
+ char buf[256];
+ struct in6_addr *tovpn_sid;
+ struct prefix_ipv6 tmp_prefix;
+ uint32_t sid_func;
+ bool found = false;
+
+ if (!bgp || !bgp->srv6_enabled)
+ return -1;
+
+ if (!bgp->srv6_locator) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: ignoring SRv6 SID notify: locator not set",
+ __func__);
+ return -1;
+ }
+
+ /* Decode the received notification message */
+ if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr,
+ &sid_func, NULL, &note, NULL)) {
+ zlog_err("%s : error in msg decode", __func__);
+ return -1;
+ }
+
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 %s",
+ __func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx),
+ &sid_addr, zapi_srv6_sid_notify2str(note));
+
+ /* Get the BGP instance for which the SID has been requested, if any */
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp_vrf)) {
+ vrf = vrf_lookup_by_id(bgp_vrf->vrf_id);
+ if (!vrf)
+ continue;
+
+ if (vrf->vrf_id == ctx.vrf_id) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: ignoring SRv6 SID notify: No VRF suitable for received SID ctx %s sid_value %pI6",
+ __func__,
+ srv6_sid_ctx2str(buf, sizeof(buf), &ctx),
+ &sid_addr);
+ return -1;
+ }
+
+ /* Handle notification */
+ switch (note) {
+ case ZAPI_SRV6_SID_ALLOCATED:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("SRv6 SID %pI6 %s : ALLOCATED", &sid_addr,
+ srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
+
+ /* Verify that the received SID belongs to the configured locator */
+ tmp_prefix.family = AF_INET6;
+ tmp_prefix.prefixlen = IPV6_MAX_BITLEN;
+ tmp_prefix.prefix = sid_addr;
+
+ if (!prefix_match((struct prefix *)&bgp->srv6_locator->prefix,
+ (struct prefix *)&tmp_prefix))
+ return -1;
+
+ /* Get label */
+ uint8_t func_len = bgp->srv6_locator->function_bits_length;
+ uint8_t shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH -
+ func_len;
+
+ int label = sid_func << shift_len;
+
+ /* Un-export VPN to VRF routes */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp,
+ bgp_vrf);
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, bgp,
+ bgp_vrf);
+
+ locator = srv6_locator_alloc(bgp->srv6_locator_name);
+ srv6_locator_copy(locator, bgp->srv6_locator);
+
+ /* Store SID, locator, and label */
+ tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
+ *tovpn_sid = sid_addr;
+ if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT6) {
+ XFREE(MTYPE_BGP_SRV6_SID,
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
+ srv6_locator_free(
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
+ sid_unregister(bgp,
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
+
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid = tovpn_sid;
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator = locator;
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_transpose_label =
+ label;
+ } else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT4) {
+ XFREE(MTYPE_BGP_SRV6_SID,
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
+ srv6_locator_free(
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
+ sid_unregister(bgp,
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
+
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid = tovpn_sid;
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator = locator;
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_transpose_label =
+ label;
+ } else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT46) {
+ XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
+ srv6_locator_free(bgp_vrf->tovpn_sid_locator);
+ sid_unregister(bgp, bgp_vrf->tovpn_sid);
+
+ bgp_vrf->tovpn_sid = tovpn_sid;
+ bgp_vrf->tovpn_sid_locator = locator;
+ bgp_vrf->tovpn_sid_transpose_label = label;
+ } else {
+ srv6_locator_free(locator);
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("Unsupported behavior. Not assigned SRv6 SID: %s %pI6",
+ srv6_sid_ctx2str(buf, sizeof(buf),
+ &ctx),
+ &sid_addr);
+ return -1;
+ }
+
+ /* Register the new SID */
+ sid_register(bgp, tovpn_sid, bgp->srv6_locator_name);
+
+ /* Export VPN to VRF routes */
+ vpn_leak_postchange_all();
+
+ break;
+ case ZAPI_SRV6_SID_RELEASED:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr,
+ srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
+
+ /* Un-export VPN to VRF routes */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp,
+ bgp_vrf);
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, bgp,
+ bgp_vrf);
+
+ /* Remove SID, locator, and label */
+ if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT6) {
+ XFREE(MTYPE_BGP_SRV6_SID,
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
+ if (bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator) {
+ srv6_locator_free(bgp->vpn_policy[AFI_IP6]
+ .tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator =
+ NULL;
+ }
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_transpose_label =
+ 0;
+
+ /* Unregister the SID */
+ sid_unregister(bgp,
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
+ } else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT4) {
+ XFREE(MTYPE_BGP_SRV6_SID,
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
+ if (bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator) {
+ srv6_locator_free(bgp->vpn_policy[AFI_IP]
+ .tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator =
+ NULL;
+ }
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_transpose_label =
+ 0;
+
+ /* Unregister the SID */
+ sid_unregister(bgp,
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
+ } else if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END_DT46) {
+ XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
+ if (bgp_vrf->tovpn_sid_locator) {
+ srv6_locator_free(bgp_vrf->tovpn_sid_locator);
+ bgp_vrf->tovpn_sid_locator = NULL;
+ }
+ bgp_vrf->tovpn_sid_transpose_label = 0;
+
+ /* Unregister the SID */
+ sid_unregister(bgp, bgp_vrf->tovpn_sid);
+ } else {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("Unsupported behavior. Not assigned SRv6 SID: %s %pI6",
+ srv6_sid_ctx2str(buf, sizeof(buf),
+ &ctx),
+ &sid_addr);
+ return -1;
+ }
+
+ /* Export VPN to VRF routes*/
+ vpn_leak_postchange_all();
+ break;
+ case ZAPI_SRV6_SID_FAIL_ALLOC:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("SRv6 SID %pI6 %s: Failed to allocate",
+ &sid_addr,
+ srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
+
+ /* Error will be logged by zebra module */
+ break;
+ case ZAPI_SRV6_SID_FAIL_RELEASE:
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: SRv6 SID %pI6 %s failure to release",
+ __func__, &sid_addr,
+ srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
+
+ /* Error will be logged by zebra module */
+ break;
+ }
+
+ return 0;
+}
+
static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
{
struct srv6_locator loc = {};
struct bgp *bgp = bgp_get_default();
- const char *loc_name = bgp->srv6_locator_name;
if (!bgp || !bgp->srv6_enabled)
return 0;
@@ -3417,10 +3658,7 @@ static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
return -1;
- if (bgp_zebra_srv6_manager_get_locator_chunk(loc_name) < 0)
- return -1;
-
- return 0;
+ return bgp_zebra_process_srv6_locator_internal(&loc);
}
static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
@@ -3428,7 +3666,8 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
struct srv6_locator loc = {};
struct bgp *bgp = bgp_get_default();
struct listnode *node, *nnode;
- struct srv6_locator_chunk *chunk, *tovpn_sid_locator;
+ struct srv6_locator_chunk *chunk;
+ struct srv6_locator *tovpn_sid_locator;
struct bgp_srv6_function *func;
struct bgp *bgp_vrf;
struct in6_addr *tovpn_sid;
@@ -3440,6 +3679,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
return -1;
+ // clear SRv6 locator
+ if (bgp->srv6_locator) {
+ srv6_locator_free(bgp->srv6_locator);
+ bgp->srv6_locator = NULL;
+ }
+
// refresh chunks
for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk))
if (prefix_match((struct prefix *)&loc.prefix,
@@ -3516,10 +3761,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
- (struct prefix *)&tmp_prefi))
- srv6_locator_chunk_free(
- &bgp_vrf->vpn_policy[AFI_IP]
- .tovpn_sid_locator);
+ (struct prefix *)&tmp_prefi)) {
+ srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP]
+ .tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator =
+ NULL;
+ }
}
/* refresh vpnv6 tovpn_sid_locator */
@@ -3530,10 +3777,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
- (struct prefix *)&tmp_prefi))
- srv6_locator_chunk_free(
- &bgp_vrf->vpn_policy[AFI_IP6]
- .tovpn_sid_locator);
+ (struct prefix *)&tmp_prefi)) {
+ srv6_locator_free(bgp_vrf->vpn_policy[AFI_IP6]
+ .tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator =
+ NULL;
+ }
}
/* refresh per-vrf tovpn_sid_locator */
@@ -3543,9 +3792,10 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
- (struct prefix *)&tmp_prefi))
- srv6_locator_chunk_free(
- &bgp_vrf->tovpn_sid_locator);
+ (struct prefix *)&tmp_prefi)) {
+ srv6_locator_free(bgp_vrf->tovpn_sid_locator);
+ bgp_vrf->tovpn_sid_locator = NULL;
+ }
}
}
@@ -3582,6 +3832,7 @@ static zclient_handler *const bgp_handlers[] = {
[ZEBRA_SRV6_LOCATOR_DELETE] = bgp_zebra_process_srv6_locator_delete,
[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
bgp_zebra_process_srv6_locator_chunk,
+ [ZEBRA_SRV6_SID_NOTIFY] = bgp_zebra_srv6_sid_notify,
};
static int bgp_if_new_hook(struct interface *ifp)
@@ -3609,14 +3860,17 @@ void bgp_if_init(void)
hook_register_prio(if_del, 0, bgp_if_delete_hook);
}
-static void bgp_start_label_manager(struct event *start)
+static bool bgp_zebra_label_manager_ready(void)
{
- bgp_zebra_label_manager_connect();
+ return (zclient_sync->sock > 0);
}
-static bool bgp_zebra_label_manager_ready(void)
+static void bgp_start_label_manager(struct event *start)
{
- return (zclient_sync->sock > 0);
+ if (!bgp_zebra_label_manager_ready() &&
+ !bgp_zebra_label_manager_connect())
+ event_add_timer(bm->master, bgp_start_label_manager, NULL, 1,
+ &bm->t_bgp_start_label_manager);
}
static bool bgp_zebra_label_manager_connect(void)
@@ -4116,6 +4370,89 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name)
return srv6_manager_release_locator_chunk(zclient, name);
}
+/**
+ * Ask the SRv6 Manager (zebra) about a specific locator
+ *
+ * @param name Locator name
+ * @return 0 on success, -1 otherwise
+ */
+int bgp_zebra_srv6_manager_get_locator(const char *name)
+{
+ if (!name)
+ return -1;
+
+ /*
+ * Send the Get Locator request to the SRv6 Manager and return the
+ * result
+ */
+ return srv6_manager_get_locator(zclient, name);
+}
+
+/**
+ * Ask the SRv6 Manager (zebra) to allocate a SID.
+ *
+ * Optionally, it is possible to provide an IPv6 address (sid_value parameter).
+ *
+ * When sid_value is provided, the SRv6 Manager allocates the requested SID
+ * address, if the request can be satisfied (explicit allocation).
+ *
+ * When sid_value is not provided, the SRv6 Manager allocates any available SID
+ * from the provided locator (dynamic allocation).
+ *
+ * @param ctx Context to be associated with the request SID
+ * @param sid_value IPv6 address to be associated with the requested SID (optional)
+ * @param locator_name Name of the locator from which the SID must be allocated
+ * @param sid_func SID Function allocated by the SRv6 Manager.
+ */
+bool bgp_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value,
+ const char *locator_name, uint32_t *sid_func)
+{
+ int ret;
+
+ if (!ctx || !locator_name)
+ return false;
+
+ /*
+ * Send the Get SRv6 SID request to the SRv6 Manager and check the
+ * result
+ */
+ ret = srv6_manager_get_sid(zclient, ctx, sid_value, locator_name,
+ sid_func);
+ if (ret < 0) {
+ zlog_warn("%s: error getting SRv6 SID!", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Ask the SRv6 Manager (zebra) to release a previously allocated SID.
+ *
+ * This function is used to tell the SRv6 Manager that BGP no longer intends
+ * to use the SID.
+ *
+ * @param ctx Context to be associated with the SID to be released
+ */
+void bgp_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx)
+{
+ int ret;
+
+ if (!ctx)
+ return;
+
+ /*
+ * Send the Release SRv6 SID request to the SRv6 Manager and check the
+ * result
+ */
+ ret = srv6_manager_release_sid(zclient, ctx);
+ if (ret < 0) {
+ zlog_warn("%s: error releasing SRv6 SID!", __func__);
+ return;
+ }
+}
+
void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
ifindex_t ifindex, vrf_id_t vrf_id,
enum lsp_types_t ltype, struct prefix *p,
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 55a4185bde..8deecba747 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -117,6 +117,13 @@ extern int bgp_zebra_update(struct bgp *bgp, afi_t afi, safi_t safi,
extern int bgp_zebra_stale_timer_update(struct bgp *bgp);
extern int bgp_zebra_srv6_manager_get_locator_chunk(const char *name);
extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name);
+extern int bgp_zebra_srv6_manager_get_locator(const char *name);
+extern bool bgp_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value,
+ const char *locator_name,
+ uint32_t *sid_func);
+extern void bgp_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx);
+
extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
ifindex_t index, vrf_id_t vrfid,
enum lsp_types_t ltype,
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index a88de651f5..80b1ae39d4 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1255,7 +1255,6 @@ static void peer_free(struct peer *peer)
EVENT_OFF(peer->t_revalidate_all[afi][safi]);
assert(!peer->connection->t_write);
assert(!peer->connection->t_read);
- event_cancel_event_ready(bm->master, peer->connection);
/* Free connected nexthop, if present */
if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)
@@ -1497,9 +1496,11 @@ static void bgp_srv6_init(struct bgp *bgp)
static void bgp_srv6_cleanup(struct bgp *bgp)
{
for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (bgp->vpn_policy[afi].tovpn_sid_locator != NULL)
- srv6_locator_chunk_free(
- &bgp->vpn_policy[afi].tovpn_sid_locator);
+ if (bgp->vpn_policy[afi].tovpn_sid_locator != NULL) {
+ srv6_locator_free(
+ bgp->vpn_policy[afi].tovpn_sid_locator);
+ bgp->vpn_policy[afi].tovpn_sid_locator = NULL;
+ }
if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent != NULL)
XFREE(MTYPE_BGP_SRV6_SID,
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
@@ -1510,8 +1511,10 @@ static void bgp_srv6_cleanup(struct bgp *bgp)
}
}
- if (bgp->tovpn_sid_locator != NULL)
- srv6_locator_chunk_free(&bgp->tovpn_sid_locator);
+ if (bgp->tovpn_sid_locator != NULL) {
+ srv6_locator_free(bgp->tovpn_sid_locator);
+ bgp->tovpn_sid_locator = NULL;
+ }
if (bgp->tovpn_zebra_vrf_sid_last_sent != NULL)
XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
if (bgp->tovpn_sid != NULL) {
@@ -1523,6 +1526,9 @@ static void bgp_srv6_cleanup(struct bgp *bgp)
list_delete(&bgp->srv6_locator_chunks);
if (bgp->srv6_functions)
list_delete(&bgp->srv6_functions);
+
+ srv6_locator_free(bgp->srv6_locator);
+ bgp->srv6_locator = NULL;
}
/* Allocate new peer object, implicitely locked. */
@@ -3414,12 +3420,18 @@ static void bgp_vrf_string_name_delete(void *data)
static struct bgp *bgp_create(as_t *as, const char *name,
enum bgp_instance_type inst_type,
const char *as_pretty,
- enum asnotation_mode asnotation)
+ enum asnotation_mode asnotation,
+ struct bgp *bgp_old, bool hidden)
{
struct bgp *bgp;
afi_t afi;
safi_t safi;
+ if (hidden) {
+ bgp = bgp_old;
+ goto peer_init;
+ }
+
bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp));
bgp->as = *as;
if (as_pretty)
@@ -3473,18 +3485,24 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->peer_self->domainname =
XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_domainname_get());
bgp->peer = list_new();
+
+peer_init:
bgp->peer->cmp = (int (*)(void *, void *))peer_cmp;
bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same,
"BGP Peer Hash");
bgp->peerhash->max_size = BGP_PEER_MAX_HASH_SIZE;
- bgp->group = list_new();
+ if (!hidden)
+ bgp->group = list_new();
bgp->group->cmp = (int (*)(void *, void *))peer_group_cmp;
FOREACH_AFI_SAFI (afi, safi) {
- bgp->route[afi][safi] = bgp_table_init(bgp, afi, safi);
- bgp->aggregate[afi][safi] = bgp_table_init(bgp, afi, safi);
- bgp->rib[afi][safi] = bgp_table_init(bgp, afi, safi);
+ if (!hidden) {
+ bgp->route[afi][safi] = bgp_table_init(bgp, afi, safi);
+ bgp->aggregate[afi][safi] = bgp_table_init(bgp, afi,
+ safi);
+ bgp->rib[afi][safi] = bgp_table_init(bgp, afi, safi);
+ }
/* Enable maximum-paths */
bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_EBGP,
@@ -3505,7 +3523,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->default_subgroup_pkt_queue_max =
BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
bgp_tcp_keepalive_unset(bgp);
- bgp_timers_unset(bgp);
+ if (!hidden)
+ bgp_timers_unset(bgp);
bgp->default_min_holdtime = 0;
bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
@@ -3520,10 +3539,10 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp_addpath_init_bgp_data(&bgp->tx_addpath);
bgp->fast_convergence = false;
bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME;
- bgp->rmap_def_originate_eval_timer = RMAP_DEFAULT_ORIGINATE_EVAL_TIMER;
+ bgp->rmap_def_originate_eval_timer = 0;
#ifdef ENABLE_BGP_VNC
- if (inst_type != BGP_INSTANCE_TYPE_VRF) {
+ if (inst_type != BGP_INSTANCE_TYPE_VRF && !hidden) {
bgp->rfapi = bgp_rfapi_new(bgp);
assert(bgp->rfapi);
assert(bgp->rfapi_cfg);
@@ -3540,9 +3559,11 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->vpn_policy[afi].import_vrf = list_new();
bgp->vpn_policy[afi].import_vrf->del =
bgp_vrf_string_name_delete;
- bgp->vpn_policy[afi].export_vrf = list_new();
- bgp->vpn_policy[afi].export_vrf->del =
- bgp_vrf_string_name_delete;
+ if (!hidden) {
+ bgp->vpn_policy[afi].export_vrf = list_new();
+ bgp->vpn_policy[afi].export_vrf->del =
+ bgp_vrf_string_name_delete;
+ }
SET_FLAG(bgp->af_flags[afi][SAFI_MPLS_VPN],
BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL);
}
@@ -3560,7 +3581,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->restart_time, &bgp->t_startup);
/* printable name we can use in debug messages */
- if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
+ if (inst_type == BGP_INSTANCE_TYPE_DEFAULT && !hidden) {
bgp->name_pretty = XSTRDUP(MTYPE_BGP_NAME, "VRF default");
} else {
const char *n;
@@ -3588,17 +3609,20 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
bgp->default_af[AFI_IP][SAFI_UNICAST] = true;
- QOBJ_REG(bgp, bgp);
+ if (!hidden)
+ QOBJ_REG(bgp, bgp);
update_bgp_group_init(bgp);
- /* assign a unique rd id for auto derivation of vrf's RD */
- bf_assign_index(bm->rd_idspace, bgp->vrf_rd_id);
+ if (!hidden) {
+ /* assign a unique rd id for auto derivation of vrf's RD */
+ bf_assign_index(bm->rd_idspace, bgp->vrf_rd_id);
- bgp_evpn_init(bgp);
- bgp_evpn_vrf_es_init(bgp);
- bgp_pbr_init(bgp);
- bgp_srv6_init(bgp);
+ bgp_evpn_init(bgp);
+ bgp_evpn_vrf_es_init(bgp);
+ bgp_pbr_init(bgp);
+ bgp_srv6_init(bgp);
+ }
/*initilize global GR FSM */
bgp_global_gr_init(bgp);
@@ -3736,10 +3760,15 @@ int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
return bgp_check_main_socket(create, bgp);
}
-int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name,
+int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
+ const char *as_pretty,
+ enum asnotation_mode asnotation, const char *name,
enum bgp_instance_type inst_type)
{
struct bgp *bgp;
+ struct peer *peer = NULL;
+ struct listnode *node, *nnode;
+ bool hidden = false;
/* Multiple instance check. */
if (name)
@@ -3748,14 +3777,41 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name,
bgp = bgp_get_default();
if (bgp) {
- *bgp_val = bgp;
+ if (IS_BGP_INSTANCE_HIDDEN(bgp) && *as != AS_UNSPECIFIED)
+ hidden = true;
+ /* Handle AS number change */
if (bgp->as != *as) {
+ if (hidden || CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) {
+ if (hidden) {
+ bgp_create(as, name, inst_type,
+ as_pretty, asnotation, bgp,
+ hidden);
+ UNSET_FLAG(bgp->flags,
+ BGP_FLAG_INSTANCE_HIDDEN);
+ } else {
+ bgp->as = *as;
+ UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO);
+ }
+
+ /* Set all peer's local AS with this ASN */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode,
+ peer))
+ peer->local_as = *as;
+ *bgp_val = bgp;
+ return BGP_INSTANCE_EXISTS;
+ }
+
*as = bgp->as;
- return BGP_ERR_AS_MISMATCH;
+ *bgp_val = bgp;
+ return BGP_ERR_INSTANCE_MISMATCH;
}
if (bgp->inst_type != inst_type)
return BGP_ERR_INSTANCE_MISMATCH;
- return BGP_SUCCESS;
+ if (hidden)
+ bgp_create(as, name, inst_type, as_pretty, asnotation,
+ bgp, hidden);
+ *bgp_val = bgp;
+ return BGP_INSTANCE_EXISTS;
}
*bgp_val = NULL;
@@ -3771,11 +3827,13 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
struct vrf *vrf = NULL;
int ret = 0;
- ret = bgp_lookup_by_as_name_type(bgp_val, as, name, inst_type);
+ ret = bgp_lookup_by_as_name_type(bgp_val, as, as_pretty, asnotation,
+ name, inst_type);
if (ret || *bgp_val)
return ret;
- bgp = bgp_create(as, name, inst_type, as_pretty, asnotation);
+ bgp = bgp_create(as, name, inst_type, as_pretty, asnotation, NULL,
+ false);
/*
* view instances will never work inside of a vrf
@@ -4015,6 +4073,15 @@ int bgp_delete(struct bgp *bgp)
bgp_damp_disable(bgp, afi, safi);
}
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT &&
+ (bgp_table_top(bgp->rib[AFI_IP][SAFI_MPLS_VPN]) ||
+ bgp_table_top(bgp->rib[AFI_IP6][SAFI_MPLS_VPN]))) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug(
+ "Marking the deleting default bgp instance as hidden");
+ SET_FLAG(bgp->flags, BGP_FLAG_INSTANCE_HIDDEN);
+ }
+
if (BGP_DEBUG(zebra, ZEBRA)) {
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
zlog_debug("Deleting Default VRF");
@@ -4027,7 +4094,8 @@ int bgp_delete(struct bgp *bgp)
}
/* unmap from RT list */
- bgp_evpn_vrf_delete(bgp);
+ if (!IS_BGP_INSTANCE_HIDDEN(bgp))
+ bgp_evpn_vrf_delete(bgp);
/* unmap bgp vrf label */
vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP);
@@ -4059,7 +4127,7 @@ int bgp_delete(struct bgp *bgp)
peer_delete(peer);
}
- if (bgp->peer_self) {
+ if (bgp->peer_self && !IS_BGP_INSTANCE_HIDDEN(bgp)) {
peer_delete(bgp->peer_self);
bgp->peer_self = NULL;
}
@@ -4069,7 +4137,8 @@ int bgp_delete(struct bgp *bgp)
/* TODO - Other memory may need to be freed - e.g., NHT */
#ifdef ENABLE_BGP_VNC
- rfapi_delete(bgp);
+ if (!IS_BGP_INSTANCE_HIDDEN(bgp))
+ rfapi_delete(bgp);
#endif
/* Free memory allocated with aggregate address configuration. */
@@ -4111,7 +4180,7 @@ int bgp_delete(struct bgp *bgp)
}
/* Deregister from Zebra, if needed */
- if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
+ if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp) && !IS_BGP_INSTANCE_HIDDEN(bgp)) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug(
"%s: deregistering this bgp %s instance from zebra",
@@ -4119,17 +4188,19 @@ int bgp_delete(struct bgp *bgp)
bgp_zebra_instance_deregister(bgp);
}
- /* Remove visibility via the master list - there may however still be
- * routes to be processed still referencing the struct bgp.
- */
- listnode_delete(bm->bgp, bgp);
-
- /* Free interfaces in this instance. */
- bgp_if_finish(bgp);
+ if (!IS_BGP_INSTANCE_HIDDEN(bgp)) {
+ /* Remove visibility via the master list -
+ * there may however still be routes to be processed
+ * still referencing the struct bgp.
+ */
+ listnode_delete(bm->bgp, bgp);
+ /* Free interfaces in this instance. */
+ bgp_if_finish(bgp);
+ }
vrf = bgp_vrf_lookup_by_instance_type(bgp);
bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, false);
- if (vrf)
+ if (vrf && !IS_BGP_INSTANCE_HIDDEN(bgp))
bgp_vrf_unlink(bgp, vrf);
/* Update EVPN VRF pointer */
@@ -4144,7 +4215,22 @@ int bgp_delete(struct bgp *bgp)
work_queue_free_and_null(&bgp->process_queue);
event_master_free_unused(bm->master);
- bgp_unlock(bgp); /* initial reference */
+
+ if (!IS_BGP_INSTANCE_HIDDEN(bgp))
+ bgp_unlock(bgp); /* initial reference */
+ else {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ enum vpn_policy_direction dir;
+
+ if (bgp->vpn_policy[afi].import_vrf)
+ list_delete(&bgp->vpn_policy[afi].import_vrf);
+
+ dir = BGP_VPN_POLICY_DIR_FROMVPN;
+ if (bgp->vpn_policy[afi].rtlist[dir])
+ ecommunity_free(
+ &bgp->vpn_policy[afi].rtlist[dir]);
+ }
+ }
return 0;
}
@@ -4689,6 +4775,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_LOCAL_AS, 0, peer_change_reset},
{PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_reset},
{PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_reset},
+ {PEER_FLAG_DUAL_AS, 0, peer_change_reset},
{PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none},
{PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE, 0, peer_change_none},
{PEER_FLAG_EXTENDED_OPT_PARAMS, 0, peer_change_reset},
@@ -4701,6 +4788,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_CAPABILITY_FQDN, 0, peer_change_none},
{PEER_FLAG_AS_LOOP_DETECTION, 0, peer_change_none},
{PEER_FLAG_EXTENDED_LINK_BANDWIDTH, 0, peer_change_none},
+ {PEER_FLAG_LONESOUL, 0, peer_change_reset_out},
{0, 0, 0}};
static const struct peer_flag_action peer_af_flag_action_list[] = {
@@ -5783,6 +5871,10 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
subgrp = peer_subgroup(peer, afi, safi);
if (rmap) {
+ if (!peer->bgp->rmap_def_originate_eval_timer)
+ peer->bgp->rmap_def_originate_eval_timer =
+ RMAP_DEFAULT_ORIGINATE_EVAL_TIMER;
+
if (!peer->default_rmap[afi][safi].name
|| strcmp(rmap, peer->default_rmap[afi][safi].name) != 0) {
struct route_map *map = NULL;
@@ -5865,6 +5957,10 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
if (rmap) {
struct route_map *map = NULL;
+ if (!member->bgp->rmap_def_originate_eval_timer)
+ member->bgp->rmap_def_originate_eval_timer =
+ RMAP_DEFAULT_ORIGINATE_EVAL_TIMER;
+
if (member->default_rmap[afi][safi].name) {
map = route_map_lookup_by_name(
member->default_rmap[afi][safi].name);
@@ -6630,9 +6726,9 @@ int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi)
}
int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
- bool replace_as, const char *as_str)
+ bool replace_as, bool dual_as, const char *as_str)
{
- bool old_no_prepend, old_replace_as;
+ bool old_no_prepend, old_replace_as, old_dual_as;
struct bgp *bgp = peer->bgp;
struct peer *member;
struct listnode *node, *nnode;
@@ -6645,14 +6741,16 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
!!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
old_replace_as =
!!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ old_dual_as = !!CHECK_FLAG(peer->flags, PEER_FLAG_DUAL_AS);
/* Set flag and configuration on peer. */
peer_flag_set(peer, PEER_FLAG_LOCAL_AS);
peer_flag_modify(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND, no_prepend);
peer_flag_modify(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS, replace_as);
+ peer_flag_modify(peer, PEER_FLAG_DUAL_AS, dual_as);
- if (peer->change_local_as == as && old_no_prepend == no_prepend
- && old_replace_as == replace_as)
+ if (peer->change_local_as == as && old_no_prepend == no_prepend &&
+ old_replace_as == replace_as && old_dual_as == dual_as)
return 0;
peer->change_local_as = as;
if (as_str) {
@@ -6681,10 +6779,11 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
PEER_FLAG_LOCAL_AS_NO_PREPEND);
old_replace_as = CHECK_FLAG(member->flags,
PEER_FLAG_LOCAL_AS_REPLACE_AS);
- if (member->change_local_as == as
- && CHECK_FLAG(member->flags, PEER_FLAG_LOCAL_AS)
- && old_no_prepend == no_prepend
- && old_replace_as == replace_as)
+ old_dual_as = !!CHECK_FLAG(member->flags, PEER_FLAG_DUAL_AS);
+ if (member->change_local_as == as &&
+ CHECK_FLAG(member->flags, PEER_FLAG_LOCAL_AS) &&
+ old_no_prepend == no_prepend &&
+ old_replace_as == replace_as && old_dual_as == dual_as)
continue;
/* Set flag and configuration on peer-group member. */
@@ -6693,6 +6792,7 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
no_prepend);
COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS,
replace_as);
+ COND_FLAG(member->flags, PEER_FLAG_DUAL_AS, dual_as);
member->change_local_as = as;
if (as_str)
member->change_local_as_pretty = XSTRDUP(MTYPE_BGP_NAME,
@@ -6715,12 +6815,14 @@ int peer_local_as_unset(struct peer *peer)
peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS);
peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ peer_flag_inherit(peer, PEER_FLAG_DUAL_AS);
PEER_ATTR_INHERIT(peer, peer->group, change_local_as);
} else {
/* Otherwise remove flag and configuration from peer. */
peer_flag_unset(peer, PEER_FLAG_LOCAL_AS);
peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ peer_flag_unset(peer, PEER_FLAG_DUAL_AS);
peer->change_local_as = 0;
XFREE(MTYPE_BGP_NAME, peer->change_local_as_pretty);
}
@@ -6752,6 +6854,7 @@ int peer_local_as_unset(struct peer *peer)
UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS);
UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ UNSET_FLAG(member->flags, PEER_FLAG_DUAL_AS);
member->change_local_as = 0;
XFREE(MTYPE_BGP_NAME, member->change_local_as_pretty);
member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
@@ -8798,6 +8901,12 @@ static ssize_t printfrr_bp(struct fbuf *buf, struct printfrr_eargs *ea,
if (!peer)
return bputs(buf, "(null)");
+ if (!peer->host) {
+ if (peer->conf_if)
+ return bprintfrr(buf, "%s", peer->conf_if);
+ return bprintfrr(buf, "%pSU", &peer->connection->su);
+ }
+
return bprintfrr(buf, "%s(%s)", peer->host,
peer->hostname ? peer->hostname : "Unknown");
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 7f1b82d9c7..3c3655f0a5 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -270,7 +270,7 @@ struct vpn_policy {
*/
uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid;
- struct srv6_locator_chunk *tovpn_sid_locator;
+ struct srv6_locator *tovpn_sid_locator;
uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
};
@@ -550,6 +550,7 @@ struct bgp {
#define BGP_FLAG_ENFORCE_FIRST_AS (1ULL << 36)
#define BGP_FLAG_DYNAMIC_CAPABILITY (1ULL << 37)
#define BGP_FLAG_VNI_DOWN (1ULL << 38)
+#define BGP_FLAG_INSTANCE_HIDDEN (1ULL << 39)
/* BGP default address-families.
* New peers inherit enabled afi/safis from bgp instance.
@@ -836,11 +837,12 @@ struct bgp {
/* BGP VPN SRv6 backend */
bool srv6_enabled;
char srv6_locator_name[SRV6_LOCNAME_SIZE];
+ struct srv6_locator *srv6_locator;
struct list *srv6_locator_chunks;
struct list *srv6_functions;
uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid;
- struct srv6_locator_chunk *tovpn_sid_locator;
+ struct srv6_locator *tovpn_sid_locator;
uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
@@ -1506,6 +1508,7 @@ struct peer {
#define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */
#define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */
#define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39)
+#define PEER_FLAG_DUAL_AS (1ULL << 40)
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
@@ -1827,16 +1830,13 @@ struct peer {
struct stream *last_reset_cause;
/* The kind of route-map Flags.*/
- uint16_t rmap_type;
+ uint8_t rmap_type;
#define PEER_RMAP_TYPE_IN (1U << 0) /* neighbor route-map in */
#define PEER_RMAP_TYPE_OUT (1U << 1) /* neighbor route-map out */
#define PEER_RMAP_TYPE_NETWORK (1U << 2) /* network route-map */
#define PEER_RMAP_TYPE_REDISTRIBUTE (1U << 3) /* redistribute route-map */
#define PEER_RMAP_TYPE_DEFAULT (1U << 4) /* default-originate route-map */
-#define PEER_RMAP_TYPE_NOSET (1U << 5) /* not allow to set commands */
-#define PEER_RMAP_TYPE_IMPORT (1U << 6) /* neighbor route-map import */
-#define PEER_RMAP_TYPE_EXPORT (1U << 7) /* neighbor route-map export */
-#define PEER_RMAP_TYPE_AGGREGATE (1U << 8) /* aggregate-address route-map */
+#define PEER_RMAP_TYPE_AGGREGATE (1U << 5) /* aggregate-address route-map */
/** Peer overwrite configuration. */
struct bfd_session_config {
@@ -2154,6 +2154,7 @@ enum bgp_clear_type {
enum bgp_create_error_code {
BGP_SUCCESS = 0,
BGP_CREATED = 1,
+ BGP_INSTANCE_EXISTS = 2,
BGP_ERR_INVALID_VALUE = -1,
BGP_ERR_INVALID_FLAG = -2,
BGP_ERR_INVALID_AS = -3,
@@ -2445,7 +2446,7 @@ extern int peer_allowas_in_set(struct peer *, afi_t, safi_t, int, int);
extern int peer_allowas_in_unset(struct peer *, afi_t, safi_t);
extern int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
- bool replace_as, const char *as_str);
+ bool replace_as, bool dual_as, const char *as_str);
extern int peer_local_as_unset(struct peer *);
extern int peer_prefix_list_set(struct peer *, afi_t, safi_t, int,
@@ -2824,6 +2825,8 @@ extern struct peer *peer_new(struct bgp *bgp);
extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
const char *ip_str, bool use_json);
extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
+ const char *as_pretty,
+ enum asnotation_mode asnotation,
const char *name,
enum bgp_instance_type inst_type);
@@ -2865,4 +2868,17 @@ extern void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode);
/* clang-format on */
#endif
+/* Macro to check if default bgp instance is hidden */
+#define IS_BGP_INSTANCE_HIDDEN(_bgp) \
+ (CHECK_FLAG(_bgp->flags, BGP_FLAG_INSTANCE_HIDDEN) && \
+ (_bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT || \
+ _bgp->inst_type == BGP_INSTANCE_TYPE_VRF))
+
+/* Macro to check if bgp instance delete in-progress and !hidden */
+#define BGP_INSTANCE_HIDDEN_DELETE_IN_PROGRESS(_bgp, _afi, _safi) \
+ (CHECK_FLAG(_bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) && \
+ !IS_BGP_INSTANCE_HIDDEN(_bgp) && \
+ !(_afi == AFI_IP && _safi == SAFI_MPLS_VPN) && \
+ !(_afi == AFI_IP6 && _safi == SAFI_MPLS_VPN))
+
#endif /* _QUAGGA_BGPD_H */
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 2afcb2f45c..44dfc88cf7 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -1272,7 +1272,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
/* label comes from MP_REACH_NLRI label */
vo->v.l2addr.label =
- bgp_path_info_num_labels(bpi)
+ BGP_PATH_INFO_NUM_LABELS(bpi)
? decode_label(&bpi->extra->labels->label[0])
: MPLS_INVALID_LABEL;
@@ -4167,7 +4167,7 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp,
BGP_PATH_REMOVED))
continue;
- if (bgp_path_info_num_labels(bpi))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi))
label = decode_label(
&bpi->extra->labels
->label[0]);
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index a0bdf4961f..53e416b2ee 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -692,7 +692,7 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri,
/* label comes from MP_REACH_NLRI label */
vo->v.l2addr.label =
- bgp_path_info_num_labels(bpi)
+ BGP_PATH_INFO_NUM_LABELS(bpi)
? decode_label(&bpi->extra->labels->label[0])
: MPLS_INVALID_LABEL;
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 9bfb6c4b45..8f1f509bbb 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -413,7 +413,7 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
- if (bgp_path_info_num_labels(bpi)) {
+ if (BGP_PATH_INFO_NUM_LABELS(bpi)) {
if (bpi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK)
vty_out(vty, " label=VRF2VRF");
else
@@ -1052,7 +1052,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
snprintf(buf_un, sizeof(buf_un), "%s",
inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop,
sizeof(buf_ntop)));
- if (bgp_path_info_num_labels(bpi)) {
+ if (BGP_PATH_INFO_NUM_LABELS(bpi)) {
uint32_t l = decode_label(&bpi->extra->labels->label[0]);
snprintf(buf_vn, sizeof(buf_vn), "Label: %d", l);
} else /* should never happen */
@@ -1161,7 +1161,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
}
}
}
- if (tun_type != BGP_ENCAP_TYPE_MPLS && bgp_path_info_num_labels(bpi)) {
+ if (tun_type != BGP_ENCAP_TYPE_MPLS && BGP_PATH_INFO_NUM_LABELS(bpi)) {
uint32_t l = decode_label(&bpi->extra->labels->label[0]);
if (!MPLS_LABEL_IS_NULL(l)) {
diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c
index 7decb75782..4de2306609 100644
--- a/bgpd/rfapi/vnc_export_bgp.c
+++ b/bgpd/rfapi/vnc_export_bgp.c
@@ -388,7 +388,7 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn,
bgp_withdraw(bpi->peer, p, 0, /* addpath_id */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL, 0, NULL); /* tag not used for unicast */
+ NULL, 0); /* tag not used for unicast */
}
static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi)
@@ -473,16 +473,14 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi)
if (ri->type == ZEBRA_ROUTE_VNC_DIRECT
&& ri->sub_type == BGP_ROUTE_REDISTRIBUTE) {
-
- bgp_withdraw(
- ri->peer, bgp_dest_get_prefix(dest),
- 0, /* addpath_id */
- AFI_IP, SAFI_UNICAST,
- ZEBRA_ROUTE_VNC_DIRECT,
- BGP_ROUTE_REDISTRIBUTE,
- NULL, /* RD not used for unicast */
- NULL, 0,
- NULL); /* tag not used for unicast */
+ bgp_withdraw(ri->peer, bgp_dest_get_prefix(dest),
+ 0, /* addpath_id */
+ AFI_IP, SAFI_UNICAST,
+ ZEBRA_ROUTE_VNC_DIRECT,
+ BGP_ROUTE_REDISTRIBUTE,
+ NULL, /* RD not used for unicast */
+ NULL,
+ 0); /* tag not used for unicast */
}
}
}
@@ -863,9 +861,8 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
0, /* addpath_id */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
- NULL, /* RD not used for unicast */
- NULL, 0,
- NULL); /* tag not used for unicast */
+ NULL, /* RD not used for unicast */
+ NULL, 0); /* tag not used for unicast */
/*
* yuck!
* - but consistent with rest of function
@@ -892,9 +889,8 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
0, /* addpath_id */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
- NULL, /* RD not used for unicast */
- NULL, 0,
- NULL); /* tag not used for unicast */
+ NULL, /* RD not used for unicast */
+ NULL, 0); /* tag not used for unicast */
}
}
}
@@ -1125,13 +1121,13 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
continue;
bgp_withdraw(irfd->peer, p, /* prefix */
- 0, /* addpath_id */
+ 0, /* addpath_id */
afi, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for
unicast */
- NULL, 0, NULL); /* tag not
+ NULL, 0); /* tag not
used for
unicast */
}
@@ -1359,7 +1355,7 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
0, /* addpath_id */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL, 0, NULL); /* tag not used for unicast */
+ NULL, 0); /* tag not used for unicast */
return;
}
@@ -1471,16 +1467,15 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt,
for (ALL_LIST_ELEMENTS_RO(nve_list, hln,
irfd)) {
-
bgp_withdraw(irfd->peer,
agg_node_get_prefix(rn),
- 0, /* addpath_id */
+ 0, /* addpath_id */
afi, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for
unicast */
- NULL, 0, NULL); /* tag not
+ NULL, 0); /* tag not
used for
unicast,
EVPN
@@ -1715,8 +1710,7 @@ static void vncExportWithdrawTimer(struct event *t)
bgp_withdraw(eti->peer, p, 0, /* addpath_id */
family2afi(p->family), SAFI_UNICAST, eti->type,
eti->subtype, NULL, /* RD not used for unicast */
- NULL, 0,
- NULL); /* tag not used for unicast, EVPN neither */
+ NULL, 0); /* tag not used for unicast, EVPN neither */
/*
* Free the eti
@@ -2001,7 +1995,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
ZEBRA_ROUTE_VNC_DIRECT_RH,
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */
- NULL, 0, NULL); /* tag not used for
+ NULL, 0); /* tag not used for
unicast, EVPN
neither */
}
diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c
index 2bb7c1b161..e688638ed7 100644
--- a/bgpd/rfapi/vnc_import_bgp.c
+++ b/bgpd/rfapi/vnc_import_bgp.c
@@ -470,7 +470,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi(
if (bgp_attr_get_ecommunity(bpi->attr))
ecommunity_merge(new_ecom, bgp_attr_get_ecommunity(bpi->attr));
- if (bgp_path_info_num_labels(bpi))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi))
label = decode_label(&bpi->extra->labels->label[0]);
else
label = MPLS_INVALID_LABEL;
@@ -1704,7 +1704,7 @@ static void vnc_import_bgp_exterior_add_route_it(
else
prd = NULL;
- if (bgp_path_info_num_labels(bpi_interior))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi_interior))
label = decode_label(
&bpi_interior->extra->labels
->label[0]);
@@ -1878,7 +1878,7 @@ void vnc_import_bgp_exterior_del_route(
else
prd = NULL;
- if (bgp_path_info_num_labels(bpi_interior))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi_interior))
label = decode_label(
&bpi_interior->extra->labels
->label[0]);
@@ -2030,7 +2030,7 @@ void vnc_import_bgp_exterior_add_route_interior(
else
prd = NULL;
- if (bgp_path_info_num_labels(bpi_interior))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi_interior))
label = decode_label(
&bpi_interior->extra->labels->label[0]);
else
@@ -2147,7 +2147,7 @@ void vnc_import_bgp_exterior_add_route_interior(
else
prd = NULL;
- if (bgp_path_info_num_labels(bpi))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi))
label = decode_label(
&bpi->extra->labels
->label[0]);
@@ -2174,7 +2174,7 @@ void vnc_import_bgp_exterior_add_route_interior(
else
prd = NULL;
- if (bgp_path_info_num_labels(bpi_interior))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi_interior))
label = decode_label(
&bpi_interior->extra->labels
->label[0]);
@@ -2297,7 +2297,7 @@ void vnc_import_bgp_exterior_add_route_interior(
else
prd = NULL;
- if (bgp_path_info_num_labels(bpi_interior))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi_interior))
label = decode_label(
&bpi_interior->extra->labels->label[0]);
else
@@ -2409,7 +2409,7 @@ void vnc_import_bgp_exterior_del_route_interior(
else
prd = NULL;
- if (bgp_path_info_num_labels(bpi_interior))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi_interior))
label = decode_label(
&bpi_interior->extra->labels->label[0]);
else
@@ -2491,7 +2491,7 @@ void vnc_import_bgp_exterior_del_route_interior(
else
prd = NULL;
- if (bgp_path_info_num_labels(bpi))
+ if (BGP_PATH_INFO_NUM_LABELS(bpi))
label = decode_label(
&bpi->extra->labels->label[0]);
else
diff --git a/configure.ac b/configure.ac
index 59636194f7..e1aa05b869 100644
--- a/configure.ac
+++ b/configure.ac
@@ -847,9 +847,12 @@ AC_ARG_WITH([crypto],
AC_ARG_WITH([frr-format],
AS_HELP_STRING([--with-frr-format[=<.../frr-format.so>]], [use frr-format GCC plugin]))
-AC_ARG_ENABLE([version-build-config],
+AC_ARG_ENABLE([version_build_config],
AS_HELP_STRING([--disable-version-build-config], [do not include build configs in show version command]))
+AC_ARG_ENABLE([python_runtime],
+ AS_HELP_STRING([--disable-python-runtime], [do not install python scripts or have python runtime dependency]))
+
#if openssl, else use the internal
AS_IF([test "$with_crypto" = "openssl"], [
AC_CHECK_LIB([crypto], [EVP_DigestInit], [LIBS="$LIBS -lcrypto"], [], [])
@@ -2811,6 +2814,9 @@ AM_CONDITIONAL([PATHD], [test "$enable_pathd" != "no"])
AM_CONDITIONAL([PATHD_PCEP], [test "$enable_pathd" != "no"])
AM_CONDITIONAL([DP_DPDK], [test "$enable_dp_dpdk" = "yes"])
+
+AM_CONDITIONAL([PYTHON_RUNTIME_DEPENDENCY], [test "$enable_python_runtime" != "no"])
+
AC_CONFIG_FILES([Makefile],[
test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build"
${PYTHON} "${ac_abs_top_srcdir}/python/makefile.py" ${makefile_devbuild} || exit 1
diff --git a/doc/developer/bgpd.rst b/doc/developer/bgpd.rst
index a35fa614f4..f5263ff31d 100644
--- a/doc/developer/bgpd.rst
+++ b/doc/developer/bgpd.rst
@@ -9,3 +9,4 @@ BGPD
next-hop-tracking
bgp-typecodes
+ bmp
diff --git a/doc/developer/conf.py b/doc/developer/conf.py
index 76dd1e4f28..634f4aa804 100644
--- a/doc/developer/conf.py
+++ b/doc/developer/conf.py
@@ -67,6 +67,13 @@ version = "?.?"
# The full version, including alpha/beta/rc tags.
release = "?.?-?"
+# Set canonical URL from the Read the Docs Domain
+html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
+
+# Tell Jinja2 templates the build is running on Read the Docs
+if os.environ.get("READTHEDOCS", "") == "True":
+ html_context["READTHEDOCS"] = True
+
# -----------------------------------------------------------------------------
# Extract values from codebase for substitution into docs.
diff --git a/doc/developer/mgmtd-dev.rst b/doc/developer/mgmtd-dev.rst
index b979af06fa..4c56cadb28 100644
--- a/doc/developer/mgmtd-dev.rst
+++ b/doc/developer/mgmtd-dev.rst
@@ -147,7 +147,7 @@ Front-End Interface:
- change route_map_init() to route_map_init_new(false) and remove from
VTYSH_ROUTE_MAP_CONFIG (leave in VTYSH_ROUTE_MAP_SHOW).
- remove vrf_cmd_init(NULL) => remove from VTYSH_INTERFACE_SUBSET
- ...
+
Back-End Interface:
diff --git a/doc/developer/northbound/yang-tools.rst b/doc/developer/northbound/yang-tools.rst
index fb5a287245..91a767dce7 100644
--- a/doc/developer/northbound/yang-tools.rst
+++ b/doc/developer/northbound/yang-tools.rst
@@ -87,7 +87,7 @@ Generate skeleton instance data:
* XML:
- .. code:: sh
+.. code:: sh
$ pyang -p <yang-search-path> \
-f sample-xml-skeleton --sample-xml-skeleton-defaults \
@@ -95,7 +95,7 @@ Generate skeleton instance data:
* JSON:
- .. code:: sh
+.. code:: sh
$ pyang -p <yang-search-path> \
-f jsonxsl module.yang -o module.xsl
diff --git a/doc/developer/scripting.rst b/doc/developer/scripting.rst
index 7a43314490..f51130b1e3 100644
--- a/doc/developer/scripting.rst
+++ b/doc/developer/scripting.rst
@@ -523,6 +523,7 @@ object which contains methods corresponding to each of the ``zlog`` levels:
log.error("error")
log.notice("notice")
log.debug("debug")
+ log.trace("trace")
The log messages will show up in the daemon's log output.
@@ -579,14 +580,14 @@ accomplished with scripting.
RM_FAILURE, RM_NOMATCH, RM_MATCH, RM_MATCH_AND_CHANGE)
log.info("Evaluating route " .. prefix.network .. " from peer " .. peer.remote_id.string)
-
+
function on_match (prefix, attributes)
log.info("Match")
return {
attributes = RM_MATCH
}
end
-
+
function on_nomatch (prefix, attributes)
log.info("No match")
return {
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index 52c0361a02..6209749636 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -33,10 +33,11 @@ Installing Topotest Requirements
net-tools \
python3-pip \
iputils-ping \
+ iptables \
tshark \
valgrind
python3 -m pip install wheel
- python3 -m pip install 'pytest>=6.2.4' 'pytest-xdist>=2.3.0'
+ python3 -m pip install 'pytest>=8.3.2' 'pytest-asyncio>=0.24.0' 'pytest-xdist>=3.6.1'
python3 -m pip install 'scapy>=2.4.5'
python3 -m pip install xmltodict
python3 -m pip install git+https://github.com/Exa-Networks/exabgp@0659057837cd6c6351579e9f0fa47e9fb7de7311
@@ -730,8 +731,8 @@ packages.
Code coverage can automatically be gathered for any topotest run. To support
this FRR must first be compiled with the ``--enable-gcov`` configure option.
-This will cause *.gnco files to be created during the build. When topotests are
-run the statistics are generated and stored in *.gcda files. Topotest
+This will cause \*.gnco files to be created during the build. When topotests are
+run the statistics are generated and stored in \*.gcda files. Topotest
infrastructure will gather these files, capture the information into a
``coverage.info`` ``lcov`` file and also report the coverage summary.
@@ -740,7 +741,7 @@ If you build your FRR in a directory outside of the FRR source directory you
will also need to pass the ``--cov-frr-build-dir`` argument specifying the build
directory location.
-During the topotest run the *.gcda files are generated into a ``gcda``
+During the topotest run the \*.gcda files are generated into a ``gcda``
sub-directory of the top-level run directory (i.e., normally
``/tmp/topotests/gcda``). These files will then be copied at the end of the
topotest run into the FRR build directory where the ``gcov`` and ``lcov``
@@ -755,7 +756,7 @@ The ``coverage.info`` file can then be used to generate coverage reports or file
markup (e.g., using the ``genhtml`` utility) or enable markup within your
IDE/editor if supported (e.g., the emacs ``cov-mode`` package)
-NOTE: the *.gcda files in ``/tmp/topotests/gcda`` are cumulative so if you do
+NOTE: the \*.gcda files in ``/tmp/topotests/gcda`` are cumulative so if you do
not remove them they will aggregate data across multiple topotest runs.
How to reproduce failed Tests
diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst
index a6bdec1e5b..5e22c4cb72 100644
--- a/doc/developer/workflow.rst
+++ b/doc/developer/workflow.rst
@@ -6,9 +6,10 @@ Process & Workflow
.. highlight:: none
-FRR is a large project developed by many different groups. This section
-documents standards for code style & quality, commit messages, pull requests
-and best practices that all contributors are asked to follow.
+FRR is a large project developed by many different groups. This
+section documents standards for code style & quality, commit messages,
+pull requests (PRs) and best practices that all contributors are asked
+to follow.
This chapter is "descriptive/post-factual" in that it documents pratices that
are in use; it is not "definitive/pre-factual" in prescribing practices. This
@@ -241,7 +242,7 @@ discontinued.
The LTS branch duties are the following ones:
- organise meetings on a (bi-)weekly or monthly basis, the handling of issues
- and pull requested relative to that branch. When time permits, this may be done
+ and pull requests relative to that branch. When time permits, this may be done
during the regularly scheduled FRR meeting.
- ensure the stability of the branch, by using and eventually adapting the
@@ -324,11 +325,17 @@ relevant to your work.
Submitting Patches and Enhancements
===================================
-FRR accepts patches using GitHub pull requests.
+FRR accepts patches using GitHub pull requests (PRs). The typical FRR
+developer will maintain a fork of the FRR project in GitHub; see the
+GitHub documentation for help setting up an account and creating a
+fork repository. Keep the ``master`` branch of your fork up-to-date
+with the FRR version. Create a dev branch in your fork and commit your
+work there. When ready, create a pull-request between your dev branch
+in your fork and the main FRR repository in GitHub.
-The base branch for new contributions and non-critical bug fixes should be
-``master``. Please ensure your pull request is based on this branch when you
-submit it.
+The base branch for new contributions and non-critical bug fixes
+should be ``master``. Please ensure your pull request targets this
+branch when you submit it.
Code submitted by pull request will be automatically tested by one or more CI
systems. Once the automated tests succeed, other developers will review your
@@ -531,6 +538,42 @@ After Submitting Your Changes
community members.
- Your submission is done once it is merged to the master branch.
+Reverting the changes
+=====================
+
+When you revert a regular commit in Git, the process is straightforward - it
+undoes the changes introduced by that commit. However, reverting a merge commit
+is more complex. While it undoes the data changes brought in by the merge, it
+does not alter the repository's history or the merge's effect on it.
+
+Reverting a Merge Commit
+------------------------
+
+When you revert a merge commit, the following occurs:
+
+* The changes made by the merge are undone;
+* The merge itself remains in the history: it continues to be recognized as the point where two branches were joined;
+* Future merges will still treat this as the last shared state, regardless of the revert.
+
+Thus, a "revert" in Git undoes data changes, but it does not serve as a true "undo"
+for the historical effects of a commit.
+
+Reverting a Merge and Bisectability
+-----------------------------------
+
+Consider the implications of reverting a merge and then reverting that revert.
+This scenario complicates the debugging process, especially when using tools like
+git bisect. A reverted merge effectively consolidates all changes from the original
+merge into a single commit, but in reverse. This creates a challenge for debugging,
+as you lose the granularity of individual commits, making it difficult to identify
+the specific change causing an issue.
+
+Considerations
+--------------
+
+When reverting the changes, e.g. a full Pull Request, we SHOULD revert every commit
+individually, and not use git revert on merge commits.
+
Programming Languages, Tools and Libraries
==========================================
diff --git a/doc/manpages/bfd-options.rst b/doc/manpages/bfd-options.rst
index 2bad5f1521..3f10916207 100644
--- a/doc/manpages/bfd-options.rst
+++ b/doc/manpages/bfd-options.rst
@@ -24,7 +24,7 @@ The following options controls the BFD daemon auxiliary sockets.
``--dplaneaddr ipv6:[::1]:50701``
- (if ommited the default port is ``50700``).
+ (if omitted 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
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 5c5584e28f..4c142cfbbb 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -66,7 +66,7 @@ may also be specified (:ref:`common-invocation-options`).
--dplaneaddr ipv6:[::1]:50701
- (if ommited the default port is ``50700``).
+ (if omitted 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
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index a569a9af28..4632c70d53 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -83,7 +83,7 @@ be specified (:ref:`common-invocation-options`).
be done to see if this is helping or not at the scale you are running
at.
-.. option:: --v6-with-v4-nexthops
+.. option:: -x, --v6-with-v4-nexthops
Allow BGP to peer in the V6 afi, when the interface only has v4 addresses.
This allows bgp to install the v6 routes with a v6 nexthop that has the
@@ -1818,7 +1818,7 @@ Configuring Peers
Since sent prefix count is managed by update-groups, this option
creates a separate update-group for outgoing updates.
-.. clicmd:: neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
+.. clicmd:: neighbor PEER local-as AS-NUMBER [no-prepend [replace-as [dual-as]]]
Specify an alternate AS for this BGP process when interacting with the
specified peer. With no modifiers, the specified local-as is prepended to
@@ -1834,6 +1834,10 @@ Configuring Peers
Note that replace-as can only be specified if no-prepend is.
+ The ``dual-as`` keyword is used to configure the neighbor to establish a peering
+ session using the real autonomous-system number (``router bgp ASN``) or by using
+ the autonomous system number configured with the ``local-as``.
+
This command is only allowed for eBGP peers.
.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> as-override
@@ -1972,12 +1976,14 @@ Configuring Peers
and will not be displayed as part of a `show run`. The no form
of the command turns off this ability.
-.. clicmd:: bgp default-originate timer (0-3600)
+.. clicmd:: bgp default-originate timer (0-65535)
Set the period to rerun the default-originate route-map scanner process. The
default is 5 seconds. With a full routing table, it might be useful to increase
this setting to avoid scanning the whole BGP table aggressively.
+ Setting to 0 turns off the scanning at all.
+
.. clicmd:: bgp default ipv4-unicast
This command allows the user to specify that the IPv4 Unicast address
@@ -2191,8 +2197,7 @@ and will share updates.
.. clicmd:: neighbor PEER solo
This command is used to indicate that routes advertised by the peer
- should not be reflected back to the peer. This command only is only
- meaningful when there is a single peer defined in the peer-group.
+ should not be reflected back to the peer.
.. clicmd:: show [ip] bgp peer-group [json]
@@ -2482,7 +2487,7 @@ is 4 octet long. The following format is used to define the community value.
``blackhole``
``blackhole`` represents well-known communities value ``BLACKHOLE``
``0xFFFF029A`` ``65535:666``. :rfc:`7999` documents sending prefixes to
- EBGP peers and upstream for the purpose of blackholing traffic.
+ peers and upstream for the purpose of blackholing traffic.
Prefixes tagged with the this community should normally not be
re-advertised from neighbors of the originating network. Upon receiving
``BLACKHOLE`` community from a BGP speaker, ``NO_ADVERTISE`` community
diff --git a/doc/user/conf.py b/doc/user/conf.py
index 18f048bc08..236a90e902 100644
--- a/doc/user/conf.py
+++ b/doc/user/conf.py
@@ -67,6 +67,16 @@ version = "?.?"
# The full version, including alpha/beta/rc tags.
release = "?.?-?"
+# RTD configuration
+
+# Set canonical URL from the Read the Docs Domain
+html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
+
+# Tell Jinja2 templates the build is running on Read the Docs
+if os.environ.get("READTHEDOCS", "") == "True":
+ html_context["READTHEDOCS"] = True
+
+
# -----------------------------------------------------------------------------
# Extract values from codebase for substitution into docs.
diff --git a/doc/user/pim.rst b/doc/user/pim.rst
index 1740828f26..0fe53247b0 100644
--- a/doc/user/pim.rst
+++ b/doc/user/pim.rst
@@ -71,6 +71,31 @@ PIM Routers
prefix of group ranges covered. This command is vrf aware, to configure for
a vrf, specify the vrf in the router pim block.
+.. clicmd:: no autorp discovery
+
+ In order to use pim, it is necessary to configure a RP for join messages to
+ be sent to. FRR supports learning RP information dynamically via the AutoRP
+ protocol and performs discovery by default. This command will disable the
+ AutoRP discovery protocol.
+ All routers in the pim network must agree on the network RP information, so
+ all routers in the network should have AutoRP either enabled or disabled.
+ This command is vrf aware, to configure for a vrf, specify the vrf in the
+ router pim block.
+
+.. clicmd:: autorp announce A.B.C.D [A.B.C.D/M | group-list PREFIX_LIST]
+
+ Configure the router to advertise itself as a candidate PIM-SM RP via AutoRP.
+ The supported groups can be defined as a single group range, or multiple
+ group ranges can be defined via a prefix list.
+
+.. clicmd:: autorp announce {scope (1-255) | interval (1-65535) | holdtime (0-65535)}
+
+ Configure the AutoRP advertise messages. The scope defines the TTL value in the
+ messages to limit the scope, defaults to 31. Interval defines the number of
+ seconds elapsed between advertise messages sent, defaults to 60. Hold time defines
+ how long the AutoRP mapping agent will consider the information valid, setting to
+ 0 will disable expiration of the candidate RP information, defaults to 3 * interval.
+
.. clicmd:: rp keep-alive-timer (1-65535)
Modify the time out value for a S,G flow from 1-65535 seconds at RP.
@@ -83,6 +108,41 @@ PIM Routers
cannot see data flowing in better than 30 second chunks. This command is
vrf aware, to configure for a vrf, specify the vrf in the router pim block.
+.. clicmd:: bsr candidate-bsr [priority (0-255)] [source [address A.B.C.D] | [interface INTERFACE] | [loopback] | [any]]
+
+ Configure the router to advertise itself as a candidate PIM-SM BSR. The candidate
+ with the highest priority becomes the BSR for the domain (high wins). When priority is the
+ same for more than one candidate BSR, the candidate with the highest IP address
+ becomes the BSR of the domain. The address can be configured explicitly
+ via ``address``, or be selecting an interface name using ``interface``.
+ If ``any`` is configured the highest address from any interface will be selected.
+ By default, the highest loopback address is selected, which can also be
+ configured via ``loopback``
+
+.. clicmd:: bsr candidate-rp [interval]
+
+ Configure the router to advertise itself as a candidate PIM-SM RP at the
+ specified ``interval`` in seconds.
+
+
+.. clicmd:: bsr candidate-rp group A.B.C.D/M
+
+ Configure the multicast group prefix that this candidate RP advertises itself for.
+ This command can be repeated for all desired groups that need to be added to the
+ candidate RP advertisement.
+
+.. clicmd:: bsr candidate-rp [priority (0-255)] [source [address A.B.C.D] | [interface INTERFACE] | [loopback] | [any]]
+
+ Configure the router to advertise itself as a candidate PIM-SM RP. ``interval``
+ can be used to configure the interval in seconds to send these advertisements.
+ The candidate with the lowest priority becomes the RP for the domain (low wins).
+ When priority is the same for more than one candidate RP, the candidate with
+ the highest IP address becomes the BSR of the domain. The address can be
+ configured explicitly via ``address``, or be selecting an interface name
+ using ``interface``. If ``any`` is configured the highest address from any
+ interface will be selected.By default, the highest loopback address is
+ selected, which can also be configured via ``loopback``.
+
.. clicmd:: register-accept-list PLIST
When pim receives a register packet the source of the packet will be compared
@@ -255,9 +315,23 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
Tell pim to receive IGMP reports and Query on this interface. The default
version is v3. This command is useful on a LHR.
-.. clicmd:: ip igmp join A.B.C.D [A.B.C.D]
+.. clicmd:: ip igmp join-group A.B.C.D [A.B.C.D]
- Join multicast group or source-group on an interface.
+ Join multicast group or source-group on an interface. This will result in
+ an IGMP join happening through a local socket so that IGMP reports will be
+ sent on this interface. It may also have the side effect of the kernel
+ forwarding multicast traffic to the socket unnessarily.
+
+.. clicmd:: ip igmp static-group A.B.C.D [A.B.C.D]
+
+ Add a static multicast group or source-group on an interface. This will behave
+ as if there is a receiver on this interface without any IGMP reports.
+
+.. clicmd:: ip igmp proxy
+
+ Tell pim to send proxy IGMP reports for joins occuring on all other
+ interfaces on this interface. Join-groups on other interfaces will
+ also be proxied. The default version is v3.
.. clicmd:: ip igmp query-interval (1-65535)
@@ -432,6 +506,10 @@ cause great confusion.
Display IGMP group retransmission information.
+.. clicmd:: show ip igmp [vrf NAME] proxy [json]
+
+ Display IGMP proxy join information.
+
.. clicmd:: show ip igmp [vrf NAME] sources [json]
Display IGMP sources information.
@@ -563,6 +641,11 @@ cause great confusion.
192.168.10.123 239.0.0.0/8 eth2 yes Static ASM
192.168.10.123 239.4.0.0/24 eth2 yes Static SSM
+.. clicmd:: show ip pim [vrf NAME] autorp [json]
+
+ Display information about AutoRP. Including state of AutoRP Discovery parsing
+ and configured AutoRP candidate RP information.
+
.. clicmd:: show ip pim rpf
Display information about currently being used S,G's and their RPF lookup
@@ -603,11 +686,28 @@ cause great confusion.
Display PIM MLAG (multi-chassis link aggregation) session status and
control message statistics.
-.. clicmd:: show ip pim bsr
+.. clicmd:: show ip pim bsr [vrf NAME] [json]
Display current bsr, its uptime and last received bsm age.
-.. clicmd:: show ip pim bsrp-info [vrf NAME] [json]
+.. clicmd:: show ip pim bsr candidate-bsr [vrf NAME] [json]
+
+ Display information about the candidate BSR state on this router.
+
+.. clicmd:: show ip pim bsr candidate-rp [vrf NAME] [json]
+
+ Display information about the candidate RP state on this router.
+
+.. clicmd:: show ip pim bsr candidate-rp-database [vrf NAME] [json]
+
+ Display the current list of candidate RPs received by this router.
+
+.. clicmd:: show ip pim bsr groups [vrf NAME] [json]
+
+ Display the current list of multicast group mapping received by
+ this router from candidate RPs.
+
+.. clicmd:: show ip pim bsr rp-info [vrf NAME] [json]
Display group-to-rp mappings received from E-BSR.
@@ -691,6 +791,10 @@ the config was written out.
This gathers data about events from zebra that come up through the ZAPI.
+.. clicmd:: debug pim autorp
+
+ This turns on debugging for PIM AutoRP protocol events.
+
PIM Clear Commands
==================
Clear commands reset various variables.
diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst
index edf7a82015..e4e28d71ab 100644
--- a/doc/user/pimv6.rst
+++ b/doc/user/pimv6.rst
@@ -80,6 +80,29 @@ PIMv6 Router
cannot see data flowing in better than 30 second chunks. This command is
vrf aware, to configure for a vrf, specify the vrf in the router pim6 block.
+.. clicmd:: bsr candidate-bsr [priority (0-255)] [source [address X:X::X:X] | [interface INTERFACE] | [loopback] | [any]]
+
+ Configure the router to advertise itself as a candidate PIM-SM BSR. The candidate
+ with the highest priority becomes the BSR for the domain (high wins). When priority is the
+ same for more than one candidate BSR, the candidate with the highest IP address
+ becomes the BSR of the domain. The address can be configured explicitly
+ via ``address``, or be selecting an interface name using ``interface``.
+ If ``any`` is configured the highest address from any interface will be selected.
+ By default, the highest loopback address is selected, which can also be
+ configured via ``loopback``
+
+.. clicmd:: bsr candidate-rp [interval (1-4294967295) ] [priority (0-255)] [source [address X:X::X:X] | [interface INTERFACE] | [loopback] | [any]]
+
+ Configure the router to advertise itself as a candidate PIM-SM RP. ``interval``
+ can be used to configure the interval in seconds to send these advertisements.
+ The candidate with the lowest priority becomes the RP for the domain (low wins).
+ When priority is the same for more than one candidate RP, the candidate with
+ the highest IP address becomes the BSR of the domain. The address can be
+ configured explicitly via ``address``, or be selecting an interface name
+ using ``interface``. If ``any`` is configured the highest address from any
+ interface will be selected.By default, the highest loopback address is
+ selected, which can also be configured via ``loopback``.
+
.. clicmd:: spt-switchover infinity-and-beyond [prefix-list PLIST]
On the last hop router if it is desired to not switch over to the SPT tree
@@ -391,11 +414,28 @@ General multicast routing state
Display total number of S,G mroutes and number of S,G mroutes
installed into the kernel for all vrfs.
-.. clicmd:: show ipv6 pim bsr
+.. clicmd:: show ipv6 pim bsr [vrf NAME] [json]
Display current bsr, its uptime and last received bsm age.
-.. clicmd:: show ipv6 pim bsrp-info [vrf NAME] [json]
+.. clicmd:: show ipv6 pim bsr candidate-bsr [vrf NAME] [json]
+
+ Display information about the candidate BSR state on this router.
+
+.. clicmd:: show ipv6 pim bsr candidate-rp [vrf NAME] [json]
+
+ Display information about the candidate RP state on this router.
+
+.. clicmd:: show ipv6 pim bsr candidate-rp-database [vrf NAME] [json]
+
+ Display the current list of candidate RPs received by this router.
+
+.. clicmd:: show ipv6 pim bsr groups [vrf NAME] [json]
+
+ Display the current list of multicast group mapping received by
+ this router from candidate RPs.
+
+.. clicmd:: show ipv6 pim bsr rp-info [vrf NAME] [json]
Display group-to-rp mappings received from E-BSR.
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 900d2fd343..06a19a6139 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -815,6 +815,16 @@ Allocated label chunks table can be dumped using the command
range is configured, static label requests that match that
range are not accepted.
+FEC nexthop entry resolution over MPLS networks
+-----------------------------------------------
+
+The LSP associated with a BGP labeled route is normally restricted to
+directly-connected nexthops. If connected nexthops are not available,
+the LSP entry will not be installed. This command permits the use of
+recursive resolution for LSPs, similar to that available for IP routes.
+
+.. clicmd:: mpls fec nexthop-resolution
+
.. _zebra-srv6:
Segment-Routing IPv6
@@ -1637,7 +1647,11 @@ zebra Terminal Mode Commands
option as that nexthop groups are per namespace in linux.
If you specify singleton you would like to see the singleton
nexthop groups that do have an afi. [type] allows you to filter those
- only coming from a specific NHG type (protocol).
+ only coming from a specific NHG type (protocol). A nexthop group
+ that has `Initial Delay`, means that this nexthop group entry
+ was not installed because no-one was using it at that point and
+ Zebra can delay installing this route until it is used by something
+ else.
.. clicmd:: show <ip|ipv6> zebra route dump [<vrf> VRFNAME]
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 2b19cbba84..e6cc794bae 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -2065,6 +2065,12 @@ void cli_show_isis_srv6_locator(struct vty *vty, const struct lyd_node *dnode,
vty_out(vty, " locator %s\n", yang_dnode_get_string(dnode, NULL));
}
+void cli_show_isis_srv6_locator_end(struct vty *vty,
+ const struct lyd_node *dnode)
+{
+ vty_out(vty, " exit\n");
+}
+
/*
* XPath: /frr-isisd:isis/instance/segment-routing-srv6/enabled
*/
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 391d42fba1..d588af314c 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -711,10 +711,6 @@ void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, struct json_object
}
}
-#if CONFDATE > 20240916
-CPP_NOTICE("Remove JSON in '-' format")
-#endif
-
void lsp_print_json(struct isis_lsp *lsp, struct json_object *json,
char dynhost, struct isis *isis)
{
@@ -728,19 +724,11 @@ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json,
own_json = json_object_new_object();
json_object_object_add(json, "lsp", own_json);
json_object_string_add(own_json, "id", LSPid);
-#if CONFDATE > 20240916
- CPP_NOTICE("remove own key")
-#endif
json_object_string_add(own_json, "own", lsp->own_lsp ? "*" : " ");
if (lsp->own_lsp)
json_object_boolean_add(own_json, "ownLSP", true);
- json_object_int_add(json, "pdu-len", lsp->hdr.pdu_len);
json_object_int_add(json, "pduLen", lsp->hdr.pdu_len);
snprintfrr(buf, sizeof(buf), "0x%08x", lsp->hdr.seqno);
-#if CONFDATE > 20240916
- CPP_NOTICE("remove seq-number key")
-#endif
- json_object_string_add(json, "seq-number", buf);
json_object_string_add(json, "seqNumber", buf);
snprintfrr(buf, sizeof(buf), "0x%04hx", lsp->hdr.checksum);
json_object_string_add(json, "chksum", buf);
@@ -751,11 +739,6 @@ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json,
} else {
json_object_int_add(json, "holdtime", lsp->hdr.rem_lifetime);
}
-#if CONFDATE > 20240916
- CPP_NOTICE("remove att-p-ol key")
-#endif
- json_object_string_add(
- json, "att-p-ol", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
json_object_string_add(json, "attPOl",
lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
}
diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c
index d04a24dc46..65ba395ffc 100644
--- a/isisd/isis_mt.c
+++ b/isisd/isis_mt.c
@@ -226,7 +226,8 @@ struct isis_area_mt_setting **area_mt_settings(struct isis_area *area,
count++;
if (count > size) {
- rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+ rv = XREALLOC(MTYPE_MT_AREA_SETTING, rv,
+ count * sizeof(*rv));
size = count;
}
rv[count - 1] = setting;
@@ -341,7 +342,8 @@ circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
count++;
if (count > size) {
- rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+ rv = XREALLOC(MTYPE_MT_AREA_SETTING, rv,
+ count * sizeof(*rv));
size = count;
}
rv[count - 1] = setting;
@@ -376,8 +378,8 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
old_mt_count = adj->mt_count;
if (old_mt_count) {
- old_mt_set =
- XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set));
+ old_mt_set = XCALLOC(MTYPE_MT_AREA_SETTING,
+ old_mt_count * sizeof(*old_mt_set));
memcpy(old_mt_set, adj->mt_set,
old_mt_count * sizeof(*old_mt_set));
}
@@ -436,7 +438,7 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
changed = true;
if (old_mt_count)
- XFREE(MTYPE_TMP, old_mt_set);
+ XFREE(MTYPE_MT_AREA_SETTING, old_mt_set);
return changed;
}
@@ -464,7 +466,7 @@ static void mt_set_add(uint16_t **mt_set, unsigned int *size,
}
if (*index >= *size) {
- *mt_set = XREALLOC(MTYPE_TMP, *mt_set,
+ *mt_set = XREALLOC(MTYPE_MT_AREA_SETTING, *mt_set,
sizeof(**mt_set) * ((*index) + 1));
*size = (*index) + 1;
}
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index 16cafa2ff0..8608d2b9bd 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -873,6 +873,7 @@ const struct frr_yang_module_info frr_isisd_info = {
.modify = isis_instance_segment_routing_srv6_locator_modify,
.destroy = isis_instance_segment_routing_srv6_locator_destroy,
.cli_show = cli_show_isis_srv6_locator,
+ .cli_show_end = cli_show_isis_srv6_locator_end,
},
},
{
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index c04a006a2e..1bf95e3db3 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -332,6 +332,8 @@ int isis_instance_segment_routing_srv6_locator_destroy(
struct nb_cb_destroy_args *args);
void cli_show_isis_srv6_locator(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
+void cli_show_isis_srv6_locator_end(struct vty *vty,
+ const struct lyd_node *dnode);
int isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_modify(
struct nb_cb_modify_args *args);
int isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_modify(
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 2b47d5cbeb..0f0c900ec2 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -2890,29 +2890,22 @@ int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args)
struct isis_area *area;
uint32_t algorithm;
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
algorithm = yang_dnode_get_uint32(args->dnode, "flex-algo");
area = nb_running_get_entry(args->dnode, NULL, true);
- switch (args->event) {
- case NB_EV_APPLY:
- for (ALL_LIST_ELEMENTS(area->flex_algos->flex_algos, node,
- nnode, fa)) {
- if (fa->algorithm == algorithm)
- flex_algo_free(area->flex_algos, fa);
- }
- if (list_isempty(area->flex_algos->flex_algos)) {
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node,
- circuit))
- isis_link_params_update_asla(circuit,
- circuit->interface);
- }
- lsp_regenerate_schedule(area, area->is_type, 0);
- break;
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
+ for (ALL_LIST_ELEMENTS(area->flex_algos->flex_algos, node, nnode, fa)) {
+ if (fa->algorithm == algorithm)
+ flex_algo_free(area->flex_algos, fa);
}
+ if (list_isempty(area->flex_algos->flex_algos)) {
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ isis_link_params_update_asla(circuit,
+ circuit->interface);
+ }
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
@@ -2960,26 +2953,22 @@ int isis_instance_flex_algo_advertise_definition_destroy(
struct flex_algo *fa;
uint32_t algorithm;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
area = nb_running_get_entry(args->dnode, NULL, true);
algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo");
- switch (args->event) {
- case NB_EV_APPLY:
- fa = flex_algo_lookup(area->flex_algos, algorithm);
- if (!fa) {
- snprintf(args->errmsg, args->errmsg_len,
- "flex-algo object not found");
- return NB_ERR_RESOURCE;
- }
- fa->advertise_definition = false;
- lsp_regenerate_schedule(area, area->is_type, 0);
- break;
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
+ fa = flex_algo_lookup(area->flex_algos, algorithm);
+ if (!fa) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "flex-algo object not found");
+ return NB_ERR_RESOURCE;
}
+ fa->advertise_definition = false;
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
@@ -2987,27 +2976,23 @@ int isis_instance_flex_algo_advertise_definition_destroy(
static int isis_instance_flex_algo_affinity_set(struct nb_cb_create_args *args,
int type)
{
- struct affinity_map *map;
+ char xpathr[XPATH_MAXLEN];
+ struct lyd_node *dnode;
struct isis_area *area;
struct admin_group *ag;
+ uint16_t bit_position;
struct flex_algo *fa;
uint32_t algorithm;
const char *val;
- algorithm = yang_dnode_get_uint32(args->dnode, "../../flex-algo");
- area = nb_running_get_entry(args->dnode, NULL, true);
val = yang_dnode_get_string(args->dnode, ".");
switch (args->event) {
case NB_EV_VALIDATE:
- fa = flex_algo_lookup(area->flex_algos, algorithm);
- if (!fa) {
- snprintf(args->errmsg, args->errmsg_len,
- "flex-algo object not found");
- return NB_ERR_RESOURCE;
- }
- map = affinity_map_get(val);
- if (!map) {
+ snprintf(xpathr, sizeof(xpathr),
+ "/frr-affinity-map:lib/affinity-maps/affinity-map[name='%s']/value",
+ val);
+ if (!yang_dnode_get(args->dnode, xpathr)) {
snprintf(args->errmsg, args->errmsg_len,
"affinity map %s isn't found", val);
return NB_ERR_VALIDATION;
@@ -3017,14 +3002,20 @@ static int isis_instance_flex_algo_affinity_set(struct nb_cb_create_args *args,
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
+ algorithm = yang_dnode_get_uint32(args->dnode,
+ "../../flex-algo");
+ area = nb_running_get_entry(args->dnode, NULL, true);
fa = flex_algo_lookup(area->flex_algos, algorithm);
if (!fa) {
snprintf(args->errmsg, args->errmsg_len,
"flex-algo object not found");
return NB_ERR_RESOURCE;
}
- map = affinity_map_get(val);
- if (!map) {
+ snprintf(xpathr, sizeof(xpathr),
+ "/frr-affinity-map:lib/affinity-maps/affinity-map[name='%s']/value",
+ val);
+ dnode = yang_dnode_get(args->dnode, xpathr);
+ if (!dnode) {
snprintf(args->errmsg, args->errmsg_len,
"affinity map %s isn't found", val);
return NB_ERR_RESOURCE;
@@ -3038,7 +3029,8 @@ static int isis_instance_flex_algo_affinity_set(struct nb_cb_create_args *args,
else
break;
- admin_group_set(ag, map->bit_position);
+ bit_position = yang_dnode_get_uint16(dnode, NULL);
+ admin_group_set(ag, bit_position);
lsp_regenerate_schedule(area, area->is_type, 0);
break;
}
@@ -3057,18 +3049,10 @@ isis_instance_flex_algo_affinity_unset(struct nb_cb_destroy_args *args,
uint32_t algorithm;
const char *val;
- algorithm = yang_dnode_get_uint32(args->dnode, "../../flex-algo");
- area = nb_running_get_entry(args->dnode, NULL, true);
val = yang_dnode_get_string(args->dnode, ".");
switch (args->event) {
case NB_EV_VALIDATE:
- fa = flex_algo_lookup(area->flex_algos, algorithm);
- if (!fa) {
- snprintf(args->errmsg, args->errmsg_len,
- "flex-algo object not found");
- return NB_ERR_RESOURCE;
- }
map = affinity_map_get(val);
if (!map) {
snprintf(args->errmsg, args->errmsg_len,
@@ -3080,6 +3064,9 @@ isis_instance_flex_algo_affinity_unset(struct nb_cb_destroy_args *args,
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
+ algorithm = yang_dnode_get_uint32(args->dnode,
+ "../../flex-algo");
+ area = nb_running_get_entry(args->dnode, NULL, true);
fa = flex_algo_lookup(area->flex_algos, algorithm);
if (!fa) {
snprintf(args->errmsg, args->errmsg_len,
@@ -3169,19 +3156,16 @@ int isis_instance_flex_algo_affinity_exclude_any_destroy(
int isis_instance_flex_algo_prefix_metric_create(struct nb_cb_create_args *args)
{
struct isis_area *area;
- const char *area_tag;
struct flex_algo *fa;
uint32_t algorithm;
- area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag");
- area = isis_area_lookup(area_tag, VRF_DEFAULT);
- if (!area)
- return NB_ERR_RESOURCE;
-
algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo");
switch (args->event) {
case NB_EV_APPLY:
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ if (!area)
+ return NB_ERR_RESOURCE;
fa = flex_algo_lookup(area->flex_algos, algorithm);
if (!fa) {
snprintf(args->errmsg, args->errmsg_len,
@@ -3204,19 +3188,17 @@ int isis_instance_flex_algo_prefix_metric_destroy(
struct nb_cb_destroy_args *args)
{
struct isis_area *area;
- const char *area_tag;
struct flex_algo *fa;
uint32_t algorithm;
- area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag");
- area = isis_area_lookup(area_tag, VRF_DEFAULT);
- if (!area)
- return NB_ERR_RESOURCE;
-
algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo");
switch (args->event) {
case NB_EV_APPLY:
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ if (!area)
+ return NB_ERR_RESOURCE;
+
fa = flex_algo_lookup(area->flex_algos, algorithm);
if (!fa) {
snprintf(args->errmsg, args->errmsg_len,
@@ -3239,19 +3221,17 @@ static int isis_instance_flex_algo_dplane_set(struct nb_cb_create_args *args,
int type)
{
struct isis_area *area;
- const char *area_tag;
struct flex_algo *fa;
uint32_t algorithm;
- area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag");
- area = isis_area_lookup(area_tag, VRF_DEFAULT);
- if (!area)
- return NB_ERR_RESOURCE;
-
algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo");
switch (args->event) {
case NB_EV_APPLY:
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ if (!area)
+ return NB_ERR_RESOURCE;
+
fa = flex_algo_lookup(area->flex_algos, algorithm);
if (!fa) {
snprintf(args->errmsg, args->errmsg_len,
@@ -3281,19 +3261,17 @@ static int isis_instance_flex_algo_dplane_unset(struct nb_cb_destroy_args *args,
int type)
{
struct isis_area *area;
- const char *area_tag;
struct flex_algo *fa;
uint32_t algorithm;
- area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag");
- area = isis_area_lookup(area_tag, VRF_DEFAULT);
- if (!area)
- return NB_ERR_RESOURCE;
-
algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo");
switch (args->event) {
case NB_EV_APPLY:
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ if (!area)
+ return NB_ERR_RESOURCE;
+
fa = flex_algo_lookup(area->flex_algos, algorithm);
if (!fa) {
snprintf(args->errmsg, args->errmsg_len,
@@ -3363,21 +3341,19 @@ int isis_instance_flex_algo_dplane_ip_destroy(struct nb_cb_destroy_args *args)
int isis_instance_flex_algo_metric_type_modify(struct nb_cb_modify_args *args)
{
struct isis_area *area;
- const char *area_tag;
struct flex_algo *fa;
uint32_t algorithm;
enum flex_algo_metric_type metric_type;
- area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag");
- area = isis_area_lookup(area_tag, VRF_DEFAULT);
- if (!area)
- return NB_ERR_RESOURCE;
-
algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo");
metric_type = yang_dnode_get_enum(args->dnode, NULL);
switch (args->event) {
case NB_EV_APPLY:
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ if (!area)
+ return NB_ERR_RESOURCE;
+
fa = flex_algo_lookup(area->flex_algos, algorithm);
if (!fa) {
snprintf(args->errmsg, args->errmsg_len,
@@ -3403,21 +3379,19 @@ int isis_instance_flex_algo_metric_type_modify(struct nb_cb_modify_args *args)
int isis_instance_flex_algo_priority_modify(struct nb_cb_modify_args *args)
{
struct isis_area *area;
- const char *area_tag;
struct flex_algo *fa;
uint32_t algorithm;
uint32_t priority;
- area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag");
- area = isis_area_lookup(area_tag, VRF_DEFAULT);
- if (!area)
- return NB_ERR_RESOURCE;
-
algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo");
priority = yang_dnode_get_uint32(args->dnode, NULL);
switch (args->event) {
case NB_EV_APPLY:
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ if (!area)
+ return NB_ERR_RESOURCE;
+
fa = flex_algo_lookup(area->flex_algos, algorithm);
if (!fa) {
snprintf(args->errmsg, args->errmsg_len,
@@ -3439,21 +3413,19 @@ int isis_instance_flex_algo_priority_modify(struct nb_cb_modify_args *args)
int isis_instance_flex_algo_priority_destroy(struct nb_cb_destroy_args *args)
{
struct isis_area *area;
- const char *area_tag;
struct flex_algo *fa;
uint32_t algorithm;
uint32_t priority = FLEX_ALGO_PRIO_DEFAULT;
- area_tag = yang_dnode_get_string(args->dnode, "../../../area-tag");
- area = isis_area_lookup(area_tag, VRF_DEFAULT);
- if (!area)
- return NB_ERR_RESOURCE;
-
algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo");
priority = yang_dnode_get_uint32(args->dnode, NULL);
switch (args->event) {
case NB_EV_APPLY:
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ if (!area)
+ return NB_ERR_RESOURCE;
+
fa = flex_algo_lookup(area->flex_algos, algorithm);
if (!fa) {
snprintf(args->errmsg, args->errmsg_len,
@@ -4325,14 +4297,6 @@ static int lib_interface_isis_multi_topology_common(
switch (event) {
case NB_EV_VALIDATE:
- circuit = nb_running_get_entry(dnode, NULL, false);
- if (circuit && circuit->area && circuit->area->oldmetric) {
- snprintf(
- errmsg, errmsg_len,
- "Multi topology IS-IS can only be used with wide metrics");
- return NB_ERR_VALIDATION;
- }
- break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
diff --git a/isisd/isis_nb_state.c b/isisd/isis_nb_state.c
index b7c33ed27b..da61bcced3 100644
--- a/isisd/isis_nb_state.c
+++ b/isisd/isis_nb_state.c
@@ -98,6 +98,8 @@ const void *lib_interface_state_isis_adjacencies_adjacency_get_next(
* adjacencies list.
*/
list = circuit->u.bc.adjdb[ISIS_LEVEL2 - 1];
+ if (!list)
+ break;
adj_next = listnode_head(list);
}
break;
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 86302076f8..8fc0f144b2 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -1469,14 +1469,13 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree,
sadj->metric = metric;
if (oldmetric)
SET_FLAG(flags, F_ISIS_SPF_ADJ_OLDMETRIC);
+ if ((oldmetric && sadj->metric == ISIS_NARROW_METRIC_INFINITY) ||
+ (!oldmetric && sadj->metric == ISIS_WIDE_METRIC_INFINITY))
+ SET_FLAG(flags, F_ISIS_SPF_ADJ_METRIC_INFINITY);
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)) {
@@ -2337,7 +2336,7 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
if (json == NULL) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
} else
*json = ttable_json_with_json_text(
tt, "ssdsss",
@@ -3016,7 +3015,7 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
} else if (json) {
*json = ttable_json_with_json_text(
tt, prefix_sid ? "sdssdsdd" : "sdsss",
@@ -3458,7 +3457,7 @@ static void isis_print_frr_summary(struct vty *vty,
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c
index f783038006..95ea36c3a8 100644
--- a/isisd/isis_sr.c
+++ b/isisd/isis_sr.c
@@ -627,6 +627,50 @@ static int sr_local_block_release_label(struct sr_local_block *srlb,
return 0;
}
+static bool sr_adj_same_subnet_ipv4(struct in_addr ipv4,
+ struct isis_circuit *circuit)
+{
+ struct listnode *node;
+ struct prefix ipv4_adj;
+ struct prefix_ipv4 *ipv4_circuit;
+
+ ipv4_adj.family = AF_INET;
+ ipv4_adj.u.prefix4 = ipv4;
+
+ for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ipv4_circuit)) {
+ ipv4_adj.prefixlen = ipv4_circuit->prefixlen;
+ if (!prefix_cmp(&ipv4_adj, (struct prefix *)ipv4_circuit))
+ return true;
+ }
+
+ return false;
+}
+
+static bool sr_adj_same_subnet_ipv6(struct in6_addr *ipv6,
+ struct isis_circuit *circuit)
+{
+ struct listnode *node;
+ struct prefix ipv6_adj;
+ struct prefix_ipv6 *ipv6_circuit;
+
+ ipv6_adj.family = AF_INET6;
+ IPV6_ADDR_COPY(&ipv6_adj.u.prefix6, ipv6);
+
+ for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ipv6_circuit)) {
+ ipv6_adj.prefixlen = ipv6_circuit->prefixlen;
+ if (!prefix_cmp(&ipv6_adj, (struct prefix *)ipv6_circuit))
+ return true;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ipv6_circuit)) {
+ ipv6_adj.prefixlen = ipv6_circuit->prefixlen;
+ if (!prefix_cmp(&ipv6_adj, (struct prefix *)ipv6_circuit))
+ return true;
+ }
+
+ return false;
+}
+
/* --- Segment Routing Adjacency-SID management functions ------------------- */
/**
@@ -658,12 +702,18 @@ void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, bool backup,
if (!circuit->ip_router || !adj->ipv4_address_count)
return;
+ if (!sr_adj_same_subnet_ipv4(adj->ipv4_addresses[0], circuit))
+ return;
+
nexthop.ipv4 = adj->ipv4_addresses[0];
break;
case AF_INET6:
if (!circuit->ipv6_router || !adj->ll_ipv6_count)
return;
+ if (!sr_adj_same_subnet_ipv6(&adj->ll_ipv6_addrs[0], circuit))
+ return;
+
nexthop.ipv6 = adj->ll_ipv6_addrs[0];
break;
default:
@@ -1064,7 +1114,7 @@ static void show_node(struct vty *vty, struct isis_area *area, int level,
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
}
ttable_del(tt);
}
diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c
index b5974b1a62..2348bd043a 100644
--- a/isisd/isis_srv6.c
+++ b/isisd/isis_srv6.c
@@ -591,7 +591,7 @@ static void show_node(struct vty *vty, struct isis_area *area, int level)
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
}
ttable_del(tt);
}
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
index b6321dbac3..c9af39ce5a 100644
--- a/isisd/isis_te.c
+++ b/isisd/isis_te.c
@@ -172,6 +172,10 @@ void isis_link_params_update_asla(struct isis_circuit *circuit,
struct isis_ext_subtlvs *ext = circuit->ext;
int i;
+ if (!ext)
+ /* no extended subTLVs - nothing to update */
+ return;
+
if (!HAS_LINK_PARAMS(ifp)) {
list_delete_all_node(ext->aslas);
return;
@@ -327,7 +331,7 @@ void isis_link_params_update(struct isis_circuit *circuit,
return;
/* Sanity Check */
- if ((ifp == NULL) || (circuit->state != C_STATE_UP))
+ if (ifp == NULL)
return;
te_debug("ISIS-TE(%s): Update circuit parameters for interface %s",
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index c7f45b2469..b5caf396c1 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -565,10 +565,6 @@ static void format_item_asla_subtlvs(struct isis_asla_subtlvs *asla,
asla->use_bw);
}
-#if CONFDATE > 20240916
-CPP_NOTICE("Remove JSON in '-' format")
-#endif
-
/* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
struct sbuf *buf, struct json_object *json,
@@ -585,10 +581,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
snprintfrr(aux_buf, sizeof(aux_buf), "0x%x",
exts->adm_group);
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "adm-group", aux_buf);
json_object_string_add(json, "admGroup", aux_buf);
} else {
sbuf_push(buf, indent, "Admin Group: 0x%08x\n",
@@ -639,13 +631,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
}
if (IS_SUBTLV(exts, EXT_LLRI)) {
if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_int_add(json, "link-local-id",
- exts->local_llri);
- json_object_int_add(json, "link-remote-id",
- exts->remote_llri);
json_object_int_add(json, "linkLocalId",
exts->local_llri);
json_object_int_add(json, "linkRemoteId",
@@ -661,10 +646,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
inet_ntop(AF_INET, &exts->local_addr, aux_buf,
sizeof(aux_buf));
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "local-iface-ip", aux_buf);
json_object_string_add(json, "localIfaceIp", aux_buf);
} else
sbuf_push(buf, indent,
@@ -675,11 +656,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
inet_ntop(AF_INET, &exts->neigh_addr, aux_buf,
sizeof(aux_buf));
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "remote-iface-ip",
- aux_buf);
json_object_string_add(json, "remoteIfaceIp", aux_buf);
} else
sbuf_push(buf, indent,
@@ -690,11 +666,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
inet_ntop(AF_INET6, &exts->local_addr6, aux_buf,
sizeof(aux_buf));
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "local-iface-ipv6",
- aux_buf);
json_object_string_add(json, "localIfaceIpv6", aux_buf);
} else
sbuf_push(buf, indent,
@@ -705,11 +676,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
inet_ntop(AF_INET6, &exts->neigh_addr6, aux_buf,
sizeof(aux_buf));
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "remote-iface-ipv6",
- aux_buf);
json_object_string_add(json, "remoteIfaceIpv6", aux_buf);
} else
sbuf_push(buf, indent,
@@ -720,11 +686,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
snprintfrr(aux_buf, sizeof(aux_buf), "%g",
exts->max_bw);
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "max-bandwith-bytes-sec",
- aux_buf);
json_object_string_add(json, "maxBandwithBytesSec",
aux_buf);
} else
@@ -736,11 +697,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
snprintfrr(aux_buf, sizeof(aux_buf), "%g",
exts->max_rsv_bw);
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(
- json, "max-res-bandwith-bytes-sec", aux_buf);
json_object_string_add(json, "maxResBandwithBytesSec",
aux_buf);
} else
@@ -763,22 +719,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
json_object_string_add(unrsv_json, cnt_buf,
aux_buf);
}
-
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- unrsv_json = json_object_new_object();
- json_object_object_add(json, "unrsv-bandwith-bytes-sec",
- unrsv_json);
- for (int j = 0; j < MAX_CLASS_TYPE; j += 1) {
- snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j);
- snprintfrr(aux_buf, sizeof(aux_buf), "%g",
- exts->unrsv_bw[j]);
- json_object_string_add(unrsv_json, cnt_buf,
- aux_buf);
- }
- /* end old deprecated key format */
} else {
sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
@@ -791,27 +731,18 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
}
}
if (IS_SUBTLV(exts, EXT_TE_METRIC)) {
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_int_add(json, "te-metric", exts->te_metric);
+ if (json)
json_object_int_add(json, "teMetric", exts->te_metric);
- } else
+ else
sbuf_push(buf, indent,
"Traffic Engineering Metric: %u\n",
exts->te_metric);
}
if (IS_SUBTLV(exts, EXT_RMT_AS)) {
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_int_add(json, "inter-as-te-remote-as",
- exts->remote_as);
+ if (json)
json_object_int_add(json, "interAsTeRemoteAs",
exts->remote_as);
- } else
+ else
sbuf_push(buf, indent,
"Inter-AS TE Remote AS number: %u\n",
exts->remote_as);
@@ -820,11 +751,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
inet_ntop(AF_INET6, &exts->remote_ip, aux_buf,
sizeof(aux_buf));
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(
- json, "inter-as-te-remote-asbr-ip", aux_buf);
json_object_string_add(json, "interAsTeRemoteAsbrIp",
aux_buf);
} else
@@ -836,16 +762,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (IS_SUBTLV(exts, EXT_DELAY)) {
if (json) {
struct json_object *avg_json;
- avg_json = json_object_new_object();
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_object_add(json, "avg-delay", avg_json);
- json_object_string_add(avg_json, "delay",
- IS_ANORMAL(exts->delay)
- ? "Anomalous"
- : "Normal");
- json_object_int_add(avg_json, "micro-sec", exts->delay);
avg_json = json_object_new_object();
json_object_object_add(json, "avgDelay", avg_json);
@@ -864,19 +780,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
if (json) {
struct json_object *avg_json;
- avg_json = json_object_new_object();
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_object_add(json, "max-min-delay", avg_json);
- json_object_string_add(avg_json, "delay",
- IS_ANORMAL(exts->min_delay)
- ? "Anomalous"
- : "Normal");
- snprintfrr(aux_buf, sizeof(aux_buf), "%u / %u",
- exts->min_delay & TE_EXT_MASK,
- exts->max_delay & TE_EXT_MASK);
- json_object_string_add(avg_json, "micro-sec", aux_buf);
avg_json = json_object_new_object();
json_object_object_add(json, "maxMinDelay", avg_json);
@@ -899,15 +802,10 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
exts->max_delay & TE_EXT_MASK);
}
if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_int_add(json, "delay-variation-micro-sec",
- exts->delay_var & TE_EXT_MASK);
+ if (json)
json_object_int_add(json, "delayVariationMicroSec",
exts->delay_var & TE_EXT_MASK);
- } else
+ else
sbuf_push(buf, indent,
"Delay Variation: %u (micro-sec)\n",
exts->delay_var & TE_EXT_MASK);
@@ -919,20 +817,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
LOSS_PRECISION));
struct json_object *link_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- link_json = json_object_new_object();
- json_object_object_add(json, "link-packet-loss",
- link_json);
- json_object_string_add(link_json, "loss",
- IS_ANORMAL(exts->pkt_loss)
- ? "Anomalous"
- : "Normal");
- /* typo */
- json_object_string_add(link_json, "percentaje",
- aux_buf);
-
link_json = json_object_new_object();
json_object_object_add(json, "linkPacketLoss",
link_json);
@@ -952,12 +836,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
snprintfrr(aux_buf, sizeof(aux_buf), "%g",
(exts->res_bw));
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json,
- "unidir-residual-band-bytes-sec",
- aux_buf);
json_object_string_add(json,
"unidirResidualBandBytesSec",
aux_buf);
@@ -971,12 +849,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
snprintfrr(aux_buf, sizeof(aux_buf), "%g",
(exts->ava_bw));
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(
- json, "unidir-available-band-bytes-sec",
- aux_buf);
json_object_string_add(json,
"unidirAvailableBandBytesSec",
aux_buf);
@@ -991,12 +863,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
snprintfrr(aux_buf, sizeof(aux_buf), "%g",
(exts->use_bw));
json_object_string_add(json,
- "unidir-utilized-band-bytes-sec",
- aux_buf);
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json,
"unidirUtilizedBandBytesSec",
aux_buf);
} else
@@ -1012,50 +878,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
struct json_object *arr_adj_json, *adj_sid_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- arr_adj_json = json_object_new_array();
- json_object_object_add(json, "adj-sid", arr_adj_json);
- for (adj = (struct isis_adj_sid *)exts->adj_sid.head;
- adj; adj = adj->next) {
- snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
- adj->sid);
- adj_sid_json = json_object_new_object();
- json_object_int_add(adj_sid_json, "sid",
- adj->sid);
- json_object_int_add(adj_sid_json, "weight",
- adj->weight);
- json_object_string_add(adj_sid_json, "flag-f",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
- ? "1"
- : "0");
- json_object_string_add(adj_sid_json, "flag-b",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
- ? "1"
- : "0");
- json_object_string_add(adj_sid_json, "flag-v",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
- ? "1"
- : "0");
- json_object_string_add(adj_sid_json, "flag-l",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
- ? "1"
- : "0");
- json_object_string_add(adj_sid_json, "flag-s",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
- ? "1"
- : "0");
- json_object_string_add(adj_sid_json, "flag-p",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
- ? "1"
- : "0");
- json_object_array_add(arr_adj_json,
- adj_sid_json);
- }
- /* end old deprecated key format */
-
arr_adj_json = json_object_new_array();
json_object_object_add(json, "adjSid", arr_adj_json);
for (adj = (struct isis_adj_sid *)exts->adj_sid.head;
@@ -1127,57 +949,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
struct json_object *arr_adj_json, *lan_adj_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- arr_adj_json = json_object_new_array();
- json_object_object_add(json, "lan-adj-sid",
- arr_adj_json);
- for (lan = (struct isis_lan_adj_sid *)
- exts->adj_sid.head;
- lan; lan = lan->next) {
- if (((mtid == ISIS_MT_IPV4_UNICAST) &&
- (lan->family != AF_INET)) ||
- ((mtid == ISIS_MT_IPV6_UNICAST) &&
- (lan->family != AF_INET6)))
- continue;
- snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
- lan->sid);
- lan_adj_json = json_object_new_object();
- json_object_int_add(lan_adj_json, "sid",
- lan->sid);
- json_object_int_add(lan_adj_json, "weight",
- lan->weight);
- json_object_string_add(lan_adj_json, "flag-f",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
- ? "1"
- : "0");
- json_object_string_add(lan_adj_json, "flag-b",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
- ? "1"
- : "0");
- json_object_string_add(lan_adj_json, "flag-v",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
- ? "1"
- : "0");
- json_object_string_add(lan_adj_json, "flag-l",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
- ? "1"
- : "0");
- json_object_string_add(lan_adj_json, "flag-s",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
- ? "1"
- : "0");
- json_object_string_add(lan_adj_json, "flag-p",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
- ? "1"
- : "0");
- json_object_array_add(arr_adj_json,
- lan_adj_json);
- }
- /* end old deprecated key format */
-
arr_adj_json = json_object_new_array();
json_object_object_add(json, "lanAdjSid", arr_adj_json);
for (lan = (struct isis_lan_adj_sid *)exts->adj_sid.head;
@@ -1264,57 +1035,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (json) {
struct json_object *arr_adj_json, *srv6_endx_sid_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- arr_adj_json = json_object_new_array();
- json_object_object_add(json, "srv6-endx-sid",
- arr_adj_json);
- for (adj = (struct isis_srv6_endx_sid_subtlv *)
- exts->srv6_endx_sid.head;
- adj; adj = adj->next) {
- snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6",
- &adj->sid);
- srv6_endx_sid_json = json_object_new_object();
- json_object_string_addf(srv6_endx_sid_json,
- "sid", "%pI6",
- &adj->sid);
- json_object_string_add(srv6_endx_sid_json,
- "algorithm",
- sr_algorithm_string(
- adj->algorithm));
- json_object_int_add(srv6_endx_sid_json,
- "weight", adj->weight);
- json_object_string_add(srv6_endx_sid_json,
- "behavior",
- seg6local_action2str(
- adj->behavior));
- json_object_string_add(srv6_endx_sid_json,
- "flag-b",
- adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG
- ? "1"
- : "0");
- json_object_string_add(srv6_endx_sid_json,
- "flag-s",
- adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG
- ? "1"
- : "0");
- json_object_string_add(srv6_endx_sid_json,
- "flag-p",
- adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG
- ? "1"
- : "0");
- json_object_array_add(arr_adj_json,
- srv6_endx_sid_json);
- if (adj->subsubtlvs)
- isis_format_subsubtlvs(adj->subsubtlvs,
- NULL,
- srv6_endx_sid_json,
- indent + 4);
- }
- /* end old deprecated key format */
-
arr_adj_json = json_object_new_array();
json_object_object_add(json, "srv6EndXSID",
arr_adj_json);
@@ -1390,63 +1110,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
struct json_object *arr_adj_json,
*srv6_lan_endx_sid_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- arr_adj_json = json_object_new_array();
- json_object_object_add(json, "srv6-lan-endx-sid",
- arr_adj_json);
- for (lan = (struct isis_srv6_lan_endx_sid_subtlv *)
- exts->srv6_lan_endx_sid.head;
- lan; lan = lan->next) {
- snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6",
- &lan->sid);
- srv6_lan_endx_sid_json =
- json_object_new_object();
- json_object_string_addf(srv6_lan_endx_sid_json,
- "sid", "%pI6",
- &lan->sid);
- json_object_int_add(srv6_lan_endx_sid_json,
- "weight", lan->weight);
- json_object_string_add(srv6_lan_endx_sid_json,
- "algorithm",
- sr_algorithm_string(
- lan->algorithm));
- json_object_int_add(srv6_lan_endx_sid_json,
- "weight", lan->weight);
- json_object_string_add(srv6_lan_endx_sid_json,
- "behavior",
- seg6local_action2str(
- lan->behavior));
- json_object_string_add(srv6_lan_endx_sid_json,
- "flag-b",
- lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG
- ? "1"
- : "0");
- json_object_string_add(srv6_lan_endx_sid_json,
- "flag-s",
- lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG
- ? "1"
- : "0");
- json_object_string_add(srv6_lan_endx_sid_json,
- "flag-p",
- lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG
- ? "1"
- : "0");
- json_object_string_addf(srv6_lan_endx_sid_json,
- "neighbor-id", "%pSY",
- lan->neighbor_id);
- json_object_array_add(arr_adj_json,
- srv6_lan_endx_sid_json);
- if (lan->subsubtlvs)
- isis_format_subsubtlvs(lan->subsubtlvs,
- NULL,
- srv6_lan_endx_sid_json,
- indent + 4);
- }
- /* end old deprecated key format */
-
arr_adj_json = json_object_new_array();
json_object_object_add(json, "srv6LanEndxSID",
arr_adj_json);
@@ -1914,8 +1577,8 @@ static int unpack_item_ext_subtlv_asla(uint16_t mtid, uint8_t subtlv_len,
uint8_t sabm_flag_len;
/* User-defined App Identifier Bit Flags/Length */
uint8_t uabm_flag_len;
- uint8_t sabm[ASLA_APP_IDENTIFIER_BIT_LENGTH] = {0};
- uint8_t uabm[ASLA_APP_IDENTIFIER_BIT_LENGTH] = {0};
+ uint8_t sabm[ASLA_APP_IDENTIFIER_BIT_MAX_LENGTH] = { 0 };
+ uint8_t uabm[ASLA_APP_IDENTIFIER_BIT_MAX_LENGTH] = { 0 };
uint8_t readable = subtlv_len;
uint8_t subsubtlv_type;
uint8_t subsubtlv_len;
@@ -1946,6 +1609,15 @@ static int unpack_item_ext_subtlv_asla(uint16_t mtid, uint8_t subtlv_len,
return -1;
}
+ if ((asla->standard_apps_length > ASLA_APP_IDENTIFIER_BIT_MAX_LENGTH) ||
+ (asla->user_def_apps_length > ASLA_APP_IDENTIFIER_BIT_MAX_LENGTH)) {
+ zlog_err("Standard or User-Defined Application Identifier Bit Mask Length greater than %u bytes. Received respectively a length of %u and %u bytes.",
+ ASLA_APP_IDENTIFIER_BIT_MAX_LENGTH,
+ asla->standard_apps_length, asla->user_def_apps_length);
+ stream_forward_getp(s, readable);
+ return -1;
+ }
+
for (int i = 0; i < asla->standard_apps_length; i++)
sabm[i] = stream_getc(s);
for (int i = 0; i < asla->user_def_apps_length; i++)
@@ -2604,33 +2276,6 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
}
json_object_int_add(sr_json, "alg", sid->algorithm);
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated non boolean json")
-#endif
- /* old deprecated keys (no booleans) */
- json_object_string_add(
- sr_json, "readvertised",
- ((sid->flags & ISIS_PREFIX_SID_READVERTISED) ? "yes"
- : ""));
- json_object_string_add(
- sr_json, "node",
- ((sid->flags & ISIS_PREFIX_SID_NODE) ? "yes" : ""));
- json_object_string_add(sr_json, "php",
- ((sid->flags & ISIS_PREFIX_SID_NO_PHP)
- ? "no-php"
- : "php"));
- json_object_string_add(
- sr_json, "explicit-null",
- ((sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL) ? "yes"
- : ""));
- json_object_string_add(
- sr_json, "value",
- ((sid->flags & ISIS_PREFIX_SID_VALUE) ? "yes" : ""));
- json_object_string_add(
- sr_json, "local",
- ((sid->flags & ISIS_PREFIX_SID_LOCAL) ? "yes" : ""));
- /* end deprecated keys (no booleans) */
-
struct json_object *flags_json;
flags_json = json_object_new_object();
@@ -2779,10 +2424,6 @@ static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
char prefixbuf[PREFIX2STR_BUFFER];
if (json) {
prefix2str(p, prefixbuf, sizeof(prefixbuf));
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "ipv6-src-prefix", prefixbuf);
json_object_string_add(json, "ipv6SrcPrefix", prefixbuf);
} else {
sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n",
@@ -2886,23 +2527,6 @@ static void format_subsubtlv_srv6_sid_structure(
if (json) {
struct json_object *sid_struct_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- sid_struct_json = json_object_new_object();
- json_object_object_add(json, "srv6-sid-structure",
- sid_struct_json);
- json_object_int_add(sid_struct_json, "loc-block-len",
- sid_struct->loc_block_len);
- json_object_int_add(sid_struct_json, "loc-node-len",
- sid_struct->loc_node_len);
- json_object_int_add(sid_struct_json, "func-len",
- sid_struct->func_len);
- json_object_int_add(sid_struct_json, "arg-len",
- sid_struct->arg_len);
- /* end old deprecated key format */
-
sid_struct_json = json_object_new_object();
json_object_object_add(json, "srv6SidStructure",
sid_struct_json);
@@ -3196,26 +2820,6 @@ static void format_item_srv6_end_sid(uint16_t mtid, struct isis_item *i,
if (json) {
struct json_object *sid_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- sid_json = json_object_new_object();
- json_object_object_add(json, "srv6-end-sid", sid_json);
- json_object_string_add(sid_json, "endpoint-behavior",
- seg6local_action2str(sid->behavior));
- json_object_string_addf(sid_json, "sid-value", "%pI6",
- &sid->sid);
- if (sid->subsubtlvs) {
- struct json_object *subtlvs_json;
- subtlvs_json = json_object_new_object();
- json_object_object_add(sid_json, "subsubtlvs",
- subtlvs_json);
- isis_format_subsubtlvs(sid->subsubtlvs, NULL,
- subtlvs_json, 0);
- }
- /* end old deprecated key format */
-
sid_json = json_object_new_object();
json_object_object_add(json, "srv6EndSid", sid_json);
json_object_string_add(sid_json, "endpointBehavior",
@@ -3376,13 +2980,9 @@ static void format_item_area_address(uint16_t mtid, struct isis_item *i,
memcpy(iso_addr.area_addr, addr->addr, ISO_ADDR_SIZE);
iso_addr.addr_len = addr->len;
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_addf(json, "area-addr", "%pIS", &iso_addr);
+ if (json)
json_object_string_addf(json, "areaAddr", "%pIS", &iso_addr);
- } else
+ else
sbuf_push(buf, indent, "Area Address: %pIS\n", &iso_addr);
}
@@ -3470,22 +3070,6 @@ static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i,
if (json) {
struct json_object *old_json, *array_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- old_json = json_object_new_object();
- json_object_object_get_ex(json, "old-reach-style", &array_json);
- if (!array_json) {
- array_json = json_object_new_array();
- json_object_object_add(json, "old-reach-style",
- array_json);
- }
- json_object_array_add(array_json, old_json);
- json_object_string_add(old_json, "is-reach", sys_id);
- json_object_int_add(old_json, "metric", r->metric);
- /* end old deprecated key format */
-
old_json = json_object_new_object();
json_object_object_get_ex(json, "oldReachStyle", &array_json);
if (!array_json) {
@@ -3573,13 +3157,9 @@ static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i,
char sys_id[ISO_SYSID_STRLEN];
snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pSY", n->mac);
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "lan-neighbor", sys_id);
+ if (json)
json_object_string_add(json, "lanNeighbor", sys_id);
- } else
+ else
sbuf_push(buf, indent, "LAN Neighbor: %s\n", sys_id);
}
@@ -3651,17 +3231,6 @@ static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i,
if (json) {
char buf[255];
struct json_object *lsp_json;
- lsp_json = json_object_new_object();
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_object_add(json, "lsp-entry", lsp_json);
- json_object_string_add(lsp_json, "id", sys_id);
- snprintfrr(buf,sizeof(buf),"0x%08x",e->seqno);
- json_object_string_add(lsp_json, "seq", buf);
- snprintfrr(buf,sizeof(buf),"0x%04hx",e->checksum);
- json_object_string_add(lsp_json, "chksum", buf);
- json_object_int_add(lsp_json, "lifetime", e->checksum);
lsp_json = json_object_new_object();
json_object_object_add(json, "lspEntry", lsp_json);
@@ -3753,31 +3322,6 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i,
if (json) {
struct json_object *reach_json, *array_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- reach_json = json_object_new_object();
- json_object_object_get_ex(json, "ext-reach", &array_json);
- if (!array_json) {
- array_json = json_object_new_array();
- json_object_object_add(json, "ext-reach", array_json);
- }
- json_object_array_add(array_json, reach_json);
- json_object_string_add(
- reach_json, "mt-id",
- (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT");
- json_object_string_add(reach_json, "id", sys_id);
- json_object_int_add(reach_json, "metric", r->metric);
- if (mtid != ISIS_MT_IPV4_UNICAST)
- json_object_string_add(reach_json, "mt-name",
- isis_mtid2str(mtid));
-
- if (r->subtlvs)
- format_item_ext_subtlvs(r->subtlvs, NULL, reach_json,
- indent + 2, mtid);
- /* end old deprecated key format */
-
reach_json = json_object_new_object();
json_object_object_get_ex(json, "extReach", &array_json);
if (!array_json) {
@@ -3926,24 +3470,6 @@ static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i,
if (json) {
struct json_object *old_json, *array_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- old_json = json_object_new_object();
- json_object_object_get_ex(json, "old-ip-reach-style",
- &array_json);
- if (!array_json) {
- array_json = json_object_new_array();
- json_object_object_add(json, "old-ip-reach-style",
- old_json);
- }
- json_object_array_add(array_json, old_json);
- json_object_string_add(old_json, "prefix",
- prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)));
- json_object_int_add(old_json, "metric", r->metric);
- /* end old deprecated key format */
-
old_json = json_object_new_object();
json_object_object_get_ex(json, "oldIpReachStyle", &array_json);
if (!array_json) {
@@ -4049,19 +3575,6 @@ static void format_tlv_protocols_supported(struct isis_protocols_supported *p,
struct json_object *protocol_json;
char buf[255];
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- protocol_json = json_object_new_object();
- json_object_object_add(json, "protocols-supported",
- protocol_json);
- for (uint8_t i = 0; i < p->count; i++) {
- snprintfrr(buf, sizeof(buf), "%d", i);
- json_object_string_add(protocol_json, buf,
- nlpid2str(p->protocols[i]));
- }
-
protocol_json = json_object_new_object();
json_object_object_add(json, "supportedProtocols",
protocol_json);
@@ -4070,7 +3583,6 @@ static void format_tlv_protocols_supported(struct isis_protocols_supported *p,
json_object_string_add(protocol_json, buf,
nlpid2str(p->protocols[i]));
}
- /* end old deprecated key format */
} else {
sbuf_push(buf, indent, "Protocols Supported: ");
for (uint8_t i = 0; i < p->count; i++) {
@@ -4286,13 +3798,9 @@ static void format_item_global_ipv6_address(uint16_t mtid, struct isis_item *i,
char addrbuf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "global-ipv6", addrbuf);
+ if (json)
json_object_string_add(json, "globalIpv6", addrbuf);
- } else
+ else
sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n",
addrbuf);
}
@@ -4374,12 +3882,6 @@ static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i,
json_object_string_add(mt_json, "mtDescription",
isis_mtid2str(mtid));
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated non boolean format")
-#endif
- json_object_string_add(mt_json, "overload", info->overload?"true":"false");
- json_object_string_add(mt_json, "attached", info->attached?"true":"false");
-
json_object_boolean_add(mt_json, "overloadBit",
!!info->overload);
json_object_boolean_add(mt_json, "attachedbit",
@@ -4466,13 +3968,9 @@ static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf,
char addrbuf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf));
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "te-router-id", addrbuf);
+ if (json)
json_object_string_add(json, "teRouterId", addrbuf);
- } else
+ else
sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf);
}
@@ -4547,37 +4045,6 @@ static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i,
char prefixbuf[PREFIX2STR_BUFFER];
if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- ext_json = json_object_new_object();
- json_object_object_get_ex(json, "ext-ip-reach", &array_json);
- if (!array_json) {
- array_json = json_object_new_array();
- json_object_object_add(json, "ext-ip-reach", array_json);
- }
- json_object_array_add(array_json, ext_json);
- json_object_string_add(ext_json, "mt-id",
- (mtid == ISIS_MT_IPV4_UNICAST)
- ? "Extended"
- : "MT");
- json_object_string_add(ext_json, "ip-reach",
- prefix2str(&r->prefix, prefixbuf,
- sizeof(prefixbuf)));
- json_object_int_add(ext_json, "ip-reach-metric", r->metric);
- json_object_string_add(ext_json, "down", r->down ? "yes" : "");
- if (mtid != ISIS_MT_IPV4_UNICAST)
- json_object_string_add(ext_json, "mt-name",
- isis_mtid2str(mtid));
- if (r->subtlvs) {
- struct json_object *subtlv_json;
- subtlv_json = json_object_new_object();
- json_object_object_add(ext_json, "subtlvs", subtlv_json);
- format_subtlvs(r->subtlvs, NULL, subtlv_json, 0);
- }
- /* end old deprecated key format */
-
ext_json = json_object_new_object();
json_object_object_get_ex(json, "extIpReach", &array_json);
if (!array_json) {
@@ -4860,13 +4327,9 @@ static void format_tlv_te_router_id_ipv6(const struct in6_addr *id,
char addrbuf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, id, addrbuf, sizeof(addrbuf));
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "ipv6-te-router-id", addrbuf);
+ if (json)
json_object_string_add(json, "ipv6TeRouterId", addrbuf);
- } else
+ else
sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf);
}
@@ -4944,30 +4407,6 @@ static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
if (json) {
struct json_object *spine_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated format */
- spine_json = json_object_new_object();
- json_object_object_add(json, "spine-leaf-extension",
- spine_json);
- if (spine_leaf->has_tier) {
- snprintfrr(aux_buf, sizeof(aux_buf), "%hhu",
- spine_leaf->tier);
- json_object_string_add(
- spine_json, "tier",
- (spine_leaf->tier == ISIS_TIER_UNDEFINED)
- ? "undefined"
- : aux_buf);
- }
- json_object_string_add(spine_json, "flag-leaf",
- spine_leaf->is_leaf ? "yes" : "");
- json_object_string_add(spine_json, "flag-spine",
- spine_leaf->is_spine ? "yes" : "");
- json_object_string_add(spine_json, "flag-backup",
- spine_leaf->is_backup ? "yes" : "");
- /* end old deprecated format */
-
spine_json = json_object_new_object();
json_object_object_add(json, "spineLeafExtension", spine_json);
if (spine_leaf->has_tier) {
@@ -5127,26 +4566,6 @@ format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
if (json) {
struct json_object *three_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- three_json = json_object_new_object();
- json_object_object_add(json, "p2p-three-way-adj", three_json);
- json_object_string_add(
- three_json, "state-name",
- isis_threeway_state_name(threeway_adj->state));
- json_object_int_add(three_json, "state", threeway_adj->state);
- json_object_int_add(three_json, "ext-local-circuit-id",
- threeway_adj->local_circuit_id);
- if (threeway_adj->neighbor_set) {
- json_object_string_add(three_json, "neigh-system-id",
- sys_id);
- json_object_int_add(three_json, "neigh-ext-circuit-id",
- threeway_adj->neighbor_circuit_id);
- }
- /* end old deprecated key format */
-
three_json = json_object_new_object();
json_object_object_add(json, "p2pThreeWayAdj", three_json);
json_object_string_add(three_json, "stateName",
@@ -5297,40 +4716,6 @@ static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i,
subtlvs_json);
format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0);
}
-
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated JSON key format */
- reach_json = json_object_new_object();
- json_object_object_get_ex(json, "ipv6-reach", &array_json);
- if (!array_json) {
- array_json = json_object_new_array();
- json_object_object_add(json, "ipv6-reach", array_json);
- }
- json_object_array_add(array_json, reach_json);
- json_object_string_add(reach_json, "mt-id",
- (mtid == ISIS_MT_IPV4_UNICAST) ? ""
- : "mt");
- json_object_string_add(
- reach_json, "prefix",
- prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)));
- json_object_int_add(reach_json, "metric", r->metric);
- json_object_string_add(reach_json, "down",
- r->down ? "yes" : "");
- json_object_string_add(reach_json, "external",
- r->external ? "yes" : "");
- if (mtid != ISIS_MT_IPV4_UNICAST)
- json_object_string_add(reach_json, "mt-name",
- isis_mtid2str(mtid));
- if (r->subtlvs) {
- struct json_object *subtlvs_json;
- subtlvs_json = json_object_new_object();
- json_object_object_add(reach_json, "subtlvs",
- subtlvs_json);
- format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0);
- }
- /* end deprecated key format */
} else {
sbuf_push(buf, indent,
"%sIPv6 Reachability: %s (Metric: %u)%s%s",
@@ -5543,22 +4928,6 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap,
/* Router ID and Flags */
struct json_object *cap_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* deprecated JSON key format */
- cap_json = json_object_new_object();
- json_object_object_add(json, "router-capability", cap_json);
- inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf));
- json_object_string_add(cap_json, "id", addrbuf);
- json_object_string_add(
- cap_json, "flag-d",
- router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? "1" : "0");
- json_object_string_add(
- cap_json, "flag-s",
- router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? "1" : "0");
- /* end deprecated JSON key format */
-
cap_json = json_object_new_object();
json_object_object_add(json, "routerCapability", cap_json);
inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf));
@@ -5573,23 +4942,6 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap,
if (router_cap->srgb.range_size != 0) {
struct json_object *gb_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* deprecated old key format */
- gb_json = json_object_new_object();
- json_object_object_add(json, "segment-routing-gb", gb_json);
- json_object_string_add(gb_json, "ipv4",
- IS_SR_IPV4(&router_cap->srgb) ? "1"
- : "0");
- json_object_string_add(gb_json, "ipv6",
- IS_SR_IPV6(&router_cap->srgb) ? "1"
- : "0");
- json_object_int_add(gb_json, "global-block-base",
- router_cap->srgb.lower_bound);
- json_object_int_add(gb_json, "global-block-range",
- router_cap->srgb.range_size);
-
gb_json = json_object_new_object();
json_object_object_add(json, "segmentRoutingGb", gb_json);
json_object_boolean_add(gb_json, "ipv4",
@@ -5606,18 +4958,6 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap,
if (router_cap->srlb.range_size != 0) {
struct json_object *lb_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- lb_json = json_object_new_object();
- json_object_object_add(json, "segment-routing-lb", lb_json);
- json_object_int_add(lb_json, "global-block-base",
- router_cap->srlb.lower_bound);
- json_object_int_add(lb_json, "global-block-range",
- router_cap->srlb.range_size);
- /* end old deprecated key format */
-
lb_json = json_object_new_object();
json_object_object_add(json, "segmentRoutingLb", lb_json);
json_object_int_add(lb_json, "globalBlockBase",
@@ -5631,23 +4971,6 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap,
char buf[255];
struct json_object *alg_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- alg_json = json_object_new_object();
- json_object_object_add(json, "segment-routing-algorithm",
- alg_json);
- for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
- if (router_cap->algo[i] != SR_ALGORITHM_UNSET) {
- snprintfrr(buf, sizeof(buf), "%d", i);
- json_object_string_add(alg_json, buf,
- router_cap->algo[i] == 0
- ? "SPF"
- : "Strict SPF");
- }
- /* end old deprecated key format */
-
alg_json = json_object_new_object();
json_object_object_add(json, "segmentRoutingAlgorithm",
alg_json);
@@ -6138,16 +5461,17 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
return 0;
}
- if (tlvs->router_cap)
- /* Multiple Router Capability found */
- rcap = tlvs->router_cap;
- else {
- /* Allocate router cap structure and initialize SR Algorithms */
- rcap = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct isis_router_cap));
+ if (!tlvs->router_cap) {
+ /* First Router Capability TLV.
+ * Allocate router cap structure and initialize SR Algorithms */
+ tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV,
+ sizeof(struct isis_router_cap));
for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
- rcap->algo[i] = SR_ALGORITHM_UNSET;
+ tlvs->router_cap->algo[i] = SR_ALGORITHM_UNSET;
}
+ rcap = tlvs->router_cap;
+
/* Get Router ID and Flags */
rcap->router_id.s_addr = stream_get_ipv4(s);
rcap->flags = stream_getc(s);
@@ -6169,7 +5493,6 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
log, indent,
"WARNING: Router Capability subTLV length too large compared to expected size\n");
stream_forward_getp(s, STREAM_READABLE(s));
- XFREE(MTYPE_ISIS_TLV, rcap);
return 0;
}
@@ -6480,7 +5803,6 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
}
subtlv_len = subtlv_len - length - 2;
}
- tlvs->router_cap = rcap;
return 0;
}
@@ -6503,24 +5825,16 @@ static void format_item_auth(uint16_t mtid, struct isis_item *i,
struct isis_auth *auth = (struct isis_auth *)i;
char obuf[768];
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "test-auth", "ok");
+ if (json)
json_object_string_add(json, "testAuth", "ok");
- } else
+ else
sbuf_push(buf, indent, "Authentication:\n");
switch (auth->type) {
case ISIS_PASSWD_TYPE_CLEARTXT:
zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length);
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "auth-pass", obuf);
+ if (json)
json_object_string_add(json, "authPass", obuf);
- } else
+ else
sbuf_push(buf, indent, " Password: %s\n", obuf);
break;
case ISIS_PASSWD_TYPE_HMAC_MD5:
@@ -6528,23 +5842,15 @@ static void format_item_auth(uint16_t mtid, struct isis_item *i,
snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, "%02hhx",
auth->value[j]);
}
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "auth-hmac-md5", obuf);
+ if (json)
json_object_string_add(json, "authHmacMd5", obuf);
- } else
+ else
sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf);
break;
default:
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_int_add(json, "auth-unknown", auth->type);
+ if (json)
json_object_int_add(json, "authUnknown", auth->type);
- } else
+ else
sbuf_push(buf, indent, " Unknown (%hhu)\n",
auth->type);
break;
@@ -6660,18 +5966,6 @@ static void format_tlv_purge_originator(struct isis_purge_originator *poi,
if (json) {
struct json_object *purge_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old deprecated key format */
- purge_json = json_object_new_object();
- json_object_object_add(json, "purge_originator", purge_json);
-
- json_object_string_add(purge_json, "id", gen_id);
- if (poi->sender_set)
- json_object_string_add(purge_json, "rec-from", sen_id);
- /* end old deprecated key format */
-
purge_json = json_object_new_object();
json_object_object_add(json, "purgeOriginator", purge_json);
@@ -7221,33 +6515,6 @@ static void format_item_srv6_locator(uint16_t mtid, struct isis_item *i,
if (json) {
struct json_object *loc_json;
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- /* old json key format */
- loc_json = json_object_new_object();
- json_object_object_add(json, "srv6-locator", loc_json);
- json_object_int_add(loc_json, "mt-id", mtid);
- json_object_string_addf(loc_json, "prefix", "%pFX",
- &loc->prefix);
- json_object_int_add(loc_json, "metric", loc->metric);
- json_object_string_add(
- loc_json, "d-flag",
- CHECK_FLAG(loc->flags, ISIS_TLV_SRV6_LOCATOR_FLAG_D)
- ? "yes"
- : "");
- json_object_int_add(loc_json, "algorithm", loc->algorithm);
- json_object_string_add(loc_json, "mt-name",
- isis_mtid2str(mtid));
- if (loc->subtlvs) {
- struct json_object *subtlvs_json;
- subtlvs_json = json_object_new_object();
- json_object_object_add(loc_json, "subtlvs",
- subtlvs_json);
- format_subtlvs(loc->subtlvs, NULL, subtlvs_json, 0);
- }
- /* old deprecated key format */
-
loc_json = json_object_new_object();
json_object_object_add(json, "srv6Locator", loc_json);
json_object_int_add(loc_json, "mtId", mtid);
@@ -7549,13 +6816,9 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, struct json_ob
&tlvs->area_addresses, buf, json, indent);
if (tlvs->mt_router_info_empty) {
- if (json) {
-#if CONFDATE > 20240916
- CPP_NOTICE("remove deprecated key format with -")
-#endif
- json_object_string_add(json, "mt-router-info", "none");
+ if (json)
json_object_object_add(json, "mtRouterInfo", NULL);
- } else
+ else
sbuf_push(buf, indent, "MT Router Info: None\n");
} else {
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
index 6ecd4c5f6a..c64bbf7f69 100644
--- a/isisd/isis_tlvs.h
+++ b/isisd/isis_tlvs.h
@@ -717,6 +717,7 @@ struct isis_ext_subtlvs {
#define ISIS_SABM_FLAG_X 0x10 /* Flex-Algorithm - RFC9350 */
#define ASLA_APP_IDENTIFIER_BIT_LENGTH 1
+#define ASLA_APP_IDENTIFIER_BIT_MAX_LENGTH 8
#define ASLA_LEGACY_FLAG 0x80
#define ASLA_APPS_LENGTH_MASK 0x7f
diff --git a/lib/bfd.h b/lib/bfd.h
index 48929a9564..99790f96a5 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -16,14 +16,8 @@ extern "C" {
#endif
#define BFD_DEF_MIN_RX 300
-#define BFD_MIN_MIN_RX 50
-#define BFD_MAX_MIN_RX 60000
#define BFD_DEF_MIN_TX 300
-#define BFD_MIN_MIN_TX 50
-#define BFD_MAX_MIN_TX 60000
#define BFD_DEF_DETECT_MULT 3
-#define BFD_MIN_DETECT_MULT 2
-#define BFD_MAX_DETECT_MULT 255
#define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */
#define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */
diff --git a/lib/command.c b/lib/command.c
index 51f2529e3e..25c9ee9a73 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -17,6 +17,7 @@
#include <lib/version.h>
#include "command.h"
+#include "debug.h"
#include "frrstr.h"
#include "memory.h"
#include "log.h"
@@ -1453,7 +1454,7 @@ DEFUN (config_help,
"Description of the interactive help system\n")
{
vty_out(vty,
- "Quagga VTY provides advanced help feature. When you need help,\n\
+ "FRR VTY provides advanced help feature. When you need help,\n\
anytime at the command line please press '?'.\n\
\n\
If nothing matches, the help list will be empty and you must backup\n\
@@ -2463,8 +2464,7 @@ const char *host_config_get(void)
void cmd_show_lib_debugs(struct vty *vty)
{
route_map_show_debug(vty);
- mgmt_debug_be_client_show_debug(vty);
- mgmt_debug_fe_client_show_debug(vty);
+ debug_status_write(vty);
}
void install_default(enum node_type node)
diff --git a/lib/command.h b/lib/command.h
index cb105c656c..f369a35243 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -84,14 +84,12 @@ enum node_type {
CONFIG_NODE, /* Config node. Default mode of config file. */
PREFIX_NODE, /* ip prefix-list node. */
PREFIX_IPV6_NODE, /* ipv6 prefix-list node. */
+ LIB_DEBUG_NODE, /* frrlib debug node. */
DEBUG_NODE, /* Debug node. */
VRF_DEBUG_NODE, /* Vrf Debug node. */
- NORTHBOUND_DEBUG_NODE, /* Northbound Debug node. */
DEBUG_VNC_NODE, /* Debug VNC node. */
RMAP_DEBUG_NODE, /* Route-map debug node */
RESOLVER_DEBUG_NODE, /* Resolver debug node */
- MGMT_BE_DEBUG_NODE, /* mgmtd backend-client debug node */
- MGMT_FE_DEBUG_NODE, /* mgmtd frontend-client debug node */
AAA_NODE, /* AAA node. */
EXTLOG_NODE, /* RFC5424 & co. extended syslog */
KEYCHAIN_NODE, /* Key-chain node. */
@@ -102,7 +100,6 @@ enum node_type {
INTERFACE_NODE, /* Interface mode node. */
NH_GROUP_NODE, /* Nexthop-Group mode node. */
ZEBRA_NODE, /* zebra connection node. */
- TABLE_NODE, /* rtm_table selection node. */
RIP_NODE, /* RIP protocol mode node. */
RIPNG_NODE, /* RIPng protocol mode node. */
BABEL_NODE, /* BABEL protocol mode node. */
@@ -120,7 +117,6 @@ enum node_type {
BGP_VNC_DEFAULTS_NODE, /* BGP VNC nve defaults */
BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */
BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
- RFP_DEFAULTS_NODE, /* RFP defaults node */
BGP_EVPN_NODE, /* BGP EVPN node. */
BGP_SRV6_NODE, /* BGP SRv6 node. */
OSPF_NODE, /* OSPF protocol mode */
diff --git a/lib/debug.c b/lib/debug.c
index 757a47ab99..d25c32d428 100644
--- a/lib/debug.c
+++ b/lib/debug.c
@@ -9,42 +9,75 @@
#include "debug.h"
#include "command.h"
-static struct debug_cb_list_head cb_head;
+static struct debug_list_head debug_head;
-DECLARE_LIST(debug_cb_list, struct debug_callbacks, item);
+DECLARE_LIST(debug_list, struct debug, item);
/* All code in this section should be reentrant and MT-safe */
-DEFUN_NOSH(debug_all, debug_all_cmd, "[no] debug all",
- NO_STR DEBUG_STR "Toggle all debugging output\n")
+DEFUN_NOSH (debug_all,
+ debug_all_cmd,
+ "[no] debug all",
+ NO_STR DEBUG_STR
+ "Toggle all debugging output\n")
{
- struct debug_callbacks *cb;
-
+ struct debug *debug;
bool set = !strmatch(argv[0]->text, "no");
uint32_t mode = DEBUG_NODE2MODE(vty->node);
- frr_each (debug_cb_list, &cb_head, cb)
- cb->debug_set_all(mode, set);
+ frr_each (debug_list, &debug_head, debug) {
+ DEBUG_MODE_SET(debug, mode, set);
+
+ /* If all modes have been turned off, don't preserve options. */
+ if (!DEBUG_MODE_CHECK(debug, DEBUG_MODE_ALL))
+ DEBUG_CLEAR(debug);
+ }
return CMD_SUCCESS;
}
/* ------------------------------------------------------------------------- */
-void debug_init(struct debug_callbacks *cb)
+void debug_status_write(struct vty *vty)
+{
+ struct debug *debug;
+
+ frr_each (debug_list, &debug_head, debug) {
+ if (DEBUG_MODE_CHECK(debug, DEBUG_MODE_ALL))
+ vty_out(vty, " %s debugging is on\n", debug->desc);
+ }
+}
+
+static int config_write_debug(struct vty *vty)
{
- static bool inited = false;
+ struct debug *debug;
- if (!inited) {
- inited = true;
- debug_cb_list_init(&cb_head);
+ frr_each (debug_list, &debug_head, debug) {
+ if (DEBUG_MODE_CHECK(debug, DEBUG_MODE_CONF))
+ vty_out(vty, "%s\n", debug->conf);
}
- debug_cb_list_add_head(&cb_head, cb);
+ return 0;
}
-void debug_init_cli(void)
+static struct cmd_node debug_node = {
+ .name = "debug",
+ .node = LIB_DEBUG_NODE,
+ .prompt = "",
+ .config_write = config_write_debug,
+};
+
+void debug_install(struct debug *debug)
{
+ debug_list_add_tail(&debug_head, debug);
+}
+
+void debug_init(void)
+{
+ debug_list_init(&debug_head);
+
+ install_node(&debug_node);
+
install_element(ENABLE_NODE, &debug_all_cmd);
install_element(CONFIG_NODE, &debug_all_cmd);
}
diff --git a/lib/debug.h b/lib/debug.h
index e9d8a31abd..eee314cff5 100644
--- a/lib/debug.h
+++ b/lib/debug.h
@@ -34,6 +34,7 @@ extern "C" {
#define DEBUG_OPT_NONE 0x00000000
+PREDECL_LIST(debug_list);
/*
* Debugging record.
*
@@ -63,37 +64,18 @@ extern "C" {
* manipulate the flags field in a multithreaded environment results in
* undefined behavior.
*
+ * conf
+ * The configuration string that will be written to the config file.
+ *
* desc
* Human-readable description of this debugging record.
*/
struct debug {
atomic_uint_fast32_t flags;
+ const char *conf;
const char *desc;
-};
-PREDECL_LIST(debug_cb_list);
-/*
- * Callback set for debugging code.
- *
- * debug_set_all
- * Function pointer to call when the user requests that all debugs have a
- * mode set.
- */
-struct debug_callbacks {
- /*
- * Linked list of Callbacks to call
- */
- struct debug_cb_list_item item;
-
- /*
- * flags
- * flags to set on debug flag fields
- *
- * set
- * true: set flags
- * false: unset flags
- */
- void (*debug_set_all)(uint32_t flags, bool set);
+ struct debug_list_item item;
};
/*
@@ -217,22 +199,19 @@ struct debug_callbacks {
#define DEBUGN(name, fmt, ...) DEBUG(notice, name, fmt, ##__VA_ARGS__)
#define DEBUGD(name, fmt, ...) DEBUG(debug, name, fmt, ##__VA_ARGS__)
+/* Show current debugging status. */
+void debug_status_write(struct vty *vty);
+
/*
- * Optional initializer for debugging. Highly recommended.
- *
- * This function installs common debugging commands and allows the caller to
- * specify callbacks to take when these commands are issued, allowing the
- * caller to respond to events such as a request to turn off all debugs.
- *
- * MT-Safe
+ * Register a debug item.
*/
-void debug_init(struct debug_callbacks *cb);
+void debug_install(struct debug *debug);
/*
- * Turn on the cli to turn on/off debugs.
- * Should only be called by libfrr
+ * Initialize debugging.
+ * Should only be called by libfrr.
*/
-void debug_init_cli(void);
+void debug_init(void);
#ifdef __cplusplus
}
diff --git a/lib/elf_py.c b/lib/elf_py.c
index 2b4fea373f..6c63d1f892 100644
--- a/lib/elf_py.c
+++ b/lib/elf_py.c
@@ -1307,7 +1307,7 @@ static PyObject *elffile_load(PyTypeObject *type, PyObject *args,
}
#endif
- w->sects = calloc(sizeof(PyObject *), w->ehdr->e_shnum);
+ w->sects = calloc(w->ehdr->e_shnum, sizeof(PyObject *));
w->n_sect = w->ehdr->e_shnum;
return (PyObject *)w;
diff --git a/lib/frrlua.c b/lib/frrlua.c
index 2cab1a5460..ef081e4bd0 100644
--- a/lib/frrlua.c
+++ b/lib/frrlua.c
@@ -323,7 +323,7 @@ void lua_pushnexthop_group(lua_State *L, const struct nexthop_group *ng)
{
lua_newtable(L);
struct nexthop *nexthop;
- int i = 0;
+ int i = 1;
for (ALL_NEXTHOPS_PTR(ng, nexthop)) {
lua_pushnexthop(L, nexthop);
@@ -382,6 +382,12 @@ static const char *frrlua_log_thunk(lua_State *L)
return lua_tostring(L, 1);
}
+static int frrlua_log_trace(lua_State *L)
+{
+ zlog_debug("%s", frrlua_stackdump(L));
+ return 0;
+}
+
static int frrlua_log_debug(lua_State *L)
{
zlog_debug("%s", frrlua_log_thunk(L));
@@ -413,11 +419,12 @@ static int frrlua_log_error(lua_State *L)
}
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},
+ { "trace", frrlua_log_trace },
+ { "debug", frrlua_log_debug },
+ { "info", frrlua_log_info },
+ { "notice", frrlua_log_notice },
+ { "warn", frrlua_log_warn },
+ { "error", frrlua_log_error },
{},
};
@@ -432,6 +439,67 @@ void frrlua_export_logging(lua_State *L)
* Debugging.
*/
+void lua_table_dump(lua_State *L, int index, struct buffer *buf, int level)
+{
+ char tmpbuf[64] = {};
+
+ lua_pushnil(L);
+
+ while (lua_next(L, index) != 0) {
+ int key_type;
+ int value_type;
+
+ for (int i = 0; i < level; i++)
+ buffer_putstr(buf, " ");
+
+ key_type = lua_type(L, -2);
+ if (key_type == LUA_TSTRING) {
+ const char *key = lua_tostring(L, -2);
+
+ buffer_putstr(buf, key);
+ buffer_putstr(buf, ": ");
+ } else if (key_type == LUA_TNUMBER) {
+ snprintf(tmpbuf, sizeof(tmpbuf), "%g",
+ lua_tonumber(L, -2));
+ buffer_putstr(buf, tmpbuf);
+ buffer_putstr(buf, ": ");
+ }
+
+ value_type = lua_type(L, -1);
+ switch (value_type) {
+ case LUA_TSTRING:
+ snprintf(tmpbuf, sizeof(tmpbuf), "\"%s\"\n",
+ lua_tostring(L, -1));
+ buffer_putstr(buf, tmpbuf);
+ break;
+ case LUA_TBOOLEAN:
+ snprintf(tmpbuf, sizeof(tmpbuf), "%s\n",
+ lua_toboolean(L, -1) ? "true" : "false");
+ buffer_putstr(buf, tmpbuf);
+ break;
+ case LUA_TNUMBER:
+ snprintf(tmpbuf, sizeof(tmpbuf), "%g\n",
+ lua_tonumber(L, -1));
+ buffer_putstr(buf, tmpbuf);
+ break;
+ case LUA_TTABLE:
+ buffer_putstr(buf, "{\n");
+ lua_table_dump(L, lua_gettop(L), buf, level + 1);
+ for (int i = 0; i < level; i++)
+ buffer_putstr(buf, " ");
+ buffer_putstr(buf, "}\n");
+ break;
+ default:
+ snprintf(tmpbuf, sizeof(tmpbuf), "%s\n",
+ lua_typename(L, value_type));
+ buffer_putstr(buf, tmpbuf);
+ break;
+ }
+
+ lua_pop(L, 1);
+ }
+}
+
char *frrlua_stackdump(lua_State *L)
{
int top = lua_gettop(L);
@@ -458,6 +526,11 @@ char *frrlua_stackdump(lua_State *L)
lua_tonumber(L, i));
buffer_putstr(buf, tmpbuf);
break;
+ case LUA_TTABLE: /* tables */
+ buffer_putstr(buf, "{\n");
+ lua_table_dump(L, i, buf, 1);
+ buffer_putstr(buf, "}\n");
+ break;
default: /* other values */
snprintf(tmpbuf, sizeof(tmpbuf), "%s\n",
lua_typename(L, t));
diff --git a/lib/frrlua.h b/lib/frrlua.h
index dc0f4d9986..e407a4492f 100644
--- a/lib/frrlua.h
+++ b/lib/frrlua.h
@@ -181,6 +181,9 @@ int frrlua_table_get_integer(lua_State *L, const char *key);
*/
void frrlua_export_logging(lua_State *L);
+/* A helper fuction that dumps the Lua stack */
+void lua_table_dump(lua_State *L, int index, struct buffer *buf, int level);
+
/*
* Dump Lua stack to a string.
*
diff --git a/lib/frrscript.c b/lib/frrscript.c
index acdd1df67b..dbae31b666 100644
--- a/lib/frrscript.c
+++ b/lib/frrscript.c
@@ -348,6 +348,9 @@ int frrscript_load(struct frrscript *fs, const char *function_name,
/* Set up the Lua script */
lua_State *L = luaL_newstate();
+ /* Load basic built-in Lua functions, e.g. ipairs, string, etc. */
+ luaL_openlibs(L);
+
frrlua_export_logging(L);
char script_name[MAXPATHLEN];
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
index abd42f359f..05088d52d1 100644
--- a/lib/grammar_sandbox_main.c
+++ b/lib/grammar_sandbox_main.c
@@ -40,7 +40,7 @@ int main(int argc, char **argv)
vty_init(master, true);
lib_cmd_init();
- nb_init(master, NULL, 0, false);
+ nb_init(master, NULL, 0, false, false);
vty_stdio(vty_do_exit);
diff --git a/lib/hash.c b/lib/hash.c
index df56243985..edbfeec464 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -444,7 +444,7 @@ DEFUN_NOSH(show_hash_stats,
ttable_colseps(tt, 0, RIGHT, true, '|');
char *table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
} else
vty_out(vty, "No named hash tables to display.\n");
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 07cd4a5306..f2247a48e5 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -809,6 +809,7 @@ struct event_loop *frr_init(void)
vty_init(master, di->log_always);
lib_cmd_init();
+ debug_init();
frr_pthread_init();
#ifdef HAVE_SCRIPTING
@@ -819,14 +820,13 @@ struct event_loop *frr_init(void)
log_ref_vty_init();
lib_error_init();
- nb_init(master, di->yang_modules, di->n_yang_modules, true);
+ nb_init(master, di->yang_modules, di->n_yang_modules, true,
+ (di->flags & FRR_LOAD_YANG_LIBRARY) != 0);
if (nb_db_init() != NB_OK)
flog_warn(EC_LIB_NB_DATABASE,
"%s: failed to initialize northbound database",
__func__);
- debug_init_cli();
-
return master;
}
@@ -1126,9 +1126,12 @@ static void frr_terminal_close(int isexit)
* don't redirect when stdout is set with --log stdout
*/
for (fd = 2; fd >= 0; fd--)
- if (isatty(fd) &&
- (fd != STDOUT_FILENO || !logging_to_stdout))
+ if (logging_to_stdout && isatty(fd) &&
+ fd == STDOUT_FILENO) {
+ /* Do nothing. */
+ } else {
dup2(nullfd, fd);
+ }
close(nullfd);
}
}
@@ -1214,9 +1217,12 @@ void frr_run(struct event_loop *master)
* stdout
*/
for (fd = 2; fd >= 0; fd--)
- if (isatty(fd) &&
- (fd != STDOUT_FILENO || !logging_to_stdout))
+ if (logging_to_stdout && isatty(fd) &&
+ fd == STDOUT_FILENO) {
+ /* Do nothing. */
+ } else {
dup2(nullfd, fd);
+ }
close(nullfd);
}
@@ -1463,7 +1469,10 @@ void _libfrr_version(void)
const char banner[] =
FRR_FULL_NAME " " FRR_VERSION ".\n"
FRR_COPYRIGHT GIT_INFO "\n"
- "configured with:\n " FRR_CONFIG_ARGS "\n";
+#ifdef ENABLE_VERSION_BUILD_CONFIG
+ "configured with:\n " FRR_CONFIG_ARGS "\n"
+#endif
+ ;
write(1, banner, sizeof(banner) - 1);
_exit(0);
}
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 7ed7be4d98..df537e2e3b 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -46,6 +46,11 @@ extern "C" {
* is responsible for calling frr_vty_serv() itself.
*/
#define FRR_MANUAL_VTY_START (1 << 7)
+/* If FRR_LOAD_YANG_LIBRARY is set then libyang will be told to load and
+ * implement it's internal ietf-yang-library implementation. This should
+ * normally only be done from mgmtd.
+ */
+#define FRR_LOAD_YANG_LIBRARY (1 << 8)
PREDECL_DLIST(log_args);
struct log_arg {
diff --git a/lib/log.c b/lib/log.c
index 880180ae5a..04b789b5da 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -351,7 +351,6 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_BFD_DEST_REPLAY),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_ADD),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_DEL),
- DESC_ENTRY(ZEBRA_VRF_UNREGISTER),
DESC_ENTRY(ZEBRA_VRF_ADD),
DESC_ENTRY(ZEBRA_VRF_DELETE),
DESC_ENTRY(ZEBRA_VRF_LABEL),
diff --git a/lib/memory.c b/lib/memory.c
index 8fbe5c4093..ac39516edd 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -25,6 +25,7 @@ struct memgroup **mg_insert = &mg_first;
DEFINE_MGROUP(LIB, "libfrr");
DEFINE_MTYPE(LIB, TMP, "Temporary memory");
+DEFINE_MTYPE(LIB, TMP_TTABLE, "Temporary memory for TTABLE");
DEFINE_MTYPE(LIB, BITFIELD, "Bitfield memory");
static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
diff --git a/lib/memory.h b/lib/memory.h
index 65b99a5fc9..8e8c61da04 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -138,6 +138,7 @@ struct memgroup {
DECLARE_MGROUP(LIB);
DECLARE_MTYPE(TMP);
+DECLARE_MTYPE(TMP_TTABLE);
extern void *qmalloc(struct memtype *mt, size_t size)
diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c
index 6e2fb05e84..f03006ad0e 100644
--- a/lib/mgmt_be_client.c
+++ b/lib/mgmt_be_client.c
@@ -116,6 +116,7 @@ struct mgmt_be_client {
frr_each_safe (mgmt_be_txns, &(client_ctx)->txn_head, (txn))
struct debug mgmt_dbg_be_client = {
+ .conf = "debug mgmt client backend",
.desc = "Management backend client operations"
};
@@ -1061,7 +1062,7 @@ static void be_client_handle_notify(struct mgmt_be_client *client, void *msgbuf,
struct mgmt_msg_notify_data *notif_msg = msgbuf;
struct nb_node *nb_node;
struct lyd_node *dnode;
- const char *data;
+ const char *data = NULL;
const char *notif;
LY_ERR err;
@@ -1258,31 +1259,6 @@ DEFPY(debug_mgmt_client_be, debug_mgmt_client_be_cmd,
return CMD_SUCCESS;
}
-static int mgmt_debug_be_client_config_write(struct vty *vty)
-{
- if (DEBUG_MODE_CHECK(&mgmt_dbg_be_client, DEBUG_MODE_CONF))
- vty_out(vty, "debug mgmt client backend\n");
-
- return 1;
-}
-
-void mgmt_debug_be_client_show_debug(struct vty *vty)
-{
- if (debug_check_be_client())
- vty_out(vty, "debug mgmt client backend\n");
-}
-
-static struct debug_callbacks mgmt_dbg_be_client_cbs = {
- .debug_set_all = mgmt_debug_client_be_set
-};
-
-static struct cmd_node mgmt_dbg_node = {
- .name = "debug mgmt client backend",
- .node = MGMT_BE_DEBUG_NODE,
- .prompt = "",
- .config_write = mgmt_debug_be_client_config_write,
-};
-
struct mgmt_be_client *mgmt_be_client_create(const char *client_name,
struct mgmt_be_client_cbs *cbs,
uintptr_t user_data,
@@ -1328,8 +1304,8 @@ struct mgmt_be_client *mgmt_be_client_create(const char *client_name,
void mgmt_be_client_lib_vty_init(void)
{
- debug_init(&mgmt_dbg_be_client_cbs);
- install_node(&mgmt_dbg_node);
+ debug_install(&mgmt_dbg_be_client);
+
install_element(ENABLE_NODE, &debug_mgmt_client_be_cmd);
install_element(CONFIG_NODE, &debug_mgmt_client_be_cmd);
}
diff --git a/lib/mgmt_be_client.h b/lib/mgmt_be_client.h
index 7ad0589bdb..6ed8c2a39f 100644
--- a/lib/mgmt_be_client.h
+++ b/lib/mgmt_be_client.h
@@ -122,11 +122,6 @@ mgmt_be_client_create(const char *name, struct mgmt_be_client_cbs *cbs,
extern void mgmt_be_client_lib_vty_init(void);
/*
- * Print enabled debugging commands.
- */
-extern void mgmt_debug_be_client_show_debug(struct vty *vty);
-
-/*
* [Un]-subscribe with MGMTD for one or more YANG subtree(s).
*
* client
diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c
index 8cfb025f72..ced2f2e454 100644
--- a/lib/mgmt_fe_client.c
+++ b/lib/mgmt_fe_client.c
@@ -49,6 +49,7 @@ struct mgmt_fe_client {
frr_each_safe (mgmt_sessions, &(client)->sessions, (session))
struct debug mgmt_dbg_fe_client = {
+ .conf = "debug mgmt client frontend",
.desc = "Management frontend client operations"
};
@@ -805,31 +806,6 @@ DEFPY(debug_mgmt_client_fe, debug_mgmt_client_fe_cmd,
return CMD_SUCCESS;
}
-static int mgmt_debug_fe_client_config_write(struct vty *vty)
-{
- if (DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, DEBUG_MODE_CONF))
- vty_out(vty, "debug mgmt client frontend\n");
-
- return CMD_SUCCESS;
-}
-
-void mgmt_debug_fe_client_show_debug(struct vty *vty)
-{
- if (debug_check_fe_client())
- vty_out(vty, "debug mgmt client frontend\n");
-}
-
-static struct debug_callbacks mgmt_dbg_fe_client_cbs = {
- .debug_set_all = mgmt_debug_client_fe_set
-};
-
-static struct cmd_node mgmt_dbg_node = {
- .name = "debug mgmt client frontend",
- .node = MGMT_FE_DEBUG_NODE,
- .prompt = "",
- .config_write = mgmt_debug_fe_client_config_write,
-};
-
/*
* Initialize library and try connecting with MGMTD.
*/
@@ -870,8 +846,8 @@ struct mgmt_fe_client *mgmt_fe_client_create(const char *client_name,
void mgmt_fe_client_lib_vty_init(void)
{
- debug_init(&mgmt_dbg_fe_client_cbs);
- install_node(&mgmt_dbg_node);
+ debug_install(&mgmt_dbg_fe_client);
+
install_element(ENABLE_NODE, &debug_mgmt_client_fe_cmd);
install_element(CONFIG_NODE, &debug_mgmt_client_fe_cmd);
}
diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h
index 20c87044a5..2b5a25fa0d 100644
--- a/lib/mgmt_fe_client.h
+++ b/lib/mgmt_fe_client.h
@@ -179,11 +179,6 @@ mgmt_fe_client_create(const char *client_name, struct mgmt_fe_client_cbs *cbs,
extern void mgmt_fe_client_lib_vty_init(void);
/*
- * Print enabled debugging commands.
- */
-extern void mgmt_debug_fe_client_show_debug(struct vty *vty);
-
-/*
* Create a new Session for a Frontend Client connection.
*
* lib_hndl
diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h
index 76a52658cd..ef03b66edc 100644
--- a/lib/mgmt_msg_native.h
+++ b/lib/mgmt_msg_native.h
@@ -383,11 +383,18 @@ _Static_assert(sizeof(struct mgmt_msg_edit) ==
/**
* struct mgmt_msg_edit_reply - frontend edit reply.
*
- * @data: the xpath of the data node that was created.
+ * @changed: If true then changes in datastore resulted.
+ * @created: If true then object was newly created (non-existing before)
+ * @data: @vsplit values, second value may be zero len.
+ * @data: [0] the xpath of the data node that was created.
+ * @data: [1] Possible structured data to pass back to client (e.g., non-"error"
+ * yang modeled error data).
*/
struct mgmt_msg_edit_reply {
struct mgmt_msg_header;
- uint8_t resv2[8];
+ uint8_t changed;
+ uint8_t created;
+ uint8_t resv2[6];
alignas(8) char data[];
};
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 65c12c1e69..98b05295b9 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -139,7 +139,7 @@ static int _nexthop_source_cmp(const struct nexthop *nh1,
}
static int _nexthop_cmp_no_labels(const struct nexthop *next1,
- const struct nexthop *next2)
+ const struct nexthop *next2, bool use_weight)
{
int ret = 0;
@@ -155,11 +155,13 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
if (next1->type > next2->type)
return 1;
- if (next1->weight < next2->weight)
- return -1;
+ if (use_weight) {
+ if (next1->weight < next2->weight)
+ return -1;
- if (next1->weight > next2->weight)
- return 1;
+ if (next1->weight > next2->weight)
+ return 1;
+ }
switch (next1->type) {
case NEXTHOP_TYPE_IPV4:
@@ -227,11 +229,12 @@ done:
return ret;
}
-int nexthop_cmp(const struct nexthop *next1, const struct nexthop *next2)
+static int nexthop_cmp_internal(const struct nexthop *next1,
+ const struct nexthop *next2, bool use_weight)
{
int ret = 0;
- ret = _nexthop_cmp_no_labels(next1, next2);
+ ret = _nexthop_cmp_no_labels(next1, next2, use_weight);
if (ret != 0)
return ret;
@@ -244,6 +247,17 @@ int nexthop_cmp(const struct nexthop *next1, const struct nexthop *next2)
return ret;
}
+int nexthop_cmp(const struct nexthop *next1, const struct nexthop *next2)
+{
+ return nexthop_cmp_internal(next1, next2, true);
+}
+
+int nexthop_cmp_no_weight(const struct nexthop *next1,
+ const struct nexthop *next2)
+{
+ return nexthop_cmp_internal(next1, next2, false);
+}
+
/*
* More-limited comparison function used to detect duplicate
* nexthops. This is used in places where we don't need the full
@@ -441,7 +455,7 @@ bool nexthop_same_no_labels(const struct nexthop *nh1,
if (nh1 == nh2)
return true;
- if (_nexthop_cmp_no_labels(nh1, nh2) != 0)
+ if (_nexthop_cmp_no_labels(nh1, nh2, true) != 0)
return false;
return true;
@@ -699,6 +713,15 @@ struct nexthop *nexthop_next(const struct nexthop *nexthop)
return NULL;
}
+struct nexthop *nexthop_next_resolution(const struct nexthop *nexthop,
+ bool nexthop_resolution)
+{
+ if (nexthop_resolution)
+ return nexthop_next(nexthop);
+ /* no resolution attempt */
+ return nexthop->next;
+}
+
/* Return the next nexthop in the tree that is resolved and active */
struct nexthop *nexthop_next_active_resolved(const struct nexthop *nexthop)
{
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 27073b948d..02ea4d96f2 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -207,6 +207,8 @@ extern bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2);
extern bool nexthop_same_no_labels(const struct nexthop *nh1,
const struct nexthop *nh2);
extern int nexthop_cmp(const struct nexthop *nh1, const struct nexthop *nh2);
+extern int nexthop_cmp_no_weight(const struct nexthop *nh1,
+ const struct nexthop *nh2);
extern int nexthop_g_addr_cmp(enum nexthop_types_t type,
const union g_addr *addr1,
const union g_addr *addr2);
@@ -223,6 +225,8 @@ extern bool nexthop_labels_match(const struct nexthop *nh1,
extern const char *nexthop2str(const struct nexthop *nexthop,
char *str, int size);
extern struct nexthop *nexthop_next(const struct nexthop *nexthop);
+extern struct nexthop *nexthop_next_resolution(const struct nexthop *nexthop,
+ bool nexthop_resolution);
extern struct nexthop *
nexthop_next_active_resolved(const struct nexthop *nexthop);
extern unsigned int nexthop_level(const struct nexthop *nexthop);
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 3f408e0a71..cb1ebb5d09 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -70,10 +70,10 @@ static struct nexthop *nexthop_group_tail(const struct nexthop_group *nhg)
return nexthop;
}
-uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg)
+uint16_t nexthop_group_nexthop_num(const struct nexthop_group *nhg)
{
struct nexthop *nhop;
- uint8_t num = 0;
+ uint16_t num = 0;
for (ALL_NEXTHOPS_PTR(nhg, nhop))
num++;
@@ -81,11 +81,10 @@ uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg)
return num;
}
-static uint8_t
-nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg)
+static uint16_t nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg)
{
struct nexthop *nhop;
- uint8_t num = 0;
+ uint16_t num = 0;
for (nhop = nhg->nexthop; nhop; nhop = nhop->next)
num++;
@@ -93,10 +92,10 @@ nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg)
return num;
}
-uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
+uint16_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
{
struct nexthop *nhop;
- uint8_t num = 0;
+ uint16_t num = 0;
for (ALL_NEXTHOPS_PTR(nhg, nhop)) {
if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE))
@@ -184,11 +183,9 @@ static struct nexthop *nhg_nh_find(const struct nexthop_group *nhg,
return NULL;
}
-static bool
-nexthop_group_equal_common(const struct nexthop_group *nhg1,
- const struct nexthop_group *nhg2,
- uint8_t (*nexthop_group_nexthop_num_func)(
- const struct nexthop_group *nhg))
+static bool nexthop_group_equal_common(
+ const struct nexthop_group *nhg1, const struct nexthop_group *nhg2,
+ uint16_t (*nexthop_group_nexthop_num_func)(const struct nexthop_group *nhg))
{
if (nhg1 && !nhg2)
return false;
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 822a35439c..9103299418 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -149,9 +149,8 @@ extern void nexthop_group_json_nexthop(json_object *j,
const struct nexthop *nh);
/* Return the number of nexthops in this nhg */
-extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg);
-extern uint8_t
-nexthop_group_active_nexthop_num(const struct nexthop_group *nhg);
+extern uint16_t nexthop_group_nexthop_num(const struct nexthop_group *nhg);
+extern uint16_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg);
extern bool nexthop_group_has_label(const struct nexthop_group *nhg);
diff --git a/lib/northbound.c b/lib/northbound.c
index 0bc79d0277..a385cc9ece 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -178,7 +178,7 @@ struct nb_node *nb_node_find(const char *path)
struct nb_node **nb_nodes_find(const char *xpath)
{
- struct lysc_node **snodes = NULL;
+ const struct lysc_node **snodes = NULL;
struct nb_node **nb_nodes = NULL;
bool simple;
LY_ERR err;
@@ -816,8 +816,9 @@ int nb_candidate_edit(struct nb_config *candidate, const struct nb_node *nb_node
static int nb_candidate_edit_tree_add(struct nb_config *candidate,
enum nb_operation operation,
LYD_FORMAT format, const char *xpath,
- const char *data, char *xpath_created,
- char *errmsg, size_t errmsg_len)
+ const char *data, bool *created,
+ char *xpath_created, char *errmsg,
+ size_t errmsg_len)
{
struct lyd_node *tree = NULL;
struct lyd_node *parent = NULL;
@@ -897,10 +898,18 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate,
}
/* check if the node already exists in candidate */
- if (operation == NB_OP_CREATE_EXCL || operation == NB_OP_REPLACE) {
+ if (operation == NB_OP_CREATE || operation == NB_OP_MODIFY)
+ existing = yang_dnode_get(candidate->dnode, xpath_created);
+ else if (operation == NB_OP_CREATE_EXCL || operation == NB_OP_REPLACE) {
existing = yang_dnode_get(candidate->dnode, xpath_created);
/* if the existing node is implicit default, ignore */
+ /* Q: Is this correct for CREATE_EXCL which is supposed to error
+ * if the resouurce already exists? This is used by RESTCONF
+ * when processing the POST command, for example. RFC8040
+ * doesn't say POST fails if resource exists "unless it was a
+ * default".
+ */
if (existing && (existing->flags & LYD_DEFAULT))
existing = NULL;
@@ -908,7 +917,7 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate,
if (operation == NB_OP_CREATE_EXCL) {
snprintf(errmsg, errmsg_len,
"Data already exists");
- ret = NB_ERR;
+ ret = NB_ERR_EXISTS;
goto done;
}
@@ -930,7 +939,7 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate,
LYD_MERGE_DESTRUCT | LYD_MERGE_WITH_FLAGS);
if (err) {
/* if replace failed, restore the original node */
- if (existing) {
+ if (existing && operation == NB_OP_REPLACE) {
if (root) {
/* Restoring the whole config. */
candidate->dnode = existing;
@@ -954,6 +963,8 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate,
ret = NB_ERR;
goto done;
} else {
+ if (!existing)
+ *created = true;
/*
* Free existing node after replace.
* We're using `lyd_free_siblings` here to free the whole
@@ -961,7 +972,7 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate,
* siblings if it wasn't root, because the existing node
* was unlinked from the tree.
*/
- if (existing)
+ if (existing && operation == NB_OP_REPLACE)
lyd_free_siblings(existing);
tree = NULL; /* LYD_MERGE_DESTRUCT deleted the tree */
@@ -995,7 +1006,7 @@ static int nb_candidate_edit_tree_del(struct nb_config *candidate,
if (!dnode || (dnode->flags & LYD_DEFAULT)) {
if (operation == NB_OP_DELETE) {
snprintf(errmsg, errmsg_len, "Data missing");
- return NB_ERR;
+ return NB_ERR_NOT_FOUND;
} else
return NB_OK;
}
@@ -1011,7 +1022,7 @@ static int nb_candidate_edit_tree_del(struct nb_config *candidate,
int nb_candidate_edit_tree(struct nb_config *candidate,
enum nb_operation operation, LYD_FORMAT format,
- const char *xpath, const char *data,
+ const char *xpath, const char *data, bool *created,
char *xpath_created, char *errmsg, size_t errmsg_len)
{
int ret = NB_ERR;
@@ -1022,8 +1033,9 @@ int nb_candidate_edit_tree(struct nb_config *candidate,
case NB_OP_MODIFY:
case NB_OP_REPLACE:
ret = nb_candidate_edit_tree_add(candidate, operation, format,
- xpath, data, xpath_created,
- errmsg, errmsg_len);
+ xpath, data, created,
+ xpath_created, errmsg,
+ errmsg_len);
break;
case NB_OP_DESTROY:
case NB_OP_DELETE:
@@ -2605,6 +2617,8 @@ const char *nb_err_name(enum nb_error error)
return "no changes";
case NB_ERR_NOT_FOUND:
return "element not found";
+ case NB_ERR_EXISTS:
+ return "element already exists";
case NB_ERR_LOCKED:
return "resource is locked";
case NB_ERR_VALIDATION:
@@ -2687,7 +2701,7 @@ void nb_validate_callbacks(void)
void nb_init(struct event_loop *tm,
const struct frr_yang_module_info *const modules[],
- size_t nmodules, bool db_enabled)
+ size_t nmodules, bool db_enabled, bool load_library)
{
struct yang_module *loaded[nmodules], **loadedp = loaded;
@@ -2703,7 +2717,7 @@ void nb_init(struct event_loop *tm,
nb_db_enabled = db_enabled;
- yang_init(true, explicit_compile);
+ yang_init(true, explicit_compile, load_library);
/* Load YANG modules and their corresponding northbound callbacks. */
for (size_t i = 0; i < nmodules; i++) {
diff --git a/lib/northbound.h b/lib/northbound.h
index 34d17a587c..97a1d31e57 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -678,6 +678,7 @@ enum nb_error {
NB_ERR,
NB_ERR_NO_CHANGES,
NB_ERR_NOT_FOUND,
+ NB_ERR_EXISTS,
NB_ERR_LOCKED,
NB_ERR_VALIDATION,
NB_ERR_RESOURCE,
@@ -799,8 +800,6 @@ DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments),
(xpath, arguments));
DECLARE_HOOK(nb_notification_tree_send,
(const char *xpath, const struct lyd_node *tree), (xpath, tree));
-DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty));
-DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set));
/* Northbound debugging records */
extern struct debug nb_dbg_cbs_config;
@@ -1017,6 +1016,9 @@ extern int nb_candidate_edit(struct nb_config *candidate,
* data
* New data tree for the node.
*
+ * created
+ * OUT param set accordingly if a node was created or just updated
+ *
* xpath_created
* XPath of the created node if operation is "create".
*
@@ -1031,9 +1033,9 @@ extern int nb_candidate_edit(struct nb_config *candidate,
* - NB_ERR for other errors.
*/
extern int nb_candidate_edit_tree(struct nb_config *candidate,
- enum nb_operation operation,
- LYD_FORMAT format, const char *xpath,
- const char *data, char *xpath_created,
+ enum nb_operation operation, LYD_FORMAT format,
+ const char *xpath, const char *data,
+ bool *created, char *xpath_created,
char *errmsg, size_t errmsg_len);
/*
@@ -1701,10 +1703,12 @@ void nb_validate_callbacks(void);
*
* db_enabled
* Set this to record the transactions in the transaction log.
+ *
+ * load_library
+ * Set this to have libyang to load/implement the ietf-yang-library.
*/
-extern void nb_init(struct event_loop *tm,
- const struct frr_yang_module_info *const modules[],
- size_t nmodules, bool db_enabled);
+extern void nb_init(struct event_loop *tm, const struct frr_yang_module_info *const modules[],
+ size_t nmodules, bool db_enabled, bool load_library);
/*
* Finish the northbound layer gracefully. Should be called only when the daemon
@@ -1714,6 +1718,7 @@ extern void nb_terminate(void);
extern void nb_oper_init(struct event_loop *loop);
extern void nb_oper_terminate(void);
+extern bool nb_oper_is_yang_lib_query(const char *xpath);
#ifdef __cplusplus
}
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 4f962cda5c..f9794bee3c 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -22,13 +22,19 @@
#include "northbound_db.h"
#include "lib/northbound_cli_clippy.c"
-struct debug nb_dbg_cbs_config = {0, "Northbound callbacks: configuration"};
-struct debug nb_dbg_cbs_state = {0, "Northbound callbacks: state"};
-struct debug nb_dbg_cbs_rpc = {0, "Northbound callbacks: RPCs"};
-struct debug nb_dbg_cbs_notify = {0, "Northbound callbacks: notifications"};
-struct debug nb_dbg_notif = {0, "Northbound notifications"};
-struct debug nb_dbg_events = {0, "Northbound events"};
-struct debug nb_dbg_libyang = {0, "libyang debugging"};
+struct debug nb_dbg_cbs_config = { 0, "debug northbound callbacks configuration",
+ "Northbound callbacks: configuration" };
+struct debug nb_dbg_cbs_state = { 0, "debug northbound callbacks state",
+ "Northbound callbacks: state" };
+struct debug nb_dbg_cbs_rpc = { 0, "debug northbound callbacks rpc",
+ "Northbound callbacks: RPCs" };
+struct debug nb_dbg_cbs_notify = { 0, "debug northbound callbacks notify",
+ "Northbound callbacks: notifications" };
+struct debug nb_dbg_notif = { 0, "debug northbound notifications",
+ "Northbound notifications" };
+struct debug nb_dbg_events = { 0, "debug northbound events",
+ "Northbound events" };
+struct debug nb_dbg_libyang = { 0, "debug northbound libyang", "libyang" };
struct nb_config *vty_shared_candidate_config;
static struct event_loop *master;
@@ -1380,7 +1386,7 @@ static int nb_cli_show_transactions(struct vty *vty)
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
} else
vty_out(vty, "No configuration transactions to display.\n\n");
@@ -1661,7 +1667,7 @@ DEFPY (show_yang_module,
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
} else
vty_out(vty, "No YANG modules to display.\n\n");
@@ -1771,7 +1777,7 @@ DEFPY (show_yang_module_translator,
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
} else
vty_out(vty, "No YANG module translators to display.\n\n");
@@ -1842,37 +1848,6 @@ DEFPY (rollback_config,
}
/* Debug CLI commands. */
-static struct debug *nb_debugs[] = {
- &nb_dbg_cbs_config, &nb_dbg_cbs_state, &nb_dbg_cbs_rpc,
- &nb_dbg_cbs_notify, &nb_dbg_notif, &nb_dbg_events,
- &nb_dbg_libyang,
-};
-
-static const char *const nb_debugs_conflines[] = {
- "debug northbound callbacks configuration",
- "debug northbound callbacks state",
- "debug northbound callbacks rpc",
- "debug northbound callbacks notify",
- "debug northbound notifications",
- "debug northbound events",
- "debug northbound libyang",
-};
-
-DEFINE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set));
-
-static void nb_debug_set_all(uint32_t flags, bool set)
-{
- for (unsigned int i = 0; i < array_size(nb_debugs); i++) {
- DEBUG_FLAGS_SET(nb_debugs[i], flags, set);
-
- /* If all modes have been turned off, don't preserve options. */
- if (!DEBUG_MODE_CHECK(nb_debugs[i], DEBUG_MODE_ALL))
- DEBUG_CLEAR(nb_debugs[i]);
- }
-
- hook_call(nb_client_debug_set_all, flags, set);
-}
-
DEFPY (debug_nb,
debug_nb_cmd,
"[no] debug northbound\
@@ -1895,8 +1870,13 @@ DEFPY (debug_nb,
"libyang debugging\n")
{
uint32_t mode = DEBUG_NODE2MODE(vty->node);
+ bool all = false;
+
+ /* no specific debug --> act on all of them */
+ if (strmatch(argv[argc - 1]->text, "northbound"))
+ all = true;
- if (cbs) {
+ if (cbs || all) {
bool none = (!cbs_cfg && !cbs_state && !cbs_rpc && !cbs_notify);
if (none || cbs_cfg)
@@ -1908,45 +1888,18 @@ DEFPY (debug_nb,
if (none || cbs_notify)
DEBUG_MODE_SET(&nb_dbg_cbs_notify, mode, !no);
}
- if (notifications)
+ if (notifications || all)
DEBUG_MODE_SET(&nb_dbg_notif, mode, !no);
- if (events)
+ if (events || all)
DEBUG_MODE_SET(&nb_dbg_events, mode, !no);
- if (libyang) {
+ if (libyang || all) {
DEBUG_MODE_SET(&nb_dbg_libyang, mode, !no);
yang_debugging_set(!no);
}
- /* no specific debug --> act on all of them */
- if (strmatch(argv[argc - 1]->text, "northbound")) {
- nb_debug_set_all(mode, !no);
- yang_debugging_set(!no);
- }
-
return CMD_SUCCESS;
}
-DEFINE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty));
-
-static int nb_debug_config_write(struct vty *vty)
-{
- for (unsigned int i = 0; i < array_size(nb_debugs); i++)
- if (DEBUG_MODE_CHECK(nb_debugs[i], DEBUG_MODE_CONF))
- vty_out(vty, "%s\n", nb_debugs_conflines[i]);
-
- hook_call(nb_client_debug_config_write, vty);
-
- return 1;
-}
-
-static struct debug_callbacks nb_dbg_cbs = {.debug_set_all = nb_debug_set_all};
-static struct cmd_node nb_debug_node = {
- .name = "northbound debug",
- .node = NORTHBOUND_DEBUG_NODE,
- .prompt = "",
- .config_write = nb_debug_config_write,
-};
-
void nb_cli_install_default(int node)
{
_install_element(node, &show_config_candidate_section_cmd);
@@ -2007,9 +1960,14 @@ void nb_cli_init(struct event_loop *tm)
/* Initialize the shared candidate configuration. */
vty_shared_candidate_config = nb_config_new(NULL);
- debug_init(&nb_dbg_cbs);
+ debug_install(&nb_dbg_cbs_config);
+ debug_install(&nb_dbg_cbs_state);
+ debug_install(&nb_dbg_cbs_rpc);
+ debug_install(&nb_dbg_cbs_notify);
+ debug_install(&nb_dbg_notif);
+ debug_install(&nb_dbg_events);
+ debug_install(&nb_dbg_libyang);
- install_node(&nb_debug_node);
install_element(ENABLE_NODE, &debug_nb_cmd);
install_element(CONFIG_NODE, &debug_nb_cmd);
diff --git a/lib/northbound_oper.c b/lib/northbound_oper.c
index 5f38c970c7..a3ff360780 100644
--- a/lib/northbound_oper.c
+++ b/lib/northbound_oper.c
@@ -751,8 +751,8 @@ static const struct lysc_node *nb_op_sib_next(struct nb_op_yield_state *ys,
/*
* If the node info stack is shorter than the schema path then we are
- * doign specific query still on the node from the schema path (should
- * match) so just return NULL (i.e., don't process siblings)
+ * working our way down the specific query path so just return NULL
+ * (i.e., don't process siblings)
*/
if (darr_len(ys->schema_path) > darr_len(ys->node_infos))
return NULL;
@@ -760,21 +760,21 @@ static const struct lysc_node *nb_op_sib_next(struct nb_op_yield_state *ys,
* If sib is on top of the node info stack then
* 1) it's a container node -or-
* 2) it's a list node that we were walking and we've reach the last entry
- * 3) if sib is a list and the list was empty we never would have
+ *
+ * If sib is a list and the list was empty we never would have
* pushed sib on the stack so the top of the stack is the parent
*
* If the query string included this node then we do not process any
* siblings as we are not walking all the parent's children just this
* specified one give by the query string.
*/
- if (sib == darr_last(ys->node_infos)->schema &&
- darr_len(ys->schema_path) >= darr_len(ys->node_infos))
- return NULL;
- /* case (3) */
- else if (sib->nodetype == LYS_LIST &&
- parent == darr_last(ys->node_infos)->schema &&
- darr_len(ys->schema_path) > darr_len(ys->node_infos))
- return NULL;
+ if (darr_len(ys->schema_path) == darr_len(ys->node_infos)) {
+ struct nb_op_node_info *node_infos = darr_last(ys->node_infos);
+
+ assert(node_infos);
+ if (sib == node_infos->schema)
+ return NULL;
+ }
sib = __sib_next(yn, sib->next);
if (sib)
@@ -801,6 +801,7 @@ static const struct lysc_node *nb_op_sib_first(struct nb_op_yield_state *ys,
{
const struct lysc_node *sib = lysc_node_child(parent);
const struct lysc_node *first_sib;
+ struct nb_op_node_info *last = darr_last(ys->node_infos);
/*
* NOTE: when we want to handle root level walks we will need to use
@@ -817,10 +818,9 @@ static const struct lysc_node *nb_op_sib_first(struct nb_op_yield_state *ys,
* base of the user query, return the next schema node from the query
* string (schema_path).
*/
- if (darr_last(ys->node_infos) != NULL &&
- !CHECK_FLAG(darr_last(ys->node_infos)->schema->nodetype,
- LYS_CASE | LYS_CHOICE))
- assert(darr_last(ys->node_infos)->schema == parent);
+ if (last != NULL &&
+ !CHECK_FLAG(last->schema->nodetype, LYS_CASE | LYS_CHOICE))
+ assert(last->schema == parent);
if (darr_lasti(ys->node_infos) < ys->query_base_level)
return ys->schema_path[darr_lasti(ys->node_infos) + 1];
@@ -908,9 +908,10 @@ static enum nb_error __walk(struct nb_op_yield_state *ys, bool is_resume)
* Otherwise get the first child of the container we are walking,
* starting with non-yielding children.
*/
- if (is_resume)
+ if (is_resume) {
+ assert(darr_last(ys->node_infos) != NULL);
sib = darr_last(ys->node_infos)->schema;
- else {
+ } else {
/*
* Start with non-yielding children first.
*
@@ -1477,7 +1478,8 @@ static void nb_op_walk_continue(struct event *thread)
goto finish;
/* otherwise we are at a resumable node */
- assert(darr_last(ys->node_infos)->has_lookup_next);
+ assert(darr_last(ys->node_infos) &&
+ darr_last(ys->node_infos)->has_lookup_next);
ret = __walk(ys, true);
if (ret == NB_YIELD) {
@@ -1739,6 +1741,16 @@ static enum nb_error nb_op_walk_start(struct nb_op_yield_state *ys)
return __walk(ys, false);
}
+bool nb_oper_is_yang_lib_query(const char *xpath)
+{
+ const char *libstr = "/ietf-yang-library:";
+ const unsigned long liblen = strlen(libstr);
+
+ if (strncmp(libstr, xpath, liblen))
+ return false;
+
+ return strlen(xpath) > liblen;
+}
void *nb_oper_walk(const char *xpath, struct yang_translator *translator,
uint32_t flags, bool should_batch, nb_oper_data_cb cb,
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 0ec7610a9a..1f4d036cc2 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -19,7 +19,9 @@
#include <sysrepo/values.h>
#include <sysrepo/xpath.h>
-static struct debug nb_dbg_client_sysrepo = {0, "Northbound client: Sysrepo"};
+static struct debug nb_dbg_client_sysrepo = { 0,
+ "debug northbound client sysrepo",
+ "Northbound client: Sysrepo" };
static struct event_loop *master;
static sr_session_ctx_t *session;
@@ -553,29 +555,9 @@ DEFUN (debug_nb_sr,
return CMD_SUCCESS;
}
-static int frr_sr_debug_config_write(struct vty *vty)
-{
- if (DEBUG_MODE_CHECK(&nb_dbg_client_sysrepo, DEBUG_MODE_CONF))
- vty_out(vty, "debug northbound client sysrepo\n");
-
- return 0;
-}
-
-static int frr_sr_debug_set_all(uint32_t flags, bool set)
-{
- DEBUG_FLAGS_SET(&nb_dbg_client_sysrepo, flags, set);
-
- /* If all modes have been turned off, don't preserve options. */
- if (!DEBUG_MODE_CHECK(&nb_dbg_client_sysrepo, DEBUG_MODE_ALL))
- DEBUG_CLEAR(&nb_dbg_client_sysrepo);
-
- return 0;
-}
-
static void frr_sr_cli_init(void)
{
- hook_register(nb_client_debug_config_write, frr_sr_debug_config_write);
- hook_register(nb_client_debug_set_all, frr_sr_debug_set_all);
+ debug_install(&nb_dbg_client_sysrepo);
install_element(ENABLE_NODE, &debug_nb_sr_cmd);
install_element(CONFIG_NODE, &debug_nb_sr_cmd);
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 8e2e497e09..f22d588080 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -937,7 +937,7 @@ DEFPY_YANG(no_set_min_metric, no_set_min_metric_cmd,
"no set min-metric [(0-4294967295)]",
NO_STR SET_STR
"Minimum metric value for destination routing protocol\n"
- "Minumum metric value\n")
+ "Minimum metric value\n")
{
const char *xpath =
"./set-action[action='frr-route-map:set-min-metric']";
diff --git a/lib/srv6.h b/lib/srv6.h
index 03ada7fcfc..9a041e3d85 100644
--- a/lib/srv6.h
+++ b/lib/srv6.h
@@ -106,6 +106,10 @@ struct seg6local_context {
struct in6_addr nh6;
uint32_t table;
struct seg6local_flavors_info flv;
+ uint8_t block_len;
+ uint8_t node_len;
+ uint8_t function_len;
+ uint8_t argument_len;
};
struct srv6_locator {
@@ -335,24 +339,23 @@ static inline const char *srv6_sid_ctx2str(char *str, size_t size,
break;
case ZEBRA_SEG6_LOCAL_ACTION_END:
- len += snprintf(str + len, size - len, " USP");
+ snprintf(str + len, size - len, " USP");
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_X:
case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
- len += snprintfrr(str + len, size - len, " nh6 %pI6", &ctx->nh6);
+ snprintfrr(str + len, size - len, " nh6 %pI6", &ctx->nh6);
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
- len += snprintfrr(str + len, size - len, " nh4 %pI4", &ctx->nh4);
+ snprintfrr(str + len, size - len, " nh4 %pI4", &ctx->nh4);
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_T:
case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
- len += snprintf(str + len, size - len, " vrf_id %u",
- ctx->vrf_id);
+ snprintf(str + len, size - len, " vrf_id %u", ctx->vrf_id);
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
@@ -364,7 +367,7 @@ static inline const char *srv6_sid_ctx2str(char *str, size_t size,
case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
case ZEBRA_SEG6_LOCAL_ACTION_END_BPF:
default:
- len += snprintf(str + len, size - len, " unknown(%s)", __func__);
+ snprintf(str + len, size - len, " unknown(%s)", __func__);
}
return str;
diff --git a/lib/termtable.c b/lib/termtable.c
index 88cc25bf68..ce19701389 100644
--- a/lib/termtable.c
+++ b/lib/termtable.c
@@ -363,7 +363,7 @@ char *ttable_dump(struct ttable *tt, const char *newline)
memcpy(&right[0], newline, nl_len);
/* allocate print buffer */
- buf = XCALLOC(MTYPE_TMP, width * (nlines + 1) + 1);
+ buf = XCALLOC(MTYPE_TMP_TTABLE, width * (nlines + 1) + 1);
pos = 0;
if (tt->style.border.top_on) {
diff --git a/lib/termtable.h b/lib/termtable.h
index 0782c82abd..d284c4f376 100644
--- a/lib/termtable.h
+++ b/lib/termtable.h
@@ -270,7 +270,7 @@ void ttable_rowseps(struct ttable *tt, unsigned int row,
*
* Caller must free this string after use with
*
- * XFREE (MTYPE_TMP, str);
+ * XFREE (MTYPE_TMP_TTABLE, str);
*
* @param tt the table to dump
* @param newline the desired newline sequence to use, null terminated.
diff --git a/lib/vty.c b/lib/vty.c
index d0bbf0e61a..256a3bb3f5 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -345,8 +345,17 @@ int vty_out(struct vty *vty, const char *format, ...)
case VTY_SHELL_SERV:
case VTY_FILE:
default:
+ vty->vty_buf_size_accumulated += strlen(filtered);
/* print without crlf replacement */
buffer_put(vty->obuf, (uint8_t *)filtered, strlen(filtered));
+ /* For every chunk of memory, we invoke vtysh_flush where we
+ * put the data of collective vty->obuf Linked List items on the
+ * socket and free the vty->obuf data.
+ */
+ if (vty->vty_buf_size_accumulated >= VTY_MAX_INTERMEDIATE_FLUSH) {
+ vty->vty_buf_size_accumulated = 0;
+ vtysh_flush(vty);
+ }
break;
}
@@ -2118,6 +2127,8 @@ static void vtysh_accept(struct event *thread)
int client_len;
struct sockaddr_un client;
struct vty *vty;
+ int ret = 0;
+ uint32_t sndbufsize = VTY_SEND_BUF_MAX;
vty_event_serv(VTYSH_SERV, vtyserv);
@@ -2141,6 +2152,20 @@ static void vtysh_accept(struct event *thread)
close(sock);
return;
}
+
+ /*
+ * Increasing the SEND socket buffer size so that the socket can hold
+ * before sending it to VTY shell.
+ */
+ ret = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndbufsize,
+ sizeof(sndbufsize));
+ if (ret < 0) {
+ flog_err(EC_LIB_SOCKET,
+ "Cannot set socket %d send buffer size, %s", sock,
+ safe_strerror(errno));
+ close(sock);
+ return;
+ }
set_cloexec(sock);
#ifdef VTYSH_DEBUG
@@ -2227,6 +2252,7 @@ static int vtysh_flush(struct vty *vty)
vty_close(vty);
return -1;
case BUFFER_EMPTY:
+ vty->vty_buf_size_accumulated = 0;
break;
}
return 0;
@@ -3903,7 +3929,7 @@ static int vty_mgmt_error_notified(struct mgmt_fe_client *client,
const char *cname = mgmt_fe_client_name(client);
if (!vty->mgmt_req_pending_cmd) {
- debug_fe_client("Erorr with no pending command: %d returned for client %s 0x%" PRIx64
+ debug_fe_client("Error with no pending command: %d returned for client %s 0x%" PRIx64
" session-id %" PRIu64 " req-id %" PRIu64
"error-str %s",
error, cname, client_id, session_id, req_id,
@@ -3914,7 +3940,7 @@ static int vty_mgmt_error_notified(struct mgmt_fe_client *client,
return CMD_WARNING;
}
- debug_fe_client("Erorr %d returned for client %s 0x%" PRIx64
+ debug_fe_client("Error %d returned for client %s 0x%" PRIx64
" session-id %" PRIu64 " req-id %" PRIu64 "error-str %s",
error, cname, client_id, session_id, req_id, errstr);
diff --git a/lib/vty.h b/lib/vty.h
index c336a816cc..e511e8e79a 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -236,6 +236,7 @@ struct vty {
uintptr_t mgmt_req_pending_data;
bool mgmt_locked_candidate_ds;
bool mgmt_locked_running_ds;
+ uint64_t vty_buf_size_accumulated;
};
static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
@@ -338,6 +339,12 @@ struct vty_arg {
/* Vty read buffer size. */
#define VTY_READ_BUFSIZ 512
+/* Vty max send buffer size */
+#define VTY_SEND_BUF_MAX 16777216
+
+/* Vty flush intermediate size */
+#define VTY_MAX_INTERMEDIATE_FLUSH 131072
+
/* Directory separator. */
#ifndef DIRECTORY_SEP
#define DIRECTORY_SEP '/'
diff --git a/lib/yang.c b/lib/yang.c
index 6a8e5223a0..b847b8b77b 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -286,7 +286,7 @@ void yang_snode_get_path(const struct lysc_node *snode,
}
LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath,
- struct lysc_node ***snodes, bool *simple)
+ const struct lysc_node ***snodes, bool *simple)
{
struct lysc_node *snode;
struct ly_set *set;
@@ -976,7 +976,7 @@ void yang_debugging_set(bool enable)
}
}
-struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile)
+struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile, bool load_library)
{
struct ly_ctx *ctx = NULL;
const char *yang_models_path = YANG_MODELS_PATH;
@@ -994,7 +994,9 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile)
YANG_MODELS_PATH);
}
- options = LY_CTX_NO_YANGLIBRARY | LY_CTX_DISABLE_SEARCHDIR_CWD;
+ options = LY_CTX_DISABLE_SEARCHDIR_CWD;
+ if (!load_library)
+ options |= LY_CTX_NO_YANGLIBRARY;
if (explicit_compile)
options |= LY_CTX_EXPLICIT_COMPILE;
err = ly_ctx_new(yang_models_path, options, &ctx);
@@ -1007,7 +1009,7 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile)
return ctx;
}
-void yang_init(bool embedded_modules, bool defer_compile)
+void yang_init(bool embedded_modules, bool defer_compile, bool load_library)
{
/* Initialize libyang global parameters that affect all containers. */
ly_set_log_clb(ly_zlog_cb
@@ -1019,7 +1021,7 @@ void yang_init(bool embedded_modules, bool defer_compile)
ly_log_options(LY_LOLOG | LY_LOSTORE);
/* Initialize libyang container for native models. */
- ly_native_ctx = yang_ctx_new_setup(embedded_modules, defer_compile);
+ ly_native_ctx = yang_ctx_new_setup(embedded_modules, defer_compile, load_library);
if (!ly_native_ctx) {
flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
exit(1);
@@ -1398,8 +1400,10 @@ LY_ERR yang_lyd_trim_xpath(struct lyd_node **root, const char *xpath)
}
}
darr_foreach_i (remove, i) {
- if (remove[i] == *root)
+ if (remove[i] == *root) {
+ assert(*root);
*root = (*root)->next;
+ }
lyd_free_tree(remove[i]);
}
darr_free(remove);
diff --git a/lib/yang.h b/lib/yang.h
index 57131f478b..52857ecf00 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -607,9 +607,11 @@ extern struct yang_data *yang_data_list_find(const struct list *list,
* explicit_compile
* True if the caller will later call ly_ctx_compile to compile all loaded
* modules at once.
+ * load_library
+ * Set this to have libyang to load/implement the ietf-yang-library.
*/
-extern struct ly_ctx *yang_ctx_new_setup(bool embedded_modules,
- bool explicit_compile);
+extern struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile,
+ bool load_library);
/*
* Enable or disable libyang verbose debugging.
@@ -727,8 +729,10 @@ extern const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf,
* Specify whether libyang should attempt to look for embedded YANG modules.
* defer_compile
* Hold off on compiling modules until yang_init_loading_complete is called.
+ * load_library
+ * Set this to have libyang to load/implement the ietf-yang-library.
*/
-extern void yang_init(bool embedded_modules, bool defer_compile);
+extern void yang_init(bool embedded_modules, bool defer_compile, bool load_library);
/*
* Should be called after yang_init and all yang_module_load()s have been done,
@@ -827,7 +831,8 @@ extern int yang_xpath_pop_node(char *xpath);
* Return: a libyang error or LY_SUCCESS.
*/
extern LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath,
- struct lysc_node ***snodes, bool *simple);
+ const struct lysc_node ***snodes,
+ bool *simple);
/*
* Libyang future functions
diff --git a/lib/yang_translator.c b/lib/yang_translator.c
index 005f6422f3..b7599e0a71 100644
--- a/lib/yang_translator.c
+++ b/lib/yang_translator.c
@@ -166,7 +166,7 @@ struct yang_translator *yang_translator_load(const char *path)
RB_INSERT(yang_translators, &yang_translators, translator);
/* Initialize the translator libyang context. */
- translator->ly_ctx = yang_ctx_new_setup(false, false);
+ translator->ly_ctx = yang_ctx_new_setup(false, false, false);
if (!translator->ly_ctx) {
flog_warn(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
goto error;
@@ -512,7 +512,7 @@ static unsigned int yang_module_nodes_count(const struct lys_module *module)
void yang_translator_init(void)
{
- ly_translator_ctx = yang_ctx_new_setup(true, false);
+ ly_translator_ctx = yang_ctx_new_setup(true, false, false);
if (!ly_translator_ctx) {
flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
exit(1);
diff --git a/lib/zclient.h b/lib/zclient.h
index 2877b347d8..91c0c9ed6d 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -124,7 +124,6 @@ typedef enum {
ZEBRA_BFD_DEST_REPLAY,
ZEBRA_REDISTRIBUTE_ROUTE_ADD,
ZEBRA_REDISTRIBUTE_ROUTE_DEL,
- ZEBRA_VRF_UNREGISTER,
ZEBRA_VRF_ADD,
ZEBRA_VRF_DELETE,
ZEBRA_VRF_LABEL,
diff --git a/mgmtd/mgmt.c b/mgmtd/mgmt.c
index 8d41643065..cfadad4829 100644
--- a/mgmtd/mgmt.c
+++ b/mgmtd/mgmt.c
@@ -15,10 +15,14 @@
#include "mgmtd/mgmt_history.h"
#include "mgmtd/mgmt_memory.h"
-struct debug mgmt_debug_be = {.desc = "Management backend adapater"};
-struct debug mgmt_debug_ds = {.desc = "Management datastore"};
-struct debug mgmt_debug_fe = {.desc = "Management frontend adapater"};
-struct debug mgmt_debug_txn = {.desc = "Management transaction"};
+struct debug mgmt_debug_be = { .conf = "debug mgmt backend",
+ .desc = "Management backend adapter" };
+struct debug mgmt_debug_ds = { .conf = "debug mgmt datastore",
+ .desc = "Management datastore" };
+struct debug mgmt_debug_fe = { .conf = "debug mgmt frontend",
+ .desc = "Management frontend adapter" };
+struct debug mgmt_debug_txn = { .conf = "debug mgmt transaction",
+ .desc = "Management transaction" };
/* MGMTD process wide configuration. */
static struct mgmt_master mgmt_master;
@@ -39,6 +43,10 @@ void mgmt_master_init(struct event_loop *master, const int buffer_size)
void mgmt_init(void)
{
+ debug_install(&mgmt_debug_be);
+ debug_install(&mgmt_debug_ds);
+ debug_install(&mgmt_debug_fe);
+ debug_install(&mgmt_debug_txn);
/* Initialize datastores */
mgmt_ds_init(mm);
diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c
index c7f4fb9d84..93c9bcac44 100644
--- a/mgmtd/mgmt_be_adapter.c
+++ b/mgmtd/mgmt_be_adapter.c
@@ -249,6 +249,8 @@ static void mgmt_register_client_xpath(enum mgmt_be_client_id id,
{
struct mgmt_be_xpath_map **maps, *map;
+ maps = NULL;
+
switch (type) {
case MGMT_BE_XPATH_SUBSCR_TYPE_CFG:
maps = &be_cfg_xpath_map;
@@ -438,7 +440,7 @@ static int mgmt_be_send_subscr_reply(struct mgmt_be_client_adapter *adapter,
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY;
be_msg.subscr_reply = &reply;
- __dbg("Sending SUBSCR_REPLY client: %s sucess: %u", adapter->name,
+ __dbg("Sending SUBSCR_REPLY client: %s success: %u", adapter->name,
success);
return mgmt_be_adapter_send_msg(adapter, &be_msg);
diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c
index 5f53c928a4..32f28a5774 100644
--- a/mgmtd/mgmt_fe_adapter.c
+++ b/mgmtd/mgmt_fe_adapter.c
@@ -1164,7 +1164,9 @@ done:
}
static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session,
- uint64_t req_id, const char *xpath)
+ uint64_t req_id, bool changed,
+ bool created, const char *xpath,
+ const char *data)
{
struct mgmt_msg_edit_reply *msg;
int ret;
@@ -1173,14 +1175,19 @@ static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session,
MTYPE_MSG_NATIVE_EDIT_REPLY);
msg->refer_id = session->session_id;
msg->req_id = req_id;
+ msg->changed = changed;
+ msg->created = created;
msg->code = MGMT_MSG_CODE_EDIT_REPLY;
mgmt_msg_native_xpath_encode(msg, xpath);
+ if (data)
+ mgmt_msg_native_append(msg, data, strlen(data) + 1);
+
__dbg("Sending edit-reply from adapter %s to session-id %" PRIu64
- " req-id %" PRIu64 " len %u",
- session->adapter->name, session->session_id, req_id,
- mgmt_msg_native_get_msg_len(msg));
+ " req-id %" PRIu64 " changed %u created %u len %u",
+ session->adapter->name, session->session_id, req_id, changed,
+ created, mgmt_msg_native_get_msg_len(msg));
ret = fe_adapter_send_native_msg(session->adapter, msg,
mgmt_msg_native_get_msg_len(msg),
@@ -1282,8 +1289,7 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session,
void *__msg, size_t msg_len)
{
struct mgmt_msg_get_data *msg = __msg;
- struct lysc_node **snodes = NULL;
- char *xpath_resolved = NULL;
+ const struct lysc_node **snodes = NULL;
uint64_t req_id = msg->req_id;
Mgmtd__DatastoreId ds_id;
uint64_t clients;
@@ -1331,6 +1337,31 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session,
goto done;
}
+ /* Check for yang-library shortcut */
+ if (nb_oper_is_yang_lib_query(msg->xpath)) {
+ struct lyd_node *ylib = NULL;
+ LY_ERR err;
+
+ err = ly_ctx_get_yanglib_data(ly_native_ctx, &ylib, "%u",
+ ly_ctx_get_change_count(
+ ly_native_ctx));
+ if (err) {
+ fe_adapter_send_error(session, req_id, false, err,
+ "Error getting yang-library data, session-id: %" PRIu64
+ " error: %s",
+ session->session_id,
+ ly_last_errmsg());
+ } else {
+ yang_lyd_trim_xpath(&ylib, msg->xpath);
+ (void)fe_adapter_send_tree_data(session, req_id, false,
+ msg->result_type,
+ wd_options, ylib, 0);
+ }
+ if (ylib)
+ lyd_free_all(ylib);
+ goto done;
+ }
+
switch (msg->datastore) {
case MGMT_MSG_DATASTORE_CANDIDATE:
ds_id = MGMTD_DS_CANDIDATE;
@@ -1395,7 +1426,6 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session,
}
done:
darr_free(snodes);
- darr_free(xpath_resolved);
}
static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session,
@@ -1408,7 +1438,12 @@ static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session,
bool lock, commit;
int ret;
- if (msg->datastore != MGMT_MSG_DATASTORE_CANDIDATE) {
+ lock = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_LOCK);
+ commit = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_COMMIT);
+
+ if (lock && commit && msg->datastore == MGMT_MSG_DATASTORE_RUNNING)
+ ;
+ else if (msg->datastore != MGMT_MSG_DATASTORE_CANDIDATE) {
fe_adapter_send_error(session, msg->req_id, false, -EINVAL,
"Unsupported datastore");
return;
@@ -1429,9 +1464,6 @@ static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session,
rds_ctx = mgmt_ds_get_ctx_by_id(mm, rds_id);
assert(rds_ctx);
- lock = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_LOCK);
- commit = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_COMMIT);
-
if (lock) {
if (mgmt_fe_session_write_lock_ds(ds_id, ds_ctx, session)) {
fe_adapter_send_error(session, msg->req_id, false,
@@ -1518,7 +1550,6 @@ static void fe_adapter_handle_notify_select(struct mgmt_fe_session_ctx *session,
const char **selectors = NULL;
const char **new;
- /* An empty message clears the selectors */
if (msg_len >= sizeof(*msg)) {
selectors = mgmt_msg_native_strings_decode(msg, msg_len,
msg->selectors);
@@ -1531,7 +1562,7 @@ static void fe_adapter_handle_notify_select(struct mgmt_fe_session_ctx *session,
if (msg->replace) {
darr_free_free(session->notify_xpaths);
session->notify_xpaths = selectors;
- } else {
+ } else if (selectors) {
new = darr_append_nz(session->notify_xpaths,
darr_len(selectors));
memcpy(new, selectors, darr_len(selectors) * sizeof(*selectors));
@@ -1978,8 +2009,8 @@ int mgmt_fe_adapter_send_rpc_reply(uint64_t session_id, uint64_t txn_id,
int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id,
uint64_t req_id, bool unlock, bool commit,
- const char *xpath, int16_t error,
- const char *errstr)
+ bool created, const char *xpath,
+ int16_t error, const char *errstr)
{
struct mgmt_fe_session_ctx *session;
Mgmtd__DatastoreId ds_id, rds_id;
@@ -2010,11 +2041,12 @@ int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id,
}
}
- if (error)
+ if (error != 0 && error != -EALREADY)
ret = fe_adapter_send_error(session, req_id, false, error, "%s",
errstr);
else
- ret = fe_adapter_send_edit_reply(session, req_id, xpath);
+ ret = fe_adapter_send_edit_reply(session, req_id, created,
+ !error, xpath, errstr);
if (session->cfg_txn_id != MGMTD_TXN_ID_NONE && !commit)
mgmt_destroy_txn(&session->cfg_txn_id);
diff --git a/mgmtd/mgmt_fe_adapter.h b/mgmtd/mgmt_fe_adapter.h
index 61d6cfae13..4d94e7604f 100644
--- a/mgmtd/mgmt_fe_adapter.h
+++ b/mgmtd/mgmt_fe_adapter.h
@@ -193,14 +193,16 @@ extern int mgmt_fe_adapter_send_rpc_reply(uint64_t session_id, uint64_t txn_id,
* req_id: the req id for the edit message
* unlock: implicit-lock flag was set in the request
* commit: implicit-commit flag was set in the request
- * xpath: the xpath of the data node that was created
- * error: the error code, zero for successful request
+ * created: true if the node was just created
+ * xpath: the xpath of the data node that was created/updated
+ * error: >0 LY_ERR, < 0 -errno
* errstr: the error string, if error is non-zero
*/
extern int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id,
uint64_t req_id, bool unlock,
- bool commit, const char *xpath,
- int16_t error, const char *errstr);
+ bool commit, bool created,
+ const char *xpath, int16_t error,
+ const char *errstr);
/**
* Send an error back to the FE client using native messaging.
@@ -210,7 +212,7 @@ extern int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id,
* Args:
* txn_id: the txn_id this error pertains to.
* short_circuit_ok: True if OK to short-circuit the call.
- * error: An integer error value.
+ * error: >0 LY_ERR, < 0 -errno
* errfmt: An error format string (i.e., printfrr)
* ...: args for use by the `errfmt` format string.
*
diff --git a/mgmtd/mgmt_main.c b/mgmtd/mgmt_main.c
index e181d0da5e..1880d94415 100644
--- a/mgmtd/mgmt_main.c
+++ b/mgmtd/mgmt_main.c
@@ -214,7 +214,7 @@ FRR_DAEMON_INFO(mgmtd, MGMTD,
.n_yang_modules = array_size(mgmt_yang_modules),
/* avoid libfrr trying to read our config file for us */
- .flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG,
+ .flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG | FRR_LOAD_YANG_LIBRARY,
);
/* clang-format on */
diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c
index 0f0cccbbd4..ccfdd7539f 100644
--- a/mgmtd/mgmt_txn.c
+++ b/mgmtd/mgmt_txn.c
@@ -94,6 +94,7 @@ DECLARE_LIST(mgmt_txn_batches, struct mgmt_txn_be_cfg_batch, list_linkage);
struct mgmt_edit_req {
char xpath_created[XPATH_MAXLEN];
+ bool created;
bool unlock;
};
@@ -742,6 +743,8 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
.edit->unlock,
true,
txn->commit_cfg_req->req.commit_cfg
+ .edit->created,
+ txn->commit_cfg_req->req.commit_cfg
.edit->xpath_created,
success ? 0 : -1,
error_if_any) != 0) {
@@ -1335,7 +1338,8 @@ static int txn_get_tree_data_done(struct mgmt_txn_ctx *txn,
" req_id %" PRIu64 " to requested type %u",
txn->txn_id, req_id, get_tree->result_type);
- (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, ret,
+ (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false,
+ errno_from_nb_error(ret),
"Error converting results of GETTREE");
}
@@ -1351,7 +1355,7 @@ static int txn_rpc_done(struct mgmt_txn_ctx *txn, struct mgmt_txn_req *txn_req)
EVENT_OFF(txn->rpc_timeout);
if (rpc->errstr)
- mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, -1,
+ mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, -EINVAL,
rpc->errstr);
else if (mgmt_fe_adapter_send_rpc_reply(txn->session_id, txn->txn_id,
req_id, rpc->result_type,
@@ -1360,7 +1364,8 @@ static int txn_rpc_done(struct mgmt_txn_ctx *txn, struct mgmt_txn_req *txn_req)
" req_id %" PRIu64 " to requested type %u",
txn->txn_id, req_id, rpc->result_type);
- (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, -1,
+ (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false,
+ -EINVAL,
"Error converting results of RPC");
}
@@ -2564,8 +2569,8 @@ int mgmt_txn_send_edit(uint64_t txn_id, uint64_t req_id,
assert(nb_config);
ret = nb_candidate_edit_tree(nb_config, operation, request_type, xpath,
- data, edit->xpath_created, errstr,
- sizeof(errstr));
+ data, &edit->created, edit->xpath_created,
+ errstr, sizeof(errstr));
if (ret)
goto reply;
@@ -2579,8 +2584,9 @@ int mgmt_txn_send_edit(uint64_t txn_id, uint64_t req_id,
}
reply:
mgmt_fe_adapter_send_edit_reply(txn->session_id, txn->txn_id, req_id,
- unlock, commit, edit->xpath_created,
- ret ? -1 : 0, errstr);
+ unlock, commit, edit->created,
+ edit->xpath_created,
+ errno_from_nb_error(ret), errstr);
XFREE(MTYPE_MGMTD_TXN_REQ, edit);
@@ -2710,7 +2716,7 @@ int mgmt_txn_notify_error(struct mgmt_be_client_adapter *adapter,
case MGMTD_TXN_PROC_GETCFG:
case MGMTD_TXN_COMMITCFG_TIMEOUT:
default:
- assert(!"non-native req event in native erorr path");
+ assert(!"non-native req event in native error path");
return -1;
}
}
diff --git a/mgmtd/mgmt_txn.h b/mgmtd/mgmt_txn.h
index b6ca288675..37dadc0171 100644
--- a/mgmtd/mgmt_txn.h
+++ b/mgmtd/mgmt_txn.h
@@ -69,6 +69,34 @@ static inline const char *mgmt_txn_type2str(enum mgmt_txn_type type)
return "Unknown";
}
+
+static inline int16_t errno_from_nb_error(enum nb_error ret)
+{
+ switch (ret) {
+ case NB_OK:
+ return 0;
+ case NB_ERR_NO_CHANGES:
+ return -EALREADY;
+ case NB_ERR_NOT_FOUND:
+ return -ENOENT;
+ case NB_ERR_EXISTS:
+ return -EEXIST;
+ case NB_ERR_LOCKED:
+ return -EWOULDBLOCK;
+ case NB_ERR_VALIDATION:
+ return -EINVAL;
+ case NB_ERR_RESOURCE:
+ return -ENOMEM;
+ case NB_ERR:
+ case NB_ERR_INCONSISTENCY:
+ return -EINVAL;
+ case NB_YIELD:
+ default:
+ return -EINVAL;
+ }
+}
+
+
/* Initialise transaction module. */
extern int mgmt_txn_init(struct mgmt_master *cm, struct event_loop *tm);
diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c
index 8ccb463577..876f703560 100644
--- a/mgmtd/mgmt_vty.c
+++ b/mgmtd/mgmt_vty.c
@@ -557,52 +557,11 @@ DEFPY(mgmt_rollback,
return CMD_SUCCESS;
}
-int config_write_mgmt_debug(struct vty *vty);
-static struct cmd_node debug_node = {
- .name = "mgmt debug",
- .node = DEBUG_NODE,
- .prompt = "",
- .config_write = config_write_mgmt_debug,
-};
-
-static int write_mgmt_debug_helper(struct vty *vty, bool config)
-{
- uint32_t mode = config ? DEBUG_MODE_CONF : DEBUG_MODE_ALL;
- bool be = DEBUG_MODE_CHECK(&mgmt_debug_be, mode);
- bool ds = DEBUG_MODE_CHECK(&mgmt_debug_ds, mode);
- bool fe = DEBUG_MODE_CHECK(&mgmt_debug_fe, mode);
- bool txn = DEBUG_MODE_CHECK(&mgmt_debug_txn, mode);
-
- if (!(be || ds || fe || txn))
- return 0;
-
- vty_out(vty, "debug mgmt");
- if (be)
- vty_out(vty, " backend");
- if (ds)
- vty_out(vty, " datastore");
- if (fe)
- vty_out(vty, " frontend");
- if (txn)
- vty_out(vty, " transaction");
-
- vty_out(vty, "\n");
-
- return 0;
-}
-
-int config_write_mgmt_debug(struct vty *vty)
-{
- return write_mgmt_debug_helper(vty, true);
-}
-
DEFPY_NOSH(show_debugging_mgmt, show_debugging_mgmt_cmd,
"show debugging [mgmt]", SHOW_STR DEBUG_STR "MGMT Information\n")
{
vty_out(vty, "MGMT debugging status:\n");
- write_mgmt_debug_helper(vty, false);
-
cmd_show_lib_debugs(vty);
return CMD_SUCCESS;
@@ -696,7 +655,6 @@ void mgmt_vty_init(void)
event_add_event(mm->master, mgmt_config_read_in, NULL, 0,
&mgmt_daemon_info->read_in);
- install_node(&debug_node);
install_node(&mgmtd_node);
install_element(VIEW_NODE, &show_mgmt_be_adapter_cmd);
diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c
index 3495317d4c..d2c1a8c401 100644
--- a/nhrpd/nhrp_peer.c
+++ b/nhrpd/nhrp_peer.c
@@ -597,6 +597,12 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
nhrp_ext_complete(zb, ext);
}
break;
+ case NHRP_EXTENSION_AUTHENTICATION:
+ /* Extensions can be copied from original packet except
+ * authentication extension which must be regenerated
+ * hop by hop.
+ */
+ break;
default:
if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0)
goto err;
diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c
index fd9090bd6e..7adc4a6399 100644
--- a/nhrpd/nhrp_route.c
+++ b/nhrpd/nhrp_route.c
@@ -219,6 +219,10 @@ int nhrp_route_read(ZAPI_CALLBACK_ARGS)
if (api.type == ZEBRA_ROUTE_NHRP)
return 0;
+ /* ignore local routes */
+ if (api.type == ZEBRA_ROUTE_LOCAL)
+ return 0;
+
sockunion_family(&nexthop_addr) = AF_UNSPEC;
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
api_nh = &api.nexthops[0];
diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c
index 9b47d974c3..55d61a90b8 100644
--- a/nhrpd/nhrp_shortcut.c
+++ b/nhrpd/nhrp_shortcut.c
@@ -21,14 +21,16 @@ static struct route_table *shortcut_rib[AFI_MAX];
static void nhrp_shortcut_do_purge(struct event *t);
static void nhrp_shortcut_delete(struct nhrp_shortcut *s,
void *arg __attribute__((__unused__)));
-static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s);
+static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s,
+ bool retry);
+static void nhrp_shortcut_retry_resolution_req(struct event *t);
static void nhrp_shortcut_check_use(struct nhrp_shortcut *s)
{
if (s->expiring && s->cache && s->cache->used) {
debugf(NHRP_DEBUG_ROUTE, "Shortcut %pFX used and expiring",
s->p);
- nhrp_shortcut_send_resolution_req(s);
+ nhrp_shortcut_send_resolution_req(s, false);
}
}
@@ -37,7 +39,7 @@ static void nhrp_shortcut_do_expire(struct event *t)
struct nhrp_shortcut *s = EVENT_ARG(t);
event_add_timer(master, nhrp_shortcut_do_purge, s, s->holding_time / 3,
- &s->t_timer);
+ &s->t_shortcut_purge);
s->expiring = 1;
nhrp_shortcut_check_use(s);
}
@@ -124,12 +126,12 @@ static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s,
s->route_installed = 0;
}
- EVENT_OFF(s->t_timer);
+ EVENT_OFF(s->t_shortcut_purge);
if (holding_time) {
s->expiring = 0;
s->holding_time = holding_time;
event_add_timer(master, nhrp_shortcut_do_expire, s,
- 2 * holding_time / 3, &s->t_timer);
+ 2 * holding_time / 3, &s->t_shortcut_purge);
}
}
@@ -139,7 +141,8 @@ static void nhrp_shortcut_delete(struct nhrp_shortcut *s,
struct route_node *rn;
afi_t afi = family2afi(PREFIX_FAMILY(s->p));
- EVENT_OFF(s->t_timer);
+ EVENT_OFF(s->t_shortcut_purge);
+ EVENT_OFF(s->t_retry_resolution);
nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
debugf(NHRP_DEBUG_ROUTE, "Shortcut %pFX purged", s->p);
@@ -159,7 +162,8 @@ static void nhrp_shortcut_delete(struct nhrp_shortcut *s,
static void nhrp_shortcut_do_purge(struct event *t)
{
struct nhrp_shortcut *s = EVENT_ARG(t);
- s->t_timer = NULL;
+ s->t_shortcut_purge = NULL;
+ EVENT_OFF(s->t_retry_resolution);
nhrp_shortcut_delete(s, NULL);
}
@@ -206,8 +210,10 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
int holding_time = pp->if_ad->holdtime;
nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
- EVENT_OFF(s->t_timer);
- event_add_timer(master, nhrp_shortcut_do_purge, s, 1, &s->t_timer);
+ EVENT_OFF(s->t_shortcut_purge);
+ EVENT_OFF(s->t_retry_resolution);
+ event_add_timer(master, nhrp_shortcut_do_purge, s, 1,
+ &s->t_shortcut_purge);
if (pp->hdr->type != NHRP_PACKET_RESOLUTION_REPLY) {
if (pp->hdr->type == NHRP_PACKET_ERROR_INDICATION
@@ -374,7 +380,8 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution reply handled");
}
-static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
+static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s,
+ bool retry)
{
struct zbuf *zb;
struct nhrp_packet_header *hdr;
@@ -389,6 +396,22 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
!= NHRP_ROUTE_NBMA_NEXTHOP)
return;
+ /*Retry interval for NHRP resolution request
+ * will start at 1 second and will be doubled every time
+ * another resolution request is sent, until it is
+ * eventually upper-bounded by the purge time of
+ * the shortcut.
+ */
+ if (!retry)
+ s->retry_interval = 1;
+ event_add_timer(master, nhrp_shortcut_retry_resolution_req, s,
+ s->retry_interval, &s->t_retry_resolution);
+ if (s->retry_interval != (NHRPD_DEFAULT_PURGE_TIME / 4))
+ s->retry_interval = ((s->retry_interval * 2) <
+ (NHRPD_DEFAULT_PURGE_TIME / 4))
+ ? (s->retry_interval * 2)
+ : (NHRPD_DEFAULT_PURGE_TIME / 4);
+
if (s->type == NHRP_CACHE_INVALID || s->type == NHRP_CACHE_NEGATIVE)
s->type = NHRP_CACHE_INCOMPLETE;
@@ -401,9 +424,23 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
zb, NHRP_PACKET_RESOLUTION_REQUEST, &nifp->nbma,
&nifp->afi[family2afi(sockunion_family(&s->addr))].addr,
&s->addr);
- hdr->u.request_id =
- htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid,
- nhrp_shortcut_recv_resolution_rep));
+
+ /* RFC2332 - The value is taken from a 32 bit counter that is incremented
+ * each time a new "request" is transmitted. The same value MUST
+ * be used when resending a "request", i.e., when a "reply" has not been
+ * received for a "request" and a retry is sent after an
+ * appropriate interval
+ */
+ if (!retry)
+ hdr->u.request_id = htonl(
+ nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid,
+ nhrp_shortcut_recv_resolution_rep));
+ else
+ /* Just pull request_id from existing incomplete
+ * shortcut in the case of a retry
+ */
+ hdr->u.request_id = htonl(s->reqid.request_id);
+
hdr->flags = htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
| NHRP_FLAG_RESOLUTION_AUTHORATIVE
| NHRP_FLAG_RESOLUTION_SOURCE_STABLE);
@@ -412,7 +449,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
* - Prefix length: widest acceptable prefix we accept (if U set, 0xff)
* - MTU: MTU of the source station
* - Holding Time: Max time to cache the source information
- * */
+ */
/* FIXME: push CIE for each local protocol address */
cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL);
if_ad = &nifp->afi[family2afi(sockunion_family(&s->addr))];
@@ -456,13 +493,25 @@ void nhrp_shortcut_initiate(union sockunion *addr)
s = nhrp_shortcut_get(&p);
if (s && s->type != NHRP_CACHE_INCOMPLETE) {
s->addr = *addr;
- EVENT_OFF(s->t_timer);
- event_add_timer(master, nhrp_shortcut_do_purge, s, 30,
- &s->t_timer);
- nhrp_shortcut_send_resolution_req(s);
+ EVENT_OFF(s->t_shortcut_purge);
+ EVENT_OFF(s->t_retry_resolution);
+
+ event_add_timer(master, nhrp_shortcut_do_purge, s,
+ NHRPD_DEFAULT_PURGE_TIME, &s->t_shortcut_purge);
+ nhrp_shortcut_send_resolution_req(s, false);
}
}
+static void nhrp_shortcut_retry_resolution_req(struct event *t)
+{
+ struct nhrp_shortcut *s = EVENT_ARG(t);
+
+ EVENT_OFF(s->t_retry_resolution);
+ debugf(NHRP_DEBUG_COMMON, "Shortcut: Retrying Resolution Request");
+ nhrp_shortcut_send_resolution_req(s, true);
+}
+
+
void nhrp_shortcut_init(void)
{
shortcut_rib[AFI_IP] = route_table_init();
@@ -503,13 +552,14 @@ struct purge_ctx {
void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force)
{
- EVENT_OFF(s->t_timer);
+ EVENT_OFF(s->t_shortcut_purge);
+ EVENT_OFF(s->t_retry_resolution);
nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
if (force) {
/* Immediate purge on route with draw or pending shortcut */
event_add_timer_msec(master, nhrp_shortcut_do_purge, s, 5,
- &s->t_timer);
+ &s->t_shortcut_purge);
} else {
/* Soft expire - force immediate renewal, but purge
* in few seconds to make sure stale route is not
@@ -518,8 +568,8 @@ void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force)
* This allows to keep nhrp route up, and to not
* cause temporary rerouting via hubs causing latency
* jitter. */
- event_add_timer_msec(master, nhrp_shortcut_do_purge, s, 3000,
- &s->t_timer);
+ event_add_timer_msec(master, nhrp_shortcut_do_purge, s,
+ NHRPD_PURGE_EXPIRE, &s->t_shortcut_purge);
s->expiring = 1;
nhrp_shortcut_check_use(s);
}
diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c
index 22b6bdcec7..f202576960 100644
--- a/nhrpd/nhrp_vty.c
+++ b/nhrpd/nhrp_vty.c
@@ -295,10 +295,15 @@ DEFUN(tunnel_protection, tunnel_protection_cmd,
}
DEFUN(no_tunnel_protection, no_tunnel_protection_cmd,
- "no tunnel protection",
+ "no tunnel protection [vici profile PROFILE [fallback-profile FALLBACK]]",
NO_STR
"NHRP/GRE integration\n"
- "IPsec protection\n")
+ "IPsec protection\n"
+ "VICI (StrongSwan)\n"
+ "IPsec profile\n"
+ "IPsec profile name\n"
+ "Fallback IPsec profile\n"
+ "Fallback IPsec profile name\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
@@ -882,7 +887,7 @@ static void show_ip_nhrp_shortcut(struct nhrp_shortcut *s, void *pctx)
char buf1[PREFIX_STRLEN], buf2[SU_ADDRSTRLEN];
struct json_object *json = NULL;
- if (!ctx->count) {
+ if (!ctx->count && !ctx->json) {
vty_out(vty, "%-8s %-24s %-24s %s\n", "Type", "Prefix", "Via",
"Identity");
}
diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h
index 344e1d5178..6cab7b3a1d 100644
--- a/nhrpd/nhrpd.h
+++ b/nhrpd/nhrpd.h
@@ -15,7 +15,8 @@
DECLARE_MGROUP(NHRPD);
#define NHRPD_DEFAULT_HOLDTIME 7200
-
+#define NHRPD_DEFAULT_PURGE_TIME 30
+#define NHRPD_PURGE_EXPIRE 3000
#define NHRP_DEFAULT_CONFIG "nhrpd.conf"
extern struct event_loop *master;
@@ -250,10 +251,12 @@ struct nhrp_shortcut {
union sockunion addr;
struct nhrp_reqid reqid;
- struct event *t_timer;
+ struct event *t_shortcut_purge;
+ struct event *t_retry_resolution;
enum nhrp_cache_type type;
unsigned int holding_time;
+ unsigned int retry_interval;
unsigned route_installed : 1;
unsigned expiring : 1;
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index 0c5be29ff8..343dfefcec 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -553,8 +553,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
lsa_header = (struct ospf6_lsa_header *)buffer;
if (route->type == OSPF6_DEST_TYPE_ROUTER) {
- router_lsa = (struct ospf6_inter_router_lsa *)
- ospf6_lsa_header_end(lsa_header);
+ router_lsa = lsa_after_header(lsa_header);
p = (caddr_t)router_lsa + sizeof(struct ospf6_inter_router_lsa);
/* Fill Inter-Area-Router-LSA */
@@ -565,8 +564,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
router_lsa->router_id = ADV_ROUTER_IN_PREFIX(&route->prefix);
type = htons(OSPF6_LSTYPE_INTER_ROUTER);
} else {
- prefix_lsa = (struct ospf6_inter_prefix_lsa *)
- ospf6_lsa_header_end(lsa_header);
+ prefix_lsa = lsa_after_header(lsa_header);
p = (caddr_t)prefix_lsa + sizeof(struct ospf6_inter_prefix_lsa);
/* Fill Inter-Area-Prefix-LSA */
@@ -1016,8 +1014,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
oa->name);
}
- prefix_lsa = (struct ospf6_inter_prefix_lsa *)
- ospf6_lsa_header_end(lsa->header);
+ prefix_lsa = lsa_after_header(lsa->header);
prefix.family = AF_INET6;
prefix.prefixlen = prefix_lsa->prefix.prefix_length;
ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa,
@@ -1036,8 +1033,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
oa->name);
}
- router_lsa = (struct ospf6_inter_router_lsa *)
- ospf6_lsa_header_end(lsa->header);
+ router_lsa = lsa_after_header(lsa->header);
ospf6_linkstate_prefix(router_lsa->router_id, htonl(0), &prefix);
if (is_debug)
inet_ntop(AF_INET, &router_lsa->router_id, buf,
@@ -1429,8 +1425,7 @@ static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
char tbuf[16];
if (lsa != NULL) {
- prefix_lsa = (struct ospf6_inter_prefix_lsa *)
- ospf6_lsa_header_end(lsa->header);
+ prefix_lsa = lsa_after_header(lsa->header);
ospf6_prefix_in6_addr(&in6, prefix_lsa, &prefix_lsa->prefix);
if (buf) {
@@ -1452,8 +1447,7 @@ static int ospf6_inter_area_prefix_lsa_show(struct vty *vty,
struct ospf6_inter_prefix_lsa *prefix_lsa;
char buf[INET6_ADDRSTRLEN];
- prefix_lsa = (struct ospf6_inter_prefix_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ prefix_lsa = lsa_after_header(lsa->header);
if (use_json) {
json_object_int_add(
@@ -1489,9 +1483,7 @@ static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa *lsa,
struct ospf6_inter_router_lsa *router_lsa;
if (lsa != NULL) {
- router_lsa = (struct ospf6_inter_router_lsa *)
- ospf6_lsa_header_end(lsa->header);
-
+ router_lsa = lsa_after_header(lsa->header);
if (buf)
inet_ntop(AF_INET, &router_lsa->router_id, buf, buflen);
@@ -1508,8 +1500,7 @@ static int ospf6_inter_area_router_lsa_show(struct vty *vty,
struct ospf6_inter_router_lsa *router_lsa;
char buf[64];
- router_lsa = (struct ospf6_inter_router_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ router_lsa = lsa_after_header(lsa->header);
ospf6_options_printbuf(router_lsa->options, buf, sizeof(buf));
if (use_json) {
diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h
index 52686ed49f..ab9e000d43 100644
--- a/ospf6d/ospf6_abr.h
+++ b/ospf6d/ospf6_abr.h
@@ -17,22 +17,6 @@ extern unsigned char conf_debug_ospf6_abr;
#define OSPF6_DEBUG_ABR_OFF() (conf_debug_ospf6_abr = 0)
#define IS_OSPF6_DEBUG_ABR (conf_debug_ospf6_abr)
-/* Inter-Area-Prefix-LSA */
-#define OSPF6_INTER_PREFIX_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */
-struct ospf6_inter_prefix_lsa {
- uint32_t metric;
- struct ospf6_prefix prefix;
-};
-
-/* Inter-Area-Router-LSA */
-#define OSPF6_INTER_ROUTER_LSA_FIX_SIZE 12U
-struct ospf6_inter_router_lsa {
- uint8_t mbz;
- uint8_t options[3];
- uint32_t metric;
- uint32_t router_id;
-};
-
#define OSPF6_ABR_SUMMARY_METRIC(E) \
(ntohl((E)->metric & htonl(OSPF6_EXT_PATH_METRIC_MAX)))
#define OSPF6_ABR_SUMMARY_METRIC_SET(E, C) \
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 2065527c93..8fa85badbe 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -39,6 +39,7 @@
#include "ospf6d.h"
#include "ospf6_spf.h"
#include "ospf6_nssa.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
#include "lib/json.h"
@@ -102,8 +103,7 @@ struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route,
/* prepare buffer */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- as_external_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa_header);
+ as_external_lsa = lsa_after_header(lsa_header);
p = (caddr_t)((caddr_t)as_external_lsa
+ sizeof(struct ospf6_as_external_lsa));
@@ -216,8 +216,7 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
if (!lsa)
return 0;
- external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ external = lsa_after_header(lsa->header);
if (!CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
return 0;
@@ -520,8 +519,7 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
type = ntohs(lsa->header->type);
oa = lsa->lsdb->data;
- external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ external = lsa_after_header(lsa->header);
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
zlog_debug("Calculate AS-External route for %s", lsa->name);
@@ -725,8 +723,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
int type;
bool debug = false;
- external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ external = lsa_after_header(lsa->header);
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || (IS_OSPF6_DEBUG_NSSA))
debug = true;
@@ -2424,8 +2421,7 @@ static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
char tbuf[16];
if (lsa) {
- external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ external = lsa_after_header(lsa->header);
if (pos == 0) {
ospf6_prefix_in6_addr(&in6, external,
@@ -2459,8 +2455,7 @@ static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
char buf[64];
assert(lsa->header);
- external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ external = lsa_after_header(lsa->header);
/* bits */
snprintf(buf, sizeof(buf), "%c%c%c",
@@ -3027,8 +3022,7 @@ ospf6_originate_summary_lsa(struct ospf6 *ospf6,
return;
}
- external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- aggr_lsa->header);
+ external = lsa_after_header(aggr_lsa->header);
metric = (unsigned long)OSPF6_ASBR_METRIC(external);
tag = ospf6_as_external_lsa_get_tag(aggr_lsa);
mtype = CHECK_FLAG(external->bits_metric,
@@ -3176,7 +3170,7 @@ ospf6_handle_external_aggr_modify(struct ospf6 *ospf6,
return OSPF6_FAILURE;
}
- asel = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(lsa->header);
+ asel = lsa_after_header(lsa->header);
metric = (unsigned long)OSPF6_ASBR_METRIC(asel);
tag = ospf6_as_external_lsa_get_tag(lsa);
mtype = CHECK_FLAG(asel->bits_metric,
@@ -3365,8 +3359,7 @@ static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6,
lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
htonl(info->id), ospf6->router_id, ospf6->lsdb);
if (lsa) {
- ext_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ ext_lsa = lsa_after_header(lsa->header);
if (rt->prefix.prefixlen != ext_lsa->prefix.prefix_length)
return;
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 21e6d898e8..ace3ba8488 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -79,17 +79,6 @@ struct ospf6_external_aggr_rt {
struct hash *match_extnl_hash;
};
-/* AS-External-LSA */
-#define OSPF6_AS_EXTERNAL_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */
-struct ospf6_as_external_lsa {
- uint32_t bits_metric;
-
- struct ospf6_prefix prefix;
- /* followed by none or one forwarding address */
- /* followed by none or one external route tag */
- /* followed by none or one referenced LS-ID */
-};
-
#define OSPF6_ASBR_BIT_T ntohl (0x01000000)
#define OSPF6_ASBR_BIT_F ntohl (0x02000000)
#define OSPF6_ASBR_BIT_E ntohl (0x04000000)
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index b87aa2ffe1..04ff35083f 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -26,6 +26,7 @@
#include "ospf6_flood.h"
#include "ospf6_nssa.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
unsigned char conf_debug_ospf6_flooding;
diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c
index ab119a4ea4..64eb90d5f2 100644
--- a/ospf6d/ospf6_gr.c
+++ b/ospf6d/ospf6_gr.c
@@ -16,6 +16,7 @@
#include "printfrr.h"
#include "lib_errors.h"
+#include "ospf6_proto.h"
#include "ospf6d/ospf6_lsa.h"
#include "ospf6d/ospf6_lsdb.h"
#include "ospf6d/ospf6_route.h"
@@ -30,6 +31,7 @@
#include "ospf6d/ospf6_flood.h"
#include "ospf6d/ospf6_intra.h"
#include "ospf6d/ospf6_spf.h"
+#include "ospf6d/ospf6_tlv.h"
#include "ospf6d/ospf6_gr.h"
#include "ospf6d/ospf6_gr_clippy.c"
@@ -54,16 +56,17 @@ static int ospf6_gr_lsa_originate(struct ospf6_interface *oi,
/* prepare buffer */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- grace_lsa = (struct ospf6_grace_lsa *)ospf6_lsa_header_end(lsa_header);
+ grace_lsa = lsa_after_header(lsa_header);
/* Put grace period. */
- grace_lsa->tlv_period.header.type = htons(GRACE_PERIOD_TYPE);
- grace_lsa->tlv_period.header.length = htons(GRACE_PERIOD_LENGTH);
+ grace_lsa->tlv_period.header.type = htons(TLV_GRACE_PERIOD_TYPE);
+ grace_lsa->tlv_period.header.length = htons(TLV_GRACE_PERIOD_LENGTH);
grace_lsa->tlv_period.interval = htonl(gr_info->grace_period);
/* Put restart reason. */
- grace_lsa->tlv_reason.header.type = htons(RESTART_REASON_TYPE);
- grace_lsa->tlv_reason.header.length = htons(RESTART_REASON_LENGTH);
+ grace_lsa->tlv_reason.header.type = htons(TLV_GRACE_RESTART_REASON_TYPE);
+ grace_lsa->tlv_reason.header.length =
+ htons(TLV_GRACE_RESTART_REASON_LENGTH);
grace_lsa->tlv_reason.reason = reason;
/* Fill LSA Header */
diff --git a/ospf6d/ospf6_gr.h b/ospf6d/ospf6_gr.h
index 84ef3aeb8a..e10d20680b 100644
--- a/ospf6d/ospf6_gr.h
+++ b/ospf6d/ospf6_gr.h
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * OSPF6 Graceful Retsart helper functions.
+ * OSPF6 Graceful Restart helper functions.
+ * Ref RFC 5187
*
* Copyright (C) 2021-22 Vmware, Inc.
* Rajesh Kumar Girada
@@ -60,58 +61,16 @@ enum ospf6_gr_helper_rejected_reason {
OSPF6_HELPER_RESTARTING,
};
-#ifdef roundup
-#define ROUNDUP(val, gran) roundup(val, gran)
-#else /* roundup */
-#define ROUNDUP(val, gran) (((val)-1 | (gran)-1) + 1)
-#endif /* roundup */
-/*
- * Generic TLV (type, length, value) macros
- */
-struct tlv_header {
- uint16_t type; /* Type of Value */
- uint16_t length; /* Length of Value portion only, in bytes */
-};
-
-#define TLV_HDR_SIZE (sizeof(struct tlv_header))
-
-#define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(uint32_t)))
-
-#define TLV_SIZE(tlvh) (uint32_t)(TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh))
-
-#define TLV_HDR_TOP(lsah) \
- (struct tlv_header *)((char *)(lsah) + OSPF6_LSA_HEADER_SIZE)
-
-#define TLV_HDR_NEXT(tlvh) \
- (struct tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh))
-
-/* Ref RFC5187 appendix-A */
-/* Grace period TLV */
-#define GRACE_PERIOD_TYPE 1
-#define GRACE_PERIOD_LENGTH 4
-struct grace_tlv_graceperiod {
- struct tlv_header header;
- uint32_t interval;
-};
-#define GRACE_PERIOD_TLV_SIZE sizeof(struct grace_tlv_graceperiod)
-
-/* Restart reason TLV */
-#define RESTART_REASON_TYPE 2
-#define RESTART_REASON_LENGTH 1
-struct grace_tlv_restart_reason {
- struct tlv_header header;
- uint8_t reason;
- uint8_t reserved[3];
-};
-#define GRACE_RESTART_REASON_TLV_SIZE sizeof(struct grace_tlv_restart_reason)
+#define GRACE_PERIOD_TLV_SIZE sizeof(struct tlv_grace_period)
+#define GRACE_RESTART_REASON_TLV_SIZE sizeof(struct tlv_grace_restart_reason)
#define OSPF6_GRACE_LSA_MIN_SIZE \
GRACE_PERIOD_TLV_SIZE + GRACE_RESTART_REASON_TLV_SIZE
struct ospf6_grace_lsa {
- struct grace_tlv_graceperiod tlv_period;
- struct grace_tlv_restart_reason tlv_reason;
+ struct tlv_grace_period tlv_period;
+ struct tlv_grace_restart_reason tlv_reason;
};
struct advRtr {
diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c
index f0e5d3a15c..da8b829cf1 100644
--- a/ospf6d/ospf6_gr_helper.c
+++ b/ospf6d/ospf6_gr_helper.c
@@ -32,6 +32,7 @@
#include "ospf6_neighbor.h"
#include "ospf6_intra.h"
#include "ospf6d.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
#include "lib/json.h"
#include "ospf6d/ospf6_gr_helper_clippy.c"
@@ -129,8 +130,8 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa,
{
struct ospf6_lsa_header *lsah = NULL;
struct tlv_header *tlvh = NULL;
- struct grace_tlv_graceperiod *gracePeriod;
- struct grace_tlv_restart_reason *grReason;
+ struct tlv_grace_period *gracePeriod;
+ struct tlv_grace_restart_reason *grReason;
uint16_t length = 0;
int sum = 0;
@@ -144,9 +145,8 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa,
length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE;
- for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
+ for (tlvh = lsdesc_start(lsah); sum < length && tlvh;
tlvh = TLV_HDR_NEXT(tlvh)) {
-
/* Check TLV len against overall LSA */
if (sum + TLV_SIZE(tlvh) > length) {
if (IS_DEBUG_OSPF6_GR)
@@ -157,8 +157,8 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa,
}
switch (ntohs(tlvh->type)) {
- case GRACE_PERIOD_TYPE:
- gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
+ case TLV_GRACE_PERIOD_TYPE:
+ gracePeriod = (struct tlv_grace_period *)tlvh;
*interval = ntohl(gracePeriod->interval);
sum += TLV_SIZE(tlvh);
@@ -167,8 +167,8 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa,
|| *interval < OSPF6_MIN_GRACE_INTERVAL)
return OSPF6_FAILURE;
break;
- case RESTART_REASON_TYPE:
- grReason = (struct grace_tlv_restart_reason *)tlvh;
+ case TLV_GRACE_RESTART_REASON_TYPE:
+ grReason = (struct tlv_grace_restart_reason *)tlvh;
*reason = grReason->reason;
sum += TLV_SIZE(tlvh);
@@ -1218,8 +1218,8 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
{
struct ospf6_lsa_header *lsah = NULL;
struct tlv_header *tlvh = NULL;
- struct grace_tlv_graceperiod *gracePeriod;
- struct grace_tlv_restart_reason *grReason;
+ struct tlv_grace_period *gracePeriod;
+ struct tlv_grace_restart_reason *grReason;
uint16_t length = 0;
int sum = 0;
@@ -1240,9 +1240,8 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
zlog_debug(" TLV info:");
}
- for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
+ for (tlvh = lsdesc_start(lsah); sum < length && tlvh;
tlvh = TLV_HDR_NEXT(tlvh)) {
-
/* Check TLV len */
if (sum + TLV_SIZE(tlvh) > length) {
if (vty)
@@ -1255,8 +1254,8 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
}
switch (ntohs(tlvh->type)) {
- case GRACE_PERIOD_TYPE:
- gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
+ case TLV_GRACE_PERIOD_TYPE:
+ gracePeriod = (struct tlv_grace_period *)tlvh;
sum += TLV_SIZE(tlvh);
if (vty) {
@@ -1272,8 +1271,8 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa,
ntohl(gracePeriod->interval));
}
break;
- case RESTART_REASON_TYPE:
- grReason = (struct grace_tlv_restart_reason *)tlvh;
+ case TLV_GRACE_RESTART_REASON_TYPE:
+ grReason = (struct tlv_grace_restart_reason *)tlvh;
sum += TLV_SIZE(tlvh);
if (vty) {
if (use_json)
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 7f813ce3cc..60f92385dd 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -14,6 +14,7 @@
#include "plist.h"
#include "zclient.h"
+#include "ospf6_proto.h"
#include "ospf6_lsa.h"
#include "ospf6_lsdb.h"
#include "ospf6_top.h"
@@ -30,9 +31,9 @@
#include "ospf6d.h"
#include "ospf6_bfd.h"
#include "ospf6_zebra.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
#include "lib/json.h"
-#include "ospf6_proto.h"
#include "lib/keychain.h"
#include "ospf6_auth_trailer.h"
#include "ospf6d/ospf6_interface_clippy.c"
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index b06796ada0..324cd7abe8 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -32,6 +32,7 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
#include "ospf6_spf.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
unsigned char conf_debug_ospf6_brouter = 0;
@@ -43,41 +44,20 @@ uint32_t conf_debug_ospf6_brouter_specific_area_id;
/* RFC2740 3.4.3.1 Router-LSA */
/******************************/
+/* OSPF6_LSTYPE_ROUTER */
static char *ospf6_router_lsa_get_nbr_id(struct ospf6_lsa *lsa, char *buf,
int buflen, int pos)
{
- struct ospf6_router_lsa *router_lsa;
- struct ospf6_router_lsdesc *lsdesc;
- char *start, *end;
char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN];
+ struct ospf6_router_lsdesc *lsdesc = nth_lsdesc(lsa->header, pos);
- if (lsa) {
- router_lsa = (struct ospf6_router_lsa
- *)((char *)lsa->header
- + sizeof(struct ospf6_lsa_header));
- start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
- end = (char *)lsa->header + ntohs(lsa->header->length);
-
- lsdesc = (struct ospf6_router_lsdesc
- *)(start
- + pos * (sizeof(struct
- ospf6_router_lsdesc)));
- if ((char *)lsdesc + sizeof(struct ospf6_router_lsdesc)
- <= end) {
- if (buf && (buflen > INET_ADDRSTRLEN * 2)) {
- inet_ntop(AF_INET,
- &lsdesc->neighbor_interface_id, buf1,
- sizeof(buf1));
- inet_ntop(AF_INET, &lsdesc->neighbor_router_id,
- buf2, sizeof(buf2));
- snprintf(buf, buflen, "%s/%s", buf2, buf1);
-
- return buf;
- }
- }
- }
+ if (!lsdesc || !buf || buflen < (2 + 2 * INET_ADDRSTRLEN))
+ return NULL;
- return NULL;
+ inet_ntop(AF_INET, &lsdesc->neighbor_interface_id, buf1, sizeof(buf1));
+ inet_ntop(AF_INET, &lsdesc->neighbor_router_id, buf2, sizeof(buf2));
+ snprintf(buf, buflen, "%s/%s", buf2, buf1);
+ return buf;
}
static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
@@ -195,9 +175,7 @@ int ospf6_router_is_stub_router(struct ospf6_lsa *lsa)
struct ospf6_router_lsa *rtr_lsa;
if (lsa != NULL && OSPF6_LSA_IS_TYPE(ROUTER, lsa)) {
- rtr_lsa = (struct ospf6_router_lsa
- *)((caddr_t)lsa->header
- + sizeof(struct ospf6_lsa_header));
+ rtr_lsa = lsa_after_header(lsa->header);
if (!OSPF6_OPT_ISSET(rtr_lsa->options, OSPF6_OPT_R)) {
return OSPF6_IS_STUB_ROUTER;
@@ -242,14 +220,12 @@ void ospf6_router_lsa_originate(struct event *thread)
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- router_lsa = (struct ospf6_router_lsa *)ospf6_lsa_header_end(lsa_header);
+ router_lsa = lsa_after_header(lsa_header);
ospf6_router_lsa_options_set(oa, router_lsa);
/* describe links for each interfaces */
- lsdesc = (struct ospf6_router_lsdesc
- *)((caddr_t)router_lsa
- + sizeof(struct ospf6_router_lsa));
+ lsdesc = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_ROUTER);
for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
/* Interfaces in state Down or Loopback are not described */
@@ -272,9 +248,9 @@ void ospf6_router_lsa_originate(struct event *thread)
&& ((size_t)((char *)lsdesc - buffer)
+ sizeof(struct ospf6_router_lsdesc)
> oa->router_lsa_size_limit)) {
- if ((caddr_t)lsdesc
- == (caddr_t)router_lsa
- + sizeof(struct ospf6_router_lsa)) {
+ if (lsdesc ==
+ lsdesc_start_lsa_type(lsa_header,
+ OSPF6_LSTYPE_ROUTER)) {
zlog_warn(
"Size limit setting for Router-LSA too short");
return;
@@ -303,15 +279,13 @@ void ospf6_router_lsa_originate(struct event *thread)
/* Reset Buffer to fill next Router LSA */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- router_lsa = (struct ospf6_router_lsa *)
- ospf6_lsa_header_end(lsa_header);
+ router_lsa = lsa_after_header(lsa_header);
ospf6_router_lsa_options_set(oa, router_lsa);
/* describe links for each interfaces */
- lsdesc = (struct ospf6_router_lsdesc
- *)((caddr_t)router_lsa
- + sizeof(struct ospf6_router_lsa));
+ lsdesc = lsdesc_start_lsa_type(lsa_header,
+ OSPF6_LSTYPE_ROUTER);
link_state_id++;
}
@@ -424,30 +398,13 @@ void ospf6_router_lsa_originate(struct event *thread)
static char *ospf6_network_lsa_get_ar_id(struct ospf6_lsa *lsa, char *buf,
int buflen, int pos)
{
- char *start, *end, *current;
- struct ospf6_network_lsa *network_lsa;
- struct ospf6_network_lsdesc *lsdesc;
+ struct ospf6_network_lsdesc *lsdesc = nth_lsdesc(lsa->header, pos);
- if (lsa) {
- network_lsa = (struct ospf6_network_lsa
- *)((caddr_t)lsa->header
- + sizeof(struct ospf6_lsa_header));
-
- start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
- end = (char *)lsa->header + ntohs(lsa->header->length);
- current = start + pos * (sizeof(struct ospf6_network_lsdesc));
-
- if ((current + sizeof(struct ospf6_network_lsdesc)) <= end) {
- lsdesc = (struct ospf6_network_lsdesc *)current;
- if (buf) {
- inet_ntop(AF_INET, &lsdesc->router_id, buf,
- buflen);
- return buf;
- }
- }
- }
+ if (!lsdesc || !buf || buflen < (1 + INET_ADDRSTRLEN))
+ return NULL;
- return NULL;
+ inet_ntop(AF_INET, &lsdesc->router_id, buf, buflen);
+ return buf;
}
static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
@@ -459,9 +416,7 @@ static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
char buf[128], options[32];
json_object *json_arr = NULL;
- network_lsa =
- (struct ospf6_network_lsa *)((caddr_t)lsa->header
- + sizeof(struct ospf6_lsa_header));
+ network_lsa = lsa_after_header(lsa->header);
ospf6_options_printbuf(network_lsa->options, options, sizeof(options));
if (use_json)
@@ -563,23 +518,19 @@ void ospf6_network_lsa_originate(struct event *thread)
/* prepare buffer */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- network_lsa =
- (struct ospf6_network_lsa *)ospf6_lsa_header_end(lsa_header);
+ network_lsa = lsa_after_header(lsa_header);
/* Collect the interface's Link-LSAs to describe
network's optional capabilities */
type = htons(OSPF6_LSTYPE_LINK);
for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) {
- link_lsa = (struct ospf6_link_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ link_lsa = lsa_after_header(lsa->header);
network_lsa->options[0] |= link_lsa->options[0];
network_lsa->options[1] |= link_lsa->options[1];
network_lsa->options[2] |= link_lsa->options[2];
}
- lsdesc = (struct ospf6_network_lsdesc
- *)((caddr_t)network_lsa
- + sizeof(struct ospf6_network_lsa));
+ lsdesc = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_NETWORK);
/* set Link Description to the router itself */
lsdesc->router_id = oi->area->ospf6->router_id;
@@ -623,52 +574,24 @@ void ospf6_network_lsa_originate(struct event *thread)
static char *ospf6_link_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf,
int buflen, int pos)
{
- char *start, *end, *current;
- struct ospf6_link_lsa *link_lsa;
- struct in6_addr in6;
- struct ospf6_prefix *prefix;
- int cnt = 0, prefixnum;
+ struct ospf6_link_lsa *link_lsa = lsa_after_header(lsa->header);
+ struct ospf6_prefix *prefix = nth_prefix(lsa->header, pos);
+ struct in6_addr in6 = { 0 };
- if (lsa) {
- link_lsa = (struct ospf6_link_lsa
- *)((caddr_t)lsa->header
- + sizeof(struct ospf6_lsa_header));
-
- if (pos == 0) {
- inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf,
- buflen);
- return (buf);
- }
+ if (!lsa || !prefix || !buf || buflen < (1 + INET6_ADDRSTRLEN))
+ return NULL;
- prefixnum = ntohl(link_lsa->prefix_num);
- if (pos > prefixnum)
- return NULL;
+ /* position zero is used for the lladdr in the body of the LSA */
+ if (pos == 0) {
+ inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, buflen);
+ return buf;
+ }
- start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
- end = (char *)lsa->header + ntohs(lsa->header->length);
- current = start;
-
- while (current + sizeof(struct ospf6_prefix) <= end) {
- prefix = (struct ospf6_prefix *)current;
- if (prefix->prefix_length == 0
- || current + OSPF6_PREFIX_SIZE(prefix) > end) {
- return NULL;
- }
+ memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
+ OSPF6_PREFIX_SPACE(prefix->prefix_length));
+ inet_ntop(AF_INET6, &in6, buf, buflen);
- if (cnt < (pos - 1)) {
- current += OSPF6_PREFIX_SIZE(prefix);
- cnt++;
- } else {
- memset(&in6, 0, sizeof(in6));
- memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
- OSPF6_PREFIX_SPACE(
- prefix->prefix_length));
- inet_ntop(AF_INET6, &in6, buf, buflen);
- return (buf);
- }
- }
- }
- return NULL;
+ return buf;
}
static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
@@ -684,8 +607,7 @@ static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
json_object *json_arr = NULL;
char prefix_string[133];
- link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa->header
- + sizeof(struct ospf6_lsa_header));
+ link_lsa = lsa_after_header(lsa->header);
ospf6_options_printbuf(link_lsa->options, options, sizeof(options));
inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, sizeof(buf));
@@ -795,7 +717,7 @@ void ospf6_link_lsa_originate(struct event *thread)
/* prepare buffer */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- link_lsa = (struct ospf6_link_lsa *)ospf6_lsa_header_end(lsa_header);
+ link_lsa = lsa_after_header(lsa_header);
/* Fill Link-LSA */
link_lsa->priority = oi->priority;
@@ -804,8 +726,7 @@ void ospf6_link_lsa_originate(struct event *thread)
sizeof(struct in6_addr));
link_lsa->prefix_num = htonl(oi->route_connected->count);
- op = (struct ospf6_prefix *)((caddr_t)link_lsa
- + sizeof(struct ospf6_link_lsa));
+ op = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_LINK);
/* connected prefix to advertise */
for (route = ospf6_route_head(oi->route_connected); route;
@@ -846,52 +767,22 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
char *buf, int buflen,
int pos)
{
- char *start, *end, *current;
- struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
- struct in6_addr in6;
- int prefixnum, cnt = 0;
- struct ospf6_prefix *prefix;
+ struct ospf6_prefix *prefix = nth_prefix(lsa->header, pos);
+ struct in6_addr in6 = { 0 };
char tbuf[16];
- if (lsa) {
- intra_prefix_lsa =
- (struct ospf6_intra_prefix_lsa
- *)((caddr_t)lsa->header
- + sizeof(struct ospf6_lsa_header));
+ /* ensure buflen >= INET6_ADDRSTRLEN + '/128\0' */
+ if (!lsa || !prefix || !buf || buflen < (5 + INET6_ADDRSTRLEN))
+ return NULL;
- prefixnum = ntohs(intra_prefix_lsa->prefix_num);
- if ((pos + 1) > prefixnum)
- return NULL;
+ memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
+ OSPF6_PREFIX_SPACE(prefix->prefix_length));
+ inet_ntop(AF_INET6, &in6, buf, buflen);
- start = (char *)intra_prefix_lsa
- + sizeof(struct ospf6_intra_prefix_lsa);
- end = ospf6_lsa_end(lsa->header);
- current = start;
+ snprintf(tbuf, sizeof(tbuf), "/%d", prefix->prefix_length);
+ strlcat(buf, tbuf, buflen);
- while (current + sizeof(struct ospf6_prefix) <= end) {
- prefix = (struct ospf6_prefix *)current;
- if (prefix->prefix_length == 0
- || current + OSPF6_PREFIX_SIZE(prefix) > end) {
- return NULL;
- }
-
- if (cnt < pos) {
- current += OSPF6_PREFIX_SIZE(prefix);
- cnt++;
- } else {
- memset(&in6, 0, sizeof(in6));
- memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
- OSPF6_PREFIX_SPACE(
- prefix->prefix_length));
- inet_ntop(AF_INET6, &in6, buf, buflen);
- snprintf(tbuf, sizeof(tbuf), "/%d",
- prefix->prefix_length);
- strlcat(buf, tbuf, buflen);
- return (buf);
- }
- }
- }
- return NULL;
+ return buf;
}
static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
@@ -908,9 +799,7 @@ static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
json_object *json_arr = NULL;
char prefix_string[133];
- intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
- *)((caddr_t)lsa->header
- + sizeof(struct ospf6_lsa_header));
+ intra_prefix_lsa = lsa_after_header(lsa->header);
prefixnum = ntohs(intra_prefix_lsa->prefix_num);
@@ -1037,8 +926,7 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread)
/* prepare buffer */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end(
- lsa_header);
+ intra_prefix_lsa = lsa_after_header(lsa_header);
/* Fill Intra-Area-Prefix-LSA */
intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER);
@@ -1122,12 +1010,10 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread)
/* put prefixes to advertise */
prefix_num = 0;
- op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa
- + sizeof(struct ospf6_intra_prefix_lsa));
+ op = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_INTRA_PREFIX);
for (route = ospf6_route_head(route_advertise); route;
route = ospf6_route_best_next(route)) {
if (((caddr_t)op - (caddr_t)lsa_header) > MAX_LSA_PAYLOAD) {
-
intra_prefix_lsa->prefix_num = htons(prefix_num);
/* Fill LSA Header */
@@ -1153,8 +1039,7 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread)
/* Prepare next buffer */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
- ospf6_lsa_header_end(lsa_header);
+ intra_prefix_lsa = lsa_after_header(lsa_header);
/* Fill Intra-Area-Prefix-LSA */
intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER);
@@ -1163,10 +1048,8 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread)
/* Put next set of prefixes to advertise */
prefix_num = 0;
- op = (struct ospf6_prefix
- *)((caddr_t)intra_prefix_lsa
- + sizeof(struct
- ospf6_intra_prefix_lsa));
+ op = lsdesc_start_lsa_type(lsa_header,
+ OSPF6_LSTYPE_INTRA_PREFIX);
}
op->prefix_length = route->prefix.prefixlen;
@@ -1261,8 +1144,7 @@ void ospf6_intra_prefix_lsa_originate_transit(struct event *thread)
/* prepare buffer */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end(
- lsa_header);
+ intra_prefix_lsa = lsa_after_header(lsa_header);
/* Fill Intra-Area-Prefix-LSA */
intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_NETWORK);
@@ -1311,9 +1193,7 @@ void ospf6_intra_prefix_lsa_originate_transit(struct event *thread)
}
}
- link_lsa = (struct ospf6_link_lsa
- *)((caddr_t)lsa->header
- + sizeof(struct ospf6_lsa_header));
+ link_lsa = lsa_after_header(lsa->header);
prefix_num = (unsigned short)ntohl(link_lsa->prefix_num);
start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
@@ -1356,8 +1236,7 @@ void ospf6_intra_prefix_lsa_originate_transit(struct event *thread)
zlog_debug("Trailing garbage in %s", lsa->name);
}
- op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa
- + sizeof(struct ospf6_intra_prefix_lsa));
+ op = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_INTRA_PREFIX);
prefix_num = 0;
for (route = ospf6_route_head(route_advertise); route;
@@ -1658,10 +1537,7 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
}
continue;
}
- intra_prefix_lsa =
- (struct ospf6_intra_prefix_lsa *)
- ospf6_lsa_header_end(
- lsa->header);
+ intra_prefix_lsa = lsa_after_header(lsa->header);
if (intra_prefix_lsa->ref_adv_router
== oa->ospf6->router_id) {
@@ -1742,8 +1618,7 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
oa = OSPF6_AREA(lsa->lsdb->data);
- intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ intra_prefix_lsa = lsa_after_header(lsa->header);
if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_ROUTER) ||
intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_NETWORK))
ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router,
@@ -1971,8 +1846,7 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
oa = OSPF6_AREA(lsa->lsdb->data);
- intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ intra_prefix_lsa = lsa_after_header(lsa->header);
prefix_num = ntohs(intra_prefix_lsa->prefix_num);
start = (caddr_t)intra_prefix_lsa
diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h
index 7d154cb4c6..fafa6d1282 100644
--- a/ospf6d/ospf6_intra.h
+++ b/ospf6d/ospf6_intra.h
@@ -13,10 +13,13 @@ extern in_addr_t conf_debug_ospf6_brouter_specific_area_id;
#define OSPF6_DEBUG_BROUTER_SUMMARY 0x01
#define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER 0x02
#define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA 0x04
+
#define OSPF6_DEBUG_BROUTER_ON() \
(conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SUMMARY)
+
#define OSPF6_DEBUG_BROUTER_OFF() \
(conf_debug_ospf6_brouter &= ~OSPF6_DEBUG_BROUTER_SUMMARY)
+
#define IS_OSPF6_DEBUG_BROUTER \
(conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SUMMARY)
@@ -26,14 +29,17 @@ extern in_addr_t conf_debug_ospf6_brouter_specific_area_id;
conf_debug_ospf6_brouter |= \
OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER; \
} while (0)
+
#define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF() \
do { \
conf_debug_ospf6_brouter_specific_router_id = 0; \
conf_debug_ospf6_brouter &= \
~OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER; \
} while (0)
+
#define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER \
(conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER)
+
#define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(router_id) \
(IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER \
&& conf_debug_ospf6_brouter_specific_router_id == (router_id))
@@ -43,42 +49,21 @@ extern in_addr_t conf_debug_ospf6_brouter_specific_area_id;
conf_debug_ospf6_brouter_specific_area_id = (area_id); \
conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SPECIFIC_AREA; \
} while (0)
+
#define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF() \
do { \
conf_debug_ospf6_brouter_specific_area_id = 0; \
conf_debug_ospf6_brouter &= \
~OSPF6_DEBUG_BROUTER_SPECIFIC_AREA; \
} while (0)
+
#define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA \
(conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SPECIFIC_AREA)
+
#define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(area_id) \
(IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA \
&& conf_debug_ospf6_brouter_specific_area_id == (area_id))
-/* Router-LSA */
-#define OSPF6_ROUTER_LSA_MIN_SIZE 4U
-struct ospf6_router_lsa {
- uint8_t bits;
- uint8_t options[3];
- /* followed by ospf6_router_lsdesc(s) */
-};
-
-/* Link State Description in Router-LSA */
-#define OSPF6_ROUTER_LSDESC_FIX_SIZE 16U
-struct ospf6_router_lsdesc {
- uint8_t type;
- uint8_t reserved;
- uint16_t metric; /* output cost */
- uint32_t interface_id;
- uint32_t neighbor_interface_id;
- in_addr_t neighbor_router_id;
-};
-
-#define OSPF6_ROUTER_LSDESC_POINTTOPOINT 1
-#define OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK 2
-#define OSPF6_ROUTER_LSDESC_STUB_NETWORK 3
-#define OSPF6_ROUTER_LSDESC_VIRTUAL_LINK 4
-
enum stub_router_mode {
OSPF6_NOT_STUB_ROUTER,
OSPF6_IS_STUB_ROUTER,
@@ -92,49 +77,16 @@ enum stub_router_mode {
: 0)
#define ROUTER_LSDESC_GET_METRIC(x) \
(ntohs(((struct ospf6_router_lsdesc *)(x))->metric))
+
#define ROUTER_LSDESC_GET_IFID(x) \
(ntohl(((struct ospf6_router_lsdesc *)(x))->interface_id))
+
#define ROUTER_LSDESC_GET_NBR_IFID(x) \
(ntohl(((struct ospf6_router_lsdesc *)(x))->neighbor_interface_id))
+
#define ROUTER_LSDESC_GET_NBR_ROUTERID(x) \
(((struct ospf6_router_lsdesc *)(x))->neighbor_router_id)
-/* Network-LSA */
-#define OSPF6_NETWORK_LSA_MIN_SIZE 4U
-struct ospf6_network_lsa {
- uint8_t reserved;
- uint8_t options[3];
- /* followed by ospf6_netowrk_lsd(s) */
-};
-
-/* Link State Description in Router-LSA */
-#define OSPF6_NETWORK_LSDESC_FIX_SIZE 4U
-struct ospf6_network_lsdesc {
- in_addr_t router_id;
-};
-#define NETWORK_LSDESC_GET_NBR_ROUTERID(x) \
- (((struct ospf6_network_lsdesc *)(x))->router_id)
-
-/* Link-LSA */
-#define OSPF6_LINK_LSA_MIN_SIZE 24U /* w/o 1st IPv6 prefix */
-struct ospf6_link_lsa {
- uint8_t priority;
- uint8_t options[3];
- struct in6_addr linklocal_addr;
- uint32_t prefix_num;
- /* followed by ospf6 prefix(es) */
-};
-
-/* Intra-Area-Prefix-LSA */
-#define OSPF6_INTRA_PREFIX_LSA_MIN_SIZE 12U /* w/o 1st IPv6 prefix */
-struct ospf6_intra_prefix_lsa {
- uint16_t prefix_num;
- uint16_t ref_type;
- uint32_t ref_id;
- in_addr_t ref_adv_router;
- /* followed by ospf6 prefix(es) */
-};
-
#define OSPF6_ROUTER_LSA_SCHEDULE(oa) \
do { \
@@ -142,18 +94,21 @@ struct ospf6_intra_prefix_lsa {
event_add_event(master, ospf6_router_lsa_originate, \
oa, 0, &(oa)->thread_router_lsa); \
} while (0)
+
#define OSPF6_NETWORK_LSA_SCHEDULE(oi) \
do { \
if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
event_add_event(master, ospf6_network_lsa_originate, \
oi, 0, &(oi)->thread_network_lsa); \
} while (0)
+
#define OSPF6_LINK_LSA_SCHEDULE(oi) \
do { \
if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
event_add_event(master, ospf6_link_lsa_originate, oi, \
0, &(oi)->thread_link_lsa); \
} while (0)
+
#define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa) \
do { \
if (CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \
@@ -161,6 +116,7 @@ struct ospf6_intra_prefix_lsa {
master, ospf6_intra_prefix_lsa_originate_stub, \
oa, 0, &(oa)->thread_intra_prefix_lsa); \
} while (0)
+
#define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi) \
do { \
if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index 017751825f..622e5f9e0f 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -37,8 +37,85 @@ DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary");
+const uint8_t ospf6_lsa_min_size[OSPF6_LSTYPE_SIZE] = {
+ [OSPF6_LSTYPE_UNKNOWN] = 0,
+ [0x00ff & OSPF6_LSTYPE_ROUTER] = OSPF6_ROUTER_LSA_MIN_SIZE,
+ [0x00ff & OSPF6_LSTYPE_NETWORK] = OSPF6_NETWORK_LSA_MIN_SIZE,
+ [0x00ff & OSPF6_LSTYPE_INTER_PREFIX] = OSPF6_INTER_PREFIX_LSA_MIN_SIZE,
+ [0x00ff & OSPF6_LSTYPE_INTER_ROUTER] = OSPF6_INTER_ROUTER_LSA_FIX_SIZE,
+ [0x00ff & OSPF6_LSTYPE_AS_EXTERNAL] = OSPF6_AS_EXTERNAL_LSA_MIN_SIZE,
+ [0x00ff & OSPF6_LSTYPE_GROUP_MEMBERSHIP] = 0, /* Unused */
+ [0x00ff & OSPF6_LSTYPE_TYPE_7] = OSPF6_AS_EXTERNAL_LSA_MIN_SIZE,
+ [0x00ff & OSPF6_LSTYPE_LINK] = OSPF6_LINK_LSA_MIN_SIZE,
+ [0x00ff & OSPF6_LSTYPE_INTRA_PREFIX] = OSPF6_INTRA_PREFIX_LSA_MIN_SIZE,
+ [0x00ff & OSPF6_LSTYPE_GRACE_LSA] = 0
+};
+
+void *lsdesc_start_lsa_type(struct ospf6_lsa_header *header, int lsa_type)
+{
+ uint8_t t = (0x00ff & lsa_type);
+
+ if (t == OSPF6_LSTYPE_UNKNOWN || t >= OSPF6_LSTYPE_SIZE) {
+ zlog_debug("Cannot get descriptor offset for unknown lsa type 0x%x",
+ t);
+ return ospf6_lsa_end(header);
+ }
+ return (char *)lsa_after_header(header) + ospf6_lsa_min_size[t];
+}
+
+void *lsdesc_start(struct ospf6_lsa_header *header)
+{
+ return lsdesc_start_lsa_type(header, ntohs(header->type));
+}
+
static struct ospf6_lsa_handler *lsa_handlers[OSPF6_LSTYPE_SIZE];
+void *nth_lsdesc(struct ospf6_lsa_header *header, int pos)
+{
+ char *lsdesc = lsdesc_start(header);
+ char *lsa_end = ospf6_lsa_end(header);
+ char *nth;
+ int lsdesc_size;
+
+ if (ntohs(header->type) == OSPF6_LSTYPE_ROUTER)
+ lsdesc_size = OSPF6_ROUTER_LSDESC_FIX_SIZE;
+ else if (ntohs(header->type) == OSPF6_LSTYPE_NETWORK)
+ lsdesc_size = OSPF6_NETWORK_LSDESC_FIX_SIZE;
+ else
+ return NULL;
+
+ nth = lsdesc + (pos * lsdesc_size);
+
+ if (nth + lsdesc_size <= lsa_end)
+ return nth;
+
+ return NULL;
+}
+
+void *nth_prefix(struct ospf6_lsa_header *header, int pos)
+{
+ struct ospf6_prefix *prefix = lsdesc_start(header);
+ char *end = ospf6_lsa_end(header);
+ int i = 0;
+
+ if (ntohs(header->type) != OSPF6_LSTYPE_LINK &&
+ ntohs(header->type) != OSPF6_LSTYPE_INTRA_PREFIX)
+ return NULL;
+
+ if (pos == 0)
+ return prefix;
+
+ while ((char *)prefix < end &&
+ (char *)prefix + OSPF6_PREFIX_SIZE(prefix) <= end) {
+ if (i == pos)
+ return prefix;
+ i++;
+ prefix = OSPF6_PREFIX_NEXT(prefix);
+ }
+
+ return NULL;
+}
+
struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa)
{
struct ospf6 *ospf6 = NULL;
@@ -65,7 +142,7 @@ static int ospf6_unknown_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
{
char *start, *end, *current;
- start = ospf6_lsa_header_end(lsa->header);
+ start = lsa_after_header(lsa->header);
end = ospf6_lsa_end(lsa->header);
if (use_json) {
@@ -234,8 +311,8 @@ int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2)
if (length <= 0)
return 0;
- return memcmp(ospf6_lsa_header_end(lsa1->header),
- ospf6_lsa_header_end(lsa2->header), length);
+ return memcmp(lsa_after_header(lsa1->header),
+ lsa_after_header(lsa2->header), length);
}
/* ospf6 age functions */
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index 4fc2f0dd18..b2c83a1d37 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -87,11 +87,17 @@ struct ospf6_lsa_header {
uint16_t length; /* LSA length */
};
+
static inline char *ospf6_lsa_header_end(struct ospf6_lsa_header *header)
{
return (char *)header + sizeof(struct ospf6_lsa_header);
}
+static inline void *lsa_after_header(struct ospf6_lsa_header *header)
+{
+ return (char *)header + sizeof(struct ospf6_lsa_header);
+}
+
static inline char *ospf6_lsa_end(struct ospf6_lsa_header *header)
{
return (char *)header + ntohs(header->length);
@@ -116,6 +122,94 @@ static inline uint16_t ospf6_lsa_size(struct ospf6_lsa_header *header)
#define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2)
#define OSPF6_LSA_IS_SEQWRAP(L) ((L)->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER + 1))
+/* Router-LSA */
+#define OSPF6_ROUTER_LSA_MIN_SIZE 4U
+struct ospf6_router_lsa {
+ uint8_t bits;
+ uint8_t options[3];
+ /* followed by ospf6_router_lsdesc(s) */
+};
+
+/* Link State Description in Router-LSA */
+#define OSPF6_ROUTER_LSDESC_FIX_SIZE 16U
+struct ospf6_router_lsdesc {
+ uint8_t type;
+ uint8_t reserved;
+ uint16_t metric; /* output cost */
+ uint32_t interface_id;
+ uint32_t neighbor_interface_id;
+ in_addr_t neighbor_router_id;
+};
+
+#define OSPF6_ROUTER_LSDESC_POINTTOPOINT 1
+#define OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK 2
+#define OSPF6_ROUTER_LSDESC_STUB_NETWORK 3
+#define OSPF6_ROUTER_LSDESC_VIRTUAL_LINK 4
+
+/* Network-LSA */
+#define OSPF6_NETWORK_LSA_MIN_SIZE 4U
+struct ospf6_network_lsa {
+ uint8_t reserved;
+ uint8_t options[3];
+ /* followed by ospf6_network_lsdesc(s) */
+};
+
+/* Link State Description in Network-LSA */
+#define OSPF6_NETWORK_LSDESC_FIX_SIZE 4U
+struct ospf6_network_lsdesc {
+ in_addr_t router_id;
+};
+#define NETWORK_LSDESC_GET_NBR_ROUTERID(x) \
+ (((struct ospf6_network_lsdesc *)(x))->router_id)
+
+/* Inter-Area-Prefix-LSA */
+#define OSPF6_INTER_PREFIX_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */
+struct ospf6_inter_prefix_lsa {
+ uint32_t metric;
+ struct ospf6_prefix prefix;
+};
+
+/* Inter-Area-Router-LSA */
+#define OSPF6_INTER_ROUTER_LSA_FIX_SIZE 12U
+struct ospf6_inter_router_lsa {
+ uint8_t mbz;
+ uint8_t options[3];
+ uint32_t metric;
+ uint32_t router_id;
+};
+
+/* AS-External-LSA */
+#define OSPF6_AS_EXTERNAL_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */
+struct ospf6_as_external_lsa {
+ uint32_t bits_metric;
+
+ struct ospf6_prefix prefix;
+ /* followed by none or one forwarding address */
+ /* followed by none or one external route tag */
+ /* followed by none or one referenced LS-ID */
+};
+
+/* FIXME: move nssa lsa here. */
+
+/* Link-LSA */
+#define OSPF6_LINK_LSA_MIN_SIZE 24U /* w/o 1st IPv6 prefix */
+struct ospf6_link_lsa {
+ uint8_t priority;
+ uint8_t options[3];
+ struct in6_addr linklocal_addr;
+ uint32_t prefix_num;
+ /* followed by ospf6 prefix(es) */
+};
+
+/* Intra-Area-Prefix-LSA */
+#define OSPF6_INTRA_PREFIX_LSA_MIN_SIZE 12U /* w/o 1st IPv6 prefix */
+struct ospf6_intra_prefix_lsa {
+ uint16_t prefix_num;
+ uint16_t ref_type;
+ uint32_t ref_id;
+ in_addr_t ref_adv_router;
+ /* followed by ospf6 prefix(es) */
+};
struct ospf6_lsa {
char name[64]; /* dump string */
@@ -146,6 +240,7 @@ struct ospf6_lsa {
bool tobe_acknowledged;
};
+
#define OSPF6_LSA_HEADERONLY 0x01
#define OSPF6_LSA_FLOODBACK 0x02
#define OSPF6_LSA_DUPLICATE 0x04
@@ -274,4 +369,11 @@ extern void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6);
extern struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa);
struct ospf6_lsa *ospf6_find_external_lsa(struct ospf6 *ospf6,
struct prefix *p);
+
+void *lsdesc_start_lsa_type(struct ospf6_lsa_header *header, int lsa_type);
+void *lsdesc_start(struct ospf6_lsa_header *header);
+
+void *nth_lsdesc(struct ospf6_lsa_header *header, int pos);
+void *nth_prefix(struct ospf6_lsa_header *header, int pos);
+
#endif /* OSPF6_LSA_H */
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
index 9aca5550a6..e5de30484a 100644
--- a/ospf6d/ospf6_lsdb.c
+++ b/ospf6d/ospf6_lsdb.c
@@ -229,8 +229,7 @@ struct ospf6_lsa *ospf6_find_inter_prefix_lsa(struct ospf6 *ospf6,
struct ospf6_inter_prefix_lsa *prefix_lsa;
struct prefix prefix;
- prefix_lsa = (struct ospf6_inter_prefix_lsa *)
- ospf6_lsa_header_end(lsa->header);
+ prefix_lsa = lsa_after_header(lsa->header);
prefix.family = AF_INET6;
prefix.prefixlen = prefix_lsa->prefix.prefix_length;
ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa,
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index a6ee8d8b01..33d15e7243 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -33,6 +33,7 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
#include <netinet/ip6.h>
#include "lib/libospf.h"
@@ -1303,9 +1304,7 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
4 bytes of referenced link state ID. */
if (headeronly)
break;
- as_external_lsa =
- (struct ospf6_as_external_lsa
- *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE);
+ as_external_lsa = lsa_after_header(lsah);
exp_length =
OSPF6_LSA_HEADER_SIZE + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE;
/* To find out if the last optional field (Referenced Link State
@@ -1350,8 +1349,7 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
by N>=0 IPv6 prefix blocks (with N declared beforehand). */
if (headeronly)
break;
- link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsah
- + OSPF6_LSA_HEADER_SIZE);
+ link_lsa = lsa_after_header(lsah);
return ospf6_prefixes_examin(
(struct ospf6_prefix *)((caddr_t)link_lsa
+ OSPF6_LINK_LSA_MIN_SIZE),
@@ -1366,9 +1364,7 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
*/
if (headeronly)
break;
- intra_prefix_lsa =
- (struct ospf6_intra_prefix_lsa
- *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE);
+ intra_prefix_lsa = lsa_after_header(lsah);
return ospf6_prefixes_examin(
(struct ospf6_prefix
*)((caddr_t)intra_prefix_lsa
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 0e44f2a142..acf15da4c3 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -30,6 +30,7 @@
#include "ospf6_lsa.h"
#include "ospf6_spf.h"
#include "ospf6_zebra.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
#include "lib/json.h"
diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c
index ea2be20cf3..8a5de468c9 100644
--- a/ospf6d/ospf6_nssa.c
+++ b/ospf6d/ospf6_nssa.c
@@ -52,8 +52,7 @@ static int ospf6_abr_nssa_am_elected(struct ospf6_area *oa)
/* Verify all the router LSA to compare the router ID */
for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) {
- router_lsa = (struct ospf6_router_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ router_lsa = lsa_after_header(lsa->header);
/* ignore non-ABR routers */
if (!CHECK_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B))
@@ -414,8 +413,7 @@ static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area,
}
/* find the translated Type-5 for this Type-7 */
- nssa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- type7->header);
+ nssa = lsa_after_header(type7->header);
prefix.family = AF_INET6;
prefix.prefixlen = nssa->prefix.prefix_length;
ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa, &nssa->prefix);
@@ -435,10 +433,8 @@ static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area,
/* prepare buffer */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- extnew = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa_header);
- ext = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- type7->header);
+ extnew = lsa_after_header(lsa_header);
+ ext = lsa_after_header(type7->header);
old_ptr =
(caddr_t)((caddr_t)ext + sizeof(struct ospf6_as_external_lsa));
new_ptr = (caddr_t)((caddr_t)extnew
@@ -546,8 +542,7 @@ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area,
"%s: try to find translated Type-5 LSA for %s",
__func__, type7->name);
- ext_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- type7->header);
+ ext_lsa = lsa_after_header(type7->header);
prefix.family = AF_INET6;
prefix.prefixlen = ext_lsa->prefix.prefix_length;
ospf6_prefix_in6_addr(&prefix.u.prefix6, ext_lsa,
@@ -614,8 +609,7 @@ static void ospf6_abr_translate_nssa(struct ospf6_area *area,
struct ospf6 *ospf6;
ospf6 = area->ospf6;
- nssa_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ nssa_lsa = lsa_after_header(lsa->header);
if (!CHECK_FLAG(nssa_lsa->prefix.prefix_options,
OSPF6_PREFIX_OPTION_P)) {
@@ -1240,8 +1234,7 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route,
/* prepare buffer */
memset(buffer, 0, sizeof(buffer));
lsa_header = (struct ospf6_lsa_header *)buffer;
- as_external_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa_header);
+ as_external_lsa = lsa_after_header(lsa_header);
p = (caddr_t)((caddr_t)as_external_lsa
+ sizeof(struct ospf6_as_external_lsa));
diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h
index 4307ee3c6e..645a408781 100644
--- a/ospf6d/ospf6_proto.h
+++ b/ospf6d/ospf6_proto.h
@@ -16,11 +16,12 @@
#define ALLSPFROUTERS6 "ff02::5"
#define ALLDROUTERS6 "ff02::6"
-#define OSPF6_ROUTER_BIT_W (1 << 3)
+/* RFC 5340 A.4.3 Router-LSAs Options field */
+#define OSPF6_ROUTER_BIT_NT (1 << 4)
+#define OSPF6_ROUTER_BIT_W (1 << 3) /* DEPRECATED */
#define OSPF6_ROUTER_BIT_V (1 << 2)
#define OSPF6_ROUTER_BIT_E (1 << 1)
#define OSPF6_ROUTER_BIT_B (1 << 0)
-#define OSPF6_ROUTER_BIT_NT (1 << 4)
/* OSPF options */
diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c
index 36864d2a7d..9ac8b6c1af 100644
--- a/ospf6d/ospf6_snmp.c
+++ b/ospf6d/ospf6_snmp.c
@@ -748,8 +748,6 @@ static uint8_t *ospfv3AreaEntry(struct variable *v, oid *name, size_t *length,
area_id = htonl(name[v->namelen]);
inet_ntop(AF_INET, &area_id, a, sizeof(a));
- zlog_debug("SNMP access by area: %s, exact=%d len=%d length=%lu", a,
- exact, len, (unsigned long)*length);
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
if (area == NULL) {
@@ -769,8 +767,6 @@ static uint8_t *ospfv3AreaEntry(struct variable *v, oid *name, size_t *length,
name[v->namelen] = ntohl(area->area_id);
inet_ntop(AF_INET, &area->area_id, a, sizeof(a));
- zlog_debug("SNMP found area: %s, exact=%d len=%d length=%lu", a, exact,
- len, (unsigned long)*length);
switch (v->magic) {
case OSPFv3IMPORTASEXTERN:
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index 7879dae8d7..5f2c5a6c47 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -16,11 +16,11 @@
#include "frrevent.h"
#include "lib_errors.h"
+#include "ospf6_proto.h"
#include "ospf6_lsa.h"
#include "ospf6_lsdb.h"
#include "ospf6_route.h"
#include "ospf6_area.h"
-#include "ospf6_proto.h"
#include "ospf6_abr.h"
#include "ospf6_asbr.h"
#include "ospf6_spf.h"
@@ -290,8 +290,7 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,
!= lsa->header->id)
continue;
- link_lsa = (struct ospf6_link_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ link_lsa = lsa_after_header(lsa->header);
if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf,
sizeof(buf));
@@ -1136,8 +1135,7 @@ int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
return 0;
}
- external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(
- lsa->header);
+ external = lsa_after_header(lsa->header);
prefix.family = AF_INET6;
prefix.prefixlen = external->prefix.prefix_length;
ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
diff --git a/ospf6d/ospf6_tlv.h b/ospf6d/ospf6_tlv.h
new file mode 100644
index 0000000000..a687a05939
--- /dev/null
+++ b/ospf6d/ospf6_tlv.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * OSPFv3 Type Length Value.
+ *
+ */
+
+#ifndef OSPF6_TLV_H
+#define OSPF6_TLV_H
+
+/*
+ * Generic TLV (type, length, value) macros
+ */
+struct tlv_header {
+ uint16_t type; /* Type of Value */
+ uint16_t length; /* Length of Value portion only, in bytes */
+};
+
+#ifdef roundup
+#define ROUNDUP(val, gran) roundup(val, gran)
+#else /* roundup */
+#define ROUNDUP(val, gran) (((val)-1 | (gran)-1) + 1)
+#endif /* roundup */
+
+#define TLV_HDR_SIZE (sizeof(struct tlv_header))
+
+#define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(uint32_t)))
+
+#define TLV_SIZE(tlvh) ((uint32_t)(TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)))
+
+#define TLV_HDR_NEXT(tlvh) \
+ ((struct tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)))
+
+/*
+ * RFC 5187 - OSPFv3 Graceful Restart - Grace-LSA
+ * Graceful restart predates Extended-LSA TLVs and IANA TLV register.
+ */
+/* Grace period TLV. */
+#define TLV_GRACE_PERIOD_TYPE 1
+#define TLV_GRACE_PERIOD_LENGTH 4
+struct tlv_grace_period {
+ struct tlv_header header;
+ uint32_t interval;
+};
+
+/* Restart reason TLV. */
+#define TLV_GRACE_RESTART_REASON_TYPE 2
+#define TLV_GRACE_RESTART_REASON_LENGTH 1
+struct tlv_grace_restart_reason {
+ struct tlv_header header;
+ uint8_t reason;
+ uint8_t reserved[3];
+};
+
+
+#endif /* OSPF6_TLV_H */
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index a3fb205374..ad487f3565 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -37,6 +37,7 @@
#include "ospf6_intra.h"
#include "ospf6_spf.h"
#include "ospf6d.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
#include "lib/json.h"
#include "ospf6_nssa.h"
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 911f3567d4..466301309f 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -27,6 +27,7 @@
#include "ospf6_zebra.h"
#include "ospf6d.h"
#include "ospf6_area.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
#include "lib/json.h"
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
index d90a950d79..e4e0354fc9 100644
--- a/ospf6d/ospf6d.c
+++ b/ospf6d/ospf6d.c
@@ -30,6 +30,7 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
#include "ospf6_bfd.h"
+#include "ospf6_tlv.h"
#include "ospf6_gr.h"
#include "lib/json.h"
#include "ospf6_nssa.h"
diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am
index 5f89af9508..a7bd94bd77 100644
--- a/ospf6d/subdir.am
+++ b/ospf6d/subdir.am
@@ -58,6 +58,7 @@ noinst_HEADERS += \
ospf6d/ospf6_route.h \
ospf6d/ospf6_routemap_nb.h \
ospf6d/ospf6_spf.h \
+ ospf6d/ospf6_tlv.h \
ospf6d/ospf6_top.h \
ospf6d/ospf6_zebra.h \
ospf6d/ospf6d.h \
diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am
index 289ddd009d..2bf32544fd 100644
--- a/ospfclient/subdir.am
+++ b/ospfclient/subdir.am
@@ -7,10 +7,13 @@ lib_LTLIBRARIES += ospfclient/libfrrospfapiclient.la
noinst_PROGRAMS += ospfclient/ospfclient
#man8 += $(MANBUILD)/frr-ospfclient.8
+if PYTHON_RUNTIME_DEPENDENCY
sbin_SCRIPTS += \
ospfclient/ospfclient.py \
# end
endif
+endif
+
ospfclient_libfrrospfapiclient_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0
ospfclient_libfrrospfapiclient_la_LIBADD = lib/libfrr.la
diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c
index 28d526870b..93779991b5 100644
--- a/ospfd/ospf_abr.c
+++ b/ospfd/ospf_abr.c
@@ -1750,11 +1750,10 @@ static void ospf_abr_announce_non_dna_routers(struct event *thread)
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
"%s: Area %pI4 FR enabled: %d", __func__,
&area->area_id, area->fr_info.enabled);
- OSPF_LOG_DEBUG(
- IS_DEBUG_OSPF_EVENT,
- "LSA with DC bit clear: %d Recived indication LSA: %d",
- area->fr_info.area_dc_clear,
- area->fr_info.area_ind_lsa_recvd);
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
+ "LSA with DC bit clear: %d Received indication LSA: %d",
+ area->fr_info.area_dc_clear,
+ area->fr_info.area_ind_lsa_recvd);
OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, "FR state change: %d",
area->fr_info.state_changed);
if (!OSPF_IS_AREA_BACKBONE(area) &&
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index 9b62f36d7a..b47c390088 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -1078,9 +1078,8 @@ static void ospf_external_aggr_timer(struct ospf *ospf,
if (ospf->aggr_action == OSPF_ROUTE_AGGR_ADD) {
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
- zlog_debug(
- "%s: Not required to retsart timer,set is already added.",
- __func__);
+ zlog_debug("%s: Not required to restart timer,set is already added.",
+ __func__);
return;
}
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index 2af4ae3170..e3398af74b 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
@@ -797,7 +797,7 @@ int ospf_flood_through_interface(struct ospf_interface *oi,
ospf_ls_upd_send_lsa(nbr, lsa,
OSPF_SEND_PACKET_DIRECT);
}
- } else
+ } else {
/* If P2MP delayed reflooding is configured and the LSA was
received from a neighbor on the P2MP interface, do not flood
if back out on the interface. The LSA will be retransmitted
@@ -815,9 +815,17 @@ int ospf_flood_through_interface(struct ospf_interface *oi,
inbr ? &(inbr->router_id)
: &(oi->ospf->router_id),
IF_NAME(oi));
- } else
- ospf_ls_upd_send_lsa(oi->nbr_self, lsa,
- OSPF_SEND_PACKET_INDIRECT);
+ /*
+ * If reflooding is delayed, a delayed acknowledge
+ * should be sent since the LSA will not be immediately
+ * reflooded and interpreted as an implied
+ * acknowledgment by the sender.
+ */
+ return 1;
+ }
+ ospf_ls_upd_send_lsa(oi->nbr_self, lsa,
+ OSPF_SEND_PACKET_INDIRECT);
+ }
return 0;
}
@@ -1094,8 +1102,13 @@ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
if (ls_rxmt_node->lsa_list_entry ==
ospf_lsa_list_first(&nbr->ls_rxmt_list))
rxmt_head_replaced = true;
+
+ /* Keep SA happy */
+ assert(ls_rxmt_node->lsa_list_entry != NULL);
+
ospf_lsa_list_del(&nbr->ls_rxmt_list,
ls_rxmt_node->lsa_list_entry);
+
XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry);
ospf_lsdb_delete(&nbr->ls_rxmt, old);
if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
@@ -1163,8 +1176,13 @@ void ospf_ls_retransmit_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
rxmt_timer_reset = false;
lsa->retransmit_counter--;
+
+ /* Keep SA happy */
+ assert(ls_rxmt_node->lsa_list_entry != NULL);
+
ospf_lsa_list_del(&nbr->ls_rxmt_list,
ls_rxmt_node->lsa_list_entry);
+
XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry);
ospf_lsdb_delete(&nbr->ls_rxmt, lsa);
if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 2d15a7ecca..d35f0a1372 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -2806,9 +2806,7 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf)
* or header area is backbone but ospf_interface is not
* check for VLINK interface
*/
- if ((oi == NULL)
- || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id)
- && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))) {
+ if (oi == NULL) {
if ((oi = ospf_associate_packet_vl(ospf, ifp, iph, ospfh))
== NULL) {
if (!ospf->instance && IS_DEBUG_OSPF_EVENT)
@@ -2817,6 +2815,15 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf)
&iph->ip_src, ifp->name);
return OSPF_READ_CONTINUE;
}
+ } else if (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id) &&
+ !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id)) {
+ oi = ospf_associate_packet_vl(ospf, ifp, iph, ospfh);
+ if (oi == NULL) {
+ flog_warn(EC_OSPF_PACKET,
+ "interface %s: ospf_read invalid Area ID %pI4",
+ ifp->name, &ospfh->area_id);
+ return OSPF_READ_CONTINUE;
+ }
}
/*
@@ -3335,7 +3342,7 @@ static int ospf_make_ls_ack(struct ospf_interface *oi,
struct ospf_lsa_list_entry *ls_ack_list_entry;
uint16_t length = OSPF_LS_ACK_MIN_SIZE;
struct ospf_lsa *lsa;
- struct in_addr first_dst_addr;
+ struct in_addr first_dst_addr = { INADDR_ANY };
/*
* For direct LS Acks, assure the destination address doesn't
@@ -3346,8 +3353,7 @@ static int ospf_make_ls_ack(struct ospf_interface *oi,
if (ls_ack_list_first)
first_dst_addr.s_addr =
ls_ack_list_first->list_entry_dst.s_addr;
- } else
- first_dst_addr.s_addr = INADDR_ANY;
+ }
frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) {
lsa = ls_ack_list_entry->lsa;
diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c
index dbe44f7be4..76e6efeb83 100644
--- a/ospfd/ospf_ri.c
+++ b/ospfd/ospf_ri.c
@@ -1843,16 +1843,6 @@ DEFUN (router_info,
return CMD_SUCCESS;
}
-#if CONFDATE > 20240809
-CPP_NOTICE("Drop deprecated router_info_area_id_cmd")
-#endif
-ALIAS_HIDDEN (router_info,
- router_info_area_id_cmd,
- "router-info area A.B.C.D",
- OSPF_RI_STR
- "Enable the Router Information functionality with Area flooding scope\n"
- "OSPF area ID in IP format (deprecated)\n")
-
DEFUN (no_router_info,
no_router_info_cmd,
"no router-info [<area|as>]",
@@ -2247,7 +2237,6 @@ static void ospf_router_info_register_vty(void)
install_element(VIEW_NODE, &show_ip_ospf_router_info_pce_cmd);
install_element(OSPF_NODE, &router_info_area_cmd);
- install_element(OSPF_NODE, &router_info_area_id_cmd);
install_element(OSPF_NODE, &no_router_info_cmd);
install_element(OSPF_NODE, &pce_address_cmd);
install_element(OSPF_NODE, &no_pce_address_cmd);
diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c
index 198309c1ef..97dc578679 100644
--- a/ospfd/ospf_sr.c
+++ b/ospfd/ospf_sr.c
@@ -1459,7 +1459,8 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
/* Update Algorithm, SRLB and MSD if present */
if (algo != NULL) {
int i;
- for (i = 0; i < ntohs(algo->header.length); i++)
+ for (i = 0;
+ i < ntohs(algo->header.length) && i < ALGORITHM_COUNT; i++)
srn->algo[i] = algo->value[0];
for (; i < ALGORITHM_COUNT; i++)
srn->algo[i] = SR_ALGORITHM_UNSET;
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 7a7a684dd6..b7261da261 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -2111,7 +2111,7 @@ DEFUN (ospf_abr_type,
DEFUN (no_ospf_abr_type,
no_ospf_abr_type_cmd,
- "no ospf abr-type <cisco|ibm|shortcut|standard>",
+ "no ospf abr-type [<cisco|ibm|shortcut|standard>]",
NO_STR
"OSPF specific commands\n"
"Set OSPF ABR type\n"
@@ -2291,6 +2291,10 @@ static int ospf_timers_spf_set(struct vty *vty, unsigned int delay,
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+ if (ospf->spf_delay != delay || ospf->spf_holdtime != hold ||
+ ospf->spf_max_holdtime != max)
+ ospf->spf_hold_multiplier = 1;
+
ospf->spf_delay = delay;
ospf->spf_holdtime = hold;
ospf->spf_max_holdtime = max;
@@ -8041,7 +8045,7 @@ static int ospf_vty_dead_interval_set(struct vty *vty, const char *interval_str,
VTY_DECLVAR_CONTEXT(interface, ifp);
uint32_t seconds;
uint8_t hellomult;
- struct in_addr addr;
+ struct in_addr addr = { INADDR_ANY };
int ret;
struct ospf_if_params *params;
struct ospf_interface *oi;
@@ -8157,7 +8161,7 @@ DEFUN (ip_ospf_dead_interval_minimal,
DEFUN (no_ip_ospf_dead_interval,
no_ip_ospf_dead_interval_cmd,
- "no ip ospf dead-interval [<(1-65535)|minimal hello-multiplier (2-20)> [A.B.C.D]]",
+ "no ip ospf dead-interval [<(1-65535)|minimal hello-multiplier [(2-20)]> [A.B.C.D]]",
NO_STR
"IP Information\n"
"OSPF interface commands\n"
@@ -9846,7 +9850,7 @@ DEFPY(ip_ospf_prefix_suppression, ip_ospf_prefix_suppression_addr_cmd,
"[no] ip ospf prefix-suppression [A.B.C.D]$ip_addr", NO_STR
"IP Information\n"
"OSPF interface commands\n"
- "Supress OSPF prefix advertisement on this interface\n"
+ "Suppress OSPF prefix advertisement on this interface\n"
"Address of interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
@@ -13184,6 +13188,10 @@ static void ospf_vty_if_init(void)
install_element(INTERFACE_NODE, &ip_ospf_hello_interval_cmd);
install_element(INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd);
+ /* "ip ospf graceful-restart" commands. */
+ install_element(INTERFACE_NODE, &ip_ospf_gr_hdelay_cmd);
+ install_element(INTERFACE_NODE, &no_ip_ospf_gr_hdelay_cmd);
+
/* "ip ospf network" commands. */
install_element(INTERFACE_NODE, &ip_ospf_network_cmd);
install_element(INTERFACE_NODE, &no_ip_ospf_network_cmd);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 2c518f2c9e..c7cba1e20f 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -119,8 +119,9 @@ static int ospf_interface_address_delete(ZAPI_CALLBACK_ARGS)
return 0;
if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug("Zebra: interface %s address delete %pFX",
- c->ifp->name, c->address);
+ zlog_debug("Zebra: interface %s address delete %pFX vrf %s id %u",
+ c->ifp->name, c->address,
+ ospf_vrf_id_to_name(vrf_id), vrf_id);
ifp = c->ifp;
p = *c->address;
@@ -261,9 +262,8 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p,
if (ospf->gr_info.restart_in_progress) {
if (IS_DEBUG_OSPF_GR)
- zlog_debug(
- "Zebra: Graceful Restart in progress -- not installing %pFX",
- p);
+ zlog_debug("Zebra: Graceful Restart in progress -- not installing %pFX(%s)",
+ p, ospf_vrf_id_to_name(ospf->vrf_id));
return;
}
@@ -311,10 +311,10 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p,
ifp = if_lookup_by_index(path->ifindex, ospf->vrf_id);
- zlog_debug(
- "Zebra: Route add %pFX nexthop %pI4, ifindex=%d %s",
- p, &path->nexthop, path->ifindex,
- ifp ? ifp->name : " ");
+ zlog_debug("Zebra: Route add %pFX(%s) nexthop %pI4, ifindex=%d %s",
+ p, ospf_vrf_id_to_name(ospf->vrf_id),
+ &path->nexthop, path->ifindex,
+ ifp ? ifp->name : " ");
}
}
@@ -331,9 +331,8 @@ void ospf_zebra_delete(struct ospf *ospf, struct prefix_ipv4 *p,
if (ospf->gr_info.restart_in_progress) {
if (IS_DEBUG_OSPF_GR)
- zlog_debug(
- "Zebra: Graceful Restart in progress -- not uninstalling %pFX",
- p);
+ zlog_debug("Zebra: Graceful Restart in progress -- not uninstalling %pFX(%s)",
+ p, ospf_vrf_id_to_name(ospf->vrf_id));
return;
}
@@ -345,7 +344,8 @@ void ospf_zebra_delete(struct ospf *ospf, struct prefix_ipv4 *p,
memcpy(&api.prefix, p, sizeof(*p));
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug("Zebra: Route delete %pFX", p);
+ zlog_debug("Zebra: Route delete %pFX(%s)", p,
+ ospf_vrf_id_to_name(ospf->vrf_id));
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
}
@@ -356,9 +356,8 @@ void ospf_zebra_add_discard(struct ospf *ospf, struct prefix_ipv4 *p)
if (ospf->gr_info.restart_in_progress) {
if (IS_DEBUG_OSPF_GR)
- zlog_debug(
- "Zebra: Graceful Restart in progress -- not installing %pFX",
- p);
+ zlog_debug("Zebra: Graceful Restart in progress -- not installing %pFX(%s)",
+ p, ospf_vrf_id_to_name(ospf->vrf_id));
return;
}
@@ -373,7 +372,8 @@ void ospf_zebra_add_discard(struct ospf *ospf, struct prefix_ipv4 *p)
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug("Zebra: Route add discard %pFX", p);
+ zlog_debug("Zebra: Route add discard %pFX(%s)", p,
+ ospf_vrf_id_to_name(ospf->vrf_id));
}
void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p)
@@ -382,9 +382,8 @@ void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p)
if (ospf->gr_info.restart_in_progress) {
if (IS_DEBUG_OSPF_GR)
- zlog_debug(
- "Zebra: Graceful Restart in progress -- not uninstalling %pFX",
- p);
+ zlog_debug("Zebra: Graceful Restart in progress -- not uninstalling %pFX(%s)",
+ p, ospf_vrf_id_to_name(ospf->vrf_id));
return;
}
@@ -399,7 +398,8 @@ void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p)
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug("Zebra: Route delete discard %pFX", p);
+ zlog_debug("Zebra: Route delete discard %pFX(%s)", p,
+ ospf_vrf_id_to_name(ospf->vrf_id));
}
struct ospf_external *ospf_external_lookup(struct ospf *ospf, uint8_t type,
@@ -475,8 +475,9 @@ bool ospf_external_default_routemap_apply_walk(struct ospf *ospf,
if (ret && ei) {
if (IS_DEBUG_OSPF_DEFAULT_INFO)
- zlog_debug("Default originate routemap permit ei: %pI4",
- &ei->p.prefix);
+ zlog_debug("Default originate routemap permit ei: %pI4(%s)",
+ &ei->p.prefix,
+ ospf_vrf_id_to_name(ospf->vrf_id));
return true;
}
@@ -507,7 +508,8 @@ static void ospf_external_lsa_default_routemap_timer(struct event *thread)
if (!default_ei) {
/* Nothing to be done here. */
if (IS_DEBUG_OSPF_DEFAULT_INFO)
- zlog_debug("Default originate info not present");
+ zlog_debug("Default originate info not present(%s)",
+ ospf_vrf_id_to_name(ospf->vrf_id));
return;
}
@@ -821,11 +823,11 @@ int ospf_redistribute_update(struct ospf *ospf, struct ospf_redist *red,
ospf_external_lsa_refresh_type(ospf, type, instance, force);
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug(
- "Redistribute[%s][%d]: Refresh Type[%d], Metric[%d]",
- ospf_redist_string(type), instance,
- metric_type(ospf, type, instance),
- metric_value(ospf, type, instance));
+ zlog_debug("Redistribute[%s][%d][%s]: Refresh Type[%d], Metric[%d]",
+ ospf_redist_string(type), instance,
+ ospf_vrf_id_to_name(ospf->vrf_id),
+ metric_type(ospf, type, instance),
+ metric_value(ospf, type, instance));
return CMD_SUCCESS;
}
@@ -842,11 +844,11 @@ int ospf_redistribute_set(struct ospf *ospf, struct ospf_redist *red, int type,
instance, ospf->vrf_id);
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug(
- "Redistribute[%s][%d] vrf id %u: Start Type[%d], Metric[%d]",
- ospf_redist_string(type), instance, ospf->vrf_id,
- metric_type(ospf, type, instance),
- metric_value(ospf, type, instance));
+ zlog_debug("Redistribute[%s][%d][%s]: Start Type[%d], Metric[%d]",
+ ospf_redist_string(type), instance,
+ ospf_vrf_id_to_name(ospf->vrf_id),
+ metric_type(ospf, type, instance),
+ metric_value(ospf, type, instance));
ospf_asbr_status_update(ospf, ++ospf->redistribute);
@@ -863,8 +865,9 @@ int ospf_redistribute_unset(struct ospf *ospf, int type,
instance, ospf->vrf_id);
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug("Redistribute[%s][%d] vrf id %u: Stop",
- ospf_redist_string(type), instance, ospf->vrf_id);
+ zlog_debug("Redistribute[%s][%d][%s]: Stop",
+ ospf_redist_string(type), instance,
+ ospf_vrf_id_to_name(ospf->vrf_id));
/* Remove the routes from OSPF table. */
ospf_redistribute_withdraw(ospf, type, instance);
@@ -894,11 +897,11 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype,
if (cur_originate == originate) {
/* Refresh the lsa since metric might different */
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug(
- "Redistribute[%s]: Refresh Type[%d], Metric[%d]",
- ospf_redist_string(DEFAULT_ROUTE),
- metric_type(ospf, DEFAULT_ROUTE, 0),
- metric_value(ospf, DEFAULT_ROUTE, 0));
+ zlog_debug("Redistribute[%s][%s]: Refresh Type[%d], Metric[%d]",
+ ospf_redist_string(DEFAULT_ROUTE),
+ ospf_vrf_id_to_name(ospf->vrf_id),
+ metric_type(ospf, DEFAULT_ROUTE, 0),
+ metric_value(ospf, DEFAULT_ROUTE, 0));
ospf_external_lsa_refresh_default(ospf);
return CMD_SUCCESS;
@@ -939,10 +942,10 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype,
}
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug("Redistribute[DEFAULT]: %s Type[%d], Metric[%d]",
- type_str,
- metric_type(ospf, DEFAULT_ROUTE, 0),
- metric_value(ospf, DEFAULT_ROUTE, 0));
+ zlog_debug("Redistribute[DEFAULT][%s]: %s Type[%d], Metric[%d]",
+ ospf_vrf_id_to_name(ospf->vrf_id), type_str,
+ metric_type(ospf, DEFAULT_ROUTE, 0),
+ metric_value(ospf, DEFAULT_ROUTE, 0));
ospf_external_lsa_refresh_default(ospf);
ospf_asbr_status_update(ospf, ospf->redistribute);
@@ -1047,16 +1050,18 @@ static bool ospf_external_lsa_default_routemap_apply(struct ospf *ospf,
}
if (IS_DEBUG_OSPF_DEFAULT_INFO)
- zlog_debug("Apply default originate routemap on ei: %pI4 cmd: %d",
- &ei->p.prefix, cmd);
+ zlog_debug("Apply default originate routemap on ei: %pI4(%s) cmd: %d",
+ &ei->p.prefix, ospf_vrf_id_to_name(ospf->vrf_id),
+ cmd);
ret = ospf_external_info_apply_default_routemap(ospf, ei, default_ei);
/* If deny then nothing to be done both in add and del case. */
if (!ret) {
if (IS_DEBUG_OSPF_DEFAULT_INFO)
- zlog_debug("Default originte routemap deny for ei: %pI4",
- &ei->p.prefix);
+ zlog_debug("Default originte routemap deny for ei: %pI4(%s)",
+ &ei->p.prefix,
+ ospf_vrf_id_to_name(ospf->vrf_id));
return false;
}
@@ -1068,12 +1073,14 @@ static bool ospf_external_lsa_default_routemap_apply(struct ospf *ospf,
/* If permit and default already advertise then return. */
if (lsa && !IS_LSA_MAXAGE(lsa)) {
if (IS_DEBUG_OSPF_DEFAULT_INFO)
- zlog_debug("Default lsa already originated");
+ zlog_debug("Default lsa already originated(%s)",
+ ospf_vrf_id_to_name(ospf->vrf_id));
return true;
}
if (IS_DEBUG_OSPF_DEFAULT_INFO)
- zlog_debug("Originating/Refreshing default lsa");
+ zlog_debug("Originating/Refreshing default lsa(%s)",
+ ospf_vrf_id_to_name(ospf->vrf_id));
if (lsa && IS_LSA_MAXAGE(lsa))
/* Refresh lsa.*/
@@ -1088,15 +1095,15 @@ static bool ospf_external_lsa_default_routemap_apply(struct ospf *ospf,
/* If deny and lsa is not originated then nothing to be done.*/
if (!lsa) {
if (IS_DEBUG_OSPF_DEFAULT_INFO)
- zlog_debug(
- "Default lsa not originated, not flushing");
+ zlog_debug("Default lsa not originated, not flushing(%s)",
+ ospf_vrf_id_to_name(ospf->vrf_id));
return true;
}
if (IS_DEBUG_OSPF_DEFAULT_INFO)
- zlog_debug(
- "Running default route-map again as ei: %pI4 deleted",
- &ei->p.prefix);
+ zlog_debug("Running default route-map again as ei: %pI4(%s) deleted",
+ &ei->p.prefix,
+ ospf_vrf_id_to_name(ospf->vrf_id));
/*
* if this route delete was permitted then we need to check
* there are any other external info which can still trigger
@@ -1142,9 +1149,10 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei,
if (access_list_apply(DISTRIBUTE_LIST(ospf, type), p)
== FILTER_DENY) {
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug(
- "Redistribute[%s]: %pFX filtered by distribute-list.",
- ospf_redist_string(type), p);
+ zlog_debug("Redistribute[%s]: %pFX(%s) filtered by distribute-list.",
+ ospf_redist_string(type), p,
+ ospf_vrf_id_to_name(
+ ospf->vrf_id));
return 0;
}
@@ -1165,9 +1173,9 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei,
if (ret == RMAP_DENYMATCH) {
ei->route_map_set = save_values;
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug(
- "Redistribute[%s]: %pFX filtered by route-map.",
- ospf_redist_string(type), p);
+ zlog_debug("Redistribute[%s]: %pFX(%s) filtered by route-map.",
+ ospf_redist_string(type), p,
+ ospf_vrf_id_to_name(ospf->vrf_id));
return 0;
}
@@ -1230,7 +1238,8 @@ static int ospf_zebra_gr_update(struct ospf *ospf, int command,
int ospf_zebra_gr_enable(struct ospf *ospf, uint32_t stale_time)
{
if (IS_DEBUG_OSPF_GR)
- zlog_debug("Zebra enable GR [stale time %u]", stale_time);
+ zlog_debug("Zebra enable GR [stale time %u] vrf %s", stale_time,
+ ospf_vrf_id_to_name(ospf->vrf_id));
return ospf_zebra_gr_update(ospf, ZEBRA_CLIENT_GR_CAPABILITIES,
stale_time);
@@ -1239,7 +1248,8 @@ int ospf_zebra_gr_enable(struct ospf *ospf, uint32_t stale_time)
int ospf_zebra_gr_disable(struct ospf *ospf)
{
if (IS_DEBUG_OSPF_GR)
- zlog_debug("Zebra disable GR");
+ zlog_debug("Zebra disable GR vrf: %s",
+ ospf_vrf_id_to_name(ospf->vrf_id));
return ospf_zebra_gr_update(ospf, ZEBRA_CLIENT_GR_DISABLE, 0);
}
@@ -1286,11 +1296,11 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS)
rt_type = DEFAULT_ROUTE;
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug(
- "%s: cmd %s from client %s: vrf_id %d, p %pFX, metric %d",
- __func__, zserv_command_string(cmd),
- zebra_route_string(api.type), vrf_id, &api.prefix,
- api.metric);
+ zlog_debug("%s: cmd %s from client %s: vrf %s(%u), p %pFX, metric %d",
+ __func__, zserv_command_string(cmd),
+ zebra_route_string(api.type),
+ ospf_vrf_id_to_name(vrf_id), vrf_id, &api.prefix,
+ api.metric);
if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) {
/* XXX|HACK|TODO|FIXME:
@@ -1343,11 +1353,12 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS)
return 0;
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
- zlog_debug(
- "%s: Send Aggreate LSA (%pI4/%d)",
- __func__,
- &aggr->p.prefix,
- aggr->p.prefixlen);
+ zlog_debug("%s: Send Aggreate LSA (%pI4/%d)(%s)",
+ __func__,
+ &aggr->p.prefix,
+ aggr->p.prefixlen,
+ ospf_vrf_id_to_name(
+ ospf->vrf_id));
ospf_originate_summary_lsa(ospf, aggr,
ei);
@@ -1402,10 +1413,11 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS)
if (IS_DEBUG_OSPF(
zebra,
ZEBRA_REDISTRIBUTE))
- zlog_debug(
- "%s: %pI4 refreshing LSA",
- __func__,
- &p.prefix);
+ zlog_debug("%s: %pI4(%s) refreshing LSA",
+ __func__,
+ &p.prefix,
+ ospf_vrf_id_to_name(
+ ospf->vrf_id));
ospf_external_lsa_refresh(
ospf, current, ei,
LSA_REFRESH_FORCE,
@@ -1464,7 +1476,8 @@ void ospf_zebra_import_default_route(struct ospf *ospf, bool unreg)
if (zclient->sock < 0) {
if (IS_DEBUG_OSPF(zebra, ZEBRA))
- zlog_debug(" Not connected to Zebra");
+ zlog_debug(" Not connected to Zebra vrf: %s",
+ ospf_vrf_id_to_name(ospf->vrf_id));
return;
}
@@ -1477,14 +1490,14 @@ void ospf_zebra_import_default_route(struct ospf *ospf, bool unreg)
command = ZEBRA_NEXTHOP_REGISTER;
if (IS_DEBUG_OSPF(zebra, ZEBRA))
- zlog_debug("%s: sending cmd %s for %pFX (vrf %u)", __func__,
+ zlog_debug("%s: sending cmd %s for %pFX(%s)", __func__,
zserv_command_string(command), &prefix,
- ospf->vrf_id);
+ ospf_vrf_id_to_name(ospf->vrf_id));
if (zclient_send_rnh(zclient, command, &prefix, SAFI_UNICAST, false,
true, ospf->vrf_id) == ZCLIENT_SEND_FAILURE)
- flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_send_rnh() failed",
- __func__);
+ flog_err(EC_LIB_ZAPI_SOCKET, "%s(%s): zclient_send_rnh() failed",
+ __func__, ospf_vrf_id_to_name(ospf->vrf_id));
}
static void ospf_zebra_import_check_update(struct vrf *vrf, struct prefix *match,
@@ -1556,7 +1569,8 @@ static void ospf_distribute_list_update_timer(struct event *thread)
ospf->t_distribute_update = NULL;
- zlog_info("Zebra[Redistribute]: distribute-list update timer fired!");
+ zlog_info("Zebra[Redistribute]: vrf: %s distribute-list update timer fired!",
+ ospf_vrf_id_to_name(ospf->vrf_id));
if (IS_DEBUG_OSPF_EVENT) {
zlog_debug("%s: ospf distribute-list update vrf %s id %d",
@@ -1607,10 +1621,12 @@ static void ospf_distribute_list_update_timer(struct event *thread)
lsa,
EXTNL_LSA_AGGR))
zlog_debug(
- "%s: Send Aggregate LSA (%pI4/%d)",
+ "%s: Send Aggregate LSA (%pI4/%d)(%s)",
__func__,
&aggr->p.prefix,
- aggr->p.prefixlen);
+ aggr->p.prefixlen,
+ ospf_vrf_id_to_name(
+ ospf->vrf_id));
/* Originate Aggregate
* LSA
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 1d013b260e..7638e979a2 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -1098,6 +1098,15 @@ struct ospf_interface *add_ospf_interface(struct connected *co,
oi->p2mp_delay_reflood = IF_DEF_PARAMS(co->ifp)->p2mp_delay_reflood;
oi->p2mp_non_broadcast = IF_DEF_PARAMS(co->ifp)->p2mp_non_broadcast;
+ /*
+ * If a neighbor filter is configured, update the neighbor filter
+ * for the interface.
+ */
+ if (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(co->ifp), nbr_filter_name))
+ oi->nbr_filter = prefix_list_lookup(AFI_IP,
+ IF_DEF_PARAMS(co->ifp)
+ ->nbr_filter_name);
+
/* Add pseudo neighbor. */
ospf_nbr_self_reset(oi, oi->ospf->router_id);
diff --git a/pathd/path_cli.c b/pathd/path_cli.c
index e22931c13e..bf8a9ea028 100644
--- a/pathd/path_cli.c
+++ b/pathd/path_cli.c
@@ -131,7 +131,7 @@ DEFPY(show_srte_policy,
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
@@ -1089,9 +1089,7 @@ DEFPY_NOSH(show_debugging_pathd, show_debugging_pathd_cmd,
vty_out(vty, "Path debugging status:\n");
cmd_show_lib_debugs(vty);
- /* nothing to do here */
- path_ted_show_debugging(vty);
- path_policy_show_debugging(vty);
+
return CMD_SUCCESS;
}
@@ -1101,10 +1099,8 @@ DEFPY(debug_path_policy, debug_path_policy_cmd, "[no] debug pathd policy",
"policy debugging\n")
{
uint32_t mode = DEBUG_NODE2MODE(vty->node);
- bool no_debug = no;
DEBUG_MODE_SET(&path_policy_debug, mode, !no);
- DEBUG_FLAGS_SET(&path_policy_debug, PATH_POLICY_DEBUG_BASIC, !no_debug);
return CMD_SUCCESS;
}
@@ -1307,33 +1303,9 @@ int config_write_segment_routing(struct vty *vty)
return 1;
}
-static int path_policy_cli_debug_config_write(struct vty *vty)
-{
- if (DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_CONF)) {
- if (DEBUG_FLAGS_CHECK(&path_policy_debug,
- PATH_POLICY_DEBUG_BASIC))
- vty_out(vty, "debug pathd policy\n");
- return 1;
- }
- return 0;
-}
-
-static int path_policy_cli_debug_set_all(uint32_t flags, bool set)
-{
- DEBUG_FLAGS_SET(&path_policy_debug, flags, set);
-
- /* If all modes have been turned off, don't preserve options. */
- if (!DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_ALL))
- DEBUG_CLEAR(&path_policy_debug);
-
- return 0;
-}
-
void path_cli_init(void)
{
- hook_register(nb_client_debug_config_write,
- path_policy_cli_debug_config_write);
- hook_register(nb_client_debug_set_all, path_policy_cli_debug_set_all);
+ debug_install(&path_policy_debug);
install_node(&segment_routing_node);
install_node(&sr_traffic_eng_node);
diff --git a/pathd/path_pcep.c b/pathd/path_pcep.c
index ec9d8adfc1..a0a53b0d84 100644
--- a/pathd/path_pcep.c
+++ b/pathd/path_pcep.c
@@ -31,7 +31,12 @@ DEFINE_MTYPE(PATHD, PCEP, "PCEP module");
/*
* Globals.
*/
-static struct pcep_glob pcep_glob_space = {.dbg = {0, "pathd module: pcep"}};
+static struct pcep_glob pcep_glob_space = {
+ .dbg_basic = { 0, "debug pathd pcep basic", "PCEP basic" },
+ .dbg_path = { 0, "debug pathd pcep path", "PCEP path" },
+ .dbg_msg = { 0, "debug pathd pcep message", "PCEP message" },
+ .dbg_lib = { 0, "debug pathd pcep pceplib", "PCEP lib" },
+};
struct pcep_glob *pcep_g = &pcep_glob_space;
/* Main Thread Even Handler */
diff --git a/pathd/path_pcep.h b/pathd/path_pcep.h
index d6dbcb5c08..a4f899df58 100644
--- a/pathd/path_pcep.h
+++ b/pathd/path_pcep.h
@@ -27,40 +27,22 @@ DECLARE_MTYPE(PCEP);
#define PCEP_DEBUG_MODE_PCEPLIB 0x08
#define PCEP_DEBUG_MODE_ALL 0x0F
#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)
+ DEBUGD(&pcep_g->dbg_basic, "pcep: " fmt, ##__VA_ARGS__)
#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)
+ DEBUGD(&pcep_g->dbg_path, "pcep: " fmt, ##__VA_ARGS__)
#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)
+ DEBUGD(&pcep_g->dbg_msg, "pcep: " fmt, ##__VA_ARGS__)
#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__); \
+ DEBUGD(&pcep_g->dbg_lib, "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__); \
+ DEBUGI(&pcep_g->dbg_lib, "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__); \
+ DEBUGN(&pcep_g->dbg_lib, "pcep: " fmt, ##__VA_ARGS__); \
break; \
case LOG_WARNING: \
case LOG_ERR: \
@@ -294,7 +276,10 @@ struct path {
};
struct pcep_glob {
- struct debug dbg;
+ struct debug dbg_basic;
+ struct debug dbg_path;
+ struct debug dbg_msg;
+ struct debug dbg_lib;
struct event_loop *master;
struct frr_pthread *fpt;
uint8_t num_pce_opts_cli;
diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c
index 47a811d144..8ceadb3e60 100644
--- a/pathd/path_pcep_cli.c
+++ b/pathd/path_pcep_cli.c
@@ -46,8 +46,6 @@
#define BUFFER_PCC_PCE_SIZE 1024
/* 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);
@@ -110,10 +108,6 @@ 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]";
@@ -463,31 +457,19 @@ static void pcep_cli_remove_pce_connection(struct pce_opts *pce_opts)
* VTY command implementations
*/
-static int path_pcep_cli_debug(struct vty *vty, const char *debug_type, bool set)
+static int path_pcep_cli_debug(struct vty *vty, bool onoff, bool basic,
+ bool path, bool message, bool lib)
{
uint32_t mode = DEBUG_NODE2MODE(vty->node);
- /* Global Set */
- if (debug_type == NULL) {
- DEBUG_MODE_SET(&pcep_g->dbg, mode, set);
- DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_ALL, set);
- return CMD_SUCCESS;
- }
-
- DEBUG_MODE_SET(&pcep_g->dbg, mode, true);
-
- if (strcmp(debug_type, "basic") == 0)
- DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC, set);
- else if (strcmp(debug_type, "path") == 0)
- DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH, set);
- else if (strcmp(debug_type, "message") == 0)
- DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP, set);
- else if (strcmp(debug_type, "pceplib") == 0)
- DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB, set);
-
- /* Unset the pcep debug mode if there is no flag at least set*/
- if (!DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_ALL))
- DEBUG_MODE_SET(&pcep_g->dbg, mode, false);
+ if (basic)
+ DEBUG_MODE_SET(&pcep_g->dbg_basic, mode, onoff);
+ if (path)
+ DEBUG_MODE_SET(&pcep_g->dbg_path, mode, onoff);
+ if (message)
+ DEBUG_MODE_SET(&pcep_g->dbg_msg, mode, onoff);
+ if (lib)
+ DEBUG_MODE_SET(&pcep_g->dbg_lib, mode, onoff);
return CMD_SUCCESS;
}
@@ -1712,42 +1694,6 @@ static int path_pcep_cli_clear_srte_pcep_session(struct vty *vty,
* 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");
@@ -2006,36 +1952,9 @@ int pcep_cli_pcep_pce_config_write(struct vty *vty)
* 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|path|message|pceplib>$debug_type]",
+ "[no] debug pathd pcep [{basic$basic|path$path|message$msg|pceplib$lib}]",
NO_STR DEBUG_STR
"pathd debugging\n"
"pcep module debugging\n"
@@ -2044,7 +1963,11 @@ DEFPY(pcep_cli_debug,
"pcep message debugging\n"
"pceplib debugging\n")
{
- return path_pcep_cli_debug(vty, debug_type, !no);
+ if (strmatch(argv[argc - 1]->text, "pcep"))
+ return path_pcep_cli_debug(vty, !no, true, true, true, true);
+ else
+ return path_pcep_cli_debug(vty, !no, !!basic, !!path, !!msg,
+ !!lib);
}
DEFPY(pcep_cli_show_srte_pcep_counters,
@@ -2372,9 +2295,11 @@ DEFPY(pcep_cli_clear_srte_pcep_session,
void pcep_cli_init(void)
{
hook_register(pathd_srte_config_write, pcep_cli_pcep_config_write);
- hook_register(nb_client_debug_config_write,
- pcep_cli_debug_config_write);
- hook_register(nb_client_debug_set_all, pcep_cli_debug_set_all);
+
+ debug_install(&pcep_g->dbg_basic);
+ debug_install(&pcep_g->dbg_path);
+ debug_install(&pcep_g->dbg_msg);
+ debug_install(&pcep_g->dbg_lib);
memset(&pce_connections_g, 0, sizeof(pce_connections_g));
@@ -2423,7 +2348,6 @@ void pcep_cli_init(void)
/* 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);
diff --git a/pathd/path_ted.c b/pathd/path_ted.c
index df23f93127..0f8d3827ff 100644
--- a/pathd/path_ted.c
+++ b/pathd/path_ted.c
@@ -30,12 +30,11 @@ static uint32_t path_ted_stop_importing_igp(void);
static enum zclient_send_status path_ted_link_state_sync(void);
static void path_ted_timer_handler_sync(struct event *thread);
static void path_ted_timer_handler_refresh(struct event *thread);
-static int path_ted_cli_debug_config_write(struct vty *vty);
-static int path_ted_cli_debug_set_all(uint32_t flags, bool set);
extern struct zclient *zclient;
-struct ted_state ted_state_g = {};
+struct ted_state ted_state_g = { .dbg = { .conf = "debug pathd mpls-te",
+ .desc = "Pathd TED" } };
/*
* path_path_ted public API function implementations
@@ -335,10 +334,8 @@ DEFPY (debug_path_ted,
"ted debugging\n")
{
uint32_t mode = DEBUG_NODE2MODE(vty->node);
- bool no_debug = (no != NULL);
DEBUG_MODE_SET(&ted_state_g.dbg, mode, !no);
- DEBUG_FLAGS_SET(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC, !no_debug);
return CMD_SUCCESS;
}
@@ -466,37 +463,6 @@ DEFPY (show_pathd_ted_db,
return CMD_SUCCESS;
}
-/*
- * Config Write functions
- */
-
-int path_ted_cli_debug_config_write(struct vty *vty)
-{
- if (DEBUG_MODE_CHECK(&ted_state_g.dbg, DEBUG_MODE_CONF)) {
- if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
- vty_out(vty, "debug pathd mpls-te\n");
- return 1;
- }
- return 0;
-}
-
-void path_ted_show_debugging(struct vty *vty)
-{
- if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
- vty_out(vty, " Path TED debugging is on\n");
-}
-
-int path_ted_cli_debug_set_all(uint32_t flags, bool set)
-{
- DEBUG_FLAGS_SET(&ted_state_g.dbg, flags, set);
-
- /* If all modes have been turned off, don't preserve options. */
- if (!DEBUG_MODE_CHECK(&ted_state_g.dbg, DEBUG_MODE_ALL))
- DEBUG_CLEAR(&ted_state_g.dbg);
-
- return 0;
-}
-
/**
* Help fn to show ted related configuration
*
@@ -543,9 +509,7 @@ static void path_ted_register_vty(void)
install_element(CONFIG_NODE, &debug_path_ted_cmd);
install_element(ENABLE_NODE, &debug_path_ted_cmd);
- hook_register(nb_client_debug_config_write,
- path_ted_cli_debug_config_write);
- hook_register(nb_client_debug_set_all, path_ted_cli_debug_set_all);
+ debug_install(&ted_state_g.dbg);
}
/**
diff --git a/pathd/path_ted.h b/pathd/path_ted.h
index a1bc784b7f..7f3b3f590f 100644
--- a/pathd/path_ted.h
+++ b/pathd/path_ted.h
@@ -59,28 +59,17 @@ struct ted_state {
struct debug dbg;
};
/* Debug flags. */
-#define PATH_TED_DEBUG_BASIC 0x01
#define PATH_TED_DEBUG(fmt, ...) \
- do { \
- if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \
- DEBUGD(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \
- } while (0)
+ DEBUGD(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__)
#define PATH_TED_ERROR(fmt, ...) \
- do { \
- if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \
- DEBUGE(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \
- } while (0)
+ DEBUGE(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__)
+
#define PATH_TED_WARN(fmt, ...) \
- do { \
- if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \
- DEBUGW(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \
- } while (0)
+ DEBUGW(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__)
+
#define PATH_TED_INFO(fmt, ...) \
- do { \
- if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \
- DEBUGI(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \
- } while (0)
+ DEBUGI(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__)
/* TED management functions */
bool path_ted_is_initialized(void);
@@ -92,7 +81,6 @@ int path_ted_segment_list_refresh(void);
/* TED configuration functions */
uint32_t path_ted_config_write(struct vty *vty);
-void path_ted_show_debugging(struct vty *vty);
/* TED util functions */
/* clang-format off */
diff --git a/pathd/pathd.c b/pathd/pathd.c
index 9bb7dbae84..431fe4d1e3 100644
--- a/pathd/pathd.c
+++ b/pathd/pathd.c
@@ -33,15 +33,13 @@ DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
(candidate));
-struct debug path_policy_debug;
+struct debug path_policy_debug = {
+ .conf = "debug pathd policy",
+ .desc = "Pathd policy",
+};
#define PATH_POLICY_DEBUG(fmt, ...) \
- do { \
- if (DEBUG_FLAGS_CHECK(&path_policy_debug, \
- PATH_POLICY_DEBUG_BASIC)) \
- DEBUGD(&path_policy_debug, "policy: " fmt, \
- ##__VA_ARGS__); \
- } while (0)
+ DEBUGD(&path_policy_debug, "policy: " fmt, ##__VA_ARGS__)
static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
@@ -1281,12 +1279,6 @@ const char *srte_origin2str(enum srte_protocol_origin origin)
assert(!"Reached end of function we should never hit");
}
-void path_policy_show_debugging(struct vty *vty)
-{
- if (DEBUG_FLAGS_CHECK(&path_policy_debug, PATH_POLICY_DEBUG_BASIC))
- vty_out(vty, " Path policy debugging is on\n");
-}
-
void pathd_shutdown(void)
{
path_ted_teardown();
diff --git a/pathd/pathd.h b/pathd/pathd.h
index 73ad49226e..75e7eff920 100644
--- a/pathd/pathd.h
+++ b/pathd/pathd.h
@@ -32,8 +32,6 @@ enum srte_protocol_origin {
extern struct debug path_policy_debug;
-#define PATH_POLICY_DEBUG_BASIC 0x01
-
enum srte_policy_status {
SRTE_POLICY_STATUS_UNKNOWN = 0,
SRTE_POLICY_STATUS_DOWN = 1,
@@ -437,7 +435,6 @@ void srte_candidate_status_update(struct srte_candidate *candidate, int status);
void srte_candidate_unset_segment_list(const char *originator, bool force);
const char *srte_origin2str(enum srte_protocol_origin origin);
void pathd_shutdown(void);
-void path_policy_show_debugging(struct vty *vty);
/* path_cli.c */
void path_cli_init(void);
diff --git a/pbrd/pbr_debug.c b/pbrd/pbr_debug.c
index b30b54b7f0..6b0d1d5a81 100644
--- a/pbrd/pbr_debug.c
+++ b/pbrd/pbr_debug.c
@@ -13,53 +13,16 @@
#include "pbrd/pbr_debug_clippy.c"
#include "pbrd/pbr_debug.h"
-struct debug pbr_dbg_map = {0, "PBR map"};
-struct debug pbr_dbg_zebra = {0, "PBR Zebra communications"};
-struct debug pbr_dbg_nht = {0, "PBR nexthop tracking"};
-struct debug pbr_dbg_event = {0, "PBR events"};
-
-struct debug *pbr_debugs[] = {&pbr_dbg_map, &pbr_dbg_zebra, &pbr_dbg_nht,
- &pbr_dbg_event};
-
-const char *pbr_debugs_conflines[] = {
- "debug pbr map",
- "debug pbr zebra",
- "debug pbr nht",
- "debug pbr events",
-};
-
-void pbr_debug_set_all(uint32_t flags, bool set)
-{
- for (unsigned int i = 0; i < array_size(pbr_debugs); i++) {
- DEBUG_FLAGS_SET(pbr_debugs[i], flags, set);
-
- /* if all modes have been turned off, don't preserve options */
- if (!DEBUG_MODE_CHECK(pbr_debugs[i], DEBUG_MODE_ALL))
- DEBUG_CLEAR(pbr_debugs[i]);
- }
-}
-
-int pbr_debug_config_write_helper(struct vty *vty, bool config)
-{
- uint32_t mode = DEBUG_MODE_ALL;
-
- if (config)
- mode = DEBUG_MODE_CONF;
-
- for (unsigned int i = 0; i < array_size(pbr_debugs); i++)
- if (DEBUG_MODE_CHECK(pbr_debugs[i], mode))
- vty_out(vty, "%s\n", pbr_debugs_conflines[i]);
- return 0;
-}
-
-int pbr_debug_config_write(struct vty *vty)
-{
- return pbr_debug_config_write_helper(vty, true);
-}
-
-struct debug_callbacks pbr_dbg_cbs = {.debug_set_all = pbr_debug_set_all};
+struct debug pbr_dbg_map = { 0, "debug pbr map", "PBR map" };
+struct debug pbr_dbg_zebra = { 0, "debug pbr zebra",
+ "PBR Zebra communications" };
+struct debug pbr_dbg_nht = { 0, "debug pbr nht", "PBR nexthop tracking" };
+struct debug pbr_dbg_event = { 0, "debug pbr events", "PBR events" };
void pbr_debug_init(void)
{
- debug_init(&pbr_dbg_cbs);
+ debug_install(&pbr_dbg_map);
+ debug_install(&pbr_dbg_zebra);
+ debug_install(&pbr_dbg_nht);
+ debug_install(&pbr_dbg_event);
}
diff --git a/pbrd/pbr_debug.h b/pbrd/pbr_debug.h
index 09109971d2..c1ffce99b8 100644
--- a/pbrd/pbr_debug.h
+++ b/pbrd/pbr_debug.h
@@ -35,26 +35,4 @@ void pbr_debug_init(void);
*/
void pbr_debug_set_all(uint32_t flags, bool set);
-/*
- * Config write helper.
- *
- * vty
- * Vty to write to
- *
- * config
- * Whether we are writing to show run or saving config file
- *
- * Returns:
- * 0 for convenience
- */
-int pbr_debug_config_write_helper(struct vty *vty, bool config);
-
-/*
- * Print PBR debugging configuration.
- *
- * vty
- * VTY to print debugging configuration to.
- */
-int pbr_debug_config_write(struct vty *vty);
-
#endif /* __PBR_DEBUG_H__ */
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index 64d88847c8..08fe56c7bb 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -1954,13 +1954,6 @@ DEFPY (show_pbr_interface,
/* PBR debugging CLI ------------------------------------------------------- */
-static struct cmd_node debug_node = {
- .name = "debug",
- .node = DEBUG_NODE,
- .prompt = "",
- .config_write = pbr_debug_config_write,
-};
-
DEFPY(debug_pbr,
debug_pbr_cmd,
"[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
@@ -1973,20 +1966,21 @@ DEFPY(debug_pbr,
"Events\n")
{
uint32_t mode = DEBUG_NODE2MODE(vty->node);
+ bool all = false;
+
+ /* no specific debug --> act on all of them */
+ if (strmatch(argv[argc - 1]->text, "pbr"))
+ all = true;
- if (map)
+ if (map || all)
DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
- if (zebra)
+ if (zebra || all)
DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
- if (nht)
+ if (nht || all)
DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
- if (events)
+ if (events || all)
DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
- /* no specific debug --> act on all of them */
- if (strmatch(argv[argc - 1]->text, "pbr"))
- pbr_debug_set_all(mode, !no);
-
return CMD_SUCCESS;
}
@@ -1999,8 +1993,6 @@ DEFUN_NOSH(show_debugging_pbr,
{
vty_out(vty, "PBR debugging status:\n");
- pbr_debug_config_write_helper(vty, false);
-
cmd_show_lib_debugs(vty);
return CMD_SUCCESS;
@@ -2194,7 +2186,6 @@ void pbr_vty_init(void)
install_node(&pbr_map_node);
/* debug */
- install_node(&debug_node);
install_element(ENABLE_NODE, &debug_pbr_cmd);
install_element(CONFIG_NODE, &debug_pbr_cmd);
install_element(ENABLE_NODE, &show_debugging_pbr_cmd);
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c
index 99f1474712..f1ebdb554c 100644
--- a/pimd/pim6_cmd.c
+++ b/pimd/pim6_cmd.c
@@ -1259,6 +1259,62 @@ DEFPY (no_ipv6_pim_ucast_bsm,
return pim_process_no_unicast_bsm_cmd(vty);
}
+DEFPY (pim6_bsr_candidate_bsr,
+ pim6_bsr_candidate_bsr_cmd,
+ "[no] bsr candidate-bsr [{priority (0-255)|source <address X:X::X:X|interface IFNAME|loopback$loopback|any$any>}]",
+ NO_STR
+ BSR_STR
+ "Make this router a Candidate BSR\n"
+ "BSR Priority (higher wins)\n"
+ "BSR Priority (higher wins)\n"
+ "Specify IP address for BSR operation\n"
+ "Local address to use\n"
+ "Local address to use\n"
+ "Interface to pick address from\n"
+ "Interface to pick address from\n"
+ "Pick highest loopback address (default)\n"
+ "Pick highest address from any interface\n")
+{
+ return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_BSR_XPATH, no,
+ false, any, ifname, address_str,
+ priority_str, NULL);
+}
+
+DEFPY (pim6_bsr_candidate_rp,
+ pim6_bsr_candidate_rp_cmd,
+ "[no] bsr candidate-rp [{priority (0-255)|interval (1-4294967295)|source <address X:X::X:X|interface IFNAME|loopback$loopback|any$any>}]",
+ NO_STR
+ "Bootstrap Router configuration\n"
+ "Make this router a Candidate RP\n"
+ "RP Priority (lower wins)\n"
+ "RP Priority (lower wins)\n"
+ "Advertisement interval (seconds)\n"
+ "Advertisement interval (seconds)\n"
+ "Specify IP address for RP operation\n"
+ "Local address to use\n"
+ "Local address to use\n"
+ "Interface to pick address from\n"
+ "Interface to pick address from\n"
+ "Pick highest loopback address (default)\n"
+ "Pick highest address from any interface\n")
+{
+ return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_RP_XPATH, no,
+ true, any, ifname, address_str,
+ priority_str, interval_str);
+}
+
+DEFPY (pim6_bsr_candidate_rp_group,
+ pim6_bsr_candidate_rp_group_cmd,
+ "[no] bsr candidate-rp group X:X::X:X/M",
+ NO_STR
+ "Bootstrap Router configuration\n"
+ "Make this router a Candidate RP\n"
+ "Configure groups to become candidate RP for\n"
+ "Multicast group prefix\n")
+{
+ return pim_process_bsr_crp_grp_cmd(vty, group_str, no);
+}
+
DEFPY (pim6_ssmpingd,
pim6_ssmpingd_cmd,
"ssmpingd [X:X::X:X]$source",
@@ -1363,45 +1419,56 @@ DEFPY_ATTR(no_ipv6_ssmpingd,
return ret;
}
-DEFPY (interface_ipv6_mld_join,
- interface_ipv6_mld_join_cmd,
- "ipv6 mld join X:X::X:X$group [X:X::X:X$source]",
+DEFPY_YANG_HIDDEN (interface_ipv6_mld_join,
+ interface_ipv6_mld_join_cmd,
+ "[no] ipv6 mld join X:X::X:X$grp [X:X::X:X]$src",
+ NO_STR
+ IPV6_STR
+ IFACE_MLD_STR
+ "MLD join multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
+{
+ nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+ NULL);
+ return nb_cli_apply_changes(vty, FRR_GMP_JOIN_GROUP_XPATH,
+ "frr-routing:ipv6", grp_str,
+ (src_str ? src_str : "::"));
+}
+ALIAS (interface_ipv6_mld_join,
+ interface_ipv6_mld_join_group_cmd,
+ "[no] ipv6 mld join-group X:X::X:X$grp [X:X::X:X]$src",
+ NO_STR
IPV6_STR
IFACE_MLD_STR
"MLD join multicast group\n"
"Multicast group address\n"
- "Source address\n")
-{
- char xpath[XPATH_MAXLEN];
-
- if (!IN6_IS_ADDR_MULTICAST(&group)) {
- vty_out(vty, "Invalid Multicast Address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (source_str) {
- if (IPV6_ADDR_SAME(&source, &in6addr_any)) {
- vty_out(vty, "Bad source address %s\n", source_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- } else
- source_str = "::";
-
- snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv6",
- group_str, source_str);
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
-}
-
-DEFPY (interface_no_ipv6_mld_join,
- interface_no_ipv6_mld_join_cmd,
- "no ipv6 mld join X:X::X:X$group [X:X::X:X$source]",
+ "Source address\n");
+
+DEFPY_YANG (interface_ipv6_mld_static_group,
+ interface_ipv6_mld_static_group_cmd,
+ "[no] ipv6 mld static-group X:X::X:X$grp [X:X::X:X]$src",
+ NO_STR
+ IPV6_STR
+ IFACE_MLD_STR
+ "Static multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
+{
+ nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+ NULL);
+ return nb_cli_apply_changes(vty, FRR_GMP_STATIC_GROUP_XPATH,
+ "frr-routing:ipv6", grp_str,
+ (src_str ? src_str : "::"));
+}
+
+DEFPY (interface_no_ipv6_mld_static_group,
+ interface_no_ipv6_mld_static_group_cmd,
+ "no ipv6 mld static-group X:X::X:X$group [X:X::X:X$source]",
NO_STR
IPV6_STR
IFACE_MLD_STR
- "MLD join multicast group\n"
+ "Static multicast group\n"
"Multicast group address\n"
"Source address\n")
{
@@ -1415,8 +1482,8 @@ DEFPY (interface_no_ipv6_mld_join,
} else
source_str = "::";
- snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv6",
- group_str, source_str);
+ snprintf(xpath, sizeof(xpath), FRR_GMP_STATIC_GROUP_XPATH,
+ "frr-routing:ipv6", group_str, source_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -1708,6 +1775,90 @@ DEFPY (show_ipv6_pim_secondary,
return pim_show_secondary_helper(vrf, vty);
}
+DEFPY (show_ipv6_pim_bsr_cand_bsr,
+ show_ipv6_pim_bsr_cand_bsr_cmd,
+ "show ipv6 pim bsr candidate-bsr [vrf NAME$vrfname] [json$json]",
+ SHOW_STR
+ IPV6_STR
+ PIM_STR
+ BSR_STR
+ "Current PIM router candidate BSR state\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, !!json);
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+ return pim_show_bsr_cand_bsr(vrf, vty, !!json);
+}
+
+DEFPY (show_ipv6_pim_bsr_cand_rp,
+ show_ipv6_pim_bsr_cand_rp_cmd,
+ "show ipv6 pim bsr candidate-rp [vrf VRF_NAME] [json$json]",
+ SHOW_STR
+ IPV6_STR
+ PIM_STR
+ BSR_STR
+ "Current PIM router candidate RP state\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ struct vrf *vrf = pim_cmd_lookup(vty, vrf_name);
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+ return pim_show_bsr_cand_rp(vrf, vty, !!json);
+}
+
+DEFPY (show_ipv6_pim_bsr_rpdb,
+ show_ipv6_pim_bsr_rpdb_cmd,
+ "show ipv6 pim bsr candidate-rp-database [vrf VRF_NAME] [json$json]",
+ SHOW_STR
+ IPV6_STR
+ PIM_STR
+ BSR_STR
+ "Candidate RPs database on this router (if it is the BSR)\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ struct vrf *vrf = pim_cmd_lookup(vty, vrf_name);
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+ struct pim_instance *pim = vrf->info;
+ struct bsm_scope *scope = &pim->global_scope;
+
+ return pim_crp_db_show(vty, scope, !!json);
+}
+
+DEFPY (show_ipv6_pim_bsr_groups,
+ show_ipv6_pim_bsr_groups_cmd,
+ "show ipv6 pim bsr groups [vrf VRF_NAME] [json$json]",
+ SHOW_STR
+ IPV6_STR
+ PIM_STR
+ "boot-strap router information\n"
+ "Candidate RP groups\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ struct vrf *vrf = pim_cmd_lookup(vty, vrf_name);
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+ struct pim_instance *pim = vrf->info;
+ struct bsm_scope *scope = &pim->global_scope;
+
+ return pim_crp_groups_show(vty, scope, !!json);
+}
+
+
DEFPY (show_ipv6_pim_statistics,
show_ipv6_pim_statistics_cmd,
"show ipv6 pim [vrf NAME] statistics [interface WORD$word] [json$json]",
@@ -2639,6 +2790,9 @@ void pim_cmd_init(void)
install_element(PIM6_NODE, &no_pim6_rp_prefix_list_cmd);
install_element(PIM6_NODE, &pim6_ssmpingd_cmd);
install_element(PIM6_NODE, &no_pim6_ssmpingd_cmd);
+ install_element(PIM6_NODE, &pim6_bsr_candidate_rp_cmd);
+ install_element(PIM6_NODE, &pim6_bsr_candidate_rp_group_cmd);
+ install_element(PIM6_NODE, &pim6_bsr_candidate_bsr_cmd);
install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd);
install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd);
@@ -2669,7 +2823,8 @@ void pim_cmd_init(void)
install_element(INTERFACE_NODE, &interface_ipv6_mld_cmd);
install_element(INTERFACE_NODE, &interface_no_ipv6_mld_cmd);
install_element(INTERFACE_NODE, &interface_ipv6_mld_join_cmd);
- install_element(INTERFACE_NODE, &interface_no_ipv6_mld_join_cmd);
+ install_element(INTERFACE_NODE, &interface_ipv6_mld_join_group_cmd);
+ install_element(INTERFACE_NODE, &interface_ipv6_mld_static_group_cmd);
install_element(INTERFACE_NODE, &interface_ipv6_mld_version_cmd);
install_element(INTERFACE_NODE, &interface_no_ipv6_mld_version_cmd);
install_element(INTERFACE_NODE, &interface_ipv6_mld_query_interval_cmd);
@@ -2693,6 +2848,10 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ipv6_pim_rpf_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_rpf_vrf_all_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_secondary_cmd);
+ install_element(VIEW_NODE, &show_ipv6_pim_bsr_cand_bsr_cmd);
+ install_element(VIEW_NODE, &show_ipv6_pim_bsr_cand_rp_cmd);
+ install_element(VIEW_NODE, &show_ipv6_pim_bsr_rpdb_cmd);
+ install_element(VIEW_NODE, &show_ipv6_pim_bsr_groups_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_statistics_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_upstream_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_upstream_vrf_all_cmd);
diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c
index 24443404eb..07b70ae2b3 100644
--- a/pimd/pim6_main.c
+++ b/pimd/pim6_main.c
@@ -103,6 +103,7 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = {
&frr_routing_info,
&frr_pim_info,
&frr_pim_rp_info,
+ &frr_pim_candidate_info,
&frr_gmp_info,
};
diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c
index a39d182990..a871837701 100644
--- a/pimd/pim6_mld.c
+++ b/pimd/pim6_mld.c
@@ -62,7 +62,6 @@ static void gm_sg_timer_start(struct gm_if *gm_ifp, struct gm_sg *sg,
sg->iface->ifp->name, &sg->sgaddr
/* clang-format off */
-#if PIM_IPV == 6
static const pim_addr gm_all_hosts = {
.s6_addr = {
0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -84,13 +83,6 @@ static const pim_addr gm_dummy_untracked = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
},
};
-#else
-/* 224.0.0.1 */
-static const pim_addr gm_all_hosts = { .s_addr = htonl(0xe0000001), };
-/* 224.0.0.22 */
-static const pim_addr gm_all_routers = { .s_addr = htonl(0xe0000016), };
-static const pim_addr gm_dummy_untracked = { .s_addr = 0xffffffff, };
-#endif
/* clang-format on */
#define IPV6_MULTICAST_SCOPE_LINK 2
@@ -2537,7 +2529,7 @@ static void gm_show_if_vrf(struct vty *vty, struct vrf *vrf, const char *ifname,
if (!js && !detail) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -3021,7 +3013,7 @@ static void gm_show_groups(struct vty *vty, struct vrf *vrf, bool uj)
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
diff --git a/pimd/pim_autorp.c b/pimd/pim_autorp.c
new file mode 100644
index 0000000000..35347a2790
--- /dev/null
+++ b/pimd/pim_autorp.c
@@ -0,0 +1,1163 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * pim_autorp.c: PIM AutoRP handling routines
+ *
+ * Copyright (C) 2024 ATCorp
+ * Nathan Bahr
+ */
+
+#include <zebra.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "lib/plist.h"
+#include "lib/plist_int.h"
+#include "lib/sockopt.h"
+#include "lib/network.h"
+#include "lib/termtable.h"
+#include "lib/json.h"
+
+#include "pimd.h"
+#include "pim_iface.h"
+#include "pim_rp.h"
+#include "pim_sock.h"
+#include "pim_instance.h"
+#include "pim_autorp.h"
+
+DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP, "PIM AutoRP info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP_RP, "PIM AutoRP advertised RP info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP_CRP, "PIM AutoRP candidate RP info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP_ANNOUNCE, "PIM AutoRP announcement packet");
+
+static const char *PIM_AUTORP_ANNOUNCEMENT_GRP = "224.0.1.39";
+static const char *PIM_AUTORP_DISCOVERY_GRP = "224.0.1.40";
+static const in_port_t PIM_AUTORP_PORT = 496;
+
+static int pim_autorp_rp_cmp(const struct pim_autorp_rp *l,
+ const struct pim_autorp_rp *r)
+{
+ return pim_addr_cmp(l->addr, r->addr);
+}
+
+DECLARE_SORTLIST_UNIQ(pim_autorp_rp, struct pim_autorp_rp, list,
+ pim_autorp_rp_cmp);
+
+static void pim_autorp_rp_free(struct pim_autorp_rp *rp)
+{
+ event_cancel(&rp->hold_timer);
+
+ /* Clean up installed RP info */
+ if (pim_rp_del(rp->autorp->pim, rp->addr, rp->grp,
+ (strlen(rp->grplist) ? rp->grplist : NULL),
+ RP_SRC_AUTORP))
+ if (PIM_DEBUG_AUTORP)
+ zlog_err("%s: Failed to delete RP %pI4", __func__,
+ &rp->addr);
+
+ XFREE(MTYPE_PIM_AUTORP_RP, rp);
+}
+
+static void pim_autorp_rplist_free(struct pim_autorp_rp_head *head)
+{
+ struct pim_autorp_rp *rp;
+
+ while ((rp = pim_autorp_rp_pop(head)))
+ pim_autorp_rp_free(rp);
+}
+
+static void pim_autorp_rplist_cfree(struct pim_autorp_rp_head *head)
+{
+ struct pim_autorp_rp *rp;
+
+ while ((rp = pim_autorp_rp_pop(head)))
+ XFREE(MTYPE_PIM_AUTORP_CRP, rp);
+}
+
+static void pim_autorp_free(struct pim_autorp *autorp)
+{
+ pim_autorp_rplist_free(&(autorp->discovery_rp_list));
+ pim_autorp_rp_fini(&(autorp->discovery_rp_list));
+
+ pim_autorp_rplist_cfree(&(autorp->candidate_rp_list));
+ pim_autorp_rp_fini(&(autorp->candidate_rp_list));
+}
+
+static bool pim_autorp_join_groups(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp;
+ struct pim_instance *pim;
+ struct pim_autorp *autorp;
+ pim_addr grp;
+
+ pim_ifp = ifp->info;
+ pim = pim_ifp->pim;
+ autorp = pim->autorp;
+
+ inet_pton(PIM_AF, PIM_AUTORP_DISCOVERY_GRP, &grp);
+ if (pim_socket_join(autorp->sock, grp, pim_ifp->primary_address,
+ ifp->ifindex, pim_ifp)) {
+ zlog_err("Failed to join group %pI4 on interface %s", &grp,
+ ifp->name);
+ return false;
+ }
+
+ /* TODO: Future Mapping agent implementation
+ * Join announcement group for AutoRP mapping agent
+ * inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &grp);
+ * if (pim_socket_join(pim->autorp->sock, grp,
+ * pim_ifp->primary_address,
+ * ifp->ifindex, pim_ifp)) {
+ * zlog_err("Failed to join group %pI4 on interface %s",
+ * &grp, ifp->name);
+ * return errno;
+ * }
+ */
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: Joined AutoRP groups on interface %s", __func__,
+ ifp->name);
+
+ return true;
+}
+
+static bool pim_autorp_leave_groups(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp;
+ struct pim_instance *pim;
+ struct pim_autorp *autorp;
+ pim_addr grp;
+
+ pim_ifp = ifp->info;
+ pim = pim_ifp->pim;
+ autorp = pim->autorp;
+
+ inet_pton(PIM_AF, PIM_AUTORP_DISCOVERY_GRP, &grp);
+ if (pim_socket_leave(autorp->sock, grp, pim_ifp->primary_address,
+ ifp->ifindex, pim_ifp)) {
+ zlog_err("Failed to leave group %pI4 on interface %s", &grp,
+ ifp->name);
+ return false;
+ }
+
+ /* TODO: Future Mapping agent implementation
+ * Leave announcement group for AutoRP mapping agent
+ * inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &grp);
+ * if (pim_socket_leave(pim->autorp->sock, grp,
+ * pim_ifp->primary_address,
+ * ifp->ifindex, pim_ifp)) {
+ * zlog_err("Failed to leave group %pI4 on interface %s",
+ * &grp, ifp->name);
+ * return errno;
+ * }
+ */
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: Left AutoRP groups on interface %s", __func__,
+ ifp->name);
+
+ return true;
+}
+
+static bool pim_autorp_setup(struct pim_autorp *autorp)
+{
+#if defined(HAVE_IP_PKTINFO)
+ int data;
+ socklen_t data_len = sizeof(data);
+#endif
+
+ struct sockaddr_in autorp_addr = { .sin_family = AF_INET,
+ .sin_addr = { .s_addr = INADDR_ANY },
+ .sin_port = htons(PIM_AUTORP_PORT) };
+
+ setsockopt_so_recvbuf(autorp->sock, 1024 * 1024 * 8);
+
+#if defined(HAVE_IP_PKTINFO)
+ /* Linux and Solaris IP_PKTINFO */
+ data = 1;
+ if (setsockopt(autorp->sock, PIM_IPPROTO, IP_PKTINFO, &data, data_len)) {
+ zlog_err("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
+ autorp->sock, errno, safe_strerror(errno));
+ return false;
+ }
+#endif
+
+ if (set_nonblocking(autorp->sock) < 0) {
+ zlog_err("Could not set non blocking on socket fd=%d: errno=%d: %s",
+ autorp->sock, errno, safe_strerror(errno));
+ return false;
+ }
+
+ if (sockopt_reuseaddr(autorp->sock)) {
+ zlog_err("Could not set reuse addr on socket fd=%d: errno=%d: %s",
+ autorp->sock, errno, safe_strerror(errno));
+ return false;
+ }
+
+ if (bind(autorp->sock, (const struct sockaddr *)&autorp_addr,
+ sizeof(autorp_addr)) < 0) {
+ zlog_err("Could not bind socket: %pSUp, fd=%d, errno=%d, %s",
+ (union sockunion *)&autorp_addr, autorp->sock, errno,
+ safe_strerror(errno));
+ return false;
+ }
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP finished setup", __func__);
+
+ return true;
+}
+
+static bool pim_autorp_announcement(struct pim_autorp *autorp, uint8_t rpcnt,
+ uint16_t holdtime, char *buf,
+ size_t buf_size)
+{
+ /* TODO: Future Mapping agent implementation
+ * Implement AutoRP mapping agent logic using received announcement messages
+ */
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP processed announcement message",
+ __func__);
+ return true;
+}
+
+static void autorp_rp_holdtime(struct event *evt)
+{
+ /* RP hold time expired, remove the RP */
+ struct pim_autorp_rp *rp = EVENT_ARG(evt);
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP hold time expired, RP removed: addr=%pI4, grp=%pFX, grplist=%s",
+ __func__, &rp->addr, &rp->grp,
+ (strlen(rp->grplist) ? rp->grplist : "NONE"));
+
+ pim_autorp_rp_del(&(rp->autorp->discovery_rp_list), rp);
+ pim_autorp_rp_free(rp);
+}
+
+static bool pim_autorp_add_rp(struct pim_autorp *autorp, pim_addr rpaddr,
+ struct prefix grp, char *listname,
+ uint16_t holdtime)
+{
+ struct pim_autorp_rp *rp;
+ struct pim_autorp_rp *trp = NULL;
+
+ if (pim_rp_new(autorp->pim, rpaddr, grp, listname, RP_SRC_AUTORP)) {
+ zlog_err("%s: Failed to add new RP addr=%pI4, grp=%pFX, grplist=%s",
+ __func__, &rpaddr, &grp,
+ (listname ? listname : "NONE"));
+ return false;
+ }
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: Added new AutoRP learned RP addr=%pI4, grp=%pFX, grplist=%s",
+ __func__, &rpaddr, &grp,
+ (listname ? listname : "NONE"));
+
+ rp = XCALLOC(MTYPE_PIM_AUTORP_RP, sizeof(*rp));
+ rp->autorp = autorp;
+ memcpy(&(rp->addr), &rpaddr, sizeof(pim_addr));
+ prefix_copy(&(rp->grp), &grp);
+ if (listname)
+ snprintf(rp->grplist, sizeof(rp->grplist), "%s", listname);
+ else
+ rp->grplist[0] = '\0';
+
+ rp->holdtime = holdtime;
+ rp->hold_timer = NULL;
+ trp = pim_autorp_rp_add(&(autorp->discovery_rp_list), rp);
+ if (trp == NULL) {
+ /* RP was brand new */
+ trp = pim_autorp_rp_find(&(autorp->discovery_rp_list),
+ (const struct pim_autorp_rp *)rp);
+ } else {
+ /* RP already existed */
+ XFREE(MTYPE_PIM_AUTORP_RP, rp);
+ event_cancel(&trp->hold_timer);
+
+ /* We know the address matches, but these values may have changed */
+ trp->holdtime = holdtime;
+ prefix_copy(&(trp->grp), &grp);
+ if (listname) {
+ snprintf(trp->grplist, sizeof(trp->grplist), "%s",
+ listname);
+ } else {
+ trp->grplist[0] = '\0';
+ }
+ }
+
+ if (holdtime > 0) {
+ event_add_timer(router->master, autorp_rp_holdtime, trp,
+ holdtime, &(trp->hold_timer));
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: Started %u second hold timer for RP %pI4", __func__,
+ holdtime, &trp->addr);
+ } else {
+ /* If hold time is zero, make sure there doesn't exist a hold timer for it already */
+ event_cancel(&trp->hold_timer);
+ }
+
+ return true;
+}
+
+static bool pim_autorp_discovery(struct pim_autorp *autorp, uint8_t rpcnt,
+ uint16_t holdtime, char *buf, size_t buf_size)
+{
+ int i, j;
+ struct autorp_pkt_rp *rp;
+ struct autorp_pkt_grp *grp;
+ size_t offset = 0;
+ pim_addr rp_addr;
+ struct prefix grppfix;
+ char plname[32];
+ struct prefix_list *pl;
+ struct prefix_list_entry *ple;
+ int64_t seq = 1;
+ bool success = true;
+
+ for (i = 0; i < rpcnt; ++i) {
+ if ((buf_size - offset) < AUTORP_RPLEN)
+ return false;
+
+ rp = (struct autorp_pkt_rp *)(buf + offset);
+ offset += AUTORP_RPLEN;
+
+ rp_addr.s_addr = rp->addr;
+
+ /* Ignore RP's limited to PIM version 1 or with an unknown version */
+ if (rp->pimver == PIM_V1 || rp->pimver == PIM_VUNKNOWN) {
+ zlog_warn("%s: Ignoring unsupported PIM version in AutoRP Discovery for RP %pI4",
+ __func__, (in_addr_t *)&(rp->addr));
+ /* Update the offset to skip past the groups advertised for this RP */
+ offset += (AUTORP_GRPLEN * rp->grpcnt);
+ continue;
+ }
+
+
+ if (rp->grpcnt == 0) {
+ /* No groups?? */
+ zlog_warn("%s: Discovery message has no groups for RP %pI4",
+ __func__, (in_addr_t *)&(rp->addr));
+ continue;
+ }
+
+ if ((buf_size - offset) < AUTORP_GRPLEN) {
+ zlog_warn("%s: Buffer underrun parsing groups for RP %pI4",
+ __func__, (in_addr_t *)&(rp->addr));
+ return false;
+ }
+
+ grp = (struct autorp_pkt_grp *)(buf + offset);
+ offset += AUTORP_GRPLEN;
+
+ if (rp->grpcnt == 1 && grp->negprefix == 0) {
+ /* Only one group with positive prefix, we can use the standard RP API */
+ grppfix.family = AF_INET;
+ grppfix.prefixlen = grp->masklen;
+ grppfix.u.prefix4.s_addr = grp->addr;
+ if (!pim_autorp_add_rp(autorp, rp_addr, grppfix, NULL,
+ holdtime))
+ success = false;
+ } else {
+ /* More than one grp, or the only group is a negative prefix, need to make a prefix list for this RP */
+ snprintfrr(plname, sizeof(plname), "__AUTORP_%pI4__",
+ &rp_addr);
+ pl = prefix_list_get(AFI_IP, 0, plname);
+
+ for (j = 0; j < rp->grpcnt; ++j) {
+ /* grp is already pointing at the first group in the buffer */
+ ple = prefix_list_entry_new();
+ ple->pl = pl;
+ ple->seq = seq;
+ seq += 5;
+ memset(&ple->prefix, 0, sizeof(ple->prefix));
+ prefix_list_entry_update_start(ple);
+ ple->type = (grp->negprefix ? PREFIX_DENY
+ : PREFIX_PERMIT);
+ ple->prefix.family = AF_INET;
+ ple->prefix.prefixlen = grp->masklen;
+ ple->prefix.u.prefix4.s_addr = grp->addr;
+ ple->any = false;
+ ple->ge = 0;
+ ple->le = 32;
+ prefix_list_entry_update_finish(ple);
+
+ if ((buf_size - offset) < AUTORP_GRPLEN)
+ return false;
+
+ grp = (struct autorp_pkt_grp *)(buf + offset);
+ offset += AUTORP_GRPLEN;
+ }
+
+ if (!pim_autorp_add_rp(autorp, rp_addr, grppfix, plname,
+ holdtime))
+ success = false;
+ }
+ }
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: Processed AutoRP Discovery message", __func__);
+
+ return success;
+}
+
+static bool pim_autorp_msg(struct pim_autorp *autorp, char *buf, size_t buf_size)
+{
+ struct autorp_pkt_hdr *h;
+
+ if (buf_size < AUTORP_HDRLEN)
+ return false;
+
+ h = (struct autorp_pkt_hdr *)buf;
+
+ if (h->version != AUTORP_VERSION)
+ return false;
+
+ if (h->type == AUTORP_ANNOUNCEMENT_TYPE &&
+ !pim_autorp_announcement(autorp, h->rpcnt, htons(h->holdtime),
+ buf + AUTORP_HDRLEN,
+ buf_size - AUTORP_HDRLEN))
+ return false;
+
+ if (h->type == AUTORP_DISCOVERY_TYPE &&
+ !pim_autorp_discovery(autorp, h->rpcnt, htons(h->holdtime),
+ buf + AUTORP_HDRLEN, buf_size - AUTORP_HDRLEN))
+ return false;
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: Processed AutoRP packet", __func__);
+
+ return true;
+}
+
+static void autorp_read(struct event *t);
+
+static void autorp_read_on(struct pim_autorp *autorp)
+{
+ event_add_read(router->master, autorp_read, autorp, autorp->sock,
+ &(autorp->read_event));
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP socket read enabled", __func__);
+}
+
+static void autorp_read_off(struct pim_autorp *autorp)
+{
+ event_cancel(&(autorp->read_event));
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP socket read disabled", __func__);
+}
+
+static void autorp_read(struct event *evt)
+{
+ struct pim_autorp *autorp = evt->arg;
+ int fd = evt->u.fd;
+ char buf[10000];
+ int rd;
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: Reading from AutoRP socket", __func__);
+
+ while (1) {
+ rd = pim_socket_recvfromto(fd, (uint8_t *)buf, sizeof(buf),
+ NULL, NULL, NULL, NULL, NULL);
+ if (rd <= 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ break;
+
+ zlog_warn("%s: Failure reading rd=%d: fd=%d: errno=%d: %s",
+ __func__, rd, fd, errno, safe_strerror(errno));
+ goto err;
+ }
+
+ if (!pim_autorp_msg(autorp, buf, rd))
+ zlog_err("%s: Failure parsing AutoRP message", __func__);
+ /* Keep reading until would block */
+ }
+
+ /* No error, enable read again */
+ autorp_read_on(autorp);
+
+err:
+ return;
+}
+
+static bool pim_autorp_socket_enable(struct pim_autorp *autorp)
+{
+ int fd;
+
+ frr_with_privs (&pimd_privs) {
+ fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (fd < 0) {
+ zlog_warn("Could not create autorp socket: errno=%d: %s",
+ errno, safe_strerror(errno));
+ return false;
+ }
+
+ autorp->sock = fd;
+ if (!pim_autorp_setup(autorp)) {
+ zlog_warn("Could not setup autorp socket fd=%d: errno=%d: %s",
+ fd, errno, safe_strerror(errno));
+ close(fd);
+ autorp->sock = -1;
+ return false;
+ }
+ }
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP socket enabled", __func__);
+
+ return true;
+}
+
+static bool pim_autorp_socket_disable(struct pim_autorp *autorp)
+{
+ if (close(autorp->sock)) {
+ zlog_warn("Failure closing autorp socket: fd=%d errno=%d: %s",
+ autorp->sock, errno, safe_strerror(errno));
+ return false;
+ }
+
+ autorp_read_off(autorp);
+ autorp->sock = -1;
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP socket disabled", __func__);
+
+ return true;
+}
+
+static void autorp_send_announcement(struct event *evt)
+{
+ struct pim_autorp *autorp = EVENT_ARG(evt);
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ struct sockaddr_in announceGrp;
+
+ announceGrp.sin_family = AF_INET;
+ announceGrp.sin_port = htons(PIM_AUTORP_PORT);
+ inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &announceGrp.sin_addr);
+
+ if (autorp->annouce_pkt_sz >= MIN_AUTORP_PKT_SZ) {
+ if (setsockopt(autorp->sock, IPPROTO_IP, IP_MULTICAST_TTL,
+ &(autorp->announce_scope),
+ sizeof(autorp->announce_scope)) < 0) {
+ if (PIM_DEBUG_AUTORP)
+ zlog_err("%s: Failed to set Multicast TTL for sending AutoRP announcement message, errno=%d, %s",
+ __func__, errno, safe_strerror(errno));
+ }
+
+ FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) {
+ pim_ifp = ifp->info;
+ /* Only send on active interfaces with full pim enabled, non-passive
+ * and have a primary address set.
+ */
+ if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) &&
+ pim_ifp && pim_ifp->pim_enable &&
+ !pim_ifp->pim_passive_enable &&
+ !pim_addr_is_any(pim_ifp->primary_address)) {
+ if (setsockopt(autorp->sock, IPPROTO_IP,
+ IP_MULTICAST_IF,
+ &(pim_ifp->primary_address),
+ sizeof(pim_ifp->primary_address)) <
+ 0) {
+ if (PIM_DEBUG_AUTORP)
+ zlog_err("%s: Failed to set Multicast Interface for sending AutoRP announcement message, errno=%d, %s",
+ __func__, errno,
+ safe_strerror(errno));
+ }
+ if (sendto(autorp->sock, autorp->annouce_pkt,
+ autorp->annouce_pkt_sz, 0,
+ (struct sockaddr *)&announceGrp,
+ sizeof(announceGrp)) <= 0) {
+ if (PIM_DEBUG_AUTORP)
+ zlog_err("%s: Failed to send AutoRP announcement message, errno=%d, %s",
+ __func__, errno,
+ safe_strerror(errno));
+ }
+ }
+ }
+ }
+
+ /* Start the new timer for the entire announce interval */
+ event_add_timer(router->master, autorp_send_announcement, autorp,
+ autorp->announce_interval, &(autorp->announce_timer));
+}
+
+static void autorp_announcement_on(struct pim_autorp *autorp)
+{
+ int interval = 5;
+
+ if (interval > autorp->announce_interval) {
+ /* If the configured interval is less than 5 seconds, then just use that */
+ interval = autorp->announce_interval;
+ }
+ event_add_timer(router->master, autorp_send_announcement, autorp,
+ interval, &(autorp->announce_timer));
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP announcement sending enabled", __func__);
+}
+
+static void autorp_announcement_off(struct pim_autorp *autorp)
+{
+ event_cancel(&(autorp->announce_timer));
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP announcement sending disabled", __func__);
+}
+
+/* Pack the groups of the RP
+ * rp - Pointer to the RP
+ * buf - Pointer to the buffer where to start packing groups
+ * returns - Total group count packed
+ */
+static uint8_t pim_autorp_new_announcement_rp_grps(struct pim_autorp_rp *rp,
+ uint8_t *buf)
+{
+ struct prefix_list *plist;
+ struct prefix_list_entry *ple;
+ struct autorp_pkt_grp *grpp = (struct autorp_pkt_grp *)buf;
+ uint8_t cnt = 0;
+ in_addr_t taddr;
+
+ if (is_default_prefix(&(rp->grp))) {
+ /* No group so pack from the prefix list
+ * The grplist should be set and the prefix list exist with at least one group address
+ */
+ plist = prefix_list_lookup(AFI_IP, rp->grplist);
+ for (ple = plist->head; ple; ple = ple->next) {
+ taddr = ntohl(ple->prefix.u.prefix4.s_addr);
+ if ((taddr & 0xF0000000) == 0xE0000000) {
+ grpp->addr = ple->prefix.u.prefix4.s_addr;
+ grpp->masklen = ple->prefix.prefixlen;
+ grpp->negprefix =
+ (ple->type == PREFIX_PERMIT ? 0 : 1);
+ grpp->reserved = 0;
+
+ ++cnt;
+ grpp = (struct autorp_pkt_grp
+ *)(buf +
+ (sizeof(struct autorp_pkt_grp) *
+ cnt));
+ }
+ }
+
+ return cnt;
+ }
+
+ /* Only one of group or prefix list should be defined */
+ grpp->addr = rp->grp.u.prefix4.s_addr;
+ grpp->masklen = rp->grp.prefixlen;
+ grpp->negprefix = 0;
+ grpp->reserved = 0;
+ return 1;
+}
+
+/* Pack a single candidate RP
+ * rp - Pointer to the RP to pack
+ * buf - Pointer to the buffer where to start packing the RP
+ * returns - Buffer pointer pointing to the start of the next RP
+ */
+static uint8_t *pim_autorp_new_announcement_rp(struct pim_autorp_rp *rp,
+ uint8_t *buf)
+{
+ struct autorp_pkt_rp *brp = (struct autorp_pkt_rp *)buf;
+
+ /* Since this is an in_addr, assume it's already the right byte order */
+ brp->addr = rp->addr.s_addr;
+ brp->pimver = PIM_V2;
+ brp->reserved = 0;
+ brp->grpcnt =
+ pim_autorp_new_announcement_rp_grps(rp,
+ buf + sizeof(struct autorp_pkt_rp));
+ return buf + sizeof(struct autorp_pkt_rp) +
+ (brp->grpcnt * sizeof(struct autorp_pkt_grp));
+}
+
+/* Pack the candidate RP's on the announcement packet
+ * autorp - Pointer to the AutoRP instance
+ * buf - Pointer to the buffer where to start packing the first RP
+ * bufsz - Output parameter to track size of packed bytes
+ * returns - Total count of RP's packed
+ */
+static int pim_autorp_new_announcement_rps(struct pim_autorp *autorp,
+ uint8_t *buf, uint16_t *bufsz)
+{
+ int cnt = 0;
+ struct pim_autorp_rp *rp;
+ /* Keep the original buffer pointer to calculate final size after packing */
+ uint8_t *obuf = buf;
+ struct prefix_list *plist;
+ struct prefix_list_entry *ple;
+ in_addr_t taddr;
+
+ frr_each_safe (pim_autorp_rp, &(autorp->candidate_rp_list), rp) {
+ /* We must have an rp address and either group or list in order to pack this RP, so skip this one */
+ if (pim_addr_is_any(rp->addr) ||
+ (is_default_prefix(&(rp->grp)) && strlen(rp->grplist) == 0))
+ continue;
+
+ /* Group is net set, so list must be set, make sure the prefix list exists and has valid multicast groups */
+ if (is_default_prefix(&(rp->grp))) {
+ plist = prefix_list_lookup(AFI_IP, rp->grplist);
+ if (plist == NULL)
+ continue;
+ plist = prefix_list_lookup(AFI_IP, rp->grplist);
+ for (ple = plist->head; ple; ple = ple->next) {
+ taddr = ntohl(ple->prefix.u.prefix4.s_addr);
+ if ((taddr & 0xF0000000) == 0xE0000000)
+ break;
+ }
+
+ /* If we went through the entire list without finding a multicast prefix, then skip this RP */
+ if (ple == NULL)
+ continue;
+ }
+
+ /* Now we know for sure we will pack this RP, so count it */
+ ++cnt;
+ /* This will return the buffer pointer at the location to start packing the next RP */
+ buf = pim_autorp_new_announcement_rp(rp, buf);
+ }
+
+ if (cnt > 0)
+ *bufsz = buf - obuf;
+
+ return cnt;
+}
+
+/* Build the new announcement packet. If there is a packet to send, restart the send timer with a short wait */
+static void pim_autorp_new_announcement(struct pim_instance *pim)
+{
+ struct pim_autorp *autorp = pim->autorp;
+ struct autorp_pkt_hdr *hdr;
+ int32_t holdtime;
+
+ /* First disable any existing send timer */
+ autorp_announcement_off(autorp);
+
+ if (!autorp->annouce_pkt) {
+ /*
+ * First time building, allocate the space
+ * Allocate the max packet size of 65536 so we don't need to resize later.
+ * This should be ok since we are only allocating the memory once for a single packet (potentially per vrf)
+ */
+ autorp->annouce_pkt = XCALLOC(MTYPE_PIM_AUTORP_ANNOUNCE, 65536);
+ }
+
+ autorp->annouce_pkt_sz = 0;
+
+ holdtime = autorp->announce_holdtime;
+ if (holdtime == DEFAULT_ANNOUNCE_HOLDTIME)
+ holdtime = autorp->announce_interval * 3;
+ if (holdtime > UINT16_MAX)
+ holdtime = UINT16_MAX;
+
+ hdr = (struct autorp_pkt_hdr *)autorp->annouce_pkt;
+ hdr->version = AUTORP_VERSION;
+ hdr->type = AUTORP_ANNOUNCEMENT_TYPE;
+ hdr->holdtime = htons((uint16_t)holdtime);
+ hdr->reserved = 0;
+ hdr->rpcnt =
+ pim_autorp_new_announcement_rps(autorp,
+ autorp->annouce_pkt +
+ sizeof(struct autorp_pkt_hdr),
+ &(autorp->annouce_pkt_sz));
+
+ /* Still need to add on the size of the header */
+ autorp->annouce_pkt_sz += sizeof(struct autorp_pkt_hdr);
+
+ /* Only turn on the announcement timer if we have a packet to send */
+ if (autorp->annouce_pkt_sz >= MIN_AUTORP_PKT_SZ)
+ autorp_announcement_on(autorp);
+}
+
+bool pim_autorp_rm_candidate_rp(struct pim_instance *pim, pim_addr rpaddr)
+{
+ struct pim_autorp *autorp = pim->autorp;
+ struct pim_autorp_rp *rp;
+ struct pim_autorp_rp find = { .addr = rpaddr };
+
+ rp = pim_autorp_rp_find(&(autorp->candidate_rp_list),
+ (const struct pim_autorp_rp *)&find);
+ if (!rp)
+ return false;
+
+ pim_autorp_rp_del(&(autorp->candidate_rp_list), rp);
+ pim_autorp_rp_free(rp);
+ pim_autorp_new_announcement(pim);
+ return true;
+}
+
+void pim_autorp_add_candidate_rp_group(struct pim_instance *pim,
+ pim_addr rpaddr, struct prefix group)
+{
+ struct pim_autorp *autorp = pim->autorp;
+ struct pim_autorp_rp *rp;
+ struct pim_autorp_rp find = { .addr = rpaddr };
+
+ rp = pim_autorp_rp_find(&(autorp->candidate_rp_list),
+ (const struct pim_autorp_rp *)&find);
+ if (!rp) {
+ rp = XCALLOC(MTYPE_PIM_AUTORP_CRP, sizeof(*rp));
+ memset(rp, 0, sizeof(struct pim_autorp_rp));
+ rp->autorp = autorp;
+ memcpy(&(rp->addr), &rpaddr, sizeof(pim_addr));
+ pim_autorp_rp_add(&(autorp->candidate_rp_list), rp);
+ }
+
+ apply_mask(&group);
+ prefix_copy(&(rp->grp), &group);
+ /* A new group prefix implies that any previous prefix list is now invalid */
+ rp->grplist[0] = '\0';
+
+ pim_autorp_new_announcement(pim);
+}
+
+bool pim_autorp_rm_candidate_rp_group(struct pim_instance *pim, pim_addr rpaddr,
+ struct prefix group)
+{
+ struct pim_autorp *autorp = pim->autorp;
+ struct pim_autorp_rp *rp;
+ struct pim_autorp_rp find = { .addr = rpaddr };
+
+ rp = pim_autorp_rp_find(&(autorp->candidate_rp_list),
+ (const struct pim_autorp_rp *)&find);
+ if (!rp)
+ return false;
+
+ memset(&(rp->grp), 0, sizeof(rp->grp));
+ pim_autorp_new_announcement(pim);
+ return true;
+}
+
+void pim_autorp_add_candidate_rp_plist(struct pim_instance *pim,
+ pim_addr rpaddr, const char *plist)
+{
+ struct pim_autorp *autorp = pim->autorp;
+ struct pim_autorp_rp *rp;
+ struct pim_autorp_rp find = { .addr = rpaddr };
+
+ rp = pim_autorp_rp_find(&(autorp->candidate_rp_list),
+ (const struct pim_autorp_rp *)&find);
+ if (!rp) {
+ rp = XCALLOC(MTYPE_PIM_AUTORP_CRP, sizeof(*rp));
+ memset(rp, 0, sizeof(struct pim_autorp_rp));
+ rp->autorp = autorp;
+ memcpy(&(rp->addr), &rpaddr, sizeof(pim_addr));
+ pim_autorp_rp_add(&(autorp->candidate_rp_list), rp);
+ }
+
+ snprintf(rp->grplist, sizeof(rp->grplist), "%s", plist);
+ /* A new group prefix list implies that any previous group prefix is now invalid */
+ memset(&(rp->grp), 0, sizeof(rp->grp));
+ rp->grp.family = AF_INET;
+
+ pim_autorp_new_announcement(pim);
+}
+
+bool pim_autorp_rm_candidate_rp_plist(struct pim_instance *pim, pim_addr rpaddr,
+ const char *plist)
+{
+ struct pim_autorp *autorp = pim->autorp;
+ struct pim_autorp_rp *rp;
+ struct pim_autorp_rp find = { .addr = rpaddr };
+
+ rp = pim_autorp_rp_find(&(autorp->candidate_rp_list),
+ (const struct pim_autorp_rp *)&find);
+ if (!rp)
+ return false;
+
+ rp->grplist[0] = '\0';
+ pim_autorp_new_announcement(pim);
+ return true;
+}
+
+void pim_autorp_announce_scope(struct pim_instance *pim, uint8_t scope)
+{
+ struct pim_autorp *autorp = pim->autorp;
+
+ scope = (scope == 0 ? DEFAULT_ANNOUNCE_SCOPE : scope);
+ if (autorp->announce_scope != scope) {
+ autorp->announce_scope = scope;
+ pim_autorp_new_announcement(pim);
+ }
+}
+
+void pim_autorp_announce_interval(struct pim_instance *pim, uint16_t interval)
+{
+ struct pim_autorp *autorp = pim->autorp;
+
+ interval = (interval == 0 ? DEFAULT_ANNOUNCE_INTERVAL : interval);
+ if (autorp->announce_interval != interval) {
+ autorp->announce_interval = interval;
+ pim_autorp_new_announcement(pim);
+ }
+}
+
+void pim_autorp_announce_holdtime(struct pim_instance *pim, int32_t holdtime)
+{
+ struct pim_autorp *autorp = pim->autorp;
+
+ if (autorp->announce_holdtime != holdtime) {
+ autorp->announce_holdtime = holdtime;
+ pim_autorp_new_announcement(pim);
+ }
+}
+
+void pim_autorp_add_ifp(struct interface *ifp)
+{
+ /* Add a new interface for autorp
+ * When autorp is enabled, we must join the autorp groups on all
+ * pim/multicast interfaces. When autorp first starts, if finds all
+ * current multicast interfaces and joins on them. If a new interface
+ * comes up or is configured for multicast after autorp is running, then
+ * this method will add it for autorp->
+ * This is called even when adding a new pim interface that is not yet
+ * active, so make sure the check, it'll call in again once the interface is up.
+ */
+ struct pim_instance *pim;
+ struct pim_interface *pim_ifp;
+
+ pim_ifp = ifp->info;
+ if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && pim_ifp &&
+ pim_ifp->pim_enable) {
+ pim = pim_ifp->pim;
+ if (pim && pim->autorp && pim->autorp->do_discovery) {
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: Adding interface %s to AutoRP, joining AutoRP groups",
+ __func__, ifp->name);
+ if (!pim_autorp_join_groups(ifp)) {
+ zlog_err("Could not join AutoRP groups, errno=%d, %s",
+ errno, safe_strerror(errno));
+ }
+ }
+ }
+}
+
+void pim_autorp_rm_ifp(struct interface *ifp)
+{
+ /* Remove interface for autorp
+ * When an interface is no longer enabled for multicast, or at all, then
+ * we should leave the AutoRP groups on this interface.
+ */
+ struct pim_instance *pim;
+ struct pim_interface *pim_ifp;
+
+ pim_ifp = ifp->info;
+ if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && pim_ifp) {
+ pim = pim_ifp->pim;
+ if (pim && pim->autorp) {
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: Removing interface %s from AutoRP, leaving AutoRP groups",
+ __func__, ifp->name);
+ if (!pim_autorp_leave_groups(ifp)) {
+ zlog_err("Could not leave AutoRP groups, errno=%d, %s",
+ errno, safe_strerror(errno));
+ }
+ }
+ }
+}
+
+void pim_autorp_start_discovery(struct pim_instance *pim)
+{
+ struct interface *ifp;
+ struct pim_autorp *autorp = pim->autorp;
+
+ if (!autorp->do_discovery) {
+ autorp->do_discovery = true;
+ autorp_read_on(autorp);
+
+ FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) {
+ pim_autorp_add_ifp(ifp);
+ }
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP Discovery started", __func__);
+ }
+}
+
+void pim_autorp_stop_discovery(struct pim_instance *pim)
+{
+ struct interface *ifp;
+ struct pim_autorp *autorp = pim->autorp;
+
+ if (autorp->do_discovery) {
+ FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) {
+ pim_autorp_rm_ifp(ifp);
+ }
+
+ autorp->do_discovery = false;
+ autorp_read_off(autorp);
+
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP Discovery stopped", __func__);
+ }
+}
+
+void pim_autorp_init(struct pim_instance *pim)
+{
+ struct pim_autorp *autorp;
+
+ autorp = XCALLOC(MTYPE_PIM_AUTORP, sizeof(*autorp));
+ autorp->pim = pim;
+ autorp->sock = -1;
+ autorp->read_event = NULL;
+ autorp->announce_timer = NULL;
+ autorp->do_discovery = false;
+ pim_autorp_rp_init(&(autorp->discovery_rp_list));
+ pim_autorp_rp_init(&(autorp->candidate_rp_list));
+ autorp->announce_scope = DEFAULT_ANNOUNCE_SCOPE;
+ autorp->announce_interval = DEFAULT_ANNOUNCE_INTERVAL;
+ autorp->announce_holdtime = DEFAULT_ANNOUNCE_HOLDTIME;
+
+ if (!pim_autorp_socket_enable(autorp)) {
+ zlog_err("%s: AutoRP failed to initialize", __func__);
+ return;
+ }
+
+ pim->autorp = autorp;
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP Initialized", __func__);
+
+ /* Start AutoRP discovery by default on startup */
+ pim_autorp_start_discovery(pim);
+}
+
+void pim_autorp_finish(struct pim_instance *pim)
+{
+ struct pim_autorp *autorp = pim->autorp;
+
+ autorp_read_off(autorp);
+ pim_autorp_free(autorp);
+ if (pim_autorp_socket_disable(autorp)) {
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP Finished", __func__);
+ } else
+ zlog_err("%s: AutoRP failed to finish", __func__);
+
+ XFREE(MTYPE_PIM_AUTORP, pim->autorp);
+}
+
+int pim_autorp_config_write(struct pim_instance *pim, struct vty *vty)
+{
+ struct pim_autorp_rp *rp;
+ struct pim_autorp *autorp = pim->autorp;
+ char interval_str[16] = { 0 };
+ char scope_str[16] = { 0 };
+ char holdtime_str[32] = { 0 };
+ char grp_str[64] = { 0 };
+ int writes = 0;
+
+ if (!autorp->do_discovery) {
+ vty_out(vty, " no autorp discovery\n");
+ ++writes;
+ }
+
+ if (autorp->announce_interval != DEFAULT_ANNOUNCE_INTERVAL) {
+ snprintf(interval_str, sizeof(interval_str), " interval %u",
+ autorp->announce_interval);
+ }
+
+ if (autorp->announce_scope != DEFAULT_ANNOUNCE_SCOPE) {
+ snprintf(scope_str, sizeof(scope_str), " scope %u",
+ autorp->announce_scope);
+ }
+
+ if (autorp->announce_holdtime != DEFAULT_ANNOUNCE_HOLDTIME) {
+ snprintf(holdtime_str, sizeof(holdtime_str), " holdtime %u",
+ autorp->announce_holdtime);
+ }
+
+ if (strlen(interval_str) || strlen(scope_str) || strlen(holdtime_str)) {
+ vty_out(vty, " autorp announce%s%s%s\n", interval_str,
+ scope_str, holdtime_str);
+ ++writes;
+ }
+
+ frr_each_safe (pim_autorp_rp, &(autorp->candidate_rp_list), rp) {
+ /* Only print candidate RP's that have all the information needed to be announced */
+ if (pim_addr_is_any(rp->addr) ||
+ (is_default_prefix(&(rp->grp)) && strlen(rp->grplist) == 0))
+ continue;
+
+ /* Don't make sure the prefix list has multicast groups, user may not have created it yet */
+
+ if (!is_default_prefix(&(rp->grp)))
+ snprintfrr(grp_str, sizeof(grp_str), "%pFX", &(rp->grp));
+ else
+ snprintfrr(grp_str, sizeof(grp_str), "group-list %s",
+ rp->grplist);
+
+ vty_out(vty, " autorp announce %pI4 %s\n", &(rp->addr), grp_str);
+ ++writes;
+ }
+
+ return writes;
+}
+
+void pim_autorp_show_autorp(struct vty *vty, struct pim_instance *pim,
+ json_object *json)
+{
+ struct pim_autorp_rp *rp;
+ struct pim_autorp *autorp = pim->autorp;
+ struct ttable *tt = NULL;
+ char *table = NULL;
+ char grp_str[64] = { 0 };
+ char plist_str[64] = { 0 };
+ json_object *annouce_jobj;
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "RP address|group|prefix-list");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+
+ frr_each_safe (pim_autorp_rp, &(autorp->candidate_rp_list), rp) {
+ if (!is_default_prefix(&(rp->grp)))
+ snprintfrr(grp_str, sizeof(grp_str), "%pFX", &(rp->grp));
+ else
+ snprintfrr(plist_str, sizeof(plist_str), "%s",
+ rp->grplist);
+
+ ttable_add_row(tt, "%pI4|%s|%s", &(rp->addr), grp_str,
+ plist_str);
+ }
+
+ if (json) {
+ json_object_boolean_add(json, "discoveryEnabled",
+ autorp->do_discovery);
+
+ annouce_jobj = json_object_new_object();
+ json_object_int_add(annouce_jobj, "scope",
+ autorp->announce_scope);
+ json_object_int_add(annouce_jobj, "interval",
+ autorp->announce_interval);
+ json_object_int_add(annouce_jobj, "holdtime",
+ autorp->announce_holdtime);
+ json_object_object_add(annouce_jobj, "rpList",
+ ttable_json_with_json_text(
+ tt, "sss",
+ "rpAddress|group|prefixList"));
+
+ json_object_object_add(json, "announce", annouce_jobj);
+ } else {
+ vty_out(vty, "AutoRP Discovery is %sabled\n",
+ (autorp->do_discovery ? "en" : "dis"));
+ vty_out(vty, "AutoRP Candidate RPs\n");
+ vty_out(vty, " interval %us, scope %u, holdtime %us\n",
+ autorp->announce_interval, autorp->announce_scope,
+ (autorp->announce_holdtime == DEFAULT_ANNOUNCE_HOLDTIME
+ ? (autorp->announce_interval * 3)
+ : autorp->announce_holdtime));
+
+ vty_out(vty, "\n");
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP_TTABLE, table);
+ }
+
+ ttable_del(tt);
+}
diff --git a/pimd/pim_autorp.h b/pimd/pim_autorp.h
new file mode 100644
index 0000000000..a0b029d00a
--- /dev/null
+++ b/pimd/pim_autorp.h
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * pim_autorp.h: PIM Auto RP handling related
+ *
+ * Copyright (C) 20224 ATCorp.
+ * Nathan Bahr
+ */
+
+#ifndef __PIM_AUTORP_H__
+#define __PIM_AUTORP_H__
+
+#include <typesafe.h>
+
+#define AUTORP_VERSION 1
+#define AUTORP_ANNOUNCEMENT_TYPE 1
+#define AUTORP_DISCOVERY_TYPE 2
+#define PIM_VUNKNOWN 0
+#define PIM_V1 1
+#define PIM_V2 2
+#define PIM_V1_2 3
+
+#define DEFAULT_ANNOUNCE_INTERVAL 60
+#define DEFAULT_ANNOUNCE_SCOPE 31
+#define DEFAULT_ANNOUNCE_HOLDTIME -1
+
+PREDECL_SORTLIST_UNIQ(pim_autorp_rp);
+
+struct autorp_pkt_grp {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ uint8_t negprefix : 1;
+ uint8_t reserved : 7;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ uint8_t reserved : 7;
+ uint8_t negprefix : 1;
+#else
+#error "Please fix <bits/endian.h>"
+#endif
+ uint8_t masklen;
+ uint32_t addr;
+} __attribute__((__packed__));
+
+struct autorp_pkt_rp {
+ uint32_t addr;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ uint8_t pimver : 2;
+ uint8_t reserved : 6;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ uint8_t reserved : 6;
+ uint8_t pimver : 2;
+#else
+#error "Please fix <bits/endian.h>"
+#endif
+ uint8_t grpcnt;
+} __attribute__((__packed__));
+
+struct autorp_pkt_hdr {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ uint8_t type : 4;
+ uint8_t version : 4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ uint8_t version : 4;
+ uint8_t type : 4;
+#else
+#error "Please fix <bits/endian.h>"
+#endif
+ uint8_t rpcnt;
+ uint16_t holdtime;
+ uint32_t reserved;
+} __attribute__((__packed__));
+
+#define MIN_AUTORP_PKT_SZ \
+ (sizeof(struct autorp_pkt_hdr) + sizeof(struct autorp_pkt_rp) + \
+ sizeof(struct autorp_pkt_grp))
+
+struct pim_autorp_rp {
+ struct pim_autorp *autorp;
+ struct in_addr addr;
+ uint16_t holdtime;
+ struct event *hold_timer;
+ struct prefix grp;
+ char grplist[32];
+ struct pim_autorp_rp_item list;
+};
+
+struct pim_autorp {
+ /* backpointer to pim instance */
+ struct pim_instance *pim;
+
+ /* UDP socket bound to AutoRP port, used for sending and receiving all AutoRP packets */
+ int sock;
+
+ /* Event for reading AutoRP packets */
+ struct event *read_event;
+
+ /* Event for sending announcement packets */
+ struct event *announce_timer;
+
+ /* Event for sending discovery packets*/
+ /* struct event *discovery_timer; */
+
+ /* Flag enabling reading discovery packets */
+ bool do_discovery;
+
+ /* Flag enabling mapping agent (reading announcements and sending discovery)*/
+ /* bool do_mapping; */
+
+ /* List of RP's in received discovery packets */
+ struct pim_autorp_rp_head discovery_rp_list;
+
+ /* List of configured candidate RP's to send in announcement packets */
+ struct pim_autorp_rp_head candidate_rp_list;
+
+ /* List of announced RP's to send in discovery packets */
+ /* struct pim_autorp_rp_head mapping_rp_list; */
+
+ /* Packet parameters for sending announcement packets */
+ uint8_t announce_scope;
+ uint16_t announce_interval;
+ int32_t announce_holdtime;
+
+ /* Pre-built announcement packet, only changes when configured RP's or packet parameters change */
+ uint8_t *annouce_pkt;
+ uint16_t annouce_pkt_sz;
+
+ /* TODO: Packet parameters for sending discovery packets
+ * int discovery_scope;
+ * int discovery_interval;
+ * int discovery_holdtime;
+ */
+};
+
+#define AUTORP_GRPLEN 6
+#define AUTORP_RPLEN 6
+#define AUTORP_HDRLEN 8
+
+bool pim_autorp_rm_candidate_rp(struct pim_instance *pim, pim_addr rpaddr);
+void pim_autorp_add_candidate_rp_group(struct pim_instance *pim,
+ pim_addr rpaddr, struct prefix group);
+bool pim_autorp_rm_candidate_rp_group(struct pim_instance *pim, pim_addr rpaddr,
+ struct prefix group);
+void pim_autorp_add_candidate_rp_plist(struct pim_instance *pim,
+ pim_addr rpaddr, const char *plist);
+bool pim_autorp_rm_candidate_rp_plist(struct pim_instance *pim, pim_addr rpaddr,
+ const char *plist);
+void pim_autorp_announce_scope(struct pim_instance *pim, uint8_t scope);
+void pim_autorp_announce_interval(struct pim_instance *pim, uint16_t interval);
+void pim_autorp_announce_holdtime(struct pim_instance *pim, int32_t holdtime);
+void pim_autorp_add_ifp(struct interface *ifp);
+void pim_autorp_rm_ifp(struct interface *ifp);
+void pim_autorp_start_discovery(struct pim_instance *pim);
+void pim_autorp_stop_discovery(struct pim_instance *pim);
+void pim_autorp_init(struct pim_instance *pim);
+void pim_autorp_finish(struct pim_instance *pim);
+int pim_autorp_config_write(struct pim_instance *pim, struct vty *vty);
+void pim_autorp_show_autorp(struct vty *vty, struct pim_instance *pim,
+ json_object *json);
+
+#endif
diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c
index 2d451718a9..115aec8933 100644
--- a/pimd/pim_bsm.c
+++ b/pimd/pim_bsm.c
@@ -10,6 +10,17 @@
#include "config.h"
#endif
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <lib/network.h>
+#include <lib/iana_afi.h>
+#include <lib/sockunion.h>
+#include <lib/sockopt.h>
+
#include "if.h"
#include "pimd.h"
#include "pim_iface.h"
@@ -23,18 +34,32 @@
#include "pim_time.h"
#include "pim_zebra.h"
#include "pim_util.h"
+#include "pim_sock.h"
/* Functions forward declaration */
static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout);
static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time);
static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
int hold_time);
+static void pim_bsm_accept_any(struct bsm_scope *scope);
+static void pim_cand_bsr_trigger(struct bsm_scope *scope, bool verbose);
+static void pim_cand_bsr_pending(struct bsm_scope *scope);
/* Memory Types */
DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info");
DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_INFO, "PIM BSR advertised RP info");
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_FRAG, "PIM BSM fragment");
+DEFINE_MTYPE(PIMD, PIM_BSM_FRAG, "PIM BSM fragment");
DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet");
+DEFINE_MTYPE_STATIC(PIMD, PIM_CAND_RP_GRP, "PIM Candidate RP group");
+
+static int cand_rp_group_cmp(const struct cand_rp_group *a,
+ const struct cand_rp_group *b)
+{
+ return prefix_cmp(&a->p, &b->p);
+}
+
+DECLARE_RBTREE_UNIQ(cand_rp_groups, struct cand_rp_group, item,
+ cand_rp_group_cmp);
/* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */
#define MAX_IP_HDR_LEN 24
@@ -90,7 +115,7 @@ static void pim_bsm_frag_free(struct bsm_frag *bsfrag)
XFREE(MTYPE_PIM_BSM_FRAG, bsfrag);
}
-static void pim_bsm_frags_free(struct bsm_scope *scope)
+void pim_bsm_frags_free(struct bsm_scope *scope)
{
struct bsm_frag *bsfrag;
@@ -140,12 +165,12 @@ static struct bsgrp_node *pim_bsm_new_bsgrp_node(struct route_table *rt,
return bsgrp;
}
+/* BS timer for NO_INFO, ACCEPT_ANY & ACCEPT_PREFERRED.
+ * Candidate BSR handling is separate further below
+ */
static void pim_on_bs_timer(struct event *t)
{
- struct route_node *rn;
struct bsm_scope *scope;
- struct bsgrp_node *bsgrp_node;
- struct bsm_rpinfo *bsrp;
scope = EVENT_ARG(t);
EVENT_OFF(scope->bs_timer);
@@ -154,7 +179,20 @@ static void pim_on_bs_timer(struct event *t)
zlog_debug("%s: Bootstrap Timer expired for scope: %d",
__func__, scope->sz_id);
+ assertf(scope->state <= ACCEPT_PREFERRED, "state=%d", scope->state);
pim_nht_bsr_del(scope->pim, scope->current_bsr);
+
+ pim_bsm_accept_any(scope);
+}
+
+static void pim_bsm_accept_any(struct bsm_scope *scope)
+{
+ struct route_node *rn;
+ struct bsgrp_node *bsgrp_node;
+ struct bsm_rpinfo *bsrp;
+
+ EVENT_OFF(scope->t_ebsr_regen_bsm);
+
/* Reset scope zone data */
scope->state = ACCEPT_ANY;
scope->current_bsr = PIMADDR_ANY;
@@ -181,6 +219,11 @@ static void pim_on_bs_timer(struct event *t)
pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
bsgrp_node->pend_rp_cnt = 0;
}
+
+ /* we're leaving ACCEPT_PREFERRED, which doubles as C-BSR if we're
+ * configured to be a Candidate BSR. See if we're P-BSR now.
+ */
+ pim_cand_bsr_trigger(scope, false);
}
static void pim_bs_timer_stop(struct bsm_scope *scope)
@@ -212,36 +255,77 @@ static inline void pim_bs_timer_restart(struct bsm_scope *scope, int bs_timeout)
pim_bs_timer_start(scope, bs_timeout);
}
+static void bsm_unicast_sock_read(struct event *t)
+{
+ struct bsm_scope *scope = EVENT_ARG(t);
+
+ pim_sock_read_helper(scope->unicast_sock, scope->pim, false);
+
+ event_add_read(router->master, bsm_unicast_sock_read, scope,
+ scope->unicast_sock, &scope->unicast_read);
+}
+
void pim_bsm_proc_init(struct pim_instance *pim)
{
- memset(&pim->global_scope, 0, sizeof(struct bsm_scope));
-
- pim->global_scope.sz_id = PIM_GBL_SZ_ID;
- pim->global_scope.bsrp_table = route_table_init();
- pim->global_scope.accept_nofwd_bsm = true;
- pim->global_scope.state = NO_INFO;
- pim->global_scope.pim = pim;
- bsm_frags_init(pim->global_scope.bsm_frags);
- pim_bs_timer_start(&pim->global_scope, PIM_BS_TIME);
+ struct bsm_scope *scope = &pim->global_scope;
+
+ memset(scope, 0, sizeof(*scope));
+
+ scope->sz_id = PIM_GBL_SZ_ID;
+ scope->bsrp_table = route_table_init();
+ scope->accept_nofwd_bsm = true;
+ scope->state = NO_INFO;
+ scope->pim = pim;
+ bsm_frags_init(scope->bsm_frags);
+ pim_bs_timer_start(scope, PIM_BS_TIME);
+
+ scope->cand_rp_interval = PIM_CRP_ADV_INTERVAL;
+ cand_rp_groups_init(scope->cand_rp_groups);
+
+ scope->unicast_sock = pim_socket_raw(IPPROTO_PIM);
+ set_nonblocking(scope->unicast_sock);
+ sockopt_reuseaddr(scope->unicast_sock);
+
+ if (setsockopt_ifindex(PIM_AF, scope->unicast_sock, 1) == -1)
+ zlog_warn("%s: Without IP_PKTINFO, src interface can't be determined",
+ __func__);
+
+ pim_socket_ip_hdr(scope->unicast_sock);
+
+ frr_with_privs (&pimd_privs) {
+ vrf_bind(pim->vrf->vrf_id, scope->unicast_sock, NULL);
+ }
+
+ event_add_read(router->master, bsm_unicast_sock_read, scope,
+ scope->unicast_sock, &scope->unicast_read);
}
void pim_bsm_proc_free(struct pim_instance *pim)
{
+ struct bsm_scope *scope = &pim->global_scope;
struct route_node *rn;
struct bsgrp_node *bsgrp;
+ struct cand_rp_group *crpgrp;
- pim_bs_timer_stop(&pim->global_scope);
- pim_bsm_frags_free(&pim->global_scope);
+ EVENT_OFF(scope->unicast_read);
+ close(scope->unicast_sock);
- for (rn = route_top(pim->global_scope.bsrp_table); rn;
- rn = route_next(rn)) {
+ pim_bs_timer_stop(scope);
+ pim_bsm_frags_free(scope);
+
+ for (rn = route_top(scope->bsrp_table); rn; rn = route_next(rn)) {
bsgrp = rn->info;
if (!bsgrp)
continue;
pim_free_bsgrp_data(bsgrp);
}
- route_table_finish(pim->global_scope.bsrp_table);
+ while ((crpgrp = cand_rp_groups_pop(scope->cand_rp_groups)))
+ XFREE(MTYPE_PIM_CAND_RP_GRP, crpgrp);
+
+ cand_rp_groups_fini(scope->cand_rp_groups);
+
+ route_table_finish(scope->bsrp_table);
}
static bool is_hold_time_elapsed(void *data)
@@ -512,9 +596,6 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node)
static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr,
uint32_t bsr_prio)
{
- if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr))
- return true;
-
if (bsr_prio > pim->global_scope.current_bsr_prio)
return true;
@@ -523,6 +604,11 @@ static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr,
return true;
else
return false;
+ } else if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr)) {
+ /* BSR config changed, lower prio now. local BSR check
+ * is handled separately in pim_bsm_update()
+ */
+ return true;
} else
return false;
}
@@ -530,17 +616,52 @@ static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr,
static void pim_bsm_update(struct pim_instance *pim, pim_addr bsr,
uint32_t bsr_prio)
{
- if (pim_addr_cmp(bsr, pim->global_scope.current_bsr)) {
- pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
- pim_nht_bsr_add(pim, bsr);
-
- pim->global_scope.current_bsr = bsr;
- pim->global_scope.current_bsr_first_ts =
- pim_time_monotonic_sec();
- pim->global_scope.state = ACCEPT_PREFERRED;
- }
pim->global_scope.current_bsr_prio = bsr_prio;
pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec();
+
+ if (pim->global_scope.bsr_addrsel.run &&
+ pim->global_scope.cand_bsr_prio > bsr_prio &&
+ pim->global_scope.state < BSR_PENDING) {
+ /* current BSR is now less preferred than ourselves */
+ pim_cand_bsr_pending(&pim->global_scope);
+ return;
+ }
+
+ if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr))
+ return;
+
+ switch (pim->global_scope.state) {
+ case BSR_PENDING:
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate BSR dropping out of BSR election, better BSR (%u, %pPA)",
+ bsr_prio, &bsr);
+ break;
+
+ case BSR_ELECTED:
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Lost BSR status, better BSR (%u, %pPA)",
+ bsr_prio, &bsr);
+ break;
+
+ case NO_INFO:
+ case ACCEPT_ANY:
+ case ACCEPT_PREFERRED:
+ break;
+ }
+
+ EVENT_OFF(pim->global_scope.t_ebsr_regen_bsm);
+
+ if (pim->global_scope.state == BSR_ELECTED)
+ pim_crp_db_clear(&pim->global_scope);
+ else
+ pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
+ pim_nht_bsr_add(pim, bsr);
+
+ pim->global_scope.current_bsr = bsr;
+ pim->global_scope.current_bsr_first_ts = pim_time_monotonic_sec();
+ pim->global_scope.state = ACCEPT_PREFERRED;
+
+ pim_cand_rp_trigger(&pim->global_scope);
}
void pim_bsm_clear(struct pim_instance *pim)
@@ -555,7 +676,12 @@ void pim_bsm_clear(struct pim_instance *pim)
struct rp_info *rp_info;
bool upstream_updated = false;
- pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
+ EVENT_OFF(pim->global_scope.t_ebsr_regen_bsm);
+
+ if (pim->global_scope.state == BSR_ELECTED)
+ pim_crp_db_clear(&pim->global_scope);
+ else
+ pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
/* Reset scope zone data */
pim->global_scope.accept_nofwd_bsm = false;
@@ -1116,8 +1242,8 @@ static void pim_update_pending_rp_cnt(struct bsm_scope *sz,
}
/* Parsing BSR packet and adding to partial list of corresponding bsgrp node */
-static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
- int buflen, uint16_t bsm_frag_tag)
+bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
+ int buflen, uint16_t bsm_frag_tag)
{
struct bsmmsg_grpinfo grpinfo;
struct bsmmsg_rpinfo rpinfo;
@@ -1338,35 +1464,6 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
}
}
- /* Drop if bsr is not preferred bsr */
- if (!is_preferred_bsr(pim, bsr_addr, bshdr->bsr_prio)) {
- if (PIM_DEBUG_BSM)
- zlog_debug("%s : Received a non-preferred BSM",
- __func__);
- pim->bsm_dropped++;
- return -1;
- }
-
- if (no_fwd) {
- /* only accept no-forward BSM if quick refresh on startup */
- if ((pim->global_scope.accept_nofwd_bsm)
- || (frag_tag == pim->global_scope.bsm_frag_tag)) {
- pim->global_scope.accept_nofwd_bsm = false;
- } else {
- if (PIM_DEBUG_BSM)
- zlog_debug(
- "%s : nofwd_bsm received on %pPAs when accpt_nofwd_bsm false",
- __func__, &bsr_addr);
- pim->bsm_dropped++;
- pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
- return -1;
- }
- }
-
- /* BSM packet is seen, so resetting accept_nofwd_bsm to false */
- if (pim->global_scope.accept_nofwd_bsm)
- pim->global_scope.accept_nofwd_bsm = false;
-
if (!pim_addr_cmp(sg->grp, qpim_all_pim_routers_addr)) {
/* Multicast BSMs are only accepted if source interface & IP
* match RPF towards the BSR's IP address, or they have
@@ -1403,6 +1500,57 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
return -1;
}
+ /* when the BSR restarts, it can get its own BSR advertisement thrown
+ * back at it, and without this we'll go into ACCEPT_PREFERRED with
+ * ourselves as the BSR when we should be in BSR_ELECTED.
+ */
+ if (if_address_is_local(&bshdr->bsr_addr.addr, PIM_AF,
+ pim->vrf->vrf_id)) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s : Dropping BSM from ourselves", __func__);
+ pim->bsm_dropped++;
+ return -1;
+ }
+
+ /* Drop if bsr is not preferred bsr */
+ if (!is_preferred_bsr(pim, bsr_addr, bshdr->bsr_prio)) {
+ if (pim->global_scope.state == BSR_PENDING && !no_fwd) {
+ /* in P-BSR state, non-preferred BSMs are forwarded, but
+ * content is ignored.
+ */
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s : Forwarding non-preferred BSM during Pending-BSR state",
+ __func__);
+
+ pim_bsm_fwd_whole_sz(pim_ifp->pim, buf, buf_size, sz);
+ return -1;
+ }
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s : Received a non-preferred BSM",
+ __func__);
+ pim->bsm_dropped++;
+ return -1;
+ }
+
+ if (no_fwd) {
+ /* only accept no-forward BSM if quick refresh on startup */
+ if ((pim->global_scope.accept_nofwd_bsm) ||
+ (frag_tag == pim->global_scope.bsm_frag_tag)) {
+ pim->global_scope.accept_nofwd_bsm = false;
+ } else {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s : nofwd_bsm received on %pPAs when accpt_nofwd_bsm false",
+ __func__, &bsr_addr);
+ pim->bsm_dropped++;
+ pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
+ return -1;
+ }
+ }
+
+ /* BSM packet is seen, so resetting accept_nofwd_bsm to false */
+ if (pim->global_scope.accept_nofwd_bsm)
+ pim->global_scope.accept_nofwd_bsm = false;
+
if (empty_bsm) {
if (PIM_DEBUG_BSM)
zlog_debug("%s : Empty Pref BSM received", __func__);
@@ -1413,9 +1561,8 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
(buf + PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN),
(buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN),
frag_tag)) {
- if (PIM_DEBUG_BSM) {
- zlog_debug("%s, Parsing BSM failed.", __func__);
- }
+ zlog_warn("BSM from %pPA failed to parse",
+ (pim_addr *)&bshdr->bsr_addr.addr);
pim->bsm_dropped++;
return -1;
}
@@ -1452,7 +1599,594 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
return 0;
}
-void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
+static void pim_elec_bsr_timer(struct event *t)
+{
+ struct bsm_scope *scope = EVENT_ARG(t);
+ struct bsm_frag *frag;
+ struct bsm_hdr *hdr;
+
+ assert(scope->state == BSR_ELECTED);
+
+ scope->bsm_frag_tag++;
+ frag = bsm_frags_first(scope->bsm_frags);
+ assert(frag);
+
+ hdr = (struct bsm_hdr *)(frag->data + PIM_MSG_HEADER_LEN);
+ hdr->frag_tag = htons(scope->bsm_frag_tag);
+
+ unsigned int timer = PIM_BS_TIME;
+
+ if (scope->changed_bsm_trigger) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Sending triggered BSM");
+ scope->changed_bsm_trigger--;
+ timer = 5;
+ } else {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Sending scheduled BSM");
+ pim_bsm_sent(scope);
+ }
+
+ pim_bsm_fwd_whole_sz(scope->pim, frag->data, frag->size, scope->sz_id);
+ scope->current_bsr_last_ts = pim_time_monotonic_sec();
+
+ event_add_timer(router->master, pim_elec_bsr_timer, scope, timer,
+ &scope->bs_timer);
+}
+
+void pim_bsm_changed(struct bsm_scope *scope)
+{
+ struct event t;
+
+ EVENT_OFF(scope->bs_timer);
+ scope->changed_bsm_trigger = 2;
+
+ t.arg = scope;
+ pim_elec_bsr_timer(&t);
+}
+
+static void pim_cand_bsr_pending_expire(struct event *t)
+{
+ struct bsm_scope *scope = EVENT_ARG(t);
+
+ assertf(scope->state == BSR_PENDING, "state=%d", scope->state);
+ assertf(pim_addr_is_any(scope->current_bsr), "current_bsr=%pPA",
+ &scope->current_bsr);
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Elected BSR, wait expired without preferable BSMs");
+
+ scope->state = BSR_ELECTED;
+ scope->current_bsr_prio = scope->cand_bsr_prio;
+ scope->current_bsr = scope->bsr_addrsel.run_addr;
+
+ scope->bsm_frag_tag = frr_weak_random();
+ scope->current_bsr_first_ts = pim_time_monotonic_sec();
+
+ pim_cand_rp_trigger(scope);
+ pim_bsm_generate(scope);
+}
+
+#if PIM_IPV == 6
+static float bsr_addr_delay(pim_addr best, pim_addr local)
+{
+ unsigned int pos;
+ uint32_t best_4b, local_4b;
+ float delay_log;
+
+ for (pos = 0; pos < 12; pos++) {
+ if (best.s6_addr[pos] != local.s6_addr[pos])
+ break;
+ }
+
+ memcpy(&best_4b, &best.s6_addr[pos], 4);
+ memcpy(&local_4b, &local.s6_addr[pos], 4);
+
+ delay_log = log2(1 + ntohl(best_4b) - ntohl(local_4b));
+ delay_log += (12 - pos) * 8;
+ return delay_log / 64.;
+}
+#endif
+
+static void pim_cand_bsr_pending(struct bsm_scope *scope)
+{
+ unsigned int bs_rand_override;
+ uint8_t best_prio;
+ pim_addr best_addr;
+ float prio_delay, addr_delay;
+
+ EVENT_OFF(scope->bs_timer);
+ EVENT_OFF(scope->t_ebsr_regen_bsm);
+ scope->state = BSR_PENDING;
+
+ best_prio = MAX(scope->cand_bsr_prio, scope->current_bsr_prio);
+ best_addr = pim_addr_cmp(scope->bsr_addrsel.run_addr,
+ scope->current_bsr) > 0
+ ? scope->bsr_addrsel.run_addr
+ : scope->current_bsr;
+
+ /* RFC5059 sec.5 */
+#if PIM_IPV == 4
+ if (scope->cand_bsr_prio == best_prio) {
+ prio_delay = 0.; /* log2(1) = 0 */
+ addr_delay = log2(1 + ntohl(best_addr.s_addr) -
+ ntohl(scope->bsr_addrsel.run_addr.s_addr)) /
+ 16.;
+ } else {
+ prio_delay = 2. * log2(1 + best_prio - scope->cand_bsr_prio);
+ addr_delay = 2 - (ntohl(scope->bsr_addrsel.run_addr.s_addr) /
+ (float)(1 << 31));
+ }
+#else
+ if (scope->cand_bsr_prio == best_prio) {
+ prio_delay = 0.; /* log2(1) = 0 */
+ addr_delay = bsr_addr_delay(best_addr,
+ scope->bsr_addrsel.run_addr);
+ } else {
+ prio_delay = 2. * log2(1 + best_prio - scope->cand_bsr_prio);
+ addr_delay = 2 -
+ (ntohl(scope->bsr_addrsel.run_addr.s6_addr32[0]) /
+ (float)(1 << 31));
+ }
+#endif
+
+ bs_rand_override = 5000 + (int)((prio_delay + addr_delay) * 1000.);
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Pending-BSR (%u, %pPA), waiting %ums",
+ scope->cand_bsr_prio, &scope->bsr_addrsel.run_addr,
+ bs_rand_override);
+
+ event_add_timer_msec(router->master, pim_cand_bsr_pending_expire, scope,
+ bs_rand_override, &scope->bs_timer);
+}
+
+static inline pim_addr if_highest_addr(pim_addr cur, struct interface *ifp)
+{
+ struct connected *connected;
+
+ frr_each (if_connected, ifp->connected, connected) {
+ pim_addr conn_addr;
+
+ if (connected->address->family != PIM_AF)
+ continue;
+
+ conn_addr = pim_addr_from_prefix(connected->address);
+ /* highest address */
+ if (pim_addr_cmp(conn_addr, cur) > 0)
+ cur = conn_addr;
+ }
+ return cur;
+}
+
+static void cand_addrsel_clear(struct cand_addrsel *asel)
+{
+ asel->run = false;
+ asel->run_addr = PIMADDR_ANY;
+}
+
+/* returns whether address or active changed */
+static bool cand_addrsel_update(struct cand_addrsel *asel, struct vrf *vrf)
+{
+ bool is_any = false, prev_run = asel->run;
+ struct interface *ifp = NULL;
+ pim_addr new_addr = PIMADDR_ANY;
+
+ if (!asel->cfg_enable)
+ goto out_disable;
+
+ switch (asel->cfg_mode) {
+ case CAND_ADDR_EXPLICIT:
+ new_addr = asel->cfg_addr;
+ ifp = if_lookup_address_local(&asel->cfg_addr, PIM_AF,
+ vrf->vrf_id);
+ break;
+
+ case CAND_ADDR_IFACE:
+ ifp = if_lookup_by_name_vrf(asel->cfg_ifname, vrf);
+
+ if (ifp)
+ new_addr = if_highest_addr(PIMADDR_ANY, ifp);
+ break;
+
+ case CAND_ADDR_ANY:
+ is_any = true;
+ /* fallthru */
+ case CAND_ADDR_LO:
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ if (!if_is_up(ifp))
+ continue;
+ if (is_any || if_is_loopback(ifp) || if_is_vrf(ifp))
+ new_addr = if_highest_addr(new_addr, ifp);
+ }
+ break;
+ }
+
+ if (ifp && !if_is_up(ifp))
+ goto out_disable;
+
+ if (pim_addr_is_any(new_addr))
+ goto out_disable;
+
+ /* nothing changed re. address (don't care about interface changes) */
+ if (asel->run && !pim_addr_cmp(asel->run_addr, new_addr))
+ return !prev_run;
+
+ asel->run = true;
+ asel->run_addr = new_addr;
+ return true;
+
+out_disable:
+ asel->run = false;
+ asel->run_addr = PIMADDR_ANY;
+
+ return prev_run;
+}
+
+static void pim_cand_bsr_stop(struct bsm_scope *scope, bool verbose)
+{
+ cand_addrsel_clear(&scope->bsr_addrsel);
+
+ switch (scope->state) {
+ case NO_INFO:
+ case ACCEPT_ANY:
+ case ACCEPT_PREFERRED:
+ return;
+ case BSR_PENDING:
+ case BSR_ELECTED:
+ break;
+ }
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate BSR ceasing operation");
+
+ EVENT_OFF(scope->t_ebsr_regen_bsm);
+ EVENT_OFF(scope->bs_timer);
+ pim_crp_db_clear(scope);
+ pim_bsm_accept_any(scope);
+}
+
+static void pim_cand_bsr_trigger(struct bsm_scope *scope, bool verbose)
+{
+ /* this is called on all state changes even if we aren't configured
+ * to be C-BSR at all.
+ */
+ if (!scope->bsr_addrsel.run)
+ return;
+
+ if (scope->current_bsr_prio > scope->cand_bsr_prio) {
+ assert(scope->state == ACCEPT_PREFERRED);
+ if (!verbose)
+ return;
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate BSR: known better BSR %pPA (higher priority %u > %u)",
+ &scope->current_bsr, scope->current_bsr_prio,
+ scope->cand_bsr_prio);
+ return;
+ } else if (scope->current_bsr_prio == scope->cand_bsr_prio &&
+ pim_addr_cmp(scope->current_bsr,
+ scope->bsr_addrsel.run_addr) > 0) {
+ assert(scope->state == ACCEPT_PREFERRED);
+ if (!verbose)
+ return;
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate BSR: known better BSR %pPA (higher address > %pPA)",
+ &scope->current_bsr,
+ &scope->bsr_addrsel.run_addr);
+ return;
+ }
+
+ if (!pim_addr_cmp(scope->current_bsr, scope->bsr_addrsel.run_addr))
+ return;
+
+ pim_cand_bsr_pending(scope);
+}
+
+void pim_cand_bsr_apply(struct bsm_scope *scope)
+{
+ if (!cand_addrsel_update(&scope->bsr_addrsel, scope->pim->vrf))
+ return;
+
+ if (!scope->bsr_addrsel.run) {
+ pim_cand_bsr_stop(scope, true);
+ return;
+ }
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate BSR: %pPA, priority %u",
+ &scope->bsr_addrsel.run_addr, scope->cand_bsr_prio);
+
+ pim_cand_bsr_trigger(scope, true);
+}
+
+static void pim_cand_rp_adv_stop_maybe(struct bsm_scope *scope)
+{
+ /* actual check whether stop should be sent - covers address
+ * changes as well as run_addr = 0.0.0.0 (C-RP shutdown)
+ */
+ if (pim_addr_is_any(scope->cand_rp_prev_addr) ||
+ !pim_addr_cmp(scope->cand_rp_prev_addr,
+ scope->cand_rp_addrsel.run_addr))
+ return;
+
+ switch (scope->state) {
+ case ACCEPT_PREFERRED:
+ case BSR_ELECTED:
+ break;
+
+ case NO_INFO:
+ case ACCEPT_ANY:
+ case BSR_PENDING:
+ default:
+ return;
+ }
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate-RP (-, %pPA) deregistering self to %pPA",
+ &scope->cand_rp_prev_addr, &scope->current_bsr);
+
+ struct cand_rp_msg *msg;
+ uint8_t buf[PIM_MSG_HEADER_LEN + sizeof(*msg) + sizeof(pim_encoded_group)];
+
+ msg = (struct cand_rp_msg *)(&buf[PIM_MSG_HEADER_LEN]);
+ msg->prefix_cnt = 0;
+ msg->rp_prio = 255;
+ msg->rp_holdtime = 0;
+ msg->rp_addr.family = PIM_IANA_AFI;
+ msg->rp_addr.reserved = 0;
+ msg->rp_addr.addr = scope->cand_rp_prev_addr;
+
+ pim_msg_build_header(PIMADDR_ANY, scope->current_bsr, buf, sizeof(buf),
+ PIM_MSG_TYPE_CANDIDATE, false);
+
+ if (pim_msg_send(scope->unicast_sock, PIMADDR_ANY, scope->current_bsr,
+ buf, sizeof(buf), NULL)) {
+ zlog_warn("failed to send Cand-RP message: %m");
+ }
+
+ scope->cand_rp_prev_addr = PIMADDR_ANY;
+}
+
+static void pim_cand_rp_adv(struct event *t)
+{
+ struct bsm_scope *scope = EVENT_ARG(t);
+ int next_msec;
+
+ pim_cand_rp_adv_stop_maybe(scope);
+
+ if (!scope->cand_rp_addrsel.run) {
+ scope->cand_rp_adv_trigger = 0;
+ return;
+ }
+
+ switch (scope->state) {
+ case ACCEPT_PREFERRED:
+ case BSR_ELECTED:
+ break;
+
+ case ACCEPT_ANY:
+ case BSR_PENDING:
+ case NO_INFO:
+ default:
+ /* state change will retrigger */
+ scope->cand_rp_adv_trigger = 0;
+
+ zlog_warn("Candidate-RP advertisement not sent in state %d",
+ scope->state);
+ return;
+ }
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate-RP (%u, %pPA) advertising %zu groups to %pPA",
+ scope->cand_rp_prio, &scope->cand_rp_addrsel.run_addr,
+ cand_rp_groups_count(scope->cand_rp_groups),
+ &scope->current_bsr);
+
+ struct cand_rp_group *grp;
+ struct cand_rp_msg *msg;
+ uint8_t buf[PIM_MSG_HEADER_LEN + sizeof(*msg) +
+ sizeof(pim_encoded_group) *
+ cand_rp_groups_count(scope->cand_rp_groups)];
+ size_t i = 0;
+
+
+ msg = (struct cand_rp_msg *)(&buf[PIM_MSG_HEADER_LEN]);
+ msg->prefix_cnt = cand_rp_groups_count(scope->cand_rp_groups);
+ msg->rp_prio = scope->cand_rp_prio;
+ msg->rp_holdtime =
+ htons(MAX(151, (scope->cand_rp_interval * 5 + 1) / 2));
+ msg->rp_addr.family = PIM_IANA_AFI;
+ msg->rp_addr.reserved = 0;
+ msg->rp_addr.addr = scope->cand_rp_addrsel.run_addr;
+
+ frr_each (cand_rp_groups, scope->cand_rp_groups, grp) {
+ memset(&msg->groups[i], 0, sizeof(msg->groups[i]));
+
+ msg->groups[i].family = PIM_IANA_AFI;
+ msg->groups[i].mask = grp->p.prefixlen;
+ msg->groups[i].addr = grp->p.prefix;
+ i++;
+ }
+
+ scope->cand_rp_prev_addr = scope->cand_rp_addrsel.run_addr;
+
+ pim_msg_build_header(scope->cand_rp_addrsel.run_addr, scope->current_bsr,
+ buf, sizeof(buf), PIM_MSG_TYPE_CANDIDATE, false);
+
+ if (pim_msg_send(scope->unicast_sock, scope->cand_rp_addrsel.run_addr,
+ scope->current_bsr, buf, sizeof(buf), NULL)) {
+ zlog_warn("failed to send Cand-RP message: %m");
+ }
+
+ /* -1s...+1s */
+ next_msec = (frr_weak_random() & 2047) - 1024;
+
+ if (scope->cand_rp_adv_trigger) {
+ scope->cand_rp_adv_trigger--;
+ next_msec += 2000;
+ } else
+ next_msec += scope->cand_rp_interval * 1000;
+
+ event_add_timer_msec(router->master, pim_cand_rp_adv, scope, next_msec,
+ &scope->cand_rp_adv_timer);
+}
+
+void pim_cand_rp_trigger(struct bsm_scope *scope)
+{
+ if (scope->cand_rp_adv_trigger && scope->cand_rp_addrsel.run) {
+ scope->cand_rp_adv_trigger = PIM_CRP_ADV_TRIGCOUNT;
+
+ /* already scheduled to send triggered advertisements, don't
+ * reschedule so burst changes don't result in an advertisement
+ * burst
+ */
+ return;
+ }
+
+ EVENT_OFF(scope->cand_rp_adv_timer);
+
+ if (!scope->cand_rp_addrsel.run)
+ return;
+
+ scope->cand_rp_adv_trigger = PIM_CRP_ADV_TRIGCOUNT;
+
+ struct event t;
+
+ t.arg = scope;
+ pim_cand_rp_adv(&t);
+}
+
+void pim_cand_rp_apply(struct bsm_scope *scope)
{
- /* stub for Candidate-RP */
+ if (!cand_addrsel_update(&scope->cand_rp_addrsel, scope->pim->vrf))
+ return;
+
+ if (!scope->cand_rp_addrsel.run) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate RP ceasing operation");
+
+ cand_addrsel_clear(&scope->cand_rp_addrsel);
+ EVENT_OFF(scope->cand_rp_adv_timer);
+ pim_cand_rp_adv_stop_maybe(scope);
+ scope->cand_rp_adv_trigger = 0;
+ return;
+ }
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate RP: %pPA, priority %u",
+ &scope->cand_rp_addrsel.run_addr,
+ scope->cand_rp_prio);
+
+ pim_cand_rp_trigger(scope);
+}
+
+void pim_cand_rp_grp_add(struct bsm_scope *scope, const prefix_pim *p)
+{
+ struct cand_rp_group *grp, ref;
+
+ ref.p = *p;
+ grp = cand_rp_groups_find(scope->cand_rp_groups, &ref);
+ if (grp)
+ return;
+
+ grp = XCALLOC(MTYPE_PIM_CAND_RP_GRP, sizeof(*grp));
+ grp->p = *p;
+ cand_rp_groups_add(scope->cand_rp_groups, grp);
+
+ pim_cand_rp_trigger(scope);
+}
+
+void pim_cand_rp_grp_del(struct bsm_scope *scope, const prefix_pim *p)
+{
+ struct cand_rp_group *grp, ref;
+
+ ref.p = *p;
+ grp = cand_rp_groups_find(scope->cand_rp_groups, &ref);
+ if (!grp)
+ return;
+
+ cand_rp_groups_del(scope->cand_rp_groups, grp);
+ XFREE(MTYPE_PIM_CAND_RP_GRP, grp);
+
+ pim_cand_rp_trigger(scope);
+}
+
+static struct event *t_cand_addrs_reapply;
+
+static void pim_cand_addrs_reapply(struct event *t)
+{
+ struct vrf *vrf;
+
+ RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+ struct pim_instance *pi = vrf->info;
+
+ if (!pi)
+ continue;
+
+ /* these call cand_addrsel_update() and apply changes */
+ pim_cand_bsr_apply(&pi->global_scope);
+ pim_cand_rp_apply(&pi->global_scope);
+ }
+}
+
+void pim_cand_addrs_changed(void)
+{
+ EVENT_OFF(t_cand_addrs_reapply);
+ event_add_timer_msec(router->master, pim_cand_addrs_reapply, NULL, 1,
+ &t_cand_addrs_reapply);
+}
+
+static void cand_addrsel_config_write(struct vty *vty,
+ struct cand_addrsel *addrsel)
+{
+ switch (addrsel->cfg_mode) {
+ case CAND_ADDR_LO:
+ break;
+ case CAND_ADDR_ANY:
+ vty_out(vty, " source any");
+ break;
+ case CAND_ADDR_IFACE:
+ vty_out(vty, " source interface %s", addrsel->cfg_ifname);
+ break;
+ case CAND_ADDR_EXPLICIT:
+ vty_out(vty, " source address %pPA", &addrsel->cfg_addr);
+ break;
+ }
+}
+
+int pim_cand_config_write(struct pim_instance *pim, struct vty *vty)
+{
+ struct bsm_scope *scope = &pim->global_scope;
+ int ret = 0;
+
+ if (scope->cand_rp_addrsel.cfg_enable) {
+ vty_out(vty, " bsr candidate-rp");
+ if (scope->cand_rp_prio != 192)
+ vty_out(vty, " priority %u", scope->cand_rp_prio);
+ if (scope->cand_rp_interval != PIM_CRP_ADV_INTERVAL)
+ vty_out(vty, " interval %u", scope->cand_rp_interval);
+ cand_addrsel_config_write(vty, &scope->cand_rp_addrsel);
+ vty_out(vty, "\n");
+ ret++;
+
+ struct cand_rp_group *group;
+
+ frr_each (cand_rp_groups, scope->cand_rp_groups, group) {
+ vty_out(vty, " bsr candidate-rp group %pFX\n",
+ &group->p);
+ ret++;
+ }
+ }
+
+ if (scope->bsr_addrsel.cfg_enable) {
+ vty_out(vty, " bsr candidate-bsr");
+ if (scope->cand_bsr_prio != 64)
+ vty_out(vty, " priority %u", scope->cand_bsr_prio);
+ cand_addrsel_config_write(vty, &scope->bsr_addrsel);
+ vty_out(vty, "\n");
+ ret++;
+ }
+ return ret;
}
diff --git a/pimd/pim_bsm.h b/pimd/pim_bsm.h
index fb09e3b1cc..1eacc1be57 100644
--- a/pimd/pim_bsm.h
+++ b/pimd/pim_bsm.h
@@ -21,6 +21,13 @@
#define PIM_BS_TIME 60 /* RFC 5059 - Sec 5 */
#define PIM_BSR_DEFAULT_TIMEOUT 130 /* RFC 5059 - Sec 5 */
+/* number of times to include rp-count = 0 ranges */
+#define PIM_BSR_DEAD_COUNT 3
+
+#define PIM_CRP_ADV_TRIGCOUNT 3
+#define PIM_CRP_ADV_INTERVAL 60
+#define PIM_CRP_HOLDTIME 150
+
/* These structures are only encoded IPv4 specific */
#define PIM_BSM_HDR_LEN sizeof(struct bsm_hdr)
#define PIM_BSM_GRP_LEN sizeof(struct bsmmsg_grpinfo)
@@ -33,19 +40,61 @@
* ==============
*/
-/* Non candidate BSR states */
-enum ncbsr_state {
+/* BSR states
+ *
+ * Candidate BSR starts at BSR_PENDING, moves to AP or E depending on
+ * loss/win. Will never go into AA (because in that case it'd become BSR
+ * itself.)
+ *
+ * Non-Candidate BSR starts at NO_INFO, moves to AP & AA depending on
+ * a BSR being available or not.
+ */
+enum bsr_state {
NO_INFO = 0,
ACCEPT_ANY,
- ACCEPT_PREFERRED
+ ACCEPT_PREFERRED, /* = same as C-BSR if candidate */
+ BSR_PENDING,
+ BSR_ELECTED,
+};
+
+enum cand_addr {
+ CAND_ADDR_LO = 0,
+ CAND_ADDR_ANY,
+ CAND_ADDR_IFACE,
+ CAND_ADDR_EXPLICIT,
};
+/* used separately for Cand-RP and Cand-BSR */
+struct cand_addrsel {
+ bool cfg_enable;
+ enum cand_addr cfg_mode : 8;
+
+ /* only valid for mode==CAND_ADDR_IFACE */
+ char cfg_ifname[IFNAMSIZ];
+ /* only valid for mode==CAND_ADDR_EXPLICIT */
+ pim_addr cfg_addr;
+
+ /* running state updated based on above on zebra events */
+ pim_addr run_addr;
+ bool run;
+};
+
+
PREDECL_DLIST(bsm_frags);
+PREDECL_RBTREE_UNIQ(cand_rp_groups);
+
+/* n*m "table" accessed both by-RP and by-group */
+PREDECL_RBTREE_UNIQ(bsr_crp_rps);
+PREDECL_RBTREE_UNIQ(bsr_crp_groups);
+
+PREDECL_RBTREE_UNIQ(bsr_crp_rp_groups);
+PREDECL_RBTREE_UNIQ(bsr_crp_group_rps);
/* BSM scope - bsm processing is per scope */
struct bsm_scope {
int sz_id; /* scope zone id */
- enum ncbsr_state state; /* non candidate BSR state */
+ enum bsr_state state; /* BSR state */
+
bool accept_nofwd_bsm; /* no fwd bsm accepted for scope */
pim_addr current_bsr; /* current elected BSR for the sz */
uint32_t current_bsr_prio; /* current BSR priority */
@@ -60,6 +109,93 @@ struct bsm_scope {
struct route_table *bsrp_table; /* group2rp mapping rcvd from BSR */
struct event *bs_timer; /* Boot strap timer */
+
+ /* Candidate BSR config */
+ struct cand_addrsel bsr_addrsel;
+ uint8_t cand_bsr_prio;
+
+ /* Candidate BSR state */
+ uint8_t current_cand_bsr_prio;
+ /* if nothing changed from Cand-RP data we received, less work... */
+ bool elec_rp_data_changed;
+
+ /* data that the E-BSR keeps - not to be confused with Candidate-RP
+ * stuff below. These two here are the info about all the Cand-RPs
+ * that we as a BSR received information for in Cand-RP-adv packets.
+ */
+ struct bsr_crp_rps_head ebsr_rps[1];
+ struct bsr_crp_groups_head ebsr_groups[1];
+
+ /* set if we have any group ranges where we're currently advertising
+ * rp-count = 0 (includes both ranges without any RPs as well as
+ * ranges with only NHT-unreachable RPs)
+ */
+ bool ebsr_have_dead_pending;
+ unsigned int changed_bsm_trigger;
+
+ struct event *t_ebsr_regen_bsm;
+
+ /* Candidate RP config */
+ struct cand_addrsel cand_rp_addrsel;
+ uint8_t cand_rp_prio;
+ unsigned int cand_rp_interval; /* default: PIM_CRP_ADV_INTERVAL=60 */
+ /* holdtime is not configurable, always 2.5 * interval. */
+ struct cand_rp_groups_head cand_rp_groups[1];
+
+ /* Candidate RP state */
+ int unicast_sock;
+ struct event *unicast_read;
+ struct event *cand_rp_adv_timer;
+ unsigned int cand_rp_adv_trigger; /* # trigg. C-RP-Adv left to send */
+
+ /* for sending holdtime=0 zap */
+ pim_addr cand_rp_prev_addr;
+};
+
+struct cand_rp_group {
+ struct cand_rp_groups_item item;
+
+ prefix_pim p;
+};
+
+struct bsr_crp_group {
+ struct bsr_crp_groups_item item;
+
+ prefix_pim range;
+ struct bsr_crp_group_rps_head rps[1];
+
+ size_t n_selected;
+ bool deleted_selected : 1;
+
+ /* number of times we've advertised this range with rp-count = 0 */
+ unsigned int dead_count;
+};
+
+struct bsr_crp_rp {
+ struct bsr_crp_rps_item item;
+
+ pim_addr addr;
+ struct bsr_crp_rp_groups_head groups[1];
+
+ struct bsm_scope *scope;
+ struct event *t_hold;
+ time_t seen_first;
+ time_t seen_last;
+
+ uint16_t holdtime;
+ uint8_t prio;
+ bool nht_ok;
+};
+
+/* "n * m" RP<->Group tie-in */
+struct bsr_crp_item {
+ struct bsr_crp_rp_groups_item r_g_item;
+ struct bsr_crp_group_rps_item g_r_item;
+
+ struct bsr_crp_group *group;
+ struct bsr_crp_rp *rp;
+
+ bool selected : 1;
};
/* BSM packet (= fragment) - this is stored as list in bsm_frags inside scope
@@ -200,6 +336,14 @@ struct bsmmsg_rpinfo {
uint8_t reserved;
} __attribute__((packed));
+struct cand_rp_msg {
+ uint8_t prefix_cnt;
+ uint8_t rp_prio;
+ uint16_t rp_holdtime;
+ pim_encoded_unicast rp_addr;
+ pim_encoded_group groups[0];
+} __attribute__((packed));
+
/* API */
void pim_bsm_proc_init(struct pim_instance *pim);
void pim_bsm_proc_free(struct pim_instance *pim);
@@ -210,4 +354,39 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
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_bsm_generate(struct bsm_scope *scope);
+void pim_bsm_changed(struct bsm_scope *scope);
+void pim_bsm_sent(struct bsm_scope *scope);
+void pim_bsm_frags_free(struct bsm_scope *scope);
+
+bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
+ int buflen, uint16_t bsm_frag_tag);
+
+void pim_cand_bsr_apply(struct bsm_scope *scope);
+void pim_cand_rp_apply(struct bsm_scope *scope);
+void pim_cand_rp_trigger(struct bsm_scope *scope);
+void pim_cand_rp_grp_add(struct bsm_scope *scope, const prefix_pim *p);
+void pim_cand_rp_grp_del(struct bsm_scope *scope, const prefix_pim *p);
+
+void pim_cand_addrs_changed(void);
+
+int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf,
+ uint32_t buf_size);
+
+struct pim_nexthop_cache;
+void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc);
+
+void pim_crp_db_clear(struct bsm_scope *scope);
+int pim_crp_db_show(struct vty *vty, struct bsm_scope *scope, bool json);
+int pim_crp_groups_show(struct vty *vty, struct bsm_scope *scope, bool json);
+
+int pim_cand_config_write(struct pim_instance *pim, struct vty *vty);
+
+DECLARE_MTYPE(PIM_BSM_FRAG);
+
+DECLARE_MTYPE(PIM_BSM_FRAG);
+
+DECLARE_MTYPE(PIM_BSM_FRAG);
+
#endif
diff --git a/pimd/pim_bsr_rpdb.c b/pimd/pim_bsr_rpdb.c
new file mode 100644
index 0000000000..3ec9f99cd1
--- /dev/null
+++ b/pimd/pim_bsr_rpdb.c
@@ -0,0 +1,634 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* PIM RP database for BSR operation
+ * Copyright (C) 2021 David Lamparter for NetDEF, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <lib/network.h>
+#include <lib/iana_afi.h>
+#include <lib/sockunion.h>
+
+#include "if.h"
+#include "pimd.h"
+#include "pim_iface.h"
+#include "pim_instance.h"
+#include "pim_rpf.h"
+#include "pim_hello.h"
+#include "pim_pim.h"
+#include "pim_nht.h"
+#include "pim_bsm.h"
+#include "pim_time.h"
+
+/* safety limits to prevent DoS/memory exhaustion attacks against the BSR
+ *
+ * The BSR is more susceptible than other PIM protocol operation because
+ * Candidate-RP messages are unicast to the BSR without any 2-way interaction
+ * and can thus be spoofed blindly(!) from anywhere in the internet.
+ *
+ * Everything else is on-link, multicast, or requires an adjacency - much
+ * harder to mess with.
+ */
+
+/* total number of RPs we keep information for */
+static size_t bsr_max_rps = 1024;
+
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSR_CRP, "PIM BSR C-RP");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSR_GROUP, "PIM BSR range");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSR_ITEM, "PIM BSR C-RP range item");
+
+static int rp_cmp(const struct bsr_crp_rp *a, const struct bsr_crp_rp *b)
+{
+ return pim_addr_cmp(a->addr, b->addr);
+}
+
+DECLARE_RBTREE_UNIQ(bsr_crp_rps, struct bsr_crp_rp, item, rp_cmp);
+
+static int group_cmp(const struct bsr_crp_group *a,
+ const struct bsr_crp_group *b)
+{
+ return prefix_cmp(&a->range, &b->range);
+}
+
+DECLARE_RBTREE_UNIQ(bsr_crp_groups, struct bsr_crp_group, item, group_cmp);
+
+static int r_g_cmp(const struct bsr_crp_item *a, const struct bsr_crp_item *b)
+{
+ return prefix_cmp(&a->group->range, &b->group->range);
+}
+
+DECLARE_RBTREE_UNIQ(bsr_crp_rp_groups, struct bsr_crp_item, r_g_item, r_g_cmp);
+
+static int g_r_cmp(const struct bsr_crp_item *a, const struct bsr_crp_item *b)
+{
+ const struct bsr_crp_rp *rp_a = a->rp, *rp_b = b->rp;
+
+ /* NHT-failed RPs last */
+ if (rp_a->nht_ok > rp_b->nht_ok)
+ return -1;
+ if (rp_a->nht_ok < rp_b->nht_ok)
+ return 1;
+
+ /* This function determines BSR policy in what subset of the received
+ * RP candidates to advertise. The BSR is free to make its choices
+ * any way it deems useful
+ */
+
+ /* lower numeric values are better */
+ if (rp_a->prio < rp_b->prio)
+ return -1;
+ if (rp_a->prio > rp_b->prio)
+ return 1;
+
+ /* prefer older RP for less churn */
+ if (rp_a->seen_first < rp_b->seen_first)
+ return -1;
+ if (rp_a->seen_first > rp_b->seen_first)
+ return 1;
+
+ return pim_addr_cmp(rp_a->addr, rp_b->addr);
+}
+
+DECLARE_RBTREE_UNIQ(bsr_crp_group_rps, struct bsr_crp_item, g_r_item, g_r_cmp);
+
+void pim_bsm_generate(struct bsm_scope *scope)
+{
+ struct bsm_frag *frag;
+ struct bsm_hdr *hdr;
+ bool have_dead = false;
+
+ assertf(scope->state == BSR_ELECTED, "state=%d", scope->state);
+
+ pim_bsm_frags_free(scope);
+
+ struct bsr_crp_group *group;
+ struct bsr_crp_item *item;
+ struct bsr_crp_rp *rp;
+ size_t n_groups = 0, n_rps = 0;
+
+ frr_each (bsr_crp_groups, scope->ebsr_groups, group) {
+ if (group->n_selected == 0) {
+ if (group->dead_count >= PIM_BSR_DEAD_COUNT)
+ continue;
+
+ have_dead = true;
+ } else
+ group->dead_count = 0;
+
+ n_groups++;
+ n_rps += group->n_selected;
+ }
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Generating BSM (%zu ranges, %zu RPs)", n_groups, n_rps);
+
+ size_t datalen = PIM_MSG_HEADER_LEN + sizeof(*hdr) +
+ n_groups * sizeof(struct bsmmsg_grpinfo) +
+ n_rps * sizeof(struct bsmmsg_rpinfo);
+
+ frag = XCALLOC(MTYPE_PIM_BSM_FRAG, sizeof(*frag) + datalen);
+
+ uint8_t *pos = frag->data + PIM_MSG_HEADER_LEN;
+ uint8_t *end = frag->data + datalen;
+
+ hdr = (struct bsm_hdr *)pos;
+ pos += sizeof(*hdr);
+ assert(pos <= end);
+
+ /* TODO: make BSR hashmasklen configurable */
+#if PIM_IPV == 6
+ hdr->hm_len = 126;
+#else
+ hdr->hm_len = 30;
+#endif
+ hdr->bsr_prio = scope->current_bsr_prio;
+ hdr->bsr_addr.family = PIM_IANA_AFI;
+ hdr->bsr_addr.reserved = 0;
+ hdr->bsr_addr.addr = scope->bsr_addrsel.run_addr;
+
+ frr_each (bsr_crp_groups, scope->ebsr_groups, group) {
+ if (group->n_selected == 0 &&
+ group->dead_count >= PIM_BSR_DEAD_COUNT)
+ continue;
+
+ struct bsmmsg_grpinfo *gi = (struct bsmmsg_grpinfo *)pos;
+
+ pos += sizeof(*gi);
+ assert(pos <= end);
+
+ gi->group.family = PIM_MSG_ADDRESS_FAMILY;
+ gi->group.mask = group->range.prefixlen;
+ gi->group.addr = group->range.prefix;
+
+ size_t n_added = 0;
+
+ frr_each (bsr_crp_group_rps, group->rps, item) {
+ if (!item->selected)
+ break;
+
+ struct bsmmsg_rpinfo *ri = (struct bsmmsg_rpinfo *)pos;
+
+ pos += sizeof(*ri);
+ assert(pos <= end);
+
+ rp = item->rp;
+ ri->rpaddr.family = PIM_MSG_ADDRESS_FAMILY;
+ ri->rpaddr.addr = rp->addr;
+ ri->rp_holdtime = htons(rp->holdtime);
+ ri->rp_pri = rp->prio;
+
+ n_added++;
+ }
+
+ gi->rp_count = group->n_selected;
+ gi->frag_rp_count = n_added;
+ assert(n_added == group->n_selected);
+ }
+
+ assertf(pos == end, "end-pos=%td", end - pos);
+ frag->size = datalen;
+
+ bsm_frags_add_head(scope->bsm_frags, frag);
+
+ scope->ebsr_have_dead_pending = have_dead;
+
+ /*
+ * The BSR itself doesn't receive (no loopback) the BSM msgs advertising
+ * the rps. Install the rps directly for the local BSR node.
+ */
+ pim_bsm_parse_install_g2rp(scope, ((uint8_t *) hdr) + PIM_BSM_HDR_LEN,
+ datalen - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN, scope->bsm_frag_tag);
+
+ pim_bsm_changed(scope);
+}
+
+static void pim_bsm_generate_timer(struct event *t)
+{
+ struct bsm_scope *scope = EVENT_ARG(t);
+
+ pim_bsm_generate(scope);
+}
+
+static void pim_bsm_generate_sched(struct bsm_scope *scope)
+{
+ assertf(scope->state == BSR_ELECTED, "state=%d", scope->state);
+
+ if (scope->t_ebsr_regen_bsm)
+ return;
+
+ event_add_timer(router->master, pim_bsm_generate_timer, scope, 1,
+ &scope->t_ebsr_regen_bsm);
+}
+
+void pim_bsm_sent(struct bsm_scope *scope)
+{
+ struct bsr_crp_group *group;
+ bool have_dead = false, changed = false;
+
+ if (!scope->ebsr_have_dead_pending)
+ return;
+
+ frr_each_safe (bsr_crp_groups, scope->ebsr_groups, group) {
+ if (group->n_selected != 0)
+ continue;
+
+ if (group->dead_count < PIM_BSR_DEAD_COUNT) {
+ group->dead_count++;
+ have_dead = true;
+ continue;
+ }
+
+ changed = true;
+
+ if (bsr_crp_group_rps_count(group->rps))
+ /* have RPs, but none selected */
+ continue;
+
+ /* no reason to keep this range anymore */
+ bsr_crp_groups_del(scope->ebsr_groups, group);
+ bsr_crp_group_rps_fini(group->rps);
+ XFREE(MTYPE_PIM_BSR_GROUP, group);
+ continue;
+ }
+
+ scope->ebsr_have_dead_pending = have_dead;
+ if (changed)
+ pim_bsm_generate_sched(scope);
+}
+
+static void bsr_crp_reselect(struct bsm_scope *scope,
+ struct bsr_crp_group *group)
+{
+ bool changed = false;
+ struct bsr_crp_item *item;
+ size_t n_selected = 0;
+
+ frr_each (bsr_crp_group_rps, group->rps, item) {
+ bool select = false;
+
+ /* hardcode best 2 RPs for now */
+ if (item->rp->nht_ok && n_selected < 2) {
+ select = true;
+ n_selected++;
+ }
+
+ if (item->selected != select) {
+ changed = true;
+ item->selected = select;
+ }
+ }
+
+ changed |= group->deleted_selected;
+ group->deleted_selected = false;
+ group->n_selected = n_selected;
+
+ if (changed)
+ pim_bsm_generate_sched(scope);
+
+ scope->elec_rp_data_changed |= changed;
+}
+
+/* changing rp->nht_ok or rp->prio affects the sort order in group->rp
+ * lists, so need a delete & re-add if either changes
+ */
+static void pim_crp_nht_prio_change(struct bsr_crp_rp *rp, bool nht_ok,
+ uint8_t prio)
+{
+ struct bsr_crp_item *item;
+
+ frr_each (bsr_crp_rp_groups, rp->groups, item)
+ bsr_crp_group_rps_del(item->group->rps, item);
+
+ rp->prio = prio;
+ rp->nht_ok = nht_ok;
+
+ frr_each (bsr_crp_rp_groups, rp->groups, item) {
+ bsr_crp_group_rps_add(item->group->rps, item);
+ bsr_crp_reselect(rp->scope, item->group);
+ }
+}
+
+static struct bsr_crp_group *group_get(struct bsm_scope *scope,
+ prefix_pim *range)
+{
+ struct bsr_crp_group *group, ref;
+
+ ref.range = *range;
+ group = bsr_crp_groups_find(scope->ebsr_groups, &ref);
+ if (!group) {
+ group = XCALLOC(MTYPE_PIM_BSR_GROUP, sizeof(*group));
+ group->range = *range;
+ bsr_crp_group_rps_init(group->rps);
+ bsr_crp_groups_add(scope->ebsr_groups, group);
+ }
+ return group;
+}
+
+static void pim_crp_update(struct bsr_crp_rp *rp, struct cand_rp_msg *msg,
+ size_t ngroups)
+{
+ struct bsr_crp_rp_groups_head oldgroups[1];
+ struct bsr_crp_item *item, itemref;
+ struct bsr_crp_group *group, groupref;
+
+ //struct bsm_scope *scope = rp->scope;
+
+ bsr_crp_rp_groups_init(oldgroups);
+ bsr_crp_rp_groups_swap_all(rp->groups, oldgroups);
+
+ itemref.rp = rp;
+ itemref.group = &groupref;
+
+ assert(msg || ngroups == 0);
+
+ for (size_t i = 0; i < ngroups; i++) {
+ if (msg->groups[i].family != PIM_MSG_ADDRESS_FAMILY)
+ continue;
+ if (msg->groups[i].bidir)
+ continue;
+
+ prefix_pim pfx;
+
+ pfx.family = PIM_AF;
+ pfx.prefixlen = msg->groups[i].mask;
+ pfx.prefix = msg->groups[i].addr;
+
+#if PIM_IPV == 4
+ if (pfx.prefixlen < 4)
+ continue;
+ if (!IPV4_CLASS_DE(ntohl(pfx.prefix.s_addr)))
+ continue;
+#endif
+
+ apply_mask(&pfx);
+
+ groupref.range = pfx;
+ item = bsr_crp_rp_groups_find(oldgroups, &itemref);
+
+ if (item) {
+ bsr_crp_rp_groups_del(oldgroups, item);
+ bsr_crp_rp_groups_add(rp->groups, item);
+ continue;
+ }
+
+ group = group_get(rp->scope, &pfx);
+
+ item = XCALLOC(MTYPE_PIM_BSR_ITEM, sizeof(*item));
+ item->rp = rp;
+ item->group = group;
+
+ bsr_crp_group_rps_add(group->rps, item);
+ bsr_crp_rp_groups_add(rp->groups, item);
+
+ bsr_crp_reselect(rp->scope, group);
+ }
+
+ while ((item = bsr_crp_rp_groups_pop(oldgroups))) {
+ group = item->group;
+ if (item->selected)
+ group->deleted_selected = true;
+
+ bsr_crp_group_rps_del(group->rps, item);
+ XFREE(MTYPE_PIM_BSR_ITEM, item);
+
+ bsr_crp_reselect(rp->scope, group);
+ }
+ bsr_crp_rp_groups_fini(oldgroups);
+
+ if (msg && msg->rp_prio != rp->prio)
+ pim_crp_nht_prio_change(rp, rp->nht_ok, msg->rp_prio);
+}
+
+void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
+{
+ struct bsm_scope *scope = &pim->global_scope;
+ struct bsr_crp_rp *rp, ref;
+ bool ok;
+
+ ref.addr = pnc->rpf.rpf_addr;
+ rp = bsr_crp_rps_find(scope->ebsr_rps, &ref);
+ assertf(rp, "addr=%pPA", &ref.addr);
+
+ ok = CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID);
+ if (ok == rp->nht_ok)
+ return;
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate-RP %pPA NHT %s", &rp->addr, ok ? "UP" : "DOWN");
+ pim_crp_nht_prio_change(rp, ok, rp->prio);
+}
+
+static void pim_crp_free(struct pim_instance *pim, struct bsr_crp_rp *rp)
+{
+ EVENT_OFF(rp->t_hold);
+ pim_nht_candrp_del(pim, rp->addr);
+ bsr_crp_rp_groups_fini(rp->groups);
+
+ XFREE(MTYPE_PIM_BSR_CRP, rp);
+}
+
+static void pim_crp_expire(struct event *t)
+{
+ struct bsr_crp_rp *rp = EVENT_ARG(t);
+ struct pim_instance *pim = rp->scope->pim;
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate-RP %pPA holdtime expired", &rp->addr);
+
+ pim_crp_update(rp, NULL, 0);
+
+ bsr_crp_rps_del(rp->scope->ebsr_rps, rp);
+ pim_crp_free(pim, rp);
+}
+
+int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf,
+ uint32_t buf_size)
+{
+ struct pim_interface *pim_ifp = NULL;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+
+ pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s: multicast not enabled on interface %s",
+ __func__, ifp->name);
+ return -1;
+ }
+
+ //pim_ifp->pim_ifstat_bsm_rx++;
+ pim = pim_ifp->pim;
+ //pim->bsm_rcvd++;
+
+ if (!pim_ifp->bsm_enable) {
+ zlog_warn("%s: BSM not enabled on interface %s", __func__,
+ ifp->name);
+ //pim_ifp->pim_ifstat_bsm_cfg_miss++;
+ //pim->bsm_dropped++;
+ return -1;
+ }
+
+ if (buf_size < (PIM_MSG_HEADER_LEN + sizeof(struct cand_rp_msg))) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s: received buffer length of %d which is too small to properly decode",
+ __func__, buf_size);
+ return -1;
+ }
+
+ scope = &pim->global_scope;
+
+ if (scope->state < BSR_PENDING) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("received Candidate-RP message from %pPA while not BSR",
+ &src_dst->src);
+ return -1;
+ }
+
+ size_t remain = buf_size;
+ struct cand_rp_msg *crp_hdr;
+
+ buf += PIM_MSG_HEADER_LEN;
+ remain -= PIM_MSG_HEADER_LEN;
+
+ crp_hdr = (struct cand_rp_msg *)buf;
+ buf += sizeof(*crp_hdr);
+ remain -= sizeof(*crp_hdr);
+
+ size_t ngroups = crp_hdr->prefix_cnt;
+
+ if (remain < ngroups * sizeof(struct pim_encoded_group_ipv4)) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("truncated Candidate-RP advertisement for RP %pPA from %pPA (too short for %zu groups)",
+ (pim_addr *)&crp_hdr->rp_addr.addr,
+ &src_dst->src, ngroups);
+ return -1;
+ }
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("Candidate-RP: %pPA, prio=%u (from %pPA, %zu groups)",
+ (pim_addr *)&crp_hdr->rp_addr.addr, crp_hdr->rp_prio,
+ &src_dst->src, ngroups);
+
+
+ struct bsr_crp_rp *rp, ref;
+
+ ref.addr = crp_hdr->rp_addr.addr;
+ rp = bsr_crp_rps_find(scope->ebsr_rps, &ref);
+
+ if (!rp) {
+ if (bsr_crp_rps_count(scope->ebsr_rps) >= bsr_max_rps) {
+ zlog_err("BSR: number of tracked Candidate RPs (%zu) exceeds DoS-protection limit (%zu), dropping advertisement for RP %pPA (packet source %pPA)",
+ bsr_crp_rps_count(scope->ebsr_rps),
+ bsr_max_rps, (pim_addr *)&crp_hdr->rp_addr.addr,
+ &src_dst->src);
+ return -1;
+ }
+
+ if (PIM_DEBUG_BSM)
+ zlog_debug("new Candidate-RP: %pPA (from %pPA)",
+ (pim_addr *)&crp_hdr->rp_addr.addr,
+ &src_dst->src);
+
+ rp = XCALLOC(MTYPE_PIM_BSR_CRP, sizeof(*rp));
+ rp->scope = scope;
+ rp->addr = crp_hdr->rp_addr.addr;
+ rp->prio = 255;
+ bsr_crp_rp_groups_init(rp->groups);
+ rp->seen_first = monotime(NULL);
+
+ bsr_crp_rps_add(scope->ebsr_rps, rp);
+ rp->nht_ok = pim_nht_candrp_add(pim, rp->addr);
+ }
+
+ rp->seen_last = monotime(NULL);
+ rp->holdtime = ntohs(crp_hdr->rp_holdtime);
+
+ EVENT_OFF(rp->t_hold);
+ event_add_timer(router->master, pim_crp_expire, rp,
+ ntohs(crp_hdr->rp_holdtime), &rp->t_hold);
+
+ pim_crp_update(rp, crp_hdr, ngroups);
+ return 0;
+}
+
+void pim_crp_db_clear(struct bsm_scope *scope)
+{
+ struct bsr_crp_rp *rp;
+ struct bsr_crp_group *group;
+ struct bsr_crp_item *item;
+
+ while ((rp = bsr_crp_rps_pop(scope->ebsr_rps))) {
+ while ((item = bsr_crp_rp_groups_pop(rp->groups))) {
+ group = item->group;
+
+ if (item->selected)
+ group->deleted_selected = true;
+
+ bsr_crp_group_rps_del(group->rps, item);
+ XFREE(MTYPE_PIM_BSR_ITEM, item);
+ }
+ pim_crp_free(scope->pim, rp);
+ }
+
+ while ((group = bsr_crp_groups_pop(scope->ebsr_groups))) {
+ assertf(!bsr_crp_group_rps_count(group->rps),
+ "range=%pFX rp_count=%zu", &group->range,
+ bsr_crp_group_rps_count(group->rps));
+
+ bsr_crp_group_rps_fini(group->rps);
+ XFREE(MTYPE_PIM_BSR_GROUP, group);
+ }
+}
+
+int pim_crp_db_show(struct vty *vty, struct bsm_scope *scope, bool json)
+{
+ struct bsr_crp_rp *rp;
+ struct bsr_crp_item *item;
+
+ vty_out(vty, "RP/Group NHT Prio Uptime Hold\n");
+
+ frr_each (bsr_crp_rps, scope->ebsr_rps, rp) {
+ vty_out(vty, "%-15pPA %4s %4u %8ld %4lu\n", &rp->addr,
+ rp->nht_ok ? "UP" : "DOWN", rp->prio,
+ (long)(monotime(NULL) - rp->seen_first),
+ event_timer_remain_second(rp->t_hold));
+
+ frr_each (bsr_crp_rp_groups, rp->groups, item)
+ vty_out(vty, "%c %-18pFX\n", item->selected ? '>' : ' ',
+ &item->group->range);
+ }
+
+ return CMD_SUCCESS;
+}
+
+int pim_crp_groups_show(struct vty *vty, struct bsm_scope *scope, bool json)
+{
+ struct bsr_crp_group *group;
+ struct bsr_crp_item *item;
+
+ if (scope->ebsr_have_dead_pending)
+ vty_out(vty, "have_dead_pending\n");
+
+ frr_each (bsr_crp_groups, scope->ebsr_groups, group) {
+ vty_out(vty, "%c %pFX", group->n_selected ? '^' : '!',
+ &group->range);
+ if (group->n_selected == 0)
+ vty_out(vty, " (dead %u)", group->dead_count);
+
+ vty_out(vty, "\n");
+
+ frr_each (bsr_crp_group_rps, group->rps, item)
+ vty_out(vty, "%c %pPA\n", item->selected ? '>' : ' ',
+ &item->rp->addr);
+ }
+
+ return CMD_SUCCESS;
+}
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index f57048c703..934da2d53e 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -66,27 +66,6 @@ static struct cmd_node debug_node = {
.config_write = pim_debug_config_write,
};
-static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[],
- const int argc, int *idx, bool uj)
-{
- struct vrf *vrf;
-
- if (argv_find(argv, argc, "NAME", idx))
- vrf = vrf_lookup_by_name(argv[*idx]->arg);
- else
- vrf = vrf_lookup_by_id(VRF_DEFAULT);
-
- if (!vrf) {
- if (uj)
- vty_json_empty(vty, NULL);
- else
- vty_out(vty, "Specified VRF: %s does not exist\n",
- argv[*idx]->arg);
- }
-
- return vrf;
-}
-
static void pim_show_assert_helper(struct vty *vty,
struct pim_interface *pim_ifp,
struct pim_ifchannel *ch, time_t now)
@@ -588,7 +567,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
}
static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty,
- bool uj)
+ bool uj, enum gm_join_type join_type)
{
struct interface *ifp;
time_t now;
@@ -633,6 +612,10 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty,
char source_str[INET_ADDRSTRLEN];
char uptime[10];
+ if (ij->join_type != join_type &&
+ ij->join_type != GM_JOIN_BOTH)
+ continue;
+
pim_time_uptime(uptime, sizeof(uptime),
now - ij->sock_creation);
pim_inet4_dump("<grp?>", ij->group_addr, group_str,
@@ -682,6 +665,91 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty,
vty_json(vty, json);
}
+static void igmp_show_interface_static_group(struct pim_instance *pim,
+ struct vty *vty, bool uj)
+{
+ struct interface *ifp;
+ json_object *json = NULL;
+ json_object *json_iface = NULL;
+ json_object *json_grp = NULL;
+ json_object *json_grp_arr = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ json_object_string_add(json, "vrf",
+ vrf_id_to_name(pim->vrf->vrf_id));
+ } else {
+ vty_out(vty,
+ "Interface Address Source Group\n");
+ }
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp;
+ struct listnode *node;
+ struct static_group *stgrp;
+ struct in_addr pri_addr;
+ char pri_addr_str[INET_ADDRSTRLEN];
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (!pim_ifp->static_group_list)
+ continue;
+
+ pri_addr = pim_find_primary_addr(ifp);
+ pim_inet4_dump("<pri?>", pri_addr, pri_addr_str,
+ sizeof(pri_addr_str));
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node,
+ stgrp)) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<grp?>", stgrp->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<src?>", stgrp->source_addr, source_str,
+ sizeof(source_str));
+
+ if (uj) {
+ json_object_object_get_ex(json, ifp->name,
+ &json_iface);
+
+ if (!json_iface) {
+ json_iface = json_object_new_object();
+ json_object_string_add(json_iface,
+ "name",
+ ifp->name);
+ json_object_object_add(json, ifp->name,
+ json_iface);
+ json_grp_arr = json_object_new_array();
+ json_object_object_add(json_iface,
+ "groups",
+ json_grp_arr);
+ }
+
+ json_grp = json_object_new_object();
+ json_object_string_add(json_grp, "source",
+ source_str);
+ json_object_string_add(json_grp, "group",
+ group_str);
+ json_object_string_add(json_grp, "primaryAddr",
+ pri_addr_str);
+ json_object_array_add(json_grp_arr, json_grp);
+ } else {
+ vty_out(vty, "%-16s %-15s %-15s %-15s\n",
+ ifp->name, pri_addr_str, source_str,
+ group_str);
+ }
+ } /* for (pim_ifp->static_group_list) */
+
+ } /* for (iflist) */
+
+ if (uj)
+ vty_json(vty, json);
+}
+
static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
const char *ifname, bool uj)
{
@@ -1720,10 +1788,19 @@ DEFUN (show_ip_igmp_join,
if (!vrf)
return CMD_WARNING;
- igmp_show_interface_join(vrf->info, vty, uj);
+ igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_STATIC);
return CMD_SUCCESS;
}
+ALIAS (show_ip_igmp_join,
+ show_ip_igmp_join_group_cmd,
+ "show ip igmp [vrf NAME] join-group [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP static join information\n"
+ JSON_STR);
DEFUN (show_ip_igmp_join_vrf_all,
show_ip_igmp_join_vrf_all_cmd,
@@ -1749,7 +1826,124 @@ DEFUN (show_ip_igmp_join_vrf_all,
first = false;
} else
vty_out(vty, "VRF: %s\n", vrf->name);
- igmp_show_interface_join(vrf->info, vty, uj);
+ igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_STATIC);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_proxy,
+ show_ip_igmp_proxy_cmd,
+ "show ip igmp [vrf NAME] proxy [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP proxy join information\n"
+ JSON_STR)
+{
+ int idx = 2;
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_PROXY);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_proxy_vrf_all,
+ show_ip_igmp_proxy_vrf_all_cmd,
+ "show ip igmp vrf all proxy [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP proxy join information\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+
+ if (uj)
+ vty_out(vty, "{ ");
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_PROXY);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
+ALIAS (show_ip_igmp_join_vrf_all,
+ show_ip_igmp_join_group_vrf_all_cmd,
+ "show ip igmp vrf all join-group [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP static join information\n"
+ JSON_STR);
+
+DEFUN (show_ip_igmp_static_group,
+ show_ip_igmp_static_group_cmd,
+ "show ip igmp [vrf NAME] static-group [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "Static group information\n"
+ JSON_STR)
+{
+ int idx = 2;
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ igmp_show_interface_static_group(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_static_group_vrf_all,
+ show_ip_igmp_static_group_vrf_all_cmd,
+ "show ip igmp vrf all static-group [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "Static group information\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+
+ if (uj)
+ vty_out(vty, "{ ");
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ igmp_show_interface_static_group(vrf->info, vty, uj);
}
if (uj)
vty_out(vty, "}\n");
@@ -2626,6 +2820,75 @@ DEFPY (show_ip_pim_rp_vrf_all,
(struct prefix *)group, !!json);
}
+DEFPY (show_ip_pim_autorp,
+ show_ip_pim_autorp_cmd,
+ "show ip pim [vrf NAME] autorp [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM AutoRP information\n"
+ JSON_STR)
+{
+ struct vrf *v;
+ json_object *json_parent = NULL;
+
+ v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+ if (!v || !v->info) {
+ if (!json)
+ vty_out(vty, "%% Unable to find pim instance\n");
+ return CMD_WARNING;
+ }
+
+ if (json)
+ json_parent = json_object_new_object();
+
+ pim_autorp_show_autorp(vty, v->info, json_parent);
+
+ if (json)
+ vty_json(vty, json_parent);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_pim_autorp_vrf_all,
+ show_ip_pim_autorp_vrf_all_cmd,
+ "show ip pim vrf all autorp [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ VRF_CMD_HELP_STR
+ "PIM AutoRP information\n"
+ JSON_STR)
+{
+ struct vrf *vrf;
+ json_object *json_parent = NULL;
+ json_object *json_vrf = NULL;
+
+ if (json)
+ json_parent = json_object_new_object();
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (vrf->info) {
+ if (!json)
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ else
+ json_vrf = json_object_new_object();
+
+ pim_autorp_show_autorp(vty, vrf->info, json_vrf);
+
+ if (json)
+ json_object_object_add(json_parent, vrf->name,
+ json_vrf);
+ }
+ }
+
+ if (json)
+ vty_json(vty, json_parent);
+
+ return CMD_SUCCESS;
+}
+
DEFPY (show_ip_pim_rpf,
show_ip_pim_rpf_cmd,
"show ip pim [vrf NAME] rpf [json$json]",
@@ -2707,7 +2970,7 @@ DEFPY (show_ip_pim_bsm_db,
return pim_show_bsm_db_helper(vrf, vty, !!json);
}
-DEFPY (show_ip_pim_bsrp,
+DEFPY_HIDDEN (show_ip_pim_bsrp,
show_ip_pim_bsrp_cmd,
"show ip pim bsrp-info [vrf NAME] [json$json]",
SHOW_STR
@@ -2720,6 +2983,109 @@ DEFPY (show_ip_pim_bsrp,
return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json);
}
+DEFPY (show_ip_pim_bsr_rpinfo,
+ show_ip_pim_bsr_rpinfo_cmd,
+ "show ip pim bsr rp-info [vrf NAME] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ BSR_STR
+ "PIM cached group-rp mappings information received from BSR\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_pim_bsr_cand_bsr,
+ show_ip_pim_bsr_cand_bsr_cmd,
+ "show ip pim bsr candidate-bsr [vrf NAME$vrfname] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ BSR_STR
+ "Current PIM router candidate BSR state\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, !!json);
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+ return pim_show_bsr_cand_bsr(vrf, vty, !!json);
+}
+
+
+DEFPY (show_ip_pim_bsr_cand_rp,
+ show_ip_pim_bsr_cand_rp_cmd,
+ "show ip pim bsr candidate-rp [vrf NAME$vrfname] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ BSR_STR
+ "Current PIM router candidate RP state\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, !!json);
+
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+
+ return pim_show_bsr_cand_rp(vrf, vty, !!json);
+}
+
+DEFPY (show_ip_pim_bsr_rpdb,
+ show_ip_pim_bsr_rpdb_cmd,
+ "show ip pim bsr candidate-rp-database [vrf NAME$vrfname] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ BSR_STR
+ "Candidate RPs database on this router (if it is the BSR)\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false);
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+ struct pim_instance *pim = vrf->info;
+ struct bsm_scope *scope = &pim->global_scope;
+
+ return pim_crp_db_show(vty, scope, !!json);
+}
+
+DEFPY (show_ip_pim_bsr_groups,
+ show_ip_pim_bsr_groups_cmd,
+ "show ip pim bsr groups [vrf NAME$vrfname] [json$json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "boot-strap router information\n"
+ "Candidate RP groups\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ int idx = 2;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false);
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+ struct pim_instance *pim = vrf->info;
+ struct bsm_scope *scope = &pim->global_scope;
+
+ return pim_crp_groups_show(vty, scope, !!json);
+}
+
DEFPY (show_ip_pim_statistics,
show_ip_pim_statistics_cmd,
"show ip pim [vrf NAME] statistics [interface WORD$word] [json$json]",
@@ -4219,6 +4585,108 @@ DEFPY_ATTR(no_ip_pim_rp_prefix_list,
return ret;
}
+DEFPY (pim_autorp_discovery,
+ pim_autorp_discovery_cmd,
+ "[no] autorp discovery",
+ NO_STR
+ "AutoRP\n"
+ "Enable AutoRP discovery\n")
+{
+ if (no)
+ return pim_process_no_autorp_cmd(vty);
+ else
+ return pim_process_autorp_cmd(vty);
+}
+
+DEFPY (pim_autorp_announce_rp,
+ pim_autorp_announce_rp_cmd,
+ "[no] autorp announce A.B.C.D$rpaddr ![A.B.C.D/M$grp|group-list PREFIX_LIST$plist]",
+ NO_STR
+ "AutoRP\n"
+ "AutoRP Candidate RP announcement\n"
+ "AutoRP Candidate RP address\n"
+ "Group prefix\n"
+ "Prefix list\n"
+ "List name\n")
+{
+ return pim_process_autorp_candidate_rp_cmd(vty, no, rpaddr_str, (grp_str ? grp : NULL),
+ plist);
+}
+
+DEFPY (pim_autorp_announce_scope_int,
+ pim_autorp_announce_scope_int_cmd,
+ "[no] autorp announce ![{scope (1-255) | interval (1-65535) | holdtime (0-65535)}]",
+ NO_STR
+ "AutoRP\n"
+ "AutoRP Candidate RP announcement\n"
+ "Packet scope (TTL)\n"
+ "TTL value\n"
+ "Announcement interval\n"
+ "Time in seconds\n"
+ "Announcement holdtime\n"
+ "Time in seconds\n")
+{
+ return pim_process_autorp_announce_scope_int_cmd(vty, no, scope_str,
+ interval_str,
+ holdtime_str);
+}
+
+DEFPY (pim_bsr_candidate_bsr,
+ pim_bsr_candidate_bsr_cmd,
+ "[no] bsr candidate-bsr [{priority (0-255)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]",
+ NO_STR
+ BSR_STR
+ "Make this router a Candidate BSR\n"
+ "BSR Priority (higher wins)\n"
+ "BSR Priority (higher wins)\n"
+ "Specify IP address for BSR operation\n"
+ "Local address to use\n"
+ "Local address to use\n"
+ "Interface to pick address from\n"
+ "Interface to pick address from\n"
+ "Pick highest loopback address (default)\n"
+ "Pick highest address from any interface\n")
+{
+ return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_BSR_XPATH, no,
+ false, any, ifname, address_str,
+ priority_str, NULL);
+}
+
+DEFPY (pim_bsr_candidate_rp,
+ pim_bsr_candidate_rp_cmd,
+ "[no] bsr candidate-rp [{priority (0-255)|interval (1-4294967295)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]",
+ NO_STR
+ BSR_STR
+ "Make this router a Candidate RP\n"
+ "RP Priority (lower wins)\n"
+ "RP Priority (lower wins)\n"
+ "Advertisement interval (seconds)\n"
+ "Advertisement interval (seconds)\n"
+ "Specify IP address for RP operation\n"
+ "Local address to use\n"
+ "Local address to use\n"
+ "Interface to pick address from\n"
+ "Interface to pick address from\n"
+ "Pick highest loopback address (default)\n"
+ "Pick highest address from any interface\n")
+{
+ return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_RP_XPATH, no,
+ true, any, ifname, address_str,
+ priority_str, interval_str);
+}
+
+DEFPY (pim_bsr_candidate_rp_group,
+ pim_bsr_candidate_rp_group_cmd,
+ "[no] bsr candidate-rp group A.B.C.D/M",
+ NO_STR
+ BSR_STR
+ "Make this router a Candidate RP\n"
+ "Configure groups to become candidate RP for (At least one group must be configured)\n"
+ "Multicast group prefix\n")
+{
+ return pim_process_bsr_crp_grp_cmd(vty, group_str, no);
+}
+
DEFPY (pim_ssm_prefix_list,
pim_ssm_prefix_list_cmd,
"ssm prefix-list PREFIXLIST4_NAME$plist",
@@ -4924,71 +5392,47 @@ DEFUN (interface_no_ip_igmp,
"frr-routing:ipv4");
}
-DEFUN (interface_ip_igmp_join,
- interface_ip_igmp_join_cmd,
- "ip igmp join A.B.C.D [A.B.C.D]",
- IP_STR
- IFACE_IGMP_STR
- "IGMP join multicast group\n"
- "Multicast group address\n"
- "Source address\n")
+DEFPY_YANG_HIDDEN (interface_ip_igmp_join,
+ interface_ip_igmp_join_cmd,
+ "[no] ip igmp join A.B.C.D$grp [A.B.C.D]$src",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP join multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
{
- int idx_group = 3;
- int idx_source = 4;
- const char *source_str;
- char xpath[XPATH_MAXLEN];
-
- if (argc == 5) {
- source_str = argv[idx_source]->arg;
-
- 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;
- }
- } else
- source_str = "0.0.0.0";
-
- snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH,
- "frr-routing:ipv4", argv[idx_group]->arg, source_str);
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+ NULL);
+ return nb_cli_apply_changes(vty, FRR_GMP_JOIN_GROUP_XPATH,
+ "frr-routing:ipv4", grp_str,
+ (src_str ? src_str : "0.0.0.0"));
}
-
-DEFUN (interface_no_ip_igmp_join,
- interface_no_ip_igmp_join_cmd,
- "no ip igmp join A.B.C.D [A.B.C.D]",
- NO_STR
- IP_STR
- IFACE_IGMP_STR
- "IGMP join multicast group\n"
- "Multicast group address\n"
- "Source address\n")
-{
- int idx_group = 4;
- int idx_source = 5;
- const char *source_str;
- char xpath[XPATH_MAXLEN];
-
- if (argc == 6) {
- source_str = argv[idx_source]->arg;
-
- 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;
- }
- } else
- source_str = "0.0.0.0";
-
- snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH,
- "frr-routing:ipv4", argv[idx_group]->arg, source_str);
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ALIAS(interface_ip_igmp_join,
+ interface_ip_igmp_join_group_cmd,
+ "[no] ip igmp join-group A.B.C.D$grp [A.B.C.D]$src",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP join multicast group\n"
+ "Multicast group address\n"
+ "Source address\n");
+
+DEFPY_YANG (interface_ip_igmp_static_group,
+ interface_ip_igmp_static_group_cmd,
+ "[no] ip igmp static-group A.B.C.D$grp [A.B.C.D]$src",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "Static multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
+{
+ nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+ NULL);
+ return nb_cli_apply_changes(vty, FRR_GMP_STATIC_GROUP_XPATH,
+ "frr-routing:ipv4", grp_str,
+ (src_str ? src_str : "0.0.0.0"));
}
DEFUN (interface_ip_igmp_query_interval,
@@ -5485,6 +5929,18 @@ DEFUN (interface_no_ip_pim_hello,
return pim_process_no_ip_pim_hello_cmd(vty);
}
+DEFPY (interface_ip_igmp_proxy,
+ interface_ip_igmp_proxy_cmd,
+ "[no] ip igmp proxy",
+ NO_STR
+ IP_STR
+ IGMP_STR
+ "Proxy IGMP join/prune operations\n")
+{
+ return pim_process_ip_gmp_proxy_cmd(vty, !no);
+}
+
+
DEFUN (debug_igmp,
debug_igmp_cmd,
"debug igmp",
@@ -6036,6 +6492,29 @@ DEFUN (no_debug_bsm,
return CMD_SUCCESS;
}
+DEFUN (debug_autorp,
+ debug_autorp_cmd,
+ "debug pim autorp",
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_AUTORP_STR)
+{
+ PIM_DO_DEBUG_AUTORP;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_autorp,
+ no_debug_autorp_cmd,
+ "no debug pim autorp",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIM_STR
+ DEBUG_PIM_AUTORP_STR)
+{
+ PIM_DONT_DEBUG_AUTORP;
+ return CMD_SUCCESS;
+}
+
DEFUN_NOSH (show_debugging_pim,
show_debugging_pim_cmd,
@@ -8373,6 +8852,9 @@ void pim_cmd_init(void)
install_element(PIM_NODE, &no_pim_rp_cmd);
install_element(PIM_NODE, &pim_rp_prefix_list_cmd);
install_element(PIM_NODE, &no_pim_rp_prefix_list_cmd);
+ install_element(PIM_NODE, &pim_autorp_discovery_cmd);
+ install_element(PIM_NODE, &pim_autorp_announce_rp_cmd);
+ install_element(PIM_NODE, &pim_autorp_announce_scope_int_cmd);
install_element(PIM_NODE, &no_pim_ssm_prefix_list_cmd);
install_element(PIM_NODE, &no_pim_ssm_prefix_list_name_cmd);
install_element(PIM_NODE, &pim_ssm_prefix_list_cmd);
@@ -8417,10 +8899,15 @@ void pim_cmd_init(void)
install_element(PIM_NODE, &no_pim_msdp_mesh_group_source_cmd);
install_element(PIM_NODE, &no_pim_msdp_mesh_group_cmd);
+ install_element(PIM_NODE, &pim_bsr_candidate_rp_cmd);
+ install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd);
+ install_element(PIM_NODE, &pim_bsr_candidate_bsr_cmd);
+
install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd);
- install_element(INTERFACE_NODE, &interface_no_ip_igmp_join_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_join_group_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_static_group_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_version_cmd);
install_element(INTERFACE_NODE, &interface_no_ip_igmp_version_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd);
@@ -8442,6 +8929,7 @@ void pim_cmd_init(void)
&interface_ip_igmp_last_member_query_interval_cmd);
install_element(INTERFACE_NODE,
&interface_no_ip_igmp_last_member_query_interval_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_proxy_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd);
install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd);
@@ -8480,7 +8968,13 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_igmp_interface_cmd);
install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_igmp_join_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_join_group_cmd);
install_element(VIEW_NODE, &show_ip_igmp_join_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_join_group_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_static_group_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_static_group_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_proxy_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_proxy_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_igmp_groups_cmd);
install_element(VIEW_NODE, &show_ip_igmp_groups_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd);
@@ -8515,6 +9009,8 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd);
install_element(VIEW_NODE, &show_ip_pim_rp_cmd);
install_element(VIEW_NODE, &show_ip_pim_rp_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_autorp_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_autorp_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_pim_bsr_cmd);
install_element(VIEW_NODE, &show_ip_multicast_cmd);
install_element(VIEW_NODE, &show_ip_multicast_vrf_all_cmd);
@@ -8532,6 +9028,11 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd);
install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd);
install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_bsr_rpinfo_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_bsr_cand_bsr_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_bsr_cand_rp_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_bsr_rpdb_cmd);
+ install_element(VIEW_NODE, &show_ip_pim_bsr_groups_cmd);
install_element(VIEW_NODE, &show_ip_pim_statistics_cmd);
install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd);
install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd);
@@ -8617,6 +9118,8 @@ void pim_cmd_init(void)
install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd);
install_element(ENABLE_NODE, &debug_ssmpingd_cmd);
install_element(CONFIG_NODE, &debug_ssmpingd_cmd);
+ install_element(ENABLE_NODE, &debug_autorp_cmd);
+ install_element(ENABLE_NODE, &no_debug_autorp_cmd);
install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd);
install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd);
install_element(ENABLE_NODE, &debug_pim_zebra_cmd);
@@ -8649,6 +9152,8 @@ void pim_cmd_init(void)
install_element(CONFIG_NODE, &debug_bsm_cmd);
install_element(ENABLE_NODE, &no_debug_bsm_cmd);
install_element(CONFIG_NODE, &no_debug_bsm_cmd);
+ install_element(CONFIG_NODE, &debug_autorp_cmd);
+ install_element(CONFIG_NODE, &no_debug_autorp_cmd);
install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd);
install_element(VRF_NODE, &ip_igmp_group_watermark_cmd);
diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h
index d39d77cd2f..17cf4bb362 100644
--- a/pimd/pim_cmd.h
+++ b/pimd/pim_cmd.h
@@ -56,6 +56,7 @@
#define DEBUG_MSDP_PACKETS_STR "MSDP protocol packets\n"
#define DEBUG_MTRACE_STR "Mtrace protocol activity\n"
#define DEBUG_PIM_BSM_STR "BSR message processing activity\n"
+#define DEBUG_PIM_AUTORP_STR "AutoRP message processing activity\n"
void pim_cmd_init(void);
diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c
index d1368ff1ff..02ddea8252 100644
--- a/pimd/pim_cmd_common.c
+++ b/pimd/pim_cmd_common.c
@@ -420,6 +420,17 @@ int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty)
FRR_PIM_AF_XPATH_VAL);
}
+int pim_process_ip_gmp_proxy_cmd(struct vty *vty, bool enable)
+{
+ if (enable)
+ nb_cli_enqueue_change(vty, "./proxy", NB_OP_MODIFY, "true");
+ else
+ nb_cli_enqueue_change(vty, "./proxy", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+}
+
int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface,
const char *group_str, const char *source_str)
{
@@ -595,6 +606,165 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str,
return nb_cli_apply_changes(vty, NULL);
}
+int pim_process_autorp_cmd(struct vty *vty)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath), "%s/%s", FRR_PIM_AUTORP_XPATH,
+ "discovery-enabled");
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_no_autorp_cmd(struct vty *vty)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath), "%s/%s", FRR_PIM_AUTORP_XPATH,
+ "discovery-enabled");
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_autorp_candidate_rp_cmd(struct vty *vty, bool no,
+ const char *rpaddr_str,
+ const struct prefix_ipv4 *grp,
+ const char *plist)
+{
+ char xpath[XPATH_MAXLEN];
+ char grpstr[64];
+
+ if (no) {
+ if ((grp && !is_default_prefix((const struct prefix *)grp)) || plist) {
+ /* If any single values are set, only destroy those */
+ if (grp && !is_default_prefix((const struct prefix *)grp)) {
+ snprintfrr(xpath, sizeof(xpath),
+ "%s/candidate-rp-list[rp-address='%s']/group",
+ FRR_PIM_AUTORP_XPATH, rpaddr_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
+ NULL);
+ }
+ if (plist) {
+ snprintfrr(xpath, sizeof(xpath),
+ "%s/candidate-rp-list[rp-address='%s']/prefix-list",
+ FRR_PIM_AUTORP_XPATH, rpaddr_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
+ NULL);
+ }
+ } else {
+ /* No values set, remove the entire RP */
+ snprintfrr(xpath, sizeof(xpath),
+ "%s/candidate-rp-list[rp-address='%s']",
+ FRR_PIM_AUTORP_XPATH, rpaddr_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ }
+ } else {
+ if ((grp && !is_default_prefix((const struct prefix *)grp)) || plist) {
+ snprintfrr(xpath, sizeof(xpath),
+ "%s/candidate-rp-list[rp-address='%s']",
+ FRR_PIM_AUTORP_XPATH, rpaddr_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (grp && !is_default_prefix((const struct prefix *)grp)) {
+ snprintfrr(xpath, sizeof(xpath),
+ "%s/candidate-rp-list[rp-address='%s']/group",
+ FRR_PIM_AUTORP_XPATH, rpaddr_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+ prefix2str(grp, grpstr,
+ sizeof(grpstr)));
+ }
+ if (plist) {
+ snprintfrr(xpath, sizeof(xpath),
+ "%s/candidate-rp-list[rp-address='%s']/prefix-list",
+ FRR_PIM_AUTORP_XPATH, rpaddr_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+ plist);
+ }
+ } else {
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+int pim_process_autorp_announce_scope_int_cmd(struct vty *vty, bool no,
+ const char *scope,
+ const char *interval,
+ const char *holdtime)
+{
+ char xpath[XPATH_MAXLEN];
+
+ if (no) {
+ if (scope || interval || holdtime) {
+ /* If any single values are set, only destroy those */
+ if (scope) {
+ snprintfrr(xpath, sizeof(xpath), "%s/%s",
+ FRR_PIM_AUTORP_XPATH,
+ "announce-scope");
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
+ NULL);
+ }
+ if (interval) {
+ snprintfrr(xpath, sizeof(xpath), "%s/%s",
+ FRR_PIM_AUTORP_XPATH,
+ "announce-interval");
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
+ NULL);
+ }
+ if (holdtime) {
+ snprintfrr(xpath, sizeof(xpath), "%s/%s",
+ FRR_PIM_AUTORP_XPATH,
+ "announce-holdtime");
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
+ NULL);
+ }
+ } else {
+ /* No values set, remove all */
+ snprintfrr(xpath, sizeof(xpath), "%s/%s",
+ FRR_PIM_AUTORP_XPATH, "announce-scope");
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ snprintfrr(xpath, sizeof(xpath), "%s/%s",
+ FRR_PIM_AUTORP_XPATH, "announce-interval");
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ snprintfrr(xpath, sizeof(xpath), "%s/%s",
+ FRR_PIM_AUTORP_XPATH, "announce-holdtime");
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ }
+ } else {
+ if (scope || interval || holdtime) {
+ if (scope) {
+ snprintfrr(xpath, sizeof(xpath), "%s/%s",
+ FRR_PIM_AUTORP_XPATH,
+ "announce-scope");
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+ scope);
+ }
+ if (interval) {
+ snprintfrr(xpath, sizeof(xpath), "%s/%s",
+ FRR_PIM_AUTORP_XPATH,
+ "announce-interval");
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+ interval);
+ }
+ if (holdtime) {
+ snprintfrr(xpath, sizeof(xpath), "%s/%s",
+ FRR_PIM_AUTORP_XPATH,
+ "announce-holdtime");
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
+ holdtime);
+ }
+ } else {
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
bool pim_sgaddr_match(pim_sgaddr item, pim_sgaddr match)
{
return (pim_addr_is_any(match.grp) ||
@@ -874,7 +1044,7 @@ void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json)
if (!json) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -926,7 +1096,7 @@ void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty)
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
@@ -1180,7 +1350,7 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty,
#else
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
#endif
}
@@ -1413,7 +1583,7 @@ void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
if (!json) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -1490,7 +1660,7 @@ void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, bool uj)
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -1569,7 +1739,7 @@ void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -1751,7 +1921,7 @@ void pim_show_join(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
if (!json) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -1831,7 +2001,7 @@ void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty)
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
@@ -1974,7 +2144,7 @@ void pim_show_membership(struct pim_instance *pim, struct vty *vty, bool uj)
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -2079,7 +2249,7 @@ void pim_show_channel(struct pim_instance *pim, struct vty *vty, bool uj)
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -2262,7 +2432,7 @@ void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, bool mlag,
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
@@ -2734,7 +2904,7 @@ static int pim_print_vty_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
/* Dump the generated table. */
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
return CMD_SUCCESS;
@@ -3214,7 +3384,7 @@ void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
if (!json) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -3389,6 +3559,55 @@ int pim_process_no_unicast_bsm_cmd(struct vty *vty)
FRR_PIM_AF_XPATH_VAL);
}
+/* helper for bsr/rp candidate commands*/
+int pim_process_bsr_candidate_cmd(struct vty *vty, const char *cand_str,
+ bool no, bool is_rp, bool any,
+ const char *ifname, const char *addr,
+ const char *prio, const char *interval)
+{
+ if (no)
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+ else {
+ nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
+
+ if (any)
+ nb_cli_enqueue_change(vty, "./if-any", NB_OP_CREATE,
+ NULL);
+ else if (ifname)
+ nb_cli_enqueue_change(vty, "./interface", NB_OP_CREATE,
+ ifname);
+ else if (addr)
+ nb_cli_enqueue_change(vty, "./address", NB_OP_CREATE,
+ addr);
+ else
+ nb_cli_enqueue_change(vty, "./if-loopback",
+ NB_OP_CREATE, NULL);
+
+ if (prio)
+ nb_cli_enqueue_change(vty,
+ (is_rp ? "./rp-priority"
+ : "./bsr-priority"),
+ NB_OP_MODIFY, prio);
+
+ /* only valid for rp candidate case*/
+ if (is_rp && interval)
+ nb_cli_enqueue_change(vty, "./advertisement-interval",
+ NB_OP_MODIFY, interval);
+ }
+
+ return nb_cli_apply_changes(vty, "%s", cand_str);
+}
+
+int pim_process_bsr_crp_grp_cmd(struct vty *vty, const char *grp, bool no)
+{
+ if (no)
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, grp);
+ else
+ nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, grp);
+
+ return nb_cli_apply_changes(vty, "%s/group-list", FRR_PIM_CAND_RP_XPATH);
+}
+
static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
time_t now)
{
@@ -3500,7 +3719,7 @@ void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty,
if (!json) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -3939,7 +4158,7 @@ void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
if (!json) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -4022,7 +4241,7 @@ void show_mroute_count(struct pim_instance *pim, struct vty *vty,
if (!json) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
}
@@ -4158,6 +4377,27 @@ struct vrf *pim_cmd_lookup(struct vty *vty, const char *name)
return vrf;
}
+struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[],
+ const int argc, int *idx, bool uj)
+{
+ struct vrf *vrf;
+
+ if (argv_find(argv, argc, "NAME", idx))
+ vrf = vrf_lookup_by_name(argv[*idx]->arg);
+ else
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+
+ if (!vrf) {
+ if (uj)
+ vty_json_empty(vty, NULL);
+ else
+ vty_out(vty, "Specified VRF: %s does not exist\n",
+ argv[*idx]->arg);
+ }
+
+ return vrf;
+}
+
void clear_mroute(struct pim_instance *pim)
{
struct pim_upstream *up;
@@ -5188,6 +5428,12 @@ void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj)
case ACCEPT_PREFERRED:
strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
break;
+ case BSR_PENDING:
+ strlcpy(bsr_state, "BSR_PENDING", sizeof(bsr_state));
+ break;
+ case BSR_ELECTED:
+ strlcpy(bsr_state, "BSR_ELECTED", sizeof(bsr_state));
+ break;
default:
strlcpy(bsr_state, "", sizeof(bsr_state));
}
@@ -5207,7 +5453,7 @@ void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj)
}
else {
- vty_out(vty, "PIMv2 Bootstrap information\n");
+ vty_out(vty, "PIMv2 Bootstrap Router information\n");
vty_out(vty, "Current preferred BSR address: %pPA\n",
&pim->global_scope.current_bsr);
vty_out(vty,
@@ -5325,7 +5571,7 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
tt = NULL;
}
@@ -5379,7 +5625,7 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
@@ -5416,6 +5662,98 @@ int pim_show_group_rp_mappings_info_helper(const char *vrf, struct vty *vty,
return CMD_SUCCESS;
}
+int pim_show_bsr_cand_rp(const struct vrf *vrf, struct vty *vty, bool uj)
+{
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+ json_object *jsondata = NULL;
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+ pim = (struct pim_instance *)vrf->info;
+ scope = &pim->global_scope;
+
+ if (!scope->cand_rp_addrsel.run) {
+ if (!!uj)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty,
+ "This router is not currently operating as Candidate RP\n");
+ return CMD_SUCCESS;
+ }
+
+ if (!!uj) {
+ jsondata = json_object_new_object();
+ json_object_string_addf(jsondata, "address", "%pPA",
+ &scope->cand_rp_addrsel.run_addr);
+ json_object_int_add(jsondata, "priority", scope->cand_rp_prio);
+ json_object_int_add(jsondata, "nextAdvertisementMsec",
+ event_timer_remain_msec(
+ scope->cand_rp_adv_timer));
+
+ vty_json(vty, jsondata);
+ return CMD_SUCCESS;
+ }
+
+ vty_out(vty, "Candidate-RP\nAddress: %pPA\nPriority: %u\n\n",
+ &scope->cand_rp_addrsel.run_addr, scope->cand_rp_prio);
+ vty_out(vty, "Next adv.: %lu msec\n",
+ event_timer_remain_msec(scope->cand_rp_adv_timer));
+
+
+ return CMD_SUCCESS;
+}
+
+int pim_show_bsr_cand_bsr(const struct vrf *vrf, struct vty *vty, bool uj)
+{
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+ json_object *jsondata = NULL;
+
+ if (!vrf || !vrf->info)
+ return CMD_WARNING;
+
+ pim = (struct pim_instance *)vrf->info;
+ scope = &pim->global_scope;
+
+ if (!scope->bsr_addrsel.cfg_enable) {
+ if (!!uj)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty,
+ "This router is not currently operating as Candidate BSR\n");
+ return CMD_SUCCESS;
+ }
+
+ if (uj) {
+ char buf[INET_ADDRSTRLEN];
+
+ jsondata = json_object_new_object();
+ inet_ntop(AF_INET, &scope->bsr_addrsel.run_addr, buf,
+ sizeof(buf));
+ json_object_string_add(jsondata, "address", buf);
+ json_object_int_add(jsondata, "priority", scope->cand_bsr_prio);
+ json_object_boolean_add(jsondata, "elected",
+ pim->global_scope.state == BSR_ELECTED);
+
+ vty_json(vty, jsondata);
+ return CMD_SUCCESS;
+ }
+
+ vty_out(vty,
+ "Candidate-BSR\nAddress: %pPA\nPriority: %u\nElected: %s\n",
+ &scope->bsr_addrsel.run_addr, scope->cand_bsr_prio,
+ (pim->global_scope.state == BSR_ELECTED) ? " Yes" : " No");
+
+ if (!pim_addr_cmp(scope->bsr_addrsel.run_addr, PIMADDR_ANY))
+ vty_out(vty,
+ "\nThis router is not currently operating as Candidate BSR\n"
+ "Configure a BSR address to enable this feature\n\n");
+
+ return CMD_SUCCESS;
+}
+
/* Display the bsm database details */
static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
{
diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h
index da2e44be58..d7c97e31d4 100644
--- a/pimd/pim_cmd_common.h
+++ b/pimd/pim_cmd_common.h
@@ -7,6 +7,8 @@
#ifndef PIM_CMD_COMMON_H
#define PIM_CMD_COMMON_H
+#define BSR_STR "Bootstrap Router configuration\n"
+
struct pim_upstream;
struct pim_instance;
@@ -33,7 +35,16 @@ int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str,
const char *prefix_list);
int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str,
const char *prefix_list);
-
+int pim_process_autorp_cmd(struct vty *vty);
+int pim_process_no_autorp_cmd(struct vty *vty);
+int pim_process_autorp_candidate_rp_cmd(struct vty *vty, bool no,
+ const char *rpaddr_str,
+ const struct prefix_ipv4 *grp,
+ const char *plist);
+int pim_process_autorp_announce_scope_int_cmd(struct vty *vty, bool no,
+ const char *scope,
+ const char *interval,
+ const char *holdtime);
int pim_process_ip_pim_cmd(struct vty *vty);
int pim_process_no_ip_pim_cmd(struct vty *vty);
int pim_process_ip_pim_passive_cmd(struct vty *vty, bool enable);
@@ -45,6 +56,7 @@ int pim_process_no_ip_pim_hello_cmd(struct vty *vty);
int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no);
int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil);
int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty);
+int pim_process_ip_gmp_proxy_cmd(struct vty *vty, bool enable);
int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface,
const char *group_str, const char *source_str);
int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface,
@@ -53,6 +65,13 @@ int pim_process_bsm_cmd(struct vty *vty);
int pim_process_no_bsm_cmd(struct vty *vty);
int pim_process_unicast_bsm_cmd(struct vty *vty);
int pim_process_no_unicast_bsm_cmd(struct vty *vty);
+
+int pim_process_bsr_candidate_cmd(struct vty *vty, const char *cand_str,
+ bool no, bool is_rp, bool any,
+ const char *ifname, const char *addr,
+ const char *prio, const char *interval);
+int pim_process_bsr_crp_grp_cmd(struct vty *vty, const char *grp, bool no);
+
void json_object_pim_upstream_add(json_object *json, struct pim_upstream *up);
void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json);
void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty);
@@ -131,6 +150,8 @@ void show_mroute_summary(struct pim_instance *pim, struct vty *vty,
json_object *json);
int clear_ip_mroute_count_command(struct vty *vty, const char *name);
struct vrf *pim_cmd_lookup(struct vty *vty, const char *name);
+struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[],
+ const int argc, int *idx, bool uj);
void clear_mroute(struct pim_instance *pim);
void clear_pim_statistics(struct pim_instance *pim);
int clear_pim_interface_traffic(const char *vrf, struct vty *vty);
@@ -182,6 +203,8 @@ int pim_show_interface_traffic_helper(const char *vrf, const char *if_name,
void clear_pim_interfaces(struct pim_instance *pim);
void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj);
int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj);
+int pim_show_bsr_cand_bsr(const struct vrf *vrf, struct vty *vty, bool uj);
+int pim_show_bsr_cand_rp(const struct vrf *vrf, struct vty *vty, bool uj);
int pim_router_config_write(struct vty *vty);
/*
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index dcb6116012..20e3ba184b 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -37,10 +37,12 @@
#include "pim_jp_agg.h"
#include "pim_igmp_join.h"
#include "pim_vxlan.h"
+#include "pim_tib.h"
#include "pim6_mld.h"
static void pim_if_gm_join_del_all(struct interface *ifp);
+static void pim_if_static_group_del_all(struct interface *ifp);
static int gm_join_sock(const char *ifname, ifindex_t ifindex,
pim_addr group_addr, pim_addr source_addr,
@@ -144,6 +146,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim,
pim_ifp->gm_enable = gm;
pim_ifp->gm_join_list = NULL;
+ pim_ifp->static_group_list = NULL;
pim_ifp->pim_neighbor_list = NULL;
pim_ifp->upstream_switch_list = NULL;
pim_ifp->pim_generation_id = 0;
@@ -188,9 +191,11 @@ void pim_if_delete(struct interface *ifp)
assert(pim_ifp);
pim_ifp->pim->mcast_if_count--;
- if (pim_ifp->gm_join_list) {
+ if (pim_ifp->gm_join_list)
pim_if_gm_join_del_all(ifp);
- }
+
+ if (pim_ifp->static_group_list)
+ pim_if_static_group_del_all(ifp);
pim_ifchannel_delete_all(ifp);
#if PIM_IPV == 4
@@ -522,77 +527,66 @@ void pim_if_addr_add(struct connected *ifc)
detect_address_change(ifp, 0, __func__);
- // if (ifc->address->family != AF_INET)
- // return;
-
#if PIM_IPV == 4
- struct in_addr ifaddr = ifc->address->u.prefix4;
+ if (ifc->address->family == AF_INET) {
+ struct in_addr ifaddr = ifc->address->u.prefix4;
- if (pim_ifp->gm_enable) {
- struct gm_sock *igmp;
+ if (pim_ifp->gm_enable) {
+ struct gm_sock *igmp;
- /* lookup IGMP socket */
- igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
- ifaddr);
- if (!igmp) {
- /* if addr new, add IGMP socket */
- if (ifc->address->family == AF_INET)
+ /* lookup IGMP socket */
+ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
+ if (!igmp) {
+ /* if addr new, add IGMP socket */
pim_igmp_sock_add(pim_ifp->gm_socket_list,
ifaddr, ifp, false);
- } else if (igmp->mtrace_only) {
- igmp_sock_delete(igmp);
- pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp,
- false);
- }
+ } else if (igmp->mtrace_only) {
+ igmp_sock_delete(igmp);
+ pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp, false);
+ }
- /* Replay Static IGMP groups */
- if (pim_ifp->gm_join_list) {
- struct listnode *node;
- struct listnode *nextnode;
- struct gm_join *ij;
- int join_fd;
-
- for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node,
- nextnode, ij)) {
- /* Close socket and reopen with Source and Group
- */
- close(ij->sock_fd);
- join_fd = gm_join_sock(
- ifp->name, ifp->ifindex, ij->group_addr,
- ij->source_addr, pim_ifp);
- if (join_fd < 0) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<grp?>", ij->group_addr,
- group_str,
- sizeof(group_str));
- pim_inet4_dump(
- "<src?>", ij->source_addr,
- source_str, sizeof(source_str));
- zlog_warn(
- "%s: gm_join_sock() failure for IGMP group %s source %s on interface %s",
- __func__, group_str, source_str,
- ifp->name);
- /* warning only */
- } else
- ij->sock_fd = join_fd;
+ /* Replay Static IGMP groups */
+ if (pim_ifp->gm_join_list) {
+ struct listnode *node;
+ struct listnode *nextnode;
+ struct gm_join *ij;
+ int join_fd;
+
+ for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij)) {
+ /* Close socket and reopen with Source and Group
+ */
+ close(ij->sock_fd);
+ join_fd = gm_join_sock(ifp->name, ifp->ifindex,
+ ij->group_addr, ij->source_addr,
+ pim_ifp);
+ if (join_fd < 0) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<grp?>", ij->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<src?>", ij->source_addr,
+ source_str, sizeof(source_str));
+ zlog_warn("%s: gm_join_sock() failure for IGMP group %s source %s on interface %s",
+ __func__, group_str, source_str,
+ ifp->name);
+ /* warning only */
+ } else
+ ij->sock_fd = join_fd;
+ }
}
- }
- } /* igmp */
- else {
- struct gm_sock *igmp;
-
- /* lookup IGMP socket */
- igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
- ifaddr);
- if (ifc->address->family == AF_INET) {
+ } /* igmp */
+ else {
+ struct gm_sock *igmp;
+
+ /* lookup IGMP socket */
+ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
if (igmp)
igmp_sock_delete(igmp);
/* if addr new, add IGMP socket */
pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp,
true);
- }
- } /* igmp mtrace only */
+ } /* igmp mtrace only */
+ }
#endif
if (pim_ifp->pim_enable) {
@@ -1218,6 +1212,11 @@ static void gm_join_free(struct gm_join *ij)
XFREE(MTYPE_PIM_IGMP_JOIN, ij);
}
+static void static_group_free(struct static_group *stgrp)
+{
+ XFREE(MTYPE_PIM_STATIC_GROUP, stgrp);
+}
+
static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr,
pim_addr source_addr)
{
@@ -1232,7 +1231,25 @@ static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr,
return ij;
}
- return 0;
+ return NULL;
+}
+
+static struct static_group *static_group_find(struct list *static_group_list,
+ pim_addr group_addr,
+ pim_addr source_addr)
+{
+ struct listnode *node;
+ struct static_group *stgrp;
+
+ assert(static_group_list);
+
+ for (ALL_LIST_ELEMENTS_RO(static_group_list, node, stgrp)) {
+ if ((!pim_addr_cmp(group_addr, stgrp->group_addr)) &&
+ (!pim_addr_cmp(source_addr, stgrp->source_addr)))
+ return stgrp;
+ }
+
+ return NULL;
}
static int gm_join_sock(const char *ifname, ifindex_t ifindex,
@@ -1266,7 +1283,8 @@ static int gm_join_sock(const char *ifname, ifindex_t ifindex,
}
static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr,
- pim_addr source_addr)
+ pim_addr source_addr,
+ enum gm_join_type join_type)
{
struct pim_interface *pim_ifp;
struct gm_join *ij;
@@ -1289,6 +1307,7 @@ static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr,
ij->sock_fd = join_fd;
ij->group_addr = group_addr;
ij->source_addr = source_addr;
+ ij->join_type = join_type;
ij->sock_creation = pim_time_monotonic_sec();
listnode_add(pim_ifp->gm_join_list, ij);
@@ -1296,8 +1315,36 @@ static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr,
return ij;
}
+static struct static_group *static_group_new(struct interface *ifp,
+ pim_addr group_addr,
+ pim_addr source_addr)
+{
+ struct pim_interface *pim_ifp;
+ struct static_group *stgrp;
+ pim_sgaddr sg;
+
+ pim_ifp = ifp->info;
+ assert(pim_ifp);
+
+ stgrp = XCALLOC(MTYPE_PIM_STATIC_GROUP, sizeof(*stgrp));
+
+ stgrp->group_addr = group_addr;
+ stgrp->source_addr = source_addr;
+ stgrp->oilp = NULL;
+
+ memset(&sg, 0, sizeof(sg));
+ sg.src = source_addr;
+ sg.grp = group_addr;
+
+ tib_sg_gm_join(pim_ifp->pim, sg, ifp, &(stgrp->oilp));
+
+ listnode_add(pim_ifp->static_group_list, stgrp);
+
+ return stgrp;
+}
+
ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
- pim_addr source_addr)
+ pim_addr source_addr, enum gm_join_type join_type)
{
struct pim_interface *pim_ifp;
struct gm_join *ij;
@@ -1319,10 +1366,16 @@ ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
* group
*/
if (ij) {
+ /* turn an existing join into a "both" join */
+ if (ij->join_type != join_type)
+ ij->join_type = GM_JOIN_BOTH;
return ferr_ok();
}
- (void)gm_join_new(ifp, group_addr, source_addr);
+ if (!gm_join_new(ifp, group_addr, source_addr, join_type)) {
+ return ferr_cfg_invalid("can't join (%pPA,%pPA) on interface %s",
+ &source_addr, &group_addr, ifp->name);
+ }
if (PIM_DEBUG_GM_EVENTS) {
zlog_debug(
@@ -1335,7 +1388,7 @@ ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
}
int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
- pim_addr source_addr)
+ pim_addr source_addr, enum gm_join_type join_type)
{
struct pim_interface *pim_ifp;
struct gm_join *ij;
@@ -1361,6 +1414,20 @@ int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
return -3;
}
+ if (ij->join_type != join_type) {
+ if (ij->join_type != GM_JOIN_BOTH) {
+ zlog_warn("%s: wrong " GM
+ " gm_join_type %pPAs source %pPAs on interface %s",
+ __func__, &group_addr, &source_addr,
+ ifp->name);
+ return -4;
+ }
+ /* drop back to a single join type from current setting of GM_JOIN_BOTH */
+ ij->join_type = (join_type == GM_JOIN_STATIC ? GM_JOIN_PROXY
+ : GM_JOIN_STATIC);
+ return 0;
+ }
+
if (close(ij->sock_fd)) {
zlog_warn(
"%s: failure closing sock_fd=%d for " GM
@@ -1379,7 +1446,6 @@ int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
return 0;
}
-__attribute__((unused))
static void pim_if_gm_join_del_all(struct interface *ifp)
{
struct pim_interface *pim_ifp;
@@ -1398,7 +1464,160 @@ static void pim_if_gm_join_del_all(struct interface *ifp)
return;
for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij))
- pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr);
+ pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr,
+ GM_JOIN_STATIC);
+}
+
+ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr,
+ pim_addr source_addr)
+{
+ struct pim_interface *pim_ifp;
+ struct static_group *stgrp;
+
+ pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ return ferr_cfg_invalid("multicast not enabled on interface %s",
+ ifp->name);
+ }
+
+ if (!pim_ifp->static_group_list) {
+ pim_ifp->static_group_list = list_new();
+ pim_ifp->static_group_list->del =
+ (void (*)(void *))static_group_free;
+ }
+
+ stgrp = static_group_find(pim_ifp->static_group_list, group_addr,
+ source_addr);
+
+ /* This interface has already been configured with this static group
+ */
+ if (stgrp)
+ return ferr_ok();
+
+ (void)static_group_new(ifp, group_addr, source_addr);
+
+ if (PIM_DEBUG_GM_EVENTS) {
+ zlog_debug("%s: Added static group (S,G)=(%pPA,%pPA) on interface %s",
+ __func__, &source_addr, &group_addr, ifp->name);
+ }
+
+ return ferr_ok();
+}
+
+int pim_if_static_group_del(struct interface *ifp, pim_addr group_addr,
+ pim_addr source_addr)
+{
+ struct pim_interface *pim_ifp;
+ struct static_group *stgrp;
+ pim_sgaddr sg;
+
+ pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ zlog_warn("%s: multicast not enabled on interface %s", __func__,
+ ifp->name);
+ return -1;
+ }
+
+ if (!pim_ifp->static_group_list) {
+ zlog_warn("%s: no static groups on interface %s", __func__,
+ ifp->name);
+ return -2;
+ }
+
+ stgrp = static_group_find(pim_ifp->static_group_list, group_addr,
+ source_addr);
+ if (!stgrp) {
+ zlog_warn("%s: could not find static group %pPAs source %pPAs on interface %s",
+ __func__, &group_addr, &source_addr, ifp->name);
+ return -3;
+ }
+
+ memset(&sg, 0, sizeof(sg));
+ sg.src = source_addr;
+ sg.grp = group_addr;
+
+ tib_sg_gm_prune(pim_ifp->pim, sg, ifp, &(stgrp->oilp));
+
+ listnode_delete(pim_ifp->static_group_list, stgrp);
+ static_group_free(stgrp);
+ if (listcount(pim_ifp->static_group_list) < 1) {
+ list_delete(&pim_ifp->static_group_list);
+ pim_ifp->static_group_list = 0;
+ }
+
+ return 0;
+}
+
+static void pim_if_static_group_del_all(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp;
+ struct listnode *node;
+ struct listnode *nextnode;
+ struct static_group *stgrp;
+
+ pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ zlog_warn("%s: multicast not enabled on interface %s", __func__,
+ ifp->name);
+ return;
+ }
+
+ if (!pim_ifp->static_group_list)
+ return;
+
+ for (ALL_LIST_ELEMENTS(pim_ifp->static_group_list, node, nextnode,
+ stgrp))
+ pim_if_static_group_del(ifp, stgrp->group_addr,
+ stgrp->source_addr);
+}
+
+void pim_if_gm_proxy_init(struct pim_instance *pim, struct interface *oif)
+{
+ struct interface *ifp;
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp = ifp->info;
+ struct listnode *source_node, *group_node;
+ struct gm_group *group;
+ struct gm_source *src;
+
+ if (!pim_ifp)
+ continue;
+
+ if (ifp == oif) /* skip the source interface */
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, group_node,
+ group)) {
+ for (ALL_LIST_ELEMENTS_RO(group->group_source_list,
+ source_node, src)) {
+ pim_if_gm_join_add(oif, group->group_addr,
+ src->source_addr,
+ GM_JOIN_PROXY);
+ }
+ }
+ } /* scan interfaces */
+}
+
+void pim_if_gm_proxy_finis(struct pim_instance *pim, struct interface *ifp)
+{
+ struct pim_interface *pim_ifp = ifp->info;
+ struct listnode *join_node;
+ struct listnode *next_join_node;
+ struct gm_join *join;
+
+ if (!pim_ifp) {
+ zlog_warn("%s: multicast not enabled on interface %s", __func__,
+ ifp->name);
+ return;
+ }
+
+ for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, join_node, next_join_node,
+ join)) {
+ if (join)
+ pim_if_gm_join_del(ifp, join->group_addr,
+ join->source_addr, GM_JOIN_PROXY);
+ }
}
/*
@@ -1683,6 +1902,14 @@ static int pim_ifp_up(struct interface *ifp)
}
}
}
+
+#if PIM_IPV == 4
+ if (pim->autorp && pim->autorp->do_discovery && pim_ifp &&
+ pim_ifp->pim_enable)
+ pim_autorp_add_ifp(ifp);
+#endif
+
+ pim_cand_addrs_changed();
return 0;
}
@@ -1719,6 +1946,11 @@ static int pim_ifp_down(struct interface *ifp)
pim_ifstat_reset(ifp);
}
+#if PIM_IPV == 4
+ pim_autorp_rm_ifp(ifp);
+#endif
+
+ pim_cand_addrs_changed();
return 0;
}
@@ -1790,6 +2022,11 @@ void pim_pim_interface_delete(struct interface *ifp)
if (!pim_ifp)
return;
+#if PIM_IPV == 4
+ if (pim_ifp->pim_enable)
+ pim_autorp_rm_ifp(ifp);
+#endif
+
pim_ifp->pim_enable = false;
pim_if_membership_clear(ifp);
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index 0312f719d3..95bac084d2 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -63,6 +63,7 @@ struct pim_interface {
bool pim_passive_enable : 1;
bool gm_enable : 1;
+ bool gm_proxy : 1; /* proxy IGMP joins/prunes */
ifindex_t mroute_vif_index;
struct pim_instance *pim;
@@ -98,6 +99,7 @@ struct pim_interface {
*/
struct list *gm_socket_list; /* list of struct IGMP or MLD sock */
struct list *gm_join_list; /* list of struct IGMP or MLD join */
+ struct list *static_group_list; /* list of struct static group */
struct list *gm_group_list; /* list of struct IGMP or MLD group */
struct hash *gm_group_hash;
@@ -218,9 +220,16 @@ int pim_if_t_override_msec(struct interface *ifp);
pim_addr pim_find_primary_addr(struct interface *ifp);
ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
- pim_addr source_addr);
+ pim_addr source_addr, enum gm_join_type join_type);
int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
- pim_addr source_addr);
+ pim_addr source_addr, enum gm_join_type join_type);
+void pim_if_gm_proxy_init(struct pim_instance *pim, struct interface *oif);
+void pim_if_gm_proxy_finis(struct pim_instance *pim, struct interface *ifp);
+
+ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr,
+ pim_addr source_addr);
+int pim_if_static_group_del(struct interface *ifp, pim_addr group_addr,
+ pim_addr source_addr);
void pim_if_update_could_assert(struct interface *ifp);
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index 063ba6edd2..1ba9bc45a2 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -213,15 +213,17 @@ void igmp_source_forward_stop(struct gm_source *source)
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
}
+ group = source->source_group;
+ pim_oif = group->interface->info;
+
/* Prevent IGMP interface from removing multicast route multiple
times */
if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
+ tib_sg_proxy_join_prune_check(pim_oif->pim, sg,
+ group->interface, false);
return;
}
- group = source->source_group;
- pim_oif = group->interface->info;
-
tib_sg_gm_prune(pim_oif->pim, sg, group->interface,
&source->source_channel_oil);
IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h
index a1f19b3c6e..83524e3980 100644
--- a/pimd/pim_igmp.h
+++ b/pimd/pim_igmp.h
@@ -51,13 +51,22 @@
output |= *((ptr) + 1); \
} while (0)
+enum gm_join_type { GM_JOIN_STATIC = 0, GM_JOIN_PROXY = 1, GM_JOIN_BOTH = 2 };
+
struct gm_join {
pim_addr group_addr;
pim_addr source_addr;
int sock_fd;
+ enum gm_join_type join_type;
time_t sock_creation;
};
+struct static_group {
+ pim_addr group_addr;
+ pim_addr source_addr;
+ struct channel_oil *oilp;
+};
+
struct gm_sock {
int fd;
struct interface *interface;
diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c
index a9eec9a9d2..f7c5ea3bcf 100644
--- a/pimd/pim_instance.c
+++ b/pimd/pim_instance.c
@@ -57,6 +57,10 @@ static void pim_instance_terminate(struct pim_instance *pim)
pim_mroute_socket_disable(pim);
+#if PIM_IPV == 4
+ pim_autorp_finish(pim);
+#endif
+
XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
@@ -125,6 +129,10 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf)
pim->msdp.keep_alive = PIM_MSDP_PEER_KA_TIME;
pim->msdp.connection_retry = PIM_MSDP_PEER_CONNECT_RETRY_TIME;
+#if PIM_IPV == 4
+ pim_autorp_init(pim);
+#endif
+
return pim;
}
@@ -253,6 +261,7 @@ void pim_vrf_terminate(void)
if (!pim)
continue;
+ pim_crp_db_clear(&pim->global_scope);
pim_ssmpingd_destroy(pim);
pim_instance_terminate(pim);
diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h
index ec331332cf..f484d847b2 100644
--- a/pimd/pim_instance.h
+++ b/pimd/pim_instance.h
@@ -17,6 +17,7 @@
#include "pim_oil.h"
#include "pim_upstream.h"
#include "pim_mroute.h"
+#include "pim_autorp.h"
enum pim_spt_switchover {
PIM_SPT_IMMEDIATE,
@@ -152,6 +153,8 @@ struct pim_instance {
struct pim_msdp msdp;
struct pim_vxlan_instance vxlan;
+ struct pim_autorp *autorp;
+
struct list *ssmpingd_list;
pim_addr ssmpingd_group_addr;
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index 8f2ce0bed3..f88aca719e 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -68,6 +68,7 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = {
&frr_routing_info,
&frr_pim_info,
&frr_pim_rp_info,
+ &frr_pim_candidate_info,
&frr_gmp_info,
};
diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c
index 604e24482d..2c35bc6473 100644
--- a/pimd/pim_memory.c
+++ b/pimd/pim_memory.c
@@ -14,6 +14,7 @@ DEFINE_MGROUP(PIMD, "pimd");
DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL");
DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface");
DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join");
+DEFINE_MTYPE(PIMD, PIM_STATIC_GROUP, "PIM interface IGMP static group");
DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket");
DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group");
DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source");
diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h
index 353e09a71c..b44d3e191a 100644
--- a/pimd/pim_memory.h
+++ b/pimd/pim_memory.h
@@ -13,6 +13,7 @@ DECLARE_MGROUP(PIMD);
DECLARE_MTYPE(PIM_CHANNEL_OIL);
DECLARE_MTYPE(PIM_INTERFACE);
DECLARE_MTYPE(PIM_IGMP_JOIN);
+DECLARE_MTYPE(PIM_STATIC_GROUP);
DECLARE_MTYPE(PIM_IGMP_SOCKET);
DECLARE_MTYPE(PIM_IGMP_GROUP);
DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE);
diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h
index 56923b7ec1..1f916af881 100644
--- a/pimd/pim_msg.h
+++ b/pimd/pim_msg.h
@@ -148,6 +148,7 @@ struct pim_encoded_source_ipv6 {
typedef struct pim_encoded_ipv4_unicast pim_encoded_unicast;
typedef struct pim_encoded_group_ipv4 pim_encoded_group;
typedef struct pim_encoded_source_ipv4 pim_encoded_source;
+#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4
typedef struct ip ipv_hdr;
#define IPV_SRC(ip_hdr) ((ip_hdr))->ip_src
#define IPV_DST(ip_hdr) ((ip_hdr))->ip_dst
@@ -156,6 +157,7 @@ typedef struct ip ipv_hdr;
typedef struct pim_encoded_ipv6_unicast pim_encoded_unicast;
typedef struct pim_encoded_group_ipv6 pim_encoded_group;
typedef struct pim_encoded_source_ipv6 pim_encoded_source;
+#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6
typedef struct ip6_hdr ipv_hdr;
#define IPV_SRC(ip_hdr) ((ip_hdr))->ip6_src
#define IPV_DST(ip_hdr) ((ip_hdr))->ip6_dst
diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c
index 72b5bdefc9..66001d1463 100644
--- a/pimd/pim_nb.c
+++ b/pimd/pim_nb.c
@@ -380,6 +380,161 @@ const struct frr_yang_module_info frr_pim_rp_info = {
}
},
{
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/discovery-enabled",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-scope",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-interval",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-holdtime",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list",
+ .cbs = {
+ .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/group",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/prefix-list",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
+
+const struct frr_yang_module_info frr_pim_candidate_info = {
+ .name = "frr-pim-candidate",
+ .nodes = {
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr",
+ .cbs = {
+ .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_create,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/bsr-priority",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_priority_modify,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/address",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/interface",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/if-loopback",
+ .cbs = {
+ .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/if-any",
+ .cbs = {
+ .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy,
+ }
+ },
+
+ /* Candidate-RP */
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp",
+ .cbs = {
+ .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/rp-priority",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/advertisement-interval",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_adv_interval_modify,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/group-list",
+ .cbs = {
+ .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/address",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/interface",
+ .cbs = {
+ .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/if-loopback",
+ .cbs = {
+ .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/if-any",
+ .cbs = {
+ .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
+ }
+ },
+ {
.xpath = NULL,
},
}
@@ -441,6 +596,19 @@ const struct frr_yang_module_info frr_gmp_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/join-group",
+ .cbs = {
+ .create = lib_interface_gmp_address_family_join_group_create,
+ .destroy = lib_interface_gmp_address_family_join_group_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/proxy",
+ .cbs = {
+ .modify = lib_interface_gmp_address_family_proxy_modify,
+ }
+ },
+{
.xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group",
.cbs = {
.create = lib_interface_gmp_address_family_static_group_create,
@@ -452,4 +620,3 @@ const struct frr_yang_module_info frr_gmp_info = {
},
}
};
-
diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h
index 3c7ab49ab3..befad4efe4 100644
--- a/pimd/pim_nb.h
+++ b/pimd/pim_nb.h
@@ -9,6 +9,7 @@
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_pim_candidate_info;
extern const struct frr_yang_module_info frr_gmp_info;
/* frr-pim prototypes*/
@@ -158,6 +159,68 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp
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);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy(
+ struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy(
+ struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy(
+ struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy(
+ struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create(
+ struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy(
+ struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy(
+ struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy(
+ struct nb_cb_destroy_args *args);
+
+/* frr-cand-bsr */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_create(
+ struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_destroy(
+ struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_priority_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create(
+ struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy(
+ struct nb_cb_destroy_args *args);
+
+/* frr-candidate */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create(
+ struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy(
+ struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_adv_interval_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create(
+ struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy(
+ struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create(
+ struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify(
+ struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy(
+ struct nb_cb_destroy_args *args);
/* frr-gmp prototypes*/
int lib_interface_gmp_address_family_create(
@@ -182,6 +245,11 @@ int lib_interface_gmp_address_family_last_member_query_interval_modify(
struct nb_cb_modify_args *args);
int lib_interface_gmp_address_family_robustness_variable_modify(
struct nb_cb_modify_args *args);
+int lib_interface_gmp_address_family_join_group_create(
+ struct nb_cb_create_args *args);
+int lib_interface_gmp_address_family_join_group_destroy(
+ struct nb_cb_destroy_args *args);
+int lib_interface_gmp_address_family_proxy_modify(struct nb_cb_modify_args *args);
int lib_interface_gmp_address_family_static_group_create(
struct nb_cb_create_args *args);
int lib_interface_gmp_address_family_static_group_destroy(
@@ -200,6 +268,9 @@ int routing_control_plane_protocols_name_validate(
#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv6"
#endif
+#define FRR_PIM_CAND_RP_XPATH "./frr-pim-candidate:candidate-rp"
+#define FRR_PIM_CAND_BSR_XPATH "./frr-pim-candidate:candidate-bsr"
+
#define FRR_PIM_VRF_XPATH \
"/frr-routing:routing/control-plane-protocols/" \
"control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \
@@ -215,12 +286,16 @@ int routing_control_plane_protocols_name_validate(
"mroute[source-addr='%s'][group-addr='%s']"
#define FRR_PIM_STATIC_RP_XPATH \
"frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']"
+#define FRR_PIM_AUTORP_XPATH "./frr-pim-rp:rp/auto-rp"
#define FRR_GMP_INTERFACE_XPATH \
"./frr-gmp:gmp/address-family[address-family='%s']"
#define FRR_GMP_ENABLE_XPATH \
"%s/frr-gmp:gmp/address-family[address-family='%s']/enable"
-#define FRR_GMP_JOIN_XPATH \
- "./frr-gmp:gmp/address-family[address-family='%s']/" \
+#define FRR_GMP_JOIN_GROUP_XPATH \
+ "./frr-gmp:gmp/address-family[address-family='%s']/" \
+ "join-group[group-addr='%s'][source-addr='%s']"
+#define FRR_GMP_STATIC_GROUP_XPATH \
+ "./frr-gmp:gmp/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
index bc7338ce18..ea8b56fee3 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -26,6 +26,8 @@
#include "lib_errors.h"
#include "pim_util.h"
#include "pim6_mld.h"
+#include "pim_autorp.h"
+#include "pim_igmp.h"
#if PIM_IPV == 6
#define pim6_msdp_err(funcname, argtype) \
@@ -146,6 +148,11 @@ static int pim_cmd_interface_add(struct interface *ifp)
pim_if_membership_refresh(ifp);
pim_if_create_pimreg(pim_ifp->pim);
+
+#if PIM_IPV == 4
+ pim_autorp_add_ifp(ifp);
+#endif
+
return 1;
}
@@ -927,10 +934,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss
yang_dnode_get_pimaddr(&source_addr, args->dnode, NULL);
result = pim_ssmpingd_start(pim, source_addr);
if (result) {
- snprintf(
- args->errmsg, args->errmsg_len,
- "%% Failure starting ssmpingd for source %pPA: %d",
- &source_addr, result);
+ snprintfrr(args->errmsg, args->errmsg_len,
+ "%% Failure starting ssmpingd for source %pPA: %d", &source_addr,
+ result);
return NB_ERR_INCONSISTENCY;
}
}
@@ -957,10 +963,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss
yang_dnode_get_pimaddr(&source_addr, args->dnode, NULL);
result = pim_ssmpingd_stop(pim, source_addr);
if (result) {
- snprintf(
- args->errmsg, args->errmsg_len,
- "%% Failure stopping ssmpingd for source %pPA: %d",
- &source_addr, result);
+ snprintfrr(args->errmsg, args->errmsg_len,
+ "%% Failure stopping ssmpingd for source %pPA: %d", &source_addr,
+ result);
return NB_ERR_INCONSISTENCY;
}
@@ -2058,6 +2063,10 @@ int lib_interface_pim_address_family_bsm_modify(struct nb_cb_modify_args *args)
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ pim_ifp = pim_if_new(ifp, false, true, false, false);
+ ifp->info = pim_ifp;
+ }
pim_ifp->bsm_enable = yang_dnode_get_bool(args->dnode, NULL);
break;
@@ -2083,6 +2092,10 @@ int lib_interface_pim_address_family_unicast_bsm_modify(
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ pim_ifp = pim_if_new(ifp, false, true, false, false);
+ ifp->info = pim_ifp;
+ }
pim_ifp->ucast_bsm_accept =
yang_dnode_get_bool(args->dnode, NULL);
@@ -2672,6 +2685,750 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp
}
/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/discovery-enabled
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify(
+ struct nb_cb_modify_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ bool enabled;
+
+ 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;
+ enabled = yang_dnode_get_bool(args->dnode, NULL);
+ if (enabled)
+ pim_autorp_start_discovery(pim);
+ else
+ pim_autorp_stop_discovery(pim);
+ break;
+ }
+#endif
+
+ return NB_OK;
+}
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy(
+ struct nb_cb_destroy_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ bool enabled;
+
+ 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;
+ enabled = yang_dnode_get_bool(args->dnode, NULL);
+ /* Run AutoRP discovery by default */
+ if (!enabled)
+ pim_autorp_start_discovery(pim);
+ break;
+ }
+#endif
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-scope
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify(
+ struct nb_cb_modify_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ uint8_t scope;
+
+ 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;
+ scope = yang_dnode_get_uint8(args->dnode, NULL);
+ pim_autorp_announce_scope(pim, scope);
+ }
+#endif
+
+ return NB_OK;
+}
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy(
+ struct nb_cb_destroy_args *args)
+{
+#if PIM_IPV == 4
+ 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_autorp_announce_scope(pim, 0);
+ }
+#endif
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-interval
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify(
+ struct nb_cb_modify_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ uint16_t interval;
+
+ 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;
+ interval = yang_dnode_get_uint16(args->dnode, NULL);
+ pim_autorp_announce_interval(pim, interval);
+ }
+#endif
+
+ return NB_OK;
+}
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy(
+ struct nb_cb_destroy_args *args)
+{
+#if PIM_IPV == 4
+ 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_autorp_announce_interval(pim, 0);
+ }
+#endif
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-holdtime
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify(
+ struct nb_cb_modify_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ uint16_t holdtime;
+
+ 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;
+ holdtime = yang_dnode_get_uint16(args->dnode, NULL);
+ pim_autorp_announce_holdtime(pim, holdtime);
+ }
+#endif
+
+ return NB_OK;
+}
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy(
+ struct nb_cb_destroy_args *args)
+{
+#if PIM_IPV == 4
+ 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;
+ /* 0 is a valid value, so -1 indicates deleting (go back to default) */
+ pim_autorp_announce_holdtime(pim, -1);
+ }
+#endif
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create(
+ struct nb_cb_create_args *args)
+{
+#if PIM_IPV == 4
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ break;
+ }
+#endif
+
+ return NB_OK;
+}
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy(
+ struct nb_cb_destroy_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ pim_addr 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_pimaddr(&rp_addr, args->dnode, "rp-address");
+ if (!pim_autorp_rm_candidate_rp(pim, rp_addr))
+ return NB_ERR_INCONSISTENCY;
+ break;
+ }
+#endif
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/group
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify(
+ struct nb_cb_modify_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct prefix group;
+ pim_addr 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_pimaddr(&rp_addr, args->dnode, "../rp-address");
+ yang_dnode_get_prefix(&group, args->dnode, NULL);
+ apply_mask(&group);
+ pim_autorp_add_candidate_rp_group(pim, rp_addr, group);
+ }
+#endif
+
+ return NB_OK;
+}
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy(
+ struct nb_cb_destroy_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct prefix group;
+ pim_addr 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_pimaddr(&rp_addr, args->dnode, "../rp-address");
+ yang_dnode_get_prefix(&group, args->dnode, NULL);
+ apply_mask(&group);
+ if (!pim_autorp_rm_candidate_rp_group(pim, rp_addr, group))
+ return NB_ERR_INCONSISTENCY;
+ }
+#endif
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/prefix-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify(
+ struct nb_cb_modify_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ pim_addr 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_pimaddr(&rp_addr, args->dnode, "../rp-address");
+ pim_autorp_add_candidate_rp_plist(pim, rp_addr, plist);
+ }
+#endif
+
+ return NB_OK;
+}
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy(
+ struct nb_cb_destroy_args *args)
+{
+#if PIM_IPV == 4
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ pim_addr 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_pimaddr(&rp_addr, args->dnode, "../rp-address");
+ plist = yang_dnode_get_string(args->dnode, NULL);
+ if (!pim_autorp_rm_candidate_rp_plist(pim, rp_addr, plist))
+ return NB_ERR_INCONSISTENCY;
+ break;
+ }
+#endif
+
+ return NB_OK;
+}
+
+static void yang_addrsel(struct cand_addrsel *addrsel,
+ const struct lyd_node *node)
+{
+ memset(addrsel->cfg_ifname, 0, sizeof(addrsel->cfg_ifname));
+ addrsel->cfg_addr = PIMADDR_ANY;
+
+ if (yang_dnode_exists(node, "if-any")) {
+ addrsel->cfg_mode = CAND_ADDR_ANY;
+ } else if (yang_dnode_exists(node, "address")) {
+ addrsel->cfg_mode = CAND_ADDR_EXPLICIT;
+ yang_dnode_get_pimaddr(&addrsel->cfg_addr, node, "address");
+ } else if (yang_dnode_exists(node, "interface")) {
+ addrsel->cfg_mode = CAND_ADDR_IFACE;
+ strlcpy(addrsel->cfg_ifname,
+ yang_dnode_get_string(node, "interface"),
+ sizeof(addrsel->cfg_ifname));
+ } else if (yang_dnode_exists(node, "if-loopback")) {
+ addrsel->cfg_mode = CAND_ADDR_LO;
+ }
+}
+
+static int candidate_bsr_addrsel(struct bsm_scope *scope,
+ const struct lyd_node *cand_bsr_node)
+{
+ yang_addrsel(&scope->bsr_addrsel, cand_bsr_node);
+ pim_cand_bsr_apply(scope);
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_create(
+ struct nb_cb_create_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+
+ 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;
+ scope = &pim->global_scope;
+
+ scope->bsr_addrsel.cfg_enable = true;
+ scope->cand_bsr_prio = yang_dnode_get_uint8(args->dnode,
+ "bsr-priority");
+
+ candidate_bsr_addrsel(scope, args->dnode);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+
+ 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;
+ scope = &pim->global_scope;
+
+ scope->bsr_addrsel.cfg_enable = false;
+
+ pim_cand_bsr_apply(scope);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_priority_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+
+ 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;
+ scope = &pim->global_scope;
+
+ scope->cand_bsr_prio = yang_dnode_get_uint8(args->dnode, NULL);
+
+ /* FIXME: force prio update */
+ candidate_bsr_addrsel(scope, args->dnode);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create(
+ struct nb_cb_create_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+ const struct lyd_node *cand_bsr_node;
+
+ cand_bsr_node = yang_dnode_get_parent(args->dnode, "candidate-bsr");
+
+ 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;
+ scope = &pim->global_scope;
+
+ return candidate_bsr_addrsel(scope, cand_bsr_node);
+ }
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+ const struct lyd_node *cand_bsr_node;
+
+ cand_bsr_node = yang_dnode_get_parent(args->dnode, "candidate-bsr");
+
+ 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;
+ scope = &pim->global_scope;
+
+ return candidate_bsr_addrsel(scope, cand_bsr_node);
+ }
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ /* nothing to do here, we'll get a CREATE for something else */
+ return NB_OK;
+}
+
+static int candidate_rp_addrsel(struct bsm_scope *scope,
+ const struct lyd_node *cand_rp_node)
+{
+ yang_addrsel(&scope->cand_rp_addrsel, cand_rp_node);
+ pim_cand_rp_apply(scope);
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create(
+ struct nb_cb_create_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+
+ 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;
+ scope = &pim->global_scope;
+
+ scope->cand_rp_addrsel.cfg_enable = true;
+ scope->cand_rp_prio = yang_dnode_get_uint8(args->dnode,
+ "rp-priority");
+ scope->cand_rp_interval =
+ yang_dnode_get_uint32(args->dnode,
+ "advertisement-interval");
+
+ candidate_rp_addrsel(scope, args->dnode);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+
+ 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;
+ scope = &pim->global_scope;
+
+ scope->cand_rp_addrsel.cfg_enable = false;
+
+ pim_cand_rp_apply(scope);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+
+ 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;
+ scope = &pim->global_scope;
+
+ scope->cand_rp_prio = yang_dnode_get_uint8(args->dnode, NULL);
+
+ pim_cand_rp_trigger(scope);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_adv_interval_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+
+ 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;
+ scope = &pim->global_scope;
+
+ scope->cand_rp_interval = yang_dnode_get_uint32(args->dnode,
+ NULL);
+
+ pim_cand_rp_trigger(scope);
+ break;
+ }
+
+ return NB_OK;
+}
+
+#if PIM_IPV == 4
+#define yang_dnode_get_pim_p yang_dnode_get_ipv4p
+#else
+#define yang_dnode_get_pim_p yang_dnode_get_ipv6p
+#endif
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create(
+ struct nb_cb_create_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+ prefix_pim p;
+
+ 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;
+ scope = &pim->global_scope;
+
+ yang_dnode_get_pim_p(&p, args->dnode, ".");
+ pim_cand_rp_grp_add(scope, &p);
+ break;
+ }
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+ prefix_pim p;
+
+ 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;
+ scope = &pim->global_scope;
+
+ yang_dnode_get_pim_p(&p, args->dnode, ".");
+ pim_cand_rp_grp_del(scope, &p);
+ break;
+ }
+ return NB_OK;
+}
+
+static int candidate_rp_addrsel_common(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct vrf *vrf;
+ struct pim_instance *pim;
+ struct bsm_scope *scope;
+
+ dnode = lyd_parent(dnode);
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ vrf = nb_running_get_entry(dnode, NULL, true);
+ pim = vrf->info;
+ scope = &pim->global_scope;
+
+ candidate_rp_addrsel(scope, dnode);
+ break;
+ }
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create(
+ struct nb_cb_create_args *args)
+{
+ return candidate_rp_addrsel_common(args->event, args->dnode);
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify(
+ struct nb_cb_modify_args *args)
+{
+ return candidate_rp_addrsel_common(args->event, args->dnode);
+}
+
+int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ /* nothing to do here - we'll get a create or modify event too */
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family
*/
int lib_interface_gmp_address_family_create(struct nb_cb_create_args *args)
@@ -2989,9 +3746,37 @@ int lib_interface_gmp_address_family_robustness_variable_modify(
}
/*
- * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/proxy
*/
-int lib_interface_gmp_address_family_static_group_create(
+int lib_interface_gmp_address_family_proxy_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 (pim_ifp) {
+ pim_ifp->gm_proxy = yang_dnode_get_bool(args->dnode,
+ NULL);
+
+ if (pim_ifp->gm_proxy)
+ pim_if_gm_proxy_init(pim_ifp->pim, ifp);
+ else
+ pim_if_gm_proxy_finis(pim_ifp->pim, ifp);
+ }
+ }
+ return NB_OK;
+}
+/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/join-group
+ */
+int lib_interface_gmp_address_family_join_group_create(
struct nb_cb_create_args *args)
{
struct interface *ifp;
@@ -3039,7 +3824,8 @@ int lib_interface_gmp_address_family_static_group_create(
"./source-addr");
yang_dnode_get_pimaddr(&group_addr, args->dnode,
"./group-addr");
- result = pim_if_gm_join_add(ifp, group_addr, source_addr);
+ result = pim_if_gm_join_add(ifp, group_addr, source_addr,
+ GM_JOIN_STATIC);
if (result) {
snprintf(args->errmsg, args->errmsg_len,
"Failure joining " GM " group");
@@ -3049,7 +3835,7 @@ int lib_interface_gmp_address_family_static_group_create(
return NB_OK;
}
-int lib_interface_gmp_address_family_static_group_destroy(
+int lib_interface_gmp_address_family_join_group_destroy(
struct nb_cb_destroy_args *args)
{
struct interface *ifp;
@@ -3068,13 +3854,104 @@ int lib_interface_gmp_address_family_static_group_destroy(
"./source-addr");
yang_dnode_get_pimaddr(&group_addr, args->dnode,
"./group-addr");
- result = pim_if_gm_join_del(ifp, group_addr, source_addr);
+ result = pim_if_gm_join_del(ifp, group_addr, source_addr,
+ GM_JOIN_STATIC);
+
+ if (result) {
+ snprintfrr(args->errmsg, args->errmsg_len,
+ "%% Failure leaving " GM " group %pPAs %pPAs on interface %s: %d",
+ &source_addr, &group_addr, ifp->name, result);
+
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ break;
+ }
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group
+ */
+int lib_interface_gmp_address_family_static_group_create(
+ struct nb_cb_create_args *args)
+{
+ struct interface *ifp;
+ pim_addr source_addr;
+ pim_addr 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, "name");
+ snprintf(args->errmsg, args->errmsg_len,
+ "multicast not enabled on interface %s",
+ ifp_name);
+ return NB_ERR_VALIDATION;
+ }
+
+ yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
+#if PIM_IPV == 4
+ if (pim_is_group_224_0_0_0_24(group_addr)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "Groups within 224.0.0.0/24 are reserved and cannot be joined");
+ return NB_ERR_VALIDATION;
+ }
+#else
+ if (ipv6_mcast_reserved(&group_addr)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "Groups within ffx2::/16 are reserved and cannot be joined");
+ return NB_ERR_VALIDATION;
+ }
+#endif
+ 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_pimaddr(&source_addr, args->dnode,
+ "./source-addr");
+ yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
+ result = pim_if_static_group_add(ifp, group_addr, source_addr);
if (result) {
snprintf(args->errmsg, args->errmsg_len,
- "%% Failure leaving " GM
- " group %pPAs %pPAs on interface %s: %d",
- &source_addr, &group_addr, ifp->name, result);
+ "Failure adding static group");
+ return NB_ERR_INCONSISTENCY;
+ }
+ }
+ return NB_OK;
+}
+
+int lib_interface_gmp_address_family_static_group_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+ pim_addr source_addr;
+ pim_addr 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_pimaddr(&source_addr, args->dnode,
+ "./source-addr");
+ yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
+ result = pim_if_static_group_del(ifp, group_addr, source_addr);
+
+ if (result) {
+ snprintfrr(args->errmsg, args->errmsg_len,
+ "%% Failure removing static group %pPAs %pPAs on interface %s: %d",
+ &source_addr, &group_addr, ifp->name, result);
return NB_ERR_INCONSISTENCY;
}
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 57dcff3b47..030b933e09 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -343,7 +343,8 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
if (!nbr)
continue;
- return znh->ifindex == src_ifp->ifindex;
+ return znh->ifindex == src_ifp->ifindex &&
+ (!pim_addr_cmp(znh->nexthop_addr, src_ip));
}
return false;
}
@@ -404,13 +405,12 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
return true;
/* MRIB (IGP) may be pointing at a router where PIM is down */
-
nbr = pim_neighbor_find(ifp, nhaddr, true);
-
if (!nbr)
continue;
- return nh->ifindex == src_ifp->ifindex;
+ return nh->ifindex == src_ifp->ifindex &&
+ (!pim_addr_cmp(nhaddr, src_ip));
}
return false;
}
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 6a7e8924f2..a41bbacea7 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -13,7 +13,6 @@
#include "network.h"
#include "pimd.h"
-#include "pim_instance.h"
#include "pim_pim.h"
#include "pim_time.h"
#include "pim_iface.h"
@@ -139,7 +138,7 @@ static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr)
}
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
- pim_sgaddr sg)
+ pim_sgaddr sg, bool is_mcast)
{
struct iovec iov[2], *iovp = iov;
#if PIM_IPV == 4
@@ -274,6 +273,22 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
return -1;
}
+ if (!is_mcast) {
+ if (header->type == PIM_MSG_TYPE_CANDIDATE) {
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("%s %s: Candidate RP PIM message from %pPA on %s",
+ __FILE__, __func__, &sg.src,
+ ifp->name);
+
+ return pim_crp_process(ifp, &sg, pim_msg, pim_msg_len);
+ }
+
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug(
+ "ignoring link traffic on BSR unicast socket");
+ return -1;
+ }
+
switch (header->type) {
case PIM_MSG_TYPE_HELLO:
return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN,
@@ -322,6 +337,13 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd);
break;
+ case PIM_MSG_TYPE_CANDIDATE:
+ /* return pim_crp_process(ifp, &sg, pim_msg, pim_msg_len); */
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug(
+ "ignoring Candidate-RP packet on multicast socket");
+ return 0;
+
default:
if (PIM_DEBUG_PIM_PACKETS) {
zlog_debug(
@@ -332,13 +354,9 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
}
}
-static void pim_sock_read_on(struct interface *ifp);
-
-static void pim_sock_read(struct event *t)
+int pim_sock_read_helper(int fd, struct pim_instance *pim, bool is_mcast)
{
- struct interface *ifp, *orig_ifp;
- struct pim_interface *pim_ifp;
- int fd;
+ struct interface *ifp = NULL;
struct sockaddr_storage from;
struct sockaddr_storage to;
socklen_t fromlen = sizeof(from);
@@ -346,16 +364,9 @@ static void pim_sock_read(struct event *t)
uint8_t buf[PIM_PIM_BUFSIZE_READ];
int len;
ifindex_t ifindex = -1;
- int result = -1; /* defaults to bad */
- static long long count = 0;
- int cont = 1;
-
- orig_ifp = ifp = EVENT_ARG(t);
- fd = EVENT_FD(t);
-
- pim_ifp = ifp->info;
+ int i;
- while (cont) {
+ for (i = 0; i < router->packet_process; i++) {
pim_sgaddr sg;
len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from,
@@ -369,7 +380,7 @@ static void pim_sock_read(struct event *t)
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("Received errno: %d %s", errno,
safe_strerror(errno));
- goto done;
+ return -1;
}
/*
@@ -378,14 +389,21 @@ static void pim_sock_read(struct event *t)
* the right ifindex, so just use it. We know
* it's the right interface because we bind to it
*/
- ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf->vrf_id);
- if (!ifp || !ifp->info) {
+ if (pim != NULL)
+ ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
+
+ /*
+ * unicast BSM pkts (C-RP) may arrive on non pim interfaces
+ * mcast pkts are only expected in pim interfaces
+ */
+ if (!ifp || (is_mcast && !ifp->info)) {
if (PIM_DEBUG_PIM_PACKETS)
- zlog_debug(
- "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim",
- __func__, ifp ? ifp->name : "Unknown",
- ifindex);
- goto done;
+ zlog_debug("%s: Received incoming pim packet on interface(%s:%d)%s",
+ __func__,
+ ifp ? ifp->name : "Unknown", ifindex,
+ is_mcast ? " not yet configured for pim"
+ : "");
+ return -1;
}
#if PIM_IPV == 4
sg.src = ((struct sockaddr_in *)&from)->sin_addr;
@@ -395,27 +413,34 @@ static void pim_sock_read(struct event *t)
sg.grp = ((struct sockaddr_in6 *)&to)->sin6_addr;
#endif
- int fail = pim_pim_packet(ifp, buf, len, sg);
+ int fail = pim_pim_packet(ifp, buf, len, sg, is_mcast);
if (fail) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: pim_pim_packet() return=%d",
__func__, fail);
- goto done;
+ return -1;
}
-
- count++;
- if (count % router->packet_process == 0)
- cont = 0;
}
+ return 0;
+}
+
+static void pim_sock_read_on(struct interface *ifp);
- result = 0; /* good */
+static void pim_sock_read(struct event *t)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ int fd;
+
+ ifp = EVENT_ARG(t);
+ fd = EVENT_FD(t);
-done:
- pim_sock_read_on(orig_ifp);
+ pim_ifp = ifp->info;
- if (result) {
+ if (pim_sock_read_helper(fd, pim_ifp->pim, true) == 0)
++pim_ifp->pim_ifstat_hello_recvfail;
- }
+
+ pim_sock_read_on(ifp);
}
static void pim_sock_read_on(struct interface *ifp)
diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h
index 35e693013a..39b27bceda 100644
--- a/pimd/pim_pim.h
+++ b/pimd/pim_pim.h
@@ -10,6 +10,7 @@
#include <zebra.h>
#include "if.h"
+#include "pim_instance.h"
#define PIM_PIM_BUFSIZE_READ (20000)
#define PIM_PIM_BUFSIZE_WRITE (20000)
@@ -42,10 +43,12 @@ void pim_hello_restart_now(struct interface *ifp);
void pim_hello_restart_triggered(struct interface *ifp);
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
- pim_sgaddr sg);
+ pim_sgaddr sg, bool is_mcast);
int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
int pim_msg_size, struct interface *ifp);
int pim_hello_send(struct interface *ifp, uint16_t holdtime);
+
+int pim_sock_read_helper(int fd, struct pim_instance *pim, bool is_mcast);
#endif /* PIM_PIM_H */
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 0f8940bb16..0c47bc1582 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -1140,7 +1140,8 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty)
if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
continue;
- if (rp_info->rp_src == RP_SRC_BSR)
+ if (rp_info->rp_src != RP_SRC_NONE &&
+ rp_info->rp_src != RP_SRC_STATIC)
continue;
rp_addr = rp_info->rp.rpf_addr;
@@ -1200,6 +1201,8 @@ void pim_rp_show_information(struct pim_instance *pim, struct prefix *range,
strlcpy(source, "Static", sizeof(source));
else if (rp_info->rp_src == RP_SRC_BSR)
strlcpy(source, "BSR", sizeof(source));
+ else if (rp_info->rp_src == RP_SRC_AUTORP)
+ strlcpy(source, "AutoRP", sizeof(source));
else
strlcpy(source, "None", sizeof(source));
if (json) {
@@ -1272,7 +1275,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct prefix *range,
if (!json) {
table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
} else {
if (prev_rp_info && json_rp_rows)
diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h
index 32c6306740..24832d0dbd 100644
--- a/pimd/pim_rp.h
+++ b/pimd/pim_rp.h
@@ -16,11 +16,7 @@
struct pim_interface;
-enum rp_source {
- RP_SRC_NONE = 0,
- RP_SRC_STATIC,
- RP_SRC_BSR
-};
+enum rp_source { RP_SRC_NONE = 0, RP_SRC_STATIC, RP_SRC_BSR, RP_SRC_AUTORP };
struct rp_info {
struct prefix group;
diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c
index 3476c177b7..8900652df9 100644
--- a/pimd/pim_sock.c
+++ b/pimd/pim_sock.c
@@ -292,6 +292,36 @@ int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
return ret;
}
+int pim_socket_leave(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
+ struct pim_interface *pim_ifp)
+{
+ int ret;
+
+#if PIM_IPV == 4
+ ret = setsockopt_ipv4_multicast(fd, IP_DROP_MEMBERSHIP, ifaddr,
+ group.s_addr, ifindex);
+#else
+ struct ipv6_mreq opt;
+
+ memcpy(&opt.ipv6mr_multiaddr, &group, 16);
+ opt.ipv6mr_interface = ifindex;
+ ret = setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &opt, sizeof(opt));
+#endif
+
+ if (ret) {
+ flog_err(EC_LIB_SOCKET,
+ "Failure socket leaving fd=%d group %pPAs on interface address %pPAs: %m",
+ fd, &group, &ifaddr);
+ pim_ifp->igmp_ifstat_joins_failed++;
+ return ret;
+ }
+
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("Socket fd=%d left group %pPAs on interface address %pPAs",
+ fd, &group, &ifaddr);
+ return ret;
+}
+
#if PIM_IPV == 4
static void cmsg_getdstaddr(struct msghdr *mh, struct sockaddr_storage *dst,
ifindex_t *ifindex)
diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h
index 04ab864744..0a81c6943a 100644
--- a/pimd/pim_sock.h
+++ b/pimd/pim_sock.h
@@ -26,11 +26,14 @@ struct pim_instance;
int pim_socket_bind(int fd, struct interface *ifp);
void pim_socket_ip_hdr(int fd);
+int pim_setsockopt_packetinfo(int fd);
int pim_socket_raw(int protocol);
int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp,
uint8_t loop);
int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
struct pim_interface *pim_ifp);
+int pim_socket_leave(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
+ struct pim_interface *pim_ifp);
int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
struct sockaddr_storage *from, socklen_t *fromlen,
struct sockaddr_storage *to, socklen_t *tolen,
diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c
index 4081786c1e..ac07154f86 100644
--- a/pimd/pim_tib.c
+++ b/pimd/pim_tib.c
@@ -78,6 +78,31 @@ tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif)
return pim_channel_oil_add(pim, &sg, __func__);
}
+void tib_sg_proxy_join_prune_check(struct pim_instance *pim, pim_sgaddr sg,
+ struct interface *oif, bool join)
+{
+ struct interface *ifp;
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (ifp == oif) /* skip the source interface */
+ continue;
+
+ if (pim_ifp->gm_enable && pim_ifp->gm_proxy) {
+ if (join)
+ pim_if_gm_join_add(ifp, sg.grp, sg.src,
+ GM_JOIN_PROXY);
+ else
+ pim_if_gm_join_del(ifp, sg.grp, sg.src,
+ GM_JOIN_PROXY);
+ }
+ } /* scan interfaces */
+}
+
bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
struct interface *oif, struct channel_oil **oilp)
{
@@ -95,6 +120,8 @@ bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
if (!*oilp)
return false;
+ tib_sg_proxy_join_prune_check(pim, sg, oif, true);
+
if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
int result;
@@ -137,6 +164,8 @@ void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
{
int result;
+ tib_sg_proxy_join_prune_check(pim, sg, oif, false);
+
/*
It appears that in certain circumstances that
igmp_source_forward_stop is called when IGMP forwarding
@@ -164,5 +193,5 @@ void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
*/
pim_ifchannel_local_membership_del(oif, &sg);
- pim_channel_oil_del(*oilp, __func__);
+ *oilp = pim_channel_oil_del(*oilp, __func__);
}
diff --git a/pimd/pim_tib.h b/pimd/pim_tib.h
index 081ad908b5..a41d0a8475 100644
--- a/pimd/pim_tib.h
+++ b/pimd/pim_tib.h
@@ -16,5 +16,8 @@ extern bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
struct interface *oif, struct channel_oil **oilp);
extern void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
struct interface *oif, struct channel_oil **oilp);
+extern void tib_sg_proxy_join_prune_check(struct pim_instance *pim,
+ pim_sgaddr sg, struct interface *oif,
+ bool join);
#endif /* _FRR_PIM_GLUE_H */
diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c
index c463fa227c..dd1bf2c059 100644
--- a/pimd/pim_tlv.c
+++ b/pimd/pim_tlv.c
@@ -19,12 +19,6 @@
#include "pim_iface.h"
#include "pim_addr.h"
-#if PIM_IPV == 4
-#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4
-#else
-#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6
-#endif
-
uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend,
uint16_t option_type, uint16_t option_value)
{
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 1910a68495..b633e81d55 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -165,6 +165,11 @@ int pim_debug_config_write(struct vty *vty)
++writes;
}
+ if (PIM_DEBUG_AUTORP) {
+ vty_out(vty, "debug pim autorp\n");
+ ++writes;
+ }
+
return writes;
}
@@ -182,6 +187,10 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty)
}
writes += pim_rp_config_write(pim, vty);
+#if PIM_IPV == 4
+ writes += pim_autorp_config_write(pim, vty);
+#endif
+ writes += pim_cand_config_write(pim, vty);
if (pim->vrf->vrf_id == VRF_DEFAULT) {
if (router->register_suppress_time
@@ -269,6 +278,11 @@ static int gm_config_write(struct vty *vty, int writes,
++writes;
}
+ if (pim_ifp->gm_proxy) {
+ vty_out(vty, " ip igmp proxy\n");
+ ++writes;
+ }
+
/* ip igmp version */
if (pim_ifp->igmp_version != IGMP_DEFAULT_VERSION) {
vty_out(vty, " ip igmp version %d\n", pim_ifp->igmp_version);
@@ -306,21 +320,38 @@ static int gm_config_write(struct vty *vty, int writes,
++writes;
}
- /* IF ip igmp join */
+ /* IF ip igmp join-group */
if (pim_ifp->gm_join_list) {
struct listnode *node;
struct gm_join *ij;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) {
if (pim_addr_is_any(ij->source_addr))
- vty_out(vty, " ip igmp join %pPAs\n",
+ vty_out(vty, " ip igmp join-group %pPAs\n",
&ij->group_addr);
else
- vty_out(vty, " ip igmp join %pPAs %pPAs\n",
+ vty_out(vty, " ip igmp join-group %pPAs %pPAs\n",
&ij->group_addr, &ij->source_addr);
++writes;
}
}
+ /* IF ip igmp static-group */
+ if (pim_ifp->static_group_list) {
+ struct listnode *node;
+ struct static_group *stgrp;
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node,
+ stgrp)) {
+ if (pim_addr_is_any(stgrp->source_addr))
+ vty_out(vty, " ip igmp static-group %pPAs\n",
+ &stgrp->group_addr);
+ else
+ vty_out(vty,
+ " ip igmp static-group %pPAs %pPAs\n",
+ &stgrp->group_addr, &stgrp->source_addr);
+ ++writes;
+ }
+ }
+
return writes;
}
#else
@@ -358,21 +389,41 @@ static int gm_config_write(struct vty *vty, int writes,
vty_out(vty, " ipv6 mld last-member-query-interval %d\n",
pim_ifp->gm_specific_query_max_response_time_dsec);
- /* IF ipv6 mld join */
+ /* IF ipv6 mld join-group */
if (pim_ifp->gm_join_list) {
struct listnode *node;
struct gm_join *ij;
+
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) {
if (pim_addr_is_any(ij->source_addr))
- vty_out(vty, " ipv6 mld join %pPAs\n",
+ vty_out(vty, " ipv6 mld join-group %pPAs\n",
&ij->group_addr);
else
- vty_out(vty, " ipv6 mld join %pPAs %pPAs\n",
+ vty_out(vty,
+ " ipv6 mld join-group %pPAs %pPAs\n",
&ij->group_addr, &ij->source_addr);
++writes;
}
}
+ /* IF ipv6 mld static-group */
+ if (pim_ifp->static_group_list) {
+ struct listnode *node;
+ struct static_group *stgrp;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node,
+ stgrp)) {
+ if (pim_addr_is_any(stgrp->source_addr))
+ vty_out(vty, " ipv6 mld static-group %pPAs\n",
+ &stgrp->group_addr);
+ else
+ vty_out(vty,
+ " ipv6 mld static-group %pPAs %pPAs\n",
+ &stgrp->group_addr, &stgrp->source_addr);
+ ++writes;
+ }
+ }
+
return writes;
}
#endif
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 04cd087e6a..ce4d85a2c8 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -97,7 +97,10 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
if (PIM_DEBUG_ZEBRA) {
zlog_debug("%s: %s(%s) connected IP address %pFX flags %u %s",
- __func__, c->ifp->name, VRF_LOGNAME(pim_ifp->pim->vrf), p, c->flags,
+ __func__, c->ifp->name,
+ (pim_ifp ? VRF_LOGNAME(pim_ifp->pim->vrf)
+ : "Unknown"),
+ p, c->flags,
CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
? "secondary"
: "primary");
@@ -154,6 +157,8 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
pim_if_addr_add_all(ifp);
}
}
+
+ pim_cand_addrs_changed();
return 0;
}
@@ -202,6 +207,8 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
}
connected_free(&c);
+
+ pim_cand_addrs_changed();
return 0;
}
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 3d9318953b..461b7d08a3 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -95,6 +95,7 @@
#define PIM_MASK_VXLAN (1 << 26)
#define PIM_MASK_BSM_PROC (1 << 27)
#define PIM_MASK_MLAG (1 << 28)
+#define PIM_MASK_AUTORP (1 << 29)
/* Remember 32 bits!!! */
/* PIM error codes */
@@ -167,6 +168,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
#define PIM_DEBUG_MTRACE (router->debugs & PIM_MASK_MTRACE)
#define PIM_DEBUG_VXLAN (router->debugs & PIM_MASK_VXLAN)
#define PIM_DEBUG_BSM (router->debugs & PIM_MASK_BSM_PROC)
+#define PIM_DEBUG_AUTORP (router->debugs & PIM_MASK_AUTORP)
#define PIM_DEBUG_EVENTS \
(router->debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_GM_EVENTS | \
@@ -209,6 +211,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
#define PIM_DO_DEBUG_PIM_NHT_RP (router->debugs |= PIM_MASK_PIM_NHT_RP)
#define PIM_DO_DEBUG_MTRACE (router->debugs |= PIM_MASK_MTRACE)
#define PIM_DO_DEBUG_VXLAN (router->debugs |= PIM_MASK_VXLAN)
+#define PIM_DO_DEBUG_AUTORP (router->debugs |= PIM_MASK_AUTORP)
#define PIM_DONT_DEBUG_PIM_EVENTS (router->debugs &= ~PIM_MASK_PIM_EVENTS)
#define PIM_DONT_DEBUG_PIM_PACKETS (router->debugs &= ~PIM_MASK_PIM_PACKETS)
@@ -243,6 +246,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
#define PIM_DONT_DEBUG_MTRACE (router->debugs &= ~PIM_MASK_MTRACE)
#define PIM_DONT_DEBUG_VXLAN (router->debugs &= ~PIM_MASK_VXLAN)
#define PIM_DONT_DEBUG_BSM (router->debugs &= ~PIM_MASK_BSM_PROC)
+#define PIM_DONT_DEBUG_AUTORP (router->debugs &= ~PIM_MASK_AUTORP)
/* RFC 3376: 8.1. Robustness Variable - Default: 2 for IGMP */
/* RFC 2710: 7.1. Robustness Variable - Default: 2 for MLD */
diff --git a/pimd/subdir.am b/pimd/subdir.am
index 1e787a3525..bda594e5c4 100644
--- a/pimd/subdir.am
+++ b/pimd/subdir.am
@@ -17,6 +17,7 @@ pim_common = \
pimd/pim_assert.c \
pimd/pim_bfd.c \
pimd/pim_bsm.c \
+ pimd/pim_bsr_rpdb.c \
pimd/pim_cmd_common.c \
pimd/pim_errors.c \
pimd/pim_hello.c \
@@ -58,6 +59,7 @@ pim_common = \
pimd_pimd_SOURCES = \
$(pim_common) \
+ pimd/pim_autorp.c \
pimd/pim_cmd.c \
pimd/pim_igmp.c \
pimd/pim_igmp_mtrace.c \
@@ -76,6 +78,7 @@ pimd_pimd_SOURCES = \
nodist_pimd_pimd_SOURCES = \
yang/frr-pim.yang.c \
yang/frr-pim-rp.yang.c \
+ yang/frr-pim-candidate.yang.c \
yang/frr-gmp.yang.c \
# end
@@ -89,12 +92,14 @@ pimd_pim6d_SOURCES = \
nodist_pimd_pim6d_SOURCES = \
yang/frr-pim.yang.c \
yang/frr-pim-rp.yang.c \
+ yang/frr-pim-candidate.yang.c \
yang/frr-gmp.yang.c \
# end
noinst_HEADERS += \
pimd/pim_addr.h \
pimd/pim_assert.h \
+ pimd/pim_autorp.h \
pimd/pim_bfd.h \
pimd/pim_bsm.h \
pimd/pim_cmd.h \
@@ -160,12 +165,12 @@ clippy_scan += \
# end
pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
-pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP)
+pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP) -lm
if PIM6D
sbin_PROGRAMS += pimd/pim6d
pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6
-pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP)
+pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP) -lm
endif
pimd_test_igmpv3_join_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
diff --git a/staticd/static_debug.c b/staticd/static_debug.c
index a65752c958..618ba91d12 100644
--- a/staticd/static_debug.c
+++ b/staticd/static_debug.c
@@ -19,68 +19,11 @@
*/
/* clang-format off */
-struct debug static_dbg_events = {0, "Staticd events"};
-struct debug static_dbg_route = {0, "Staticd route"};
-struct debug static_dbg_bfd = {0, "Staticd bfd"};
-
-struct debug *static_debug_arr[] = {
- &static_dbg_events,
- &static_dbg_route,
- &static_dbg_bfd
-};
-
-const char *static_debugs_conflines[] = {
- "debug static events",
- "debug static route",
- "debug static bfd"
-};
+struct debug static_dbg_events = {0, "debug static events", "Staticd events"};
+struct debug static_dbg_route = {0, "debug static route", "Staticd route"};
+struct debug static_dbg_bfd = {0, "debug static bfd", "Staticd bfd"};
/* clang-format on */
-
-/*
- * Set or unset all staticd debugs
- *
- * flags
- * The flags to set
- *
- * set
- * Whether to set or unset the specified flags
- */
-static void static_debug_set_all(uint32_t flags, bool set)
-{
- for (unsigned int i = 0; i < array_size(static_debug_arr); i++) {
- DEBUG_FLAGS_SET(static_debug_arr[i], flags, set);
-
- /* if all modes have been turned off, don't preserve options */
- if (!DEBUG_MODE_CHECK(static_debug_arr[i], DEBUG_MODE_ALL))
- DEBUG_CLEAR(static_debug_arr[i]);
- }
-}
-
-static int static_debug_config_write_helper(struct vty *vty, bool config)
-{
- uint32_t mode = DEBUG_MODE_ALL;
-
- if (config)
- mode = DEBUG_MODE_CONF;
-
- for (unsigned int i = 0; i < array_size(static_debug_arr); i++)
- if (DEBUG_MODE_CHECK(static_debug_arr[i], mode))
- vty_out(vty, "%s\n", static_debugs_conflines[i]);
-
- return 0;
-}
-
-int static_config_write_debug(struct vty *vty)
-{
- return static_debug_config_write_helper(vty, true);
-}
-
-int static_debug_status_write(struct vty *vty)
-{
- return static_debug_config_write_helper(vty, false);
-}
-
/*
* Set debugging status.
*
@@ -113,11 +56,9 @@ void static_debug_set(int vtynode, bool onoff, bool events, bool route,
* Debug lib initialization
*/
-struct debug_callbacks static_dbg_cbs = {
- .debug_set_all = static_debug_set_all
-};
-
void static_debug_init(void)
{
- debug_init(&static_dbg_cbs);
+ debug_install(&static_dbg_events);
+ debug_install(&static_dbg_route);
+ debug_install(&static_dbg_bfd);
}
diff --git a/staticd/static_debug.h b/staticd/static_debug.h
index c9100680f7..b990f7bcc9 100644
--- a/staticd/static_debug.h
+++ b/staticd/static_debug.h
@@ -29,22 +29,6 @@ extern struct debug static_dbg_bfd;
void static_debug_init(void);
/*
- * Print staticd debugging configuration.
- *
- * vty
- * VTY to print debugging configuration to.
- */
-int static_config_write_debug(struct vty *vty);
-
-/*
- * Print staticd debugging configuration, human readable form.
- *
- * vty
- * VTY to print debugging configuration to.
- */
-int static_debug_status_write(struct vty *vty);
-
-/*
* Set debugging status.
*
* vtynode
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index a18028ed08..07b8bc3d28 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -1639,26 +1639,16 @@ DEFUN_NOSH (show_debugging_static,
{
vty_out(vty, "Staticd debugging status\n");
- static_debug_status_write(vty);
-
cmd_show_lib_debugs(vty);
return CMD_SUCCESS;
}
-static struct cmd_node debug_node = {
- .name = "debug",
- .node = DEBUG_NODE,
- .prompt = "",
- .config_write = static_config_write_debug,
-};
-
#endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */
void static_vty_init(void)
{
#ifndef INCLUDE_MGMTD_CMDDEFS_ONLY
- install_node(&debug_node);
install_element(ENABLE_NODE, &debug_staticd_cmd);
install_element(CONFIG_NODE, &debug_staticd_cmd);
install_element(ENABLE_NODE, &show_debugging_static_cmd);
diff --git a/tests/bgpd/subdir.am b/tests/bgpd/subdir.am
index 5148e7e440..97845ec1aa 100644
--- a/tests/bgpd/subdir.am
+++ b/tests/bgpd/subdir.am
@@ -52,17 +52,6 @@ tests_bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD)
tests_bgpd_test_mp_attr_SOURCES = tests/bgpd/test_mp_attr.c
EXTRA_DIST += tests/bgpd/test_mp_attr.py
-
-if BGPD
-check_PROGRAMS += tests/bgpd/test_mpath
-endif
-tests_bgpd_test_mpath_CFLAGS = $(TESTS_CFLAGS)
-tests_bgpd_test_mpath_CPPFLAGS = $(TESTS_CPPFLAGS)
-tests_bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD)
-tests_bgpd_test_mpath_SOURCES = tests/bgpd/test_mpath.c
-EXTRA_DIST += tests/bgpd/test_mpath.py
-
-
if BGPD
check_PROGRAMS += tests/bgpd/test_packet
endif
diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c
deleted file mode 100644
index ebbe3ac3e2..0000000000
--- a/tests/bgpd/test_mpath.c
+++ /dev/null
@@ -1,482 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * BGP Multipath Unit Test
- * Copyright (C) 2010 Google Inc.
- *
- * This file is part of Quagga
- */
-
-#include <zebra.h>
-
-#include "qobj.h"
-#include "vty.h"
-#include "stream.h"
-#include "privs.h"
-#include "linklist.h"
-#include "memory.h"
-#include "zclient.h"
-#include "queue.h"
-#include "filter.h"
-
-#include "bgpd/bgpd.h"
-#include "bgpd/bgp_table.h"
-#include "bgpd/bgp_route.h"
-#include "bgpd/bgp_attr.h"
-#include "bgpd/bgp_nexthop.h"
-#include "bgpd/bgp_mpath.h"
-#include "bgpd/bgp_evpn.h"
-#include "bgpd/bgp_network.h"
-
-#define VT100_RESET "\x1b[0m"
-#define VT100_RED "\x1b[31m"
-#define VT100_GREEN "\x1b[32m"
-#define VT100_YELLOW "\x1b[33m"
-#define OK VT100_GREEN "OK" VT100_RESET
-#define FAILED VT100_RED "failed" VT100_RESET
-
-#define TEST_PASSED 0
-#define TEST_FAILED -1
-
-#define EXPECT_TRUE(expr, res) \
- if (!(expr)) { \
- printf("Test failure in %s line %u: %s\n", __func__, __LINE__, \
- #expr); \
- (res) = TEST_FAILED; \
- }
-
-typedef struct testcase_t__ testcase_t;
-
-typedef int (*test_setup_func)(testcase_t *);
-typedef int (*test_run_func)(testcase_t *);
-typedef int (*test_cleanup_func)(testcase_t *);
-
-struct testcase_t__ {
- const char *desc;
- void *test_data;
- void *verify_data;
- void *tmp_data;
- test_setup_func setup;
- test_run_func run;
- test_cleanup_func cleanup;
-};
-
-/* need these to link in libbgp */
-struct event_loop *master = NULL;
-extern struct zclient *zclient;
-struct zebra_privs_t bgpd_privs = {
- .user = NULL,
- .group = NULL,
- .vty_group = NULL,
-};
-
-static int tty = 0;
-
-/* Create fake bgp instance */
-static struct bgp *bgp_create_fake(as_t *as, const char *name)
-{
- struct bgp *bgp;
- afi_t afi;
- safi_t safi;
-
- if ((bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp))) == NULL)
- return NULL;
-
- bgp_lock(bgp);
- // bgp->peer_self = peer_new (bgp);
- // bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static
- // announcement");
-
- bgp->peer = list_new();
- // bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp;
-
- bgp->group = list_new();
- // bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp;
-
- bgp_evpn_init(bgp);
- FOREACH_AFI_SAFI (afi, safi) {
- bgp->route[afi][safi] = bgp_table_init(bgp, afi, safi);
- bgp->aggregate[afi][safi] = bgp_table_init(bgp, afi, safi);
- bgp->rib[afi][safi] = bgp_table_init(bgp, afi, safi);
- bgp->maxpaths[afi][safi].maxpaths_ebgp = MULTIPATH_NUM;
- bgp->maxpaths[afi][safi].maxpaths_ibgp = MULTIPATH_NUM;
- }
-
- bgp_scan_init(bgp);
- bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
- bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
- bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
- bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
- bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
-
- bgp->as = *as;
-
- if (name)
- bgp->name = strdup(name);
-
- return bgp;
-}
-
-/*=========================================================
- * Testcase for maximum-paths configuration
- */
-static int setup_bgp_cfg_maximum_paths(testcase_t *t)
-{
- as_t asn = 1;
- t->tmp_data = bgp_create_fake(&asn, NULL);
- if (!t->tmp_data)
- return -1;
- return 0;
-}
-
-static int run_bgp_cfg_maximum_paths(testcase_t *t)
-{
- afi_t afi;
- safi_t safi;
- struct bgp *bgp;
- int api_result;
- int test_result = TEST_PASSED;
-
- bgp = t->tmp_data;
- FOREACH_AFI_SAFI (afi, safi) {
- /* test bgp_maximum_paths_set */
- api_result = bgp_maximum_paths_set(bgp, afi, safi,
- BGP_PEER_EBGP, 10, 0);
- EXPECT_TRUE(api_result == 0, test_result);
- api_result = bgp_maximum_paths_set(bgp, afi, safi,
- BGP_PEER_IBGP, 10, 0);
- EXPECT_TRUE(api_result == 0, test_result);
- EXPECT_TRUE(bgp->maxpaths[afi][safi].maxpaths_ebgp == 10,
- test_result);
- EXPECT_TRUE(bgp->maxpaths[afi][safi].maxpaths_ibgp == 10,
- test_result);
-
- /* test bgp_maximum_paths_unset */
- api_result =
- bgp_maximum_paths_unset(bgp, afi, safi, BGP_PEER_EBGP);
- EXPECT_TRUE(api_result == 0, test_result);
- api_result =
- bgp_maximum_paths_unset(bgp, afi, safi, BGP_PEER_IBGP);
- EXPECT_TRUE(api_result == 0, test_result);
- EXPECT_TRUE((bgp->maxpaths[afi][safi].maxpaths_ebgp
- == MULTIPATH_NUM),
- test_result);
- EXPECT_TRUE((bgp->maxpaths[afi][safi].maxpaths_ibgp
- == MULTIPATH_NUM),
- test_result);
- }
-
- return test_result;
-}
-
-static int cleanup_bgp_cfg_maximum_paths(testcase_t *t)
-{
- return bgp_delete((struct bgp *)t->tmp_data);
-}
-
-testcase_t test_bgp_cfg_maximum_paths = {
- .desc = "Test bgp maximum-paths config",
- .setup = setup_bgp_cfg_maximum_paths,
- .run = run_bgp_cfg_maximum_paths,
- .cleanup = cleanup_bgp_cfg_maximum_paths,
-};
-
-/*=========================================================
- * Testcase for bgp_mp_list
- */
-struct peer test_mp_list_peer[] = {
- {.local_as = 1, .as = 2}, {.local_as = 1, .as = 2},
- {.local_as = 1, .as = 2}, {.local_as = 1, .as = 2},
- {.local_as = 1, .as = 2},
-};
-int test_mp_list_peer_count = array_size(test_mp_list_peer);
-struct attr test_mp_list_attr[4];
-struct bgp_path_info test_mp_list_info[] = {
- {.peer = &test_mp_list_peer[0], .attr = &test_mp_list_attr[0]},
- {.peer = &test_mp_list_peer[1], .attr = &test_mp_list_attr[1]},
- {.peer = &test_mp_list_peer[2], .attr = &test_mp_list_attr[1]},
- {.peer = &test_mp_list_peer[3], .attr = &test_mp_list_attr[2]},
- {.peer = &test_mp_list_peer[4], .attr = &test_mp_list_attr[3]},
-};
-int test_mp_list_info_count = array_size(test_mp_list_info);
-
-static int setup_bgp_mp_list(testcase_t *t)
-{
- test_mp_list_attr[0].nexthop.s_addr = 0x01010101;
- test_mp_list_attr[1].nexthop.s_addr = 0x02020202;
- test_mp_list_attr[2].nexthop.s_addr = 0x03030303;
- test_mp_list_attr[3].nexthop.s_addr = 0x04040404;
-
- if ((test_mp_list_peer[0].su_remote = sockunion_str2su("1.1.1.1"))
- == NULL)
- return -1;
- if ((test_mp_list_peer[1].su_remote = sockunion_str2su("2.2.2.2"))
- == NULL)
- return -1;
- if ((test_mp_list_peer[2].su_remote = sockunion_str2su("3.3.3.3"))
- == NULL)
- return -1;
- if ((test_mp_list_peer[3].su_remote = sockunion_str2su("4.4.4.4"))
- == NULL)
- return -1;
- if ((test_mp_list_peer[4].su_remote = sockunion_str2su("5.5.5.5"))
- == NULL)
- return -1;
-
- return 0;
-}
-
-static int run_bgp_mp_list(testcase_t *t)
-{
- struct list mp_list;
- struct listnode *mp_node;
- struct bgp_path_info *info;
- int i;
- int test_result = TEST_PASSED;
- bgp_mp_list_init(&mp_list);
- EXPECT_TRUE(listcount(&mp_list) == 0, test_result);
-
- bgp_mp_list_add(&mp_list, &test_mp_list_info[1]);
- bgp_mp_list_add(&mp_list, &test_mp_list_info[4]);
- bgp_mp_list_add(&mp_list, &test_mp_list_info[2]);
- bgp_mp_list_add(&mp_list, &test_mp_list_info[3]);
- bgp_mp_list_add(&mp_list, &test_mp_list_info[0]);
-
- for (i = 0, mp_node = mp_list.head; i < test_mp_list_info_count;
- i++, mp_node = listnextnode(mp_node)) {
- info = listgetdata(mp_node);
- info->lock++;
- EXPECT_TRUE(info == &test_mp_list_info[i], test_result);
- }
-
- bgp_mp_list_clear(&mp_list);
- EXPECT_TRUE(listcount(&mp_list) == 0, test_result);
-
- return test_result;
-}
-
-static int cleanup_bgp_mp_list(testcase_t *t)
-{
- int i;
-
- for (i = 0; i < test_mp_list_peer_count; i++)
- sockunion_free(test_mp_list_peer[i].su_remote);
-
- return 0;
-}
-
-testcase_t test_bgp_mp_list = {
- .desc = "Test bgp_mp_list",
- .setup = setup_bgp_mp_list,
- .run = run_bgp_mp_list,
- .cleanup = cleanup_bgp_mp_list,
-};
-
-/*=========================================================
- * Testcase for bgp_path_info_mpath_update
- */
-
-static struct bgp_dest *dest;
-
-static int setup_bgp_path_info_mpath_update(testcase_t *t)
-{
- int i;
- struct bgp *bgp;
- struct bgp_table *rt;
- struct prefix p;
- as_t asn = 1;
-
- t->tmp_data = bgp_create_fake(&asn, NULL);
- if (!t->tmp_data)
- return -1;
-
- bgp = t->tmp_data;
- rt = bgp->rib[AFI_IP][SAFI_UNICAST];
-
- if (!rt)
- return -1;
-
- str2prefix("42.1.1.0/24", &p);
- dest = bgp_node_get(rt, &p);
-
- setup_bgp_mp_list(t);
- for (i = 0; i < test_mp_list_info_count; i++)
- bgp_path_info_add(dest, &test_mp_list_info[i]);
- return 0;
-}
-
-static int run_bgp_path_info_mpath_update(testcase_t *t)
-{
- struct bgp_path_info *new_best, *old_best, *mpath;
- struct list mp_list;
- struct bgp_maxpaths_cfg mp_cfg = {3, 3};
-
- int test_result = TEST_PASSED;
- bgp_mp_list_init(&mp_list);
- bgp_mp_list_add(&mp_list, &test_mp_list_info[4]);
- bgp_mp_list_add(&mp_list, &test_mp_list_info[3]);
- bgp_mp_list_add(&mp_list, &test_mp_list_info[0]);
- bgp_mp_list_add(&mp_list, &test_mp_list_info[1]);
- new_best = &test_mp_list_info[3];
- old_best = NULL;
- bgp_path_info_mpath_update(NULL, dest, new_best, old_best, &mp_list,
- &mp_cfg);
- bgp_mp_list_clear(&mp_list);
- EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 2, test_result);
- mpath = bgp_path_info_mpath_first(new_best);
- EXPECT_TRUE(mpath == &test_mp_list_info[0], test_result);
- EXPECT_TRUE(CHECK_FLAG(mpath->flags, BGP_PATH_MULTIPATH), test_result);
- mpath = bgp_path_info_mpath_next(mpath);
- EXPECT_TRUE(mpath == &test_mp_list_info[1], test_result);
- EXPECT_TRUE(CHECK_FLAG(mpath->flags, BGP_PATH_MULTIPATH), test_result);
-
- bgp_mp_list_add(&mp_list, &test_mp_list_info[0]);
- bgp_mp_list_add(&mp_list, &test_mp_list_info[1]);
- new_best = &test_mp_list_info[0];
- old_best = &test_mp_list_info[3];
- bgp_path_info_mpath_update(NULL, dest, new_best, old_best, &mp_list,
- &mp_cfg);
- bgp_mp_list_clear(&mp_list);
- EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 1, test_result);
- mpath = bgp_path_info_mpath_first(new_best);
- EXPECT_TRUE(mpath == &test_mp_list_info[1], test_result);
- EXPECT_TRUE(CHECK_FLAG(mpath->flags, BGP_PATH_MULTIPATH), test_result);
- EXPECT_TRUE(!CHECK_FLAG(test_mp_list_info[0].flags, BGP_PATH_MULTIPATH),
- test_result);
-
- return test_result;
-}
-
-static int cleanup_bgp_path_info_mpath_update(testcase_t *t)
-{
- int i;
-
- for (i = 0; i < test_mp_list_peer_count; i++)
- sockunion_free(test_mp_list_peer[i].su_remote);
-
- return bgp_delete((struct bgp *)t->tmp_data);
-}
-
-testcase_t test_bgp_path_info_mpath_update = {
- .desc = "Test bgp_path_info_mpath_update",
- .setup = setup_bgp_path_info_mpath_update,
- .run = run_bgp_path_info_mpath_update,
- .cleanup = cleanup_bgp_path_info_mpath_update,
-};
-
-/*=========================================================
- * Set up testcase vector
- */
-testcase_t *all_tests[] = {
- &test_bgp_cfg_maximum_paths, &test_bgp_mp_list,
- &test_bgp_path_info_mpath_update,
-};
-
-int all_tests_count = array_size(all_tests);
-
-/*=========================================================
- * Test Driver Functions
- */
-static int global_test_init(void)
-{
- qobj_init();
- master = event_master_create(NULL);
- zclient = zclient_new(master, &zclient_options_default, NULL, 0);
- bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
- vrf_init(NULL, NULL, NULL, NULL);
- bgp_option_set(BGP_OPT_NO_LISTEN);
-
- if (fileno(stdout) >= 0)
- tty = isatty(fileno(stdout));
- return 0;
-}
-
-static int global_test_cleanup(void)
-{
- if (zclient != NULL)
- zclient_free(zclient);
- event_master_free(master);
- return 0;
-}
-
-static void display_result(testcase_t *test, int result)
-{
- if (tty)
- printf("%s: %s\n", test->desc,
- result == TEST_PASSED ? OK : FAILED);
- else
- printf("%s: %s\n", test->desc,
- result == TEST_PASSED ? "OK" : "FAILED");
-}
-
-static int setup_test(testcase_t *t)
-{
- int res = 0;
- if (t->setup)
- res = t->setup(t);
- return res;
-}
-
-static int cleanup_test(testcase_t *t)
-{
- int res = 0;
- if (t->cleanup)
- res = t->cleanup(t);
- return res;
-}
-
-static void run_tests(testcase_t *tests[], int num_tests, int *pass_count,
- int *fail_count)
-{
- int test_index, result;
- testcase_t *cur_test;
-
- *pass_count = *fail_count = 0;
-
- for (test_index = 0; test_index < num_tests; test_index++) {
- cur_test = tests[test_index];
- if (!cur_test->desc) {
- printf("error: test %d has no description!\n",
- test_index);
- continue;
- }
- if (!cur_test->run) {
- printf("error: test %s has no run function!\n",
- cur_test->desc);
- continue;
- }
- if (setup_test(cur_test) != 0) {
- printf("error: setup failed for test %s\n",
- cur_test->desc);
- continue;
- }
- result = cur_test->run(cur_test);
- if (result == TEST_PASSED)
- *pass_count += 1;
- else
- *fail_count += 1;
- display_result(cur_test, result);
- if (cleanup_test(cur_test) != 0) {
- printf("error: cleanup failed for test %s\n",
- cur_test->desc);
- continue;
- }
- }
-}
-
-int main(void)
-{
- int pass_count, fail_count;
- time_t cur_time;
- char buf[32];
-
- time(&cur_time);
- printf("BGP Multipath Tests Run at %s", ctime_r(&cur_time, buf));
- if (global_test_init() != 0) {
- printf("Global init failed. Terminating.\n");
- exit(1);
- }
- run_tests(all_tests, all_tests_count, &pass_count, &fail_count);
- global_test_cleanup();
- printf("Total pass/fail: %d/%d\n", pass_count, fail_count);
- return fail_count;
-}
diff --git a/tests/bgpd/test_mpath.py b/tests/bgpd/test_mpath.py
deleted file mode 100644
index 582fd25c20..0000000000
--- a/tests/bgpd/test_mpath.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import frrtest
-
-
-class TestMpath(frrtest.TestMultiOut):
- program = "./test_mpath"
-
-
-TestMpath.okfail("bgp maximum-paths config")
-TestMpath.okfail("bgp_mp_list")
-TestMpath.okfail("bgp_path_info_mpath_update")
diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c
index 767c41cfee..17002464e1 100644
--- a/tests/bgpd/test_peer_attr.c
+++ b/tests/bgpd/test_peer_attr.c
@@ -5,6 +5,7 @@
*/
#include <zebra.h>
+#include "debug.h"
#include "memory.h"
#include "plist.h"
#include "printfrr.h"
@@ -1348,12 +1349,13 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
static void bgp_startup(void)
{
cmd_init(1);
+ debug_init();
zlog_aux_init("NONE: ", LOG_DEBUG);
zprivs_preinit(&bgpd_privs);
zprivs_init(&bgpd_privs);
master = event_master_create(NULL);
- nb_init(master, NULL, 0, false);
+ nb_init(master, NULL, 0, false, false);
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
bgp_option_set(BGP_OPT_NO_LISTEN);
vrf_init(NULL, NULL, NULL, NULL);
diff --git a/tests/helpers/c/main.c b/tests/helpers/c/main.c
index fdda7f1e2a..344af82fca 100644
--- a/tests/helpers/c/main.c
+++ b/tests/helpers/c/main.c
@@ -6,6 +6,7 @@
#include <sys/stat.h>
#include <lib/version.h>
+#include "debug.h"
#include "getopt.h"
#include "frrevent.h"
#include "vty.h"
@@ -141,7 +142,8 @@ int main(int argc, char **argv)
cmd_init(1);
vty_init(master, false);
lib_cmd_init();
- nb_init(master, NULL, 0, false);
+ debug_init();
+ nb_init(master, NULL, 0, false, false);
/* OSPF vty inits. */
test_vty_init();
diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
index 195a7dd8c1..05e9f723a1 100644
--- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
+++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
Binary files differ
diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c
index 93009a1b84..e5a8f7a513 100644
--- a/tests/isisd/test_isis_spf.c
+++ b/tests/isisd/test_isis_spf.c
@@ -546,7 +546,7 @@ int main(int argc, char **argv)
cmd_init(1);
cmd_hostname_set("test");
vty_init(master, false);
- yang_init(true, false);
+ yang_init(true, false, false);
if (debug)
zlog_aux_init("NONE: ", LOG_DEBUG);
else
diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c
index f9f584f450..342a91cc79 100644
--- a/tests/lib/cli/common_cli.c
+++ b/tests/lib/cli/common_cli.c
@@ -9,6 +9,7 @@
#include <zebra.h>
#include <sys/stat.h>
+#include "debug.h"
#include "frrevent.h"
#include "vty.h"
#include "command.h"
@@ -71,11 +72,12 @@ int main(int argc, char **argv)
vty_init(master, false);
lib_cmd_init();
+ debug_init();
for (yangcount = 0; test_yang_modules && test_yang_modules[yangcount];
yangcount++)
;
- nb_init(master, test_yang_modules, yangcount, false);
+ nb_init(master, test_yang_modules, yangcount, false, false);
test_init(argc, argv);
diff --git a/tests/lib/cli/test_cli.refout.in b/tests/lib/cli/test_cli.refout.in
index 84365810d5..222abcdade 100644
--- a/tests/lib/cli/test_cli.refout.in
+++ b/tests/lib/cli/test_cli.refout.in
@@ -409,7 +409,6 @@ domainname test.domain
!
!
!
-!
end
test# conf t
test(config)# hostname foohost
@@ -425,7 +424,6 @@ domainname test.domain
!
!
!
-!
end
foohost(config)#
end.
diff --git a/tests/lib/cli/test_commands.c b/tests/lib/cli/test_commands.c
index ea84120fc1..9873383fdc 100644
--- a/tests/lib/cli/test_commands.c
+++ b/tests/lib/cli/test_commands.c
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <unistd.h>
+#include "debug.h"
#include "command.h"
#include "memory.h"
#include "vector.h"
@@ -195,7 +196,8 @@ static void test_init(void)
struct cmd_element *cmd;
cmd_init(1);
- nb_init(master, NULL, 0, false);
+ debug_init();
+ nb_init(master, NULL, 0, false, false);
install_node(&bgp_node);
install_node(&rip_node);
diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c
index 321f158668..fdc9e53ca3 100644
--- a/tests/lib/northbound/test_oper_data.c
+++ b/tests/lib/northbound/test_oper_data.c
@@ -7,6 +7,7 @@
#include <zebra.h>
#include <sys/stat.h>
+#include "debug.h"
#include "frrevent.h"
#include "vty.h"
#include "command.h"
@@ -459,7 +460,8 @@ int main(int argc, char **argv)
cmd_hostname_set("test");
vty_init(master, false);
lib_cmd_init();
- nb_init(master, modules, array_size(modules), false);
+ debug_init();
+ nb_init(master, modules, array_size(modules), false, false);
install_element(ENABLE_NODE, &test_rpc_cmd);
diff --git a/tests/lib/test_frrlua.c b/tests/lib/test_frrlua.c
index 2760a273bd..4aa8c8a8c3 100644
--- a/tests/lib/test_frrlua.c
+++ b/tests/lib/test_frrlua.c
@@ -13,6 +13,8 @@ static void test_encode_decode(void)
{
lua_State *L = luaL_newstate();
+ luaL_openlibs(L);
+
int a = 123;
int b = a;
@@ -99,6 +101,20 @@ static void test_encode_decode(void)
lua_decode_sockunion(L, -1, &su_a);
assert(sockunion_cmp(&su_a, &su_b) == 0);
assert(lua_gettop(L) == 0);
+
+ /* Test if built-in functions (string() in this case) are working */
+ const char *result;
+
+ lua_getglobal(L, "string");
+ lua_getfield(L, -1, "upper");
+ lua_pushstring(L, "testas");
+ lua_pcall(L, 1, 1, 0);
+
+ result = lua_tostring(L, -1);
+ assert(strmatch(result, "TESTAS"));
+ lua_pop(L, 1);
+ lua_close(L);
+ /* End of built-in functions test */
}
int main(int argc, char **argv)
diff --git a/tests/lib/test_grpc.cpp b/tests/lib/test_grpc.cpp
index 202313603d..379a8688a7 100644
--- a/tests/lib/test_grpc.cpp
+++ b/tests/lib/test_grpc.cpp
@@ -9,6 +9,7 @@
#include <unistd.h>
#include <zebra.h>
+#include "debug.h"
#include "filter.h"
#include "frr_pthread.h"
#include "libfrr.h"
@@ -79,6 +80,7 @@ static void static_startup(void)
// static struct option_chain *oc;
cmd_init(1);
+ debug_init();
zlog_aux_init("NONE: ", LOG_DEBUG);
zprivs_preinit(&static_privs);
@@ -109,8 +111,7 @@ static void static_startup(void)
static_debug_init();
master = event_master_create(NULL);
- nb_init(master, staticd_yang_modules, array_size(staticd_yang_modules),
- false);
+ nb_init(master, staticd_yang_modules, array_size(staticd_yang_modules), false, false);
static_zebra_init();
vty_init(master, true);
diff --git a/tests/lib/test_ttable.c b/tests/lib/test_ttable.c
index 562ddf9d66..7ac0e3516b 100644
--- a/tests/lib/test_ttable.c
+++ b/tests/lib/test_ttable.c
@@ -20,7 +20,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 1);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* add new row with 1 column, assert that it is not added */
assert(ttable_add_row(tt, "%s", "Garbage") == NULL);
@@ -28,7 +28,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 1);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* add new row, assert that it is added */
assert(ttable_add_row(tt, "%s|%s|%s", "a", "b", "c"));
@@ -36,7 +36,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 2);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* add empty row, assert that it is added */
assert(ttable_add_row(tt, "||"));
@@ -44,7 +44,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 3);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* delete 1st row, assert that it is removed */
ttable_del_row(tt, 0);
@@ -52,7 +52,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 2);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* delete last row, assert that it is removed */
ttable_del_row(tt, 0);
@@ -60,7 +60,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 1);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* delete the remaining row, check dumping an empty table */
ttable_del_row(tt, 0);
@@ -68,7 +68,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 0);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* add new row */
ttable_add_row(tt, "%s|%s||%s|%9d", "slick", "black", "triple", 1337);
@@ -76,7 +76,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 1);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* add bigger row */
ttable_add_row(tt, "%s|%s||%s|%s",
@@ -86,7 +86,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 2);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* insert new row at beginning */
ttable_insert_row(tt, 0, "%s|%s||%d|%lf", "converting", "vegetarians",
@@ -95,7 +95,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 3);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* insert new row at end */
ttable_insert_row(tt, tt->nrows - 1, "%s|%s||%d|%ld", "converting",
@@ -104,7 +104,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 4);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* insert new row at middle */
ttable_insert_row(tt, 1, "%s|%s||%s|%ld", "she", "pioneer", "aki", 1l);
@@ -112,7 +112,7 @@ int main(int argc, char **argv)
assert(tt->nrows == 5);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* set alignment */
ttable_align(tt, 0, 1, 2, 2, LEFT);
@@ -120,14 +120,14 @@ int main(int argc, char **argv)
assert(tt->nrows == 5);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_align(tt, 0, 1, 5, 1, RIGHT);
assert(tt->ncols == 5);
assert(tt->nrows == 5);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* set padding */
ttable_pad(tt, 0, 1, 1, 1, RIGHT, 2);
@@ -135,14 +135,14 @@ int main(int argc, char **argv)
assert(tt->nrows == 5);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_pad(tt, 0, 0, 5, 4, LEFT, 2);
assert(tt->ncols == 5);
assert(tt->nrows == 5);
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* restyle */
tt->style.cell.border.bottom_on = false;
@@ -156,13 +156,13 @@ int main(int argc, char **argv)
ttable_rowseps(tt, 1, TOP, true, '-');
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* column separators for leftmost column */
ttable_colseps(tt, 0, RIGHT, true, '|');
table = ttable_dump(tt, "\n");
fprintf(stdout, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
/* delete table */
ttable_del(tt);
diff --git a/tests/ospf6d/test_lsdb.c b/tests/ospf6d/test_lsdb.c
index f9df73538a..9cec4a3182 100644
--- a/tests/ospf6d/test_lsdb.c
+++ b/tests/ospf6d/test_lsdb.c
@@ -12,6 +12,7 @@
#include "vector.h"
#include "vty.h"
+#include "ospf6d/ospf6_proto.h" /* for struct ospf6_prefix */
#include "ospf6d/ospf6_lsa.h"
#include "ospf6d/ospf6_lsdb.h"
diff --git a/tests/topotests/all_protocol_startup/r1/ip_nht.ref b/tests/topotests/all_protocol_startup/r1/ip_nht.ref
index a2f3d3b0db..2b4363b69e 100644
--- a/tests/topotests/all_protocol_startup/r1/ip_nht.ref
+++ b/tests/topotests/all_protocol_startup/r1/ip_nht.ref
@@ -1,35 +1,35 @@
VRF default:
Resolve via default: on
1.1.1.1
- resolved via static
+ resolved via static, prefix 1.1.1.1/32
is directly connected, r1-eth1 (vrf default), weight 1
Client list: pbr(fd XX)
1.1.1.2
- resolved via static
+ resolved via static, prefix 1.1.1.2/32
is directly connected, r1-eth2 (vrf default), weight 1
Client list: pbr(fd XX)
1.1.1.3
- resolved via static
+ resolved via static, prefix 1.1.1.3/32
is directly connected, r1-eth3 (vrf default), weight 1
Client list: pbr(fd XX)
1.1.1.4
- resolved via static
+ resolved via static, prefix 1.1.1.4/32
is directly connected, r1-eth4 (vrf default), weight 1
Client list: pbr(fd XX)
1.1.1.5
- resolved via static
+ resolved via static, prefix 1.1.1.5/32
is directly connected, r1-eth5 (vrf default), weight 1
Client list: pbr(fd XX)
1.1.1.6
- resolved via static
+ resolved via static, prefix 1.1.1.6/32
is directly connected, r1-eth6 (vrf default), weight 1
Client list: pbr(fd XX)
1.1.1.7
- resolved via static
+ resolved via static, prefix 1.1.1.7/32
is directly connected, r1-eth7 (vrf default), weight 1
Client list: pbr(fd XX)
1.1.1.8
- resolved via static
+ resolved via static, prefix 1.1.1.8/32
is directly connected, r1-eth8 (vrf default), weight 1
Client list: pbr(fd XX)
2.2.2.1
@@ -54,20 +54,20 @@ VRF default:
unresolved
Client list: pbr(fd XX)
192.168.0.2
- resolved via connected
- is directly connected, r1-eth0 (vrf default)
+ resolved via connected, prefix 192.168.0.0/24
+ is directly connected, r1-eth0 (vrf default), weight 1
Client list: static(fd XX)
192.168.0.4
- resolved via connected
- is directly connected, r1-eth0 (vrf default)
+ resolved via connected, prefix 192.168.0.0/24
+ is directly connected, r1-eth0 (vrf default), weight 1
Client list: static(fd XX)
192.168.7.10
- resolved via connected
- is directly connected, r1-eth7 (vrf default)
+ resolved via connected, prefix 192.168.7.0/26
+ is directly connected, r1-eth7 (vrf default), weight 1
Client list: bgp(fd XX)
192.168.7.20(Connected)
- resolved via connected
- is directly connected, r1-eth7 (vrf default)
+ resolved via connected, prefix 192.168.7.0/26
+ is directly connected, r1-eth7 (vrf default), weight 1
Client list: bgp(fd XX)
192.168.161.4
unresolved
diff --git a/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref b/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref
index a4a4aba3d1..33c44780b4 100644
--- a/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref
+++ b/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref
@@ -1,23 +1,23 @@
-C>* 192.168.0.0/24 is directly connected, r1-eth0, XX:XX:XX
-C>* 192.168.1.0/26 is directly connected, r1-eth1, XX:XX:XX
-C>* 192.168.2.0/26 is directly connected, r1-eth2, XX:XX:XX
-C>* 192.168.3.0/26 is directly connected, r1-eth3, XX:XX:XX
-C>* 192.168.4.0/26 is directly connected, r1-eth4, XX:XX:XX
-C>* 192.168.5.0/26 is directly connected, r1-eth5, XX:XX:XX
-C>* 192.168.6.0/26 is directly connected, r1-eth6, XX:XX:XX
-C>* 192.168.7.0/26 is directly connected, r1-eth7, XX:XX:XX
-C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX
-C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX
-L>* 192.168.0.1/32 is directly connected, r1-eth0, XX:XX:XX
-L>* 192.168.1.1/32 is directly connected, r1-eth1, XX:XX:XX
-L>* 192.168.2.1/32 is directly connected, r1-eth2, XX:XX:XX
-L>* 192.168.3.1/32 is directly connected, r1-eth3, XX:XX:XX
-L>* 192.168.4.1/32 is directly connected, r1-eth4, XX:XX:XX
-L>* 192.168.5.1/32 is directly connected, r1-eth5, XX:XX:XX
-L>* 192.168.6.1/32 is directly connected, r1-eth6, XX:XX:XX
-L>* 192.168.7.1/32 is directly connected, r1-eth7, XX:XX:XX
-L>* 192.168.8.1/32 is directly connected, r1-eth8, XX:XX:XX
-L>* 192.168.9.1/32 is directly connected, r1-eth9, XX:XX:XX
+C>* 192.168.0.0/24 is directly connected, r1-eth0, weight 1, XX:XX:XX
+C>* 192.168.1.0/26 is directly connected, r1-eth1, weight 1, XX:XX:XX
+C>* 192.168.2.0/26 is directly connected, r1-eth2, weight 1, XX:XX:XX
+C>* 192.168.3.0/26 is directly connected, r1-eth3, weight 1, XX:XX:XX
+C>* 192.168.4.0/26 is directly connected, r1-eth4, weight 1, XX:XX:XX
+C>* 192.168.5.0/26 is directly connected, r1-eth5, weight 1, XX:XX:XX
+C>* 192.168.6.0/26 is directly connected, r1-eth6, weight 1, XX:XX:XX
+C>* 192.168.7.0/26 is directly connected, r1-eth7, weight 1, XX:XX:XX
+C>* 192.168.8.0/26 is directly connected, r1-eth8, weight 1, XX:XX:XX
+C>* 192.168.9.0/26 is directly connected, r1-eth9, weight 1, XX:XX:XX
+L>* 192.168.0.1/32 is directly connected, r1-eth0, weight 1, XX:XX:XX
+L>* 192.168.1.1/32 is directly connected, r1-eth1, weight 1, XX:XX:XX
+L>* 192.168.2.1/32 is directly connected, r1-eth2, weight 1, XX:XX:XX
+L>* 192.168.3.1/32 is directly connected, r1-eth3, weight 1, XX:XX:XX
+L>* 192.168.4.1/32 is directly connected, r1-eth4, weight 1, XX:XX:XX
+L>* 192.168.5.1/32 is directly connected, r1-eth5, weight 1, XX:XX:XX
+L>* 192.168.6.1/32 is directly connected, r1-eth6, weight 1, XX:XX:XX
+L>* 192.168.7.1/32 is directly connected, r1-eth7, weight 1, XX:XX:XX
+L>* 192.168.8.1/32 is directly connected, r1-eth8, weight 1, XX:XX:XX
+L>* 192.168.9.1/32 is directly connected, r1-eth9, weight 1, XX:XX:XX
O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX
O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, weight 1, XX:XX:XX
S>* 1.1.1.1/32 [1/0] is directly connected, r1-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref
index 100a36a8d6..3f03d6fe93 100644
--- a/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref
+++ b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref
@@ -1,15 +1,15 @@
VRF default:
Resolve via default: on
fc00::2
- resolved via connected
- is directly connected, r1-eth0 (vrf default)
+ resolved via connected, prefix fc00::/64
+ is directly connected, r1-eth0 (vrf default), weight 1
Client list: static(fd XX)
fc00:0:0:8::1000
- resolved via connected
- is directly connected, r1-eth8 (vrf default)
+ resolved via connected, prefix fc00:0:0:8::/64
+ is directly connected, r1-eth8 (vrf default), weight 1
Client list: bgp(fd XX)
fc00:0:0:8::2000(Connected)
- resolved via connected
- is directly connected, r1-eth8 (vrf default)
+ resolved via connected, prefix fc00:0:0:8::/64
+ is directly connected, r1-eth8 (vrf default), weight 1
Client list: bgp(fd XX)
diff --git a/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref b/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref
index a25b53aa21..f5c1d6d7d2 100644
--- a/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref
+++ b/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref
@@ -1,34 +1,34 @@
-C>* fc00:0:0:1::/64 is directly connected, r1-eth1, XX:XX:XX
-C>* fc00:0:0:2::/64 is directly connected, r1-eth2, XX:XX:XX
-C>* fc00:0:0:3::/64 is directly connected, r1-eth3, XX:XX:XX
-C>* fc00:0:0:4::/64 is directly connected, r1-eth4, XX:XX:XX
-C>* fc00:0:0:5::/64 is directly connected, r1-eth5, XX:XX:XX
-C>* fc00:0:0:6::/64 is directly connected, r1-eth6, XX:XX:XX
-C>* fc00:0:0:7::/64 is directly connected, r1-eth7, XX:XX:XX
-C>* fc00:0:0:8::/64 is directly connected, r1-eth8, XX:XX:XX
-C>* fc00:0:0:9::/64 is directly connected, r1-eth9, XX:XX:XX
-C>* fc00::/64 is directly connected, r1-eth0, XX:XX:XX
-C>* fe80::/64 is directly connected, lo, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth0, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth1, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth2, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth3, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth4, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth5, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth6, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX
-C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX
-L>* fc00:0:0:1::1/128 is directly connected, r1-eth1, XX:XX:XX
-L>* fc00:0:0:2::1/128 is directly connected, r1-eth2, XX:XX:XX
-L>* fc00:0:0:3::1/128 is directly connected, r1-eth3, XX:XX:XX
-L>* fc00:0:0:4::1/128 is directly connected, r1-eth4, XX:XX:XX
-L>* fc00:0:0:5::1/128 is directly connected, r1-eth5, XX:XX:XX
-L>* fc00:0:0:6::1/128 is directly connected, r1-eth6, XX:XX:XX
-L>* fc00:0:0:7::1/128 is directly connected, r1-eth7, XX:XX:XX
-L>* fc00:0:0:8::1/128 is directly connected, r1-eth8, XX:XX:XX
-L>* fc00:0:0:9::1/128 is directly connected, r1-eth9, XX:XX:XX
-L>* fc00::1/128 is directly connected, r1-eth0, XX:XX:XX
+C>* fc00:0:0:1::/64 is directly connected, r1-eth1, weight 1, XX:XX:XX
+C>* fc00:0:0:2::/64 is directly connected, r1-eth2, weight 1, XX:XX:XX
+C>* fc00:0:0:3::/64 is directly connected, r1-eth3, weight 1, XX:XX:XX
+C>* fc00:0:0:4::/64 is directly connected, r1-eth4, weight 1, XX:XX:XX
+C>* fc00:0:0:5::/64 is directly connected, r1-eth5, weight 1, XX:XX:XX
+C>* fc00:0:0:6::/64 is directly connected, r1-eth6, weight 1, XX:XX:XX
+C>* fc00:0:0:7::/64 is directly connected, r1-eth7, weight 1, XX:XX:XX
+C>* fc00:0:0:8::/64 is directly connected, r1-eth8, weight 1, XX:XX:XX
+C>* fc00:0:0:9::/64 is directly connected, r1-eth9, weight 1, XX:XX:XX
+C>* fc00::/64 is directly connected, r1-eth0, weight 1, XX:XX:XX
+C>* fe80::/64 is directly connected, lo, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth0, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth1, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth2, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth3, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth4, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth5, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth6, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth7, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth8, weight 1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth9, weight 1, XX:XX:XX
+L>* fc00:0:0:1::1/128 is directly connected, r1-eth1, weight 1, XX:XX:XX
+L>* fc00:0:0:2::1/128 is directly connected, r1-eth2, weight 1, XX:XX:XX
+L>* fc00:0:0:3::1/128 is directly connected, r1-eth3, weight 1, XX:XX:XX
+L>* fc00:0:0:4::1/128 is directly connected, r1-eth4, weight 1, XX:XX:XX
+L>* fc00:0:0:5::1/128 is directly connected, r1-eth5, weight 1, XX:XX:XX
+L>* fc00:0:0:6::1/128 is directly connected, r1-eth6, weight 1, XX:XX:XX
+L>* fc00:0:0:7::1/128 is directly connected, r1-eth7, weight 1, XX:XX:XX
+L>* fc00:0:0:8::1/128 is directly connected, r1-eth8, weight 1, XX:XX:XX
+L>* fc00:0:0:9::1/128 is directly connected, r1-eth9, weight 1, XX:XX:XX
+L>* fc00::1/128 is directly connected, r1-eth0, weight 1, XX:XX:XX
O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, weight 1, XX:XX:XX
S>* 4:5::6:10/128 [1/0] via fc00::2, r1-eth0, weight 1, XX:XX:XX
S>* 4:5::6:11/128 [1/0] via fc00::2, r1-eth0, weight 1, XX:XX:XX
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/h1/zebra.conf b/tests/topotests/bgp_6vpe_ebgp_topo1/h1/zebra.conf
deleted file mode 100644
index 06a23bb0fd..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/h1/zebra.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-ipv6 route fd00:200::/64 fd00:100::2
-interface eth-pe1
- ipv6 address fd00:100::1/64
-!
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/h2/zebra.conf b/tests/topotests/bgp_6vpe_ebgp_topo1/h2/zebra.conf
deleted file mode 100644
index 2dadfc4007..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/h2/zebra.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-ipv6 route fd00:100::/64 fd00:200::5
-interface eth-pe2
- ipv6 address fd00:200::6/64
- ipv6 address fd00:201::6/64
- ipv6 address fd00:300::6/64
- ipv6 address fd00:400::6/64
- ipv6 address fd01:200::6/64
-!
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgp_summary.json b/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgp_summary.json
deleted file mode 100644
index c2100add8e..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgp_summary.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "ipv6Vpn": {
- "routerId": "198.51.100.2",
- "as": 65500,
- "peers": {
- "192.0.2.5": {
- "remoteAs": 65501,
- "state": "Established",
- "peerState": "OK"
- }
- }
- }
-}
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgp_vrf_ipv6.json b/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgp_vrf_ipv6.json
deleted file mode 100644
index c6e776d069..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgp_vrf_ipv6.json
+++ /dev/null
@@ -1,116 +0,0 @@
-{
- "vrfName": "vrf1",
- "routerId": "198.51.100.2",
- "defaultLocPrf": 100,
- "localAS": 65500,
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:100::/64",
- "metric": 0,
- "weight": 32768,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:200::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:200::/64",
- "metric": 0,
- "weight": 0,
- "path": "65501",
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:201::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:201::/64",
- "metric": 0,
- "weight": 0,
- "path": "65501",
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:300::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:300::/64",
- "metric": 0,
- "weight": 0,
- "path": "65501",
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:400::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:400::/64",
- "metric": 0,
- "weight": 0,
- "path": "65501",
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd01:200::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd01:200::/64",
- "metric": 0,
- "weight": 0,
- "path": "65501",
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgpd.conf b/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgpd.conf
deleted file mode 100644
index 26e94d4b97..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgpd.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-!
-!debug bgp zebra
-router bgp 65500
- bgp router-id 198.51.100.2
- no bgp ebgp-requires-policy
- neighbor 192.0.2.5 remote-as 65501
- neighbor 192.0.2.5 capability extended-nexthop
- address-family ipv4 unicast
- no neighbor 192.0.2.5 activate
- exit-address-family
- address-family ipv6 vpn
- neighbor 192.0.2.5 activate
- neighbor 192.0.2.5 route-map rmap in
- exit-address-family
-exit
-router bgp 65500 vrf vrf1
- bgp router-id 198.51.100.2
- address-family ipv6 unicast
- redistribute connected
- label vpn export 101
- rd vpn export 444:1
- rt vpn both 52:100
- export vpn
- import vpn
- exit-address-family
-!
-interface eth-pe2
- mpls bgp forwarding
-!
-route-map rmap permit 1
- set ipv6 next-hop prefer-global
-!
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/ipv6_routes_vrf.json b/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/ipv6_routes_vrf.json
deleted file mode 100644
index 154574963b..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/ipv6_routes_vrf.json
+++ /dev/null
@@ -1,142 +0,0 @@
-{
- "fd00:100::/64": [
- {
- "prefix": "fd00:100::/64",
- "protocol": "connected",
- "vrfName": "vrf1",
- "selected": true,
- "destSelected": true,
- "distance": 0,
- "metric": 0,
- "installed": true,
- "nexthops": [
- {
- "fib": true,
- "directlyConnected": true,
- "interfaceName": "eth-h1",
- "active": true
- }
- ]
- }
- ],
- "fd00:200::/64": [
- {
- "prefix": "fd00:200::/64",
- "protocol": "bgp",
- "vrfName": "vrf1",
- "selected": true,
- "destSelected": true,
- "distance": 20,
- "metric": 0,
- "installed": true,
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "vrf": "default",
- "active": true,
- "labels": [
- 102
- ],
- "weight": 1
- }
- ]
- }
- ],
- "fd00:201::/64": [
- {
- "prefix": "fd00:201::/64",
- "protocol": "bgp",
- "vrfName": "vrf1",
- "selected": true,
- "destSelected": true,
- "distance": 20,
- "metric": 0,
- "installed": true,
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "vrf": "default",
- "active": true,
- "labels": [
- 102
- ],
- "weight": 1
- }
- ]
- }
- ],
- "fd00:300::/64": [
- {
- "prefix": "fd00:300::/64",
- "protocol": "bgp",
- "vrfName": "vrf1",
- "selected": true,
- "destSelected": true,
- "distance": 20,
- "metric": 0,
- "installed": true,
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "vrf": "default",
- "active": true,
- "labels": [
- 102
- ],
- "weight": 1
- }
- ]
- }
- ],
- "fd00:400::/64": [
- {
- "prefix": "fd00:400::/64",
- "protocol": "bgp",
- "vrfName": "vrf1",
- "selected": true,
- "destSelected": true,
- "distance": 20,
- "metric": 0,
- "installed": true,
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "vrf": "default",
- "active": true,
- "labels": [
- 102
- ],
- "weight": 1
- }
- ]
- }
- ],
- "fd01:200::/64": [
- {
- "prefix": "fd01:200::/64",
- "protocol": "bgp",
- "vrfName": "vrf1",
- "selected": true,
- "destSelected": true,
- "distance": 20,
- "metric": 0,
- "installed": true,
- "nexthops": [
- {
- "ip": "::ffff:c000:205",
- "afi": "ipv6",
- "vrf": "default",
- "active": true,
- "labels": [
- 102
- ],
- "weight": 1
- }
- ]
- }
- ]
-}
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/isisd.conf b/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/isisd.conf
deleted file mode 100644
index 61f2fe7def..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/isisd.conf
+++ /dev/null
@@ -1,23 +0,0 @@
-!
-interface lo
- ip router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
-!
-interface eth-pe2
- ip router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
-!
-router isis 1
- net 49.0000.0007.e901.2222.00
- is-type level-1
- lsp-gen-interval 1
- mpls-te on
- mpls-te router-address 198.51.100.2
- segment-routing on
- segment-routing node-msd 8
- segment-routing global-block 1000 10000 local-block 30000 30999
- segment-routing prefix 198.51.100.2/32 index 22
-!
-
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/zebra.conf b/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/zebra.conf
deleted file mode 100644
index 7ddd98f6e7..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe1/zebra.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-!
-interface eth-h1
- ipv6 address fd00:100::2/64
-!
-interface eth-pe2
- ip address 192.0.2.2/24
- ipv6 address ::ffff:192.0.2.2/120
-!
-interface lo
- ip address 198.51.100.2/32
-!
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgp_summary.json b/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgp_summary.json
deleted file mode 100644
index d74079498e..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgp_summary.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "ipv6Vpn": {
- "routerId": "198.51.100.5",
- "as": 65501,
- "peers": {
- "192.0.2.2": {
- "remoteAs": 65500,
- "state": "Established",
- "peerState": "OK"
- }
- }
- }
-}
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgp_vrf_ipv6.json b/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgp_vrf_ipv6.json
deleted file mode 100644
index ec42999e8a..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgp_vrf_ipv6.json
+++ /dev/null
@@ -1,116 +0,0 @@
-{
- "vrfName": "vrf1",
- "routerId": "198.51.100.5",
- "defaultLocPrf": 100,
- "localAS": 65501,
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:100::/64",
- "metric": 0,
- "weight": 0,
- "path": "65500",
- "nexthops": [
- {
- "ip": "::ffff:c000:202",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:200::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:200::/64",
- "metric": 0,
- "weight": 32768,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:201::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:201::/64",
- "metric": 0,
- "weight": 32768,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:300::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:300::/64",
- "metric": 0,
- "weight": 32768,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:400::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd00:400::/64",
- "metric": 0,
- "weight": 32768,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd01:200::/64": [
- {
- "valid": true,
- "bestpath": true,
- "network": "fd01:200::/64",
- "metric": 0,
- "weight": 32768,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgpd.conf b/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgpd.conf
deleted file mode 100644
index 03b63af90f..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/bgpd.conf
+++ /dev/null
@@ -1,31 +0,0 @@
-!
-router bgp 65501
- bgp router-id 198.51.100.5
- no bgp ebgp-requires-policy
- neighbor 192.0.2.2 remote-as 65500
- neighbor 192.0.2.2 capability extended-nexthop
- address-family ipv4 unicast
- no neighbor 192.0.2.2 activate
- exit-address-family
- address-family ipv6 vpn
- neighbor 192.0.2.2 activate
- neighbor 192.0.2.2 route-map rmap in
- exit-address-family
-exit
-router bgp 65501 vrf vrf1
- bgp router-id 198.51.100.5
- address-family ipv6 unicast
- redistribute connected
- label vpn export 102
- rd vpn export 444:2
- rt vpn both 52:100
- export vpn
- import vpn
-exit-address-family
-!
-interface eth-pe1
- mpls bgp forwarding
-!
-route-map rmap permit 1
- set ipv6 next-hop prefer-global
-! \ No newline at end of file
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/zebra.conf b/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/zebra.conf
deleted file mode 100644
index bf20638684..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/zebra.conf
+++ /dev/null
@@ -1,15 +0,0 @@
-!
-interface eth-h2
- ipv6 address fd00:200::5/64
- ipv6 address fd00:201::5/64
- ipv6 address fd00:300::5/64
- ipv6 address fd00:400::5/64
- ipv6 address fd01:200::5/64
-!
-interface eth-pe1
- ip address 192.0.2.5/24
- ipv6 address ::ffff:192.0.2.5/120
-!
-interface lo
- ip address 198.51.100.5/32
-!
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py b/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py
deleted file mode 100644
index 477cfa206b..0000000000
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py
+++ /dev/null
@@ -1,178 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: ISC
-
-#
-# Copyright (c) 2023 by 6WIND
-#
-
-"""
-Test the FRR BGP 6VPE functionality
-"""
-
-import os
-import sys
-import json
-from functools import partial
-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
-from lib.checkping import check_ping
-
-pytestmark = [pytest.mark.bgpd, pytest.mark.isisd]
-
-
-def build_topo(tgen):
- """
- +---+ +---+ +---+ +---+
- | h1|----|pe1|----|pe2|----| h2|
- +---+ +---+ +---+ +---+
- """
-
- def connect_routers(tgen, left, right):
- pe = None
- host = None
- for rname in [left, right]:
- if rname not in tgen.routers().keys():
- tgen.add_router(rname)
- if "pe" in rname:
- pe = tgen.gears[rname]
- if "h" in rname:
- host = tgen.gears[rname]
-
- switch = tgen.add_switch("s-{}-{}".format(left, right))
- switch.add_link(tgen.gears[left], nodeif="eth-{}".format(right))
- switch.add_link(tgen.gears[right], nodeif="eth-{}".format(left))
-
- if pe and host:
- pe.cmd("ip link add vrf1 type vrf table 10")
- pe.cmd("ip link set vrf1 up")
- pe.cmd("ip link set dev eth-{} master vrf1".format(host.name))
-
- if "p" in left and "p" in right:
- # PE <-> P or P <-> P
- tgen.gears[left].run("sysctl -w net.mpls.conf.eth-{}.input=1".format(right))
- tgen.gears[right].run("sysctl -w net.mpls.conf.eth-{}.input=1".format(left))
-
- connect_routers(tgen, "h1", "pe1")
- connect_routers(tgen, "pe1", "pe2")
- connect_routers(tgen, "pe2", "h2")
-
-
-def setup_module(mod):
- "Sets up the pytest environment"
-
- tgen = Topogen(build_topo, mod.__name__)
- tgen.start_topology()
- logger.info("setup_module")
-
- for rname, router in tgen.routers().items():
- router.load_config(
- TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
- )
- if "h" in rname:
- # hosts
- continue
-
- router.load_config(
- TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
- )
-
- router.load_config(
- TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
- )
-
- # Initialize all routers.
- tgen.start_router()
-
-
-def teardown_module(_mod):
- "Teardown the pytest environment"
- tgen = get_topogen()
- tgen.stop_topology()
-
-
-def test_bgp_convergence():
- "Assert that BGP is converging."
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- logger.info("waiting for bgp peers to go up")
-
- router_list = ["pe1", "pe2"]
-
- for name in router_list:
- router = tgen.gears[name]
- ref_file = "{}/{}/bgp_summary.json".format(CWD, router.name)
- expected = json.loads(open(ref_file).read())
- test_func = partial(
- topotest.router_json_cmp, router, "show bgp summary json", expected
- )
- _, res = topotest.run_and_expect(test_func, None, count=90, wait=1)
- assertmsg = "{}: bgp did not converge".format(router.name)
- assert res is None, assertmsg
-
-
-def test_bgp_ipv6_vpn():
- "Assert that BGP is exchanging BGP route."
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- logger.info("waiting for bgp peers exchanging UPDATES")
-
- router_list = ["pe1", "pe2"]
-
- for name in router_list:
- router = tgen.gears[name]
- ref_file = "{}/{}/bgp_vrf_ipv6.json".format(CWD, router.name)
- expected = json.loads(open(ref_file).read())
- test_func = partial(
- topotest.router_json_cmp,
- router,
- "show bgp vrf vrf1 ipv6 unicast json",
- expected,
- )
- _, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
- assertmsg = "{}: BGP UPDATE exchange failure".format(router.name)
- assert res is None, assertmsg
-
-
-def test_zebra_ipv6_installed():
- "Assert that routes are installed."
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
- pe1 = tgen.gears["pe1"]
- logger.info("check ipv6 routes installed on pe1")
-
- ref_file = "{}/{}/ipv6_routes_vrf.json".format(CWD, pe1.name)
- expected = json.loads(open(ref_file).read())
- test_func = partial(
- topotest.router_json_cmp, pe1, "show ipv6 route vrf vrf1 json", expected
- )
- _, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
- assertmsg = "{}: Zebra Installation failure on vrf vrf1".format(pe1.name)
- assert res is None, assertmsg
-
-
-def test_bgp_ping6_ok():
- "Check that h1 pings h2"
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- check_ping("h1", "fd00:200::6", True, 5, 1)
-
-
-if __name__ == "__main__":
- args = ["-s"] + sys.argv[1:]
- sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
index c97fc5f0eb..5662e5935b 100644
--- a/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
+++ b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
@@ -831,7 +831,6 @@ def test_bgp_with_loopback_interface(request):
for bgp_neighbor in topo["routers"][routerN]["bgp"]["address_family"]["ipv4"][
"unicast"
]["neighbor"].keys():
-
# Adding ['source_link'] = 'lo' key:value pair
topo["routers"][routerN]["bgp"]["address_family"]["ipv4"]["unicast"][
"neighbor"
@@ -876,294 +875,6 @@ def test_bgp_with_loopback_interface(request):
write_test_footer(tc_name)
-def test_bgp_with_loopback_with_same_subnet_p1(request):
- """
- Verify routes not installed in zebra when /32 routes received
- with loopback BGP session subnet
- """
-
- tgen = get_topogen()
- if BGP_CONVERGENCE is not True:
- pytest.skip("skipped because of BGP Convergence failure")
-
- # test case name
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Creating configuration from JSON
- reset_config_on_routers(tgen)
- step("Delete BGP seesion created initially")
- input_dict_r1 = {
- "r1": {"bgp": {"delete": True}},
- "r2": {"bgp": {"delete": True}},
- "r3": {"bgp": {"delete": True}},
- "r4": {"bgp": {"delete": True}},
- }
- result = create_router_bgp(tgen, topo, input_dict_r1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
-
- step("Create BGP session over loop address")
- topo_modify = deepcopy(topo)
-
- for routerN in sorted(topo["routers"].keys()):
- for addr_type in ADDR_TYPES:
- for bgp_neighbor in topo_modify["routers"][routerN]["bgp"][
- "address_family"
- ][addr_type]["unicast"]["neighbor"].keys():
-
- # Adding ['source_link'] = 'lo' key:value pair
- topo_modify["routers"][routerN]["bgp"]["address_family"][addr_type][
- "unicast"
- ]["neighbor"][bgp_neighbor]["dest_link"] = {
- "lo": {"source_link": "lo", "ebgp_multihop": 2}
- }
-
- result = create_router_bgp(tgen, topo_modify["routers"])
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
-
- step("Disable IPv6 BGP nbr from ipv4 address family")
- raw_config = {
- "r1": {
- "raw_config": [
- "router bgp {}".format(topo["routers"]["r1"]["bgp"]["local_as"]),
- "address-family ipv4 unicast",
- "no neighbor {} activate".format(
- topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
- ),
- "no neighbor {} activate".format(
- topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
- ),
- ]
- },
- "r2": {
- "raw_config": [
- "router bgp {}".format(topo["routers"]["r2"]["bgp"]["local_as"]),
- "address-family ipv4 unicast",
- "no neighbor {} activate".format(
- topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0]
- ),
- "no neighbor {} activate".format(
- topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
- ),
- ]
- },
- "r3": {
- "raw_config": [
- "router bgp {}".format(topo["routers"]["r3"]["bgp"]["local_as"]),
- "address-family ipv4 unicast",
- "no neighbor {} activate".format(
- topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0]
- ),
- "no neighbor {} activate".format(
- topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
- ),
- "no neighbor {} activate".format(
- topo["routers"]["r4"]["links"]["lo"]["ipv6"].split("/")[0]
- ),
- ]
- },
- "r4": {
- "raw_config": [
- "router bgp {}".format(topo["routers"]["r4"]["bgp"]["local_as"]),
- "address-family ipv4 unicast",
- "no neighbor {} activate".format(
- topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
- ),
- ]
- },
- }
-
- step("Configure kernel routes")
- result = apply_raw_config(tgen, raw_config)
- assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
-
- r1_ipv4_lo = topo["routers"]["r1"]["links"]["lo"]["ipv4"]
- r1_ipv6_lo = topo["routers"]["r1"]["links"]["lo"]["ipv6"]
- r2_ipv4_lo = topo["routers"]["r2"]["links"]["lo"]["ipv4"]
- r2_ipv6_lo = topo["routers"]["r2"]["links"]["lo"]["ipv6"]
- r3_ipv4_lo = topo["routers"]["r3"]["links"]["lo"]["ipv4"]
- r3_ipv6_lo = topo["routers"]["r3"]["links"]["lo"]["ipv6"]
- r4_ipv4_lo = topo["routers"]["r4"]["links"]["lo"]["ipv4"]
- r4_ipv6_lo = topo["routers"]["r4"]["links"]["lo"]["ipv6"]
-
- r1_r2 = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0]
- r2_r1 = topo["routers"]["r2"]["links"]["r1"]["ipv6"].split("/")[0]
- r1_r3 = topo["routers"]["r1"]["links"]["r3"]["ipv6"].split("/")[0]
- r3_r1 = topo["routers"]["r3"]["links"]["r1"]["ipv6"].split("/")[0]
- r2_r3 = topo["routers"]["r2"]["links"]["r3"]["ipv6"].split("/")[0]
- r3_r2 = topo["routers"]["r3"]["links"]["r2"]["ipv6"].split("/")[0]
- r3_r4 = topo["routers"]["r3"]["links"]["r4"]["ipv6"].split("/")[0]
- r4_r3 = topo["routers"]["r4"]["links"]["r3"]["ipv6"].split("/")[0]
-
- r1_r2_ipv4 = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0]
- r2_r1_ipv4 = topo["routers"]["r2"]["links"]["r1"]["ipv4"].split("/")[0]
- r1_r3_ipv4 = topo["routers"]["r1"]["links"]["r3"]["ipv4"].split("/")[0]
- r3_r1_ipv4 = topo["routers"]["r3"]["links"]["r1"]["ipv4"].split("/")[0]
- r2_r3_ipv4 = topo["routers"]["r2"]["links"]["r3"]["ipv4"].split("/")[0]
- r3_r2_ipv4 = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0]
- r3_r4_ipv4 = topo["routers"]["r3"]["links"]["r4"]["ipv4"].split("/")[0]
- r4_r3_ipv4 = topo["routers"]["r4"]["links"]["r3"]["ipv4"].split("/")[0]
-
- r1_r2_intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
- r2_r1_intf = topo["routers"]["r2"]["links"]["r1"]["interface"]
- r1_r3_intf = topo["routers"]["r1"]["links"]["r3"]["interface"]
- r3_r1_intf = topo["routers"]["r3"]["links"]["r1"]["interface"]
- r2_r3_intf = topo["routers"]["r2"]["links"]["r3"]["interface"]
- r3_r2_intf = topo["routers"]["r3"]["links"]["r2"]["interface"]
- r3_r4_intf = topo["routers"]["r3"]["links"]["r4"]["interface"]
- r4_r3_intf = topo["routers"]["r4"]["links"]["r3"]["interface"]
-
- ipv4_list = [
- ("r1", r1_r2_intf, r2_ipv4_loopback),
- ("r1", r1_r3_intf, r3_ipv4_loopback),
- ("r2", r2_r1_intf, r1_ipv4_loopback),
- ("r2", r2_r3_intf, r3_ipv4_loopback),
- ("r3", r3_r1_intf, r1_ipv4_loopback),
- ("r3", r3_r2_intf, r2_ipv4_loopback),
- ("r3", r3_r4_intf, r4_ipv4_loopback),
- ("r4", r4_r3_intf, r3_ipv4_loopback),
- ]
-
- ipv6_list = [
- ("r1", r1_r2_intf, r2_ipv6_loopback, r2_r1),
- ("r1", r1_r3_intf, r3_ipv6_loopback, r3_r1),
- ("r2", r2_r1_intf, r1_ipv6_loopback, r1_r2),
- ("r2", r2_r3_intf, r3_ipv6_loopback, r3_r2),
- ("r3", r3_r1_intf, r1_ipv6_loopback, r1_r3),
- ("r3", r3_r2_intf, r2_ipv6_loopback, r2_r3),
- ("r3", r3_r4_intf, r4_ipv6_loopback, r4_r3),
- ("r4", r4_r3_intf, r3_ipv6_loopback, r3_r4),
- ]
-
- for dut, intf, loop_addr in ipv4_list:
- result = addKernelRoute(tgen, dut, intf, loop_addr)
- assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result)
-
- for dut, intf, loop_addr, next_hop in ipv6_list:
- result = addKernelRoute(tgen, dut, intf, loop_addr, next_hop)
- assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result)
-
- step("Configure static routes")
-
- input_dict = {
- "r1": {
- "static_routes": [
- {"network": r2_ipv4_loopback, "next_hop": r2_r1_ipv4},
- {"network": r3_ipv4_loopback, "next_hop": r3_r1_ipv4},
- {"network": r2_ipv6_loopback, "next_hop": r2_r1},
- {"network": r3_ipv6_loopback, "next_hop": r3_r1},
- ]
- },
- "r2": {
- "static_routes": [
- {"network": r1_ipv4_loopback, "next_hop": r1_r2_ipv4},
- {"network": r3_ipv4_loopback, "next_hop": r3_r2_ipv4},
- {"network": r1_ipv6_loopback, "next_hop": r1_r2},
- {"network": r3_ipv6_loopback, "next_hop": r3_r2},
- ]
- },
- "r3": {
- "static_routes": [
- {"network": r1_ipv4_loopback, "next_hop": r1_r3_ipv4},
- {"network": r2_ipv4_loopback, "next_hop": r2_r3_ipv4},
- {"network": r4_ipv4_loopback, "next_hop": r4_r3_ipv4},
- {"network": r1_ipv6_loopback, "next_hop": r1_r3},
- {"network": r2_ipv6_loopback, "next_hop": r2_r3},
- {"network": r4_ipv6_loopback, "next_hop": r4_r3},
- ]
- },
- "r4": {
- "static_routes": [
- {"network": r3_ipv4_loopback, "next_hop": r3_r4_ipv4},
- {"network": r3_ipv6_loopback, "next_hop": r3_r4},
- ]
- },
- }
- result = create_static_routes(tgen, input_dict)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("Verify BGP session convergence")
-
- result = verify_bgp_convergence(tgen, topo_modify)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("Configure redistribute connected on R2 and R4")
- input_dict_1 = {
- "r2": {
- "bgp": {
- "address_family": {
- "ipv4": {
- "unicast": {"redistribute": [{"redist_type": "connected"}]}
- },
- "ipv6": {
- "unicast": {"redistribute": [{"redist_type": "connected"}]}
- },
- }
- }
- },
- "r4": {
- "bgp": {
- "address_family": {
- "ipv4": {
- "unicast": {"redistribute": [{"redist_type": "connected"}]}
- },
- "ipv6": {
- "unicast": {"redistribute": [{"redist_type": "connected"}]}
- },
- }
- }
- },
- }
-
- result = create_router_bgp(tgen, topo, input_dict_1)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("Verify Ipv4 and Ipv6 network installed in R1 RIB but not in FIB")
- input_dict_r1 = {
- "r1": {
- "static_routes": [
- {"network": "1.0.2.17/32"},
- {"network": "2001:db8:f::2:17/128"},
- ]
- }
- }
-
- dut = "r1"
- protocol = "bgp"
- for addr_type in ADDR_TYPES:
- result = verify_fib_routes(
- tgen, addr_type, dut, input_dict_r1, expected=False
- ) # pylint: disable=E1123
- assert result is not True, (
- "Testcase {} : Failed \n "
- "Expected: Routes should not be present in {} FIB \n "
- "Found: {}".format(tc_name, dut, result)
- )
-
- step("Verify Ipv4 and Ipv6 network installed in r3 RIB but not in FIB")
- input_dict_r3 = {
- "r3": {
- "static_routes": [
- {"network": "1.0.4.17/32"},
- {"network": "2001:db8:f::4:17/128"},
- ]
- }
- }
- dut = "r3"
- protocol = "bgp"
- for addr_type in ADDR_TYPES:
- result = verify_fib_routes(
- tgen, addr_type, dut, input_dict_r1, expected=False
- ) # pylint: disable=E1123
- assert result is not True, (
- "Testcase {} : Failed \n "
- "Expected: Routes should not be present in {} FIB \n "
- "Found: {}".format(tc_name, dut, result)
- )
-
- write_test_footer(tc_name)
-
-
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py
index f4f874f942..bcdd987889 100644
--- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py
+++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py
@@ -266,21 +266,21 @@ def verify_the_uptime(time_stamp_before, time_stamp_after, incremented=None):
if incremented == True:
if uptime_before < uptime_after:
logger.info(
- " The Uptime [{}] is incremented than [{}].......PASSED ".format(
+ " The Uptime before [{}] is less than [{}].......PASSED ".format(
time_stamp_before, time_stamp_after
)
)
return True
else:
logger.error(
- " The Uptime [{}] is expected to be incremented than [{}].......FAILED ".format(
+ " The Uptime before [{}] is greater than the uptime after [{}].......FAILED ".format(
time_stamp_before, time_stamp_after
)
)
return False
else:
logger.info(
- " The Uptime [{}] is not incremented than [{}] ".format(
+ " The Uptime before [{}] the same as after [{}] ".format(
time_stamp_before, time_stamp_after
)
)
@@ -1027,7 +1027,7 @@ def test_verify_bgp_default_originate_with_default_static_route_p1(request):
result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
- step("Taking uptime snapshot before removing redisctribute static ")
+ step("Taking uptime snapshot before removing redistribute static")
uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
sleep(1)
@@ -1074,6 +1074,7 @@ def test_verify_bgp_default_originate_with_default_static_route_p1(request):
)
assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ step("Now look that the route is not pointed at link2")
result = verify_rib_default_route(
tgen,
topo,
@@ -1093,7 +1094,7 @@ def test_verify_bgp_default_originate_with_default_static_route_p1(request):
)
assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
- step("Taking uptime snapshot before removing redisctribute static ")
+ step("Taking uptime snapshot after removing redistribute static")
uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py
index eca41e3b9e..73b2c19659 100644
--- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py
+++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py
@@ -16,6 +16,7 @@ import sys
import time
import pytest
from lib.topolog import logger
+import json
# pylint: disable=C0413
# Import topogen and topotest helpers
@@ -54,6 +55,7 @@ from lib.common_config import (
reset_config_on_routers,
create_static_routes,
check_router_status,
+ retry,
)
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
@@ -657,7 +659,7 @@ def test_verify_default_originate_after_BGP_and_FRR_restart_p2(request):
)
step(
- " Configure default originate with route-map RMv4 and RMv6 for IPv4 and IPv6 bgp neighbors on R1 ( R1-R2) "
+ "Configure default originate with route-map RMv4 and RMv6 for IPv4 and IPv6 bgp neighbors on R1 ( R1-R2) "
)
local_as = get_dut_as_number(tgen, dut="r1")
default_originate_config = {
@@ -775,7 +777,7 @@ def test_verify_default_originate_after_BGP_and_FRR_restart_p2(request):
tc_name, result
)
- step(" Configure default-originate on R3 for R3 to R2 IPv4 and IPv6 BGP neighbors ")
+ step("Configure default-originate on R3 for R3 to R2 IPv4 and IPv6 BGP neighbors ")
local_as = get_dut_as_number(tgen, dut="r3")
default_originate_config = {
"r3": {
@@ -831,7 +833,7 @@ def test_verify_default_originate_after_BGP_and_FRR_restart_p2(request):
dut="r2",
routes=DEFAULT_ROUTES,
expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
- expected=False,
+ expected=True,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
@@ -890,7 +892,31 @@ def test_verify_default_originate_after_BGP_and_FRR_restart_p2(request):
tc_name, result
)
- step(" BGP Daemon restart operation")
+ # Allow for verification of the table version
+ # as that restarting bgp on one router will cause
+ # r2's version number should go up as that r1
+ # is not directly connected to r2
+ # where?
+ @retry(retry_timeout=60)
+ def verify_version_upgrade(dut, version):
+ dut_new_ipv4_uni_json = json.loads(dut.vtysh_cmd("show bgp ipv4 uni json"))
+
+ logger.info(
+ "New version: {} comparing to old {}".format(
+ dut_new_ipv4_uni_json["tableVersion"], version
+ )
+ )
+ if version >= dut_new_ipv4_uni_json["tableVersion"]:
+ return False
+
+ return True
+
+ r2 = tgen.gears["r2"]
+
+ r2_bgp_ipv4_uni_json = json.loads(r2.vtysh_cmd("show bgp ipv4 uni json"))
+ curr_version = r2_bgp_ipv4_uni_json["tableVersion"]
+
+ step("BGP Daemon restart operation")
routers = ["r1", "r2"]
for dut in routers:
step(
@@ -898,41 +924,86 @@ def test_verify_default_originate_after_BGP_and_FRR_restart_p2(request):
dut
)
)
+
kill_router_daemons(tgen, dut, ["bgpd"])
+ # Let's ensure that r2's version has upgraded and then
+ # let's check that the default route goes through
+ # r3's connection.
+ if dut == "r1":
+ step("Ensure that r2 prefers r3's default route at this point in time")
+ verify_version_upgrade(r2, curr_version)
+ # write code to ensure r1 neighbor is down
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Failed \n IBGP default route should be prefeered over EBGP \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
start_router_daemons(tgen, dut, ["bgpd"])
- step("After restarting the BGP daomon Verify the default originate ")
- DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
- result = verify_fib_default_route(
- tgen,
- topo,
- dut="r2",
- routes=DEFAULT_ROUTES,
- expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
- expected=False,
- )
- assert (
- result is not True
- ), "Testcase {} : Failed \n IBGP default route should be prefeered over EBGP \n Error: {}".format(
- tc_name, result
- )
+ if dut == "r2":
- result = verify_rib_default_route(
- tgen,
- topo,
- dut="r2",
- routes=DEFAULT_ROUTES,
- expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
- expected=True,
- )
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result
- )
+ @retry(60)
+ def check_pfx_received_sent(dut):
+ output = json.loads(dut.vtysh_cmd("show bgp ipv4 uni summ json"))
+
+ logger.info(output)
+ if output["peerCount"] != 2:
+ logger.info(output["peerCount"])
+ logger.info("pc")
+ return False
+
+ if output["peers"]["192.168.1.1"]["state"] != "Established":
+ logger.info("Not Established 192.168.1.1")
+ return False
+
+ if output["peers"]["192.168.2.2"]["state"] != "Established":
+ logger.info("Not established 192.168.2.2")
+ return False
+ if output["peers"]["192.168.1.1"]["pfxRcd"] != 6:
+ logger.info("1.1 prxRcd")
+ return False
+
+ if output["peers"]["192.168.1.1"]["pfxSnt"] != 3:
+ logger.info("1.1 pfxsent")
+ return False
+
+ if output["peers"]["192.168.2.2"]["pfxRcd"] != 4:
+ logger.info("2.2 pfxRcd")
+ return False
+
+ if output["peers"]["192.168.2.2"]["pfxSnt"] != 9:
+ logger.info("2.2 pfxsnt")
+ return False
+
+ return True
+
+ check_pfx_received_sent(r2)
step(
"Verify the default route from R1 is is recieved both on RIB and FIB on R2"
)
-
DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
result = verify_fib_default_route(
tgen,
@@ -940,7 +1011,7 @@ def test_verify_default_originate_after_BGP_and_FRR_restart_p2(request):
dut="r2",
routes=DEFAULT_ROUTES,
expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
- expected=False,
+ expected=True,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
@@ -1003,7 +1074,7 @@ def test_verify_default_originate_after_BGP_and_FRR_restart_p2(request):
tc_name, result
)
- step(" Restarting FRR routers operation")
+ step("Restarting FRR routers operation")
"""
NOTE : Verify that iBGP default route is preffered over eBGP default route
"""
diff --git a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py
index 1506b02e5d..905c3e2b66 100644
--- a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py
+++ b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py
@@ -546,13 +546,7 @@ def test_verify_default_originate_route_with_non_default_VRF_p1(request):
tc_name, result
)
- result = verify_rib(
- tgen,
- addr_type,
- "r2",
- static_routes_input,
- next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type],
- )
+ result = verify_rib(tgen, addr_type, "r2", static_routes_input)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/__init__.py b/tests/topotests/bgp_dual_as/__init__.py
index e69de29bb2..e69de29bb2 100644
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/__init__.py
+++ b/tests/topotests/bgp_dual_as/__init__.py
diff --git a/tests/topotests/bgp_dual_as/r1/frr.conf b/tests/topotests/bgp_dual_as/r1/frr.conf
new file mode 100644
index 0000000000..9dcfe05d69
--- /dev/null
+++ b/tests/topotests/bgp_dual_as/r1/frr.conf
@@ -0,0 +1,11 @@
+!
+interface r1-eth0
+ ip address 10.0.0.1/24
+!
+router bgp 65000
+ no bgp ebgp-requires-policy
+ neighbor 10.0.0.2 remote-as 65002
+ neighbor 10.0.0.2 local-as 65001 no-prepend replace-as dual-as
+ neighbor 10.0.0.2 timers 3 10
+ neighbor 10.0.0.2 timers connect 1
+!
diff --git a/tests/topotests/bgp_dual_as/r2/frr.conf b/tests/topotests/bgp_dual_as/r2/frr.conf
new file mode 100644
index 0000000000..a901d49a53
--- /dev/null
+++ b/tests/topotests/bgp_dual_as/r2/frr.conf
@@ -0,0 +1,10 @@
+!
+interface r2-eth0
+ ip address 10.0.0.2/24
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 10.0.0.1 remote-as 65000
+ neighbor 10.0.0.1 timers 3 10
+ neighbor 10.0.0.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_dual_as/test_bgp_dual_as.py b/tests/topotests/bgp_dual_as/test_bgp_dual_as.py
new file mode 100644
index 0000000000..b202d7819b
--- /dev/null
+++ b/tests/topotests/bgp_dual_as/test_bgp_dual_as.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+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, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ r1 = tgen.add_router("r1")
+ r2 = tgen.add_router("r2")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(r1)
+ switch.add_link(r2)
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ for _, (rname, router) in enumerate(tgen.routers().items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_dual_as():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ def _bgp_converge_65000():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 summary json"))
+ expected = {
+ "ipv4Unicast": {
+ "as": 65000,
+ "peers": {
+ "10.0.0.2": {
+ "hostname": "r2",
+ "remoteAs": 65002,
+ "localAs": 65000,
+ "state": "Established",
+ "peerState": "OK",
+ }
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge_65000)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't establish BGP session using global AS 65000"
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_features/r1/ip_route.json b/tests/topotests/bgp_features/r1/ip_route.json
index 34c58033ad..3f95e27078 100644
--- a/tests/topotests/bgp_features/r1/ip_route.json
+++ b/tests/topotests/bgp_features/r1/ip_route.json
@@ -29,7 +29,7 @@
"metric":0,
"nexthops":[
{
- "flags":1,
+ "flags":3,
"directlyConnected":true,
"interfaceName":"lo",
"active":true,
@@ -109,7 +109,7 @@
"table":254,
"nexthops":[
{
- "flags":1,
+ "flags":3,
"directlyConnected":true,
"interfaceName":"r1-eth1",
"active":true,
@@ -175,7 +175,7 @@
"metric":10,
"nexthops":[
{
- "flags":1,
+ "flags":3,
"directlyConnected":true,
"interfaceName":"r1-eth2",
"active":true,
@@ -210,7 +210,7 @@
"metric":10,
"nexthops":[
{
- "flags":1,
+ "flags":3,
"directlyConnected":true,
"interfaceName":"r1-eth0",
"active":true,
diff --git a/tests/topotests/bgp_features/r1/ip_route_norib.json b/tests/topotests/bgp_features/r1/ip_route_norib.json
index f6536d1e9f..b8e0fc2883 100644
--- a/tests/topotests/bgp_features/r1/ip_route_norib.json
+++ b/tests/topotests/bgp_features/r1/ip_route_norib.json
@@ -7,7 +7,7 @@
"metric":0,
"nexthops":[
{
- "flags":1,
+ "flags":3,
"directlyConnected":true,
"interfaceName":"lo",
"active":true,
@@ -86,7 +86,7 @@
"metric":10,
"nexthops":[
{
- "flags":1,
+ "flags":3,
"directlyConnected":true,
"interfaceName":"r1-eth1",
"active":true,
@@ -152,7 +152,7 @@
"metric":10,
"nexthops":[
{
- "flags":1,
+ "flags":3,
"directlyConnected":true,
"interfaceName":"r1-eth2",
"active":true,
@@ -187,7 +187,7 @@
"metric":10,
"nexthops":[
{
- "flags":1,
+ "flags":3,
"directlyConnected":true,
"interfaceName":"r1-eth0",
"active":true,
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py
index 60d959fd1e..5347604250 100755
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py
@@ -84,6 +84,9 @@ def test_check_scale_up():
CliOnFail = None
# For debugging, uncomment the next line
# CliOnFail = 'tgen.mininet_cli'
+ # Skip test on 32bit platforms (limited memory)
+ if sys.maxsize <= 2**32:
+ pytest.skip("skipped because of limited memory on 32bit platforms")
CheckFunc = "ltemplateVersionCheck('4.1', iproute2='4.9')"
# uncomment next line to start cli *before* script is run
# CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True, iproute2=\'4.9\')'
@@ -94,6 +97,9 @@ def test_check_scale_down():
CliOnFail = None
# For debugging, uncomment the next line
# CliOnFail = 'tgen.mininet_cli'
+ # Skip test on 32bit platforms (limited memory)
+ if sys.maxsize <= 2**32:
+ pytest.skip("skipped because of limited memory on 32bit platforms")
CheckFunc = "ltemplateVersionCheck('4.1', iproute2='4.9')"
# uncomment next line to start cli *before* script is run
# CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True, iproute2=\'4.9\')'
diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json
index bb50bc96d9..5773d86065 100644
--- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json
+++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json
@@ -7,12 +7,12 @@
{
"fib":true,
"ip":"11.1.1.6",
- "weight":85
+ "weight":84
},
{
"fib":true,
"ip":"11.1.1.2",
- "weight":255
+ "weight":254
}
]
}
diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json
index 57726ce46c..a65eb8f591 100644
--- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json
+++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json
@@ -12,7 +12,7 @@
{
"fib":true,
"ip":"11.1.1.2",
- "weight":255
+ "weight":254
}
]
}
diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json
index f2368dfdc5..a1546f57ec 100644
--- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json
+++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json
@@ -12,7 +12,7 @@
{
"fib":true,
"ip":"11.1.1.2",
- "weight":255
+ "weight":254
}
]
}
diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json
index 7b4da2a8d0..0444d2d6cb 100644
--- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json
+++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json
@@ -7,7 +7,7 @@
{
"fib":true,
"ip":"11.1.1.2",
- "weight":255
+ "weight":254
}
]
}
diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json
index 3062d1cf8b..dd84a0f373 100644
--- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json
+++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json
@@ -7,7 +7,7 @@
{
"fib":true,
"ip":"11.1.1.2",
- "weight":255
+ "weight":254
}
]
}
diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json
index 662b7f716c..63b7a6b508 100644
--- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json
+++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json
@@ -12,7 +12,7 @@
{
"fib":true,
"ip":"11.1.1.2",
- "weight":255
+ "weight":254
}
]
}
diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json
index d9b5a8992d..edd764a80a 100644
--- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json
+++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json
@@ -12,7 +12,7 @@
{
"fib":true,
"ip":"11.1.1.2",
- "weight":255
+ "weight":254
}
]
}
diff --git a/tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json b/tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json
index 53be1171f6..05928b1167 100644
--- a/tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json
+++ b/tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json
@@ -12,7 +12,7 @@
{
"fib":true,
"ip":"11.1.2.2",
- "weight":255
+ "weight":254
}
]
}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/__init__.py b/tests/topotests/bgp_match_peer/__init__.py
index e69de29bb2..e69de29bb2 100644
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/__init__.py
+++ b/tests/topotests/bgp_match_peer/__init__.py
diff --git a/tests/topotests/bgp_match_peer/r1/frr.conf b/tests/topotests/bgp_match_peer/r1/frr.conf
new file mode 100644
index 0000000000..f30da3b896
--- /dev/null
+++ b/tests/topotests/bgp_match_peer/r1/frr.conf
@@ -0,0 +1,37 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.1.2 remote-as external
+ neighbor r3 peer-group
+ neighbor r3 remote-as external
+ neighbor 192.168.1.3 peer-group r3
+ neighbor r4 peer-group
+ neighbor r4 remote-as external
+ neighbor 192.168.1.4 peer-group r4
+ address-family ipv4 unicast
+ network 10.0.0.1/32 route-map all
+ neighbor 192.168.1.2 route-map all in
+ neighbor r3 route-map all in
+ neighbor r4 route-map all in
+ exit-address-family
+!
+route-map all permit 5
+ match peer local
+ set metric 1
+!
+route-map all permit 10
+ match peer 192.168.1.2
+ set metric 2
+!
+route-map all permit 15
+ match peer r3
+ set metric 3
+!
+route-map all permit 20
+ match peer r4
+ set metric 4
+!
diff --git a/tests/topotests/bgp_match_peer/r2/frr.conf b/tests/topotests/bgp_match_peer/r2/frr.conf
new file mode 100644
index 0000000000..86dd8e3389
--- /dev/null
+++ b/tests/topotests/bgp_match_peer/r2/frr.conf
@@ -0,0 +1,14 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ address-family ipv4 unicast
+ network 10.0.0.2/32
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_match_peer/r3/frr.conf b/tests/topotests/bgp_match_peer/r3/frr.conf
new file mode 100644
index 0000000000..978f967a0f
--- /dev/null
+++ b/tests/topotests/bgp_match_peer/r3/frr.conf
@@ -0,0 +1,14 @@
+!
+int r3-eth0
+ ip address 192.168.1.3/24
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ address-family ipv4 unicast
+ network 10.0.0.3/32
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_match_peer/r4/frr.conf b/tests/topotests/bgp_match_peer/r4/frr.conf
new file mode 100644
index 0000000000..6fb0bc660d
--- /dev/null
+++ b/tests/topotests/bgp_match_peer/r4/frr.conf
@@ -0,0 +1,14 @@
+!
+int r4-eth0
+ ip address 192.168.1.4/24
+!
+router bgp 65004
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ address-family ipv4 unicast
+ network 10.0.0.4/32
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_match_peer/test_bgp_match_peer.py b/tests/topotests/bgp_match_peer/test_bgp_match_peer.py
new file mode 100644
index 0000000000..4eb7473df0
--- /dev/null
+++ b/tests/topotests/bgp_match_peer/test_bgp_match_peer.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+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, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2", "r3", "r4")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_match_peer():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ def _bgp_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "10.0.0.1/32": [
+ {
+ "metric": 1,
+ }
+ ],
+ "10.0.0.2/32": [
+ {
+ "metric": 2,
+ }
+ ],
+ "10.0.0.3/32": [
+ {
+ "metric": 3,
+ }
+ ],
+ "10.0.0.4/32": [
+ {
+ "metric": 4,
+ }
+ ],
+ }
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't converge"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf
deleted file mode 100644
index 9b19b2cfbd..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-ipv6 route ::/0 fd00:100::2
-ip route 0.0.0.0/0 192.168.1.2
-interface eth-r1
- ip address 192.168.1.1/24
- ipv6 address fd00:100::1/64
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf
deleted file mode 100644
index 2bf4a66680..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-ipv6 route ::/0 fd00:700::2
-ip route 0.0.0.0/0 192.168.7.2
-interface eth-r7
- ip address 192.168.7.1/24
- ipv6 address fd00:700::1/64
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf
deleted file mode 100644
index e8b6ac6e26..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-ipv6 route ::/0 fd00:800::2
-ip route 0.0.0.0/0 192.168.8.2
-interface eth-r8
- ip address 192.168.8.1/24
- ipv6 address fd00:800::1/64
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json
deleted file mode 100755
index 12fecee39f..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "routes": {
- "192.168.1.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "",
- "nexthops": [
- {
- "ip": "0.0.0.0",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.7.0/24": [
- {
- "valid": true,
- "multipath": true,
- "path": "65000 65700",
- "nexthops": [
- {
- "ip": "172.16.1.3",
- "afi": "ipv4",
- "used": true
- }
- ]
- },
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65700",
- "nexthops": [
- {
- "ip": "172.16.0.2",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.8.0/24": [
- {
- "valid": true,
- "multipath": true,
- "path": "65000 65800",
- "nexthops": [
- {
- "ip": "172.16.1.3",
- "afi": "ipv4",
- "used": true
- }
- ]
- },
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65800",
- "nexthops": [
- {
- "ip": "172.16.0.2",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json
deleted file mode 100755
index f7c5c7c3b5..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step1.json
+++ /dev/null
@@ -1,90 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "multipath": true,
- "path": "65000 65700",
- "nexthops": [
- {
- "ip": "fd00:0:2::3",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- },
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65700",
- "nexthops": [
- {
- "ip": "fd00:0:1::2",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "multipath": true,
- "path": "65000 65800",
- "nexthops": [
- {
- "ip": "fd00:0:2::3",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- },
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65800",
- "nexthops": [
- {
- "ip": "fd00:0:1::2",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json
deleted file mode 100755
index f7c5c7c3b5..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv6_step2.json
+++ /dev/null
@@ -1,90 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "multipath": true,
- "path": "65000 65700",
- "nexthops": [
- {
- "ip": "fd00:0:2::3",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- },
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65700",
- "nexthops": [
- {
- "ip": "fd00:0:1::2",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "multipath": true,
- "path": "65000 65800",
- "nexthops": [
- {
- "ip": "fd00:0:2::3",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- },
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65800",
- "nexthops": [
- {
- "ip": "fd00:0:1::2",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf
deleted file mode 100644
index 23b986d130..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgpd.conf
+++ /dev/null
@@ -1,23 +0,0 @@
-router bgp 65100
- no bgp ebgp-requires-policy
- neighbor 172.16.0.2 remote-as external
- neighbor 172.16.1.3 remote-as external
- ! neighbor 172.16.0.2 capability extended-nexthop
- !
- address-family ipv4 unicast
- redistribute connected route-map RMAP4
- !
- address-family ipv6 unicast
- redistribute connected route-map RMAP6
- neighbor 172.16.0.2 activate
- neighbor 172.16.1.3 activate
- !
-
-ip prefix-list RANGE4 seq 10 permit 192.168.0.0/16 le 24
-ipv6 prefix-list RANGE6 seq 10 permit fd00:100::0/64
-
-route-map RMAP4 permit 10
- match ip address prefix-list RANGE4
-!
-route-map RMAP6 permit 10
- match ipv6 address prefix-list RANGE6
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf
deleted file mode 100644
index 79cbafb5b8..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r1/zebra.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-!
-interface eth-h1
- ip address 192.168.1.2/24
- ipv6 address fd00:100::2/64
-!
-interface eth-r2
- ip address 172.16.0.1/24
- ipv6 address fd00:0:1::1/64
-!
-interface eth-r3
- ip address 172.16.1.1/24
- ipv6 address fd00:0:2::1/64
-!
-interface lo
- ip address 192.0.2.1/32
- ipv6 address 2001:db8::1/128
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json
deleted file mode 100755
index 64dadf680c..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv4.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "routes": {
- "192.168.1.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "172.16.0.1",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.7.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "172.17.0.7",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.8.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "172.17.0.8",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json
deleted file mode 100644
index 4f86a1a648..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step1.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "fd00:0:1::1",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json
deleted file mode 100644
index 6738d45750..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgp_ipv6_step2.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "::ffff:ac10:1",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf
deleted file mode 100644
index badb11cbeb..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/bgpd.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-router bgp 65000
- no bgp ebgp-requires-policy
- neighbor 172.16.0.1 remote-as external
- ! neighbor 172.16.0.1 capability extended-nexthop
- neighbor 192.0.2.101 remote-as internal
- neighbor 192.0.2.101 update-source 192.0.2.2
- !
- address-family ipv6 unicast
- neighbor 172.16.0.1 activate
- neighbor 192.0.2.101 activate
- !
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf
deleted file mode 100644
index 16963798f8..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/isisd.conf
+++ /dev/null
@@ -1,24 +0,0 @@
-!
-interface lo
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-interface eth-rr1
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-interface eth-r1
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-router isis 1
- net 49.0000.0000.0000.0002.00
- is-type level-1
- lsp-gen-interval 1
- topology ipv6-unicast
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf
deleted file mode 100644
index 8997115d87..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r2/zebra.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-!
-interface eth-r1
- ip address 172.16.0.2/24
- ipv6 address fd00:0:1::2/64
-!
-interface eth-rr1
- ip address 10.0.0.2/24
- ipv6 address fd00:0:3::2/64
-!
-interface lo
- ip address 192.0.2.2/32
- ipv6 address 2001:db8::2/128
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json
deleted file mode 100644
index 0f18a43bf5..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv4.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "routes": {
- "192.168.1.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "172.16.1.1",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.7.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "172.17.0.7",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.8.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "172.17.0.8",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json
deleted file mode 100644
index f44121c30e..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step1.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "fd00:0:2::1",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json
deleted file mode 100644
index 807806ff8d..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgp_ipv6_step2.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "::ffff:ac10:101",
- "afi": "ipv6",
- "scope": "global"
- },
- {
- "afi": "ipv6",
- "scope": "link-local",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf
deleted file mode 100644
index 4dec311f51..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/bgpd.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-router bgp 65000
- no bgp ebgp-requires-policy
- neighbor 172.16.1.1 remote-as external
- ! neighbor 172.16.1.1 capability extended-nexthop
- neighbor 192.0.2.101 remote-as internal
- neighbor 192.0.2.101 update-source 192.0.2.3
- !
- address-family ipv6 unicast
- neighbor 172.16.1.1 activate
- neighbor 192.0.2.101 activate
- !
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf
deleted file mode 100644
index fe3e307b42..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/isisd.conf
+++ /dev/null
@@ -1,24 +0,0 @@
-!
-interface lo
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-interface eth-rr1
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-interface eth-r1
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-router isis 1
- net 49.0000.0000.0000.0003.00
- is-type level-1
- lsp-gen-interval 1
- topology ipv6-unicast
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf
deleted file mode 100644
index 8074bbdcde..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r3/zebra.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-!
-interface eth-r1
- ip address 172.16.1.3/24
- ipv6 address fd00:0:2::3/64
-!
-interface eth-rr1
- ip address 10.0.1.3/24
- ipv6 address fd00:0:4::3/64
-!
-interface lo
- ip address 192.0.2.3/32
- ipv6 address 2001:db8::3/128
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json
deleted file mode 100755
index 64dadf680c..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv4.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "routes": {
- "192.168.1.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "172.16.0.1",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.7.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "172.17.0.7",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.8.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "172.17.0.8",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json
deleted file mode 100755
index 756a78e3b1..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step1.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "fd00:0:1::1",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json
deleted file mode 100755
index 7d0786c0ef..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgp_ipv6_step2.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "2001:db8::2",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf
deleted file mode 100644
index 2dbc4acddc..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/bgpd.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-router bgp 65000
- neighbor 192.0.2.5 remote-as internal
- neighbor 192.0.2.6 remote-as internal
- neighbor 192.0.2.101 remote-as internal
- neighbor 192.0.2.5 update-source 192.0.2.4
- neighbor 192.0.2.6 update-source 192.0.2.4
- neighbor 192.0.2.101 update-source 192.0.2.4
- !
- address-family ipv6 unicast
- neighbor 192.0.2.5 activate
- neighbor 192.0.2.6 activate
- neighbor 192.0.2.101 activate
- !
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf
deleted file mode 100644
index 21eb80f58b..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/isisd.conf
+++ /dev/null
@@ -1,26 +0,0 @@
-!
-interface lo
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-interface eth-rr1
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-interface eth-r6
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-router isis 1
- net 49.0000.0000.0000.0004.00
- is-type level-1
- lsp-gen-interval 1
- topology ipv6-unicast
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf
deleted file mode 100644
index c598b345e5..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r4/zebra.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-!
-interface eth-r6
- ip address 10.0.4.4/24
- ipv6 address fd00:0:7::4/64
-!
-interface eth-rr1
- ip address 10.0.2.4/24
- ipv6 address fd00:0:5::4/64
-!
-interface lo
- ip address 192.0.2.4/32
- ipv6 address 2001:db8::4/128
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json
deleted file mode 100755
index 64dadf680c..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv4.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "routes": {
- "192.168.1.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "172.16.0.1",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.7.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "172.17.0.7",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.8.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "172.17.0.8",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json
deleted file mode 100755
index 756a78e3b1..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step1.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "fd00:0:1::1",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json
deleted file mode 100755
index 7d0786c0ef..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgp_ipv6_step2.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "2001:db8::2",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf
deleted file mode 100644
index 101edbd71b..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/bgpd.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-router bgp 65000
- neighbor 192.0.2.4 remote-as internal
- neighbor 192.0.2.6 remote-as internal
- neighbor 192.0.2.101 remote-as internal
- neighbor 192.0.2.4 update-source 192.0.2.5
- neighbor 192.0.2.6 update-source 192.0.2.5
- neighbor 192.0.2.101 update-source 192.0.2.5
- !
- address-family ipv6 unicast
- neighbor 192.0.2.4 activate
- neighbor 192.0.2.6 activate
- neighbor 192.0.2.101 activate
- !
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf
deleted file mode 100644
index f998e805b5..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/isisd.conf
+++ /dev/null
@@ -1,26 +0,0 @@
-!
-interface lo
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-interface eth-rr1
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-interface eth-r6
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-router isis 1
- net 49.0000.0000.0000.0005.00
- is-type level-1
- lsp-gen-interval 1
- topology ipv6-unicast
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf
deleted file mode 100644
index 7b43db0958..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r5/zebra.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-!
-interface eth-r6
- ip address 10.0.5.5/24
- ipv6 address fd00:0:8::5/64
-!
-interface eth-rr1
- ip address 10.0.3.5/24
- ipv6 address fd00:0:6::5/64
-!
-interface lo
- ip address 192.0.2.5/32
- ipv6 address 2001:db8::5/128
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json
deleted file mode 100644
index 64dadf680c..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv4.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "routes": {
- "192.168.1.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "172.16.0.1",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.7.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "172.17.0.7",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.8.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "172.17.0.8",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json
deleted file mode 100644
index 1a01ead2cd..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step1.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "nexthops": [
- {
- "ip": "fd00:0:1::1",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json
deleted file mode 100644
index 55912dd74c..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgp_ipv6_step2.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "nexthops": [
- {
- "ip": "2001:db8::2",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf
deleted file mode 100644
index e036a779ae..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/bgpd.conf
+++ /dev/null
@@ -1,17 +0,0 @@
-router bgp 65000
- no bgp ebgp-requires-policy
- no bgp enforce-first-as
- neighbor 192.0.2.4 remote-as internal
- neighbor 192.0.2.5 remote-as internal
- neighbor 192.0.2.101 remote-as internal
- neighbor 172.17.0.201 remote-as external
- neighbor 192.0.2.4 update-source 192.0.2.6
- neighbor 192.0.2.5 update-source 192.0.2.6
- neighbor 192.0.2.101 update-source 192.0.2.6
- !
- address-family ipv6 unicast
- neighbor 192.0.2.4 activate
- neighbor 192.0.2.5 activate
- neighbor 192.0.2.101 activate
- neighbor 172.17.0.201 activate
- !
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf
deleted file mode 100644
index b575290e9b..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/isisd.conf
+++ /dev/null
@@ -1,31 +0,0 @@
-!
-interface lo
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-interface eth-r4
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-interface eth-r5
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-interface eth-sw1
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-router isis 1
- net 49.0000.0000.0000.0006.00
- is-type level-1
- lsp-gen-interval 1
- topology ipv6-unicast
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf
deleted file mode 100644
index fce74c146c..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r6/zebra.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-!
-interface eth-r4
- ip address 10.0.4.6/24
- ipv6 address fd00:0:7::6/64
-!
-interface eth-r5
- ip address 10.0.5.6/24
- ipv6 address fd00:0:8::6/64
-!
-interface eth-sw1
- ip address 172.17.0.6/24
- ipv6 address fd00:0:9::6/64
-!
-interface lo
- ip address 192.0.2.6/32
- ipv6 address 2001:db8::6/128
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json
deleted file mode 100644
index 72b0f03c51..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv4.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "routes": {
- "192.168.1.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65100",
- "nexthops": [
- {
- "ip": "172.17.0.6",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.7.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "",
- "nexthops": [
- {
- "ip": "0.0.0.0",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.8.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "172.17.0.8",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json
deleted file mode 100644
index 8fe5f7c1de..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step1.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65100",
- "nexthops": [
- {
- "ip": "fd00:0:9::6",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json
deleted file mode 100644
index 8fe5f7c1de..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgp_ipv6_step2.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65100",
- "nexthops": [
- {
- "ip": "fd00:0:9::6",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf
deleted file mode 100644
index a707b23af0..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/bgpd.conf
+++ /dev/null
@@ -1,21 +0,0 @@
-router bgp 65700
- no bgp ebgp-requires-policy
- no bgp enforce-first-as
- neighbor 172.17.0.201 remote-as external
- !
- address-family ipv4 unicast
- redistribute connected route-map RMAP4
- !
- address-family ipv6 unicast
- redistribute connected route-map RMAP6
- neighbor 172.17.0.201 activate
- !
-
-ip prefix-list RANGE4 seq 10 permit 192.168.0.0/16 le 24
-ipv6 prefix-list RANGE6 seq 10 permit fd00:700::0/64
-
-route-map RMAP4 permit 10
- match ip address prefix-list RANGE4
-!
-route-map RMAP6 permit 10
- match ipv6 address prefix-list RANGE6
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf
deleted file mode 100644
index 75448297eb..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r7/zebra.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-!
-interface eth-h2
- ip address 192.168.7.2/24
- ipv6 address fd00:700::2/64
-!
-interface eth-sw1
- ip address 172.17.0.7/24
- ipv6 address fd00:0:9::7/64
-!
-interface lo
- ip address 192.0.2.7/32
- ipv6 address 2001:db8::7/128
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json
deleted file mode 100644
index 596ee4b40b..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv4.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "routes": {
- "192.168.1.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65100",
- "nexthops": [
- {
- "ip": "172.17.0.6",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.7.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "172.17.0.7",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.8.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "",
- "nexthops": [
- {
- "ip": "0.0.0.0",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json
deleted file mode 100644
index 20f4940328..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step1.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65100",
- "nexthops": [
- {
- "ip": "fd00:0:9::6",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json
deleted file mode 100644
index 20f4940328..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgp_ipv6_step2.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65000 65100",
- "nexthops": [
- {
- "ip": "fd00:0:9::6",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "",
- "nexthops": [
- {
- "ip": "::",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf
deleted file mode 100644
index d57712dcdd..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/bgpd.conf
+++ /dev/null
@@ -1,21 +0,0 @@
-router bgp 65800
- no bgp ebgp-requires-policy
- no bgp enforce-first-as
- neighbor 172.17.0.201 remote-as external
- !
- address-family ipv4 unicast
- redistribute connected route-map RMAP4
- !
- address-family ipv6 unicast
- redistribute connected route-map RMAP6
- neighbor 172.17.0.201 activate
- !
-
-ip prefix-list RANGE4 seq 10 permit 192.168.0.0/16 le 24
-ipv6 prefix-list RANGE6 seq 10 permit fd00:800::0/64
-
-route-map RMAP4 permit 10
- match ip address prefix-list RANGE4
-!
-route-map RMAP6 permit 10
- match ipv6 address prefix-list RANGE6
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf
deleted file mode 100644
index 7e2479b751..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/r8/zebra.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-!
-interface eth-h3
- ip address 192.168.8.2/24
- ipv6 address fd00:800::2/64
-!
-interface eth-sw1
- ip address 172.17.0.8/24
- ipv6 address fd00:0:9::8/64
-!
-interface lo
- ip address 192.0.2.8/32
- ipv6 address 2001:db8::8/128
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json
deleted file mode 100644
index ac67fe069c..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv4.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "routes": {
- "192.168.1.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "172.16.0.1",
- "afi": "ipv4",
- "used": true
- }
- ]
- },
- {
- "valid": true,
- "multipath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "172.16.1.1",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.7.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "172.17.0.7",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ],
- "192.168.8.0/24": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "172.17.0.8",
- "afi": "ipv4",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json
deleted file mode 100644
index 4e359fd97f..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step1.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "fd00:0:1::1",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- },
- {
- "valid": true,
- "multipath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "fd00:0:2::1",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "scope": "global",
- "afi": "ipv6",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json
deleted file mode 100644
index 4ab0e1c2ae..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgp_ipv6_step2.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- "routes": {
- "fd00:100::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "2001:db8::2",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- },
- {
- "valid": true,
- "multipath": true,
- "path": "65100",
- "nexthops": [
- {
- "ip": "2001:db8::3",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:700::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65700",
- "nexthops": [
- {
- "ip": "fd00:0:9::7",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ],
- "fd00:800::/64": [
- {
- "valid": true,
- "bestpath": true,
- "path": "65800",
- "nexthops": [
- {
- "ip": "fd00:0:9::8",
- "afi": "ipv6",
- "scope": "global",
- "used": true
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf
deleted file mode 100644
index 9bbac8b68e..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/bgpd.conf
+++ /dev/null
@@ -1,26 +0,0 @@
-router bgp 65000
- neighbor 192.0.2.2 remote-as internal
- neighbor 192.0.2.3 remote-as internal
- neighbor 192.0.2.4 remote-as internal
- neighbor 192.0.2.5 remote-as internal
- neighbor 192.0.2.6 remote-as internal
- neighbor 192.0.2.2 update-source 192.0.2.101
- neighbor 192.0.2.3 update-source 192.0.2.101
- neighbor 192.0.2.4 update-source 192.0.2.101
- neighbor 192.0.2.5 update-source 192.0.2.101
- neighbor 192.0.2.6 update-source 192.0.2.101
- !
- address-family ipv4 unicast
- neighbor 192.0.2.2 route-reflector-client
- neighbor 192.0.2.3 route-reflector-client
-
- !
- address-family ipv6 unicast
- neighbor 192.0.2.2 activate
- neighbor 192.0.2.3 activate
- neighbor 192.0.2.4 activate
- neighbor 192.0.2.5 activate
- neighbor 192.0.2.6 activate
- neighbor 192.0.2.2 route-reflector-client
- neighbor 192.0.2.3 route-reflector-client
- !
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf
deleted file mode 100644
index fe5bcfb9f1..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/isisd.conf
+++ /dev/null
@@ -1,40 +0,0 @@
-!
-interface lo
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-interface eth-r2
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-interface eth-r3
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-interface eth-r4
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-interface eth-r5
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
- isis network point-to-point
-!
-router isis 1
- net 49.0000.0000.0000.0101.00
- is-type level-1
- lsp-gen-interval 1
- topology ipv6-unicast
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf
deleted file mode 100644
index 7f5c8d1c61..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rr1/zebra.conf
+++ /dev/null
@@ -1,21 +0,0 @@
-!
-interface eth-r2
- ip address 10.0.0.101/24
- ipv6 address fd00:0:3::101/64
-!
-interface eth-r3
- ip address 10.0.1.101/24
- ipv6 address fd00:0:4::101/64
-!
-interface eth-r4
- ip address 10.0.2.101/24
- ipv6 address fd00:0:5::101/64
-!
-interface eth-r5
- ip address 10.0.3.101/24
- ipv6 address fd00:0:6::101/64
-!
-interface lo
- ip address 192.0.2.101/32
- ipv6 address 2001:db8::101/128
-
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf
deleted file mode 100644
index 596cc3e25c..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/bgpd.conf
+++ /dev/null
@@ -1,21 +0,0 @@
-router bgp 65200 view RS
- bgp router-id 192.0.2.201
- no bgp ebgp-requires-policy
- neighbor 172.17.0.6 remote-as external
- neighbor 172.17.0.7 remote-as external
- neighbor 172.17.0.8 remote-as external
- !
- address-family ipv4 unicast
- neighbor 172.17.0.6 route-server-client
- neighbor 172.17.0.7 route-server-client
- neighbor 172.17.0.8 route-server-client
-
- !
- address-family ipv6 unicast
- neighbor 172.17.0.6 activate
- neighbor 172.17.0.7 activate
- neighbor 172.17.0.8 activate
- neighbor 172.17.0.6 route-server-client
- neighbor 172.17.0.7 route-server-client
- neighbor 172.17.0.8 route-server-client
- !
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf
deleted file mode 100644
index 892b4e7b74..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/isisd.conf
+++ /dev/null
@@ -1,36 +0,0 @@
-!
-interface lo
- ip router isis 1
- ipv6 router isis 1
- isis passive
-!
-interface eth-r2
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
-!
-interface eth-r3
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
-!
-interface eth-r4
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
-!
-interface eth-r5
- ip router isis 1
- ipv6 router isis 1
- isis hello-interval 1
- isis hello-multiplier 3
-!
-router isis 1
- net 49.0000.0000.0000.0101.00
- is-type level-1
- lsp-gen-interval 1
- topology ipv6-unicast
-!
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf b/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf
deleted file mode 100644
index 75ee08363a..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/rs1/zebra.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-interface eth-sw1
- ip address 172.17.0.201/24
- ipv6 address fd00:0:9::201/64
-!
-interface lo
- ip address 192.0.2.201/32
- ipv6 address 2001:db8::201/128
-
diff --git a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py b/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py
deleted file mode 100644
index e1c28084de..0000000000
--- a/tests/topotests/bgp_nexthop_mp_ipv4_6/test_nexthop_mp_ipv4_6.py
+++ /dev/null
@@ -1,282 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: ISC
-
-#
-# Copyright (c) 2024 by 6WIND
-#
-
-"""
-Test BGP nexthop conformity with IPv4,6 MP-BGP over IPv4 peering
-"""
-
-import os
-import sys
-import json
-from functools import partial
-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
-from lib.checkping import check_ping
-from lib.bgp import verify_bgp_convergence_from_running_config
-
-pytestmark = [pytest.mark.bgpd, pytest.mark.isisd]
-
-
-def build_topo(tgen):
- r"""
- +---+
- | h1|
- +---+
- |
- +---+
- | r1| AS 65100
- +---+
- / \ _____________
- / \
- +---+ +---+
- | r2| | r3| rr1 is route-reflector
- +---+ +---+ for r2 and r3
- \ /
- \ /
- +---+
- |rr1| AS 65000
- +---+
- / \
- / \
- +---+ +---+
- | r4| | r5| iBGP full-mesh between
- +---+ +---+ rr1, r4, r5 and r6
- \ /
- \ /
- +---+
- | r6|
- +---+
- | _____________
- |
- | +---+
- [sw1]-----|rs1| AS 65200
- /\ +---+ rs1: route-server
- / \
- / \ _____________
- +---+ +---+
- | r7| | r8| AS 65700 (r7)
- +---+ +---+ AS 65800 (r8)
- | |
- +---+ +---+
- | h2| | h3|
- +---+ +---+
- """
-
- def connect_routers(tgen, left, right):
- for rname in [left, right]:
- if rname not in tgen.routers().keys():
- tgen.add_router(rname)
-
- switch = tgen.add_switch("s-{}-{}".format(left, right))
- switch.add_link(tgen.gears[left], nodeif="eth-{}".format(right))
- switch.add_link(tgen.gears[right], nodeif="eth-{}".format(left))
-
- def connect_switchs(tgen, rname, switch):
- if rname not in tgen.routers().keys():
- tgen.add_router(rname)
-
- switch.add_link(tgen.gears[rname], nodeif="eth-{}".format(switch.name))
-
- connect_routers(tgen, "h1", "r1")
- connect_routers(tgen, "r1", "r2")
- connect_routers(tgen, "r1", "r3")
- connect_routers(tgen, "r2", "rr1")
- connect_routers(tgen, "r3", "rr1")
- connect_routers(tgen, "rr1", "r4")
- connect_routers(tgen, "rr1", "r5")
- connect_routers(tgen, "r4", "r6")
- connect_routers(tgen, "r5", "r6")
-
- sw1 = tgen.add_switch("sw1")
- connect_switchs(tgen, "r6", sw1)
- connect_switchs(tgen, "rs1", sw1)
- connect_switchs(tgen, "r7", sw1)
- connect_switchs(tgen, "r8", sw1)
-
- connect_routers(tgen, "r7", "h2")
- connect_routers(tgen, "r8", "h3")
-
-
-def setup_module(mod):
- "Sets up the pytest environment"
-
- tgen = Topogen(build_topo, mod.__name__)
- tgen.start_topology()
- logger.info("setup_module")
-
- for rname, router in tgen.routers().items():
- router.load_config(
- TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
- )
- if "h" in rname:
- # hosts
- continue
-
- router.load_config(
- TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
- )
-
- if rname in ["r1", "r7", "r8", "rs1"]:
- # external routers
- continue
-
- router.load_config(
- TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
- )
-
- # Initialize all routers.
- tgen.start_router()
-
-
-def teardown_module(_mod):
- "Teardown the pytest environment"
- tgen = get_topogen()
- tgen.stop_topology()
-
-
-def test_bgp_convergence():
- "Assert that BGP is converging."
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- logger.info("waiting for bgp peers to go up")
-
- for rname in tgen.routers().keys():
- if "h" in rname:
- # hosts
- continue
- result = verify_bgp_convergence_from_running_config(tgen, dut=rname)
- assert result is True, "BGP is not converging on {}".format(rname)
-
-
-def test_bgp_ipv4_nexthop_step1():
- "Assert that BGP has correct ipv4 nexthops."
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- for rname, router in tgen.routers().items():
- if "h" in rname:
- # hosts
- continue
- if "rs1" in rname:
- continue
- ref_file = "{}/{}/bgp_ipv4.json".format(CWD, rname)
- expected = json.loads(open(ref_file).read())
- test_func = partial(
- topotest.router_json_cmp,
- router,
- "show bgp ipv4 unicast json",
- expected,
- )
- _, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
- assertmsg = "{}: BGP IPv4 Nexthop failure".format(rname)
- assert res is None, assertmsg
-
-
-def test_bgp_ipv6_nexthop_step1():
- "Assert that BGP has correct ipv6 nexthops."
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- for rname, router in tgen.routers().items():
- if "h" in rname:
- # hosts
- continue
- if "rs1" in rname:
- continue
- ref_file = "{}/{}/bgp_ipv6_step1.json".format(CWD, rname)
- expected = json.loads(open(ref_file).read())
- test_func = partial(
- topotest.router_json_cmp,
- router,
- "show bgp ipv6 unicast json",
- expected,
- )
- _, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
- assertmsg = "{}: BGP IPv6 Nexthop failure".format(rname)
- assert res is None, assertmsg
-
-
-def test_bgp_ping_ok_step1():
- "Check that h1 pings h2 and h3"
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- check_ping("h1", "192.168.7.1", True, 5, 1)
- check_ping("h1", "fd00:700::1", True, 5, 1)
- check_ping("h1", "192.168.8.1", True, 5, 1)
- check_ping("h1", "fd00:800::1", True, 5, 1)
-
-
-def test_bgp_ipv6_nexthop_step2():
- """
- Remove IPv6 global on r1 and r7
- Assert that BGP has correct ipv6 nexthops.
- """
-
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- tgen.gears["r1"].vtysh_cmd(
- """
-configure
-interface eth-r2
- no ipv6 address fd00:0:1::1/64
-!
-interface eth-r3
- no ipv6 address fd00:0:2::1/64
-"""
- )
-
- for rname, router in tgen.routers().items():
- if "h" in rname:
- # hosts
- continue
- if "rs1" in rname:
- continue
- ref_file = "{}/{}/bgp_ipv6_step2.json".format(CWD, rname)
- expected = json.loads(open(ref_file).read())
- test_func = partial(
- topotest.router_json_cmp,
- router,
- "show bgp ipv6 unicast json",
- expected,
- )
- _, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
- assertmsg = "{}: BGP IPv6 Nexthop failure".format(rname)
- assert res is None, assertmsg
-
-
-def test_bgp_ping_ok_step2():
- "Check that h1 pings h2 and h3"
- tgen = get_topogen()
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- check_ping("h1", "192.168.7.1", True, 5, 1)
- check_ping("h1", "fd00:700::1", True, 5, 1)
- check_ping("h1", "192.168.8.1", True, 5, 1)
- check_ping("h1", "fd00:800::1", True, 5, 1)
-
-
-if __name__ == "__main__":
- args = ["-s"] + sys.argv[1:]
- sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_peer_group_solo/__init__.py b/tests/topotests/bgp_peer_group_solo/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_peer_group_solo/__init__.py
diff --git a/tests/topotests/bgp_peer_group_solo/r1/frr.conf b/tests/topotests/bgp_peer_group_solo/r1/frr.conf
new file mode 100644
index 0000000000..53959aa134
--- /dev/null
+++ b/tests/topotests/bgp_peer_group_solo/r1/frr.conf
@@ -0,0 +1,21 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
+int r1-eth1
+ ip address 192.168.14.1/24
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor pg peer-group
+ neighbor pg remote-as external
+ neighbor pg solo
+ neighbor pg timers 1 3
+ neighbor pg timers connect 1
+ neighbor 192.168.1.2 peer-group pg
+ neighbor 192.168.1.3 peer-group pg
+ address-family ipv4 unicast
+ network 10.0.0.1/32
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_peer_group_solo/r2/frr.conf b/tests/topotests/bgp_peer_group_solo/r2/frr.conf
new file mode 100644
index 0000000000..ba99827a47
--- /dev/null
+++ b/tests/topotests/bgp_peer_group_solo/r2/frr.conf
@@ -0,0 +1,10 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_peer_group_solo/r3/frr.conf b/tests/topotests/bgp_peer_group_solo/r3/frr.conf
new file mode 100644
index 0000000000..ed06170bf2
--- /dev/null
+++ b/tests/topotests/bgp_peer_group_solo/r3/frr.conf
@@ -0,0 +1,10 @@
+!
+int r3-eth0
+ ip address 192.168.1.3/24
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_peer_group_solo/test_bgp_peer_group_solo.py b/tests/topotests/bgp_peer_group_solo/test_bgp_peer_group_solo.py
new file mode 100644
index 0000000000..cdbc1e02a7
--- /dev/null
+++ b/tests/topotests/bgp_peer_group_solo/test_bgp_peer_group_solo.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+import os
+import re
+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, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2", "r3")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_remote_as_auto():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ def _bgp_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json"))
+ expected = {
+ "peers": {
+ "192.168.1.2": {
+ "remoteAs": 65002,
+ "state": "Established",
+ "peerState": "OK",
+ },
+ "192.168.1.3": {
+ "remoteAs": 65003,
+ "state": "Established",
+ "peerState": "OK",
+ },
+ },
+ "totalPeers": 2,
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't converge initial state"
+
+ def _bgp_update_groups():
+ actual = []
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast update-groups json"))
+ expected = [
+ {"subGroup": [{"adjListCount": 1, "peers": ["192.168.1.2"]}]},
+ {"subGroup": [{"adjListCount": 1, "peers": ["192.168.1.3"]}]},
+ ]
+
+ # update-group's number can be random and it's not deterministic,
+ # so we need to normalize the data a bit before checking.
+ # We care here about the `peers` array only actually.
+ for updgrp in output["default"].keys():
+ actual.append(output["default"][updgrp])
+
+ return topotest.json_cmp(actual, expected)
+
+ test_func = functools.partial(
+ _bgp_update_groups,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see separate update-groups"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_self_prefix/__init__.py b/tests/topotests/bgp_self_prefix/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_self_prefix/__init__.py
diff --git a/tests/topotests/bgp_self_prefix/r1/frr.conf b/tests/topotests/bgp_self_prefix/r1/frr.conf
new file mode 100644
index 0000000000..879afb1947
--- /dev/null
+++ b/tests/topotests/bgp_self_prefix/r1/frr.conf
@@ -0,0 +1,19 @@
+!
+int lo
+ ip address 10.0.0.1/32
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
+router bgp 65000
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.0.2 remote-as internal
+ neighbor 10.0.0.2 update-source lo
+ neighbor 10.0.0.2 next-hop-self
+ neighbor 10.0.0.3 remote-as external
+ neighbor 10.0.0.3 update-source lo
+ neighbor 10.0.0.3 next-hop-self
+!
+ip route 10.0.0.2/32 192.168.1.2
+ip route 10.0.0.3/32 192.168.1.3
diff --git a/tests/topotests/bgp_self_prefix/r2/frr.conf b/tests/topotests/bgp_self_prefix/r2/frr.conf
new file mode 100644
index 0000000000..eb0db356ea
--- /dev/null
+++ b/tests/topotests/bgp_self_prefix/r2/frr.conf
@@ -0,0 +1,20 @@
+!
+int lo
+ ip address 10.0.0.2/32
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+router bgp 65000
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.0.1 remote-as internal
+ neighbor 10.0.0.1 timers 1 3
+ neighbor 10.0.0.1 timers connect 1
+ neighbor 10.0.0.1 update-source lo
+ neighbor 10.0.0.1 next-hop-self
+ address-family ipv4 unicast
+ network 10.0.0.2/32
+ exit-address-family
+!
+ip route 10.0.0.1/32 192.168.1.1
diff --git a/tests/topotests/bgp_self_prefix/r3/frr.conf b/tests/topotests/bgp_self_prefix/r3/frr.conf
new file mode 100644
index 0000000000..e2348f4a68
--- /dev/null
+++ b/tests/topotests/bgp_self_prefix/r3/frr.conf
@@ -0,0 +1,20 @@
+!
+int lo
+ ip address 10.0.0.3/32
+!
+int r3-eth0
+ ip address 192.168.1.3/24
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.0.1 remote-as external
+ neighbor 10.0.0.1 timers 1 3
+ neighbor 10.0.0.1 timers connect 1
+ neighbor 10.0.0.1 update-source lo
+ neighbor 10.0.0.1 next-hop-self
+ address-family ipv4 unicast
+ network 10.0.0.3/32
+ exit-address-family
+!
+ip route 10.0.0.1/32 192.168.1.1
diff --git a/tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py b/tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py
new file mode 100644
index 0000000000..1045800368
--- /dev/null
+++ b/tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+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, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2", "r3")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_self_prefix():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r3 = tgen.gears["r3"]
+
+ def _bgp_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "10.0.0.2/32": [
+ {
+ "valid": True,
+ "path": "",
+ "nexthops": [
+ {"ip": "10.0.0.2", "hostname": "r2", "afi": "ipv4"}
+ ],
+ }
+ ],
+ "10.0.0.3/32": [
+ {
+ "valid": True,
+ "path": "65003",
+ "nexthops": [
+ {"ip": "10.0.0.3", "hostname": "r3", "afi": "ipv4"}
+ ],
+ }
+ ],
+ }
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't converge"
+
+ def _bgp_check_received_routes():
+ output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "10.0.0.2/32": [
+ {
+ "valid": True,
+ "bestpath": True,
+ "nexthops": [
+ {"ip": "10.0.0.1", "hostname": "r1", "afi": "ipv4"}
+ ],
+ }
+ ],
+ }
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_received_routes,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see 10.0.0.2/32"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
index 63f1719e1d..a5232ad694 100644
--- a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
+++ b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
@@ -108,7 +108,7 @@ def test_bgp_set_aspath_exclude():
pytest.skip(tgen.errors)
test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed overriding incoming AS-PATH with route-map"
@@ -128,7 +128,6 @@ def test_bgp_set_aspath_exclude_access_list():
conf
bgp as-path access-list FIRST permit ^65
route-map r2 permit 6
- no set as-path exclude as-path-access-list SECOND
set as-path exclude as-path-access-list FIRST
"""
)
@@ -140,21 +139,20 @@ clear bgp *
)
test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_2)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed change of exclude rule in route map"
r1.vtysh_cmd(
"""
conf
route-map r2 permit 6
- no set as-path exclude as-path-access-list FIRST
set as-path exclude as-path-access-list SECOND
"""
)
# tgen.mininet_cli()
test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed reverting exclude rule in route map"
@@ -182,7 +180,7 @@ clear bgp *
)
test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed to removing current accesslist"
@@ -200,7 +198,7 @@ clear bgp *
)
test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_4)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed to renegotiate with peers 2"
@@ -208,7 +206,7 @@ clear bgp *
"""
conf
route-map r2 permit 6
- no set as-path exclude as-path-access-list SECOND
+ set as-path exclude 65555
"""
)
@@ -219,7 +217,26 @@ clear bgp *
)
test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+
+ assert result is None, "Failed to renegotiate with peers 2"
+
+ r1.vtysh_cmd(
+ """
+conf
+ route-map r2 permit 6
+ set as-path exclude as-path-access-list NON-EXISTING
+ """
+ )
+
+ r1.vtysh_cmd(
+ """
+clear bgp *
+ """
+ )
+
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed to renegotiate with peers 2"
diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/r2/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/bgpd.conf
new file mode 100644
index 0000000000..a550b4c143
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/bgpd.conf
@@ -0,0 +1,18 @@
+!
+!debug bgp updates
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ no bgp default ipv4-unicast
+ neighbor 192.168.12.4 remote-as external
+ neighbor 192.168.12.4 timers 1 3
+ neighbor 192.168.12.4 timers connect 1
+ !
+ address-family ipv4 unicast
+ neighbor 192.168.12.4 activate
+ neighbor 192.168.12.4 addpath-tx-all-paths
+ exit-address-family
+!
+agentx
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/r2/snmpd.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/snmpd.conf
new file mode 100644
index 0000000000..032b93b676
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/snmpd.conf
@@ -0,0 +1,17 @@
+agentAddress 127.0.0.1,[::1]
+
+group public_group v1 public
+group public_group v2c public
+access public_group "" any noauth prefix all all none
+
+rocommunity public default
+
+view all included .1
+
+iquerySecName frr
+rouser frr
+
+master agentx
+
+agentXSocket /etc/frr/agentx
+agentXPerms 777 755 root frr
diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/r2/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/zebra.conf
new file mode 100644
index 0000000000..d7dfd899cc
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r2-eth0
+ ip address 192.168.12.2/24
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/rr/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/rr/bgpd.conf
new file mode 100644
index 0000000000..145a8f008e
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2_notification/rr/bgpd.conf
@@ -0,0 +1,19 @@
+!
+!debug bgp updates
+!
+router bgp 65004
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ no bgp default ipv4-unicast
+ neighbor 192.168.12.2 remote-as external
+ neighbor 192.168.12.2 timers 1 3
+ neighbor 192.168.12.2 timers connect 1
+ !
+ address-family ipv4 unicast
+ neighbor 192.168.12.2 activate
+ neighbor 192.168.12.2 addpath-tx-all-paths
+ neighbor 192.168.12.2 route-server-client
+ exit-address-family
+!
+agentx
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/rr/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/rr/zebra.conf
new file mode 100644
index 0000000000..eb8a486438
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2_notification/rr/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface rr-eth0
+ ip address 192.168.12.4/24
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/test_bgp_snmp_bgp4v2_notification.py b/tests/topotests/bgp_snmp_bgp4v2_notification/test_bgp_snmp_bgp4v2_notification.py
new file mode 100755
index 0000000000..c41ef30bb5
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2_notification/test_bgp_snmp_bgp4v2_notification.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright 2024 6WIND S.A.
+#
+
+
+"""
+Test BGP OPEN NOTIFY (Configuration mismatch) followed by snmpwalk.
+"""
+
+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
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib import topotest
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.snmp]
+
+
+def build_topo(tgen):
+ """Build function"""
+
+ tgen.add_router("r2")
+ tgen.add_router("rr")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["rr"])
+
+
+def setup_module(mod):
+ snmpd = os.system("which snmpd")
+ if snmpd:
+ error_msg = "SNMP not installed - skipping"
+ pytest.skip(error_msg)
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ for rname, router in tgen.routers().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)),
+ "-M snmp",
+ )
+ router.load_config(
+ TopoRouter.RD_SNMP,
+ os.path.join(CWD, "{}/snmpd.conf".format(rname)),
+ "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX",
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_open_notification_change_configuration():
+ tgen = get_topogen()
+
+ tgen.gears["rr"].vtysh_multicmd(
+ """
+configure terminal
+router bgp 65004
+neighbor 192.168.12.2 password 8888"
+"""
+ )
+ tgen.net["r2"].cmd("snmpwalk -v 2c -c public 127.0.0.1 .1.3.6.1.4.1.7336.4.2.1")
+ tgen.gears["rr"].vtysh_multicmd(
+ """
+configure terminal
+router bgp 65004
+no neighbor 192.168.12.2 password 8888"
+"""
+ )
+
+ def _check_bgp_session():
+ r2 = tgen.gears["r2"]
+
+ output = json.loads(r2.vtysh_cmd("show bgp summary json"))
+ expected = {
+ "ipv4Unicast": {"peers": {"192.168.12.4": {"state": "Established"}}}
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func1 = functools.partial(_check_bgp_session)
+ _, result1 = topotest.run_and_expect(test_func1, None, count=120, wait=0.5)
+
+ assert result1 is None, "Failed to verify the bgp session"
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py
index 2400cd2853..bba0061858 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py
@@ -21,7 +21,7 @@ from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
from lib.common_config import required_linux_kernel_version
-from lib.checkping import check_ping, check_ping
+from lib.checkping import check_ping
pytestmark = [pytest.mark.bgpd]
diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
index f7ac827e26..3932c29b98 100644
--- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
+++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
@@ -140,7 +140,7 @@ def test_bgp_better_admin_won():
topotest.router_json_cmp, r3, "show ip route 40.0.0.0 json", expected
)
- _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"r3" route to 40.0.0.0 should have been lost'
assert result is None, assertmsg
@@ -155,7 +155,7 @@ def test_bgp_better_admin_won():
"show ip route 40.0.0.0 json",
expected,
)
- _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"r3" route to 40.0.0.0 did not come back'
assert result is None, assertmsg
@@ -196,7 +196,7 @@ def test_bgp_allow_as_in():
expected,
)
- _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"r1" 192.168.1.1/32 route should have arrived'
assert result is None, assertmsg
@@ -212,7 +212,7 @@ def test_bgp_allow_as_in():
expected,
)
- _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"r2" 192.168.1.1/32 route should be gone'
assert result is None, assertmsg
diff --git a/tests/topotests/bgp_vpn_import_nexthop_default_vrf/__init__.py b/tests/topotests/bgp_vpn_import_nexthop_default_vrf/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_vpn_import_nexthop_default_vrf/__init__.py
diff --git a/tests/topotests/bgp_vpn_import_nexthop_default_vrf/r1/frr.conf b/tests/topotests/bgp_vpn_import_nexthop_default_vrf/r1/frr.conf
new file mode 100644
index 0000000000..2a2288cf05
--- /dev/null
+++ b/tests/topotests/bgp_vpn_import_nexthop_default_vrf/r1/frr.conf
@@ -0,0 +1,29 @@
+!
+interface r1-eth0
+ ip address 192.168.179.4/24
+exit
+!
+router bgp 65001
+ bgp router-id 192.168.179.4
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.179.5 remote-as auto
+!
+ address-family ipv4 vpn
+ neighbor 192.168.179.5 activate
+ neighbor 192.168.179.5 next-hop-self
+ exit-address-family
+!
+router bgp 65001 vrf CUSTOMER-A
+ bgp router-id 192.168.0.1
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+!
+ address-family ipv4 unicast
+ label vpn export auto
+ rd vpn export 100:1
+ rt vpn both 100:1
+ export vpn
+ import vpn
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_vpn_import_nexthop_default_vrf/r2/frr.conf b/tests/topotests/bgp_vpn_import_nexthop_default_vrf/r2/frr.conf
new file mode 100644
index 0000000000..6fe07f5622
--- /dev/null
+++ b/tests/topotests/bgp_vpn_import_nexthop_default_vrf/r2/frr.conf
@@ -0,0 +1,34 @@
+!
+interface r2-eth0
+ ip address 192.168.179.5/24
+exit
+!
+interface r2-eth1
+ ip address 192.168.2.2/24
+exit
+!
+router bgp 65002
+ bgp router-id 192.168.179.5
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.179.4 remote-as auto
+!
+ address-family ipv4 vpn
+ neighbor 192.168.179.4 activate
+ neighbor 192.168.179.4 next-hop-self
+ exit-address-family
+!
+router bgp 65002 vrf CUSTOMER-A
+ bgp router-id 192.168.0.2
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+!
+ address-family ipv4 unicast
+ redistribute connected
+ label vpn export auto
+ rd vpn export 100:1
+ rt vpn both 100:1
+ export vpn
+ import vpn
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_vpn_import_nexthop_default_vrf/test_bgp_vpn_import_nexthop_default_vrf.py b/tests/topotests/bgp_vpn_import_nexthop_default_vrf/test_bgp_vpn_import_nexthop_default_vrf.py
new file mode 100644
index 0000000000..ccea88b211
--- /dev/null
+++ b/tests/topotests/bgp_vpn_import_nexthop_default_vrf/test_bgp_vpn_import_nexthop_default_vrf.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+
+ r1.run("ip link add CUSTOMER-A type vrf table 1001")
+ r1.run("ip link set up dev CUSTOMER-A")
+ r1.run("ip link set r1-eth1 master CUSTOMER-A")
+
+ r2.run("ip link add CUSTOMER-A type vrf table 1001")
+ r2.run("ip link set up dev CUSTOMER-A")
+ r2.run("ip link set r2-eth1 master CUSTOMER-A")
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_issue_12502():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ def _bgp_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp vrf CUSTOMER-A ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "192.168.2.0/24": [
+ {
+ "valid": True,
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "path": "65002",
+ "nhVrfName": "default",
+ "nexthops": [
+ {
+ "ip": "192.168.179.5",
+ "hostname": "r1",
+ "afi": "ipv4",
+ "used": True,
+ }
+ ],
+ }
+ ]
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Failed to see 192.168.2.0/24 with a valid next-hop"
+
+ def _vrf_route_imported_to_zebra():
+ output = json.loads(
+ r1.vtysh_cmd("show ip route vrf CUSTOMER-A 192.168.2.0/24 json")
+ )
+ expected = {
+ "192.168.2.0/24": [
+ {
+ "prefix": "192.168.2.0/24",
+ "protocol": "bgp",
+ "vrfName": "CUSTOMER-A",
+ "selected": True,
+ "installed": True,
+ "table": 1001,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": True,
+ "ip": "192.168.179.5",
+ "afi": "ipv4",
+ "interfaceName": "r1-eth0",
+ "vrf": "default",
+ "active": True,
+ }
+ ],
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_vrf_route_imported_to_zebra)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert (
+ result is None
+ ), "Failed to see 192.168.2.0/24 to be imported into default VRF (Zebra)"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_init.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_init.json
index 2769c6eb3f..cb072e3c60 100644
--- a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_init.json
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_init.json
@@ -7,6 +7,9 @@
"routes": {
"10.204.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.204.0.0",
"prefixLen": 24,
@@ -63,6 +66,9 @@
],
"10.201.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.201.0.0",
"prefixLen": 24,
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r1_vrf1.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r1_vrf1.json
index 488dc4aab9..43100aad2d 100644
--- a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r1_vrf1.json
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r1_vrf1.json
@@ -7,6 +7,9 @@
"routes": {
"10.204.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.204.0.0",
"prefixLen": 24,
@@ -63,6 +66,9 @@
],
"10.201.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.201.0.0",
"prefixLen": 24,
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf2.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf2.json
index b751756fce..b11b16bca2 100644
--- a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf2.json
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf2.json
@@ -7,6 +7,9 @@
"routes": {
"10.204.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.204.0.0",
"prefixLen": 24,
@@ -63,6 +66,9 @@
],
"10.201.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.201.0.0",
"prefixLen": 24,
@@ -161,6 +167,9 @@
"routes": {
"10.202.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.202.0.0",
"prefixLen": 24,
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf3.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf3.json
index 49d4066e19..643aae401d 100644
--- a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf3.json
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vrf_all_routes_plus_r2_vrf3.json
@@ -7,6 +7,9 @@
"routes": {
"10.204.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.204.0.0",
"prefixLen": 24,
@@ -63,6 +66,9 @@
],
"10.201.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.201.0.0",
"prefixLen": 24,
@@ -161,6 +167,9 @@
"routes": {
"10.203.0.0/24": [
{
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
"pathFrom": "external",
"prefix": "10.203.0.0",
"prefixLen": 24,
diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json
index f664bb6b52..768bffbe9d 100644
--- a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json
@@ -15,16 +15,15 @@
"origin": "incomplete",
"nexthops": [
{
- "ip": "::ffff:c000:202",
"hostname": "ce1",
"afi": "ipv6",
- "scope": "global"
+ "scope": "global",
+ "used": true
},
{
"hostname": "ce1",
"afi": "ipv6",
- "scope": "link-local",
- "used": true
+ "scope": "link-local"
}
]
}
diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json
index 3498ed4326..1e93715270 100644
--- a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json
@@ -17,16 +17,15 @@
"nhVrfName": "vrf10",
"nexthops": [
{
- "ip": "::ffff:c000:202",
"hostname": "pe1",
"afi": "ipv6",
- "scope": "global"
+ "scope": "global",
+ "used": true
},
{
"hostname": "pe1",
"afi": "ipv6",
- "scope": "link-local",
- "used": true
+ "scope": "link-local"
}
]
}
diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py b/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py
index 7a6d068e56..5dc917bd1a 100644
--- a/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py
+++ b/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py
@@ -71,25 +71,25 @@ def test_bgp_weighted_ecmp_recursive():
"ip": "192.168.24.4",
"active": True,
"recursive": True,
- "weight": 204,
+ "weight": 203,
},
{
"ip": "192.168.12.2",
"active": True,
"resolver": True,
- "weight": 204,
+ "weight": 203,
},
{
"ip": "192.168.35.5",
"active": True,
"recursive": True,
- "weight": 255,
+ "weight": 254,
},
{
"ip": "192.168.13.3",
"active": True,
"resolver": True,
- "weight": 255,
+ "weight": 254,
},
],
}
diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py
index a2315138cc..44536e945e 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -18,12 +18,11 @@ from pathlib import Path
import lib.fixtures
import pytest
from lib.common_config import generate_support_bundle
-from lib.micronet_compat import Mininet
from lib.topogen import diagnose_env, get_topogen
from lib.topolog import get_test_logdir, logger
from lib.topotest import json_cmp_result
from munet import cli
-from munet.base import Commander, proc_error
+from munet.base import BaseMunet, Commander, proc_error
from munet.cleanup import cleanup_current, cleanup_previous
from munet.config import ConfigOptionsProxy
from munet.testing.util import pause_test
@@ -32,7 +31,7 @@ from lib import topolog, topotest
try:
# Used by munet native tests
- from munet.testing.fixtures import event_loop, unet # pylint: disable=all # noqa
+ from munet.testing.fixtures import unet # pylint: disable=all # noqa
@pytest.fixture(scope="module")
def rundir_module(pytestconfig):
@@ -86,7 +85,7 @@ def pytest_addoption(parser):
parser.addoption(
"--cli-on-error",
action="store_true",
- help="Mininet cli on test failure",
+ help="Munet cli on test failure",
)
parser.addoption(
@@ -711,7 +710,7 @@ def pytest_runtest_makereport(item, call):
wait_for_procs = []
# Really would like something better than using this global here.
# Not all tests use topogen though so get_topogen() won't work.
- for node in Mininet.g_mnet_inst.hosts.values():
+ for node in BaseMunet.g_unet.hosts.values():
pause = True
if is_tmux:
@@ -720,13 +719,15 @@ def pytest_runtest_makereport(item, call):
if not isatty
else None
)
- Commander.tmux_wait_gen += 1
- wait_for_channels.append(channel)
+ # If we don't have a tty to pause on pause for tmux windows to exit
+ if channel is not None:
+ Commander.tmux_wait_gen += 1
+ wait_for_channels.append(channel)
pane_info = node.run_in_window(
error_cmd,
new_window=win_info is None,
- background=True,
+ background=not isatty,
title="{} ({})".format(title, node.name),
name=title,
tmux_target=win_info,
@@ -737,9 +738,13 @@ def pytest_runtest_makereport(item, call):
win_info = pane_info
elif is_xterm:
assert isinstance(pane_info, subprocess.Popen)
- wait_for_procs.append(pane_info)
+ # If we don't have a tty to pause on pause for xterm procs to exit
+ if not isatty:
+ wait_for_procs.append(pane_info)
# Now wait on any channels
+ if wait_for_channels or wait_for_procs:
+ logger.info("Pausing for error command windows to exit")
for channel in wait_for_channels:
logger.debug("Waiting on TMUX channel %s", channel)
commander.cmd_raises([commander.get_exec_path("tmux"), "wait", channel])
@@ -752,10 +757,10 @@ def pytest_runtest_makereport(item, call):
if error and item.config.option.cli_on_error:
# Really would like something better than using this global here.
# Not all tests use topogen though so get_topogen() won't work.
- if Mininet.g_mnet_inst:
- cli.cli(Mininet.g_mnet_inst, title=title, background=False)
+ if BaseMunet.g_unet:
+ cli.cli(BaseMunet.g_unet, title=title, background=False)
else:
- logger.error("Could not launch CLI b/c no mininet exists yet")
+ logger.error("Could not launch CLI b/c no munet exists yet")
if pause and isatty:
pause_test()
@@ -800,9 +805,20 @@ done"""
def pytest_terminal_summary(terminalreporter, exitstatus, config):
# Only run if we are the top level test runner
is_xdist_worker = "PYTEST_XDIST_WORKER" in os.environ
+ is_xdist = os.environ["PYTEST_XDIST_MODE"] != "no"
if config.option.cov_topotest and not is_xdist_worker:
coverage_finish(terminalreporter, config)
+ if (
+ is_xdist
+ and not is_xdist_worker
+ and (
+ bool(config.getoption("--pause"))
+ or bool(config.getoption("--pause-at-end"))
+ )
+ ):
+ pause_test("pause-at-end")
+
#
# Add common fixtures available to all tests as parameters
diff --git a/tests/topotests/dump_of_bgp/r1/frr.conf b/tests/topotests/dump_of_bgp/r1/frr.conf
new file mode 100644
index 0000000000..d677e2007e
--- /dev/null
+++ b/tests/topotests/dump_of_bgp/r1/frr.conf
@@ -0,0 +1,12 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ neighbor 192.168.1.2 capability dynamic
+ !
+!
diff --git a/tests/topotests/dump_of_bgp/r2/frr.conf b/tests/topotests/dump_of_bgp/r2/frr.conf
new file mode 100644
index 0000000000..d68d13d075
--- /dev/null
+++ b/tests/topotests/dump_of_bgp/r2/frr.conf
@@ -0,0 +1,17 @@
+!
+int lo
+ ip address 10.10.10.10/32
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/dump_of_bgp/test_dump_of_bgp.py b/tests/topotests/dump_of_bgp/test_dump_of_bgp.py
new file mode 100644
index 0000000000..1359c57f31
--- /dev/null
+++ b/tests/topotests/dump_of_bgp/test_dump_of_bgp.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2024 by Nvidia Corporation
+# Donald Sharp <sharpd@nvidia.com>
+
+import os
+import sys
+import json
+import pytest
+import functools
+from lib.topolog import logger
+
+pytestmark = [pytest.mark.bgpd]
+
+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, get_topogen
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_dump():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Test the ability for bgp to dump a file specified")
+ r1 = tgen.gears["r1"]
+
+ logger.info("Converge BGP")
+ def _converge():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json"))
+ expected = {
+ "paths": [
+ {
+ "valid": True,
+ "nexthops": [
+ {
+ "hostname": "r2",
+ "accessible": True,
+ }
+ ],
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _converge,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't converge"
+
+ logger.info("Dumping file")
+ ####
+ # Create a dump file
+ ####
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ dump bgp all bgp_dump.file
+ """
+ )
+
+ def _test_dump_file_existence():
+ dump_file = "{}/r1/bgp_dump.file".format(tgen.logdir)
+
+ logger.info("Looking for {} file".format(dump_file))
+ logger.info(os.path.isfile(dump_file))
+ return os.path.isfile(dump_file)
+
+ logger.info("Ensure that Log file exists")
+ _, result = topotest.run_and_expect(_test_dump_file_existence, True, count=30, wait = 3)
+ assert result is True
+
+ # At this point all we have done is ensure that the dump file
+ # is generated for r1. What is correctness of the dump anyways?
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/example_munet/r1/frr.conf b/tests/topotests/example_munet/r1/frr.conf
index 468bda5e01..692e4ceb47 100644
--- a/tests/topotests/example_munet/r1/frr.conf
+++ b/tests/topotests/example_munet/r1/frr.conf
@@ -4,4 +4,4 @@ service integrated-vtysh-config
interface eth0
ip address 10.0.1.1/24
-ip route 10.0.0.0/8 blackhole
+ip route 10.0.2.0/24 10.0.1.2
diff --git a/tests/topotests/example_munet/r2/frr.conf b/tests/topotests/example_munet/r2/frr.conf
index 77d9892485..da3f15b801 100644
--- a/tests/topotests/example_munet/r2/frr.conf
+++ b/tests/topotests/example_munet/r2/frr.conf
@@ -5,6 +5,4 @@ interface eth0
ip address 10.0.1.2/24
interface eth1
- ip address 10.0.2.2/24
-
-ip route 10.0.0.0/8 blackhole
+ ip address 10.0.2.2/24 \ No newline at end of file
diff --git a/tests/topotests/example_munet/r3/frr.conf b/tests/topotests/example_munet/r3/frr.conf
index e0839e6d8a..84527b34df 100644
--- a/tests/topotests/example_munet/r3/frr.conf
+++ b/tests/topotests/example_munet/r3/frr.conf
@@ -4,4 +4,4 @@ service integrated-vtysh-config
interface eth0
ip address 10.0.2.3/24
-ip route 10.0.0.0/8 blackhole
+ip route 10.0.1.0/24 10.0.2.2 \ No newline at end of file
diff --git a/tests/topotests/example_munet/test_munet.py b/tests/topotests/example_munet/test_munet.py
index 0d9599fa54..71052099c4 100644
--- a/tests/topotests/example_munet/test_munet.py
+++ b/tests/topotests/example_munet/test_munet.py
@@ -5,6 +5,22 @@
#
# Copyright (c) 2023, LabN Consulting, L.L.C.
#
+from munet.testing.util import retry
+
+
+@retry(retry_timeout=10)
+def wait_for_route(r, p):
+ o = r.cmd_raises(f"ip route show {p}")
+ assert p in o
+
+
async def test_native_test(unet):
- o = unet.hosts["r1"].cmd_nostatus("ip addr")
+ r1 = unet.hosts["r1"]
+ o = r1.cmd_nostatus("ip addr")
print(o)
+
+ wait_for_route(r1, "10.0.2.0/24")
+
+ r1.cmd_raises("ping -c1 10.0.1.2")
+ r1.cmd_raises("ping -c1 10.0.2.2")
+ r1.cmd_raises("ping -c1 10.0.2.3")
diff --git a/tests/topotests/forwarding_on_off/r1/frr.conf b/tests/topotests/forwarding_on_off/r1/frr.conf
new file mode 100644
index 0000000000..677ba8f63e
--- /dev/null
+++ b/tests/topotests/forwarding_on_off/r1/frr.conf
@@ -0,0 +1,14 @@
+int lo
+ ip address 10.1.1.1/32
+ ip address 10:1::1:1/128
+
+int eth0
+ ip address 10.1.2.1/24
+ ipv6 address 10:1::2:1/120
+
+ip route 10.1.1.2/32 10.1.2.2
+ip route 10.1.1.3/32 10.1.2.2
+ip route 10.1.3.0/24 10.1.2.2
+ipv6 route 10:1::1:2/128 10:1::2:2
+ipv6 route 10:1::1:3/128 10:1::2:2
+ipv6 route 10:1::3:0/90 10:1::2:2 \ No newline at end of file
diff --git a/tests/topotests/forwarding_on_off/r2/frr.conf b/tests/topotests/forwarding_on_off/r2/frr.conf
new file mode 100644
index 0000000000..b6da6e2231
--- /dev/null
+++ b/tests/topotests/forwarding_on_off/r2/frr.conf
@@ -0,0 +1,19 @@
+no ip forwarding
+no ipv6 forwarding
+
+int lo
+ ip address 10.1.1.2/32
+ ipv6 address 10:1::1:2/128
+
+int eth0
+ ip address 10.1.2.2/24
+ ipv6 address 10:1::2:2/120
+
+int eth1
+ ip address 10.1.3.2/24
+ ipv6 address 10:1::3:2/120
+
+ip route 10.1.1.1/32 10.1.2.1
+ip route 10.1.1.3/32 10.1.3.3
+ipv6 route 10:1::1:1/128 10:1::2:1
+ipv6 route 10:1::1:3/128 10:1::3:3
diff --git a/tests/topotests/forwarding_on_off/r3/frr.conf b/tests/topotests/forwarding_on_off/r3/frr.conf
new file mode 100644
index 0000000000..ea05f18400
--- /dev/null
+++ b/tests/topotests/forwarding_on_off/r3/frr.conf
@@ -0,0 +1,15 @@
+int lo
+ ip address 10.1.1.3/32
+ ipv6 address 10:1::1:3/128
+
+int eth0
+ ip address 10.1.3.3/24
+ ipv6 address 10:1::3:3/120
+
+
+ip route 10.1.1.1/32 10.1.3.2
+ip route 10.1.1.2/32 10.1.3.2
+ip route 10.1.2.0/24 10.1.3.2
+ipv6 route 10:1::1:1/128 10:1::3:2
+ipv6 route 10:1::1:2/128 10:1::3:2
+ipv6 route 10:1::2:0/120 10:1::3:2 \ No newline at end of file
diff --git a/tests/topotests/forwarding_on_off/test_forwarding_on_off.py b/tests/topotests/forwarding_on_off/test_forwarding_on_off.py
new file mode 100644
index 0000000000..fa0483888c
--- /dev/null
+++ b/tests/topotests/forwarding_on_off/test_forwarding_on_off.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+#
+# test_forwarding_on_off.py
+#
+# Copyright (c) 2024 by Nvidia Corporation
+# Donald Sharp
+#
+
+"""
+test_forwarding_on_off.py: Test that forwarding is turned off then back on
+
+"""
+
+import ipaddress
+import json
+import pytest
+import sys
+import time
+
+from functools import partial
+from lib import topotest
+from lib.topogen import Topogen, get_topogen
+from lib.topolog import logger
+from lib.checkping import check_ping
+
+pytestmark = [
+ pytest.mark.staticd,
+]
+
+
+def build_topo(tgen):
+ """Build the topology used by all tests below."""
+
+ # Create 3 routers
+ r1 = tgen.add_router("r1")
+ r2 = tgen.add_router("r2")
+ r3 = tgen.add_router("r3")
+
+ # Add a link between r1 <-> r2 and r2 <-> r3
+ tgen.add_link(r1, r2, ifname1="eth0", ifname2="eth0")
+ tgen.add_link(r2, r3, ifname1="eth1", ifname2="eth0")
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, router in router_list.items():
+ router.load_frr_config("frr.conf")
+
+ tgen.start_router()
+
+
+def teardown_module():
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_no_forwarding():
+ tgen = get_topogen()
+ r2 = tgen.gears["r2"]
+
+ def _no_forwarding(family, status):
+ logger.info("Testing for: {} {}".format(family, status))
+ rc, o, e = r2.net.cmd_status(
+ 'vtysh -c "show zebra" | grep "{}" | grep "{}"'.format(family, status)
+ )
+
+ logger.info("Output: {}".format(o))
+ return rc
+
+ test_func = partial(_no_forwarding, "v4 Forwarding", "Off")
+ _, result = topotest.run_and_expect(test_func, 0, count=15, wait=1)
+ assert result == 0
+
+ test_func = partial(_no_forwarding, "v6 Forwarding", "Off")
+ _, result = topotest.run_and_expect(test_func, 0, count=15, wait=1)
+ assert result == 0
+
+ logger.info("Sending pings that should fail")
+ check_ping("r1", "10.1.1.3", False, 10, 1)
+ check_ping("r1", "10:1::1:3", False, 10, 1)
+
+ logger.info("Turning on Forwarding")
+ r2.vtysh_cmd("conf\nip forwarding\nipv6 forwarding")
+
+ test_func = partial(_no_forwarding, "v4 Forwarding", "On")
+ _, result = topotest.run_and_expect(test_func, 0, count=15, wait=1)
+ assert result == 0
+
+ test_func = partial(_no_forwarding, "v6 Forwarding", "On")
+ _, result = topotest.run_and_expect(test_func, 0, count=15, wait=1)
+ assert result == 0
+
+ check_ping("r1", "10.1.1.3", True, 10, 1)
+ check_ping("r1", "10:1::1:3", True, 10, 1)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py
index a574f43d89..1cec2f16f0 100644
--- a/tests/topotests/isis_topo1/test_isis_topo1.py
+++ b/tests/topotests/isis_topo1/test_isis_topo1.py
@@ -623,7 +623,7 @@ def test_isis_hello_padding_during_adjacency_formation():
assert result is True, result
-@retry(retry_timeout=5)
+@retry(retry_timeout=10)
def check_last_iih_packet_for_padding(router, expect_padding):
logfilename = "{}/{}".format(router.gearlogdir, "isisd.log")
last_hello_packet_line = None
diff --git a/tests/topotests/kinds.yaml b/tests/topotests/kinds.yaml
index 5f4b61d4b7..20c819c79c 100644
--- a/tests/topotests/kinds.yaml
+++ b/tests/topotests/kinds.yaml
@@ -10,9 +10,10 @@ kinds:
/usr/lib/frr/frrinit.sh stop
volumes:
- "./%NAME%:/etc/frr"
+ - "%RUNDIR%/var.lib.frr:/var/lib/frr"
- "%RUNDIR%/var.log.frr:/var/log/frr"
- "%RUNDIR%/var.run.frr:/var/run/frr"
- - "%RUNDIR%/var.lib.frr:/var/lib/frr"
+ - "%RUNDIR%/var.tmp.frr:/var/tmp/frr"
cap-add:
- SYS_ADMIN
- AUDIT_WRITE
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index e856c23d36..f34c48b890 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -936,7 +936,7 @@ def generate_support_bundle():
tgen = get_topogen()
if tgen is None:
- logger.warn(
+ logger.warning(
"Support bundle attempted to be generated, but topogen is not being used"
)
return True
@@ -1847,7 +1847,13 @@ def retry(retry_timeout, initial_wait=0, expected=True, diag_pct=0.75):
while True:
seconds_left = (retry_until - datetime.now()).total_seconds()
try:
- ret = func(*args, **kwargs)
+ try:
+ ret = func(*args, seconds_left=seconds_left, **kwargs)
+ except TypeError as error:
+ if "seconds_left" not in str(error):
+ raise
+ ret = func(*args, **kwargs)
+
logger.debug("Function returned %s", ret)
negative_result = ret is False or is_string(ret)
@@ -1868,7 +1874,7 @@ def retry(retry_timeout, initial_wait=0, expected=True, diag_pct=0.75):
return saved_failure
except Exception as error:
- logger.info("Function raised exception: %s", str(error))
+ logger.info('Function raised exception: "%s"', repr(error))
ret = error
if seconds_left < 0 and saved_failure:
@@ -3365,7 +3371,7 @@ def verify_rib(
found_hops = [
rib_r["ip"]
for rib_r in rib_routes_json[st_rt][0]["nexthops"]
- if "ip" in rib_r
+ if "ip" in rib_r and "active" in rib_r
]
# If somehow key "ip" is not found in nexthops JSON
diff --git a/tests/topotests/lib/grpc-query.py b/tests/topotests/lib/grpc-query.py
index 13b63614c7..cc7b1ad207 100755
--- a/tests/topotests/lib/grpc-query.py
+++ b/tests/topotests/lib/grpc-query.py
@@ -40,7 +40,6 @@ try:
try:
sys.path[0:0] = [tmpdir]
- print(sys.path)
import frr_northbound_pb2
import frr_northbound_pb2_grpc
diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py
index cc56ffdd8c..369a794ebc 100644
--- a/tests/topotests/lib/pim.py
+++ b/tests/topotests/lib/pim.py
@@ -332,6 +332,13 @@ def create_igmp_config(tgen, topo, input_dict=None, build=False):
cmd = "no {}".format(cmd)
config_data.append(cmd)
+ if attribute == "static-group":
+ 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":
@@ -1600,7 +1607,7 @@ def verify_pim_rp_info(
if type(group_addresses) is not list:
group_addresses = [group_addresses]
- if type(oif) is not list:
+ if oif is not None and type(oif) is not list:
oif = [oif]
for grp in group_addresses:
@@ -1739,6 +1746,49 @@ def verify_pim_rp_info(
@retry(retry_timeout=60, diag_pct=0)
+def verify_pim_rp_info_is_empty(tgen, dut, af="ipv4"):
+ """
+ Verify pim rp info by running "show ip pim rp-info" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `dut`: device under test
+
+ Usage
+ -----
+ dut = "r1"
+ result = verify_pim_rp_info_is_empty(tgen, dut)
+
+ 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]
+
+ ip_cmd = "ip"
+ if af == "ipv6":
+ ip_cmd = "ipv6"
+
+ logger.info("[DUT: %s]: Verifying %s rp info", dut, ip_cmd)
+ cmd = "show {} pim rp-info json".format(ip_cmd)
+ show_ip_rp_info_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ if show_ip_rp_info_json:
+ errormsg = "[DUT %s]: Verifying empty rp-info [FAILED]!!" % (dut)
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+@retry(retry_timeout=60, diag_pct=0)
def verify_pim_state(
tgen,
dut,
@@ -2404,10 +2454,11 @@ def clear_igmp_interfaces(tgen, dut):
# 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)
+ if group in group_after_clear:
+ 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!!]")
@@ -2744,6 +2795,48 @@ def scapy_send_bsr_raw_packet(tgen, topo, senderRouter, receiverRouter, packet=N
return True
+def scapy_send_autorp_raw_packet(tgen, senderRouter, senderInterface, packet=None):
+ """
+ Using scapy Raw() method to send AutoRP raw packet from one FRR
+ to other
+
+ Parameters:
+ -----------
+ * `tgen` : Topogen object
+ * `senderRouter` : Sender router
+ * `senderInterface` : SenderInterface
+ * `packet` : AutoRP packet in raw format
+
+ returns:
+ --------
+ errormsg or True
+ """
+
+ global CWD
+ result = ""
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ python3_path = tgen.net.get_exec_path(["python3", "python"])
+ # send_bsr_packet.py has no direct ties to bsr, just sends a raw packet out
+ # a given interface, so just reuse it
+ script_path = os.path.join(CWD, "send_bsr_packet.py")
+ node = tgen.net[senderRouter]
+
+ cmd = [
+ python3_path,
+ script_path,
+ packet,
+ senderInterface,
+ "--interval=1",
+ "--count=1",
+ ]
+ logger.info("Scapy cmd: \n %s", cmd)
+ node.cmd_raises(cmd)
+
+ logger.debug("Exiting lib API: scapy_send_autorp_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
@@ -4254,6 +4347,143 @@ def verify_local_igmp_groups(tgen, dut, interface, group_addresses):
return True
+@retry(retry_timeout=62)
+def verify_static_groups(tgen, dut, interface, group_addresses):
+ """
+ Verify static groups are received from an intended interface
+ by running "show ip igmp static-group json" command
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `dut`: device under test
+ * `interface`: interface, from which IGMP groups are configured
+ * `group_addresses`: IGMP group address
+
+ Usage
+ -----
+ dut = "r1"
+ interface = "r1-r0-eth0"
+ group_address = "225.1.1.1"
+ result = verify_static_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 static groups received:", dut)
+ show_static_group_json = run_frr_cmd(
+ rnode, "show ip igmp static-group json", isjson=True
+ )
+
+ if type(group_addresses) is not list:
+ group_addresses = [group_addresses]
+
+ if interface not in show_static_group_json:
+ errormsg = (
+ "[DUT %s]: Verifying static group received"
+ " from interface %s [FAILED]!! " % (dut, interface)
+ )
+ return errormsg
+
+ for grp_addr in group_addresses:
+ found = False
+ for index in show_static_group_json[interface]["groups"]:
+ if index["group"] == grp_addr:
+ found = True
+ break
+ if not found:
+ errormsg = (
+ "[DUT %s]: Verifying static group received"
+ " from interface %s [FAILED]!! "
+ " Expected: %s " % (dut, interface, grp_addr)
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: Verifying static group %s received "
+ "from interface %s [PASSED]!! ",
+ dut,
+ grp_addr,
+ interface,
+ )
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+@retry(retry_timeout=62)
+def verify_local_igmp_proxy_groups(
+ tgen, dut, group_addresses_present, group_addresses_not_present
+):
+ """
+ Verify igmp proxy groups are as expected by running
+ "show ip igmp static-group json" command
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `dut`: device under test
+ * `group_addresses_present`: IGMP group addresses which should
+ currently be proxied
+ * `group_addresses_not_present`: IGMP group addresses which should
+ not currently be proxied
+
+ Usage
+ -----
+ dut = "r1"
+ group_addresses_present = "225.1.1.1"
+ group_addresses_not_present = "225.2.2.2"
+ result = verify_igmp_proxy_groups(tgen, dut, group_p, group_np)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ if dut not in tgen.routers():
+ errormsg = "[DUT %s]: Device not found!"
+ return errormsg
+
+ rnode = tgen.routers()[dut]
+
+ logger.info("[DUT: %s]: Verifying local IGMP proxy groups:", dut)
+
+ out = rnode.vtysh_cmd("show ip igmp proxy json", isjson=True)
+ groups = [g["group"] if "group" in g else None for g in out["r1-eth1"]["groups"]]
+
+ if type(group_addresses_present) is not list:
+ group_addresses_present = [group_addresses_present]
+ if type(group_addresses_not_present) is not list:
+ group_addresses_not_present = [group_addresses_not_present]
+
+ for test_addr in group_addresses_present:
+ if not test_addr in groups:
+ errormsg = (
+ "[DUT %s]: Verifying local IGMP proxy joins FAILED!! "
+ " Expected but not found: %s " % (dut, test_addr)
+ )
+ return errormsg
+
+ for test_addr in group_addresses_not_present:
+ if test_addr in groups:
+ errormsg = (
+ "[DUT %s]: Verifying local IGMP proxy join removed FAILED!! "
+ " Unexpected but found: %s " % (dut, test_addr)
+ )
+ return errormsg
+
+ return True
+
+
def verify_pim_interface_traffic(tgen, input_dict, return_stats=True, addr_type="ipv4"):
"""
Verify ip pim interface traffic by running
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index f49e30ea5f..14dd61b077 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -492,7 +492,16 @@ class Topogen(object):
"Errors found post shutdown - details follow: {}".format(errors)
)
- self.net.stop()
+ try:
+ self.net.stop()
+
+ except OSError as error:
+ # OSError exception is raised when mininet tries to stop switch
+ # though switch is stopped once but mininet tries to stop same
+ # switch again, where it ended up with exception
+
+ logger.info(error)
+ logger.info("Exception ignored: switch is already stopped")
def get_exabgp_cmd(self):
if not self.exabgp_cmd:
@@ -832,10 +841,10 @@ class TopoRouter(TopoGear):
for daemon in self.RD:
# This will not work for all daemons
daemonstr = self.RD.get(daemon).rstrip("d")
- if daemonstr == "pim":
- grep_cmd = "grep 'ip {}' {}".format(daemonstr, source_path)
+ if daemonstr == "path":
+ grep_cmd = "grep 'candidate-path' {}".format(source_path)
else:
- grep_cmd = "grep 'router {}' {}".format(daemonstr, source_path)
+ grep_cmd = "grep -w '{}' {}".format(daemonstr, source_path)
result = self.run(grep_cmd, warn=False).strip()
if result:
self.load_config(daemon, "")
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 5a8c2e5964..d15fefc039 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -396,6 +396,9 @@ def run_and_expect(func, what, count=20, wait=3):
waiting `wait` seconds between tries. By default it tries 20 times with
3 seconds delay between tries.
+ Changing default count/wait values, please change them below also for
+ `minimum_wait`, and `minimum_count`.
+
Returns (True, func-return) on success or
(False, func-return) on failure.
@@ -414,13 +417,18 @@ def run_and_expect(func, what, count=20, wait=3):
# Just a safety-check to avoid running topotests with very
# small wait/count arguments.
+ # If too low count/wait values are defined, override them
+ # with the minimum values.
+ minimum_count = 20
+ minimum_wait = 3
+ minimum_wait_time = 15 # The overall minimum seconds for the test to wait
wait_time = wait * count
- if wait_time < 5:
- assert (
- wait_time >= 5
- ), "Waiting time is too small (count={}, wait={}), adjust timer values".format(
- count, wait
+ if wait_time < minimum_wait_time:
+ logger.warning(
+ f"Waiting time is too small (count={count}, wait={wait}), using default values (count={minimum_count}, wait={minimum_wait})"
)
+ count = minimum_count
+ wait = minimum_wait
logger.debug(
"'{}' polling started (interval {} secs, maximum {} tries)".format(
diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json
index 435d7336fc..948f4e6c23 100644
--- a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json
+++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json
@@ -38,7 +38,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -66,7 +67,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -94,7 +96,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -122,7 +125,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -245,7 +249,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -271,7 +276,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -297,7 +303,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -323,7 +330,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -360,7 +368,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -388,7 +397,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -416,7 +426,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -444,7 +455,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -479,7 +491,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -505,7 +518,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -531,7 +545,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -557,7 +572,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -573,4 +589,3 @@
]
}
}
-
diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json
index 1a1f6480fa..30daecf16e 100644
--- a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json
+++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json
@@ -38,7 +38,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -66,7 +67,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -94,7 +96,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -122,7 +125,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -245,7 +249,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -271,7 +276,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -297,7 +303,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -323,7 +330,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -360,7 +368,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -388,7 +397,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -416,7 +426,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -444,7 +455,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -479,7 +491,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -505,7 +518,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -531,7 +545,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -557,7 +572,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -607,7 +623,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -635,7 +652,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -663,7 +681,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -691,7 +710,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -814,7 +834,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -840,7 +861,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -866,7 +888,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -892,7 +915,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -929,7 +953,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -957,7 +982,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -985,7 +1011,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -1013,7 +1040,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -1048,7 +1076,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -1074,7 +1103,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -1100,7 +1130,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -1126,7 +1157,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json
index 2e2b8ec7ad..b1124bd7bb 100644
--- a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json
+++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json
@@ -34,7 +34,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -62,7 +63,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -90,7 +92,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -118,7 +121,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -241,7 +245,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -267,7 +272,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -293,7 +299,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -319,7 +326,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -356,7 +364,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -384,7 +393,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -412,7 +422,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -440,7 +451,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -475,7 +487,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -501,7 +514,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -527,7 +541,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -553,7 +568,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json
index 2e2b8ec7ad..70c8798b31 100644
--- a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json
+++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json
@@ -34,7 +34,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -62,7 +63,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -90,7 +92,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -118,7 +121,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -241,7 +245,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -267,7 +272,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -293,7 +299,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -319,7 +326,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -356,7 +364,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -384,7 +393,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -412,7 +422,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -440,7 +451,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -475,7 +487,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -501,7 +514,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -527,7 +541,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -553,7 +568,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib.json b/tests/topotests/mgmt_oper/oper-results/result-lib.json
index 1a1f6480fa..0b2a9fa427 100644
--- a/tests/topotests/mgmt_oper/oper-results/result-lib.json
+++ b/tests/topotests/mgmt_oper/oper-results/result-lib.json
@@ -38,7 +38,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -66,7 +67,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -94,7 +96,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -122,7 +125,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -245,7 +249,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -271,7 +276,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -297,7 +303,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -323,7 +330,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -360,7 +368,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -388,7 +397,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -416,7 +426,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -444,7 +455,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -479,7 +491,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -505,7 +518,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -531,7 +545,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -557,7 +572,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -607,7 +623,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -635,7 +652,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -663,7 +681,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -691,7 +710,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -814,7 +834,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -840,7 +861,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -866,7 +888,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -892,7 +915,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -929,7 +953,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -957,7 +982,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -985,7 +1011,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -1013,7 +1040,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -1048,7 +1076,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -1074,7 +1103,8 @@
"gateway": "",
"interface": "r1-eth2",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -1100,7 +1130,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -1126,7 +1157,8 @@
"gateway": "",
"interface": "r1-eth3",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
diff --git a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json
index 956d3a8922..769c1f73a5 100644
--- a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json
+++ b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json
@@ -34,7 +34,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -62,7 +63,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -90,7 +92,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -118,7 +121,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
diff --git a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json
index 2e2b8ec7ad..c740f592f7 100644
--- a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json
+++ b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json
@@ -34,7 +34,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -62,7 +63,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -90,7 +92,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -118,7 +121,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -241,7 +245,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -267,7 +272,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -293,7 +299,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -319,7 +326,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -356,7 +364,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -384,7 +393,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -412,7 +422,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -440,7 +451,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -475,7 +487,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -501,7 +514,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -527,7 +541,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
@@ -553,7 +568,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
diff --git a/tests/topotests/mgmt_oper/oper.py b/tests/topotests/mgmt_oper/oper.py
index 934093aeee..f54e64ae18 100644
--- a/tests/topotests/mgmt_oper/oper.py
+++ b/tests/topotests/mgmt_oper/oper.py
@@ -63,7 +63,7 @@ def disable_debug(router):
@retry(retry_timeout=30, initial_wait=1)
-def _do_oper_test(tgen, qr):
+def _do_oper_test(tgen, qr, seconds_left=None):
r1 = tgen.gears["r1"].net
qcmd = (
@@ -80,6 +80,8 @@ def _do_oper_test(tgen, qr):
expected = open(qr[1], encoding="ascii").read()
output = r1.cmd_nostatus(qcmd.format(qr[0], qr[2] if len(qr) > 2 else ""))
+ diag = logging.debug if seconds_left else logging.warning
+
try:
ojson = json.loads(output)
except json.decoder.JSONDecodeError as error:
@@ -92,28 +94,31 @@ def _do_oper_test(tgen, qr):
logging.error(
"Error decoding json exp result: %s\noutput:\n%s", error, expected
)
+ diag("FILE: {}".format(qr[1]))
raise
if dd_json_cmp:
cmpout = json_cmp(ojson, ejson, exact_match=True)
if cmpout:
- logging.warning(
+ diag(
"-------DIFF---------\n%s\n---------DIFF----------",
pprint.pformat(cmpout),
)
else:
cmpout = tt_json_cmp(ojson, ejson, exact=True)
if cmpout:
- logging.warning(
+ diag(
"-------EXPECT--------\n%s\n------END-EXPECT------",
json.dumps(ejson, indent=4),
)
- logging.warning(
+ diag(
"--------GOT----------\n%s\n-------END-GOT--------",
json.dumps(ojson, indent=4),
)
-
- assert cmpout is None
+ diag("----diff---\n{}".format(cmpout))
+ diag("Command: {}".format(qcmd.format(qr[0], qr[2] if len(qr) > 2 else "")))
+ diag("File: {}".format(qr[1]))
+ return cmpout
def do_oper_test(tgen, query_results):
diff --git a/tests/topotests/mgmt_oper/r1/frr-yanglib.conf b/tests/topotests/mgmt_oper/r1/frr-yanglib.conf
new file mode 100644
index 0000000000..f37766b158
--- /dev/null
+++ b/tests/topotests/mgmt_oper/r1/frr-yanglib.conf
@@ -0,0 +1,10 @@
+log timestamp precision 6
+log file frr.log
+
+no debug memstats-at-exit
+
+debug mgmt backend datastore frontend transaction
+
+interface r1-eth0
+ ip address 1.1.1.1/24
+exit
diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-state-mtu.json b/tests/topotests/mgmt_oper/simple-results/result-intf-state-mtu.json
index 60359716d7..018ed99f40 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-intf-state-mtu.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-intf-state-mtu.json
@@ -10,3 +10,4 @@
]
}
}
+
diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-state.json b/tests/topotests/mgmt_oper/simple-results/result-intf-state.json
index 981df024cd..35669fd571 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-intf-state.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-intf-state.json
@@ -15,3 +15,4 @@
]
}
}
+
diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json
index cea4bf5a6b..f85b163bd6 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json
@@ -38,7 +38,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -66,7 +67,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -130,7 +132,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -156,7 +159,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json
index 75414ca045..e2cfec9724 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json
@@ -38,7 +38,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -66,7 +67,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -130,7 +132,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -156,7 +159,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -224,7 +228,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -252,7 +257,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -287,7 +293,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -313,7 +320,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json
index 05382316a3..3567f35a34 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json
@@ -38,7 +38,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -66,7 +67,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -101,7 +103,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -127,7 +130,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json
index 4f40820bb6..d9ca58d25d 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json
@@ -34,7 +34,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -62,7 +63,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -126,7 +128,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -152,7 +155,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json
index 4f40820bb6..d9ca58d25d 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json
@@ -34,7 +34,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -62,7 +63,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -126,7 +128,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -152,7 +155,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib.json b/tests/topotests/mgmt_oper/simple-results/result-lib.json
index 75414ca045..e2cfec9724 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-lib.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-lib.json
@@ -38,7 +38,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -66,7 +67,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -130,7 +132,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -156,7 +159,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -224,7 +228,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -252,7 +257,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -287,7 +293,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -313,7 +320,8 @@
"gateway": "",
"interface": "r1-eth1",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-ipv4-unicast.json b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-ipv4-unicast.json
index 7ce60c3bdb..11766ce9c1 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-ipv4-unicast.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-ipv4-unicast.json
@@ -34,7 +34,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -62,7 +63,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json
index 4f40820bb6..d9ca58d25d 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json
@@ -34,7 +34,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -62,7 +63,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -126,7 +128,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -152,7 +155,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-nokey.json b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-nokey.json
index 7ce60c3bdb..11766ce9c1 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-nokey.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-nokey.json
@@ -34,7 +34,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
@@ -62,7 +63,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight": 1
}
]
}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-prefix.json b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-prefix.json
index 833d418f9a..ef4a4ab131 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-prefix.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-prefix.json
@@ -31,7 +31,8 @@
"gateway": "",
"interface": "r1-eth0",
"active": [null],
- "fib": [null]
+ "fib": [null],
+ "weight":1
}
]
}
diff --git a/tests/topotests/mgmt_oper/test_simple.py b/tests/topotests/mgmt_oper/test_simple.py
index 3b115f6238..2b3d6ff6a5 100644
--- a/tests/topotests/mgmt_oper/test_simple.py
+++ b/tests/topotests/mgmt_oper/test_simple.py
@@ -181,7 +181,7 @@ vtysh -c 'show mgmt get-data /frr-vrf:lib' > ${resdir}/result-lib.json
vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf' > ${resdir}/result-lib-vrf-nokey.json
vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]' > ${resdir}/result-lib-vrf-default.json
vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="red"]' > ${resdir}/result-lib-vrf-red.json
-vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra' > ${resdir}/result-lib-vrf-zebra.json
+vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra' > ${resdir}/result-lib-vrf-ebra.json
vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs' > ${resdir}/result-lib-vrf-zebra-ribs.json
vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib' > ${resdir}/result-ribs-rib-nokeys.json
vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]' > ${resdir}/result-ribs-rib-ipv4-unicast.json
diff --git a/tests/topotests/mgmt_oper/test_yanglib.py b/tests/topotests/mgmt_oper/test_yanglib.py
new file mode 100644
index 0000000000..e094ca5443
--- /dev/null
+++ b/tests/topotests/mgmt_oper/test_yanglib.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+#
+# September 17 2024, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2024, LabN Consulting, L.L.C.
+#
+
+import json
+import pytest
+from lib.topogen import Topogen
+
+pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd]
+
+
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
+ topodef = {"s1": ("r1",)}
+
+ tgen = Topogen(topodef, request.module.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ router.load_frr_config("frr-yanglib.conf")
+
+ tgen.start_router()
+ yield tgen
+ tgen.stop_topology()
+
+
+def test_yang_lib(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"].net
+ output = r1.cmd_nostatus(
+ "vtysh -c 'show mgmt get-data /ietf-yang-library:yang-library'"
+ )
+ ret = json.loads(output)
+ loaded_modules = ret['ietf-yang-library:yang-library']['module-set'][0]['module']
+ assert len(loaded_modules) > 10, "Modules missing from yang-library"
diff --git a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_transit_router_topo3.py b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_transit_router_topo3.py
index 1987001002..8d91826022 100755
--- a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_transit_router_topo3.py
+++ b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_transit_router_topo3.py
@@ -25,6 +25,10 @@ import time
import datetime
from time import sleep
import pytest
+from functools import partial
+
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
@@ -594,6 +598,66 @@ def pre_config_for_source_dr_tests(
result = create_pim_config(tgen, topo, input_dict)
assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ expected = {
+ "r2-s1-eth1.2501": {
+ "state": "up",
+ "address": "10.1.1.1",
+ "neighbors": {
+ "10.1.1.2": {
+ "address": "10.1.1.2",
+ }
+ },
+ "drAddress": "10.1.1.2",
+ }
+ }
+
+ step("Ensure that neighbors have come up on the vlan")
+ r2 = tgen.gears["r2"]
+ test_func = partial(
+ topotest.router_json_cmp,
+ r2,
+ "show ip pim interface r2-s1-eth1.2501 json",
+ expected,
+ )
+ result, _ = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result, "Neighbors did not come up: {}".format(result)
+
+ expected = {
+ "10.1.1.0/24": [
+ {
+ "prefix": "10.1.1.0/24",
+ "prefixLen": 24,
+ "protocol": "ospf",
+ "vrfName": "default",
+ "distance": 110,
+ "metric": 20,
+ "nexthops": [
+ {
+ "ip": "10.0.3.1",
+ "afi": "ipv4",
+ "interfaceName": "r5-r4-eth1",
+ "weight": 1,
+ },
+ {
+ "ip": "10.0.3.1",
+ "afi": "ipv4",
+ "interfaceName": "r5-r4-eth1",
+ "weight": 1,
+ },
+ ],
+ }
+ ]
+ }
+
+ step("Ensure that the vlan route is available where it is needed")
+ r5 = tgen.gears["r5"]
+ test_func = partial(
+ topotest.router_json_cmp, r5, "show ip route 10.1.1.0/24 json", expected
+ )
+
+ result, _ = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result, "vlan routes are not available on r5\n{}".format(result)
+
step("Configure IGMP on R5 port and send IGMP join for groups " "(226.1.1.1-5)")
intf_r5_i2 = topo["routers"]["r5"]["links"]["i2"]["interface"]
diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json
index 715aa1de72..44a7db56f1 100644
--- a/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json
+++ b/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json
@@ -1 +1 @@
-{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
+{"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json
index 3bbcce1370..982157a624 100644
--- a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json
+++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json
@@ -1,5 +1,4 @@
{
- "totalGroups":5,
"watermarkLimit":0,
"l1-i1-eth1":{
"name":"l1-i1-eth1",
@@ -48,4 +47,3 @@
]
}
}
-
diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json
index 876befa1b8..6042ef4dbf 100644
--- a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json
+++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json
@@ -1 +1 @@
-{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
+{"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json
index a3fb496d25..0312c3026d 100644
--- a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json
+++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json
@@ -1,5 +1,4 @@
{
- "totalGroups":5,
"watermarkLimit":0,
"l1-i1-eth1":{
"name":"l1-i1-eth1",
diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json
index 11ac5a01e7..537be377be 100644
--- a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json
+++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json
@@ -1 +1 @@
-{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
+{"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
diff --git a/tests/topotests/multicast_pim_uplink_topo4/multicast_pim_uplink_topo4.json b/tests/topotests/multicast_pim_uplink_topo4/multicast_pim_uplink_topo4.json
new file mode 100644
index 0000000000..dc9e1ac49b
--- /dev/null
+++ b/tests/topotests/multicast_pim_uplink_topo4/multicast_pim_uplink_topo4.json
@@ -0,0 +1,295 @@
+{
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24, "link_local": "disable"},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32},
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "r2-link1": {"ipv4": "auto", "pim": "enable"},
+ "r2-link2": {"ipv4": "auto", "pim": "enable"},
+ "r2-link3": {"ipv4": "auto", "pim": "enable"},
+ "r2-link4": {"ipv4": "auto", "pim": "enable"},
+ "r3-link1": {"ipv4": "auto", "pim": "enable"},
+ "r3-link2": {"ipv4": "auto", "pim": "enable"},
+ "r3-link3": {"ipv4": "auto", "pim": "enable"},
+ "r3-link4": {"ipv4": "auto", "pim": "enable"},
+ "r4": {"ipv4": "auto", "pim": "enable"},
+ "r5": {"ipv4": "auto", "pim": "enable"},
+ "i1": {"ipv4": "auto", "pim": "enable"},
+ "i2": {"ipv4": "auto", "pim": "enable"},
+ "i9": {"ipv4": "auto", "pim": "enable"}
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {},
+ "r1-link2": {},
+ "r1-link3": {},
+ "r1-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1-link1": {},
+ "r1-link2": {},
+ "r1-link3": {},
+ "r1-link4": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "r1-link1": {"ipv4": "auto", "pim": "enable"},
+ "r1-link2": {"ipv4": "auto", "pim": "enable"},
+ "r1-link3": {"ipv4": "auto", "pim": "enable"},
+ "r1-link4": {"ipv4": "auto", "pim": "enable"},
+ "r4-link1": {"ipv4": "auto", "pim": "enable"},
+ "r4-link2": {"ipv4": "auto", "pim": "enable"},
+ "r4-link3": {"ipv4": "auto", "pim": "enable"},
+ "r4-link4": {"ipv4": "auto", "pim": "enable"},
+ "i3": {"ipv4": "auto", "pim": "enable"},
+ "i4": {"ipv4": "auto", "pim": "enable"}
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {},
+ "r2-link2": {},
+ "r2-link3": {},
+ "r2-link4": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r2-link1": {},
+ "r2-link2": {},
+ "r2-link3": {},
+ "r2-link4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "r1-link1": {"ipv4": "auto", "pim": "enable"},
+ "r1-link2": {"ipv4": "auto", "pim": "enable"},
+ "r1-link3": {"ipv4": "auto", "pim": "enable"},
+ "r1-link4": {"ipv4": "auto", "pim": "enable"},
+ "r4-link1": {"ipv4": "auto", "pim": "enable"},
+ "r4-link2": {"ipv4": "auto", "pim": "enable"},
+ "r4-link3": {"ipv4": "auto", "pim": "enable"},
+ "r4-link4": {"ipv4": "auto", "pim": "enable"},
+ "i5": {"ipv4": "auto", "pim": "enable"}
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {},
+ "r3-link2": {},
+ "r3-link3": {},
+ "r3-link4": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {},
+ "r3-link2": {},
+ "r3-link3": {},
+ "r3-link4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "r2-link1": {"ipv4": "auto", "pim": "enable"},
+ "r2-link2": {"ipv4": "auto", "pim": "enable"},
+ "r2-link3": {"ipv4": "auto", "pim": "enable"},
+ "r2-link4": {"ipv4": "auto", "pim": "enable"},
+ "r3-link1": {"ipv4": "auto", "pim": "enable"},
+ "r3-link2": {"ipv4": "auto", "pim": "enable"},
+ "r3-link3": {"ipv4": "auto", "pim": "enable"},
+ "r3-link4": {"ipv4": "auto", "pim": "enable"},
+ "r1": {"ipv4": "auto", "pim": "enable"},
+ "r5": {"ipv4": "auto", "pim": "enable"},
+ "i6": {"ipv4": "auto", "pim": "enable"},
+ "i7": {"ipv4": "auto", "pim": "enable"}
+ },
+ "bgp": {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {},
+ "r4-link2": {},
+ "r4-link3": {},
+ "r4-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link1": {},
+ "r4-link2": {},
+ "r4-link3": {},
+ "r4-link4": {}
+ }
+ },
+ "r1": {
+ "dest_link": {
+ "r4": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r5": {
+ "links": {
+ "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"},
+ "r1": {"ipv4": "auto", "pim": "enable"},
+ "r4": {"ipv4": "auto", "pim": "enable"},
+ "i8": {"ipv4": "auto", "pim": "enable"}
+ },
+ "bgp": {
+ "local_as": "500",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r5": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r5": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "i1": {
+ "links": {
+ "r1": {"ipv4": "auto"}
+ }
+ },
+ "i2": {
+ "links": {
+ "r1": {"ipv4": "auto"}
+ }
+ },
+ "i3": {
+ "links": {
+ "r2": {"ipv4": "auto"}
+ }
+ },
+ "i4": {
+ "links": {
+ "r2": {"ipv4": "auto"}
+ }
+ },
+ "i5": {
+ "links": {
+ "r3": {"ipv4": "auto"}
+ }
+ },
+ "i6": {
+ "links": {
+ "r4": {"ipv4": "auto"}
+ }
+ },
+ "i7": {
+ "links": {
+ "r4": {"ipv4": "auto"}
+ }
+ },
+ "i8": {
+ "links": {
+ "r5": {"ipv4": "auto"}
+ }
+ },
+ "i9": {
+ "links": {
+ "r1": {"ipv4": "auto"}
+ }
+ }
+
+ }
+}
diff --git a/tests/topotests/multicast_pim_uplink_topo4/test_multicast_pim_uplink_topo4.py b/tests/topotests/multicast_pim_uplink_topo4/test_multicast_pim_uplink_topo4.py
new file mode 100644
index 0000000000..d384baa452
--- /dev/null
+++ b/tests/topotests/multicast_pim_uplink_topo4/test_multicast_pim_uplink_topo4.py
@@ -0,0 +1,893 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: ISC
+#
+# Copyright (c) 2024 by Architecture Technology Corp. (ATCorp)
+#
+
+"""
+Following tests are covered to test multicast pim sm:
+
+1. TC:1 Verify static group populated when static "ip igmp static-group <grp>" in configured
+2. TC:2 Verify mroute and upstream populated with correct OIL/IIF with static group
+3. TC:3 Verify static group not allowed for "224.0.0.0/24" and non multicast group
+4. TC:4 Verify static group removed from DUT while removing "ip igmp static-group" CLI
+5. TC:5 Verify static groups after removing and adding static-group config
+"""
+
+import os
+import sys
+import time
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ step,
+ addKernelRoute,
+ reset_config_on_routers,
+ shutdown_bringup_interface,
+ required_linux_kernel_version,
+)
+from lib.pim import (
+ create_pim_config,
+ create_igmp_config,
+ verify_mroutes,
+ clear_pim_interface_traffic,
+ verify_upstream_iif,
+ clear_mroute,
+ verify_pim_rp_info,
+ verify_static_groups,
+ McastTesterHelper,
+)
+from lib.bgp import (
+ verify_bgp_convergence,
+)
+from lib.topolog import logger
+from lib.topojson import build_config_from_json
+
+# Global variables
+TOPOLOGY = """
+
+ i9 i3-+-i4 i6-+-i7
+ | | |
+ i1--- R1-------R2----------R4------R5---i8
+ | | |
+ i2 R3-------------------+
+ +
+ |
+ i5
+
+ Description:
+ i1, i2, i3. i4, i5, i6, i7, i8 - FRR running iperf to send IGMP
+ join and traffic
+ R1 - DUT (LHR/FHR)
+ R2 - RP
+ R3 - Transit
+ R4 - (LHR/FHR)
+ R5 - Transit
+"""
+# Global variables
+RP_RANGE1 = "226.0.0.1/32"
+RP_RANGE2 = "226.0.0.2/32"
+RP_RANGE3 = "226.0.0.3/32"
+RP_RANGE4 = "226.0.0.4/32"
+RP_RANGE5 = "226.0.0.5/32"
+RP_RANGE6 = "232.0.0.1/32"
+RP_RANGE7 = "232.0.0.2/32"
+RP_RANGE8 = "232.0.0.3/32"
+RP_RANGE9 = "232.0.0.4/32"
+RP_RANGE10 = "232.0.0.5/32"
+
+GROUP_RANGE = "224.0.0.0/4"
+IGMP_GROUP = "225.1.1.1/32"
+IGMP_JOIN = "225.1.1.1"
+GROUP_RANGE_1 = [
+ "225.1.1.1/32",
+ "225.1.1.2/32",
+ "225.1.1.3/32",
+ "225.1.1.4/32",
+ "225.1.1.5/32",
+]
+IGMP_JOIN_RANGE_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"]
+IGMP_JOIN_RANGE_2 = ["224.0.0.1", "224.0.0.2", "224.0.0.3", "192.0.0.4", "192.0.0.5"]
+IGMP_JOIN_RANGE_3 = [
+ "226.0.0.1",
+ "226.0.0.2",
+ "226.0.0.3",
+ "226.0.0.4",
+ "226.0.0.5",
+ "232.0.0.1",
+ "232.0.0.2",
+ "232.0.0.3",
+ "232.0.0.4",
+ "232.0.0.5",
+]
+GROUP_RANGE_3 = [
+ "226.0.0.1/32",
+ "226.0.0.2/32",
+ "226.0.0.3/32",
+ "226.0.0.4/32",
+ "226.0.0.5/32",
+ "232.0.0.1/32",
+ "232.0.0.2/32",
+ "232.0.0.3/32",
+ "232.0.0.4/32",
+ "232.0.0.5/32",
+]
+
+r1_r2_links = []
+r1_r3_links = []
+r2_r1_links = []
+r2_r4_links = []
+r3_r1_links = []
+r3_r4_links = []
+r4_r2_links = []
+r4_r3_links = []
+
+pytestmark = [pytest.mark.pimd]
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.19")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ 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")
+
+ testdir = os.path.dirname(os.path.realpath(__file__))
+ json_file = "{}/multicast_pim_uplink_topo4.json".format(testdir)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, tgen.json_topo)
+
+ # Pre-requisite data
+ get_interfaces_names(topo)
+
+ # XXX Replace this using "with McastTesterHelper()... " in each test if possible.
+ global app_helper
+ app_helper = McastTesterHelper(tgen)
+
+ # Verify BGP convergence
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ app_helper.cleanup()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Local APIs
+#
+#####################################################
+
+
+def get_interfaces_names(topo):
+ """
+ API to fetch interfaces names and create list, which further would be used
+ for verification
+
+ Parameters
+ ----------
+ * `topo` : inout JSON data
+ """
+
+ for link in range(1, 5):
+ intf = topo["routers"]["r1"]["links"]["r2-link{}".format(link)]["interface"]
+ r1_r2_links.append(intf)
+
+ intf = topo["routers"]["r1"]["links"]["r3-link{}".format(link)]["interface"]
+ r1_r3_links.append(intf)
+
+ intf = topo["routers"]["r2"]["links"]["r1-link{}".format(link)]["interface"]
+ r2_r1_links.append(intf)
+
+ intf = topo["routers"]["r3"]["links"]["r1-link{}".format(link)]["interface"]
+ r3_r1_links.append(intf)
+
+ intf = topo["routers"]["r2"]["links"]["r4-link{}".format(link)]["interface"]
+ r2_r4_links.append(intf)
+
+ intf = topo["routers"]["r4"]["links"]["r2-link{}".format(link)]["interface"]
+ r4_r2_links.append(intf)
+
+ intf = topo["routers"]["r4"]["links"]["r3-link{}".format(link)]["interface"]
+ r4_r3_links.append(intf)
+
+
+def shutdown_interfaces(tgen):
+ """
+ API to Shut down interfaces which is not
+ used in all the testcases as part of this TDS
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+
+ """
+ logger.info("shutting down extra interfaces")
+ intf_r1_r4 = topo["routers"]["r1"]["links"]["r4"]["interface"]
+ intf_r1_r5 = topo["routers"]["r1"]["links"]["r5"]["interface"]
+ intf_r4_r1 = topo["routers"]["r4"]["links"]["r1"]["interface"]
+ intf_r5_r1 = topo["routers"]["r5"]["links"]["r1"]["interface"]
+ intf_r4_r5 = topo["routers"]["r4"]["links"]["r5"]["interface"]
+ intf_r5_r4 = topo["routers"]["r5"]["links"]["r4"]["interface"]
+ shutdown_bringup_interface(tgen, "r1", intf_r1_r4, False)
+ shutdown_bringup_interface(tgen, "r1", intf_r1_r5, False)
+ shutdown_bringup_interface(tgen, "r4", intf_r4_r1, False)
+ shutdown_bringup_interface(tgen, "r5", intf_r5_r1, False)
+ shutdown_bringup_interface(tgen, "r4", intf_r4_r5, False)
+ shutdown_bringup_interface(tgen, "r5", intf_r5_r4, False)
+
+
+def config_to_send_igmp_join_and_traffic(
+ tgen, topo, tc_name, iperf, iperf_intf, GROUP_RANGE, join=False, traffic=False
+):
+ """
+ API to do pre-configuration to send IGMP join and multicast
+ traffic
+
+ parameters:
+ -----------
+ * `tgen`: topogen object
+ * `topo`: input json data
+ * `tc_name`: caller test case name
+ * `iperf`: router running iperf
+ * `iperf_intf`: interface name router running iperf
+ * `GROUP_RANGE`: group range
+ * `join`: IGMP join, default False
+ * `traffic`: multicast traffic, default False
+ """
+
+ if join:
+ # Add route to kernal
+ result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ if traffic:
+ # Add route to kernal
+ result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ router_list = tgen.routers()
+ for router in router_list.keys():
+ if router == iperf:
+ continue
+
+ rnode = router_list[router]
+ rnode.run("echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter")
+
+ return True
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_ip_igmp_static_groups_p0(request):
+ """
+ TC_1 Verify static group populated when static
+ "ip igmp static-group <grp>" in configured
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ # Verify BGP convergence
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("shut down not required interfaces")
+ shutdown_interfaces(tgen)
+
+ step("Enable the PIM on all the interfaces of R1, R2, R3, R4")
+ step("configure BGP on R1, R2, R3, R4 and enable redistribute static/connected")
+ step("Enable the IGMP on R11 interfac of R1 and configure static groups")
+ intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"]
+ intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"]
+ input_dict = {
+ "r1": {
+ "igmp": {
+ "interfaces": {
+ intf_r1_i1: {"igmp": {"static-group": IGMP_JOIN_RANGE_1}},
+ intf_r1_i2: {"igmp": {"static-group": IGMP_JOIN_RANGE_1}},
+ }
+ }
+ }
+ }
+
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (225.1.1.1-5) as R2")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("verify static group using show ip igmp static-group")
+ dut = "r1"
+ interfaces = [intf_r1_i1, intf_r1_i2]
+ for interface in interfaces:
+ result = verify_static_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_mroute_with_igmp_static_groups_p0(request):
+ """
+ TC_2 Verify mroute and upstream populated with correct OIL/IIF with
+ static groups
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ # Verify BGP convergence
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("shut down not required interfaces")
+ shutdown_interfaces(tgen)
+
+ step("Enable the PIM on all the interfaces of R1, R2, R3, R4")
+ step("configure BGP on R1, R2, R3, R4 and enable redistribute static/connected")
+ step("Enable the IGMP on R11 interfac of R1 and configure static groups")
+
+ intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"]
+ intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"]
+ input_dict = {
+ "r1": {
+ "igmp": {
+ "interfaces": {
+ intf_r1_i1: {"igmp": {"version": "2", "static-group": IGMP_JOIN_RANGE_1}},
+ intf_r1_i2: {"igmp": {"version": "2", "static-group": IGMP_JOIN_RANGE_1}},
+ }
+ }
+ }
+ }
+
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (225.1.1.1-5) as R2")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("verify static group using show ip igmp static-group")
+ dut = "r1"
+ interfaces = [intf_r1_i1, intf_r1_i2]
+ for interface in interfaces:
+ result = verify_static_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify RP-info populated in DUT")
+ dut = "r1"
+ rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0]
+ SOURCE = "Static"
+ oif = r1_r2_links
+ result = verify_pim_rp_info(tgen, topo, dut, GROUP_RANGE_1, oif, rp_address, SOURCE)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Send traffic from R4 to all the groups ( 225.1.1.1 to 225.1.1.5)")
+
+ result = app_helper.run_traffic("i6", IGMP_JOIN_RANGE_1, "r4")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i6 = topo["routers"]["i6"]["links"]["r4"]["ipv4"].split("/")[0]
+
+ r1_r2_r3 = r1_r2_links + r1_r3_links
+ input_dict_starg = [
+ {
+ "dut": "r1",
+ "src_address": "*",
+ "iif": r1_r2_r3,
+ "oil": topo["routers"]["r1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r1",
+ "src_address": "*",
+ "iif": r1_r2_links,
+ "oil": topo["routers"]["r1"]["links"]["i2"]["interface"],
+ },
+ ]
+
+ input_dict_sg = [
+ {
+ "dut": "r1",
+ "src_address": source_i6,
+ "iif": r1_r2_r3,
+ "oil": topo["routers"]["r1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r1",
+ "src_address": source_i6,
+ "iif": r1_r2_r3,
+ "oil": topo["routers"]["r1"]["links"]["i2"]["interface"],
+ },
+ ]
+
+ step("Verify mroutes and iff upstream for static groups")
+ for input_dict in [input_dict_starg, input_dict_sg]:
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_1,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify mroutes not created with local interface ip ")
+
+ input_dict_local_sg = [
+ {
+ "dut": "r1",
+ "src_address": intf_r1_i1,
+ "iif": r1_r2_r3,
+ "oil": topo["routers"]["r1"]["links"]["i1"]["interface"],
+ },
+ {
+ "dut": "r1",
+ "src_address": intf_r1_i2,
+ "iif": r1_r2_r3,
+ "oil": topo["routers"]["r1"]["links"]["i2"]["interface"],
+ },
+ ]
+
+ for data in input_dict_local_sg:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_1,
+ data["iif"],
+ data["oil"],
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed Error: {}"
+ "sg created with local interface ip".format(tc_name, result)
+ )
+
+ result = verify_upstream_iif(
+ tgen,
+ data["dut"],
+ data["iif"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_1,
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed Error: {}"
+ "upstream created with local interface ip".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_igmp_static_group_with_reserved_address_p0(request):
+ """
+ TC_3 Verify static group not allowed for "224.0.0.0/24"
+ and non multicast group
+ """
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ # Verify BGP convergence
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("shut down not required interfaces")
+ shutdown_interfaces(tgen)
+
+ step("Enable the PIM on all the interfaces of R1, R2, R3, R4")
+ step("configure BGP on R1, R2, R3, R4 and enable redistribute static/connected")
+ step("Enable the IGMP on R11 interface of R1 and configure static groups")
+
+ intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"]
+ input_dict = {
+ "r1": {
+ "igmp": {
+ "interfaces": {
+ intf_r1_i1: {"igmp": {"version": "2", "statig-group": IGMP_JOIN_RANGE_2}}
+ }
+ }
+ }
+ }
+
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("verify static group using show ip igmp static-group")
+ dut = "r1"
+ interface = intf_r1_i1
+ result = verify_static_groups(
+ tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} :Failed \n Error: {}" "static group still present".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_remove_add_igmp_static_groups_p1(request):
+ """
+ TC_4 Verify static group removed from DUT while
+ removing "ip igmp static-group" CLI
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ app_helper.stop_all_hosts()
+ clear_mroute(tgen)
+ reset_config_on_routers(tgen)
+ clear_pim_interface_traffic(tgen, topo)
+
+ # Verify BGP convergence
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("shut down not required interfaces")
+ shutdown_interfaces(tgen)
+
+ step("Enable the PIM on all the interfaces of R1, R2, R3, R4")
+ step("configure BGP on R1, R2, R3, R4 and enable redistribute static/connected")
+ step("Enable the IGMP on R11 interfac of R1 and configure static groups")
+
+ intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"]
+ intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"]
+ input_dict = {
+ "r1": {
+ "igmp": {
+ "interfaces": {
+ intf_r1_i1: {"igmp": {"version": "2", "static-group": IGMP_JOIN_RANGE_1}}
+ }
+ }
+ }
+ }
+
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("Configure static RP for (225.1.1.1-5) as R2")
+
+ input_dict = {
+ "r2": {
+ "pim": {
+ "rp": [
+ {
+ "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE,
+ }
+ ]
+ }
+ }
+ }
+ result = create_pim_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("verify static group using show ip igmp static-group")
+ dut = "r1"
+ interface = intf_r1_i1
+ result = verify_static_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("verify RP-info populated in DUT")
+ dut = "r1"
+ rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0]
+ SOURCE = "Static"
+ oif = r1_r2_links
+ result = verify_pim_rp_info(tgen, topo, dut, GROUP_RANGE_1, oif, rp_address, SOURCE)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Send traffic from R4 to all the groups ( 225.1.1.1 to 225.1.1.5)")
+
+ result = app_helper.run_traffic("i6", IGMP_JOIN_RANGE_1, "r4")
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ source_i6 = topo["routers"]["i6"]["links"]["r4"]["ipv4"].split("/")[0]
+
+ logger.info("waiting 30 sec for SPT switchover")
+
+ r1_r2_r3 = r1_r2_links + r1_r3_links
+ input_dict_starg = [
+ {
+ "dut": "r1",
+ "src_address": "*",
+ "iif": r1_r2_r3,
+ "oil": topo["routers"]["r1"]["links"]["i1"]["interface"],
+ }
+ ]
+
+ input_dict_sg = [
+ {
+ "dut": "r1",
+ "src_address": source_i6,
+ "iif": r1_r2_r3,
+ "oil": topo["routers"]["r1"]["links"]["i1"]["interface"],
+ }
+ ]
+
+ step("Verify mroutes and iff upstream for static groups")
+ for input_dict in [input_dict_starg, input_dict_sg]:
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_1,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove static group from DUT")
+ input_dict = {
+ "r1": {
+ "igmp": {
+ "interfaces": {
+ intf_r1_i1: {
+ "igmp": {
+ "static-group": IGMP_JOIN_RANGE_1,
+ "delete_attr": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("verify static group removed using show ip igmp static-group")
+ dut = "r1"
+ interface = intf_r1_i1
+ result = verify_static_groups(
+ tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} :Failed \n Error: {}" "static group still present".format(
+ tc_name, result
+ )
+
+ step("Verify mroutes and iff upstream for static groups")
+ for input_dict in [input_dict_starg, input_dict_sg]:
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_1,
+ data["iif"],
+ data["oil"],
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed Error: {}" "mroutes still present".format(
+ tc_name, result
+ )
+
+ result = verify_upstream_iif(
+ tgen,
+ data["dut"],
+ data["iif"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_1,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed Error: {}" "mroutes still present".format(
+ tc_name, result
+ )
+
+ step("Add static group on DUT again")
+ input_dict = {
+ "r1": {
+ "igmp": {
+ "interfaces": {
+ intf_r1_i1: {
+ "igmp": {
+ "static-group": IGMP_JOIN_RANGE_1,
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_igmp_config(tgen, topo, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("verify static group using show ip igmp static-group")
+ dut = "r1"
+ interface = intf_r1_i1
+ result = verify_static_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify mroutes and iff upstream for static groups")
+ for input_dict in [input_dict_starg, input_dict_sg]:
+ for data in input_dict:
+ result = verify_mroutes(
+ tgen,
+ data["dut"],
+ data["src_address"],
+ IGMP_JOIN_RANGE_1,
+ data["iif"],
+ data["oil"],
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_upstream_iif(
+ tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/munet/cli.py b/tests/topotests/munet/cli.py
index 01a7091512..d273a30ead 100644
--- a/tests/topotests/munet/cli.py
+++ b/tests/topotests/munet/cli.py
@@ -745,7 +745,7 @@ async def cli_client_connected(unet, background, reader, writer):
await writer.drain()
-async def remote_cli(unet, prompt, title, background):
+async def remote_cli(unet, prompt, title, background, remote_wait=False):
"""Open a CLI in a new window."""
try:
if not unet.cli_sockpath:
@@ -756,6 +756,13 @@ async def remote_cli(unet, prompt, title, background):
unet.cli_sockpath = sockpath
logging.info("server created on :\n%s\n", sockpath)
+ if remote_wait:
+ wait_tmux = bool(os.getenv("TMUX", ""))
+ wait_x11 = not wait_tmux and bool(os.getenv("DISPLAY", ""))
+ else:
+ wait_tmux = False
+ wait_x11 = False
+
# Open a new window with a new CLI
python_path = await unet.async_get_exec_path(["python3", "python"])
us = os.path.realpath(__file__)
@@ -765,7 +772,32 @@ async def remote_cli(unet, prompt, title, background):
if prompt:
cmd += f" --prompt='{prompt}'"
cmd += " " + unet.cli_sockpath
- unet.run_in_window(cmd, title=title, background=False)
+
+ channel = None
+ if wait_tmux:
+ from .base import Commander # pylint: disable=import-outside-toplevel
+
+ channel = "{}-{}".format(os.getpid(), Commander.tmux_wait_gen)
+ logger.info("XXX channel is %s", channel)
+ # If we don't have a tty to pause on pause for tmux windows to exit
+ if channel is not None:
+ Commander.tmux_wait_gen += 1
+
+ pane_info = unet.run_in_window(
+ cmd, title=title, background=False, wait_for=channel
+ )
+
+ if wait_tmux and channel:
+ from .base import commander # pylint: disable=import-outside-toplevel
+
+ logger.debug("Waiting on TMUX CLI window")
+ await commander.async_cmd_raises(
+ [commander.get_exec_path("tmux"), "wait", channel]
+ )
+ elif wait_x11 and isinstance(pane_info, subprocess.Popen):
+ logger.debug("Waiting on xterm CLI process %s", pane_info)
+ if hasattr(asyncio, "to_thread"):
+ await asyncio.to_thread(pane_info.wait) # pylint: disable=no-member
except Exception as error:
logging.error("cli server: unexpected exception: %s", error)
@@ -906,8 +938,22 @@ def cli(
prompt=None,
background=True,
):
+ # In the case of no tty a remote_cli will be used, and we want it to wait on finish
+ # of the spawned cli.py script, otherwise it returns back here and exits async loop
+ # which kills the server side CLI socket operation.
+ remote_wait = not sys.stdin.isatty()
+
asyncio.run(
- async_cli(unet, histfile, sockpath, force_window, title, prompt, background)
+ async_cli(
+ unet,
+ histfile,
+ sockpath,
+ force_window,
+ title,
+ prompt,
+ background,
+ remote_wait=remote_wait,
+ )
)
@@ -919,12 +965,14 @@ async def async_cli(
title=None,
prompt=None,
background=True,
+ remote_wait=False,
):
if prompt is None:
prompt = "munet> "
if force_window or not sys.stdin.isatty():
- await remote_cli(unet, prompt, title, background)
+ await remote_cli(unet, prompt, title, background, remote_wait)
+ return
if not unet:
logger.debug("client-cli using sockpath %s", sockpath)
diff --git a/tests/topotests/munet/mutini.py b/tests/topotests/munet/mutini.py
index e5f9931714..3ce372cf60 100755
--- a/tests/topotests/munet/mutini.py
+++ b/tests/topotests/munet/mutini.py
@@ -15,6 +15,7 @@ import errno
import logging
import os
import re
+import select
import shlex
import signal
import subprocess
@@ -119,9 +120,15 @@ def exit_with_status(status):
sys.exit(ec)
-def waitpid(tag):
- logging.debug("%s: waitid for exiting process", tag)
- idobj = os.waitid(os.P_ALL, 0, os.WEXITED)
+def __waitpid(tag, nohang=False): # pylint: disable=inconsistent-return-statements
+ if nohang:
+ idobj = os.waitid(os.P_ALL, 0, os.WEXITED | os.WNOHANG)
+ if idobj is None:
+ return True
+ else:
+ idobj = os.waitid(os.P_ALL, 0, os.WEXITED)
+ assert idobj is not None
+
pid = idobj.si_pid
status = idobj.si_status
@@ -130,13 +137,23 @@ def waitpid(tag):
logging.debug(
"%s: reaped zombie %s (%s) w/ status %s", tag, pid, pidname, status
)
- return
+ return False
logging.debug("reaped child with status %s", status)
exit_with_status(status)
# NOTREACHED
+def waitpid(tag):
+ logging.debug("%s: waitid for exiting process", tag)
+ __waitpid(tag, False)
+
+ while True:
+ logging.debug("%s: checking for another exiting process", tag)
+ if __waitpid(tag, True):
+ return
+
+
def sig_trasmit(signum, _):
signame = signal.Signals(signum).name
if g.child_pid == -1:
@@ -158,10 +175,6 @@ def sig_trasmit(signum, _):
def sig_sigchld(signum, _):
assert signum == S.SIGCHLD
- try:
- waitpid("SIGCHLD")
- except ChildProcessError as error:
- logging.warning("got SIGCHLD but no pid to wait on: %s", error)
def setup_init_signals():
@@ -250,6 +263,19 @@ def is_creating_pid_namespace():
return p1name != p2name
+def poll_for_pids(msg, tag):
+ poller = select.poll()
+ while True:
+ logging.info("%s", msg)
+ events = poller.poll(1000)
+ logging.info("init: poll: checking for zombies and child exit: %s", events)
+ try:
+ waitpid(tag)
+ except ChildProcessError as error:
+ logging.warning("init: got SIGCHLD but no pid to wait on: %s", error)
+ # NOTREACHED
+
+
def be_init(new_pg, exec_args):
#
# Arrange for us to be killed when our parent dies, this will subsequently also kill
@@ -299,10 +325,7 @@ def be_init(new_pg, exec_args):
# Reap children as init process
vdebug("installing local handler for SIGCHLD")
signal.signal(signal.SIGCHLD, sig_sigchld)
-
- while True:
- logging.info("init: waiting to reap zombies")
- linux.pause()
+ poll_for_pids("init: waiting to reap zombies", "PAUSE-EXIT")
# NOTREACHED
# Set (parent) signal handlers before any fork to avoid race
@@ -321,9 +344,8 @@ def be_init(new_pg, exec_args):
os.execvp(exec_args[0], exec_args)
# NOTREACHED
- while True:
- logging.info("parent: waiting for child pid %s to exit", g.child_pid)
- waitpid("parent")
+ poll_for_pids(f"parent: waiting for child pid {g.child_pid} to exit", "PARENT")
+ # NOTREACHED
def unshare(flags):
@@ -411,9 +433,7 @@ def main():
if g.orig_pid != 1 and not new_pid:
# Simply hold the namespaces
- while True:
- logging.info("holding namespace waiting to be signaled to exit")
- linux.pause()
+ poll_for_pids("holding namespace waiting to be signaled to exit", "PARENT")
# NOTREACHED
be_init(not args.no_proc_group, args.rest)
diff --git a/tests/topotests/munet/native.py b/tests/topotests/munet/native.py
index 5747d5e1d7..e3b782396e 100644
--- a/tests/topotests/munet/native.py
+++ b/tests/topotests/munet/native.py
@@ -490,6 +490,10 @@ class NodeMixin:
gdbcmd += f" '-ex={cmd}'"
self.run_in_window(gdbcmd, ns_only=True)
+
+ # We need somehow signal from the launched gdb that it has continued
+ # this is non-trivial so for now just wait a while. :/
+ time.sleep(5)
elif should_gdb and use_emacs:
gdbcmd = gdbcmd.replace("gdb ", "gdb -i=mi ")
ecbin = self.get_exec_path("emacsclient")
@@ -2729,7 +2733,7 @@ ff02::2\tip6-allrouters
),
"format": "stdout HOST [HOST ...]",
"help": "tail -f on the stdout of the qemu/cmd for this node",
- "new-window": True,
+ "new-window": {"background": True, "ns_only": True},
},
{
"name": "stderr",
@@ -2739,7 +2743,7 @@ ff02::2\tip6-allrouters
),
"format": "stderr HOST [HOST ...]",
"help": "tail -f on the stdout of the qemu/cmd for this node",
- "new-window": True,
+ "new-window": {"background": True, "ns_only": True},
},
]
}
diff --git a/tests/topotests/munet/testing/util.py b/tests/topotests/munet/testing/util.py
index a1a94bcd1b..99687c0a83 100644
--- a/tests/topotests/munet/testing/util.py
+++ b/tests/topotests/munet/testing/util.py
@@ -52,12 +52,13 @@ def pause_test(desc=""):
asyncio.run(async_pause_test(desc))
-def retry(retry_timeout, initial_wait=0, expected=True):
+def retry(retry_timeout, initial_wait=0, retry_sleep=2, expected=True):
"""decorator: retry while functions return is not None or raises an exception.
* `retry_timeout`: Retry for at least this many seconds; after waiting
initial_wait seconds
* `initial_wait`: Sleeps for this many seconds before first executing function
+ * `retry_sleep`: The time to sleep between retries.
* `expected`: if False then the return logic is inverted, except for exceptions,
(i.e., a non None ends the retry loop, and returns that value)
"""
@@ -65,9 +66,8 @@ def retry(retry_timeout, initial_wait=0, expected=True):
def _retry(func):
@functools.wraps(func)
def func_retry(*args, **kwargs):
- retry_sleep = 2
-
# Allow the wrapped function's args to override the fixtures
+ _retry_sleep = float(kwargs.pop("retry_sleep", retry_sleep))
_retry_timeout = kwargs.pop("retry_timeout", retry_timeout)
_expected = kwargs.pop("expected", expected)
_initial_wait = kwargs.pop("initial_wait", initial_wait)
@@ -82,13 +82,21 @@ def retry(retry_timeout, initial_wait=0, expected=True):
while True:
seconds_left = (retry_until - datetime.datetime.now()).total_seconds()
try:
- ret = func(*args, **kwargs)
- if _expected and ret is None:
+ try:
+ ret = func(*args, seconds_left=seconds_left, **kwargs)
+ except TypeError as error:
+ if "seconds_left" not in str(error):
+ raise
+ ret = func(*args, **kwargs)
+
+ logging.debug("Function returned %s", ret)
+
+ positive_result = ret is None
+ if _expected == positive_result:
logging.debug("Function succeeds")
return ret
- logging.debug("Function returned %s", ret)
except Exception as error:
- logging.info("Function raised exception: %s", str(error))
+ logging.info('Function raised exception: "%s"', error)
ret = error
if seconds_left < 0:
@@ -99,10 +107,10 @@ def retry(retry_timeout, initial_wait=0, expected=True):
logging.info(
"Sleeping %ds until next retry with %.1f retry time left",
- retry_sleep,
+ _retry_sleep,
seconds_left,
)
- time.sleep(retry_sleep)
+ time.sleep(_retry_sleep)
func_retry._original = func # pylint: disable=W0212
return func_retry
diff --git a/tests/topotests/nhrp_redundancy/host/frr.conf b/tests/topotests/nhrp_redundancy/host/frr.conf
new file mode 100644
index 0000000000..8bb7da0ad6
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/host/frr.conf
@@ -0,0 +1,4 @@
+interface host-eth0
+ ip address 10.4.4.7/24
+!
+ip route 0.0.0.0/0 10.4.4.4
diff --git a/tests/topotests/nhrp_redundancy/nhc1/frr.conf b/tests/topotests/nhrp_redundancy/nhc1/frr.conf
new file mode 100644
index 0000000000..98e848bccf
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/frr.conf
@@ -0,0 +1,25 @@
+ip forwarding
+!debug nhrp all
+interface nhc1-eth0
+ ip address 192.168.2.4/24
+!
+ip route 192.168.1.0/24 192.168.2.6
+interface nhc1-gre0
+ ip address 172.16.1.4/32
+ no link-detect
+ ipv6 nd suppress-ra
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ ip nhrp nhs dynamic nbma 192.168.1.1
+ ip nhrp nhs dynamic nbma 192.168.1.2
+ ip nhrp nhs dynamic nbma 192.168.1.3
+ ip nhrp shortcut
+ tunnel source nhc1-eth0
+!
+interface nhc1-eth1
+ ip address 10.4.4.4/24
+!
+ip route 0.0.0.0/0 172.16.1.1 50
+ip route 0.0.0.0/0 172.16.1.2 60
+ip route 0.0.0.0/0 172.16.1.3 70
diff --git a/tests/topotests/nhrp_redundancy/r4/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache.json
index f87ebcf5fc..9e8a5c999d 100644
--- a/tests/topotests/nhrp_redundancy/r4/nhrp_cache.json
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache.json
@@ -4,9 +4,9 @@
},
"table": [
{
- "interface": "r4-gre0",
+ "interface": "nhc1-gre0",
"type": "nhs",
- "protocol": "176.16.1.2",
+ "protocol": "172.16.1.2",
"nbma": "192.168.1.2",
"claimed_nbma": "192.168.1.2",
"used": false,
@@ -15,9 +15,9 @@
"identity": ""
},
{
- "interface": "r4-gre0",
+ "interface": "nhc1-gre0",
"type": "local",
- "protocol": "176.16.1.4",
+ "protocol": "172.16.1.4",
"nbma": "192.168.2.4",
"claimed_nbma": "192.168.2.4",
"used": false,
@@ -26,9 +26,9 @@
"identity": "-"
},
{
- "interface": "r4-gre0",
+ "interface": "nhc1-gre0",
"type": "nhs",
- "protocol": "176.16.1.3",
+ "protocol": "172.16.1.3",
"nbma": "192.168.1.3",
"claimed_nbma": "192.168.1.3",
"used": false,
@@ -37,9 +37,9 @@
"identity": ""
},
{
- "interface": "r4-gre0",
+ "interface": "nhc1-gre0",
"type": "nhs",
- "protocol": "176.16.1.1",
+ "protocol": "172.16.1.1",
"nbma": "192.168.1.1",
"claimed_nbma": "192.168.1.1",
"used": false,
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache_nhs1_down.json
new file mode 100644
index 0000000000..5b91f3bcfb
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_cache_nhs1_down.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhc1-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.2",
+ "nbma": "192.168.1.2",
+ "claimed_nbma": "192.168.1.2",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc1-gre0",
+ "type": "local",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhc1-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.3",
+ "nbma": "192.168.1.3",
+ "claimed_nbma": "192.168.1.3",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/r5/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route.json
index 1d1c16ffb8..083675651f 100644
--- a/tests/topotests/nhrp_redundancy/r5/nhrp_route.json
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route.json
@@ -1,7 +1,7 @@
{
- "176.16.1.1\/32": [
+ "172.16.1.1\/32": [
{
- "prefix": "176.16.1.1\/32",
+ "prefix": "172.16.1.1\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -16,15 +16,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r5-gre0",
+ "interfaceName": "nhc1-gre0",
"active": true
}
]
}
],
- "176.16.1.2\/32": [
+ "172.16.1.2\/32": [
{
- "prefix": "176.16.1.2\/32",
+ "prefix": "172.16.1.2\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -39,15 +39,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r5-gre0",
+ "interfaceName": "nhc1-gre0",
"active": true
}
]
}
],
- "176.16.1.3\/32": [
+ "172.16.1.3\/32": [
{
- "prefix": "176.16.1.3\/32",
+ "prefix": "172.16.1.3\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -62,7 +62,7 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r5-gre0",
+ "interfaceName": "nhc1-gre0",
"active": true
}
]
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_nhs1_down.json
new file mode 100644
index 0000000000..bfb468b0fb
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_nhs1_down.json
@@ -0,0 +1,49 @@
+{
+ "172.16.1.1\/32": null,
+ "172.16.1.2\/32": [
+ {
+ "prefix": "172.16.1.2\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.3\/32": [
+ {
+ "prefix": "172.16.1.3\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/r4/nhrp_route_shortcut.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut.json
index f8efff2059..3a91f1baaa 100644
--- a/tests/topotests/nhrp_redundancy/r4/nhrp_route_shortcut.json
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut.json
@@ -1,7 +1,7 @@
{
- "5.5.5.5\/32": [
+ "10.5.5.0\/24": [
{
- "prefix": "5.5.5.5\/32",
+ "prefix": "10.5.5.0\/24",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -15,17 +15,17 @@
"nexthops": [
{
"fib": true,
- "ip": "176.16.1.5",
+ "ip": "172.16.1.5",
"afi": "ipv4",
- "interfaceName": "r4-gre0",
+ "interfaceName": "nhc1-gre0",
"active": true
}
]
}
],
- "176.16.1.1\/32": [
+ "172.16.1.1\/32": [
{
- "prefix": "176.16.1.1\/32",
+ "prefix": "172.16.1.1\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -40,15 +40,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r4-gre0",
+ "interfaceName": "nhc1-gre0",
"active": true
}
]
}
],
- "176.16.1.2\/32": [
+ "172.16.1.2\/32": [
{
- "prefix": "176.16.1.2\/32",
+ "prefix": "172.16.1.2\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -63,15 +63,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r4-gre0",
+ "interfaceName": "nhc1-gre0",
"active": true
}
]
}
],
- "176.16.1.3\/32": [
+ "172.16.1.3\/32": [
{
- "prefix": "176.16.1.3\/32",
+ "prefix": "172.16.1.3\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -86,15 +86,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r4-gre0",
+ "interfaceName": "nhc1-gre0",
"active": true
}
]
}
],
- "176.16.1.5\/32": [
+ "172.16.1.5\/32": [
{
- "prefix": "176.16.1.5\/32",
+ "prefix": "172.16.1.5\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -109,7 +109,7 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r4-gre0",
+ "interfaceName": "nhc1-gre0",
"active": true
}
]
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut_nhs1_down.json
new file mode 100644
index 0000000000..0f38feb6a8
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_route_shortcut_nhs1_down.json
@@ -0,0 +1,96 @@
+{
+ "10.5.5.0\/24": [
+ {
+ "prefix": "10.5.5.0\/24",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "ip": "172.16.1.5",
+ "afi": "ipv4",
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.1\/32": null,
+ "172.16.1.2\/32": [
+ {
+ "prefix": "172.16.1.2\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.3\/32": [
+ {
+ "prefix": "172.16.1.3\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc1-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_absent.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_absent.json
new file mode 100644
index 0000000000..78563cb902
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_absent.json
@@ -0,0 +1,5 @@
+{
+ "attr":{
+ "entriesCount":0
+ }
+}
diff --git a/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_present.json b/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_present.json
new file mode 100644
index 0000000000..4547c59c88
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc1/nhrp_shortcut_present.json
@@ -0,0 +1,9 @@
+{
+ "table":[
+ {
+ "type":"dynamic",
+ "prefix":"10.5.5.0/24",
+ "via":"172.16.1.5"
+ }
+ ]
+}
diff --git a/tests/topotests/nhrp_redundancy/nhc2/frr.conf b/tests/topotests/nhrp_redundancy/nhc2/frr.conf
new file mode 100644
index 0000000000..818dd48251
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc2/frr.conf
@@ -0,0 +1,25 @@
+ip forwarding
+!debug nhrp all
+interface nhc2-eth0
+ ip address 192.168.2.5/24
+!
+ip route 192.168.1.0/24 192.168.2.6
+interface nhc2-gre0
+ ip address 172.16.1.5/32
+ no link-detect
+ ipv6 nd suppress-ra
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp nhs dynamic nbma 192.168.1.1
+ ip nhrp nhs dynamic nbma 192.168.1.2
+ ip nhrp nhs dynamic nbma 192.168.1.3
+ ip nhrp registration no-unique
+ ip nhrp shortcut
+ tunnel source nhc2-eth0
+!
+interface nhc2-eth1
+ ip address 10.5.5.5/24
+!
+ip route 0.0.0.0/0 172.16.1.1 50
+ip route 0.0.0.0/0 172.16.1.2 60
+ip route 0.0.0.0/0 172.16.1.3 70
diff --git a/tests/topotests/nhrp_redundancy/r5/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache.json
index bc041c6014..8ee02a7cbf 100644
--- a/tests/topotests/nhrp_redundancy/r5/nhrp_cache.json
+++ b/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache.json
@@ -4,9 +4,9 @@
},
"table": [
{
- "interface": "r5-gre0",
+ "interface": "nhc2-gre0",
"type": "nhs",
- "protocol": "176.16.1.2",
+ "protocol": "172.16.1.2",
"nbma": "192.168.1.2",
"claimed_nbma": "192.168.1.2",
"used": false,
@@ -15,9 +15,9 @@
"identity": ""
},
{
- "interface": "r5-gre0",
+ "interface": "nhc2-gre0",
"type": "nhs",
- "protocol": "176.16.1.3",
+ "protocol": "172.16.1.3",
"nbma": "192.168.1.3",
"claimed_nbma": "192.168.1.3",
"used": false,
@@ -26,9 +26,9 @@
"identity": ""
},
{
- "interface": "r5-gre0",
+ "interface": "nhc2-gre0",
"type": "nhs",
- "protocol": "176.16.1.1",
+ "protocol": "172.16.1.1",
"nbma": "192.168.1.1",
"claimed_nbma": "192.168.1.1",
"used": false,
@@ -37,9 +37,9 @@
"identity": ""
},
{
- "interface": "r5-gre0",
+ "interface": "nhc2-gre0",
"type": "local",
- "protocol": "176.16.1.5",
+ "protocol": "172.16.1.5",
"nbma": "192.168.2.5",
"claimed_nbma": "192.168.2.5",
"used": false,
diff --git a/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache_nhs1_down.json
new file mode 100644
index 0000000000..bb1c483718
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc2/nhrp_cache_nhs1_down.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhc2-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.2",
+ "nbma": "192.168.1.2",
+ "claimed_nbma": "192.168.1.2",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc2-gre0",
+ "type": "nhs",
+ "protocol": "172.16.1.3",
+ "nbma": "192.168.1.3",
+ "claimed_nbma": "192.168.1.3",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhc2-gre0",
+ "type": "local",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/r4/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhc2/nhrp_route.json
index 4f1faee7a7..a69c0caec3 100644
--- a/tests/topotests/nhrp_redundancy/r4/nhrp_route.json
+++ b/tests/topotests/nhrp_redundancy/nhc2/nhrp_route.json
@@ -1,7 +1,7 @@
{
- "176.16.1.1\/32": [
+ "172.16.1.1\/32": [
{
- "prefix": "176.16.1.1\/32",
+ "prefix": "172.16.1.1\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -16,15 +16,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r4-gre0",
+ "interfaceName": "nhc2-gre0",
"active": true
}
]
}
],
- "176.16.1.2\/32": [
+ "172.16.1.2\/32": [
{
- "prefix": "176.16.1.2\/32",
+ "prefix": "172.16.1.2\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -39,15 +39,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r4-gre0",
+ "interfaceName": "nhc2-gre0",
"active": true
}
]
}
],
- "176.16.1.3\/32": [
+ "172.16.1.3\/32": [
{
- "prefix": "176.16.1.3\/32",
+ "prefix": "172.16.1.3\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -62,7 +62,7 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r4-gre0",
+ "interfaceName": "nhc2-gre0",
"active": true
}
]
diff --git a/tests/topotests/nhrp_redundancy/nhc2/nhrp_route_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhc2/nhrp_route_nhs1_down.json
new file mode 100644
index 0000000000..e2dd9dde23
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhc2/nhrp_route_nhs1_down.json
@@ -0,0 +1,49 @@
+{
+ "172.16.1.1\/32": null,
+ "172.16.1.2\/32": [
+ {
+ "prefix": "172.16.1.2\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.3\/32": [
+ {
+ "prefix": "172.16.1.3\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhc2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs1/frr.conf b/tests/topotests/nhrp_redundancy/nhs1/frr.conf
new file mode 100644
index 0000000000..583d014348
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs1/frr.conf
@@ -0,0 +1,19 @@
+ip forwarding
+!debug nhrp all
+interface nhs1-eth0
+ ip address 192.168.1.1/24
+!
+ip route 192.168.2.0/24 192.168.1.6
+nhrp nflog-group 1
+interface nhs1-gre0
+ ip address 172.16.1.1/32
+ no link-detect
+ ipv6 nd suppress-ra
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ ip nhrp redirect
+ tunnel source nhs1-eth0
+!
+ip route 10.4.4.0/24 172.16.1.4
+ip route 10.5.5.0/24 172.16.1.5
diff --git a/tests/topotests/nhrp_redundancy/r1/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhs1/nhrp_cache.json
index a94dd9fecf..11d41d1b83 100644
--- a/tests/topotests/nhrp_redundancy/r1/nhrp_cache.json
+++ b/tests/topotests/nhrp_redundancy/nhs1/nhrp_cache.json
@@ -4,9 +4,9 @@
},
"table": [
{
- "interface": "r1-gre0",
+ "interface": "nhs1-gre0",
"type": "dynamic",
- "protocol": "176.16.1.4",
+ "protocol": "172.16.1.4",
"nbma": "192.168.2.4",
"claimed_nbma": "192.168.2.4",
"used": false,
@@ -15,9 +15,9 @@
"identity": ""
},
{
- "interface": "r1-gre0",
+ "interface": "nhs1-gre0",
"type": "local",
- "protocol": "176.16.1.1",
+ "protocol": "172.16.1.1",
"nbma": "192.168.1.1",
"claimed_nbma": "192.168.1.1",
"used": false,
@@ -26,9 +26,9 @@
"identity": "-"
},
{
- "interface": "r1-gre0",
+ "interface": "nhs1-gre0",
"type": "dynamic",
- "protocol": "176.16.1.5",
+ "protocol": "172.16.1.5",
"nbma": "192.168.2.5",
"claimed_nbma": "192.168.2.5",
"used": false,
diff --git a/tests/topotests/nhrp_redundancy/r3/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhs1/nhrp_route.json
index 3d548c08fd..2574b1a5d2 100644
--- a/tests/topotests/nhrp_redundancy/r3/nhrp_route.json
+++ b/tests/topotests/nhrp_redundancy/nhs1/nhrp_route.json
@@ -1,7 +1,7 @@
{
- "176.16.1.4\/32": [
+ "172.16.1.4\/32": [
{
- "prefix": "176.16.1.4\/32",
+ "prefix": "172.16.1.4\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -16,15 +16,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r3-gre0",
+ "interfaceName": "nhs1-gre0",
"active": true
}
]
}
],
- "176.16.1.5\/32": [
+ "172.16.1.5\/32": [
{
- "prefix": "176.16.1.5\/32",
+ "prefix": "172.16.1.5\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -39,7 +39,7 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r3-gre0",
+ "interfaceName": "nhs1-gre0",
"active": true
}
]
diff --git a/tests/topotests/nhrp_redundancy/nhs2/frr.conf b/tests/topotests/nhrp_redundancy/nhs2/frr.conf
new file mode 100644
index 0000000000..a6e0a98e6b
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs2/frr.conf
@@ -0,0 +1,19 @@
+ip forwarding
+!debug nhrp all
+interface nhs2-eth0
+ ip address 192.168.1.2/24
+!
+ip route 192.168.2.0/24 192.168.1.6
+nhrp nflog-group 1
+interface nhs2-gre0
+ ip address 172.16.1.2/32
+ no link-detect
+ ipv6 nd suppress-ra
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ ip nhrp redirect
+ tunnel source nhs2-eth0
+!
+ip route 10.4.4.0/24 172.16.1.4
+ip route 10.5.5.0/24 172.16.1.5
diff --git a/tests/topotests/nhrp_redundancy/r2/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache.json
index 91557a1918..6343c4deb9 100644
--- a/tests/topotests/nhrp_redundancy/r2/nhrp_cache.json
+++ b/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache.json
@@ -4,9 +4,9 @@
},
"table": [
{
- "interface": "r2-gre0",
+ "interface": "nhs2-gre0",
"type": "local",
- "protocol": "176.16.1.2",
+ "protocol": "172.16.1.2",
"nbma": "192.168.1.2",
"claimed_nbma": "192.168.1.2",
"used": false,
@@ -15,9 +15,9 @@
"identity": "-"
},
{
- "interface": "r2-gre0",
+ "interface": "nhs2-gre0",
"type": "dynamic",
- "protocol": "176.16.1.4",
+ "protocol": "172.16.1.4",
"nbma": "192.168.2.4",
"claimed_nbma": "192.168.2.4",
"used": false,
@@ -26,9 +26,9 @@
"identity": ""
},
{
- "interface": "r2-gre0",
+ "interface": "nhs2-gre0",
"type": "dynamic",
- "protocol": "176.16.1.5",
+ "protocol": "172.16.1.5",
"nbma": "192.168.2.5",
"claimed_nbma": "192.168.2.5",
"used": false,
diff --git a/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache_nhs1_down.json
new file mode 100644
index 0000000000..6343c4deb9
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs2/nhrp_cache_nhs1_down.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhs2-gre0",
+ "type": "local",
+ "protocol": "172.16.1.2",
+ "nbma": "192.168.1.2",
+ "claimed_nbma": "192.168.1.2",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhs2-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhs2-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/r1/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhs2/nhrp_route.json
index b5f3e29e74..0ad37fc319 100644
--- a/tests/topotests/nhrp_redundancy/r1/nhrp_route.json
+++ b/tests/topotests/nhrp_redundancy/nhs2/nhrp_route.json
@@ -1,7 +1,7 @@
{
- "176.16.1.4\/32": [
+ "172.16.1.4\/32": [
{
- "prefix": "176.16.1.4\/32",
+ "prefix": "172.16.1.4\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -16,15 +16,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r1-gre0",
+ "interfaceName": "nhs2-gre0",
"active": true
}
]
}
],
- "176.16.1.5\/32": [
+ "172.16.1.5\/32": [
{
- "prefix": "176.16.1.5\/32",
+ "prefix": "172.16.1.5\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -39,7 +39,7 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r1-gre0",
+ "interfaceName": "nhs2-gre0",
"active": true
}
]
diff --git a/tests/topotests/nhrp_redundancy/nhs2/nhrp_route_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhs2/nhrp_route_nhs1_down.json
new file mode 100644
index 0000000000..0ad37fc319
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs2/nhrp_route_nhs1_down.json
@@ -0,0 +1,48 @@
+{
+ "172.16.1.4\/32": [
+ {
+ "prefix": "172.16.1.4\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs2-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/nhs3/frr.conf b/tests/topotests/nhrp_redundancy/nhs3/frr.conf
new file mode 100644
index 0000000000..e965baf327
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs3/frr.conf
@@ -0,0 +1,19 @@
+ip forwarding
+!debug nhrp all
+interface nhs3-eth0
+ ip address 192.168.1.3/24
+!
+ip route 192.168.2.0/24 192.168.1.6
+nhrp nflog-group 1
+interface nhs3-gre0
+ ip address 172.16.1.3/32
+ no link-detect
+ ipv6 nd suppress-ra
+ ip nhrp holdtime 10
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ ip nhrp redirect
+ tunnel source nhs3-eth0
+!
+ip route 10.4.4.0/24 172.16.1.4
+ip route 10.5.5.0/24 172.16.1.5 \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/r3/nhrp_cache.json b/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache.json
index ef3ab690bc..d911de348b 100644
--- a/tests/topotests/nhrp_redundancy/r3/nhrp_cache.json
+++ b/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache.json
@@ -4,9 +4,9 @@
},
"table": [
{
- "interface": "r3-gre0",
+ "interface": "nhs3-gre0",
"type": "dynamic",
- "protocol": "176.16.1.4",
+ "protocol": "172.16.1.4",
"nbma": "192.168.2.4",
"claimed_nbma": "192.168.2.4",
"used": false,
@@ -15,9 +15,9 @@
"identity": ""
},
{
- "interface": "r3-gre0",
+ "interface": "nhs3-gre0",
"type": "local",
- "protocol": "176.16.1.3",
+ "protocol": "172.16.1.3",
"nbma": "192.168.1.3",
"claimed_nbma": "192.168.1.3",
"used": false,
@@ -26,9 +26,9 @@
"identity": "-"
},
{
- "interface": "r3-gre0",
+ "interface": "nhs3-gre0",
"type": "dynamic",
- "protocol": "176.16.1.5",
+ "protocol": "172.16.1.5",
"nbma": "192.168.2.5",
"claimed_nbma": "192.168.2.5",
"used": false,
diff --git a/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache_nhs1_down.json
new file mode 100644
index 0000000000..d911de348b
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs3/nhrp_cache_nhs1_down.json
@@ -0,0 +1,40 @@
+{
+ "attr": {
+ "entriesCount": 3
+ },
+ "table": [
+ {
+ "interface": "nhs3-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.4",
+ "nbma": "192.168.2.4",
+ "claimed_nbma": "192.168.2.4",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ },
+ {
+ "interface": "nhs3-gre0",
+ "type": "local",
+ "protocol": "172.16.1.3",
+ "nbma": "192.168.1.3",
+ "claimed_nbma": "192.168.1.3",
+ "used": false,
+ "timeout": false,
+ "auth": false,
+ "identity": "-"
+ },
+ {
+ "interface": "nhs3-gre0",
+ "type": "dynamic",
+ "protocol": "172.16.1.5",
+ "nbma": "192.168.2.5",
+ "claimed_nbma": "192.168.2.5",
+ "used": false,
+ "timeout": true,
+ "auth": false,
+ "identity": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/r2/nhrp_route.json b/tests/topotests/nhrp_redundancy/nhs3/nhrp_route.json
index f1fa6e54c1..29a4f8f11b 100644
--- a/tests/topotests/nhrp_redundancy/r2/nhrp_route.json
+++ b/tests/topotests/nhrp_redundancy/nhs3/nhrp_route.json
@@ -1,7 +1,7 @@
{
- "176.16.1.4\/32": [
+ "172.16.1.4\/32": [
{
- "prefix": "176.16.1.4\/32",
+ "prefix": "172.16.1.4\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -16,15 +16,15 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r2-gre0",
+ "interfaceName": "nhs3-gre0",
"active": true
}
]
}
],
- "176.16.1.5\/32": [
+ "172.16.1.5\/32": [
{
- "prefix": "176.16.1.5\/32",
+ "prefix": "172.16.1.5\/32",
"protocol": "nhrp",
"vrfId": 0,
"vrfName": "default",
@@ -39,7 +39,7 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "r2-gre0",
+ "interfaceName": "nhs3-gre0",
"active": true
}
]
diff --git a/tests/topotests/nhrp_redundancy/nhs3/nhrp_route_nhs1_down.json b/tests/topotests/nhrp_redundancy/nhs3/nhrp_route_nhs1_down.json
new file mode 100644
index 0000000000..29a4f8f11b
--- /dev/null
+++ b/tests/topotests/nhrp_redundancy/nhs3/nhrp_route_nhs1_down.json
@@ -0,0 +1,48 @@
+{
+ "172.16.1.4\/32": [
+ {
+ "prefix": "172.16.1.4\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs3-gre0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "172.16.1.5\/32": [
+ {
+ "prefix": "172.16.1.5\/32",
+ "protocol": "nhrp",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 10,
+ "metric": 0,
+ "installed": true,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "nhs3-gre0",
+ "active": true
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/r1/nhrpd.conf b/tests/topotests/nhrp_redundancy/r1/nhrpd.conf
deleted file mode 100644
index ad48ce3769..0000000000
--- a/tests/topotests/nhrp_redundancy/r1/nhrpd.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-!debug nhrp all
-nhrp nflog-group 1
-interface r1-gre0
- ip nhrp holdtime 10
- ip nhrp network-id 42
- ip nhrp registration no-unique
- ip nhrp redirect
- tunnel source r1-eth0
-exit
diff --git a/tests/topotests/nhrp_redundancy/r1/zebra.conf b/tests/topotests/nhrp_redundancy/r1/zebra.conf
deleted file mode 100644
index 0f11563f57..0000000000
--- a/tests/topotests/nhrp_redundancy/r1/zebra.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-ip forwarding
-interface r1-eth0
- ip address 192.168.1.1/24
-!
-ip route 192.168.2.0/24 192.168.1.6
-interface r1-gre0
- ip address 176.16.1.1/32
- no link-detect
- ipv6 nd suppress-ra
-!
-ip route 4.4.4.0/24 176.16.1.4
-ip route 5.5.5.0/24 176.16.1.5
diff --git a/tests/topotests/nhrp_redundancy/r2/nhrpd.conf b/tests/topotests/nhrp_redundancy/r2/nhrpd.conf
deleted file mode 100644
index 4d63f07d1f..0000000000
--- a/tests/topotests/nhrp_redundancy/r2/nhrpd.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-!debug nhrp all
-nhrp nflog-group 1
-interface r2-gre0
- ip nhrp holdtime 10
- ip nhrp network-id 42
- ip nhrp registration no-unique
- ip nhrp redirect
- tunnel source r2-eth0
-exit
diff --git a/tests/topotests/nhrp_redundancy/r2/zebra.conf b/tests/topotests/nhrp_redundancy/r2/zebra.conf
deleted file mode 100644
index 1a9c4ff915..0000000000
--- a/tests/topotests/nhrp_redundancy/r2/zebra.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-ip forwarding
-interface r2-eth0
- ip address 192.168.1.2/24
-!
-ip route 192.168.2.0/24 192.168.1.6
-interface r2-gre0
- ip address 176.16.1.2/32
- no link-detect
- ipv6 nd suppress-ra
-!
-ip route 4.4.4.0/24 176.16.1.4
-ip route 5.5.5.0/24 176.16.1.5
diff --git a/tests/topotests/nhrp_redundancy/r3/nhrpd.conf b/tests/topotests/nhrp_redundancy/r3/nhrpd.conf
deleted file mode 100644
index 87cc2161f8..0000000000
--- a/tests/topotests/nhrp_redundancy/r3/nhrpd.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-!debug nhrp all
-nhrp nflog-group 1
-interface r3-gre0
- ip nhrp holdtime 10
- ip nhrp network-id 42
- ip nhrp registration no-unique
- ip nhrp redirect
- tunnel source r3-eth0
-exit
diff --git a/tests/topotests/nhrp_redundancy/r3/zebra.conf b/tests/topotests/nhrp_redundancy/r3/zebra.conf
deleted file mode 100644
index 980cfbcaab..0000000000
--- a/tests/topotests/nhrp_redundancy/r3/zebra.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-ip forwarding
-interface r3-eth0
- ip address 192.168.1.3/24
-!
-ip route 192.168.2.0/24 192.168.1.6
-interface r3-gre0
- ip address 176.16.1.3/32
- no link-detect
- ipv6 nd suppress-ra
-!
-ip route 4.4.4.0/24 176.16.1.4
-ip route 5.5.5.0/24 176.16.1.5 \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/r4/nhrpd.conf b/tests/topotests/nhrp_redundancy/r4/nhrpd.conf
deleted file mode 100644
index 8a52f3386e..0000000000
--- a/tests/topotests/nhrp_redundancy/r4/nhrpd.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-!debug nhrp all
-interface r4-gre0
- ip nhrp holdtime 10
- ip nhrp network-id 42
- ip nhrp registration no-unique
- ip nhrp nhs dynamic nbma 192.168.1.1
- ip nhrp nhs dynamic nbma 192.168.1.2
- ip nhrp nhs dynamic nbma 192.168.1.3
- ip nhrp shortcut
- tunnel source r4-eth0
-exit
diff --git a/tests/topotests/nhrp_redundancy/r4/zebra.conf b/tests/topotests/nhrp_redundancy/r4/zebra.conf
deleted file mode 100644
index e4a9a6f80f..0000000000
--- a/tests/topotests/nhrp_redundancy/r4/zebra.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-ip forwarding
-interface r4-eth0
- ip address 192.168.2.4/24
-!
-ip route 192.168.1.0/24 192.168.2.6
-interface r4-gre0
- ip address 176.16.1.4/32
- no link-detect
- ipv6 nd suppress-ra
-!
-interface r4-eth1
- ip address 4.4.4.4/24
-!
-ip route 0.0.0.0/0 176.16.1.1 50
-ip route 0.0.0.0/0 176.16.1.2 60
-ip route 0.0.0.0/0 176.16.1.3 70 \ No newline at end of file
diff --git a/tests/topotests/nhrp_redundancy/r5/nhrpd.conf b/tests/topotests/nhrp_redundancy/r5/nhrpd.conf
deleted file mode 100644
index 7241ed592d..0000000000
--- a/tests/topotests/nhrp_redundancy/r5/nhrpd.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-!debug nhrp all
-interface r5-gre0
- ip nhrp holdtime 10
- ip nhrp network-id 42
- ip nhrp nhs dynamic nbma 192.168.1.1
- ip nhrp nhs dynamic nbma 192.168.1.2
- ip nhrp nhs dynamic nbma 192.168.1.3
- ip nhrp registration no-unique
- ip nhrp shortcut
- tunnel source r5-eth0
-exit
diff --git a/tests/topotests/nhrp_redundancy/r5/zebra.conf b/tests/topotests/nhrp_redundancy/r5/zebra.conf
deleted file mode 100644
index 9b1e1c0646..0000000000
--- a/tests/topotests/nhrp_redundancy/r5/zebra.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-ip forwarding
-interface r5-eth0
- ip address 192.168.2.5/24
-!
-ip route 192.168.1.0/24 192.168.2.6
-interface r5-gre0
- ip address 176.16.1.5/32
- no link-detect
- ipv6 nd suppress-ra
-!
-interface r5-eth1
- ip address 5.5.5.5/24
-!
-ip route 0.0.0.0/0 176.16.1.1 50
-ip route 0.0.0.0/0 176.16.1.2 60
-ip route 0.0.0.0/0 176.16.1.3 70
diff --git a/tests/topotests/nhrp_redundancy/r7/zebra.conf b/tests/topotests/nhrp_redundancy/r7/zebra.conf
deleted file mode 100644
index 5747b40956..0000000000
--- a/tests/topotests/nhrp_redundancy/r7/zebra.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-interface r7-eth0
- ip address 4.4.4.7/24
-!
-ip route 0.0.0.0/0 4.4.4.4
diff --git a/tests/topotests/nhrp_redundancy/r6/zebra.conf b/tests/topotests/nhrp_redundancy/router/frr.conf
index 63a37cd5bf..c0eb19ca40 100644
--- a/tests/topotests/nhrp_redundancy/r6/zebra.conf
+++ b/tests/topotests/nhrp_redundancy/router/frr.conf
@@ -1,7 +1,7 @@
ip forwarding
-interface r6-eth0
+interface router-eth0
ip address 192.168.1.6/24
!
-interface r6-eth1
+interface router-eth1
ip address 192.168.2.6/24
exit
diff --git a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot
index c169436db0..e94e1d0734 100644
--- a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot
+++ b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot
@@ -16,43 +16,43 @@ graph template {
label="nhrp-topo-redundant-nhs";
# Routers
- r1 [
+ nhs1 [
shape=doubleoctagon,
label="NHS 1",
fillcolor="#f08080",
style=filled,
];
- r2 [
+ nhs2 [
shape=doubleoctagon
label="NHS 2",
fillcolor="#f08080",
style=filled,
];
- r3 [
+ nhs3 [
shape=doubleoctagon
label="NHS 3",
fillcolor="#f08080",
style=filled,
];
- r4 [
+ nhc1 [
shape=doubleoctagon
label="NHC 1",
fillcolor="#f08080",
style=filled,
];
- r5 [
+ nhc2 [
shape=doubleoctagon
label="NHC 2",
fillcolor="#f08080",
style=filled,
];
- r6 [
+ router [
shape=doubleoctagon
label="router",
fillcolor="#f08080",
style=filled,
];
- r7 [
+ host [
shape=doubleoctagon
label="host",
fillcolor="#f08080",
@@ -74,30 +74,30 @@ graph template {
];
sw3 [
shape=oval,
- label="sw3\n4.4.4.0/24",
+ label="sw3\n10.4.4.0/24",
fillcolor="#d0e0d0",
style=filled,
];
sw4 [
shape=oval,
- label="sw4\n5.5.5.0/24",
+ label="sw4\n10.5.5.0/24",
fillcolor="#d0e0d0",
style=filled,
];
# Connections
- r1 -- sw1 [label="eth0"];
- r2 -- sw1 [label="eth0"];
- r3 -- sw1 [label="eth0"];
- r6 -- sw1 [label="eth0"];
+ nhs1 -- sw1 [label="eth0"];
+ nhs2 -- sw1 [label="eth0"];
+ nhs3 -- sw1 [label="eth0"];
+ router -- sw1 [label="eth0"];
- r4 -- sw2 [label="eth0"];
- r5 -- sw2 [label="eth0"];
- r6 -- sw2 [label="eth1"];
+ nhc1 -- sw2 [label="eth0"];
+ nhc2 -- sw2 [label="eth0"];
+ router -- sw2 [label="eth1"];
- r4 -- sw3 [label="eth1"];
- r7 -- sw3 [label="eth0"];
+ nhc1 -- sw3 [label="eth1"];
+ host -- sw3 [label="eth0"];
- r5 -- sw4 [label="eth1"];
+ nhc2 -- sw4 [label="eth1"];
}
diff --git a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py
index ffd9abc9d4..d4cf98596c 100644
--- a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py
+++ b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py
@@ -29,38 +29,38 @@ test_nhrp_redundancy.py: Test NHS redundancy for NHRP
"""
TOPOLOGY = """
-+------------+ +------------+ +------------+
-| | | | | |
-| | | | | |
-| NHS 1 | | NHS 2 | | NHS 3 |
-| | | | | |
-+-----+------+ +-----+------+ +-----+------+
- |.1 |.2 |.3
- | | |
- | | 192.168.1.0/24 |
-------+-------------------------------+------------------+-------------+------
- |
- |.6
- GRE P2MP between all NHS and NHC +-----+------+
- 172.16.1.x/32 | |
- | |
- | Router |
- | |
- +-----+------+
- |
- |
- ---------+----------------+-------------+------
- | 192.168.2.0/24 |
- | |
- | |.4 |.5
-+------------+ | +-------+----+ +------+-----+ |
-| | | | | | | |
-| | +--------+ | | | |
-| Host |.7 | | NHC 1 | | NHC 2 +-----+5.5.5.0/24
-| +---------+ | | | | |
-+------------+ | +------------+ +------------+ |
- | |
- 4.4.4.0/24
++------------+ +------------+ +------------+
+| | | | | |
+| | | | | |
+| NHS 1 | | NHS 2 | | NHS 3 |
+| | | | | |
++-----+------+ +-----+------+ +-----+------+
+ |.1 |.2 |.3
+ | | |
+ | | 192.168.1.0/24 |
+------+-------------------------------+------------------+-------------+------
+ |
+ |.6
+ GRE P2MP between all NHS and NHC +-----+------+
+ 172.16.1.x/32 | |
+ | |
+ | Router |
+ | |
+ +-----+------+
+ |
+ |
+ ---------+----------------+-------------+------
+ | 192.168.2.0/24 |
+ | |
+ | |.4 |.5
++------------+ | +-------+----+ +------+-----+ |
+| | | | | | | |
+| | +--------+ | | | |
+| Host |.7 | | NHC 1 | | NHC 2 +-----+10.5.5.0/24
+| +---------+ | | | | |
++------------+ | +------------+ +------------+ |
+ | |
+ 10.4.4.0/24
"""
# Save the Current Working Directory to find configuration files.
@@ -76,30 +76,26 @@ def build_topo(tgen):
"Build function"
# Create 7 routers
- for routern in range(1, 8):
- tgen.add_router("r{}".format(routern))
+ for rname in ["nhs1", "nhs2", "nhs3", "nhc1", "nhc2", "router", "host"]:
+ tgen.add_router(rname)
- # Interconnect routers 1, 2, 3, 6
switch = tgen.add_switch("s1")
- switch.add_link(tgen.gears["r1"])
- switch.add_link(tgen.gears["r2"])
- switch.add_link(tgen.gears["r3"])
- switch.add_link(tgen.gears["r6"])
+ switch.add_link(tgen.gears["nhs1"])
+ switch.add_link(tgen.gears["nhs2"])
+ switch.add_link(tgen.gears["nhs3"])
+ switch.add_link(tgen.gears["router"])
- # Interconnect routers 4, 5, 6
switch = tgen.add_switch("s2")
- switch.add_link(tgen.gears["r4"])
- switch.add_link(tgen.gears["r5"])
- switch.add_link(tgen.gears["r6"])
+ switch.add_link(tgen.gears["nhc1"])
+ switch.add_link(tgen.gears["nhc2"])
+ switch.add_link(tgen.gears["router"])
- # Connect router 4, 7
switch = tgen.add_switch("s3")
- switch.add_link(tgen.gears["r4"])
- switch.add_link(tgen.gears["r7"])
+ switch.add_link(tgen.gears["nhc1"])
+ switch.add_link(tgen.gears["host"])
- # Connect router 5
switch = tgen.add_switch("s4")
- switch.add_link(tgen.gears["r5"])
+ switch.add_link(tgen.gears["nhc2"])
def _populate_iface():
@@ -110,7 +106,7 @@ def _populate_iface():
"echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu",
"echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6",
"echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6",
- "iptables -A FORWARD -i {0}-gre0 -o {0}-gre0 -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 --hashlimit-dstmask 24 --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-range 128",
+ "iptables -A FORWARD -i {0}-gre0 -o {0}-gre0 -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 --hashlimit-dstmask 24 --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-size 128",
]
cmds_tot = [
@@ -122,41 +118,38 @@ def _populate_iface():
]
for cmd in cmds_tot_hub:
- # Router 1
- input = cmd.format("r1", "1")
+ input = cmd.format("nhs1", "1")
logger.info("input: " + input)
- output = tgen.net["r1"].cmd(input)
+ output = tgen.net["nhs1"].cmd(input)
logger.info("output: " + output)
- # Router 2
- input = cmd.format("r2", "2")
+ input = cmd.format("nhs2", "2")
logger.info("input: " + input)
- output = tgen.net["r2"].cmd(input)
+ output = tgen.net["nhs2"].cmd(input)
logger.info("output: " + output)
- # Router 3
- input = cmd.format("r3", "3")
+ input = cmd.format("nhs3", "3")
logger.info("input: " + input)
- output = tgen.net["r3"].cmd(input)
+ output = tgen.net["nhs3"].cmd(input)
logger.info("output: " + output)
for cmd in cmds_tot:
- input = cmd.format("r4", "4")
+ input = cmd.format("nhc1", "4")
logger.info("input: " + input)
- output = tgen.net["r4"].cmd(input)
+ output = tgen.net["nhc1"].cmd(input)
logger.info("output: " + output)
- input = cmd.format("r5", "5")
+ input = cmd.format("nhc2", "5")
logger.info("input: " + input)
- output = tgen.net["r5"].cmd(input)
+ output = tgen.net["nhc2"].cmd(input)
logger.info("output: " + output)
def _verify_iptables():
tgen = get_topogen()
# Verify iptables is installed. Required for shortcuts
- rc, _, _ = tgen.net["r1"].cmd_status("iptables")
- return False if rc == 127 else True
+ rc, _, _ = tgen.net["nhs1"].cmd_status("iptables -V")
+ return True if rc == 0 else False
def setup_module(mod):
@@ -174,14 +167,8 @@ def setup_module(mod):
_populate_iface()
for rname, router in router_list.items():
- router.load_config(
- TopoRouter.RD_ZEBRA,
- os.path.join(CWD, "{}/zebra.conf".format(rname)),
- )
- if rname in ("r1", "r2", "r3", "r4", "r5"):
- router.load_config(
- TopoRouter.RD_NHRP, os.path.join(CWD, "{}/nhrpd.conf".format(rname))
- )
+ logger.info("Loading router %s" % rname)
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
# Initialize all routers.
tgen.start_router()
@@ -202,17 +189,15 @@ def test_protocols_convergence():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info("Checking NHRP cache and IPv4 routes for convergence")
+ logger.info("Checking NHRP cache for convergence")
router_list = tgen.routers()
# Check NHRP cache on servers and clients
- for _, router in router_list.items():
-
- json_file = "{}/{}/nhrp_cache.json".format(CWD, router.name)
- if not os.path.isfile(json_file):
- logger.info("skipping file {}".format(json_file))
+ for rname, router in router_list.items():
+ if "nh" not in rname:
continue
+ json_file = "{}/{}/nhrp_cache.json".format(CWD, router.name)
expected = json.loads(open(json_file).read())
test_func = partial(
topotest.router_json_cmp, router, "show ip nhrp cache json", expected
@@ -226,13 +211,12 @@ def test_protocols_convergence():
assert result is None, assertmsg
# Check NHRP IPV4 routes on servers and clients
+ logger.info("Checking IPv4 routes for convergence")
for rname, router in router_list.items():
-
- json_file = "{}/{}/nhrp_route.json".format(CWD, router.name)
- if not os.path.isfile(json_file):
- logger.info("skipping file {}".format(json_file))
+ if "nh" not in rname:
continue
+ json_file = "{}/{}/nhrp_route.json".format(CWD, router.name)
expected = json.loads(open(json_file).read())
test_func = partial(
topotest.router_json_cmp, router, "show ip route nhrp json", expected
@@ -246,53 +230,53 @@ def test_protocols_convergence():
assert result is None, assertmsg
# Test connectivity from 1 NHRP server to all clients
- pingrouter = tgen.gears["r1"]
- logger.info("Check Ping IPv4 from R1 to R4 = 176.16.1.4)")
- output = pingrouter.run("ping 176.16.1.4 -f -c 1000")
+ nhs1 = tgen.gears["nhs1"]
+ logger.info("Check Ping IPv4 from nhs1 to nhc1 = 172.16.1.4)")
+ output = nhs1.run("ping 172.16.1.4 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
- assertmsg = "expected ping IPv4 from R1 to R4 should be ok"
+ assertmsg = "expected ping IPv4 from nhs1 to nhc1 should be ok"
assert 0, assertmsg
else:
- logger.info("Check Ping IPv4 from R1 to R4 OK")
+ logger.info("Check Ping IPv4 from nhs1 to nhc1 OK")
- logger.info("Check Ping IPv4 from R1 to R5 = 176.16.1.5)")
- output = pingrouter.run("ping 176.16.1.5 -f -c 1000")
+ logger.info("Check Ping IPv4 from nhs1 to nhc2 = 172.16.1.5)")
+ output = nhs1.run("ping 172.16.1.5 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
- assertmsg = "expected ping IPv4 from R1 to R5 should be ok"
+ assertmsg = "expected ping IPv4 from nhs1 to nhc2 should be ok"
assert 0, assertmsg
else:
- logger.info("Check Ping IPv4 from R1 to R5 OK")
+ logger.info("Check Ping IPv4 from nhs1 to nhc2 OK")
# Test connectivity from 1 NHRP client to all servers
- pingrouter = tgen.gears["r4"]
- logger.info("Check Ping IPv4 from R4 to R1 = 176.16.1.1)")
- output = pingrouter.run("ping 176.16.1.1 -f -c 1000")
+ nhc1 = tgen.gears["nhc1"]
+ logger.info("Check Ping IPv4 from nhc1 to nhs1 = 172.16.1.1)")
+ output = nhc1.run("ping 172.16.1.1 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
- assertmsg = "expected ping IPv4 from R4 to R1 should be ok"
+ assertmsg = "expected ping IPv4 from nhc1 to nhs1 should be ok"
assert 0, assertmsg
else:
- logger.info("Check Ping IPv4 from R4 to R1 OK")
+ logger.info("Check Ping IPv4 from nhc1 to nhs1 OK")
- logger.info("Check Ping IPv4 from R4 to R2 = 176.16.1.2)")
- output = pingrouter.run("ping 176.16.1.2 -f -c 1000")
+ logger.info("Check Ping IPv4 from nhc1 to nhs2 = 172.16.1.2)")
+ output = nhc1.run("ping 172.16.1.2 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
- assertmsg = "expected ping IPv4 from R4 to R2 should be ok"
+ assertmsg = "expected ping IPv4 from nhc1 to nhs2 should be ok"
assert 0, assertmsg
else:
- logger.info("Check Ping IPv4 from R4 to R2 OK")
+ logger.info("Check Ping IPv4 from nhc1 to nhs2 OK")
- logger.info("Check Ping IPv4 from R4 to R3 = 176.16.1.3)")
- output = pingrouter.run("ping 176.16.1.3 -f -c 1000")
+ logger.info("Check Ping IPv4 from nhc1 to nhs3 = 172.16.1.3)")
+ output = nhc1.run("ping 172.16.1.3 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
- assertmsg = "expected ping IPv4 from R4 to R3 should be ok"
+ assertmsg = "expected ping IPv4 from nhc1 to nhs3 should be ok"
assert 0, assertmsg
else:
- logger.info("Check Ping IPv4 from R4 to R3 OK")
+ logger.info("Check Ping IPv4 from nhc1 to nhs3 OK")
@retry(retry_timeout=30, initial_wait=5)
@@ -301,22 +285,21 @@ def verify_shortcut_path():
Verifying that traffic flows through shortcut path
"""
tgen = get_topogen()
- pingrouter = tgen.gears["r7"]
- logger.info("Check Ping IPv4 from R7 to R5 = 5.5.5.5")
+ host = tgen.gears["host"]
+ logger.info("Check Ping IPv4 from host to nhc2 = 10.5.5.5")
- output = pingrouter.run("ping 5.5.5.5 -f -c 1000")
+ output = host.run("ping 10.5.5.5 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
- assertmsg = "expected ping IPv4 from R7 to R5 should be ok"
+ assertmsg = "expected ping IPv4 from host to nhc2 should be ok"
assert 0, assertmsg
else:
- logger.info("Check Ping IPv4 from R7 to R5 OK")
+ logger.info("Check Ping IPv4 from host to nhc2 OK")
def test_redundancy_shortcut():
"""
Assert that if shortcut created and then NHS goes down, there is no traffic disruption
- Stop traffic and verify next time traffic started, shortcut is initiated by backup NHS
"""
tgen = get_topogen()
if tgen.routers_have_failure():
@@ -327,84 +310,207 @@ def test_redundancy_shortcut():
logger.info("Testing NHRP shortcuts with redundant servers")
- # Verify R4 nhrp routes before shortcut creation
- router = tgen.gears["r4"]
- json_file = "{}/{}/nhrp_route.json".format(CWD, router.name)
+ # Verify nhc1 nhrp routes before shortcut creation
+ nhc1 = tgen.gears["nhc1"]
+ json_file = "{}/{}/nhrp_route.json".format(CWD, nhc1.name)
assertmsg = "No nhrp_route file found"
assert os.path.isfile(json_file), assertmsg
expected = json.loads(open(json_file).read())
test_func = partial(
- topotest.router_json_cmp, router, "show ip route nhrp json", expected
+ topotest.router_json_cmp, nhc1, "show ip route nhrp json", expected
)
_, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
- output = router.vtysh_cmd("show ip route nhrp")
+ output = nhc1.vtysh_cmd("show ip route nhrp")
logger.info(output)
- assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
assert result is None, assertmsg
# Initiate shortcut by pinging between clients
- pingrouter = tgen.gears["r7"]
- logger.info("Check Ping IPv4 from R7 to R5 via shortcut = 5.5.5.5")
+ host = tgen.gears["host"]
+ logger.info("Check Ping IPv4 from host to nhc2 via shortcut = 10.5.5.5")
- output = pingrouter.run("ping 5.5.5.5 -f -c 1000")
+ output = host.run("ping 10.5.5.5 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
- assertmsg = "expected ping IPv4 from R7 to R5 via shortcut should be ok"
+ assertmsg = "expected ping IPv4 from host to nhc2 via shortcut should be ok"
assert 0, assertmsg
else:
- logger.info("Check Ping IPv4 from R7 to R5 via shortcut OK")
+ logger.info("Check Ping IPv4 from host to nhc2 via shortcut OK")
# Now check that NHRP shortcut route installed
- json_file = "{}/{}/nhrp_route_shortcut.json".format(CWD, router.name)
+ json_file = "{}/{}/nhrp_route_shortcut.json".format(CWD, nhc1.name)
assertmsg = "No nhrp_route file found"
assert os.path.isfile(json_file), assertmsg
expected = json.loads(open(json_file).read())
test_func = partial(
- topotest.router_json_cmp, router, "show ip route nhrp json", expected
+ topotest.router_json_cmp, nhc1, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+ json_file = "{}/{}/nhrp_shortcut_present.json".format(CWD, nhc1.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip nhrp shortcut json", expected
)
_, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
- output = router.vtysh_cmd("show ip route nhrp")
+ output = nhc1.vtysh_cmd("show ip nhrp shortcut")
logger.info(output)
- assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
assert result is None, assertmsg
+ # check the shortcut disappears because of no traffic
+ json_file = "{}/{}/nhrp_shortcut_absent.json".format(CWD, nhc1.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip nhrp shortcut json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip nhrp shortcut")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+
+def test_redundancy_shortcut_backup():
+ """
+ Stop traffic and verify next time traffic started, shortcut is initiated by backup NHS
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ if not _verify_iptables():
+ pytest.skip("iptables not installed")
+
+ nhc1 = tgen.gears["nhc1"]
+ router_list = tgen.routers()
+
# Bring down primary GRE interface and verify shortcut is not disturbed
- logger.info("Bringing down R1, primary NHRP server.")
- shutdown_bringup_interface(tgen, "r1", "r1-gre0", False)
+ logger.info("Bringing down nhs1, primary NHRP server.")
+ shutdown_bringup_interface(tgen, "nhs1", "nhs1-gre0", False)
+
+ # Check NHRP cache on servers and clients
+ for rname, router in router_list.items():
+ if "nh" not in rname:
+ continue
+ if "nhs1" in rname:
+ continue
+
+ json_file = "{}/{}/nhrp_cache_nhs1_down.json".format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip nhrp cache json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = router.vtysh_cmd("show ip nhrp cache")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Check NHRP IPV4 routes on servers and clients
+ logger.info("Checking IPv4 routes for convergence")
+ for rname, router in router_list.items():
+ if "nh" not in rname:
+ continue
+ if "nhs1" in rname:
+ continue
+
+ json_file = "{}/{}/nhrp_route_nhs1_down.json".format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = router.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
# Verify shortcut is still active
- pingrouter = tgen.gears["r7"]
- logger.info("Check Ping IPv4 from R7 to R5 via shortcut = 5.5.5.5")
+ host = tgen.gears["host"]
+ logger.info("Check Ping IPv4 from host to nhc2 via shortcut = 10.5.5.5")
- output = pingrouter.run("ping 5.5.5.5 -f -c 1000")
+ output = host.run("ping 10.5.5.5 -f -c 1000")
logger.info(output)
if "1000 packets transmitted, 1000 received" not in output:
- assertmsg = "expected ping IPv4 from R7 to R5 via shortcut should be ok"
+ assertmsg = "expected ping IPv4 from host to nhc2 via shortcut should be ok"
assert 0, assertmsg
else:
- logger.info("Check Ping IPv4 from R7 to R5 via shortcut OK")
+ logger.info("Check Ping IPv4 from host to nhc2 via shortcut OK")
+
+ # Verify shortcut is present in routing table
+ json_file = "{}/{}/nhrp_route_shortcut_nhs1_down.json".format(CWD, nhc1.name)
+ assertmsg = "No nhrp_route file found"
+ assert os.path.isfile(json_file), assertmsg
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ json_file = "{}/{}/nhrp_shortcut_present.json".format(CWD, nhc1.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip nhrp shortcut json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip nhrp shortcut")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
# Now verify shortcut is purged with lack of traffic
- json_file = "{}/{}/nhrp_route.json".format(CWD, router.name)
+ json_file = "{}/{}/nhrp_route_nhs1_down.json".format(CWD, nhc1.name)
assertmsg = "No nhrp_route file found"
assert os.path.isfile(json_file), assertmsg
expected = json.loads(open(json_file).read())
test_func = partial(
- topotest.router_json_cmp, router, "show ip route nhrp json", expected
+ topotest.router_json_cmp, nhc1, "show ip route nhrp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+
+ output = nhc1.vtysh_cmd("show ip route nhrp")
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
+ assert result is None, assertmsg
+
+ json_file = "{}/{}/nhrp_shortcut_absent.json".format(CWD, nhc1.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, nhc1, "show ip nhrp shortcut json", expected
)
_, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
- output = router.vtysh_cmd("show ip route nhrp")
+ output = nhc1.vtysh_cmd("show ip nhrp shortcut")
logger.info(output)
- assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assertmsg = '"{}" JSON output mismatches'.format(nhc1.name)
assert result is None, assertmsg
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
index 248375dc6c..131085a47a 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
@@ -1,11 +1,11 @@
O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX
-C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX
-L>* 10.0.1.1/32 is directly connected, r1-eth0, XX:XX:XX
+C>* 10.0.1.0/24 is directly connected, r1-eth0, weight 1, XX:XX:XX
+L>* 10.0.1.1/32 is directly connected, r1-eth0, weight 1, XX:XX:XX
O>* 10.0.2.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
-B>* 10.0.3.0/24 [20/20] via 10.0.30.3, r1-eth2 (vrf neno), weight 1, XX:XX:XX
+B>* 10.0.3.0/24 [110/20] via 10.0.30.3, r1-eth2 (vrf neno), weight 1, XX:XX:XX
O>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
O 10.0.20.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX
-C>* 10.0.20.0/24 is directly connected, r1-eth1, XX:XX:XX
-L>* 10.0.20.1/32 is directly connected, r1-eth1, XX:XX:XX
+C>* 10.0.20.0/24 is directly connected, r1-eth1, weight 1, XX:XX:XX
+L>* 10.0.20.1/32 is directly connected, r1-eth1, weight 1, XX:XX:XX
B>* 10.0.30.0/24 [20/0] is directly connected, neno (vrf neno), weight 1, XX:XX:XX
O>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt
index 6e1335243b..45ee1071d4 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt
@@ -1,7 +1,7 @@
VRF neno:
O>* 10.0.3.0/24 [110/20] via 10.0.30.3, r1-eth2, weight 1, XX:XX:XX
-B>* 10.0.4.0/24 [20/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX
+B>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX
O 10.0.30.0/24 [110/10] is directly connected, r1-eth2, weight 1, XX:XX:XX
-C>* 10.0.30.0/24 is directly connected, r1-eth2, XX:XX:XX
-L>* 10.0.30.1/32 is directly connected, r1-eth2, XX:XX:XX
-B>* 10.0.40.0/24 [20/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX
+C>* 10.0.30.0/24 is directly connected, r1-eth2, weight 1, XX:XX:XX
+L>* 10.0.30.1/32 is directly connected, r1-eth2, weight 1, XX:XX:XX
+B>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
index d7d31434c6..f3724bbb9f 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
@@ -1,12 +1,12 @@
S>* 0.0.0.0/0 [1/0] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
O>* 10.0.1.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX
-C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX
-L>* 10.0.2.2/32 is directly connected, r2-eth0, XX:XX:XX
+C>* 10.0.2.0/24 is directly connected, r2-eth0, weight 1, XX:XX:XX
+L>* 10.0.2.2/32 is directly connected, r2-eth0, weight 1, XX:XX:XX
O>* 10.0.3.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
-B>* 10.0.4.0/24 [20/20] via 10.0.40.4, r2-eth2 (vrf ray), weight 1, XX:XX:XX
+B>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2 (vrf ray), weight 1, XX:XX:XX
O 10.0.20.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX
-C>* 10.0.20.0/24 is directly connected, r2-eth1, XX:XX:XX
-L>* 10.0.20.2/32 is directly connected, r2-eth1, XX:XX:XX
+C>* 10.0.20.0/24 is directly connected, r2-eth1, weight 1, XX:XX:XX
+L>* 10.0.20.2/32 is directly connected, r2-eth1, weight 1, XX:XX:XX
O>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
B>* 10.0.40.0/24 [20/0] is directly connected, ray (vrf ray), weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
index 1495c88936..0f8b12bdfa 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
@@ -1,10 +1,10 @@
VRF ray:
-B 10.0.1.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
+B 10.0.1.0/24 [110/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
B 10.0.2.0/24 [20/0] is directly connected, r2-eth0 (vrf default) inactive, weight 1, XX:XX:XX
-B>* 10.0.3.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
+B>* 10.0.3.0/24 [110/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
O>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2, weight 1, XX:XX:XX
B 10.0.20.0/24 [20/0] is directly connected, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
-B>* 10.0.30.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
+B>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
O 10.0.40.0/24 [110/10] is directly connected, r2-eth2, weight 1, XX:XX:XX
-C>* 10.0.40.0/24 is directly connected, r2-eth2, XX:XX:XX
-L>* 10.0.40.2/32 is directly connected, r2-eth2, XX:XX:XX
+C>* 10.0.40.0/24 is directly connected, r2-eth2, weight 1, XX:XX:XX
+L>* 10.0.40.2/32 is directly connected, r2-eth2, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt
index b1701fe177..db4e268cb0 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt
@@ -1,10 +1,10 @@
O 10.0.3.0/24 [110/10] is directly connected, r3-eth0, weight 1, XX:XX:XX
-C>* 10.0.3.0/24 is directly connected, r3-eth0, XX:XX:XX
-L>* 10.0.3.3/32 is directly connected, r3-eth0, XX:XX:XX
+C>* 10.0.3.0/24 is directly connected, r3-eth0, weight 1, XX:XX:XX
+L>* 10.0.3.3/32 is directly connected, r3-eth0, weight 1, XX:XX:XX
O>* 10.0.4.0/24 [110/20] via 10.0.30.1, r3-eth1, weight 1, XX:XX:XX
O 10.0.30.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX
-C>* 10.0.30.0/24 is directly connected, r3-eth1, XX:XX:XX
-L>* 10.0.30.3/32 is directly connected, r3-eth1, XX:XX:XX
+C>* 10.0.30.0/24 is directly connected, r3-eth1, weight 1, XX:XX:XX
+L>* 10.0.30.3/32 is directly connected, r3-eth1, weight 1, XX:XX:XX
O>* 10.0.40.0/24 [110/20] via 10.0.30.1, r3-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt
index 3723a8a8cb..4865708578 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt
@@ -1,9 +1,9 @@
O>* 10.0.3.0/24 [110/20] via 10.0.40.2, r4-eth1, weight 1, XX:XX:XX
O 10.0.4.0/24 [110/10] is directly connected, r4-eth0, weight 1, XX:XX:XX
-C>* 10.0.4.0/24 is directly connected, r4-eth0, XX:XX:XX
-L>* 10.0.4.4/32 is directly connected, r4-eth0, XX:XX:XX
+C>* 10.0.4.0/24 is directly connected, r4-eth0, weight 1, XX:XX:XX
+L>* 10.0.4.4/32 is directly connected, r4-eth0, weight 1, XX:XX:XX
O>* 10.0.30.0/24 [110/20] via 10.0.40.2, r4-eth1, weight 1, XX:XX:XX
O 10.0.40.0/24 [110/10] is directly connected, r4-eth1, weight 1, XX:XX:XX
-C>* 10.0.40.0/24 is directly connected, r4-eth1, XX:XX:XX
-L>* 10.0.40.4/32 is directly connected, r4-eth1, XX:XX:XX
+C>* 10.0.40.0/24 is directly connected, r4-eth1, weight 1, XX:XX:XX
+L>* 10.0.40.4/32 is directly connected, r4-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt
index bf874ac762..68fd30d4cc 100644
--- a/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt
+++ b/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt
@@ -1,10 +1,10 @@
VRF r1-ospf-cust1:
O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX
-C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX
-L>* 10.0.1.1/32 is directly connected, r1-eth0, XX:XX:XX
+C>* 10.0.1.0/24 is directly connected, r1-eth0, weight 1, XX:XX:XX
+L>* 10.0.1.1/32 is directly connected, r1-eth0, weight 1, XX:XX:XX
O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX
O 10.0.3.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX
-C>* 10.0.3.0/24 is directly connected, r1-eth1, XX:XX:XX
-L>* 10.0.3.2/32 is directly connected, r1-eth1, XX:XX:XX
+C>* 10.0.3.0/24 is directly connected, r1-eth1, weight 1, XX:XX:XX
+L>* 10.0.3.2/32 is directly connected, r1-eth1, weight 1, XX:XX:XX
O>* 10.0.10.0/24 [110/20] via 10.0.3.1, r1-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt b/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt
index e515205307..f0bce905b1 100644
--- a/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt
+++ b/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt
@@ -1,9 +1,9 @@
VRF r1-ospf-cust1:
O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX
-C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX
-L>* 10.0.1.1/32 is directly connected, r1-eth0, XX:XX:XX
+C>* 10.0.1.0/24 is directly connected, r1-eth0, weight 1, XX:XX:XX
+L>* 10.0.1.1/32 is directly connected, r1-eth0, weight 1, XX:XX:XX
O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX
O 10.0.3.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX
-C>* 10.0.3.0/24 is directly connected, r1-eth1, XX:XX:XX
-L>* 10.0.3.2/32 is directly connected, r1-eth1, XX:XX:XX
+C>* 10.0.3.0/24 is directly connected, r1-eth1, weight 1, XX:XX:XX
+L>* 10.0.3.2/32 is directly connected, r1-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt
index 3763ef8006..098eceb28b 100644
--- a/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt
+++ b/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt
@@ -1,10 +1,10 @@
VRF r2-ospf-cust1:
O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX
O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX
-C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX
-L>* 10.0.2.1/32 is directly connected, r2-eth0, XX:XX:XX
+C>* 10.0.2.0/24 is directly connected, r2-eth0, weight 1, XX:XX:XX
+L>* 10.0.2.1/32 is directly connected, r2-eth0, weight 1, XX:XX:XX
O 10.0.3.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX
-C>* 10.0.3.0/24 is directly connected, r2-eth1, XX:XX:XX
-L>* 10.0.3.3/32 is directly connected, r2-eth1, XX:XX:XX
+C>* 10.0.3.0/24 is directly connected, r2-eth1, weight 1, XX:XX:XX
+L>* 10.0.3.3/32 is directly connected, r2-eth1, weight 1, XX:XX:XX
O>* 10.0.10.0/24 [110/20] via 10.0.3.1, r2-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt b/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt
index f6eaba6e1d..a9300f8dfa 100644
--- a/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt
+++ b/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt
@@ -1,9 +1,9 @@
VRF r2-ospf-cust1:
O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX
O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX
-C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX
-L>* 10.0.2.1/32 is directly connected, r2-eth0, XX:XX:XX
+C>* 10.0.2.0/24 is directly connected, r2-eth0, weight 1, XX:XX:XX
+L>* 10.0.2.1/32 is directly connected, r2-eth0, weight 1, XX:XX:XX
O 10.0.3.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX
-C>* 10.0.3.0/24 is directly connected, r2-eth1, XX:XX:XX
-L>* 10.0.3.3/32 is directly connected, r2-eth1, XX:XX:XX
+C>* 10.0.3.0/24 is directly connected, r2-eth1, weight 1, XX:XX:XX
+L>* 10.0.3.3/32 is directly connected, r2-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt
index 5eb92efd20..f58beb81a7 100644
--- a/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt
+++ b/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt
@@ -2,9 +2,9 @@ VRF r3-ospf-cust1:
O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r3-eth0, weight 1, XX:XX:XX
O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r3-eth0, weight 1, XX:XX:XX
O 10.0.3.0/24 [110/10] is directly connected, r3-eth0, weight 1, XX:XX:XX
-C>* 10.0.3.0/24 is directly connected, r3-eth0, XX:XX:XX
-L>* 10.0.3.1/32 is directly connected, r3-eth0, XX:XX:XX
+C>* 10.0.3.0/24 is directly connected, r3-eth0, weight 1, XX:XX:XX
+L>* 10.0.3.1/32 is directly connected, r3-eth0, weight 1, XX:XX:XX
O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX
-C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX
-L>* 10.0.10.1/32 is directly connected, r3-eth1, XX:XX:XX
+C>* 10.0.10.0/24 is directly connected, r3-eth1, weight 1, XX:XX:XX
+L>* 10.0.10.1/32 is directly connected, r3-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt b/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt
index 26cc19660a..cfedf8fcb4 100644
--- a/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt
+++ b/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt
@@ -1,5 +1,5 @@
VRF r3-ospf-cust1:
O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX
-C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX
-L>* 10.0.10.1/32 is directly connected, r3-eth1, XX:XX:XX
+C>* 10.0.10.0/24 is directly connected, r3-eth1, weight 1, XX:XX:XX
+L>* 10.0.10.1/32 is directly connected, r3-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py
index eae8806a59..718445f01f 100644
--- a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py
+++ b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py
@@ -234,7 +234,7 @@ def test_ospf_json():
"show ip ospf vrf {0}-ospf-cust1 json".format(rname),
expected,
)
- _, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ _, diff = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"{}" JSON output mismatches'.format(rname)
assert diff is None, assertmsg
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
index d981a84597..00d4e8ffdb 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
@@ -704,11 +704,6 @@ def test_ospfv3_hello_tc10_p0(request):
tc_name, result
)
- step("verify that ospf neighbours are full")
- ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut)
- assert ospf_covergence is True, "Testcase {} [22]: Failed \n Error: {}".format(
- tc_name, ospf_covergence
- )
step(" Try configuring timer values outside range for example 65536")
topo1 = {
"r0": {
@@ -790,7 +785,9 @@ def test_ospfv3_dead_tc11_p0(request):
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [01]: Failed \n Error: {}".format(
+ tc_name, result
+ )
step(
"verify that new timer value is configured and applied using "
@@ -799,7 +796,9 @@ def test_ospfv3_dead_tc11_p0(request):
dut = "r1"
input_dict = {"r1": {"links": {"r0": {"ospf6": {"timerIntervalsConfigDead": 48}}}}}
result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [02]: Failed \n Error: {}".format(
+ tc_name, result
+ )
step("modify dead interval from default value to r1 dead interval timer on r2")
@@ -808,31 +807,35 @@ def test_ospfv3_dead_tc11_p0(request):
"links": {
"r1": {
"interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
- "ospf6": {"dead_interval": 48, "hello_interval": 12},
+ "ospf6": {"hello_interval": 12, "dead_interval": 48},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [03]: Failed \n Error: {}".format(
+ tc_name, result
+ )
step("verify that new timer value is configured.")
input_dict = {"r0": {"links": {"r1": {"ospf6": {"timerIntervalsConfigDead": 48}}}}}
dut = "r0"
result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [04]: Failed \n Error: {}".format(
+ tc_name, result
+ )
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut)
- assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format(
+ assert ospf_covergence is True, "Testcase {} [05]: Failed \n Error: {}".format(
tc_name, ospf_covergence
)
step("remove ospf on R0")
ospf_del = {"r0": {"ospf6": {"delete": True}}}
result = create_router_ospf(tgen, topo, ospf_del)
- assert result is True, "Testcase : Failed \n Error: {}".format(result)
+ assert result is True, "Testcase [06]: Failed \n Error: {}".format(result)
# reconfiguring deleted ospf process by resetting the configs.
reset_config_on_routers(tgen)
@@ -850,7 +853,9 @@ def test_ospfv3_dead_tc11_p0(request):
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [07]: Failed \n Error: {}".format(
+ tc_name, result
+ )
topo1 = {
"r1": {
@@ -864,17 +869,21 @@ def test_ospfv3_dead_tc11_p0(request):
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [08]: Failed \n Error: {}".format(
+ tc_name, result
+ )
step("verify that new timer value is configured.")
input_dict = {"r0": {"links": {"r1": {"ospf6": {"timerIntervalsConfigDead": 40}}}}}
dut = "r0"
result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [09]: Failed \n Error: {}".format(
+ tc_name, result
+ )
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut)
- assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format(
+ assert ospf_covergence is True, "Testcase {} [10]: Failed \n Error: {}".format(
tc_name, ospf_covergence
)
@@ -892,7 +901,9 @@ def test_ospfv3_dead_tc11_p0(request):
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [11]: Failed \n Error: {}".format(
+ tc_name, result
+ )
topo1 = {
"r1": {
@@ -906,7 +917,9 @@ def test_ospfv3_dead_tc11_p0(request):
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [12]: Failed \n Error: {}".format(
+ tc_name, result
+ )
step("verify that new timer value is configured.")
input_dict = {
@@ -914,11 +927,13 @@ def test_ospfv3_dead_tc11_p0(request):
}
dut = "r0"
result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [13]: Failed \n Error: {}".format(
+ tc_name, result
+ )
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut)
- assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format(
+ assert ospf_covergence is True, "Testcase {} [14]: Failed \n Error: {}".format(
tc_name, ospf_covergence
)
@@ -937,7 +952,7 @@ def test_ospfv3_dead_tc11_p0(request):
result = create_interfaces_cfg(tgen, topo1)
assert (
result is not True
- ), "Testcase {} : Failed \n Create interface config failed. Error: {}".format(
+ ), "Testcase {} [15]: Failed \n Create interface config failed. Error: {}".format(
tc_name, result
)
@@ -956,13 +971,17 @@ def test_ospfv3_dead_tc11_p0(request):
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [16]: 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": {"ospf6": {"timerIntervalsConfigDead": 40}}}}}
dut = "r1"
result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} [17]: Failed \n Error: {}".format(
+ tc_name, result
+ )
write_test_footer(tc_name)
diff --git a/tests/topotests/pim_autorp/__init__.py b/tests/topotests/pim_autorp/__init__.py
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/pim_autorp/__init__.py
diff --git a/tests/topotests/pim_autorp/r1/frr.conf b/tests/topotests/pim_autorp/r1/frr.conf
new file mode 100644
index 0000000000..2fddbc3ae2
--- /dev/null
+++ b/tests/topotests/pim_autorp/r1/frr.conf
@@ -0,0 +1,16 @@
+!
+hostname r1
+password zebra
+log file /tmp/r1-frr.log
+debug pim autorp
+!
+interface r1-eth0
+ ip address 10.10.76.1/24
+ ip igmp
+ ip pim
+!
+ip forwarding
+!
+router pim
+ autorp discovery
+! \ No newline at end of file
diff --git a/tests/topotests/pim_autorp/r2/frr.conf b/tests/topotests/pim_autorp/r2/frr.conf
new file mode 100644
index 0000000000..fd3c0cad39
--- /dev/null
+++ b/tests/topotests/pim_autorp/r2/frr.conf
@@ -0,0 +1,16 @@
+!
+hostname r2
+password zebra
+log file /tmp/r2-frr.log
+debug pim autorp
+!
+interface r2-eth0
+ ip address 10.10.76.2/24
+ ip igmp
+ ip pim
+!
+ip forwarding
+!
+router pim
+ autorp discovery
+! \ No newline at end of file
diff --git a/tests/topotests/pim_autorp/test_pim_autorp.py b/tests/topotests/pim_autorp/test_pim_autorp.py
new file mode 100644
index 0000000000..ad618af29e
--- /dev/null
+++ b/tests/topotests/pim_autorp/test_pim_autorp.py
@@ -0,0 +1,341 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# test_pim_autorp.py
+#
+# Copyright (c) 2024 ATCorp
+# Nathan Bahr
+#
+
+import os
+import sys
+import pytest
+from functools import partial
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, get_topogen
+from lib.topolog import logger
+from lib.pim import (
+ scapy_send_autorp_raw_packet,
+ verify_pim_rp_info,
+ verify_pim_rp_info_is_empty,
+)
+from lib.common_config import step, write_test_header
+
+from time import sleep
+
+"""
+test_pim_autorp.py: Test general PIM AutoRP functionality
+"""
+
+TOPOLOGY = """
+ Basic AutoRP functionality
+
+ +---+---+ +---+---+
+ | | 10.10.76.0/24 | |
+ + R1 + <------------------> + R2 |
+ | | .1 .2 | |
+ +---+---+ +---+---+
+"""
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# Required to instantiate the topology builder class.
+pytestmark = [pytest.mark.pimd]
+
+
+def build_topo(tgen):
+ "Build function"
+
+ # Create routers
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+
+ # Create link between router 1 and 2
+ switch = tgen.add_switch("s1-2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ logger.info("PIM AutoRP basic functionality:\n {}".format(TOPOLOGY))
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ # Router 1 will be the router configured with "fake" autorp configuration, so give it a default route
+ # to router 2 so that routing to the RP address is not an issue
+ # r1_defrt_setup_cmds = [
+ # "ip route add default via 10.10.76.1 dev r1-eth0",
+ # ]
+ # for cmd in r1_defrt_setup_cmds:
+ # tgen.net["r1"].cmd(cmd)
+
+ logger.info("Testing PIM AutoRP support")
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ logger.info("Loading router %s" % rname)
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ # Initialize all routers.
+ tgen.start_router()
+ for router in router_list.values():
+ if router.has_version("<", "4.0"):
+ tgen.set_error("unsupported version")
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_pim_autorp_discovery_single_rp(request):
+ "Test PIM AutoRP Discovery with single RP"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Start with no RP configuration")
+ result = verify_pim_rp_info_is_empty(tgen, "r1")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Send AutoRP packet from r1 to r2")
+ # 1 RP(s), hold time 5 secs, 10.10.76.1, group(s) 224.0.0.0/4
+ data = "01005e00012800127f55cfb1080045c00030700c000008110abe0a0a4c01e000012801f001f0001c798b12010005000000000a0a4c0103010004e0000000"
+ scapy_send_autorp_raw_packet(tgen, "r1", "r1-eth0", data)
+
+ step("Verify rp-info from AutoRP packet")
+ result = verify_pim_rp_info(
+ tgen,
+ None,
+ "r2",
+ "224.0.0.0/4",
+ "r2-eth0",
+ "10.10.76.1",
+ "AutoRP",
+ False,
+ "ipv4",
+ True,
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify AutoRP configuration times out")
+ result = verify_pim_rp_info_is_empty(tgen, "r2")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+
+def test_pim_autorp_discovery_multiple_rp(request):
+ "Test PIM AutoRP Discovery with multiple RP's"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ step("Start with no RP configuration")
+ result = verify_pim_rp_info_is_empty(tgen, "r2")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Send AutoRP packet from r1 to r2")
+ # 2 RP(s), hold time 5 secs, 10.10.76.1, group(s) 224.0.0.0/8, 10.10.76.3, group(s) 225.0.0.0/8
+ data = "01005e00012800127f55cfb1080045c0003c700c000008110ab20a0a4c01e000012801f001f000283f5712020005000000000a0a4c0103010008e00000000a0a4c0303010008e1000000"
+ scapy_send_autorp_raw_packet(tgen, "r1", "r1-eth0", data)
+
+ step("Verify rp-info from AutoRP packet")
+ result = verify_pim_rp_info(
+ tgen,
+ None,
+ "r2",
+ "224.0.0.0/8",
+ "r2-eth0",
+ "10.10.76.1",
+ "AutoRP",
+ False,
+ "ipv4",
+ True,
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+ result = verify_pim_rp_info(
+ tgen,
+ None,
+ "r2",
+ "225.0.0.0/8",
+ "r2-eth0",
+ "10.10.76.3",
+ "AutoRP",
+ False,
+ "ipv4",
+ True,
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+
+def test_pim_autorp_discovery_static(request):
+ "Test PIM AutoRP Discovery with Static RP"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ step("Start with no RP configuration")
+ result = verify_pim_rp_info_is_empty(tgen, "r2")
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Add static RP configuration to r2")
+ rnode = tgen.routers()["r2"]
+ rnode.cmd("vtysh -c 'conf t' -c 'router pim' -c 'rp 10.10.76.3 224.0.0.0/4'")
+
+ step("Verify static rp-info from r2")
+ result = verify_pim_rp_info(
+ tgen,
+ None,
+ "r2",
+ "224.0.0.0/4",
+ "r2-eth0",
+ "10.10.76.3",
+ "Static",
+ False,
+ "ipv4",
+ True,
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Send AutoRP packet from r1 to r2")
+ # 1 RP(s), hold time 5 secs, 10.10.76.1, group(s) 224.0.0.0/4
+ data = "01005e00012800127f55cfb1080045c00030700c000008110abe0a0a4c01e000012801f001f0001c798b12010005000000000a0a4c0103010004e0000000"
+ scapy_send_autorp_raw_packet(tgen, "r1", "r1-eth0", data)
+
+ step("Verify rp-info from AutoRP packet")
+ result = verify_pim_rp_info(
+ tgen,
+ None,
+ "r2",
+ "224.0.0.0/4",
+ "r2-eth0",
+ "10.10.76.1",
+ "AutoRP",
+ False,
+ "ipv4",
+ True,
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+
+def test_pim_autorp_announce_cli(request):
+ "Test PIM AutoRP Announcement CLI commands"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ step("Add AutoRP announcement configuration to r1")
+ r1 = tgen.routers()["r1"]
+ r1.vtysh_cmd(
+ """
+ conf
+ router pim
+ autorp announce holdtime 90
+ autorp announce interval 120
+ autorp announce scope 5
+ autorp announce 10.2.3.4 225.0.0.0/24
+"""
+ )
+
+ expected = {
+ "discoveryEnabled": True,
+ "announce": {
+ "scope": 5,
+ "interval": 120,
+ "holdtime": 90,
+ "rpList": [
+ {"rpAddress": "10.2.3.4", "group": "225.0.0.0/24", "prefixList": ""}
+ ],
+ },
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip pim autorp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(r1.name)
+ assert result is None, assertmsg
+
+ r1.vtysh_cmd(
+ """
+ conf
+ router pim
+ autorp announce 10.2.3.4 group-list ListA
+"""
+ )
+ expected = {
+ "discoveryEnabled": True,
+ "announce": {
+ "scope": 5,
+ "interval": 120,
+ "holdtime": 90,
+ "rpList": [{"rpAddress": "10.2.3.4", "group": "", "prefixList": "ListA"}],
+ },
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip pim autorp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(r1.name)
+ assert result is None, assertmsg
+
+
+def test_pim_autorp_announce_group(request):
+ "Test PIM AutoRP Announcement with a single group"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ step("Add candidate RP configuration to r1")
+ rnode = tgen.routers()["r1"]
+ rnode.cmd(
+ "vtysh -c 'conf t' -c 'router pim' -c 'send-rp-announce 10.10.76.1 224.0.0.0/4'"
+ )
+ step("Verify Announcement sent data")
+ # TODO: Verify AutoRP mapping agent receives candidate RP announcement
+ # Mapping agent is not yet implemented
+ # sleep(10)
+ step("Change AutoRP Announcement packet parameters")
+ rnode.cmd(
+ "vtysh -c 'conf t' -c 'router pim' -c 'send-rp-announce scope 8 interval 10 holdtime 60'"
+ )
+ step("Verify Announcement sent data")
+ # TODO: Verify AutoRP mapping agent receives updated candidate RP announcement
+ # Mapping agent is not yet implemented
+ # sleep(10)
+
+
+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/pim_basic_igmp_proxy/r1/frr.conf b/tests/topotests/pim_basic_igmp_proxy/r1/frr.conf
new file mode 100644
index 0000000000..72d031e1a3
--- /dev/null
+++ b/tests/topotests/pim_basic_igmp_proxy/r1/frr.conf
@@ -0,0 +1,29 @@
+hostname r1
+!
+interface r1-eth0
+ ip address 10.0.20.1/24
+ ip igmp
+ ip pim
+ ip igmp join 225.1.1.1
+ ip igmp join 225.2.2.2
+!
+interface r1-eth1
+ ip address 10.0.30.1/24
+ ip pim
+ ip igmp
+ ip igmp proxy
+!
+interface r1-eth2
+ ip address 10.0.40.1/24
+ ip igmp
+ ip pim
+ ip igmp join 225.3.3.3
+ ip igmp join 225.4.4.4
+!
+interface lo
+ ip address 10.254.0.1/32
+ ip pim
+!
+router pim
+ rp 10.254.0.3
+ join-prune-interval 5
diff --git a/tests/topotests/pim_basic_igmp_proxy/r2/frr.conf b/tests/topotests/pim_basic_igmp_proxy/r2/frr.conf
new file mode 100644
index 0000000000..08f721ddea
--- /dev/null
+++ b/tests/topotests/pim_basic_igmp_proxy/r2/frr.conf
@@ -0,0 +1,19 @@
+hostname r2
+!
+interface r2-eth0
+ ip address 10.0.20.2/24
+ ip igmp
+ ip pim
+ ip igmp proxy
+!
+interface r2-eth1
+ ip address 10.0.80.1/24
+ ip igmp
+ ip pim passive
+!
+interface lo
+ ip address 10.254.0.2/32
+!
+router pim
+ rp 10.254.0.3
+ join-prune-interval 5
diff --git a/tests/topotests/pim_basic_igmp_proxy/r3/frr.conf b/tests/topotests/pim_basic_igmp_proxy/r3/frr.conf
new file mode 100644
index 0000000000..8e58e8c66a
--- /dev/null
+++ b/tests/topotests/pim_basic_igmp_proxy/r3/frr.conf
@@ -0,0 +1,8 @@
+hostname r3
+!
+interface r3-eth0
+ ip address 10.0.40.4/24
+!
+interface lo
+ ip address 10.254.0.4/32
+!
diff --git a/tests/topotests/pim_basic_igmp_proxy/rp/frr.conf b/tests/topotests/pim_basic_igmp_proxy/rp/frr.conf
new file mode 100644
index 0000000000..ed60fdd4e7
--- /dev/null
+++ b/tests/topotests/pim_basic_igmp_proxy/rp/frr.conf
@@ -0,0 +1,16 @@
+hostname rp
+!
+interface rp-eth0
+ ip address 10.0.30.3/24
+ ip pim
+!
+interface lo
+ ip address 10.254.0.3/32
+ ip pim
+!
+router pim
+ join-prune-interval 5
+ rp 10.254.0.3
+ register-accept-list ACCEPT
+
+ip prefix-list ACCEPT seq 5 permit 10.0.20.0/24 le 32
diff --git a/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py b/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py
new file mode 100644
index 0000000000..b6804fa1d8
--- /dev/null
+++ b/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py
@@ -0,0 +1,319 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# test_pim_igmp_proxy.py
+#
+# Copyright (c) 2024 ATCorp
+# Barry A. Trent
+#
+
+"""
+Following tests are covered to test pim igmp proxy:
+
+1. TC:1 Verify correct joins were read from the config and proxied
+2. TC:2 Verify joins from another interface are proxied
+3. TC:3 Verify correct proxy disable on 'no ip igmp proxy'
+4. TC:4 Verify that proper proxy joins are set up on run-time enable
+5. TC:5 Verify igmp drops/timeouts from another interface cause
+ proxy join removal
+"""
+
+import os
+import sys
+import pytest
+import json
+import time
+from functools import partial
+
+pytestmark = [pytest.mark.pimd]
+
+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 lib.pim import verify_local_igmp_proxy_groups
+
+
+def build_topo(tgen):
+ "Build function"
+
+ for routern in range(1, 4):
+ tgen.add_router("r{}".format(routern))
+
+ tgen.add_router("rp")
+
+ # rp ------ r1 -------- r2 -------
+ # \
+ # --------- r3
+ # r1 -> .1
+ # r2 -> .2
+ # rp -> .3
+ # r3 -> .4
+ # loopback network is 10.254.0.X/32
+ #
+ # r1 <- sw1 -> r2
+ # r1-eth0 <-> r2-eth0
+ # 10.0.20.0/24
+ sw = tgen.add_switch("sw1")
+ sw.add_link(tgen.gears["r1"])
+ sw.add_link(tgen.gears["r2"])
+
+ # r1 <- sw2 -> rp
+ # r1-eth1 <-> rp-eth0
+ # 10.0.30.0/24
+ sw = tgen.add_switch("sw2")
+ sw.add_link(tgen.gears["r1"])
+ sw.add_link(tgen.gears["rp"])
+
+ # 10.0.40.0/24
+ sw = tgen.add_switch("sw3")
+ sw.add_link(tgen.gears["r1"])
+ sw.add_link(tgen.gears["r3"])
+
+ # Dummy interface for static joins
+ tgen.gears["r2"].run("ip link add r2-eth1 type dummy")
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in tgen.routers().items():
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ # After loading the configurations, this function loads configured daemons.
+ tgen.start_router()
+ # tgen.mininet_cli()
+
+
+def teardown_module():
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def test_pim_igmp_proxy_config():
+ "Ensure correct joins were read from the config and proxied"
+ logger.info("Verify initial igmp proxy setup from config file")
+ tgen = get_topogen()
+
+ r1 = tgen.gears["r1"]
+
+ expected = {
+ "vrf": "default",
+ "r1-eth1": {
+ "name": "r1-eth1",
+ "groups": [
+ {
+ "source": "*",
+ "group": "225.4.4.4",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.3.3.3",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.2.2.2",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.1.1.1",
+ "primaryAddr": "10.0.30.1",
+ },
+ ],
+ },
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip igmp proxy json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(r1.name)
+ assert result is None, assertmsg
+ # tgen.mininet_cli()
+
+
+def test_pim_igmp_proxy_learn():
+ "Ensure joins learned from a neighbor are propagated"
+ logger.info("Verify joins can be learned")
+ tgen = get_topogen()
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+
+ r2.vtysh_cmd(
+ "conf\nint r2-eth0\nip igmp join 225.5.5.5\nip igmp join 225.6.6.6\nexit\nexit"
+ )
+ r2.vtysh_cmd(
+ "conf\nint r2-eth1\nip igmp join 225.7.7.7\nip igmp join 225.8.8.8\nexit\nexit"
+ )
+ expected = {
+ "vrf": "default",
+ "r1-eth1": {
+ "name": "r1-eth1",
+ "groups": [
+ {
+ "source": "*",
+ "group": "225.5.5.5",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.6.6.6",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.7.7.7",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.8.8.8",
+ "primaryAddr": "10.0.30.1",
+ },
+ ],
+ },
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip igmp proxy json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(r1.name)
+ assert result is None, assertmsg
+ # tgen.mininet_cli()
+
+
+def test_pim_no_igmp_proxy():
+ "Check for correct proxy disable"
+ logger.info("Verify no ip igmp proxy")
+ tgen = get_topogen()
+
+ r1 = tgen.gears["r1"]
+
+ r1.vtysh_cmd("conf\nint r1-eth1\nno ip igmp proxy\nexit\nexit")
+ expected = {"vrf": "default"}
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip igmp proxy json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(r1.name)
+ assert result is None, assertmsg
+ # tgen.mininet_cli()
+
+
+def test_pim_igmp_proxy_restart():
+ "Check that all proxy joins are captured at run-time enable"
+ logger.info("Verify runtime ip igmp proxy")
+ tgen = get_topogen()
+
+ r1 = tgen.gears["r1"]
+
+ r1.vtysh_cmd("conf\nint r1-eth1\nip igmp proxy\nexit\nexit")
+ expected = {
+ "vrf": "default",
+ "r1-eth1": {
+ "name": "r1-eth1",
+ "groups": [
+ {
+ "source": "*",
+ "group": "225.8.8.8",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.7.7.7",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.6.6.6",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.5.5.5",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.4.4.4",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.3.3.3",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.2.2.2",
+ "primaryAddr": "10.0.30.1",
+ },
+ {
+ "source": "*",
+ "group": "225.1.1.1",
+ "primaryAddr": "10.0.30.1",
+ },
+ ],
+ },
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip igmp proxy json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(r1.name)
+ assert result is None, assertmsg
+ # tgen.mininet_cli()
+
+
+def test_pim_igmp_proxy_leave():
+ "Ensure drops/timeouts learned from a neighbor are propagated"
+ logger.info("Verify joins can be dropped")
+ tgen = get_topogen()
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+
+ r1.vtysh_cmd("conf\nint r1-eth0\nno ip igmp join 225.1.1.1\nexit\nexit")
+ r2.vtysh_cmd("conf\nint r2-eth0\nno ip igmp join 225.6.6.6\nexit\nexit")
+ r2.vtysh_cmd("conf\nint r2-eth1\nno ip igmp join 225.8.8.8\nexit\nexit")
+
+ joined_addresses = ["225.2.2.2", "225.3.3.3", "225.4.4.4", "225.5.5.5", "225.7.7.7"]
+ deleted_addresses = ["225.1.1.1", "225.6.6.6", "225.8.8.8"]
+
+ result = verify_local_igmp_proxy_groups(
+ tgen, "r1", joined_addresses, deleted_addresses
+ )
+
+ assert result is True, "Error: {}".format(result)
+ # tgen.mininet_cli()
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/pim_cand_rp_bsr/__init__.py b/tests/topotests/pim_cand_rp_bsr/__init__.py
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/pim_cand_rp_bsr/__init__.py
diff --git a/tests/topotests/pim_cand_rp_bsr/r1/frr.conf b/tests/topotests/pim_cand_rp_bsr/r1/frr.conf
new file mode 100644
index 0000000000..d0aa3d529f
--- /dev/null
+++ b/tests/topotests/pim_cand_rp_bsr/r1/frr.conf
@@ -0,0 +1,25 @@
+!
+hostname r1
+password zebra
+log file /tmp/r1-frr.log
+!
+!debug pim packet
+!debug pim bsm
+!
+ip route 0.0.0.0/0 10.0.0.4
+!
+interface r1-eth0
+ ip address 10.0.0.1/24
+ ip igmp
+ ip pim
+!
+interface r1-eth1
+ ip address 10.0.1.1/24
+ ip igmp
+ ip pim
+!
+router pim
+ bsr candidate-bsr priority 200 source address 10.0.0.1
+!
+ip forwarding
+!
diff --git a/tests/topotests/pim_cand_rp_bsr/r2/frr.conf b/tests/topotests/pim_cand_rp_bsr/r2/frr.conf
new file mode 100644
index 0000000000..741c839f19
--- /dev/null
+++ b/tests/topotests/pim_cand_rp_bsr/r2/frr.conf
@@ -0,0 +1,22 @@
+!
+hostname r2
+password zebra
+log file /tmp/r2-frr.log
+!
+ip route 0.0.0.0/0 10.0.0.4
+!
+interface r2-eth0
+ ip address 10.0.0.2/24
+ ip igmp
+ ip pim
+!
+interface r2-eth1
+ ip address 10.0.2.2/24
+ ip igmp
+ ip pim
+!
+router pim
+ bsr candidate-bsr priority 100 source address 10.0.0.2
+!
+ip forwarding
+!
diff --git a/tests/topotests/pim_cand_rp_bsr/r3/frr.conf b/tests/topotests/pim_cand_rp_bsr/r3/frr.conf
new file mode 100644
index 0000000000..bd5c8ce93f
--- /dev/null
+++ b/tests/topotests/pim_cand_rp_bsr/r3/frr.conf
@@ -0,0 +1,32 @@
+!
+hostname r3
+password zebra
+log file /tmp/r3-frr.log
+!
+!debug pim packet
+!debug pim bsm
+!
+ip route 0.0.0.0/0 10.0.3.4
+ip route 10.0.6.0/24 10.0.3.6
+!
+interface r3-eth0
+ ip address 10.0.1.3/24
+ ip igmp
+ ip pim
+!
+interface r3-eth1
+ ip address 10.0.3.3/24
+ ip igmp
+ ip pim
+!
+interface r3-eth2
+ ip address 10.0.4.3/24
+ ip igmp
+ ip pim
+!
+router pim
+ bsr candidate-rp group 239.0.0.0/16
+ bsr candidate-rp priority 10 source address 10.0.3.3
+!
+ip forwarding
+!
diff --git a/tests/topotests/pim_cand_rp_bsr/r4/frr.conf b/tests/topotests/pim_cand_rp_bsr/r4/frr.conf
new file mode 100644
index 0000000000..825b227728
--- /dev/null
+++ b/tests/topotests/pim_cand_rp_bsr/r4/frr.conf
@@ -0,0 +1,37 @@
+!
+hostname r4
+password zebra
+log file /tmp/r4-frr.log
+!
+ip route 10.0.1.0/24 10.0.0.1
+ip route 10.0.4.0/24 10.0.3.3
+ip route 10.0.6.0/24 10.0.3.6
+!
+interface r4-eth0
+ ip address 10.0.2.4/24
+ ip igmp
+ ip pim
+!
+interface r4-eth1
+ ip address 10.0.3.4/24
+ ip igmp
+ ip pim
+!
+interface r4-eth2
+ ip address 10.0.5.4/24
+ ip igmp
+ ip pim
+!
+interface r4-eth3
+ ip address 10.0.0.4/24
+ ip igmp
+ ip pim
+!
+router pim
+ bsr candidate-rp group 239.0.0.0/24
+ bsr candidate-rp group 239.0.0.0/16
+ bsr candidate-rp group 239.0.0.0/8
+ bsr candidate-rp priority 20 source address 10.0.3.4
+!
+ip forwarding
+!
diff --git a/tests/topotests/pim_cand_rp_bsr/r5/frr.conf b/tests/topotests/pim_cand_rp_bsr/r5/frr.conf
new file mode 100644
index 0000000000..c934717d08
--- /dev/null
+++ b/tests/topotests/pim_cand_rp_bsr/r5/frr.conf
@@ -0,0 +1,17 @@
+!
+hostname r5
+password zebra
+log file /tmp/r5-frr.log
+!
+ip route 0.0.0.0/0 10.0.4.3
+!
+interface r5-eth0
+ ip address 10.0.4.5/24
+ ip igmp
+ ip pim
+!
+interface r5-eth1
+ ip address 10.0.6.5/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/pim_cand_rp_bsr/r6/frr.conf b/tests/topotests/pim_cand_rp_bsr/r6/frr.conf
new file mode 100644
index 0000000000..fd9d1eb5c4
--- /dev/null
+++ b/tests/topotests/pim_cand_rp_bsr/r6/frr.conf
@@ -0,0 +1,22 @@
+!
+hostname r6
+password zebra
+log file /tmp/r6-frr.log
+!
+ip route 0.0.0.0/0 10.0.6.6
+!
+interface r6-eth0
+ ip address 10.0.5.6/24
+ ip igmp
+ ip pim
+!
+interface r6-eth1
+ ip address 10.0.6.6/24
+!
+interface r6-eth2
+ ip address 10.0.3.6/24
+ ip igmp
+ ip pim
+!
+ip forwarding
+!
diff --git a/tests/topotests/pim_cand_rp_bsr/test_pim_cand_rp_bsr.py b/tests/topotests/pim_cand_rp_bsr/test_pim_cand_rp_bsr.py
new file mode 100644
index 0000000000..ce7bc9dc56
--- /dev/null
+++ b/tests/topotests/pim_cand_rp_bsr/test_pim_cand_rp_bsr.py
@@ -0,0 +1,324 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# test_pim_cand_rp_bsr.py
+#
+# Copyright (c) 2024 ATCorp
+# Jafar Al-Gharaibeh
+#
+
+import os
+import sys
+import pytest
+import json
+from functools import partial
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, get_topogen
+from lib.topolog import logger
+from lib.pim import verify_pim_rp_info
+from lib.common_config import step, write_test_header, retry
+
+from time import sleep
+
+"""
+test_pim_cand_rp_bsr.py: Test candidate RP/BSR functionality
+"""
+
+TOPOLOGY = """
+ Candidate RP/BSR functionality
+
+ +---+---+ +---+---+
+ | C-BSR | 10.0.0.0/24 | C-BSR |
+ + R1 + <--------+---------> + R2 |
+ |elected| .1 | .2 | |
+ +---+---+ | +---+---+
+ .1 | | 10.0.2.0/24 | .2
+ | 10.0.1.0/24 | |
+ .3 | +-----| .4 | .4
+ +---+---+ |---->+---+---+
+ | C-RP | 10.0.3.0/24 | C-RP |
+ + R3 + <--------+---------> + R4 |
+ | prio | .3 | .4 | |
+ +---+---+ | +---+---+
+ .3 | | | .4
+ |10.0.4.0/24 | 10.0.5.0/24|
+ .5 | | .6 | .6
+ +---+---+ +---------->+---+---+
+ | | | |
+ + R5 + <------------------> + R6 |
+ | | .5 .6 | |
+ +---+---+ 10.0.6.0/24 +---+---+
+"""
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# Required to instantiate the topology builder class.
+pytestmark = [pytest.mark.pimd]
+
+
+def build_topo(tgen):
+ "Build function"
+
+ # Create 6 routers
+ for rn in range(1, 7):
+ tgen.add_router("r{}".format(rn))
+
+ # Create 7 switches and connect routers
+ sw1 = tgen.add_switch("s1")
+ sw1.add_link(tgen.gears["r1"])
+ sw1.add_link(tgen.gears["r2"])
+
+ sw = tgen.add_switch("s2")
+ sw.add_link(tgen.gears["r1"])
+ sw.add_link(tgen.gears["r3"])
+
+ sw = tgen.add_switch("s3")
+ sw.add_link(tgen.gears["r2"])
+ sw.add_link(tgen.gears["r4"])
+
+ sw3 = tgen.add_switch("s4")
+ sw3.add_link(tgen.gears["r3"])
+ sw3.add_link(tgen.gears["r4"])
+
+ sw = tgen.add_switch("s5")
+ sw.add_link(tgen.gears["r3"])
+ sw.add_link(tgen.gears["r5"])
+
+ sw = tgen.add_switch("s6")
+ sw.add_link(tgen.gears["r4"])
+ sw.add_link(tgen.gears["r6"])
+
+ sw = tgen.add_switch("s7")
+ sw.add_link(tgen.gears["r5"])
+ sw.add_link(tgen.gears["r6"])
+
+ # make the diagnoal connections
+ sw1.add_link(tgen.gears["r4"])
+ sw3.add_link(tgen.gears["r6"])
+
+def setup_module(mod):
+ logger.info("PIM Candidate RP/BSR:\n {}".format(TOPOLOGY))
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ logger.info("Loading router %s" % rname)
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ # Initialize all routers.
+ tgen.start_router()
+ for router in router_list.values():
+ if router.has_version("<", "4.0"):
+ tgen.set_error("unsupported version")
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+def test_pim_bsr_election_r1(request):
+ "Test PIM BSR Election"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ r2 = tgen.gears["r2"]
+ # r1 should be the BSR winner because it has higher priority
+ expected = {
+ "bsr":"10.0.0.1",
+ "priority":200,
+ "state":"ACCEPT_PREFERRED",
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r2, "show ip pim bsr json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+
+ assertmsg = "r2: r1 was not elected, bsr election mismatch"
+ assert result is None, assertmsg
+
+def test_pim_bsr_cand_bsr_r1(request):
+ "Test PIM BSR candidate BSR"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ r2 = tgen.gears["r2"]
+
+ # r2 is a candidate bsr with low priority: elected = False
+ expected = {
+ "address": "10.0.0.2",
+ "priority": 100,
+ "elected": False
+ }
+ test_func = partial(
+ topotest.router_json_cmp, r2, "show ip pim bsr candidate-bsr json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+
+ assertmsg = "r2: candidate bsr mismatch "
+ assert result is None, assertmsg
+
+def test_pim_bsr_cand_rp(request):
+ "Test PIM BSR candidate RP"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ r3 = tgen.gears["r3"]
+
+ # r3 is a candidate rp
+ expected = {
+ "address":"10.0.3.3",
+ "priority":10
+ }
+ test_func = partial(
+ topotest.router_json_cmp, r3, "show ip pim bsr candidate-rp json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+
+ assertmsg = "r3: bsr candidate rp mismatch"
+ assert result is None, assertmsg
+
+
+def test_pim_bsr_rp_info(request):
+ "Test RP info state"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ # At this point, all nodes, including r5 should have synced the RP state
+ step("Verify rp-info on r5 from BSR")
+ result = verify_pim_rp_info(tgen, None, "r5", "239.0.0.0/16", None, "10.0.3.3",
+ "BSR", False, "ipv4", True, retry_timeout = 90)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_pim_rp_info(tgen, None, "r5", "239.0.0.0/8", None, "10.0.3.4",
+ "BSR", False, "ipv4", True, retry_timeout = 30)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_pim_rp_info(tgen, None, "r5", "239.0.0.0/24", None, "10.0.3.4",
+ "BSR", False, "ipv4", True, retry_timeout = 30)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify rp-info on the BSR node itself r1")
+ result = verify_pim_rp_info(tgen, None, "r1", "239.0.0.0/16", None, "10.0.3.3",
+ "BSR", False, "ipv4", True, retry_timeout = 10)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_pim_rp_info(tgen, None, "r1", "239.0.0.0/8", None, "10.0.3.4",
+ "BSR", False, "ipv4", True, retry_timeout = 10)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_pim_rp_info(tgen, None, "r1", "239.0.0.0/24", None, "10.0.3.4",
+ "BSR", False, "ipv4", True, retry_timeout = 10)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+
+def test_pim_bsr_election_fallback_r2(request):
+ "Test PIM BSR Election Backup"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ step("Take r1 out from BSR candidates")
+ r1 = tgen.gears["r1"]
+ r1.vtysh_cmd(
+ """
+ configure
+ router pim
+ no bsr candidate-bsr priority 200 source address 10.0.0.1
+ """)
+
+ step("Verify r1 is no longer a BSR candidate")
+ expected = {}
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip pim bsr candidate-bsr json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=1)
+
+ assertmsg = "r1: failed to remove bsr candidate configuration"
+ assert result is None, assertmsg
+
+ r2 = tgen.gears["r2"]
+ # We should fall back to r2 as the BSR
+ expected = {
+ "bsr":"10.0.0.2",
+ "priority":100,
+ "state":"BSR_ELECTED",
+ }
+
+ step("Verify that we fallback to r2 as the new BSR")
+
+ test_func = partial(
+ topotest.router_json_cmp, r2, "show ip pim bsr json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=180, wait=1)
+
+ assertmsg = "r2: failed to fallback to r2 as a BSR"
+ assert result is None, assertmsg
+
+
+def test_pim_bsr_rp_info_fallback(request):
+ "Test RP info state on r5"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ step("Take r3 out from RP candidates for group 239.0.0.0/16")
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ """
+ configure
+ router pim
+ no bsr candidate-rp group 239.0.0.0/16
+ """)
+
+ step("Verify falling back to r4 as the new RP for 239.0.0.0/16")
+
+ result = verify_pim_rp_info(tgen, None, "r5", "239.0.0.0/16", None, "10.0.3.4",
+ "BSR", False, "ipv4", True, retry_timeout = 30)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+
+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/pytest.ini b/tests/topotests/pytest.ini
index db806fed39..b234a84252 100644
--- a/tests/topotests/pytest.ini
+++ b/tests/topotests/pytest.ini
@@ -1,6 +1,9 @@
# Skip pytests example directory
[pytest]
+asyncio_mode = auto
+asyncio_default_fixture_loop_scope = module
+
# NEEDS_EXABGP_4_2_11_FRR
# asyncio_mode = auto
diff --git a/tests/topotests/route_scale/scale_test_common.py b/tests/topotests/route_scale/scale_test_common.py
index 0b239dc04b..bb95c66031 100644
--- a/tests/topotests/route_scale/scale_test_common.py
+++ b/tests/topotests/route_scale/scale_test_common.py
@@ -86,6 +86,23 @@ def scale_converge_protocols():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
+ logger.info("Ensuring that Connected Routes are actually installed")
+ r1 = tgen.gears["r1"]
+ expected = {
+ "routes": [
+ {"fib": 32, "rib": 32, "type": "connected"},
+ {"fib": 32, "rib": 32, "type": "local"},
+ ],
+ "routesTotal": 64,
+ "routesTotalFib": 64,
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip route summary json", expected
+ )
+ success, result = topotest.run_and_expect(test_func, None, 60, 1)
+ assert success, "Connected routes are not properly installed:\n{}".format(result)
+
def run_one_setup(r1, s):
"Run one ecmp config"
@@ -102,7 +119,11 @@ def run_one_setup(r1, s):
count = d["rib"]
break
- logger.info("Testing {} routes X {} ecmp".format(count, s["ecmp"]))
+ logger.info(
+ "Testing {} routes X {} ecmp, waiting {} retries {}".format(
+ count, s["ecmp"], wait, retries
+ )
+ )
r1.vtysh_cmd(
"sharp install route 1.0.0.0 \
@@ -176,8 +197,8 @@ def route_install_helper(iter):
[2, "two"],
[4, "four"],
[8, "eight"],
- [16, "sixteen", 10, 40],
- [32, "thirtytwo", 10, 40],
+ [16, "sixteen", 10, 80],
+ [32, "thirtytwo", 10, 80],
]
# Build up a list of dicts with params for each step of the test;
diff --git a/tests/topotests/srv6_encap_src_addr/r1/zebra.conf b/tests/topotests/srv6_encap_src_addr/r1/zebra.conf
index c570756b52..c245dd2d96 100644
--- a/tests/topotests/srv6_encap_src_addr/r1/zebra.conf
+++ b/tests/topotests/srv6_encap_src_addr/r1/zebra.conf
@@ -4,7 +4,6 @@ hostname r1
! debug zebra rib detailed
!
log stdout notifications
-log monitor notifications
log commands
log file zebra.log debugging
!
diff --git a/tests/topotests/srv6_sid_manager/ce1/bgpd.conf b/tests/topotests/srv6_sid_manager/ce1/bgpd.conf
new file mode 100644
index 0000000000..3459796629
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce1/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce1
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/srv6_sid_manager/ce1/ipv6_rib.json b/tests/topotests/srv6_sid_manager/ce1/ipv6_rib.json
new file mode 100644
index 0000000000..a35e2b1b3d
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce1/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:1::1",
+ "afi": "ipv6",
+ "interfaceName": "eth-rt1",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:1::/64": [
+ {
+ "prefix": "2001:1::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-rt1",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/ce1/zebra.conf b/tests/topotests/srv6_sid_manager/ce1/zebra.conf
new file mode 100644
index 0000000000..0dea0c5751
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce1/zebra.conf
@@ -0,0 +1,14 @@
+log file zebra.log
+!
+hostname ce1
+!
+interface eth-rt1
+ ipv6 address 2001:1::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route ::/0 2001:1::1
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/ce2/bgpd.conf b/tests/topotests/srv6_sid_manager/ce2/bgpd.conf
new file mode 100644
index 0000000000..8ed9978749
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce2/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce2
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/srv6_sid_manager/ce2/ipv6_rib.json b/tests/topotests/srv6_sid_manager/ce2/ipv6_rib.json
new file mode 100644
index 0000000000..b4594d1c57
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce2/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:2::1",
+ "afi": "ipv6",
+ "interfaceName": "eth-rt6",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:2::/64": [
+ {
+ "prefix": "2001:2::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-rt6",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/ce2/zebra.conf b/tests/topotests/srv6_sid_manager/ce2/zebra.conf
new file mode 100644
index 0000000000..c4755f8485
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce2/zebra.conf
@@ -0,0 +1,14 @@
+log file zebra.log
+!
+hostname ce2
+!
+interface eth-rt6
+ ipv6 address 2001:2::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route ::/0 2001:2::1
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/ce3/bgpd.conf b/tests/topotests/srv6_sid_manager/ce3/bgpd.conf
new file mode 100644
index 0000000000..a85d9701c7
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce3/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce3
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/srv6_sid_manager/ce3/ipv6_rib.json b/tests/topotests/srv6_sid_manager/ce3/ipv6_rib.json
new file mode 100644
index 0000000000..3a50cb0199
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce3/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:3::1",
+ "afi": "ipv6",
+ "interfaceName": "eth-rt1",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "prefix": "2001:3::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-rt1",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/ce3/zebra.conf b/tests/topotests/srv6_sid_manager/ce3/zebra.conf
new file mode 100644
index 0000000000..046bcb6af8
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce3/zebra.conf
@@ -0,0 +1,14 @@
+log file zebra.log
+!
+hostname ce3
+!
+interface eth-rt1
+ ipv6 address 2001:3::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route ::/0 2001:3::1
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/ce4/bgpd.conf b/tests/topotests/srv6_sid_manager/ce4/bgpd.conf
new file mode 100644
index 0000000000..93fb32fd1b
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce4/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce4
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/srv6_sid_manager/ce4/ipv6_rib.json b/tests/topotests/srv6_sid_manager/ce4/ipv6_rib.json
new file mode 100644
index 0000000000..f6484355ba
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce4/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:4::1",
+ "afi": "ipv6",
+ "interfaceName": "eth-rt6",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:4::/64": [
+ {
+ "prefix": "2001:4::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-rt6",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/ce4/zebra.conf b/tests/topotests/srv6_sid_manager/ce4/zebra.conf
new file mode 100644
index 0000000000..7913d6f397
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce4/zebra.conf
@@ -0,0 +1,14 @@
+log file zebra.log
+!
+hostname ce4
+!
+interface eth-rt6
+ ipv6 address 2001:4::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route ::/0 2001:4::1
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/ce5/bgpd.conf b/tests/topotests/srv6_sid_manager/ce5/bgpd.conf
new file mode 100644
index 0000000000..2ab6f2d2a7
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce5/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce5
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/srv6_sid_manager/ce5/ipv6_rib.json b/tests/topotests/srv6_sid_manager/ce5/ipv6_rib.json
new file mode 100644
index 0000000000..a88df73c5a
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce5/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:5::1",
+ "afi": "ipv6",
+ "interfaceName": "eth-rt1",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:5::/64": [
+ {
+ "prefix": "2001:5::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-rt1",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/ce5/zebra.conf b/tests/topotests/srv6_sid_manager/ce5/zebra.conf
new file mode 100644
index 0000000000..21414ffcbc
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce5/zebra.conf
@@ -0,0 +1,14 @@
+log file zebra.log
+!
+hostname ce5
+!
+interface eth-rt1
+ ipv6 address 2001:5::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route ::/0 2001:5::1
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/ce6/bgpd.conf b/tests/topotests/srv6_sid_manager/ce6/bgpd.conf
new file mode 100644
index 0000000000..e0b6540514
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce6/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce6
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/srv6_sid_manager/ce6/ipv6_rib.json b/tests/topotests/srv6_sid_manager/ce6/ipv6_rib.json
new file mode 100644
index 0000000000..ab6dfc9e13
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce6/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:6::1",
+ "afi": "ipv6",
+ "interfaceName": "eth-rt6",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "prefix": "2001:6::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-rt6",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/ce6/zebra.conf b/tests/topotests/srv6_sid_manager/ce6/zebra.conf
new file mode 100644
index 0000000000..ebe8556092
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/ce6/zebra.conf
@@ -0,0 +1,14 @@
+log file zebra.log
+!
+hostname ce6
+!
+interface eth-rt6
+ ipv6 address 2001:6::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route ::/0 2001:6::1
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/dst/sharpd.conf b/tests/topotests/srv6_sid_manager/dst/sharpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/dst/sharpd.conf
diff --git a/tests/topotests/srv6_sid_manager/dst/zebra.conf b/tests/topotests/srv6_sid_manager/dst/zebra.conf
new file mode 100644
index 0000000000..80741856cb
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/dst/zebra.conf
@@ -0,0 +1,22 @@
+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 fc00:0:9::1/128
+!
+interface eth-rt6
+ ip address 10.0.10.2/24
+ ipv6 address 2001:db8:10::2/64
+!
+ip forwarding
+!
+ip route 2001:db8:1::1 2001:db8:10::1
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/rt1/bgpd.conf b/tests/topotests/srv6_sid_manager/rt1/bgpd.conf
new file mode 100644
index 0000000000..20c396afde
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/bgpd.conf
@@ -0,0 +1,66 @@
+frr defaults traditional
+!
+bgp send-extra-data zebra
+!
+hostname rt1
+password zebra
+!
+log stdout notifications
+log commands
+!
+!debug bgp neighbor-events
+!debug bgp zebra
+!debug bgp vnc verbose
+!debug bgp update-groups
+!debug bgp updates in
+!debug bgp updates out
+!debug bgp vpn label
+!debug bgp vpn leak-from-vrf
+!debug bgp vpn leak-to-vrf
+!debug bgp vpn rmap-event
+!
+router bgp 1
+ bgp router-id 1.1.1.1
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor fc00:0:6::1 remote-as 6
+ neighbor fc00:0:6::1 timers 3 10
+ neighbor fc00:0:6::1 timers connect 1
+ neighbor fc00:0:6::1 ttl-security hops 20
+ !
+ address-family ipv6 vpn
+ neighbor fc00:0:6::1 activate
+ exit-address-family
+ !
+ segment-routing srv6
+ locator loc1
+ !
+!
+router bgp 1 vrf vrf10
+ bgp router-id 1.1.1.1
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ !
+ address-family ipv6 unicast
+ sid vpn export 65024
+ rd vpn export 1:10
+ rt vpn both 99:99
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
+router bgp 1 vrf vrf20
+ bgp router-id 1.1.1.1
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ !
+ address-family ipv6 unicast
+ sid vpn export 65025
+ rd vpn export 1:20
+ rt vpn both 88:88
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/srv6_sid_manager/rt1/isisd.conf b/tests/topotests/srv6_sid_manager/rt1/isisd.conf
new file mode 100644
index 0000000000..29e1a31171
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/isisd.conf
@@ -0,0 +1,35 @@
+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-interval 1
+ isis hello-multiplier 10
+!
+router isis 1
+ lsp-gen-interval 2
+ net 49.0000.0000.0000.0001.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing srv6
+ locator loc1
+ node-msd
+ max-segs-left 3
+ max-end-pop 3
+ max-h-encaps 2
+ max-end-d 5
+ interface sr0
+!
diff --git a/tests/topotests/srv6_sid_manager/rt1/sharpd.conf b/tests/topotests/srv6_sid_manager/rt1/sharpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/sharpd.conf
diff --git a/tests/topotests/srv6_sid_manager/rt1/show_ip_route.ref b/tests/topotests/srv6_sid_manager/rt1/show_ip_route.ref
new file mode 100644
index 0000000000..590d75afbf
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/show_ip_route.ref
@@ -0,0 +1,276 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt1/show_ipv6_route.ref b/tests/topotests/srv6_sid_manager/rt1/show_ipv6_route.ref
new file mode 100644
index 0000000000..cdbec3f2c1
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/show_ipv6_route.ref
@@ -0,0 +1,314 @@
+{
+ "fc00:0:2::1\/128":[
+ {
+ "prefix":"fc00:0:2::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::1\/128":[
+ {
+ "prefix":"fc00:0:3::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::1\/128":[
+ {
+ "prefix":"fc00:0:4::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::1\/128":[
+ {
+ "prefix":"fc00:0:5::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::1\/128":[
+ {
+ "prefix":"fc00:0:6::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::\/48":[
+ {
+ "prefix":"fc00:0:2::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::\/48":[
+ {
+ "prefix":"fc00:0:3::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::\/48":[
+ {
+ "prefix":"fc00:0:4::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::\/48":[
+ {
+ "prefix":"fc00:0:5::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::\/48":[
+ {
+ "prefix":"fc00:0:6::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:1::\/48":[
+ {
+ "prefix":"fc00:0:1::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"sr0",
+ "active":true,
+ "seg6local":{
+ "action":"End"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:1:e000::\/64":[
+ {
+ "prefix":"fc00:0:1:e000::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:1:e001::\/64":[
+ {
+ "prefix":"fc00:0:1:e001::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:1:fe00::\/128":[
+ {
+ "prefix":"fc00:0:1:fe00::\/128",
+ "protocol":"bgp",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"vrf10",
+ "active":true,
+ "seg6local":{
+ "action":"End.DT6"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:1:fe01::\/128":[
+ {
+ "prefix":"fc00:0:1:fe01::\/128",
+ "protocol":"bgp",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"vrf20",
+ "active":true,
+ "seg6local":{
+ "action":"End.DT6"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt1/show_srv6_locator_table.ref b/tests/topotests/srv6_sid_manager/rt1/show_srv6_locator_table.ref
new file mode 100644
index 0000000000..c4a5d7507b
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/show_srv6_locator_table.ref
@@ -0,0 +1,15 @@
+{
+ "locators":[
+ {
+ "name":"loc1",
+ "prefix":"fc00:0:1::/48",
+ "blockBitsLength":32,
+ "nodeBitsLength":16,
+ "functionBitsLength":16,
+ "argumentBitsLength":0,
+ "statusUp":true,
+ "chunks":[
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/srv6_sid_manager/rt1/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..9c5901b90f
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,32 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-sw1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "hold-timer": 10,
+ "neighbor-priority": 64,
+ "state": "up"
+ },
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "hold-timer": 10,
+ "neighbor-priority": 64,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/srv6_sid_manager/rt1/vpnv6_rib.ref b/tests/topotests/srv6_sid_manager/rt1/vpnv6_rib.ref
new file mode 100644
index 0000000000..52bc589a7f
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/vpnv6_rib.ref
@@ -0,0 +1,169 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "2001:1::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:1::",
+ "prefixLen": 64,
+ "network": "2001:1::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "rt1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:3::",
+ "prefixLen": 64,
+ "network": "2001:3::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "rt1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "rt1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "6:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "fc00:0:6::1",
+ "path": "6",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "fc00:0:6::1",
+ "hostname": "rt6",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "6:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "fc00:0:6::1",
+ "path": "6",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "fc00:0:6::1",
+ "hostname": "rt6",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "fc00:0:6::1",
+ "path": "6",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "fc00:0:6::1",
+ "hostname": "rt6",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/srv6_sid_manager/rt1/vrf10_rib.ref b/tests/topotests/srv6_sid_manager/rt1/vrf10_rib.ref
new file mode 100644
index 0000000000..2aae3497f4
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/vrf10_rib.ref
@@ -0,0 +1,86 @@
+{
+ "2001:1::/64": [
+ {
+ "prefix": "2001:1::/64",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-ce1",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:2::/64": [
+ {
+ "prefix": "2001:2::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 9,
+ "internalNextHopNum": 3,
+ "internalNextHopActiveNum": 3,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth-sw1",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "fc00:0:6:fe00::"
+ }
+ }
+ ],
+ "asPath": "6"
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "prefix": "2001:3::/64",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-ce3",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt1/vrf20_rib.ref b/tests/topotests/srv6_sid_manager/rt1/vrf20_rib.ref
new file mode 100644
index 0000000000..de9e450cf6
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/vrf20_rib.ref
@@ -0,0 +1,92 @@
+{
+ "2001:4::/64": [
+ {
+ "prefix": "2001:4::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 9,
+ "internalNextHopNum": 3,
+ "internalNextHopActiveNum": 3,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth-sw1",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "fc00:0:6:fe01::"
+ }
+ }
+ ],
+ "asPath": "6"
+ }
+ ],
+ "2001:5::/64": [
+ {
+ "prefix": "2001:5::/64",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-ce5",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "prefix": "2001:6::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 9,
+ "internalNextHopNum": 3,
+ "internalNextHopActiveNum": 3,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth-sw1",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "fc00:0:6:fe01::"
+ }
+ }
+ ],
+ "asPath": "6"
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt1/zebra.conf b/tests/topotests/srv6_sid_manager/rt1/zebra.conf
new file mode 100644
index 0000000000..ef7fb78eed
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt1/zebra.conf
@@ -0,0 +1,37 @@
+log file zebra.log
+!
+hostname rt1
+!
+! debug zebra kernel
+! debug zebra packet
+!
+interface lo
+ ip address 1.1.1.1/32
+ ipv6 address fc00:0:1::1/128
+!
+interface eth-sw1
+ ip address 10.0.1.1/24
+ ipv6 address 2001:db8:1::1/64
+!
+interface eth-ce1 vrf vrf10
+ ipv6 address 2001:1::1/64
+!
+interface eth-ce3 vrf vrf10
+ ipv6 address 2001:3::1/64
+!
+interface eth-ce5 vrf vrf20
+ ipv6 address 2001:5::1/64
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:1::/48
+ format usid-f3216
+ !
+ !
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/rt2/isisd.conf b/tests/topotests/srv6_sid_manager/rt2/isisd.conf
new file mode 100644
index 0000000000..b095f04910
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt2/isisd.conf
@@ -0,0 +1,48 @@
+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-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt4-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt4-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+router isis 1
+ lsp-gen-interval 2
+ net 49.0000.0000.0000.0002.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing srv6
+ locator loc1
+ node-msd
+ max-segs-left 3
+ max-end-pop 3
+ max-h-encaps 2
+ max-end-d 5
+ interface sr0
+!
diff --git a/tests/topotests/srv6_sid_manager/rt2/show_ip_route.ref b/tests/topotests/srv6_sid_manager/rt2/show_ip_route.ref
new file mode 100644
index 0000000000..1d4a9e9a25
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt2/show_ip_route.ref
@@ -0,0 +1,320 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt2/show_ipv6_route.ref b/tests/topotests/srv6_sid_manager/rt2/show_ipv6_route.ref
new file mode 100644
index 0000000000..fc0f1d3bcc
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt2/show_ipv6_route.ref
@@ -0,0 +1,346 @@
+{
+ "fc00:0:1::1\/128":[
+ {
+ "prefix":"fc00:0:1::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::1\/128":[
+ {
+ "prefix":"fc00:0:3::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::1\/128":[
+ {
+ "prefix":"fc00:0:4::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::1\/128":[
+ {
+ "prefix":"fc00:0:5::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::1\/128":[
+ {
+ "prefix":"fc00:0:6::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:1::\/48":[
+ {
+ "prefix":"fc00:0:1::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::\/48":[
+ {
+ "prefix":"fc00:0:3::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::\/48":[
+ {
+ "prefix":"fc00:0:4::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::\/48":[
+ {
+ "prefix":"fc00:0:5::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::\/48":[
+ {
+ "prefix":"fc00:0:6::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::\/48":[
+ {
+ "prefix":"fc00:0:2::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"sr0",
+ "active":true,
+ "seg6local":{
+ "action":"End"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:2:e000::\/64":[
+ {
+ "prefix":"fc00:0:2:e000::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:2:e001::\/64":[
+ {
+ "prefix":"fc00:0:2:e001::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:2:e002::\/64":[
+ {
+ "prefix":"fc00:0:2:e002::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:2:e003::\/64":[
+ {
+ "prefix":"fc00:0:2:e003::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt2/show_srv6_locator_table.ref b/tests/topotests/srv6_sid_manager/rt2/show_srv6_locator_table.ref
new file mode 100644
index 0000000000..f8a5d93f3c
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt2/show_srv6_locator_table.ref
@@ -0,0 +1,15 @@
+{
+ "locators":[
+ {
+ "name":"loc1",
+ "prefix":"fc00:0:2::/48",
+ "blockBitsLength":32,
+ "nodeBitsLength":16,
+ "functionBitsLength":16,
+ "argumentBitsLength":0,
+ "statusUp":true,
+ "chunks":[
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/srv6_sid_manager/rt2/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..5e46ddf728
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt2/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,70 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt4-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0004",
+ "hold-timer": 10,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt4-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0004",
+ "hold-timer": 10,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-sw1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "hold-timer": 10,
+ "neighbor-priority": 64,
+ "state": "up"
+ },
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0001",
+ "hold-timer": 10,
+ "neighbor-priority": 64,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/srv6_sid_manager/rt2/zebra.conf b/tests/topotests/srv6_sid_manager/rt2/zebra.conf
new file mode 100644
index 0000000000..32737dfcd6
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt2/zebra.conf
@@ -0,0 +1,34 @@
+log file zebra.log
+!
+hostname rt2
+!
+! debug zebra kernel
+! debug zebra packet
+!
+interface lo
+ ip address 2.2.2.2/32
+ ipv6 address fc00:0:2::1/128
+!
+interface eth-sw1
+ ip address 10.0.1.2/24
+ ipv6 address 2001:db8:1::2/64
+!
+interface eth-rt4-1
+ ip address 10.0.2.2/24
+!
+interface eth-rt4-2
+ ip address 10.0.3.2/24
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:2::/48
+ format usid-f3216
+ !
+ !
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/rt3/isisd.conf b/tests/topotests/srv6_sid_manager/rt3/isisd.conf
new file mode 100644
index 0000000000..e237db2f49
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt3/isisd.conf
@@ -0,0 +1,48 @@
+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-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt5-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt5-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+router isis 1
+ lsp-gen-interval 2
+ net 49.0000.0000.0000.0003.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing srv6
+ locator loc1
+ node-msd
+ max-segs-left 3
+ max-end-pop 3
+ max-h-encaps 2
+ max-end-d 5
+ interface sr0
+!
diff --git a/tests/topotests/srv6_sid_manager/rt3/show_ip_route.ref b/tests/topotests/srv6_sid_manager/rt3/show_ip_route.ref
new file mode 100644
index 0000000000..6ce5760e4f
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt3/show_ip_route.ref
@@ -0,0 +1,320 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt3/show_ipv6_route.ref b/tests/topotests/srv6_sid_manager/rt3/show_ipv6_route.ref
new file mode 100644
index 0000000000..c590fcfdbc
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt3/show_ipv6_route.ref
@@ -0,0 +1,346 @@
+{
+ "fc00:0:1::1\/128":[
+ {
+ "prefix":"fc00:0:1::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::1\/128":[
+ {
+ "prefix":"fc00:0:2::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::1\/128":[
+ {
+ "prefix":"fc00:0:4::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::1\/128":[
+ {
+ "prefix":"fc00:0:5::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::1\/128":[
+ {
+ "prefix":"fc00:0:6::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:1::\/48":[
+ {
+ "prefix":"fc00:0:1::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::\/48":[
+ {
+ "prefix":"fc00:0:2::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::\/48":[
+ {
+ "prefix":"fc00:0:4::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::\/48":[
+ {
+ "prefix":"fc00:0:5::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::\/48":[
+ {
+ "prefix":"fc00:0:6::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::\/48":[
+ {
+ "prefix":"fc00:0:3::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"sr0",
+ "active":true,
+ "seg6local":{
+ "action":"End"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:3:e000::\/64":[
+ {
+ "prefix":"fc00:0:3:e000::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:3:e001::\/64":[
+ {
+ "prefix":"fc00:0:3:e001::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:3:e002::\/64":[
+ {
+ "prefix":"fc00:0:3:e002::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:3:e003::\/64":[
+ {
+ "prefix":"fc00:0:3:e003::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt3/show_srv6_locator_table.ref b/tests/topotests/srv6_sid_manager/rt3/show_srv6_locator_table.ref
new file mode 100644
index 0000000000..c62870587b
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt3/show_srv6_locator_table.ref
@@ -0,0 +1,15 @@
+{
+ "locators":[
+ {
+ "name":"loc1",
+ "prefix":"fc00:0:3::/48",
+ "blockBitsLength":32,
+ "nodeBitsLength":16,
+ "functionBitsLength":16,
+ "argumentBitsLength":0,
+ "statusUp":true,
+ "chunks":[
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/srv6_sid_manager/rt3/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..a284240d24
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt3/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,70 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt5-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0005",
+ "hold-timer": 10,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt5-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0005",
+ "hold-timer": 10,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-sw1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0001",
+ "hold-timer": 10,
+ "neighbor-priority": 64,
+ "state": "up"
+ },
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "hold-timer": 10,
+ "neighbor-priority": 64,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/srv6_sid_manager/rt3/zebra.conf b/tests/topotests/srv6_sid_manager/rt3/zebra.conf
new file mode 100644
index 0000000000..73cf6b08f4
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt3/zebra.conf
@@ -0,0 +1,33 @@
+log file zebra.log
+!
+hostname rt3
+!
+! debug zebra kernel
+! debug zebra packet
+!
+interface lo
+ ip address 3.3.3.3/32
+ ipv6 address fc00:0:3::1/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
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:3::/48
+ format usid-f3216
+ !
+ !
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/rt4/isisd.conf b/tests/topotests/srv6_sid_manager/rt4/isisd.conf
new file mode 100644
index 0000000000..b4c92146a1
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt4/isisd.conf
@@ -0,0 +1,56 @@
+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-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt2-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+router isis 1
+ lsp-gen-interval 2
+ net 49.0000.0000.0000.0004.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing srv6
+ locator loc1
+ node-msd
+ max-segs-left 3
+ max-end-pop 3
+ max-h-encaps 2
+ max-end-d 5
+ interface sr0
+!
diff --git a/tests/topotests/srv6_sid_manager/rt4/show_ip_route.ref b/tests/topotests/srv6_sid_manager/rt4/show_ip_route.ref
new file mode 100644
index 0000000000..0f26fa5d7a
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt4/show_ip_route.ref
@@ -0,0 +1,296 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt4/show_ipv6_route.ref b/tests/topotests/srv6_sid_manager/rt4/show_ipv6_route.ref
new file mode 100644
index 0000000000..7b575f1888
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt4/show_ipv6_route.ref
@@ -0,0 +1,346 @@
+{
+ "fc00:0:1::1\/128":[
+ {
+ "prefix":"fc00:0:1::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::1\/128":[
+ {
+ "prefix":"fc00:0:2::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::1\/128":[
+ {
+ "prefix":"fc00:0:3::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::1\/128":[
+ {
+ "prefix":"fc00:0:5::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::1\/128":[
+ {
+ "prefix":"fc00:0:6::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:1::\/48":[
+ {
+ "prefix":"fc00:0:1::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::\/48":[
+ {
+ "prefix":"fc00:0:2::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::\/48":[
+ {
+ "prefix":"fc00:0:3::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::\/48":[
+ {
+ "prefix":"fc00:0:5::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::\/48":[
+ {
+ "prefix":"fc00:0:6::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::\/48":[
+ {
+ "prefix":"fc00:0:4::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"sr0",
+ "active":true,
+ "seg6local":{
+ "action":"End"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:4:e000::\/64":[
+ {
+ "prefix":"fc00:0:4:e000::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:4:e001::\/64":[
+ {
+ "prefix":"fc00:0:4:e001::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:4:e002::\/64":[
+ {
+ "prefix":"fc00:0:4:e002::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:4:e003::\/64":[
+ {
+ "prefix":"fc00:0:4:e003::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/topotests/srv6_sid_manager/rt4/show_srv6_locator_table.ref b/tests/topotests/srv6_sid_manager/rt4/show_srv6_locator_table.ref
new file mode 100644
index 0000000000..cb052dbbb5
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt4/show_srv6_locator_table.ref
@@ -0,0 +1,15 @@
+{
+ "locators":[
+ {
+ "name":"loc1",
+ "prefix":"fc00:0:4::/48",
+ "blockBitsLength":32,
+ "nodeBitsLength":16,
+ "functionBitsLength":16,
+ "argumentBitsLength":0,
+ "statusUp":true,
+ "chunks":[
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/srv6_sid_manager/rt4/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..0ca7a76bd4
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt4/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,82 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt2-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "hold-timer": 10,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt2-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "hold-timer": 10,
+ "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": 10,
+ "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": 10,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/srv6_sid_manager/rt4/zebra.conf b/tests/topotests/srv6_sid_manager/rt4/zebra.conf
new file mode 100644
index 0000000000..266db7c53a
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt4/zebra.conf
@@ -0,0 +1,36 @@
+log file zebra.log
+!
+hostname rt4
+!
+! debug zebra kernel
+! debug zebra packet
+!
+interface lo
+ ip address 4.4.4.4/32
+ ipv6 address fc00:0:4::1/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
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:4::/48
+ format usid-f3216
+ !
+ !
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/rt5/isisd.conf b/tests/topotests/srv6_sid_manager/rt5/isisd.conf
new file mode 100644
index 0000000000..26f895dd82
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt5/isisd.conf
@@ -0,0 +1,56 @@
+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-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt3-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+router isis 1
+ lsp-gen-interval 2
+ net 49.0000.0000.0000.0005.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing srv6
+ locator loc1
+ node-msd
+ max-segs-left 3
+ max-end-pop 3
+ max-h-encaps 2
+ max-end-d 5
+ interface sr0
+!
diff --git a/tests/topotests/srv6_sid_manager/rt5/show_ip_route.ref b/tests/topotests/srv6_sid_manager/rt5/show_ip_route.ref
new file mode 100644
index 0000000000..65beaa5998
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt5/show_ip_route.ref
@@ -0,0 +1,296 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt5/show_ipv6_route.ref b/tests/topotests/srv6_sid_manager/rt5/show_ipv6_route.ref
new file mode 100644
index 0000000000..a7b3262f86
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt5/show_ipv6_route.ref
@@ -0,0 +1,346 @@
+{
+ "fc00:0:1::1\/128":[
+ {
+ "prefix":"fc00:0:1::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::1\/128":[
+ {
+ "prefix":"fc00:0:2::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::1\/128":[
+ {
+ "prefix":"fc00:0:3::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::1\/128":[
+ {
+ "prefix":"fc00:0:4::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::1\/128":[
+ {
+ "prefix":"fc00:0:6::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:1::\/48":[
+ {
+ "prefix":"fc00:0:1::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::\/48":[
+ {
+ "prefix":"fc00:0:2::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::\/48":[
+ {
+ "prefix":"fc00:0:3::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::\/48":[
+ {
+ "prefix":"fc00:0:4::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::\/48":[
+ {
+ "prefix":"fc00:0:6::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::\/48":[
+ {
+ "prefix":"fc00:0:5::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"sr0",
+ "active":true,
+ "seg6local":{
+ "action":"End"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:5:e000::\/64":[
+ {
+ "prefix":"fc00:0:5:e000::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:5:e001::\/64":[
+ {
+ "prefix":"fc00:0:5:e001::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:5:e002::\/64":[
+ {
+ "prefix":"fc00:0:5:e002::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:5:e003::\/64":[
+ {
+ "prefix":"fc00:0:5:e003::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt5/show_srv6_locator_table.ref b/tests/topotests/srv6_sid_manager/rt5/show_srv6_locator_table.ref
new file mode 100644
index 0000000000..ec55f24d7b
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt5/show_srv6_locator_table.ref
@@ -0,0 +1,15 @@
+{
+ "locators":[
+ {
+ "name":"loc1",
+ "prefix":"fc00:0:5::/48",
+ "blockBitsLength":32,
+ "nodeBitsLength":16,
+ "functionBitsLength":16,
+ "argumentBitsLength":0,
+ "statusUp":true,
+ "chunks":[
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/srv6_sid_manager/rt5/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..f40b0d353d
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt5/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,82 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt3-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "hold-timer": 10,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt3-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "hold-timer": 10,
+ "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": 10,
+ "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": 10,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/srv6_sid_manager/rt5/zebra.conf b/tests/topotests/srv6_sid_manager/rt5/zebra.conf
new file mode 100644
index 0000000000..901103554b
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt5/zebra.conf
@@ -0,0 +1,36 @@
+log file zebra.log
+!
+hostname rt5
+!
+! debug zebra kernel
+! debug zebra packet
+!
+interface lo
+ ip address 5.5.5.5/32
+ ipv6 address fc00:0:5::1/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
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:5::/48
+ format usid-f3216
+ !
+ !
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/rt6/bgpd.conf b/tests/topotests/srv6_sid_manager/rt6/bgpd.conf
new file mode 100644
index 0000000000..c36fae7901
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/bgpd.conf
@@ -0,0 +1,67 @@
+frr defaults traditional
+!
+bgp send-extra-data zebra
+!
+hostname rt6
+password zebra
+!
+log stdout notifications
+log commands
+!
+!debug bgp neighbor-events
+!debug bgp zebra
+!debug bgp vnc verbose
+!debug bgp update-groups
+!debug bgp updates in
+!debug bgp updates out
+!debug bgp updates
+!debug bgp vpn label
+!debug bgp vpn leak-from-vrf
+!debug bgp vpn leak-to-vrf
+!!debug bgp vpn rmap-event
+!
+router bgp 6
+ bgp router-id 6.6.6.6
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor fc00:0:1::1 remote-as 1
+ neighbor fc00:0:1::1 timers 3 10
+ neighbor fc00:0:1::1 timers connect 1
+ neighbor fc00:0:1::1 ttl-security hops 20
+ !
+ address-family ipv6 vpn
+ neighbor fc00:0:1::1 activate
+ exit-address-family
+ !
+ segment-routing srv6
+ locator loc1
+ !
+!
+router bgp 6 vrf vrf10
+ bgp router-id 6.6.6.6
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ !
+ address-family ipv6 unicast
+ sid vpn export 65024
+ rd vpn export 6:10
+ rt vpn both 99:99
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
+router bgp 6 vrf vrf20
+ bgp router-id 6.6.6.6
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ !
+ address-family ipv6 unicast
+ sid vpn export 65025
+ rd vpn export 6:20
+ rt vpn both 88:88
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/srv6_sid_manager/rt6/isisd.conf b/tests/topotests/srv6_sid_manager/rt6/isisd.conf
new file mode 100644
index 0000000000..f8816db43a
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/isisd.conf
@@ -0,0 +1,42 @@
+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-interval 1
+ isis hello-multiplier 10
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-interval 1
+ isis hello-multiplier 10
+!
+router isis 1
+ lsp-gen-interval 2
+ net 49.0000.0000.0000.0006.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing srv6
+ locator loc1
+ node-msd
+ max-segs-left 3
+ max-end-pop 3
+ max-h-encaps 2
+ max-end-d 5
+ interface sr0
+!
diff --git a/tests/topotests/srv6_sid_manager/rt6/sharpd.conf b/tests/topotests/srv6_sid_manager/rt6/sharpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/sharpd.conf
diff --git a/tests/topotests/srv6_sid_manager/rt6/show_ip_route.ref b/tests/topotests/srv6_sid_manager/rt6/show_ip_route.ref
new file mode 100644
index 0000000000..5fc293b6d8
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/show_ip_route.ref
@@ -0,0 +1,273 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt6/show_ipv6_route.ref b/tests/topotests/srv6_sid_manager/rt6/show_ipv6_route.ref
new file mode 100644
index 0000000000..d06354b872
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/show_ipv6_route.ref
@@ -0,0 +1,312 @@
+{
+ "fc00:0:1::1\/128":[
+ {
+ "prefix":"fc00:0:1::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::1\/128":[
+ {
+ "prefix":"fc00:0:2::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::1\/128":[
+ {
+ "prefix":"fc00:0:3::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::1\/128":[
+ {
+ "prefix":"fc00:0:4::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::1\/128":[
+ {
+ "prefix":"fc00:0:5::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:1::\/48":[
+ {
+ "prefix":"fc00:0:1::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:2::\/48":[
+ {
+ "prefix":"fc00:0:2::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:3::\/48":[
+ {
+ "prefix":"fc00:0:3::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:4::\/48":[
+ {
+ "prefix":"fc00:0:4::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:5::\/48":[
+ {
+ "prefix":"fc00:0:5::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "fc00:0:6::\/48":[
+ {
+ "prefix":"fc00:0:6::\/48",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"sr0",
+ "active":true,
+ "seg6local":{
+ "action":"End"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:6:e000::\/64":[
+ {
+ "prefix":"fc00:0:6:e000::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:6:e001::\/64":[
+ {
+ "prefix":"fc00:0:6:e001::\/64",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "active":true,
+ "seg6local":{
+ "action":"End.X"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:6:fe00::\/128":[
+ {
+ "prefix":"fc00:0:6:fe00::\/128",
+ "protocol":"bgp",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"vrf10",
+ "active":true,
+ "seg6local":{
+ "action":"End.DT6"
+ }
+ }
+ ]
+ }
+ ],
+ "fc00:0:6:fe01::\/128":[
+ {
+ "prefix":"fc00:0:6:fe01::\/128",
+ "protocol":"bgp",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"vrf20",
+ "active":true,
+ "seg6local":{
+ "action":"End.DT6"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt6/show_srv6_locator_table.ref b/tests/topotests/srv6_sid_manager/rt6/show_srv6_locator_table.ref
new file mode 100644
index 0000000000..abcdeddea4
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/show_srv6_locator_table.ref
@@ -0,0 +1,15 @@
+{
+ "locators":[
+ {
+ "name":"loc1",
+ "prefix":"fc00:0:6::/48",
+ "blockBitsLength":32,
+ "nodeBitsLength":16,
+ "functionBitsLength":16,
+ "argumentBitsLength":0,
+ "statusUp":true,
+ "chunks":[
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/srv6_sid_manager/rt6/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..8300ca0b5c
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,44 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt4",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0004",
+ "hold-timer": 10,
+ "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": 10,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/srv6_sid_manager/rt6/vpnv6_rib.ref b/tests/topotests/srv6_sid_manager/rt6/vpnv6_rib.ref
new file mode 100644
index 0000000000..fe0fa24529
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/vpnv6_rib.ref
@@ -0,0 +1,169 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "6.6.6.6",
+ "defaultLocPrf": 100,
+ "localAS": 6,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "2001:1::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:1::",
+ "prefixLen": 64,
+ "network": "2001:1::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "fc00:0:1::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "fc00:0:1::1",
+ "hostname": "rt1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:3::",
+ "prefixLen": 64,
+ "network": "2001:3::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "fc00:0:1::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "fc00:0:1::1",
+ "hostname": "rt1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "fc00:0:1::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "fc00:0:1::1",
+ "hostname": "rt1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "6:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "rt6",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "6:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "rt6",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "rt6",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/srv6_sid_manager/rt6/vrf10_rib.ref b/tests/topotests/srv6_sid_manager/rt6/vrf10_rib.ref
new file mode 100644
index 0000000000..87ff5a9902
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/vrf10_rib.ref
@@ -0,0 +1,92 @@
+{
+ "2001:1::/64": [
+ {
+ "prefix": "2001:1::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 9,
+ "internalNextHopNum": 3,
+ "internalNextHopActiveNum": 3,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth-rt5",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "fc00:0:1:fe00::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ],
+ "2001:2::/64": [
+ {
+ "prefix": "2001:2::/64",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-ce2",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "prefix": "2001:3::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 9,
+ "internalNextHopNum": 3,
+ "internalNextHopActiveNum": 3,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth-rt5",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "fc00:0:1:fe00::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt6/vrf20_rib.ref b/tests/topotests/srv6_sid_manager/rt6/vrf20_rib.ref
new file mode 100644
index 0000000000..95d7d4412b
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/vrf20_rib.ref
@@ -0,0 +1,86 @@
+{
+ "2001:4::/64": [
+ {
+ "prefix": "2001:4::/64",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-ce4",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:5::/64": [
+ {
+ "prefix": "2001:5::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 9,
+ "internalNextHopNum": 3,
+ "internalNextHopActiveNum": 3,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth-rt5",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "fc00:0:1:fe01::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "prefix": "2001:6::/64",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth-ce6",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_sid_manager/rt6/zebra.conf b/tests/topotests/srv6_sid_manager/rt6/zebra.conf
new file mode 100644
index 0000000000..8ac64c559e
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/rt6/zebra.conf
@@ -0,0 +1,45 @@
+log file zebra.log
+!
+hostname rt6
+!
+! debug zebra kernel
+! debug zebra packet
+!
+interface lo
+ ip address 6.6.6.6/32
+ ipv6 address fc00:0:6::1/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.10.1/24
+ ip address 2001:db8:10::1/64
+!
+interface eth-ce2 vrf vrf10
+ ipv6 address 2001:2::1/64
+!
+interface eth-ce4 vrf vrf20
+ ipv6 address 2001:4::1/64
+!
+interface eth-ce6 vrf vrf20
+ ipv6 address 2001:6::1/64
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:6::/48
+ format usid-f3216
+ !
+ !
+!
+ip forwarding
+!
+ipv6 route fc00:0:9::1/128 2001:db8:10::2 vrf vrf10
+!
+line vty
+!
diff --git a/tests/topotests/srv6_sid_manager/test_srv6_sid_manager.py b/tests/topotests/srv6_sid_manager/test_srv6_sid_manager.py
new file mode 100644
index 0000000000..31f22d9900
--- /dev/null
+++ b/tests/topotests/srv6_sid_manager/test_srv6_sid_manager.py
@@ -0,0 +1,421 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# Copyright (c) 2023 by Carmine Scarpitta <cscarpit@cisco.com>
+#
+
+"""
+test_srv6_sid_manager.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.10.0/24
+ |
+ |eth-rt6 (.2)
+ +---------+
+ | |
+ | DST |
+ | 9.9.9.2 |
+ | |
+ +---------+
+
+"""
+
+import os
+import re
+import sys
+import json
+import functools
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import (
+ required_linux_kernel_version,
+ create_interface_in_kernel,
+)
+from lib.checkping import check_ping
+
+pytestmark = [pytest.mark.isisd, pytest.mark.sharpd]
+
+
+def build_topo(tgen):
+ """Build function"""
+
+ # Define FRR Routers
+ tgen.add_router("rt1")
+ tgen.add_router("rt2")
+ tgen.add_router("rt3")
+ tgen.add_router("rt4")
+ tgen.add_router("rt5")
+ tgen.add_router("rt6")
+ tgen.add_router("dst")
+ tgen.add_router("ce1")
+ tgen.add_router("ce2")
+ tgen.add_router("ce3")
+ tgen.add_router("ce4")
+ tgen.add_router("ce5")
+ tgen.add_router("ce6")
+
+ # 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")
+
+ tgen.add_link(tgen.gears["ce1"], tgen.gears["rt1"], "eth-rt1", "eth-ce1")
+ tgen.add_link(tgen.gears["ce2"], tgen.gears["rt6"], "eth-rt6", "eth-ce2")
+ tgen.add_link(tgen.gears["ce3"], tgen.gears["rt1"], "eth-rt1", "eth-ce3")
+ tgen.add_link(tgen.gears["ce4"], tgen.gears["rt6"], "eth-rt6", "eth-ce4")
+ tgen.add_link(tgen.gears["ce5"], tgen.gears["rt1"], "eth-rt1", "eth-ce5")
+ tgen.add_link(tgen.gears["ce6"], tgen.gears["rt6"], "eth-rt6", "eth-ce6")
+
+ tgen.gears["rt1"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["rt1"].run("ip link set vrf10 up")
+ tgen.gears["rt1"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["rt1"].run("ip link set vrf20 up")
+ tgen.gears["rt1"].run("ip link set eth-ce1 master vrf10")
+ tgen.gears["rt1"].run("ip link set eth-ce3 master vrf10")
+ tgen.gears["rt1"].run("ip link set eth-ce5 master vrf20")
+
+ tgen.gears["rt6"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["rt6"].run("ip link set vrf10 up")
+ tgen.gears["rt6"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["rt6"].run("ip link set vrf20 up")
+ tgen.gears["rt6"].run("ip link set eth-ce2 master vrf10")
+ tgen.gears["rt6"].run("ip link set eth-ce4 master vrf20")
+ tgen.gears["rt6"].run("ip link set eth-ce6 master vrf20")
+
+ # Add dummy interface for SRv6
+ create_interface_in_kernel(
+ tgen,
+ "rt1",
+ "sr0",
+ "2001:db8::1",
+ netmask="128",
+ create=True,
+ )
+ create_interface_in_kernel(
+ tgen,
+ "rt2",
+ "sr0",
+ "2001:db8::2",
+ netmask="128",
+ create=True,
+ )
+ create_interface_in_kernel(
+ tgen,
+ "rt3",
+ "sr0",
+ "2001:db8::3",
+ netmask="128",
+ create=True,
+ )
+ create_interface_in_kernel(
+ tgen,
+ "rt4",
+ "sr0",
+ "2001:db8::4",
+ netmask="128",
+ create=True,
+ )
+ create_interface_in_kernel(
+ tgen,
+ "rt5",
+ "sr0",
+ "2001:db8::5",
+ netmask="128",
+ create=True,
+ )
+ create_interface_in_kernel(
+ tgen,
+ "rt6",
+ "sr0",
+ "2001:db8::6",
+ netmask="128",
+ create=True,
+ )
+
+
+def setup_module(mod):
+ """Sets up the pytest environment"""
+
+ # Verify if kernel requirements are satisfied
+ result = required_linux_kernel_version("4.10")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ # Build the topology
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ # For all registered routers, load the zebra and isis configuration files
+ for rname, router in tgen.routers().items():
+ 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_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname)))
+ if (os.path.exists('{}/sharpd.conf'.format(rname))):
+ router.load_config(TopoRouter.RD_SHARP,
+ os.path.join(CWD, '{}/sharpd.conf'.format(rname)))
+
+ # Start routers
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+
+ # Teardown the topology
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def router_compare_json_output(rname, command, reference):
+ "Compare router JSON output"
+
+ logger.info('Comparing router "%s" "%s" output', rname, command)
+
+ tgen = get_topogen()
+ filename = "{}/{}/{}".format(CWD, rname, reference)
+ expected = json.loads(open(filename).read())
+
+ # Run test function until we get an result. Wait at most 60 seconds.
+ test_func = functools.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
+
+
+def check_ping6(name, dest_addr, expect_connected):
+ def _check(name, dest_addr, match):
+ tgen = get_topogen()
+ output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr))
+ logger.info(output)
+ if match not in output:
+ return "ping fail"
+
+ match = "{} packet loss".format("0%" if expect_connected else "100%")
+ logger.info("[+] check {} {} {}".format(name, dest_addr, match))
+ tgen = get_topogen()
+ func = functools.partial(_check, name, dest_addr, match)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=1)
+ assert result is None, "Failed"
+
+
+def open_json_file(filename):
+ try:
+ with open(filename, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(filename)
+
+
+def check_rib(name, cmd, expected_file):
+ def _check(name, cmd, expected_file):
+ logger.info("polling")
+ tgen = get_topogen()
+ router = tgen.gears[name]
+ output = json.loads(router.vtysh_cmd(cmd))
+ expected = open_json_file("{}/{}".format(CWD, expected_file))
+ return topotest.json_cmp(output, expected)
+
+ logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file))
+ tgen = get_topogen()
+ func = functools.partial(_check, name, cmd, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
+ assert result is None, "Failed"
+
+
+#
+# Step 1
+#
+# Test initial network convergence
+#
+def test_isis_adjacencies():
+ logger.info("Test: check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show yang operational-data /frr-interface:lib isisd",
+ "show_yang_interface_isis_adjacencies.ref",
+ )
+
+
+def test_rib_ipv4():
+ logger.info("Test: verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", "show_ip_route.ref"
+ )
+
+
+def test_rib_ipv6():
+ logger.info("Test: verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route json", "show_ipv6_route.ref"
+ )
+
+
+def test_srv6_locator():
+ logger.info("Test: verify SRv6 Locator")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show segment-routing srv6 locator json", "show_srv6_locator_table.ref"
+ )
+
+
+def test_vpn_rib():
+ check_rib("rt1", "show bgp ipv6 vpn json", "rt1/vpnv6_rib.ref")
+ check_rib("rt6", "show bgp ipv6 vpn json", "rt6/vpnv6_rib.ref")
+ check_rib("rt1", "show ipv6 route vrf vrf10 json", "rt1/vrf10_rib.ref")
+ check_rib("rt1", "show ipv6 route vrf vrf20 json", "rt1/vrf20_rib.ref")
+ check_rib("rt6", "show ipv6 route vrf vrf10 json", "rt6/vrf10_rib.ref")
+ check_rib("rt6", "show ipv6 route vrf vrf20 json", "rt6/vrf20_rib.ref")
+ check_rib("ce1", "show ipv6 route json", "ce1/ipv6_rib.json")
+ check_rib("ce2", "show ipv6 route json", "ce2/ipv6_rib.json")
+ check_rib("ce3", "show ipv6 route json", "ce3/ipv6_rib.json")
+ check_rib("ce4", "show ipv6 route json", "ce4/ipv6_rib.json")
+ check_rib("ce5", "show ipv6 route json", "ce5/ipv6_rib.json")
+ check_rib("ce6", "show ipv6 route json", "ce6/ipv6_rib.json")
+
+
+def test_ping():
+ logger.info("Test: verify ping")
+ tgen = get_topogen()
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("6.1")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met, kernel version should be >=6.1")
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Setup encap route on rt1, decap route on rt2
+ # tgen.gears["rt1"].vtysh_cmd("sharp install seg6-routes fc00:0:9::1 nexthop-seg6 2001:db8:1::2 encap fc00:0:2:6:fe00:: 1")
+ tgen.gears["rt1"].cmd("ip -6 r a fc00:0:9::1/128 encap seg6 mode encap segs fc00:0:2:6:fe00:: via 2001:db8:1::2")
+ # tgen.gears["rt6"].vtysh_cmd("sharp install seg6local-routes fc00:0:f00d:: nexthop-seg6local eth-dst End_DT6 254 1")
+ tgen.gears["rt6"].cmd("ip -6 r a fc00:0:9::1/128 via 2001:db8:10::2 vrf vrf10")
+ tgen.gears["dst"].cmd("ip -6 r a 2001:db8:1::1/128 via 2001:db8:10::1")
+
+ # Try to ping dst from rt1
+ check_ping("rt1", "fc00:0:9::1", True, 10, 1)
+
+
+# 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/zebra_fec_nexthop_resolution/__init__.py b/tests/topotests/zebra_fec_nexthop_resolution/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/__init__.py
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r1/bgpd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r1/bgpd.conf
new file mode 100644
index 0000000000..9d28957d99
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r1/bgpd.conf
@@ -0,0 +1,24 @@
+!
+router bgp 65500
+ bgp router-id 192.0.2.1
+ neighbor 192.0.2.3 remote-as 65500
+ neighbor 192.0.2.3 update-source lo
+ neighbor 192.0.2.7 remote-as 65500
+ neighbor 192.0.2.7 ttl-security hops 10
+ neighbor 192.0.2.7 disable-connected-check
+ neighbor 192.0.2.7 update-source lo
+ !
+ address-family ipv4 unicast
+ network 192.0.2.1/32
+ no neighbor 192.0.2.3 activate
+ neighbor 192.0.2.7 activate
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 192.0.2.3 activate
+ neighbor 192.0.2.3 route-reflector-client
+ neighbor 192.0.2.3 next-hop-self force
+ exit-address-family
+ !
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r1/ospfd.conf.after b/tests/topotests/zebra_fec_nexthop_resolution/r1/ospfd.conf.after
new file mode 100644
index 0000000000..3bb8cf8ac5
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r1/ospfd.conf.after
@@ -0,0 +1,25 @@
+log stdout
+!
+interface lo
+ ip ospf passive
+exit
+!
+interface r1-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 1
+exit
+!
+router ospf
+ ospf router-id 192.0.2.1
+ network 192.0.2.1/32 area 0.0.0.0
+ network 192.168.1.0/24 area 0.0.0.0
+ passive-interface lo
+ capability opaque
+ mpls-te on
+ mpls-te router-address 192.0.2.1
+ segment-routing on
+ segment-routing global-block 1000 10000 local-block 32000 32999
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.1/32 index 11
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r1/zebra.conf b/tests/topotests/zebra_fec_nexthop_resolution/r1/zebra.conf
new file mode 100644
index 0000000000..1522e90398
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r1/zebra.conf
@@ -0,0 +1,13 @@
+interface lo
+ ip address 192.0.2.1/32
+ mpls enable
+exit
+!
+interface r1-eth0
+ ip address 192.168.1.1/24
+ mpls enable
+ link-params
+ enable
+ exit-link-params
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r2/bgpd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r2/bgpd.conf
new file mode 100644
index 0000000000..46d2c9a01d
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r2/bgpd.conf
@@ -0,0 +1,23 @@
+router bgp 65500
+ bgp router-id 192.0.2.2
+ neighbor 192.0.2.1 remote-as 65500
+ neighbor 192.0.2.1 update-source lo
+ neighbor 192.0.2.3 remote-as 65500
+ neighbor 192.0.2.3 update-source lo
+ !
+ address-family ipv4 unicast
+ network 192.0.2.2/32
+ no neighbor 192.0.2.1 activate
+ no neighbor 192.0.2.3 activate
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 192.0.2.1 activate
+ neighbor 192.0.2.1 route-reflector-client
+ neighbor 192.0.2.1 next-hop-self force
+ neighbor 192.0.2.3 activate
+ neighbor 192.0.2.3 route-reflector-client
+ neighbor 192.0.2.3 next-hop-self force
+ exit-address-family
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r2/isisd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r2/isisd.conf
new file mode 100644
index 0000000000..add181ddae
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r2/isisd.conf
@@ -0,0 +1,25 @@
+!
+interface lo
+ ip router isis 1
+ isis hello-interval 1
+ isis hello-multiplier 3
+exit
+!
+interface r2-eth1
+ ip router isis 2
+ isis hello-interval 1
+ isis hello-multiplier 3
+exit
+!
+router isis 1
+ is-type level-1
+ net 49.0000.0007.e901.2223.00
+ lsp-timers gen-interval 1 refresh-interval 900 max-lifetime 1200
+ mpls-te on
+ mpls-te router-address 192.0.2.2
+ segment-routing on
+ segment-routing global-block 11000 20000 local-block 36000 36999
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.2/32 index 22 no-php-flag
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r2/ospfd.conf.after b/tests/topotests/zebra_fec_nexthop_resolution/r2/ospfd.conf.after
new file mode 100644
index 0000000000..8b02669862
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r2/ospfd.conf.after
@@ -0,0 +1,32 @@
+log stdout
+!
+interface lo
+ ip ospf network point-to-point
+ ip ospf passive
+exit
+!
+interface r2-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 1
+exit
+!
+interface r2-eth1
+ ip ospf network point-to-point
+ ip ospf hello-interval 1
+exit
+!
+router ospf
+ ospf router-id 192.0.2.2
+ network 192.0.2.2/32 area 0.0.0.0
+ network 192.168.1.0/24 area 0.0.0.0
+ network 192.168.2.0/24 area 0.0.0.0
+ passive-interface lo
+ capability opaque
+ mpls-te on
+ mpls-te router-address 192.0.2.2
+ segment-routing on
+ segment-routing global-block 1000 10000 local-block 36000 36999
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.2/32 index 22
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r2/zebra.conf b/tests/topotests/zebra_fec_nexthop_resolution/r2/zebra.conf
new file mode 100644
index 0000000000..af0d1eb7fe
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r2/zebra.conf
@@ -0,0 +1,16 @@
+!
+interface lo
+ ip address 192.0.2.2/32
+ mpls enable
+exit
+!
+interface r2-eth0
+ ip address 192.168.1.2/24
+ mpls enable
+exit
+!
+interface r2-eth1
+ ip address 192.168.2.2/24
+ mpls enable
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r3/bgpd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r3/bgpd.conf
new file mode 100644
index 0000000000..060777e7fe
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r3/bgpd.conf
@@ -0,0 +1,23 @@
+router bgp 65500
+ bgp router-id 192.0.2.3
+ neighbor 192.0.2.1 remote-as 65500
+ neighbor 192.0.2.1 update-source lo
+ neighbor 192.0.2.5 remote-as 65500
+ neighbor 192.0.2.5 update-source lo
+ !
+ address-family ipv4 unicast
+ network 192.0.2.3/32
+ no neighbor 192.0.2.1 activate
+ no neighbor 192.0.2.5 activate
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 192.0.2.1 activate
+ neighbor 192.0.2.1 route-reflector-client
+ neighbor 192.0.2.1 next-hop-self force
+ neighbor 192.0.2.5 activate
+ neighbor 192.0.2.5 route-reflector-client
+ neighbor 192.0.2.5 next-hop-self force
+ exit-address-family
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r3/isisd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r3/isisd.conf
new file mode 100644
index 0000000000..db6a503bb2
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r3/isisd.conf
@@ -0,0 +1,25 @@
+!
+interface lo
+ ip router isis 1
+ isis hello-interval 1
+ isis hello-multiplier 3
+exit
+!
+interface r3-eth1
+ ip router isis 1
+ isis hello-interval 1
+ isis hello-multiplier 3
+exit
+!
+router isis 1
+ is-type level-1
+ net 49.0000.0007.e901.3333.00
+ lsp-timers gen-interval 1 refresh-interval 900 max-lifetime 1200
+ mpls-te on
+ mpls-te router-address 192.0.2.3
+ segment-routing on
+ segment-routing global-block 11000 12000 local-block 36000 36999
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.3/32 index 33
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r3/ospfd.conf.after b/tests/topotests/zebra_fec_nexthop_resolution/r3/ospfd.conf.after
new file mode 100644
index 0000000000..a3f5ae54f0
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r3/ospfd.conf.after
@@ -0,0 +1,26 @@
+log stdout
+!
+interface lo
+ ip ospf network point-to-point
+ ip ospf passive
+exit
+!
+interface r3-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 1
+exit
+!
+router ospf
+ ospf router-id 192.0.2.3
+ network 192.0.2.3/32 area 0.0.0.0
+ network 192.168.2.0/24 area 0.0.0.0
+ passive-interface lo
+ capability opaque
+ mpls-te on
+ mpls-te router-address 192.0.2.3
+ segment-routing on
+ segment-routing global-block 1000 10000 local-block 30000 30999
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.3/32 index 33
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r3/zebra.conf b/tests/topotests/zebra_fec_nexthop_resolution/r3/zebra.conf
new file mode 100644
index 0000000000..b309e15afa
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r3/zebra.conf
@@ -0,0 +1,19 @@
+!
+interface lo
+ ip address 192.0.2.3/32
+ mpls enable
+exit
+!
+interface r3-eth0
+ ip address 192.168.2.3/24
+ mpls enable
+ link-params
+ enable
+ exit-link-params
+exit
+!
+interface r3-eth1
+ ip address 192.168.3.3/24
+ mpls enable
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r4/bgpd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r4/bgpd.conf
new file mode 100644
index 0000000000..dc052da863
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r4/bgpd.conf
@@ -0,0 +1,24 @@
+!
+router bgp 65500
+ bgp router-id 192.0.2.4
+ neighbor 192.0.2.1 remote-as 65500
+ neighbor 192.0.2.1 ttl-security hops 10
+ neighbor 192.0.2.1 disable-connected-check
+ neighbor 192.0.2.1 update-source lo
+ neighbor 192.0.2.3 remote-as 65500
+ neighbor 192.0.2.3 update-source lo
+ !
+ address-family ipv4 unicast
+ network 192.0.2.4/32
+ neighbor 192.0.2.1 activate
+ no neighbor 192.0.2.3 activate
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 192.0.2.3 activate
+ neighbor 192.0.2.3 route-reflector-client
+ neighbor 192.0.2.3 next-hop-self force
+ exit-address-family
+ !
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r4/isisd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r4/isisd.conf
new file mode 100644
index 0000000000..7096ce081e
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r4/isisd.conf
@@ -0,0 +1,31 @@
+!
+interface lo
+ ip router isis 1
+ isis hello-interval 1
+ isis hello-multiplier 3
+exit
+!
+interface r4-eth0
+ ip router isis 1
+ isis hello-interval 1
+ isis hello-multiplier 3
+exit
+!
+interface r4-eth1
+ ip router isis 1
+ isis hello-interval 1
+ isis hello-multiplier 3
+exit
+!
+router isis 1
+ is-type level-1
+ net 49.0000.0007.e901.4444.00
+ lsp-timers gen-interval 1 refresh-interval 900 max-lifetime 1200
+ mpls-te on
+ mpls-te router-address 192.0.2.4
+ segment-routing on
+ segment-routing global-block 11000 12000 local-block 37000 37999
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.4/32 index 44
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r4/ospfd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r4/ospfd.conf
new file mode 100644
index 0000000000..c160049675
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r4/ospfd.conf
@@ -0,0 +1,19 @@
+!
+interface lo
+ ip ospf area 0
+ ip ospf passive
+exit
+!
+interface r4-eth0
+ ip ospf area 0
+exit
+!
+router ospf
+ mpls-te on
+ mpls-te router-address 192.0.2.4
+ segment-routing on
+ segment-routing global-block 21000 29000 local-block 31000 31999
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.4/32 index 44 no-php-flag
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r4/zebra.conf b/tests/topotests/zebra_fec_nexthop_resolution/r4/zebra.conf
new file mode 100644
index 0000000000..8591047906
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r4/zebra.conf
@@ -0,0 +1,16 @@
+!
+interface lo
+ ip address 192.0.2.4/32
+ mpls enable
+exit
+!
+interface r4-eth0
+ ip address 192.168.3.4/24
+ mpls enable
+exit
+!
+interface r4-eth1
+ ip address 192.168.4.4/24
+ mpls enable
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r5/bgpd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r5/bgpd.conf
new file mode 100644
index 0000000000..1c73154e27
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r5/bgpd.conf
@@ -0,0 +1,23 @@
+router bgp 65500
+ bgp router-id 192.0.2.5
+ neighbor 192.0.2.3 remote-as 65500
+ neighbor 192.0.2.3 update-source lo
+ neighbor 192.0.2.7 remote-as 65500
+ neighbor 192.0.2.7 update-source lo
+ !
+ address-family ipv4 unicast
+ network 192.0.2.5/32
+ no neighbor 192.0.2.3 activate
+ no neighbor 192.0.2.7 activate
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 192.0.2.3 activate
+ neighbor 192.0.2.3 route-reflector-client
+ neighbor 192.0.2.3 next-hop-self force
+ neighbor 192.0.2.7 activate
+ neighbor 192.0.2.7 route-reflector-client
+ neighbor 192.0.2.7 next-hop-self force
+ exit-address-family
+exit
+!
diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/isisd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r5/isisd.conf
index f210554ff6..959d5be29b 100644
--- a/tests/topotests/bgp_6vpe_ebgp_topo1/pe2/isisd.conf
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r5/isisd.conf
@@ -3,20 +3,24 @@ interface lo
ip router isis 1
isis hello-interval 1
isis hello-multiplier 3
+ isis passive
+exit
!
-interface eth-pe1
+interface r5-eth0
ip router isis 1
isis hello-interval 1
isis hello-multiplier 3
+exit
!
router isis 1
- net 49.0000.0007.e901.5555.00
is-type level-1
- lsp-gen-interval 1
+ net 49.0000.0007.e901.5555.00
+ lsp-timers gen-interval 1 refresh-interval 900 max-lifetime 1200
mpls-te on
- mpls-te router-address 198.51.100.5
+ mpls-te router-address 192.0.2.5
segment-routing on
+ segment-routing global-block 11000 12000 local-block 33000 33999
segment-routing node-msd 8
- segment-routing global-block 1000 10000 local-block 33000 33999
- segment-routing prefix 198.51.100.5/32 index 55
+ segment-routing prefix 192.0.2.5/32 index 55
+exit
!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r5/ospfd.conf.after b/tests/topotests/zebra_fec_nexthop_resolution/r5/ospfd.conf.after
new file mode 100644
index 0000000000..868129f890
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r5/ospfd.conf.after
@@ -0,0 +1,26 @@
+log stdout
+!
+interface lo
+ ip ospf network point-to-point
+ ip ospf passive
+exit
+!
+interface r5-eth1
+ ip ospf network point-to-point
+ ip ospf hello-interval 1
+exit
+!
+router ospf
+ ospf router-id 192.0.2.5
+ network 192.0.2.5/32 area 0.0.0.0
+ network 192.168.5.0/24 area 0.0.0.0
+ passive-interface lo
+ capability opaque
+ mpls-te on
+ mpls-te router-address 192.0.2.5
+ segment-routing on
+ segment-routing global-block 21000 22000 local-block 35000 35999
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.5/32 index 55
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r5/zebra.conf b/tests/topotests/zebra_fec_nexthop_resolution/r5/zebra.conf
new file mode 100644
index 0000000000..dd519e8d12
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r5/zebra.conf
@@ -0,0 +1,19 @@
+!
+interface lo
+ ip address 192.0.2.5/32
+ mpls enable
+exit
+!
+interface r5-eth0
+ ip address 192.168.4.5/24
+ mpls enable
+exit
+!
+interface r5-eth1
+ ip address 192.168.5.5/24
+ mpls enable
+ link-params
+ enable
+ exit-link-params
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r6/ospfd.conf.after b/tests/topotests/zebra_fec_nexthop_resolution/r6/ospfd.conf.after
new file mode 100644
index 0000000000..60c4928f77
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r6/ospfd.conf.after
@@ -0,0 +1,32 @@
+log stdout
+!
+interface lo
+ ip ospf network point-to-point
+ ip ospf passive
+exit
+!
+interface r6-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 1
+exit
+!
+interface r6-eth1
+ ip ospf network point-to-point
+ ip ospf hello-interval 1
+exit
+!
+router ospf
+ ospf router-id 192.0.2.6
+ segment-routing on
+ segment-routing global-block 21000 22000 local-block 38000 38999
+ network 192.0.2.6/32 area 0.0.0.0
+ network 192.168.5.0/24 area 0.0.0.0
+ network 192.168.6.0/24 area 0.0.0.0
+ passive-interface lo
+ capability opaque
+ mpls-te on
+ mpls-te router-address 192.0.2.6
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.6/32 index 66
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r6/zebra.conf b/tests/topotests/zebra_fec_nexthop_resolution/r6/zebra.conf
new file mode 100644
index 0000000000..5e16e3e434
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r6/zebra.conf
@@ -0,0 +1,22 @@
+!
+interface lo
+ ip address 192.0.2.6/32
+ mpls enable
+exit
+!
+interface r6-eth0
+ ip address 192.168.5.6/24
+ mpls enable
+ link-params
+ enable
+ exit-link-params
+exit
+!
+interface r6-eth1
+ ip address 192.168.6.6/24
+ mpls enable
+ link-params
+ enable
+ exit-link-params
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r7/bgpd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r7/bgpd.conf
new file mode 100644
index 0000000000..eeda9d9cfa
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r7/bgpd.conf
@@ -0,0 +1,24 @@
+!
+router bgp 65500
+ bgp router-id 192.0.2.7
+ neighbor 192.0.2.1 remote-as 65500
+ neighbor 192.0.2.1 ttl-security hops 10
+ neighbor 192.0.2.1 disable-connected-check
+ neighbor 192.0.2.1 update-source lo
+ neighbor 192.0.2.5 remote-as 65500
+ neighbor 192.0.2.5 update-source lo
+ !
+ address-family ipv4 unicast
+ network 192.0.2.7/32
+ neighbor 192.0.2.1 activate
+ no neighbor 192.0.2.5 activate
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 192.0.2.5 activate
+ neighbor 192.0.2.5 route-reflector-client
+ neighbor 192.0.2.5 next-hop-self force
+ exit-address-family
+ !
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r7/ospfd.conf.after b/tests/topotests/zebra_fec_nexthop_resolution/r7/ospfd.conf.after
new file mode 100644
index 0000000000..f8e56e1217
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r7/ospfd.conf.after
@@ -0,0 +1,26 @@
+log stdout
+!
+interface lo
+ ip ospf network point-to-point
+ ip ospf passive
+exit
+!
+interface r7-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 1
+exit
+!
+router ospf
+ ospf router-id 192.0.2.7
+ network 192.0.2.7/32 area 0.0.0.0
+ network 192.168.6.0/24 area 0.0.0.0
+ passive-interface lo
+ capability opaque
+ mpls-te on
+ mpls-te router-address 192.0.2.7
+ segment-routing on
+ segment-routing global-block 21000 22000 local-block 31000 31999
+ segment-routing node-msd 8
+ segment-routing prefix 192.0.2.7/32 index 77
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/r7/zebra.conf b/tests/topotests/zebra_fec_nexthop_resolution/r7/zebra.conf
new file mode 100644
index 0000000000..f520225476
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/r7/zebra.conf
@@ -0,0 +1,14 @@
+!
+interface lo
+ ip address 192.0.2.7/32
+ mpls enable
+exit
+!
+interface r7-eth0
+ ip address 192.168.6.7/24
+ mpls enable
+ link-params
+ enable
+ exit-link-params
+exit
+!
diff --git a/tests/topotests/zebra_fec_nexthop_resolution/test_zebra_fec_nexthop_resolution.py b/tests/topotests/zebra_fec_nexthop_resolution/test_zebra_fec_nexthop_resolution.py
new file mode 100644
index 0000000000..984ff3c185
--- /dev/null
+++ b/tests/topotests/zebra_fec_nexthop_resolution/test_zebra_fec_nexthop_resolution.py
@@ -0,0 +1,259 @@
+#!/usr/bin/env python
+
+#
+# Copyright 2022 6WIND S.A.
+#
+# 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.
+#
+
+"""
+Check if fec nexthop resolution works correctly.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ """
+ r1 ---- r2 ---- r3 ---- r4 ----- r5 ---- r6 ---- r7
+ <--- ospf ----> <---- isis -----> <--- ospf ---->
+ """
+ for routern in range(1, 8):
+ tgen.add_router("r{}".format(routern))
+
+ switch1 = tgen.add_switch("s1")
+ switch1.add_link(tgen.gears["r1"])
+ switch1.add_link(tgen.gears["r2"])
+
+ switch2 = tgen.add_switch("s2")
+ switch2.add_link(tgen.gears["r2"])
+ switch2.add_link(tgen.gears["r3"])
+
+ switch3 = tgen.add_switch("s3")
+ switch3.add_link(tgen.gears["r3"])
+ switch3.add_link(tgen.gears["r4"])
+
+ switch4 = tgen.add_switch("s4")
+ switch4.add_link(tgen.gears["r4"])
+ switch4.add_link(tgen.gears["r5"])
+
+ switch5 = tgen.add_switch("s5")
+ switch5.add_link(tgen.gears["r5"])
+ switch5.add_link(tgen.gears["r6"])
+
+ switch6 = tgen.add_switch("s6")
+ switch6.add_link(tgen.gears["r6"])
+ switch6.add_link(tgen.gears["r7"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ def _enable_mpls_misc(router):
+ router.run("modprobe mpls_router")
+ router.run("echo 100000 > /proc/sys/net/mpls/platform_labels")
+ router.run("echo 1 > /proc/sys/net/mpls/conf/lo/input")
+
+ router = tgen.gears["r1"]
+ _enable_mpls_misc(router)
+
+ router = tgen.gears["r2"]
+ _enable_mpls_misc(router)
+
+ router = tgen.gears["r3"]
+ _enable_mpls_misc(router)
+
+ router = tgen.gears["r4"]
+ _enable_mpls_misc(router)
+
+ router = tgen.gears["r5"]
+ _enable_mpls_misc(router)
+
+ router = tgen.gears["r6"]
+ _enable_mpls_misc(router)
+
+ router = tgen.gears["r7"]
+ _enable_mpls_misc(router)
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ if rname in ("r1", "r3", "r5", "r7"):
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+ if rname in ("r3", "r4", "r5"):
+ router.load_config(
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
+ )
+ if rname in ("r1", "r2", "r3", "r5", "r6", "r7"):
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+# There are some startup issued when initialising OSPF
+# To avoid those issues, load the ospf configuration after zebra started
+def test_zebra_fec_nexthop_resolution_finalise_ospf_config():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ topotest.sleep(2)
+
+ tgen.net["r1"].cmd("vtysh -f {}/r1/ospfd.conf.after".format(CWD))
+ tgen.net["r2"].cmd("vtysh -f {}/r2/ospfd.conf.after".format(CWD))
+ tgen.net["r3"].cmd("vtysh -f {}/r3/ospfd.conf.after".format(CWD))
+ tgen.net["r5"].cmd("vtysh -f {}/r5/ospfd.conf.after".format(CWD))
+ tgen.net["r6"].cmd("vtysh -f {}/r6/ospfd.conf.after".format(CWD))
+ tgen.net["r7"].cmd("vtysh -f {}/r7/ospfd.conf.after".format(CWD))
+
+
+def test_zebra_fec_nexthop_resolution_bgp():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _check_bgp_session():
+ r1 = tgen.gears["r1"]
+
+ tgen.gears["r3"].vtysh_cmd("config \n no mpls fec nexthop-resolution \n end")
+ tgen.gears["r3"].vtysh_cmd("config \n mpls fec nexthop-resolution \n end")
+ tgen.gears["r5"].vtysh_cmd("config \n no mpls fec nexthop-resolution \n end")
+ tgen.gears["r5"].vtysh_cmd("config \n mpls fec nexthop-resolution \n end")
+ output = json.loads(r1.vtysh_cmd("show bgp summary json"))
+
+ if output["ipv4Unicast"]["peers"]["192.0.2.7"]["state"] == "Established":
+ return None
+ return False
+
+ test_func1 = functools.partial(_check_bgp_session)
+ _, result1 = topotest.run_and_expect(test_func1, None, count=60, wait=0.5)
+ assert result1 is None, "Failed to verify the fec_nexthop_resolution: bgp session"
+
+
+def test_zebra_fec_nexthop_resolution_ping():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _check_ping_launch():
+ r1 = tgen.gears["r1"]
+
+ ping_launch = "ping 192.0.2.7 -I 192.0.2.1 -c 1"
+ selected_lines = r1.run(ping_launch).splitlines()[-2:-1]
+ rtx_stats = "".join(selected_lines[0].split(",")[0:3])
+ current = topotest.normalize_text(rtx_stats)
+
+ expected_stats = "1 packets transmitted 1 received 0% packet loss"
+ expected = topotest.normalize_text(expected_stats)
+
+ if current == expected:
+ return None
+
+ return False
+
+ test_func2 = functools.partial(_check_ping_launch)
+ _, result2 = topotest.run_and_expect(test_func2, None, count=60, wait=1)
+ assert result2 is None, "Failed to verify the fec_nexthop_resolution: ping"
+
+
+def test_zebra_fec_nexthop_resolution_table():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _zebra_check_mpls_table():
+ r3 = tgen.gears["r3"]
+ inLabel = 0
+ outLabels = 0
+
+ """
+ Retrieve inLabel from MPLS FEC table
+ """
+ mpls_fec = r3.vtysh_cmd("show mpls fec 192.0.2.7/32")
+ lines = mpls_fec.split("\n")
+ for line in lines:
+ if "Label" in line:
+ inLabel = line.split(": ", 1)[1]
+
+ """
+ Retrieve outLabel from BGP
+ """
+ output = json.loads(r3.vtysh_cmd("show ip route 192.0.2.7/32 json"))
+
+ outLabels = output["192.0.2.7/32"][0]["nexthops"][1]["labels"]
+
+ if (inLabel == 0) or (outLabels == 0):
+ return True
+
+ """
+ Compare expected data with real data
+ """
+ output = json.loads(r3.vtysh_cmd("show mpls table " + str(inLabel) + " json"))
+
+ expected = {
+ "inLabel": int(inLabel),
+ "installed": True,
+ "nexthops": [
+ {
+ "type": "BGP",
+ "outLabel": outLabels[0],
+ "outLabelStack": outLabels,
+ "distance": 20,
+ "installed": True,
+ "nexthop": "192.168.3.4",
+ }
+ ],
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func3 = functools.partial(_zebra_check_mpls_table)
+ _, result3 = topotest.run_and_expect(test_func3, None, count=60, wait=0.5)
+ assert result3 is None, "Failed to verify the fec_nexthop_resolution: mpls table"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/zebra_multiple_connected/r1/ip_route_connected.json b/tests/topotests/zebra_multiple_connected/r1/ip_route_connected.json
new file mode 100644
index 0000000000..db03ce84a6
--- /dev/null
+++ b/tests/topotests/zebra_multiple_connected/r1/ip_route_connected.json
@@ -0,0 +1,24 @@
+{
+ "192.168.44.0/24":[
+ {
+ "prefix":"192.168.44.0/24",
+ "prefixLen":24,
+ "protocol":"connected",
+ "vrfName":"default",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/zebra_multiple_connected/r1/ip_route_kernel.json b/tests/topotests/zebra_multiple_connected/r1/ip_route_kernel.json
new file mode 100644
index 0000000000..22465cb477
--- /dev/null
+++ b/tests/topotests/zebra_multiple_connected/r1/ip_route_kernel.json
@@ -0,0 +1,24 @@
+{
+ "4.5.6.7/32":[
+ {
+ "prefix":"4.5.6.7/32",
+ "prefixLen":32,
+ "protocol":"kernel",
+ "vrfName":"default",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
index dc47527c74..7dbeb6f1cc 100644
--- a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
+++ b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
@@ -19,6 +19,9 @@ import sys
import pytest
import json
from functools import partial
+from lib.topolog import logger
+
+pytestmark = pytest.mark.random_order(disabled=True)
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
@@ -159,6 +162,46 @@ def test_zebra_noprefix_connected():
assert result, "Connected Route should not have been added"
+def test_zebra_noprefix_connected_add():
+ "Test that a noprefixroute created with a manual route works as expected, this is for NetworkManager"
+
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r1"]
+ router.run("ip route add 192.168.44.0/24 dev r1-eth1")
+
+ connected = "{}/{}/ip_route_connected.json".format(CWD, router.name)
+ expected = json.loads(open(connected).read())
+
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip route 192.168.44.0/24 json", expected
+ )
+ result, _ = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assert result, "Connected Route should have been added\n{}".format(_)
+
+
+def test_zebra_kernel_route_add():
+ "Test that a random kernel route is properly handled as expected"
+
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r1"]
+ router.run("ip route add 4.5.6.7/32 dev r1-eth1")
+
+ kernel = "{}/{}/ip_route_kernel.json".format(CWD, router.name)
+ expected = json.loads(open(kernel).read())
+
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip route 4.5.6.7/32 json", expected
+ )
+ result, _ = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assert result, "Connected Route should have been added\n{}".format(_)
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py
index 93296cd51a..c0a79ed79d 100644
--- a/tests/topotests/zebra_rib/test_zebra_rib.py
+++ b/tests/topotests/zebra_rib/test_zebra_rib.py
@@ -153,7 +153,7 @@ def test_zebra_kernel_admin_distance():
# metric. That needs to be properly resolved. Making a note for
# coming back around later and fixing this.
# tgen.mininet_cli()
- for i in range(1, 2):
+ for i in range(1, 3):
json_file = "{}/r1/v4_route_{}.json".format(CWD, i)
expected = json.loads(open(json_file).read())
diff --git a/tests/topotests/zebra_seg6local_route/r1/routes.json b/tests/topotests/zebra_seg6local_route/r1/routes.json
index e391922566..7dcc6450fa 100644
--- a/tests/topotests/zebra_seg6local_route/r1/routes.json
+++ b/tests/topotests/zebra_seg6local_route/r1/routes.json
@@ -119,5 +119,78 @@
}]
}],
"required_kernel": "5.14"
+ },
+ {
+ "in": {
+ "dest": "6::1",
+ "context": "End_DX6 2001::1"
+ },
+ "out":[{
+ "prefix":"6::1/128",
+ "protocol":"sharp",
+ "selected":true,
+ "destSelected":true,
+ "distance":150,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[{
+ "flags":3,
+ "fib":true,
+ "active":true,
+ "directlyConnected":true,
+ "interfaceName": "dum0",
+ "seg6local": { "action": "End.DX6" }
+ }]
+ }]
+ },
+ {
+ "in": {
+ "dest": "7::1",
+ "context": "End_DT4 10"
+ },
+ "out":[{
+ "prefix":"7::1/128",
+ "protocol":"sharp",
+ "selected":true,
+ "destSelected":true,
+ "distance":150,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[{
+ "flags":3,
+ "fib":true,
+ "active":true,
+ "directlyConnected":true,
+ "interfaceName": "dum0",
+ "seg6local": { "action": "End.DT4" }
+ }]
+ }],
+ "required_kernel": "5.11"
+ },
+ {
+ "in": {
+ "dest": "8::1",
+ "context": "End_DT6 10"
+ },
+ "out":[{
+ "prefix":"8::1/128",
+ "protocol":"sharp",
+ "selected":true,
+ "destSelected":true,
+ "distance":150,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[{
+ "flags":3,
+ "fib":true,
+ "active":true,
+ "directlyConnected":true,
+ "interfaceName": "dum0",
+ "seg6local": { "action": "End.DT6" }
+ }]
+ }]
}
]
diff --git a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py
index a90f5c9c98..59c681df48 100755
--- a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py
+++ b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py
@@ -42,7 +42,7 @@ def setup_module(mod):
tgen = Topogen({None: "r1"}, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in tgen.routers().items():
+ for rname, router in router_list.items():
router.run(
"/bin/bash {}".format(os.path.join(CWD, "{}/setup.sh".format(rname)))
)
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index a88f6b616d..08a1f1e07e 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -203,7 +203,7 @@ def get_normalized_es_id(line):
"""
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)
+ obj = re.match(sub_str + r" (?P<esi>\S*)", line)
if obj:
line = "%s %s" % (sub_str, obj.group("esi").lower())
break
@@ -871,7 +871,7 @@ def bgp_delete_nbr_remote_as_line(lines_to_add):
if ctx_keys[0] not in pg_dict:
pg_dict[ctx_keys[0]] = dict()
# find 'neighbor <pg_name> peer-group'
- re_pg = re.match("neighbor (\S+) peer-group$", line)
+ re_pg = re.match(r"neighbor (\S+) peer-group$", line)
if re_pg and re_pg.group(1) not in pg_dict[ctx_keys[0]]:
pg_dict[ctx_keys[0]][re_pg.group(1)] = {
"nbr": list(),
@@ -1066,7 +1066,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del):
if ctx_keys[0] not in del_dict:
del_dict[ctx_keys[0]] = dict()
# find 'no neighbor <pg_name> peer-group'
- re_pg = re.match("neighbor (\S+) peer-group$", line)
+ re_pg = re.match(r"neighbor (\S+) peer-group$", line)
if re_pg and re_pg.group(1) not in del_dict[ctx_keys[0]]:
del_dict[ctx_keys[0]][re_pg.group(1)] = list()
found_pg_del_cmd = True
@@ -1140,14 +1140,14 @@ def pim_delete_move_lines(lines_to_add, lines_to_del):
# they are implicitly deleted by 'no ip pim'.
# Remove all such depdendent options from delete
# pending list.
- pim_disable = False
+ pim_disable = []
lines_to_del_to_del = []
index = -1
for ctx_keys, line in lines_to_del:
index = index + 1
if ctx_keys[0].startswith("interface") and line and line == "ip pim":
- pim_disable = True
+ pim_disable.append(ctx_keys[0])
# no ip msdp peer <> does not accept source so strip it off.
if line and line.startswith("ip msdp peer "):
@@ -1158,14 +1158,19 @@ def pim_delete_move_lines(lines_to_add, lines_to_del):
lines_to_del.remove((ctx_keys, line))
lines_to_del.insert(index, (ctx_keys, new_line))
- if pim_disable:
- for ctx_keys, line in lines_to_del:
- if (
- ctx_keys[0].startswith("interface")
- and line
- and (line.startswith("ip pim ") or line.startswith("ip multicast "))
- ):
- lines_to_del_to_del.append((ctx_keys, line))
+ for ctx_keys, line in lines_to_del:
+ if (
+ ctx_keys[0] in pim_disable
+ and ctx_keys[0].startswith("interface")
+ and line
+ and (
+ line.startswith("ip pim ")
+ or line.startswith("no ip pim ")
+ or line.startswith("ip multicast ")
+ or line.startswith("no ip multicast ")
+ )
+ ):
+ lines_to_del_to_del.append((ctx_keys, line))
for ctx_keys, line in lines_to_del_to_del:
lines_to_del.remove((ctx_keys, line))
diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c
index a879811363..046dc9e99e 100644
--- a/tools/gen_northbound_callbacks.c
+++ b/tools/gen_northbound_callbacks.c
@@ -448,7 +448,7 @@ int main(int argc, char *argv[])
if (argc != 1)
usage(EXIT_FAILURE);
- yang_init(false, true);
+ yang_init(false, true, false);
if (search_path)
ly_ctx_set_searchdir(ly_native_ctx, search_path);
diff --git a/tools/gen_yang_deviations.c b/tools/gen_yang_deviations.c
index 251643c69e..c2e7fd91c6 100644
--- a/tools/gen_yang_deviations.c
+++ b/tools/gen_yang_deviations.c
@@ -52,7 +52,7 @@ int main(int argc, char *argv[])
if (argc != 1)
usage(EXIT_FAILURE);
- yang_init(false, false);
+ yang_init(false, false, false);
/* Load YANG module. */
module = yang_module_load(argv[0], NULL);
diff --git a/tools/subdir.am b/tools/subdir.am
index 64ca0bd514..f2ed2332b8 100644
--- a/tools/subdir.am
+++ b/tools/subdir.am
@@ -13,15 +13,20 @@ EXTRA_PROGRAMS += \
# end
sbin_PROGRAMS += tools/ssd
+
+if PYTHON_RUNTIME_DEPENDENCY
sbin_SCRIPTS += \
- tools/frr-reload \
tools/frr-reload.py \
+ tools/generate_support_bundle.py \
+ tools/frr_babeltrace.py
+endif
+
+sbin_SCRIPTS += \
+ tools/frr-reload \
tools/frr \
\
tools/frrcommon.sh \
tools/frrinit.sh \
- tools/generate_support_bundle.py \
- tools/frr_babeltrace.py \
tools/watchfrr.sh \
# end
diff --git a/vrrpd/vrrp_debug.c b/vrrpd/vrrp_debug.c
index a772b3b5c5..fd0edcfc77 100644
--- a/vrrpd/vrrp_debug.c
+++ b/vrrpd/vrrp_debug.c
@@ -13,79 +13,15 @@
#include "vrrp_debug.h"
/* clang-format off */
-struct debug vrrp_dbg_arp = {0, "VRRP ARP"};
-struct debug vrrp_dbg_auto = {0, "VRRP autoconfiguration events"};
-struct debug vrrp_dbg_ndisc = {0, "VRRP Neighbor Discovery"};
-struct debug vrrp_dbg_pkt = {0, "VRRP packets"};
-struct debug vrrp_dbg_proto = {0, "VRRP protocol events"};
-struct debug vrrp_dbg_sock = {0, "VRRP sockets"};
-struct debug vrrp_dbg_zebra = {0, "VRRP Zebra events"};
-
-struct debug *vrrp_debugs[] = {
- &vrrp_dbg_arp,
- &vrrp_dbg_auto,
- &vrrp_dbg_ndisc,
- &vrrp_dbg_pkt,
- &vrrp_dbg_proto,
- &vrrp_dbg_sock,
- &vrrp_dbg_zebra
-};
-
-const char *vrrp_debugs_conflines[] = {
- "debug vrrp arp",
- "debug vrrp autoconfigure",
- "debug vrrp ndisc",
- "debug vrrp packets",
- "debug vrrp protocol",
- "debug vrrp sockets",
- "debug vrrp zebra",
-};
+struct debug vrrp_dbg_arp = {0, "debug vrrp arp", "VRRP ARP"};
+struct debug vrrp_dbg_auto = {0, "debug vrrp autoconfigure", "VRRP autoconfiguration events"};
+struct debug vrrp_dbg_ndisc = {0, "debug vrrp ndisc", "VRRP Neighbor Discovery"};
+struct debug vrrp_dbg_pkt = {0, "debug vrrp packets", "VRRP packets"};
+struct debug vrrp_dbg_proto = {0, "debug vrrp protocol", "VRRP protocol events"};
+struct debug vrrp_dbg_sock = {0, "debug vrrp sockets", "VRRP sockets"};
+struct debug vrrp_dbg_zebra = {0, "debug vrrp zebra", "VRRP Zebra events"};
/* clang-format on */
-/*
- * Set or unset flags on all debugs for vrrpd.
- *
- * flags
- * The flags to set
- *
- * set
- * Whether to set or unset the specified flags
- */
-static void vrrp_debug_set_all(uint32_t flags, bool set)
-{
- for (unsigned int i = 0; i < array_size(vrrp_debugs); i++) {
- DEBUG_FLAGS_SET(vrrp_debugs[i], flags, set);
-
- /* if all modes have been turned off, don't preserve options */
- if (!DEBUG_MODE_CHECK(vrrp_debugs[i], DEBUG_MODE_ALL))
- DEBUG_CLEAR(vrrp_debugs[i]);
- }
-}
-
-static int vrrp_debug_config_write_helper(struct vty *vty, bool config)
-{
- uint32_t mode = DEBUG_MODE_ALL;
-
- if (config)
- mode = DEBUG_MODE_CONF;
-
- for (unsigned int i = 0; i < array_size(vrrp_debugs); i++)
- if (DEBUG_MODE_CHECK(vrrp_debugs[i], mode))
- vty_out(vty, "%s\n", vrrp_debugs_conflines[i]);
-
- return 0;
-}
-
-int vrrp_config_write_debug(struct vty *vty)
-{
- return vrrp_debug_config_write_helper(vty, true);
-}
-
-int vrrp_debug_status_write(struct vty *vty)
-{
- return vrrp_debug_config_write_helper(vty, false);
-}
-
void vrrp_debug_set(struct interface *ifp, uint8_t vrid, int vtynode,
bool onoff, bool proto, bool autoconf, bool pkt, bool sock,
bool ndisc, bool arp, bool zebra)
@@ -110,9 +46,13 @@ void vrrp_debug_set(struct interface *ifp, uint8_t vrid, int vtynode,
/* ------------------------------------------------------------------------- */
-struct debug_callbacks vrrp_dbg_cbs = {.debug_set_all = vrrp_debug_set_all};
-
void vrrp_debug_init(void)
{
- debug_init(&vrrp_dbg_cbs);
+ debug_install(&vrrp_dbg_arp);
+ debug_install(&vrrp_dbg_auto);
+ debug_install(&vrrp_dbg_ndisc);
+ debug_install(&vrrp_dbg_pkt);
+ debug_install(&vrrp_dbg_proto);
+ debug_install(&vrrp_dbg_sock);
+ debug_install(&vrrp_dbg_zebra);
}
diff --git a/vrrpd/vrrp_debug.h b/vrrpd/vrrp_debug.h
index c1421ebbaa..c8b4c897f0 100644
--- a/vrrpd/vrrp_debug.h
+++ b/vrrpd/vrrp_debug.h
@@ -28,14 +28,6 @@ extern struct debug vrrp_dbg_zebra;
void vrrp_debug_init(void);
/*
- * Print VRRP debugging configuration.
- *
- * vty
- * VTY to print debugging configuration to.
- */
-int vrrp_config_write_debug(struct vty *vty);
-
-/*
* Print VRRP debugging configuration, human readable form.
*
* vty
diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c
index 36494c7df8..a2fb2bc321 100644
--- a/vrrpd/vrrp_packet.c
+++ b/vrrpd/vrrp_packet.c
@@ -234,7 +234,7 @@ ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph,
} else if (family == AF_INET6) {
struct cmsghdr *c;
- for (c = CMSG_FIRSTHDR(m); c != NULL; CMSG_NXTHDR(m, c)) {
+ for (c = CMSG_FIRSTHDR(m); c != NULL; c = CMSG_NXTHDR(m, c)) {
if (c->cmsg_level == IPPROTO_IPV6
&& c->cmsg_type == IPV6_HOPLIMIT)
break;
diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c
index fd6cbc8b67..59794d9297 100644
--- a/vrrpd/vrrp_vty.c
+++ b/vrrpd/vrrp_vty.c
@@ -590,7 +590,7 @@ static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr)
char *table = ttable_dump(tt, "\n");
vty_out(vty, "\n%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
}
@@ -695,7 +695,7 @@ DEFPY_YANG(vrrp_vrid_show_summary,
char *table = ttable_dump(tt, "\n");
vty_out(vty, "\n%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
ttable_del(tt);
list_delete(&ll);
@@ -738,8 +738,6 @@ DEFUN_NOSH (show_debugging_vrrp,
{
vty_out(vty, "VRRP debugging status:\n");
- vrrp_debug_status_write(vty);
-
cmd_show_lib_debugs(vty);
return CMD_SUCCESS;
@@ -747,13 +745,6 @@ DEFUN_NOSH (show_debugging_vrrp,
/* clang-format on */
-static struct cmd_node debug_node = {
- .name = "debug",
- .node = DEBUG_NODE,
- .prompt = "",
- .config_write = vrrp_config_write_debug,
-};
-
static struct cmd_node vrrp_node = {
.name = "vrrp",
.node = VRRP_NODE,
@@ -763,7 +754,6 @@ static struct cmd_node vrrp_node = {
void vrrp_vty_init(void)
{
- install_node(&debug_node);
install_node(&vrrp_node);
vrf_cmd_init(NULL);
if_cmd_init_default();
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index c43e1909e3..2d80feef6c 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -4639,6 +4639,7 @@ static int vtysh_connect(struct vtysh_client *vclient)
struct sockaddr_un addr;
struct stat s_stat;
const char *path;
+ uint32_t rcvbufsize = VTYSH_RCV_BUF_MAX;
if (!vclient->path[0])
snprintf(vclient->path, sizeof(vclient->path), "%s/%s.vty",
@@ -4688,6 +4689,22 @@ static int vtysh_connect(struct vtysh_client *vclient)
close(sock);
return -1;
}
+
+ /*
+ * Increasing the RECEIVE socket buffer size so that the socket can hold
+ * after receving from other process.
+ */
+ ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbufsize,
+ sizeof(rcvbufsize));
+ if (ret < 0) {
+#ifdef DEBUG
+ fprintf(stderr, "Cannot set socket %d rcv buffer size, %s\n",
+ sock, safe_strerror(errno));
+#endif /* DEBUG */
+ close(sock);
+ return -1;
+ }
+
vclient->fd = sock;
return 0;
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index b1d57aa3c2..3c532b99a8 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -36,6 +36,8 @@ extern struct event_loop *master;
#define VTYSH_PIM6D 0x100000
#define VTYSH_MGMTD 0x200000
+#define VTYSH_RCV_BUF_MAX 16777216
+
#define VTYSH_WAS_ACTIVE (-2)
/* commands in REALLYALL are crucial to correct vtysh operation */
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 8f7cd84818..6536e1b376 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -453,10 +453,6 @@ void vtysh_config_parse_line(void *arg, const char *line)
config = config_get(FORWARDING_NODE, line);
else if (strncmp(line, "debug vrf", strlen("debug vrf")) == 0)
config = config_get(VRF_DEBUG_NODE, line);
- else if (strncmp(line, "debug northbound",
- strlen("debug northbound"))
- == 0)
- config = config_get(NORTHBOUND_DEBUG_NODE, line);
else if (strncmp(line, "debug route-map",
strlen("debug route-map"))
== 0)
@@ -464,12 +460,6 @@ void vtysh_config_parse_line(void *arg, const char *line)
else if (strncmp(line, "debug resolver",
strlen("debug resolver")) == 0)
config = config_get(RESOLVER_DEBUG_NODE, line);
- else if (strncmp(line, "debug mgmt client frontend",
- strlen("debug mgmt client frontend")) == 0)
- config = config_get(MGMT_FE_DEBUG_NODE, line);
- else if (strncmp(line, "debug mgmt client backend",
- strlen("debug mgmt client backend")) == 0)
- config = config_get(MGMT_BE_DEBUG_NODE, line);
else if (strncmp(line, "debug", strlen("debug")) == 0)
config = config_get(DEBUG_NODE, line);
else if (strncmp(line, "password", strlen("password")) == 0
@@ -537,9 +527,8 @@ void vtysh_config_parse_line(void *arg, const char *line)
(I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE || \
(I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE || \
(I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE || \
- (I) == NORTHBOUND_DEBUG_NODE || (I) == RMAP_DEBUG_NODE || \
- (I) == RESOLVER_DEBUG_NODE || (I) == MPLS_NODE || \
- (I) == KEYCHAIN_KEY_NODE)
+ (I) == RMAP_DEBUG_NODE || (I) == RESOLVER_DEBUG_NODE || \
+ (I) == MPLS_NODE || (I) == KEYCHAIN_KEY_NODE)
static void configvec_dump(vector vec, bool nested)
{
diff --git a/yang/frr-bgp-common.yang b/yang/frr-bgp-common.yang
index 2b1babdd28..9d21597304 100644
--- a/yang/frr-bgp-common.yang
+++ b/yang/frr-bgp-common.yang
@@ -320,6 +320,19 @@ submodule frr-bgp-common {
When set to 'false' BGP instance type is regular.";
}
+ leaf as-notation {
+ type enumeration {
+ enum "plain" { value 0; }
+ enum "dot" { value 1; }
+ enum "dot+" { value 2; }
+ }
+ description
+ "The as-notation type:
+ - plain: use plain format for all AS values
+ - dot: use 'AA.BB' format for AS 4 byte values.
+ - dot+: use 'AA.BB' format for all AS values.";
+ }
+
leaf ebgp-multihop-connected-route-check {
type boolean;
default "false";
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index abfb14c23c..44058ab04e 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -847,7 +847,7 @@ identity set-extcommunity-color {
}
case extcommunity-nt {
- when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-nt')";
+ when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-nt')";
description
"Value of the ext-community";
leaf extcommunity-nt {
@@ -1008,7 +1008,7 @@ identity set-extcommunity-color {
}
case aigp-metric {
- when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:aigp-metric')";
+ when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:aigp-metric')";
leaf aigp-metric {
type string;
description
@@ -1127,16 +1127,14 @@ identity set-extcommunity-color {
case comm-list-name {
when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:comm-list-delete') or "
+ "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:large-comm-list-delete') or "
- + "derived-from-or-self(../frr-route-map:action,
-'frr-bgp-route-map:extended-comm-list-delete')";
+ + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:extended-comm-list-delete')";
leaf comm-list-name {
type bgp-filter:bgp-list-name;
}
}
case evpn-gateway-ip-ipv4 {
when
- "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action,
- 'frr-bgp-route-map:set-evpn-gateway-ip-ipv4')";
+ "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-evpn-gateway-ip-ipv4')";
description
"Set EVPN gateway IP overlay index IPv4";
leaf evpn-gateway-ip-ipv4 {
@@ -1145,8 +1143,7 @@ identity set-extcommunity-color {
}
case evpn-gateway-ip-ipv6 {
when
- "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action,
- 'frr-bgp-route-map:set-evpn-gateway-ip-ipv6')";
+ "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-evpn-gateway-ip-ipv6')";
description
"Set EVPN gateway IP overlay index IPv6";
leaf evpn-gateway-ip-ipv6 {
@@ -1155,8 +1152,7 @@ identity set-extcommunity-color {
}
case l3vpn-nexthop-encapsulation {
when
- "derived-from-or-self(../frr-route-map:action,
- 'frr-bgp-route-map:set-l3vpn-nexthop-encapsulation')";
+ "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-l3vpn-nexthop-encapsulation')";
description
"Accept L3VPN traffic over other than LSP encapsulation";
leaf l3vpn-nexthop-encapsulation {
diff --git a/yang/frr-gmp.yang b/yang/frr-gmp.yang
index c8a05a2bdb..5636010d91 100644
--- a/yang/frr-gmp.yang
+++ b/yang/frr-gmp.yang
@@ -146,11 +146,18 @@ module frr-gmp {
"Querier's Robustness Variable allows tuning for the
expected packet loss on a network.";
}
+
+ leaf proxy {
+ type boolean;
+ default "false";
+ description
+ "Enable IGMP proxy on the interface.";
+ }
- list static-group {
+ list join-group {
key "group-addr source-addr";
description
- "A static multicast route, (*,G) or (S,G).
+ "A static GMP join, (*,G) or (S,G).
The version of IGMP must be 3 to support (S,G).";
leaf group-addr {
@@ -164,6 +171,23 @@ module frr-gmp {
"Multicast source address.";
}
}
+
+ list static-group {
+ key "group-addr source-addr";
+ description
+ "A static multicast group without GMP, (*,G) or (S,G).";
+
+ leaf group-addr {
+ type rt-types:ip-multicast-group-address;
+ description
+ "Multicast group address.";
+ }
+ leaf source-addr {
+ type inet:ip-address;
+ description
+ "Multicast source address.";
+ }
+ }
} // interface-config-attributes
/*
diff --git a/yang/frr-pim-candidate.yang b/yang/frr-pim-candidate.yang
new file mode 100644
index 0000000000..09d0a06353
--- /dev/null
+++ b/yang/frr-pim-candidate.yang
@@ -0,0 +1,174 @@
+module frr-pim-candidate {
+ yang-version "1.1";
+ namespace "http://frrouting.org/yang/pim-candidate";
+
+ prefix frr-pim-candidate;
+
+ import frr-interface {
+ prefix frr-interface;
+ }
+
+ import ietf-inet-types {
+ prefix "inet";
+ }
+
+ import frr-routing {
+ prefix "frr-rt";
+ }
+
+ import frr-pim {
+ prefix "frr-pim";
+ }
+
+ import frr-route-types {
+ prefix frr-route-types;
+ }
+
+ organization
+ "FRRouting";
+
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org>
+ FRR Development List: <mailto:dev@lists.frrouting.org>";
+
+ description
+ "The module defines a collection of YANG definitions common for
+ all PIM (Protocol Independent Multicast) Candidate RP & BSR
+ (Rendezvous Point & Bootstrap Router) operation.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2021-05-04 {
+ description
+ "Initial revision.";
+ reference
+ "TBD";
+ }
+
+ /*
+ * Groupings
+ */
+ grouping candidate-bsr-container {
+ description
+ "Grouping of Candidate BSR settings.";
+
+ container candidate-bsr {
+ presence
+ "Enable router to be a Candidate BSR.";
+
+ description
+ "Candidate BSR settings";
+
+ leaf bsr-priority {
+ type uint8;
+ default "64";
+ description
+ "BSR priority for this router, higher values win.";
+ }
+
+ choice source-address-or-interface {
+ description "IP address to use for BSR operation";
+ default if-loopback;
+ leaf address {
+ type inet:ip-address;
+ }
+ leaf interface {
+ type frr-interface:interface-ref;
+ }
+ leaf if-loopback {
+ type empty;
+ }
+ leaf if-any {
+ type empty;
+ }
+ }
+ } // candidate-bsr
+ } // candidate-bsr-container
+
+ grouping candidate-rp-container {
+ description
+ "Grouping of Candidate RP settings.";
+
+ container candidate-rp {
+ presence
+ "Enable router to be a Candidate RP.";
+
+ description
+ "Candidate RP settings";
+
+ leaf rp-priority {
+ type uint8;
+ default "192";
+ description
+ "RP priority for this router, lower values win.";
+ }
+
+ leaf advertisement-interval {
+ type uint32 {
+ range 1..4294967295;
+ }
+ default "60";
+ description
+ "RP advertisement interval (seconds). Holdtime is 2.5 times this.";
+ }
+
+ leaf-list group-list {
+ type frr-route-types:ip-multicast-group-prefix;
+ description
+ "List of multicast group address.";
+ }
+
+ choice source-address-or-interface {
+ description "IP address to use for RP operation";
+ default if-loopback;
+ leaf address {
+ type inet:ip-address;
+ }
+ leaf interface {
+ type frr-interface:interface-ref;
+ }
+ leaf if-loopback {
+ type empty;
+ }
+ leaf if-any {
+ type empty;
+ }
+ }
+ }
+ }
+
+ /*
+ * Configuration data nodes
+ */
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/"
+ + "frr-rt:control-plane-protocol/frr-pim:pim/"
+ + "frr-pim:address-family" {
+ description "PIM Candidate RP augmentation.";
+
+ uses candidate-bsr-container;
+ uses candidate-rp-container;
+ }
+}
diff --git a/yang/frr-pim-rp.yang b/yang/frr-pim-rp.yang
index 4cc214135d..dbd5513ee5 100644
--- a/yang/frr-pim-rp.yang
+++ b/yang/frr-pim-rp.yang
@@ -111,6 +111,70 @@ module frr-pim-rp {
} // static-rp
} // static-rp-container
+ grouping auto-rp-container {
+ description
+ "Grouping of AutoRP container.";
+
+ container auto-rp {
+ description
+ "Containing AutoRP attributes.";
+
+ leaf discovery-enabled {
+ type boolean;
+ description
+ "Flag indicating if Auto RP discovery is enabled.";
+ }
+
+ leaf announce-scope {
+ type uint8;
+ description
+ "The TTL of the C-RP Announcement packet.";
+ }
+
+ leaf announce-interval {
+ type uint16;
+ description
+ "The time between sending C-RP announcement packets.";
+ }
+
+ leaf announce-holdtime {
+ type uint16;
+ description
+ "The hold time in seconds advertised in the announcement packet.";
+ }
+
+ list candidate-rp-list {
+ key "rp-address";
+ description
+ "A list of Candidate RP addresses.";
+
+ leaf rp-address {
+ type inet:ip-address;
+ description
+ "Specifies a candidate RP address.";
+ }
+
+ choice group-or-prefix-list {
+ description "Use group or prefix-list";
+ case group {
+ leaf group {
+ type frr-route-types:ip-multicast-group-prefix;
+ description
+ "Multicast group prefix.";
+ }
+ }
+ case prefix-list {
+ leaf prefix-list {
+ type plist-ref;
+ description
+ "Group prefix-list filter";
+ }
+ }
+ }
+ } // candidate-rp-list
+ } // auto-rp
+ } // auto-rp-container
+
/*
* Configuration data nodes
*/
@@ -123,6 +187,13 @@ module frr-pim-rp {
description
"PIM RP configuration data.";
uses static-rp-container;
+
+ uses auto-rp-container {
+ when "../frr-pim:address-family = 'frr-rt:ipv4'" {
+ description
+ "Only applicable to IPv4 address family.";
+ }
+ }
} // rp
} // augment
}
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
index 1c7d1c8ef4..f97a4cc129 100644
--- a/yang/frr-zebra.yang
+++ b/yang/frr-zebra.yang
@@ -2856,6 +2856,16 @@ module frr-zebra {
}
}
+ container mpls {
+ description
+ "MPLS Configuration.";
+ leaf fec-nexthop-resolution {
+ type boolean;
+ description
+ "Authorise nexthop resolution over all labeled routes.";
+ }
+ }
+
uses ribs;
uses vrf-vni-mapping;
diff --git a/yang/ietf/ietf-bgp-types.yang b/yang/ietf/ietf-bgp-types.yang
index 9c7a6af76c..ed64b78ad6 100644
--- a/yang/ietf/ietf-bgp-types.yang
+++ b/yang/ietf/ietf-bgp-types.yang
@@ -333,7 +333,7 @@ module ietf-bgp-types {
// TODO: needs more work to make this more precise given the
// variability of extended community attribute specifications
// 8-octet value:
- // <type> 2 octects
+ // <type> 2 octets
// <value> 6 octets
type union {
diff --git a/yang/subdir.am b/yang/subdir.am
index 71aa040878..786bd0bca6 100644
--- a/yang/subdir.am
+++ b/yang/subdir.am
@@ -80,6 +80,7 @@ if PIMD
dist_yangmodels_DATA += yang/frr-gmp.yang
dist_yangmodels_DATA += yang/frr-pim.yang
dist_yangmodels_DATA += yang/frr-pim-rp.yang
+dist_yangmodels_DATA += yang/frr-pim-candidate.yang
endif
if BGPD
diff --git a/zebra/connected.c b/zebra/connected.c
index 404f892f6e..974a1c17a2 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -185,6 +185,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
.type = NEXTHOP_TYPE_IFINDEX,
.ifindex = ifp->ifindex,
.vrf_id = ifp->vrf->vrf_id,
+ .weight = 1,
};
struct zebra_vrf *zvrf;
uint32_t metric;
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 09080aa616..d594fc2c86 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -381,7 +381,7 @@ DEFPY(fpm_show_status,
out = ttable_dump(table, "\n");
vty_out(vty, "%s\n", out);
- XFREE(MTYPE_TMP, out);
+ XFREE(MTYPE_TMP_TTABLE, out);
ttable_del(table);
}
@@ -1336,7 +1336,7 @@ static void fpm_enqueue_l3vni_table(struct hash_bucket *bucket, void *arg)
struct zebra_l3vni *zl3vni = bucket->data;
fra->zl3vni = zl3vni;
- hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, zl3vni);
+ hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, fra);
}
static void fpm_rmac_send(struct event *t)
@@ -1678,6 +1678,25 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov)
fnc = dplane_provider_get_data(prov);
limit = dplane_provider_get_work_limit(prov);
+
+ frr_with_mutex (&fnc->ctxqueue_mutex) {
+ cur_queue = dplane_ctx_queue_count(&fnc->ctxqueue);
+ }
+
+ if (cur_queue >= (uint64_t)limit) {
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug("%s: Already at a limit(%" PRIu64
+ ") of internal work, hold off",
+ __func__, cur_queue);
+ limit = 0;
+ } else if (cur_queue != 0) {
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug("%s: current queue is %" PRIu64
+ ", limiting to lesser amount of %" PRIu64,
+ __func__, cur_queue, limit - cur_queue);
+ limit -= cur_queue;
+ }
+
for (counter = 0; counter < limit; counter++) {
ctx = dplane_provider_dequeue_in_ctx(prov);
if (ctx == NULL)
diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c
index d0aa2167fe..688a7f6e33 100644
--- a/zebra/if_ioctl.c
+++ b/zebra/if_ioctl.c
@@ -296,6 +296,8 @@ void interface_list(struct zebra_ns *zns)
/proc/net/if_inet6. */
ifaddr_proc_ipv6();
#endif /* HAVE_PROC_NET_IF_INET6 */
+
+ zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_INTERFACES_READ);
}
#endif /* OPEN_BSD */
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 3233519873..8beae125d2 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -1032,212 +1032,6 @@ netlink_put_intf_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
return netlink_batch_add_msg(bth, ctx, netlink_intf_msg_encoder, false);
}
-int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
-{
- int len;
- struct ifaddrmsg *ifa;
- struct rtattr *tb[IFA_MAX + 1];
- struct interface *ifp;
- void *addr;
- void *broad;
- uint8_t flags = 0;
- char *label = NULL;
- struct zebra_ns *zns;
- uint32_t metric = METRIC_MAX;
- uint32_t kernel_flags = 0;
-
- frrtrace(3, frr_zebra, netlink_interface_addr, h, ns_id, startup);
-
- zns = zebra_ns_lookup(ns_id);
- ifa = NLMSG_DATA(h);
-
- if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) {
- flog_warn(
- EC_ZEBRA_UNKNOWN_FAMILY,
- "Invalid address family: %u received from kernel interface addr change: %s",
- ifa->ifa_family, nl_msg_type_to_str(h->nlmsg_type));
- return 0;
- }
-
- if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
- return 0;
-
- len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
- if (len < 0) {
- zlog_err(
- "%s: Message received from netlink is of a broken size: %d %zu",
- __func__, h->nlmsg_len,
- (size_t)NLMSG_LENGTH(sizeof(struct ifaddrmsg)));
- return -1;
- }
-
- netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);
-
- ifp = if_lookup_by_index_per_ns(zns, ifa->ifa_index);
- if (ifp == NULL) {
- if (startup) {
- /* During startup, failure to lookup the referenced
- * interface should not be an error, so we have
- * downgraded this condition to warning, and we permit
- * the startup interface state retrieval to continue.
- */
- flog_warn(EC_LIB_INTERFACE,
- "%s: can't find interface by index %d",
- __func__, ifa->ifa_index);
- return 0;
- } else {
- flog_err(EC_LIB_INTERFACE,
- "%s: can't find interface by index %d",
- __func__, ifa->ifa_index);
- return -1;
- }
- }
-
- /* Flags passed through */
- if (tb[IFA_FLAGS])
- kernel_flags = *(int *)RTA_DATA(tb[IFA_FLAGS]);
- else
- kernel_flags = ifa->ifa_flags;
-
- if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
- {
- char buf[BUFSIZ];
- zlog_debug("%s %s %s flags 0x%x:", __func__,
- nl_msg_type_to_str(h->nlmsg_type), ifp->name,
- kernel_flags);
- if (tb[IFA_LOCAL])
- zlog_debug(" IFA_LOCAL %s/%d",
- inet_ntop(ifa->ifa_family,
- RTA_DATA(tb[IFA_LOCAL]), buf,
- BUFSIZ),
- ifa->ifa_prefixlen);
- if (tb[IFA_ADDRESS])
- zlog_debug(" IFA_ADDRESS %s/%d",
- inet_ntop(ifa->ifa_family,
- RTA_DATA(tb[IFA_ADDRESS]), buf,
- BUFSIZ),
- ifa->ifa_prefixlen);
- if (tb[IFA_BROADCAST])
- zlog_debug(" IFA_BROADCAST %s/%d",
- inet_ntop(ifa->ifa_family,
- RTA_DATA(tb[IFA_BROADCAST]), buf,
- BUFSIZ),
- ifa->ifa_prefixlen);
- if (tb[IFA_LABEL] && strcmp(ifp->name, RTA_DATA(tb[IFA_LABEL])))
- zlog_debug(" IFA_LABEL %s",
- (char *)RTA_DATA(tb[IFA_LABEL]));
-
- if (tb[IFA_CACHEINFO]) {
- struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]);
- zlog_debug(" IFA_CACHEINFO pref %d, valid %d",
- ci->ifa_prefered, ci->ifa_valid);
- }
- }
-
- /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
- if (tb[IFA_LOCAL] == NULL)
- tb[IFA_LOCAL] = tb[IFA_ADDRESS];
- if (tb[IFA_ADDRESS] == NULL)
- tb[IFA_ADDRESS] = tb[IFA_LOCAL];
-
- /* local interface address */
- addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
-
- /* is there a peer address? */
- if (tb[IFA_ADDRESS]
- && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]),
- RTA_PAYLOAD(tb[IFA_ADDRESS]))) {
- broad = RTA_DATA(tb[IFA_ADDRESS]);
- SET_FLAG(flags, ZEBRA_IFA_PEER);
- } else
- /* seeking a broadcast address */
- broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST])
- : NULL);
-
- /* addr is primary key, SOL if we don't have one */
- if (addr == NULL) {
- zlog_debug("%s: Local Interface Address is NULL for %s",
- __func__, ifp->name);
- return -1;
- }
-
- /* Flags. */
- if (kernel_flags & IFA_F_SECONDARY)
- SET_FLAG(flags, ZEBRA_IFA_SECONDARY);
-
- /* Label */
- if (tb[IFA_LABEL])
- label = (char *)RTA_DATA(tb[IFA_LABEL]);
-
- if (label && strcmp(ifp->name, label) == 0)
- label = NULL;
-
- if (tb[IFA_RT_PRIORITY])
- metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]);
-
- /* Register interface address to the interface. */
- if (ifa->ifa_family == AF_INET) {
- if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) {
- zlog_err(
- "Invalid prefix length: %u received from kernel interface addr change: %s",
- ifa->ifa_prefixlen,
- nl_msg_type_to_str(h->nlmsg_type));
- return -1;
- }
-
- if (h->nlmsg_type == RTM_NEWADDR)
- connected_add_ipv4(ifp, flags, (struct in_addr *)addr,
- ifa->ifa_prefixlen,
- (struct in_addr *)broad, label,
- metric);
- else if (CHECK_FLAG(flags, ZEBRA_IFA_PEER)) {
- /* Delete with a peer address */
- connected_delete_ipv4(
- ifp, flags, (struct in_addr *)addr,
- ifa->ifa_prefixlen, broad);
- } else
- connected_delete_ipv4(
- ifp, flags, (struct in_addr *)addr,
- ifa->ifa_prefixlen, NULL);
- }
-
- if (ifa->ifa_family == AF_INET6) {
- if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) {
- zlog_err(
- "Invalid prefix length: %u received from kernel interface addr change: %s",
- ifa->ifa_prefixlen,
- nl_msg_type_to_str(h->nlmsg_type));
- return -1;
- }
- if (h->nlmsg_type == RTM_NEWADDR) {
- /* Only consider valid addresses; we'll not get a
- * notification from
- * the kernel till IPv6 DAD has completed, but at init
- * time, Quagga
- * does query for and will receive all addresses.
- */
- if (!(kernel_flags
- & (IFA_F_DADFAILED | IFA_F_TENTATIVE)))
- connected_add_ipv6(ifp, flags,
- (struct in6_addr *)addr,
- (struct in6_addr *)broad,
- ifa->ifa_prefixlen, label,
- metric);
- } else
- connected_delete_ipv6(ifp, (struct in6_addr *)addr,
- NULL, ifa->ifa_prefixlen);
- }
-
- /*
- * Linux kernel does not send route delete on interface down/addr del
- * so we have to re-process routes it owns (i.e. kernel routes)
- */
- if (h->nlmsg_type != RTM_NEWADDR)
- rib_update(RIB_UPDATE_KERNEL);
-
- return 0;
-}
-
/*
* Parse and validate an incoming interface address change message,
* generating a dplane context object.
@@ -1799,14 +1593,18 @@ int netlink_tunneldump_read(struct zebra_ns *zns)
ret = netlink_request_tunneldump(zns, PF_BRIDGE,
tmp_if->ifindex);
- if (ret < 0)
+ if (ret < 0) {
+ route_unlock_node(rn);
return ret;
+ }
ret = netlink_parse_info(netlink_link_change, netlink_cmd,
&dp_info, 0, true);
- if (ret < 0)
+ if (ret < 0) {
+ route_unlock_node(rn);
return ret;
+ }
}
return 0;
diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h
index 9b31906a17..dc1f71cb77 100644
--- a/zebra/if_netlink.h
+++ b/zebra/if_netlink.h
@@ -12,9 +12,6 @@
extern "C" {
#endif
-extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id,
- int startup);
-
/*
* Parse an incoming interface address change message, generate a dplane
* context object for processing.
diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c
index 9db959896e..28cbb0415a 100644
--- a/zebra/if_sysctl.c
+++ b/zebra/if_sysctl.c
@@ -128,6 +128,8 @@ void interface_list(struct zebra_ns *zns)
/* Free sysctl buffer. */
XFREE(MTYPE_TMP, ref);
+
+ zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_INTERFACES_READ);
}
#endif /* !defined(GNU_LINUX) && !defined(OPEN_BSD) */
diff --git a/zebra/interface.c b/zebra/interface.c
index 03b710e1a0..d146004781 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1058,6 +1058,8 @@ void if_down(struct interface *ifp)
/* Delete all neighbor addresses learnt through IPv6 RA */
if_down_del_nbr_connected(ifp);
+
+ rib_update_handle_vrf_all(RIB_UPDATE_INTERFACE_DOWN, ZEBRA_ROUTE_KERNEL);
}
void if_refresh(struct interface *ifp)
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index d2f1db67ee..84aabc4254 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -672,21 +672,6 @@ void netlink_parse_rtattr_nested(struct rtattr **tb, int max,
netlink_parse_rtattr(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta));
}
-bool nl_addraw_l(struct nlmsghdr *n, unsigned int maxlen, const void *data,
- unsigned int len)
-{
- if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
- zlog_err("ERROR message exceeded bound of %d", maxlen);
- return false;
- }
-
- memcpy(NLMSG_TAIL(n), data, len);
- memset((uint8_t *)NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
- n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
-
- return true;
-}
-
bool nl_attr_put(struct nlmsghdr *n, unsigned int maxlen, int type,
const void *data, unsigned int alen)
{
diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h
index e37bba0cf6..9db4e5789a 100644
--- a/zebra/kernel_netlink.h
+++ b/zebra/kernel_netlink.h
@@ -77,14 +77,6 @@ extern void netlink_parse_rtattr_flags(struct rtattr **tb, int max,
unsigned short flags);
extern void netlink_parse_rtattr_nested(struct rtattr **tb, int max,
struct rtattr *rta);
-/*
- * nl_addraw_l copies raw form the netlink message buffer into netlink
- * message header pointer. It ensures the aligned data buffer does not
- * override past max length.
- * return value is 0 if its successful
- */
-extern bool nl_addraw_l(struct nlmsghdr *n, unsigned int maxlen,
- const void *data, unsigned int len);
extern const char *nl_msg_type_to_str(uint16_t msg_type);
extern const char *nl_rtproto_to_str(uint8_t rtproto);
extern const char *nl_family_to_str(uint8_t family);
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index d50e7de229..5cfbe7a896 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -1468,10 +1468,12 @@ static void routing_socket(struct zebra_ns *zns)
void interface_list_second(struct zebra_ns *zns)
{
+ zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_ADDRESSES_READ);
}
void interface_list_tunneldump(struct zebra_ns *zns)
{
+ zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_TUNNELS_READ);
}
/* Exported interface function. This function simply calls
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 11c1330398..2de0917a7e 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -290,6 +290,7 @@ void redistribute_delete(const struct route_node *rn,
if (IS_ZEBRA_DEBUG_RIB) {
uint8_t old_inst, new_inst;
uint32_t table = 0;
+ struct vrf *vrf = vrf_lookup_by_id(vrfid);
old_inst = new_inst = 0;
@@ -302,8 +303,8 @@ void redistribute_delete(const struct route_node *rn,
table = new_re->table;
}
- zlog_debug("(%u:%u):%pRN: Redist del: re %p (%u:%s), new re %p (%u:%s)",
- vrfid, table, rn, old_re, old_inst,
+ zlog_debug("(%s:%u):%pRN: Redist del: re %p (%u:%s), new re %p (%u:%s)",
+ VRF_LOGNAME(vrf), table, rn, old_re, old_inst,
old_re ? zebra_route_string(old_re->type) : "None",
new_re, new_inst,
new_re ? zebra_route_string(new_re->type) : "None");
diff --git a/zebra/rib.h b/zebra/rib.h
index 84ea766c47..5fedb07335 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -108,8 +108,8 @@ struct route_entry {
uint32_t nexthop_mtu;
/* Flags of this route.
- * This flag's definition is in lib/zebra.h ZEBRA_FLAG_* and is exposed
- * to clients via Zserv
+ * This flag's definition is in lib/zclient.h ZEBRA_FLAG_* and is
+ * exposed to clients via Zserv
*/
uint32_t flags;
@@ -326,6 +326,7 @@ typedef struct rib_tables_iter_t_ {
/* Events/reasons triggering a RIB update. */
enum rib_update_event {
+ RIB_UPDATE_INTERFACE_DOWN,
RIB_UPDATE_KERNEL,
RIB_UPDATE_RMAP_CHANGE,
RIB_UPDATE_OTHER,
@@ -395,7 +396,7 @@ extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
extern 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 prefix *p, const 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);
@@ -407,9 +408,6 @@ extern struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id,
union g_addr *gaddr,
struct route_node **rn_out);
-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_table(struct route_table *table,
enum rib_update_event event, int rtype);
@@ -477,6 +475,8 @@ extern uint8_t route_distance(int type);
extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq,
bool rt_delete);
+extern void rib_update_handle_vrf_all(enum rib_update_event event, int rtype);
+
/*
* rib_find_rn_from_ctx
*
@@ -628,11 +628,16 @@ extern int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto,
uint8_t instance, time_t restart_time);
extern void zebra_vty_init(void);
+extern uint32_t zebra_rib_dplane_results_count(void);
extern pid_t pid;
extern uint32_t rt_table_main_id;
+void route_entry_dump_nh(const struct route_entry *re, const char *straddr,
+ const struct vrf *re_vrf,
+ const struct nexthop *nexthop);
+
/* Name of hook calls */
#define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results"
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 768090badb..75e4396e92 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -506,7 +506,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb,
void *gate, afi_t afi, vrf_id_t vrf_id)
{
struct interface *ifp = NULL;
- struct nexthop nh = {0};
+ struct nexthop nh = {.weight = 1};
mpls_label_t labels[MPLS_MAX_LABELS] = {0};
int num_labels = 0;
enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
@@ -799,8 +799,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
return 0;
if (rtm->rtm_protocol == RTPROT_REDIRECT)
return 0;
- if (rtm->rtm_protocol == RTPROT_KERNEL)
- return 0;
selfroute = is_selfroute(rtm->rtm_protocol);
@@ -1690,7 +1688,7 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
return false;
if (!nl_attr_put(nlmsg, req_size,
SEG6_LOCAL_NH6, &ctx->nh6,
- sizeof(struct in_addr)))
+ sizeof(struct in6_addr)))
return false;
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
@@ -2981,7 +2979,7 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
if (!nl_attr_put(&req->n, buflen,
SEG6_LOCAL_NH6,
&ctx->nh6,
- sizeof(struct in_addr)))
+ sizeof(struct in6_addr)))
return 0;
break;
case SEG6_LOCAL_ACTION_END_DT6:
@@ -3210,7 +3208,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
struct interface **ifp,
ns_id_t ns_id)
{
- struct nexthop nh = {};
+ struct nexthop nh = {.weight = 1};
void *gate = NULL;
enum nexthop_types_t type = 0;
int if_index = 0;
@@ -3357,7 +3355,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
vrf_id_t vrf_id = VRF_DEFAULT;
struct interface *ifp = NULL;
struct nhmsg *nhm = NULL;
- struct nexthop nh = {};
+ struct nexthop nh = {.weight = 1};
struct nh_grp grp[MULTIPATH_NUM] = {};
/* Count of nexthops in group array */
uint8_t grp_count = 0;
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 470391de9b..8f6713517d 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -1960,7 +1960,7 @@ uint32_t rtadv_get_interfaces_configured_from_bgp(void)
void rtadv_init(void)
{
if (CMSG_SPACE(sizeof(struct in6_pktinfo)) > RTADV_ADATA_SIZE) {
- zlog_debug("%s: RTADV_ADATA_SIZE choosen will not work on this platform, please use a larger size",
+ zlog_debug("%s: RTADV_ADATA_SIZE chosen will not work on this platform, please use a larger size",
__func__);
exit(-1);
diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c
index 19667e66ac..3c4db0090c 100644
--- a/zebra/tc_netlink.c
+++ b/zebra/tc_netlink.c
@@ -661,27 +661,6 @@ netlink_put_tc_filter_update_msg(struct nl_batch *bth,
}
/*
- * Request filters from the kernel
- */
-static int netlink_request_filters(struct zebra_ns *zns, int family, int type,
- ifindex_t ifindex)
-{
- struct {
- struct nlmsghdr n;
- struct tcmsg tc;
- } req;
-
- memset(&req, 0, sizeof(req));
- req.n.nlmsg_type = type;
- req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
- req.tc.tcm_family = family;
- req.tc.tcm_ifindex = ifindex;
-
- return netlink_request(&zns->netlink_cmd, &req);
-}
-
-/*
* Request queue discipline from the kernel
*/
static int netlink_request_qdiscs(struct zebra_ns *zns, int family, int type)
@@ -852,23 +831,4 @@ int netlink_qdisc_read(struct zebra_ns *zns)
return 0;
}
-int netlink_tfilter_read_for_interface(struct zebra_ns *zns, ifindex_t ifindex)
-{
- int ret;
- struct zebra_dplane_info dp_info;
-
- zebra_dplane_info_from_zns(&dp_info, zns, true);
-
- ret = netlink_request_filters(zns, AF_UNSPEC, RTM_GETTFILTER, ifindex);
- if (ret < 0)
- return ret;
-
- ret = netlink_parse_info(netlink_tfilter_change, &zns->netlink_cmd,
- &dp_info, 0, true);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
#endif /* HAVE_NETLINK */
diff --git a/zebra/tc_netlink.h b/zebra/tc_netlink.h
index 5e95e6c1d8..300c53b6f5 100644
--- a/zebra/tc_netlink.h
+++ b/zebra/tc_netlink.h
@@ -50,8 +50,6 @@ netlink_put_tc_filter_update_msg(struct nl_batch *bth,
*/
extern int netlink_qdisc_read(struct zebra_ns *zns);
-extern int netlink_tfilter_read_for_interface(struct zebra_ns *zns,
- ifindex_t ifindex);
extern int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id,
int startup);
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index aecbba2ebc..b13d58f99d 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -735,11 +735,13 @@ static int route_notify_internal(const struct route_node *rn, int type,
client = zserv_find_client(type, instance);
if (!client || !client->notify_owner) {
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug(
- "Not Notifying Owner: %s about prefix %pRN(%u) %d vrf: %u",
- zebra_route_string(type), rn, table_id, note,
- vrf_id);
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+
+ zlog_debug("Not Notifying Owner: %s about prefix %pRN(%u) %d vrf: %s",
+ zebra_route_string(type), rn, table_id, note,
+ VRF_LOGNAME(vrf));
+ }
return 0;
}
@@ -2129,8 +2131,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
vrf_id = zvrf_id(zvrf);
if (IS_ZEBRA_DEBUG_RECV)
- zlog_debug("%s: p=(%u:%u)%pFX, msg flags=0x%x, flags=0x%x",
- __func__, vrf_id, api.tableid, &api.prefix,
+ zlog_debug("%s: p=(%s:%u)%pFX, msg flags=0x%x, flags=0x%x",
+ __func__, zvrf_name(zvrf), api.tableid, &api.prefix,
(int)api.message, api.flags);
/* Allocate new route. */
@@ -2475,22 +2477,6 @@ stream_failure:
return;
}
-/* Unregister all information in a VRF. */
-static void zread_vrf_unregister(ZAPI_HANDLER_ARGS)
-{
- int i;
- afi_t afi;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
- vrf_bitmap_unset(&client->redist[afi][i],
- zvrf_id(zvrf));
- vrf_bitmap_unset(&client->redist_default[afi], zvrf_id(zvrf));
- vrf_bitmap_unset(&client->ridinfo[afi], zvrf_id(zvrf));
- vrf_bitmap_unset(&client->neighinfo[afi], zvrf_id(zvrf));
- }
-}
-
/*
* Validate incoming zapi mpls lsp / labels message
*/
@@ -4053,7 +4039,6 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
#if HAVE_BFDD > 0
[ZEBRA_BFD_DEST_REPLAY] = zebra_ptm_bfd_dst_replay,
#endif /* HAVE_BFDD */
- [ZEBRA_VRF_UNREGISTER] = zread_vrf_unregister,
[ZEBRA_VRF_LABEL] = zread_vrf_label,
[ZEBRA_BFD_CLIENT_REGISTER] = zebra_ptm_bfd_client_register,
[ZEBRA_INTERFACE_ENABLE_RADV] = zebra_interface_radv_enable,
diff --git a/zebra/zebra_cli.c b/zebra/zebra_cli.c
index 3e03d74775..6ee0fdbb8d 100644
--- a/zebra/zebra_cli.c
+++ b/zebra/zebra_cli.c
@@ -2221,6 +2221,37 @@ static void lib_vrf_zebra_ipv6_resolve_via_default_cli_write(
}
}
+DEFPY_YANG (mpls_fec_nexthop_resolution, mpls_fec_nexthop_resolution_cmd,
+ "[no$no] mpls fec nexthop-resolution",
+ NO_STR
+ MPLS_STR
+ "MPLS FEC table\n"
+ "Authorise nexthop resolution over all labeled routes.\n")
+{
+ nb_cli_enqueue_change(vty,
+ "./frr-zebra:zebra/mpls/fec-nexthop-resolution",
+ NB_OP_MODIFY, no ? "false" : "true");
+
+ if (vty->node == CONFIG_NODE)
+ return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']",
+ VRF_DEFAULT_NAME);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+static void lib_vrf_mpls_fec_nexthop_resolution_cli_write(
+ struct vty *vty, const struct lyd_node *dnode, bool show_defaults)
+{
+ bool fec_nexthop_resolution = yang_dnode_get_bool(dnode, NULL);
+
+ if (fec_nexthop_resolution || show_defaults) {
+ zebra_vrf_indent_cli_write(vty, dnode);
+
+ vty_out(vty, "%smpls fec nexthop-resolution\n",
+ fec_nexthop_resolution ? "" : "no ");
+ }
+}
+
DEFPY_YANG (vrf_netns,
vrf_netns_cmd,
"[no] netns ![NAME$netns_name]",
@@ -2852,6 +2883,10 @@ const struct frr_yang_module_info frr_zebra_cli_info = {
.cbs.cli_show = lib_vrf_zebra_netns_table_range_cli_write,
},
{
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/mpls/fec-nexthop-resolution",
+ .cbs.cli_show = lib_vrf_mpls_fec_nexthop_resolution_cli_write,
+ },
+ {
.xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id",
.cbs.cli_show = lib_vrf_zebra_l3vni_id_cli_write,
},
@@ -2957,6 +2992,9 @@ void zebra_cli_init(void)
install_element(VRF_NODE, &ip_nht_default_route_cmd);
install_element(VRF_NODE, &ipv6_nht_default_route_cmd);
+ install_element(CONFIG_NODE, &mpls_fec_nexthop_resolution_cmd);
+ install_element(VRF_NODE, &mpls_fec_nexthop_resolution_cmd);
+
install_element(CONFIG_NODE, &vni_mapping_cmd);
install_element(VRF_NODE, &vni_mapping_cmd);
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 1cee1ebb93..75147e7136 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -483,10 +483,8 @@ struct zebra_dplane_provider {
int (*dp_fini)(struct zebra_dplane_provider *prov, bool early_p);
_Atomic uint32_t dp_in_counter;
- _Atomic uint32_t dp_in_queued;
_Atomic uint32_t dp_in_max;
_Atomic uint32_t dp_out_counter;
- _Atomic uint32_t dp_out_queued;
_Atomic uint32_t dp_out_max;
_Atomic uint32_t dp_error_counter;
@@ -4503,8 +4501,21 @@ dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op)
ctx = dplane_ctx_alloc();
ret = dplane_ctx_nexthop_init(ctx, op, nhe);
- if (ret == AOK)
+ if (ret == AOK) {
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL)) {
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL);
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+
+ dplane_ctx_free(&ctx);
+ atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in,
+ 1, memory_order_relaxed);
+
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+ }
+
ret = dplane_update_enqueue(ctx);
+ }
/* Update counter */
atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, 1,
@@ -6116,35 +6127,45 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed)
struct zebra_dplane_provider *prov;
uint64_t in, in_q, in_max, out, out_q, out_max;
- vty_out(vty, "Zebra dataplane providers:\n");
-
DPLANE_LOCK();
prov = dplane_prov_list_first(&zdplane_info.dg_providers);
+ in = dplane_ctx_queue_count(&zdplane_info.dg_update_list);
DPLANE_UNLOCK();
+ vty_out(vty, "dataplane Incoming Queue from Zebra: %" PRIu64 "\n", in);
+ vty_out(vty, "Zebra dataplane providers:\n");
+
/* Show counters, useful info from each registered provider */
while (prov) {
+ dplane_provider_lock(prov);
+ in_q = dplane_ctx_queue_count(&prov->dp_ctx_in_list);
+ out_q = dplane_ctx_queue_count(&prov->dp_ctx_out_list);
+ dplane_provider_unlock(prov);
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: %"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);
+ 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);
prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
}
+ out = zebra_rib_dplane_results_count();
+ vty_out(vty, "dataplane Outgoing Queue to Zebra: %" PRIu64 "\n", out);
+
return CMD_SUCCESS;
}
@@ -6286,10 +6307,6 @@ struct zebra_dplane_ctx *dplane_provider_dequeue_in_ctx(
dplane_provider_lock(prov);
ctx = dplane_ctx_list_pop(&(prov->dp_ctx_in_list));
- if (ctx) {
- atomic_fetch_sub_explicit(&prov->dp_in_queued, 1,
- memory_order_relaxed);
- }
dplane_provider_unlock(prov);
@@ -6317,10 +6334,6 @@ int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov,
break;
}
- if (ret > 0)
- atomic_fetch_sub_explicit(&prov->dp_in_queued, ret,
- memory_order_relaxed);
-
dplane_provider_unlock(prov);
return ret;
@@ -6345,10 +6358,7 @@ void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
dplane_ctx_list_add_tail(&(prov->dp_ctx_out_list), ctx);
/* 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);
+ curr = dplane_ctx_queue_count(&prov->dp_ctx_out_list);
high = atomic_load_explicit(&prov->dp_out_max,
memory_order_relaxed);
if (curr > high)
@@ -6370,9 +6380,6 @@ dplane_provider_dequeue_out_ctx(struct zebra_dplane_provider *prov)
if (!ctx)
return NULL;
- atomic_fetch_sub_explicit(&(prov->dp_out_queued), 1,
- memory_order_relaxed);
-
return ctx;
}
@@ -7318,10 +7325,10 @@ static void dplane_thread_loop(struct event *event)
{
struct dplane_ctx_list_head work_list;
struct dplane_ctx_list_head error_list;
- struct zebra_dplane_provider *prov;
+ struct zebra_dplane_provider *prov, *next_prov;
struct zebra_dplane_ctx *ctx;
int limit, counter, error_counter;
- uint64_t curr, high;
+ uint64_t curr, out_curr, high;
bool reschedule = false;
/* Capture work limit per cycle */
@@ -7345,18 +7352,48 @@ static void dplane_thread_loop(struct event *event)
/* Locate initial registered provider */
prov = dplane_prov_list_first(&zdplane_info.dg_providers);
- /* Move new work from incoming list to temp list */
- for (counter = 0; counter < limit; counter++) {
- ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list);
- if (ctx) {
- ctx->zd_provider = prov->dp_id;
+ curr = dplane_ctx_queue_count(&prov->dp_ctx_in_list);
+ out_curr = dplane_ctx_queue_count(&prov->dp_ctx_out_list);
- dplane_ctx_list_add_tail(&work_list, ctx);
- } else {
- break;
+ if (curr >= (uint64_t)limit) {
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("%s: Current first provider(%s) Input queue is %" PRIu64
+ ", holding off work",
+ __func__, prov->dp_name, curr);
+ counter = 0;
+ } else if (out_curr >= (uint64_t)limit) {
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("%s: Current first provider(%s) Output queue is %" PRIu64
+ ", holding off work",
+ __func__, prov->dp_name, out_curr);
+ counter = 0;
+ } else {
+ int tlimit;
+ /*
+ * Let's limit the work to how what can be put on the
+ * in or out queue without going over
+ */
+ tlimit = limit - MAX(curr, out_curr);
+ /* Move new work from incoming list to temp list */
+ for (counter = 0; counter < tlimit; counter++) {
+ ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list);
+ if (ctx) {
+ ctx->zd_provider = prov->dp_id;
+
+ dplane_ctx_list_add_tail(&work_list, ctx);
+ } else {
+ break;
+ }
}
}
+ /*
+ * If there is anything still on the two input queues reschedule
+ */
+ if (dplane_ctx_queue_count(&prov->dp_ctx_in_list) > 0 ||
+ dplane_ctx_queue_count(&zdplane_info.dg_update_list) > 0)
+ reschedule = true;
+
DPLANE_UNLOCK();
atomic_fetch_sub_explicit(&zdplane_info.dg_routes_queued, counter,
@@ -7375,8 +7412,9 @@ static void dplane_thread_loop(struct event *event)
* items.
*/
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
- zlog_debug("dplane enqueues %d new work to provider '%s'",
- counter, dplane_provider_get_name(prov));
+ zlog_debug("dplane enqueues %d new work to provider '%s' curr is %" PRIu64,
+ counter, dplane_provider_get_name(prov),
+ curr);
/* Capture current provider id in each context; check for
* error status.
@@ -7409,10 +7447,7 @@ static void dplane_thread_loop(struct event *event)
atomic_fetch_add_explicit(&prov->dp_in_counter, counter,
memory_order_relaxed);
- atomic_fetch_add_explicit(&prov->dp_in_queued, counter,
- memory_order_relaxed);
- curr = atomic_load_explicit(&prov->dp_in_queued,
- memory_order_relaxed);
+ curr = dplane_ctx_queue_count(&prov->dp_ctx_in_list);
high = atomic_load_explicit(&prov->dp_in_max,
memory_order_relaxed);
if (curr > high)
@@ -7437,18 +7472,61 @@ static void dplane_thread_loop(struct event *event)
if (!zdplane_info.dg_run)
break;
+ /* Locate next provider */
+ next_prov = dplane_prov_list_next(&zdplane_info.dg_providers,
+ prov);
+ if (next_prov) {
+ curr = dplane_ctx_queue_count(
+ &next_prov->dp_ctx_in_list);
+ out_curr = dplane_ctx_queue_count(
+ &next_prov->dp_ctx_out_list);
+ } else
+ out_curr = curr = 0;
+
/* Dequeue completed work from the provider */
dplane_provider_lock(prov);
- while (counter < limit) {
- ctx = dplane_provider_dequeue_out_ctx(prov);
- if (ctx) {
- dplane_ctx_list_add_tail(&work_list, ctx);
- counter++;
- } else
- break;
+ if (curr >= (uint64_t)limit) {
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("%s: Next Provider(%s) Input queue is %" PRIu64
+ ", holding off work",
+ __func__, next_prov->dp_name, curr);
+ counter = 0;
+ } else if (out_curr >= (uint64_t)limit) {
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("%s: Next Provider(%s) Output queue is %" PRIu64
+ ", holding off work",
+ __func__, next_prov->dp_name,
+ out_curr);
+ counter = 0;
+ } else {
+ int tlimit;
+
+ /*
+ * Let's limit the work to how what can be put on the
+ * in or out queue without going over
+ */
+ tlimit = limit - MAX(curr, out_curr);
+ while (counter < tlimit) {
+ ctx = dplane_provider_dequeue_out_ctx(prov);
+ if (ctx) {
+ dplane_ctx_list_add_tail(&work_list,
+ ctx);
+ counter++;
+ } else
+ break;
+ }
}
+ /*
+ * Let's check if there are still any items on the
+ * input or output queus of the current provider
+ * if so then we know we need to reschedule.
+ */
+ if (dplane_ctx_queue_count(&prov->dp_ctx_in_list) > 0 ||
+ dplane_ctx_queue_count(&prov->dp_ctx_out_list) > 0)
+ reschedule = true;
+
dplane_provider_unlock(prov);
if (counter >= limit)
@@ -7464,7 +7542,7 @@ static void dplane_thread_loop(struct event *event)
}
/* Locate next provider */
- prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
+ prov = next_prov;
}
/*
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index ebb5a42298..a733b5917f 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -663,6 +663,7 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns,
vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
if (vni_id) {
found = 1;
+ route_unlock_node(rn);
break;
}
}
@@ -757,6 +758,7 @@ static int zebra_evpn_from_svi_ns(struct ns *ns,
zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
if (vni_id) {
found = 1;
+ route_unlock_node(rn);
break;
}
}
@@ -842,6 +844,7 @@ static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp)
if (zif->link == in_param->svi_if) {
*p_ifp = tmp_if;
+ route_unlock_node(rn);
return NS_WALK_STOP;
}
}
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index bfc060db61..0d53591336 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -47,9 +47,9 @@ uint32_t num_valid_macs(struct zebra_evpn *zevpn)
for (i = 0; i < hash->size; i++) {
for (hb = hash->index[i]; hb; hb = hb->next) {
mac = (struct zebra_mac *)hb->data;
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
- || CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
- || !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ||
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ||
+ !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
num_macs++;
}
}
@@ -103,7 +103,8 @@ static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac)
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)",
- zmac->zevpn->vni, &zmac->macaddr, ifp->name, ifp->ifindex);
+ zmac->zevpn->vni, &zmac->macaddr, ifp->name,
+ ifp->ifindex);
zif = ifp->info;
list_delete_node(zif->mac_list, &zmac->ifp_listnode);
@@ -117,16 +118,17 @@ void zebra_evpn_mac_ifp_del(struct interface *ifp)
struct listnode *node;
struct zebra_mac *zmac;
- if (zif->mac_list) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("MAC list deleted for ifp %s (%u)",
- zif->ifp->name, zif->ifp->ifindex);
+ if (!zif->mac_list)
+ return;
- for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) {
- zebra_evpn_mac_ifp_unlink(zmac);
- }
- list_delete(&zif->mac_list);
- }
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("MAC list deleted for ifp %s (%u)", zif->ifp->name,
+ zif->ifp->ifindex);
+
+ for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac))
+ zebra_evpn_mac_ifp_unlink(zmac);
+
+ list_delete(&zif->mac_list);
}
/* Link local mac to destination access port. This is done only if the
@@ -159,7 +161,8 @@ static void zebra_evpn_mac_ifp_link(struct zebra_mac *zmac,
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)",
- zmac->zevpn->vni, &zmac->macaddr, ifp->name, ifp->ifindex);
+ zmac->zevpn->vni, &zmac->macaddr, ifp->name,
+ ifp->ifindex);
zmac->ifp = ifp;
listnode_init(&zmac->ifp_listnode, zmac);
@@ -201,7 +204,7 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
return -1;
sticky = !!CHECK_FLAG(mac->flags,
- (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
+ (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
/* If nexthop group for the FDB entry is inactive (not programmed in
* the dataplane) the MAC entry cannot be installed
@@ -245,14 +248,14 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn,
enum zebra_dplane_result res;
/* If the MAC was not installed there is no need to uninstall it */
- if (!force && mac->es && !CHECK_FLAG(mac->es->flags, ZEBRA_EVPNES_NHG_ACTIVE))
+ if (!force && mac->es &&
+ !CHECK_FLAG(mac->es->flags, ZEBRA_EVPNES_NHG_ACTIVE))
return -1;
if (!zevpn->vxlan_if) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "VNI %u hash %p couldn't be uninstalled - no intf",
- zevpn->vni, zevpn);
+ zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf",
+ zevpn->vni, zevpn);
return -1;
}
@@ -278,7 +281,8 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn,
ifp = zevpn->vxlan_if;
vtep_ip = mac->fwd_info.r_vtep_ip;
- res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni, vtep_ip);
+ res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni,
+ vtep_ip);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
@@ -297,9 +301,9 @@ void zebra_evpn_deref_ip2mac(struct zebra_evpn *zevpn, struct zebra_mac *mac)
/* If all remote neighbors referencing a remote MAC go away,
* we need to uninstall the MAC.
*/
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
- && remote_neigh_count(mac) == 0) {
- zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
+ remote_neigh_count(mac) == 0) {
+ zebra_evpn_rem_mac_uninstall(zevpn, mac, false);
zebra_evpn_es_mac_deref_entry(mac);
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
}
@@ -336,7 +340,8 @@ static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac,
*vid = mac->fwd_info.local.vid;
zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
- *p_ifp = if_lookup_by_index_per_ns(zns, mac->fwd_info.local.ifindex);
+ *p_ifp = if_lookup_by_index_per_ns(zns,
+ mac->fwd_info.local.ifindex);
}
}
@@ -350,18 +355,26 @@ static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac *mac, char *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) ? "PEER Active " : "",
- CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "",
- CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) ? "LOC Inactive " : "");
+ 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)
+ ? "PEER Active "
+ : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY "
+ : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)
+ ? "LOC Inactive "
+ : "");
return buf;
}
@@ -391,11 +404,11 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t)
if (IS_ZEBRA_DEBUG_VXLAN) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired",
- __func__, &mac->macaddr,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)),
- mac->dad_count, listcount(mac->neigh_list));
+ zlog_debug("%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired",
+ __func__, &mac->macaddr,
+ 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 */
@@ -404,7 +417,7 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t)
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
ZEBRA_NEIGH_SET_INACTIVE(nbr);
else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
- zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/);
+ zebra_evpn_rem_neigh_install(zevpn, nbr, false);
}
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
@@ -423,11 +436,12 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t)
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
/* Inform to BGP */
if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr,
- mac->flags, mac->loc_seq, mac->es))
+ mac->flags, mac->loc_seq,
+ mac->es))
return;
/* Process all neighbors associated with this MAC. */
- zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, 0 /*es_change*/);
+ zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, 0);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
@@ -445,7 +459,7 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
{
struct zebra_neigh *nbr;
struct listnode *node = NULL;
- struct timeval elapsed = {0, 0};
+ struct timeval elapsed = { 0, 0 };
bool reset_params = false;
if (!(zebra_evpn_do_dup_addr_detect(zvrf) && do_dad))
@@ -459,11 +473,11 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
if (IS_ZEBRA_DEBUG_VXLAN) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u",
- __func__, &mac->macaddr,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)),
- mac->dad_count, zvrf->dad_freeze_time);
+ zlog_debug("%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u",
+ __func__, &mac->macaddr,
+ 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
@@ -495,11 +509,11 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
if (IS_ZEBRA_DEBUG_VXLAN) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u",
- __func__, &mac->macaddr,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)),
- mac->dad_count);
+ zlog_debug("%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u",
+ __func__, &mac->macaddr,
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ mac->dad_count);
}
mac->dad_count = 0;
@@ -526,10 +540,11 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
if (mac->dad_count >= zvrf->dad_max_moves) {
flog_warn(EC_ZEBRA_DUP_MAC_DETECTED,
- "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4",
- mac->zevpn->vni, &mac->macaddr,
- is_local ? "local update, last" : "remote update, from",
- &vtep_ip);
+ "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4",
+ mac->zevpn->vni, &mac->macaddr,
+ is_local ? "local update, last"
+ : "remote update, from",
+ &vtep_ip);
SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
@@ -540,7 +555,6 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
* associcated with this MAC
*/
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
-
/* Ony Mark IPs which are Local */
if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
continue;
@@ -561,16 +575,18 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
if (IS_ZEBRA_DEBUG_VXLAN) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start",
- __func__, &mac->macaddr,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)),
- zvrf->dad_freeze_time);
+ zlog_debug("%s: duplicate addr MAC %pEA flags %sauto recovery time %u start",
+ __func__, &mac->macaddr,
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf,
+ sizeof(mac_buf)),
+ zvrf->dad_freeze_time);
}
event_add_timer(zrouter.master,
- zebra_evpn_dad_mac_auto_recovery_exp, mac,
- zvrf->dad_freeze_time, &mac->dad_mac_auto_recovery_timer);
+ zebra_evpn_dad_mac_auto_recovery_exp,
+ mac, zvrf->dad_freeze_time,
+ &mac->dad_mac_auto_recovery_timer);
}
/* In case of local update, do not inform to client (BGPd),
@@ -592,7 +608,7 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
struct zebra_vrf *zvrf;
- struct timeval detect_start_time = {0, 0};
+ struct timeval detect_start_time = { 0, 0 };
char timebuf[MONOTIME_STRLEN];
char thread_buf[EVENT_TIMER_STRLEN];
time_t uptime;
@@ -617,18 +633,22 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
json_object_string_add(json_mac, "type", "local");
if (ifp) {
- json_object_string_add(json_mac, "intf", ifp->name);
- json_object_int_add(json_mac, "ifindex", ifp->ifindex);
+ json_object_string_add(json_mac, "intf",
+ ifp->name);
+ json_object_int_add(json_mac, "ifindex",
+ ifp->ifindex);
}
if (vid)
json_object_int_add(json_mac, "vlan", vid);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
json_object_string_add(json_mac, "type", "remote");
if (mac->es)
- json_object_string_add(json_mac, "remoteEs", mac->es->esi_str);
+ json_object_string_add(json_mac, "remoteEs",
+ mac->es->esi_str);
else
- json_object_string_addf(
- json_mac, "remoteVtep", "%pI4", &mac->fwd_info.r_vtep_ip);
+ json_object_string_addf(json_mac, "remoteVtep",
+ "%pI4",
+ &mac->fwd_info.r_vtep_ip);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
json_object_string_add(json_mac, "type", "auto");
@@ -642,7 +662,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
json_object_boolean_true_add(json_mac, "defaultGateway");
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
- json_object_boolean_true_add(json_mac, "remoteGatewayMac");
+ json_object_boolean_true_add(json_mac,
+ "remoteGatewayMac");
json_object_string_add(json_mac, "uptime", up_str);
json_object_int_add(json_mac, "localSequence", mac->loc_seq);
@@ -663,30 +684,42 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
json_object_boolean_true_add(json_mac, "peerActive");
if (mac->hold_timer)
- json_object_string_add(json_mac, "peerActiveHold",
- event_timer_to_hhmmss(thread_buf, sizeof(thread_buf), mac->hold_timer));
+ json_object_string_add(
+ json_mac, "peerActiveHold",
+ event_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ mac->hold_timer));
if (mac->es)
- json_object_string_add(json_mac, "esi", mac->es->esi_str);
+ json_object_string_add(json_mac, "esi",
+ mac->es->esi_str);
/* print all the associated neigh */
if (!listcount(mac->neigh_list))
json_object_string_add(json_mac, "neighbors", "none");
else {
json_object *json_active_nbrs = json_object_new_array();
- json_object *json_inactive_nbrs = json_object_new_array();
+ json_object *json_inactive_nbrs =
+ json_object_new_array();
json_object *json_nbrs = json_object_new_object();
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
if (IS_ZEBRA_NEIGH_ACTIVE(n))
- json_object_array_add(json_active_nbrs,
- json_object_new_string(ipaddr2str(&n->ip, buf2, sizeof(buf2))));
+ json_object_array_add(
+ json_active_nbrs,
+ json_object_new_string(
+ ipaddr2str(&n->ip, buf2,
+ sizeof(buf2))));
else
json_object_array_add(
json_inactive_nbrs,
- json_object_new_string(ipaddr2str(&n->ip, buf2, sizeof(buf2))));
+ json_object_new_string(
+ ipaddr2str(&n->ip, buf2,
+ sizeof(buf2))));
}
- json_object_object_add(json_nbrs, "active", json_active_nbrs);
- json_object_object_add(json_nbrs, "inactive", json_inactive_nbrs);
+ json_object_object_add(json_nbrs, "active",
+ json_active_nbrs);
+ json_object_object_add(json_nbrs, "inactive",
+ json_inactive_nbrs);
json_object_object_add(json_mac, "neighbors", json_nbrs);
}
@@ -704,7 +737,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
vty_out(vty, " ESI: %s\n", mac->es->esi_str);
if (ifp)
- vty_out(vty, " Intf: %s(%u)", ifp->name, ifp->ifindex);
+ vty_out(vty, " Intf: %s(%u)", ifp->name,
+ ifp->ifindex);
else
vty_out(vty, " Intf: -");
vty_out(vty, " VLAN: %u", vid);
@@ -712,7 +746,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
if (mac->es)
vty_out(vty, " Remote ES: %s", mac->es->esi_str);
else
- vty_out(vty, " Remote VTEP: %pI4", &mac->fwd_info.r_vtep_ip);
+ vty_out(vty, " Remote VTEP: %pI4",
+ &mac->fwd_info.r_vtep_ip);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
vty_out(vty, " Auto Mac ");
}
@@ -739,18 +774,24 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
vty_out(vty, " peer-active");
if (mac->hold_timer)
vty_out(vty, " (ht: %s)",
- event_timer_to_hhmmss(thread_buf, sizeof(thread_buf), mac->hold_timer));
+ event_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ mac->hold_timer));
vty_out(vty, "\n");
- vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq, mac->rem_seq);
+ vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq,
+ mac->rem_seq);
vty_out(vty, " Uptime: %s\n", up_str);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
vty_out(vty, " Duplicate, detected at %s",
- time_to_string(mac->dad_dup_detect_time, timebuf));
+ time_to_string(mac->dad_dup_detect_time,
+ timebuf));
} else if (mac->dad_count) {
- monotime_since(&mac->detect_start_time, &detect_start_time);
+ monotime_since(&mac->detect_start_time,
+ &detect_start_time);
if (detect_start_time.tv_sec <= zvrf->dad_time) {
- time_to_string(mac->detect_start_time.tv_sec, timebuf);
+ time_to_string(mac->detect_start_time.tv_sec,
+ timebuf);
vty_out(vty,
" Duplicate detection started at %s, detection count %u\n",
timebuf, mac->dad_count);
@@ -765,7 +806,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
vty_out(vty, " %s %s\n",
ipaddr2str(&n->ip, buf2, sizeof(buf2)),
- (IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active" : "Inactive"));
+ (IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active"
+ : "Inactive"));
}
}
@@ -817,12 +859,14 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
if (json_mac_hdr == NULL) {
vty_out(vty, "%-17s %-6s %-5s %-30s", buf1, "local",
- zebra_evpn_print_mac_flags(mac, flags_buf, sizeof(flags_buf)),
+ zebra_evpn_print_mac_flags(mac, flags_buf,
+ sizeof(flags_buf)),
ifp ? ifp->name : "-");
} else {
json_object_string_add(json_mac, "type", "local");
if (ifp)
- json_object_string_add(json_mac, "intf", ifp->name);
+ json_object_string_add(json_mac, "intf",
+ ifp->name);
}
if (vid) {
if (json_mac_hdr == NULL)
@@ -831,35 +875,41 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
json_object_int_add(json_mac, "vlan", vid);
} else /* No vid? fill out the space */
if (json_mac_hdr == NULL)
- vty_out(vty, " %-5s", "");
+ vty_out(vty, " %-5s", "");
if (json_mac_hdr == NULL) {
vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq);
vty_out(vty, "\n");
} else {
- json_object_int_add(json_mac, "localSequence", mac->loc_seq);
- json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
- json_object_int_add(json_mac, "detectionCount", mac->dad_count);
+ json_object_int_add(json_mac, "localSequence",
+ mac->loc_seq);
+ json_object_int_add(json_mac, "remoteSequence",
+ mac->rem_seq);
+ json_object_int_add(json_mac, "detectionCount",
+ mac->dad_count);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
- json_object_boolean_true_add(json_mac, "isDuplicate");
+ json_object_boolean_true_add(json_mac,
+ "isDuplicate");
else
- json_object_boolean_false_add(json_mac, "isDuplicate");
+ json_object_boolean_false_add(json_mac,
+ "isDuplicate");
json_object_object_add(json_mac_hdr, buf1, json_mac);
}
wctx->count++;
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
-
- if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)
- && !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
+ if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) &&
+ !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
return;
if (json_mac_hdr == NULL) {
- if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)
- && (wctx->count == 0)) {
+ if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) &&
+ (wctx->count == 0)) {
vty_out(vty, "\nVNI %u\n\n", wctx->zevpn->vni);
vty_out(vty, "%-17s %-6s %-5s%-30s %-5s %s\n",
- "MAC", "Type", "Flags", "Intf/Remote ES/VTEP", "VLAN", "Seq #'s");
+ "MAC", "Type", "Flags",
+ "Intf/Remote ES/VTEP", "VLAN",
+ "Seq #'s");
}
if (mac->es == NULL)
inet_ntop(AF_INET, &mac->fwd_info.r_vtep_ip,
@@ -867,24 +917,32 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1,
"remote",
- zebra_evpn_print_mac_flags(mac, flags_buf, sizeof(flags_buf)),
- mac->es ? mac->es->esi_str : addr_buf,
- "", mac->loc_seq, mac->rem_seq);
+ zebra_evpn_print_mac_flags(mac, flags_buf,
+ sizeof(flags_buf)),
+ mac->es ? mac->es->esi_str : addr_buf, "",
+ mac->loc_seq, mac->rem_seq);
} else {
json_object_string_add(json_mac, "type", "remote");
if (mac->es)
- json_object_string_add(json_mac, "remoteEs", mac->es->esi_str);
+ json_object_string_add(json_mac, "remoteEs",
+ mac->es->esi_str);
else
- json_object_string_addf(
- json_mac, "remoteVtep", "%pI4", &mac->fwd_info.r_vtep_ip);
+ json_object_string_addf(json_mac, "remoteVtep",
+ "%pI4",
+ &mac->fwd_info.r_vtep_ip);
json_object_object_add(json_mac_hdr, buf1, json_mac);
- json_object_int_add(json_mac, "localSequence", mac->loc_seq);
- json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
- json_object_int_add(json_mac, "detectionCount", mac->dad_count);
+ json_object_int_add(json_mac, "localSequence",
+ mac->loc_seq);
+ json_object_int_add(json_mac, "remoteSequence",
+ mac->rem_seq);
+ json_object_int_add(json_mac, "detectionCount",
+ mac->dad_count);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
- json_object_boolean_true_add(json_mac, "isDuplicate");
+ json_object_boolean_true_add(json_mac,
+ "isDuplicate");
else
- json_object_boolean_false_add(json_mac, "isDuplicate");
+ json_object_boolean_false_add(json_mac,
+ "isDuplicate");
}
wctx->count++;
@@ -917,8 +975,7 @@ void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt)
/*
* Inform BGP about local MACIP.
*/
-int zebra_evpn_macip_send_msg_to_client(vni_t vni,
- const struct ethaddr *macaddr,
+int zebra_evpn_macip_send_msg_to_client(vni_t vni, const struct ethaddr *macaddr,
const struct ipaddr *ip, uint8_t flags,
uint32_t seq, int state,
struct zebra_evpn_es *es, uint16_t cmd)
@@ -966,13 +1023,12 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni,
if (IS_ZEBRA_DEBUG_VXLAN) {
char flag_buf[MACIP_BUF_SIZE];
- zlog_debug(
- "Send MACIP %s f %s state %u MAC %pEA IP %pIA 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)),
- state, macaddr, ip, seq, vni,
- es ? es->esi_str : "-",
- zebra_route_string(client->proto));
+ zlog_debug("Send MACIP %s f %s state %u MAC %pEA IP %pIA 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)),
+ state, macaddr, ip, seq, vni, es ? es->esi_str : "-",
+ zebra_route_string(client->proto));
}
if (cmd == ZEBRA_MACIP_ADD)
@@ -1005,7 +1061,8 @@ static bool mac_cmp(const void *p1, const void *p2)
if (pmac1 == NULL || pmac2 == NULL)
return false;
- return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN) == 0);
+ return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN) ==
+ 0);
}
/*
@@ -1046,7 +1103,8 @@ struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevpn,
char mac_buf[MAC_BUF_SIZE];
zlog_debug("%s: MAC %pEA flags %s", __func__, &mac->macaddr,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
return mac;
}
@@ -1062,7 +1120,8 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
char mac_buf[MAC_BUF_SIZE];
zlog_debug("%s: MAC %pEA flags %s", __func__, &mac->macaddr,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
/* force de-ref any ES entry linked to the MAC */
@@ -1087,10 +1146,10 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
*/
if (!list_isempty(mac->neigh_list)) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list "
- "count %u, mark MAC as AUTO", &mac->macaddr, mac->flags,
- zevpn->vni, listcount(mac->neigh_list));
+ zlog_debug("MAC %pEA (flags 0x%x vni %u) has non-empty neigh list "
+ "count %u, mark MAC as AUTO",
+ &mac->macaddr, mac->flags, zevpn->vni,
+ listcount(mac->neigh_list));
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
return 0;
@@ -1127,25 +1186,26 @@ struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn,
static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
struct zebra_mac *mac)
{
- if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC)
- && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
+ if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) &&
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
return true;
- else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC)
- && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
+ else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC) &&
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
return true;
- else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC_FROM_VTEP)
- && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
- && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
+ else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC_FROM_VTEP) &&
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
+ IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
return true;
- else if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC)
- && CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)
- && !listcount(mac->neigh_list)) {
+ else if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) &&
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) &&
+ !listcount(mac->neigh_list)) {
if (IS_ZEBRA_DEBUG_VXLAN) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "%s: Del MAC %pEA flags %s", __func__, &mac->macaddr,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("%s: Del MAC %pEA flags %s", __func__,
+ &mac->macaddr,
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
wctx->uninstall = 0;
@@ -1163,23 +1223,25 @@ static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
struct mac_walk_ctx *wctx = arg;
struct zebra_mac *mac = bucket->data;
- if (zebra_evpn_check_mac_del_from_db(wctx, mac)) {
- if (wctx->upd_client && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni,
- &mac->macaddr, mac->flags, false);
- }
- if (wctx->uninstall) {
- if (zebra_evpn_mac_is_static(mac))
- zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
- true /* force_clear_static */, __func__);
+ if (!zebra_evpn_check_mac_del_from_db(wctx, mac))
+ return;
- if (mac->flags & ZEBRA_MAC_REMOTE)
- zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false /*force*/);
- }
+ if (wctx->upd_client && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni,
+ &mac->macaddr, mac->flags,
+ false);
+ }
+ if (wctx->uninstall) {
+ if (zebra_evpn_mac_is_static(mac))
+ zebra_evpn_sync_mac_dp_install(mac, false, true,
+ __func__);
- zebra_evpn_mac_del(wctx->zevpn, mac);
+ if (mac->flags & ZEBRA_MAC_REMOTE)
+ zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false);
}
+ zebra_evpn_mac_del(wctx->zevpn, mac);
+
return;
}
@@ -1249,7 +1311,8 @@ int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr,
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, flags,
- seq, ZEBRA_NEIGH_ACTIVE, es, ZEBRA_MACIP_ADD);
+ seq, ZEBRA_NEIGH_ACTIVE, es,
+ ZEBRA_MACIP_ADD);
}
/*
@@ -1261,8 +1324,8 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr,
int state = ZEBRA_NEIGH_ACTIVE;
if (!force) {
- if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE)
- && !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE) &&
+ !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE))
/* the host was not advertised - nothing to delete */
return 0;
@@ -1275,8 +1338,8 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr,
state = ZEBRA_NEIGH_INACTIVE;
}
- return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL,
- 0 /* flags */, 0 /* seq */, state, NULL, ZEBRA_MACIP_DEL);
+ return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, 0, 0,
+ state, NULL, ZEBRA_MACIP_DEL);
}
/*
@@ -1308,12 +1371,11 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive,
es_evi = zebra_evpn_es_evi_find(mac->es, mac->zevpn);
if (!es_evi) {
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug(
- "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi",
- caller, zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-",
- mac->flags,
- set_inactive ? "inactive " : "");
+ zlog_debug("%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi",
+ caller, zevpn->vni, &mac->macaddr,
+ mac->es ? mac->es->esi_str : "-",
+ mac->flags,
+ set_inactive ? "inactive " : "");
return -1;
}
}
@@ -1325,12 +1387,12 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive,
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "%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 " : "");
+ zlog_debug("%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 -1;
}
@@ -1341,12 +1403,12 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive,
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "%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 " : "");
+ zlog_debug("%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 -1;
}
@@ -1365,21 +1427,21 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive,
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 " : "");
+ 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 */);
+ zebra_evpn_rem_mac_install(zevpn, mac, true);
else
- zebra_evpn_rem_mac_uninstall(zevpn, mac, false /* force */);
+ zebra_evpn_rem_mac_uninstall(zevpn, mac, false);
return 0;
}
@@ -1390,13 +1452,14 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive,
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)),
+ 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);
+ set_static, set_inactive);
return 0;
}
@@ -1406,11 +1469,11 @@ void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac *mac,
{
if (new_bgp_ready)
zebra_evpn_mac_send_add_to_client(mac->zevpn->vni,
- &mac->macaddr, mac->flags,
- mac->loc_seq, mac->es);
+ &mac->macaddr, mac->flags,
+ mac->loc_seq, mac->es);
else if (old_bgp_ready)
- zebra_evpn_mac_send_del_to_client(mac->zevpn->vni,
- &mac->macaddr, mac->flags, true /* force */);
+ zebra_evpn_mac_send_del_to_client(mac->zevpn->vni, &mac->macaddr,
+ mac->flags, true);
}
/* MAC hold timer is used to age out peer-active flag.
@@ -1443,23 +1506,23 @@ static void zebra_evpn_mac_hold_exp_cb(struct event *t)
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "sync-mac vni %u mac %pEA es %s %shold expired",
- mac->zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-",
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("sync-mac vni %u mac %pEA es %s %shold expired",
+ mac->zevpn->vni, &mac->macaddr,
+ 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
*/
if (old_static != new_static)
- zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
- false /* force_clear_static */, __func__);
+ zebra_evpn_sync_mac_dp_install(mac, false, false, __func__);
/* inform bgp if needed */
if (old_bgp_ready != new_bgp_ready)
- zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready);
+ zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
+ new_bgp_ready);
}
static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac)
@@ -1470,11 +1533,11 @@ static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac)
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "sync-mac vni %u mac %pEA es %s %shold started",
- mac->zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-",
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("sync-mac vni %u mac %pEA es %s %shold started",
+ mac->zevpn->vni, &mac->macaddr,
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
event_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
zmh_info->mac_hold_time, &mac->hold_timer);
@@ -1488,11 +1551,11 @@ void zebra_evpn_mac_stop_hold_timer(struct zebra_mac *mac)
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "sync-mac vni %u mac %pEA es %s %shold stopped",
- mac->zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-",
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("sync-mac vni %u mac %pEA es %s %shold stopped",
+ mac->zevpn->vni, &mac->macaddr,
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
EVENT_OFF(mac->hold_timer);
@@ -1506,11 +1569,11 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac)
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "sync-mac del vni %u mac %pEA es %s seq %d f %s",
- mac->zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-", mac->loc_seq,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("sync-mac del vni %u mac %pEA es %s seq %d f %s",
+ mac->zevpn->vni, &mac->macaddr,
+ mac->es ? mac->es->esi_str : "-", mac->loc_seq,
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
old_static = zebra_evpn_mac_is_static(mac);
@@ -1521,8 +1584,7 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac)
if (old_static != new_static)
/* program the local mac in the kernel */
- zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
- false /* force_clear_static */, __func__);
+ zebra_evpn_sync_mac_dp_install(mac, false, false, __func__);
}
static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
@@ -1543,44 +1605,41 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
n_type = "remote";
}
- if (seq < tmp_seq) {
-
- if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x",
- sync ? "sync" : "rem", zevpn->vni,
- n_type, &mac->macaddr, tmp_seq, mac->flags);
- return true;
- }
-
- /* if the mac was never advertised to bgp we must accept
- * whatever sequence number bgp sends
- */
- if (!is_local && zebra_vxlan_get_accept_bgp_seq()) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC ||
- IS_ZEBRA_DEBUG_VXLAN) {
- zlog_debug(
- "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s",
- (sync ? "sync" : "rem"),
- zevpn->vni, n_type, &mac->macaddr, tmp_seq,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
- }
+ if (seq >= tmp_seq)
+ return true;
- return true;
- }
+ if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x",
+ sync ? "sync" : "rem", zevpn->vni, n_type,
+ &mac->macaddr, tmp_seq, mac->flags);
+ return true;
+ }
+ /* if the mac was never advertised to bgp we must accept
+ * whatever sequence number bgp sends
+ */
+ if (!is_local && zebra_vxlan_get_accept_bgp_seq()) {
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
- zlog_debug(
- "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s",
- (sync ? "sync" : "rem"), zevpn->vni, n_type, &mac->macaddr, tmp_seq,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("%s-macip accept vni %u %s-mac %pEA lower seq %u f %s",
+ (sync ? "sync" : "rem"), zevpn->vni, n_type,
+ &mac->macaddr, tmp_seq,
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
- return false;
+ return true;
}
- return true;
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
+ zlog_debug("%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s",
+ (sync ? "sync" : "rem"), zevpn->vni, n_type,
+ &mac->macaddr, tmp_seq,
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
+ }
+
+ return false;
}
struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
@@ -1644,13 +1703,14 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW);
if (sticky || remote_gw) {
if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug(
- "Ignore sync-macip vni %u mac %pEA%s%s%s%s",
- zevpn->vni, macaddr,
- ipa_len ? " IP " : "",
- ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "",
- sticky ? " sticky" : "",
- remote_gw ? " remote_gw" : "");
+ zlog_debug("Ignore sync-macip vni %u mac %pEA%s%s%s%s",
+ zevpn->vni, macaddr,
+ ipa_len ? " IP " : "",
+ ipa_len ? ipaddr2str(ipaddr, ipbuf,
+ sizeof(ipbuf))
+ : "",
+ sticky ? " sticky" : "",
+ remote_gw ? " remote_gw" : "");
return NULL;
}
if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, true))
@@ -1664,7 +1724,9 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
/* retain old local activity flag */
if (CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL))
- SET_FLAG (new_flags, CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL_INACTIVE));
+ SET_FLAG(new_flags,
+ CHECK_FLAG(old_flags,
+ ZEBRA_MAC_LOCAL_INACTIVE));
else
SET_FLAG(new_flags, ZEBRA_MAC_LOCAL_INACTIVE);
@@ -1672,7 +1734,9 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
/* if mac-ip route do NOT update the peer flags
* i.e. retain only flags as is
*/
- SET_FLAG(new_flags, CHECK_FLAG(old_flags, ZEBRA_MAC_ALL_PEER_FLAGS));
+ SET_FLAG(new_flags,
+ CHECK_FLAG(old_flags,
+ ZEBRA_MAC_ALL_PEER_FLAGS));
} else {
/* if mac-only route update peer flags */
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
@@ -1682,8 +1746,10 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
* holdtimer on it. the peer-active flag is
* cleared on holdtimer expiry.
*/
- if (CHECK_FLAG(old_flags, ZEBRA_MAC_ES_PEER_ACTIVE)) {
- SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE);
+ if (CHECK_FLAG(old_flags,
+ ZEBRA_MAC_ES_PEER_ACTIVE)) {
+ SET_FLAG(new_flags,
+ ZEBRA_MAC_ES_PEER_ACTIVE);
zebra_evpn_mac_start_hold_timer(mac);
}
} else {
@@ -1703,11 +1769,13 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
struct zebra_mac omac;
omac.flags = old_flags;
- zlog_debug(
- "sync-mac vni %u mac %pEA old_f %snew_f %s",
- zevpn->vni, macaddr,
- zebra_evpn_zebra_mac_flag_dump(&omac, omac_buf, sizeof(omac_buf)),
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("sync-mac vni %u mac %pEA old_f %snew_f %s",
+ zevpn->vni, macaddr,
+ 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 */
@@ -1747,24 +1815,25 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
char mac_buf[MAC_BUF_SIZE];
zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
- created ? "created" : "updated",
- zevpn->vni, macaddr,
- mac->es ? mac->es->esi_str : "-",
- mac->loc_seq,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)),
- inform_bgp ? "inform_bgp" : "",
- inform_dataplane ? " inform_dp" : "");
+ created ? "created" : "updated", zevpn->vni, macaddr,
+ mac->es ? mac->es->esi_str : "-", mac->loc_seq,
+ 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, new_bgp_ready);
+ zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
+ new_bgp_ready);
/* neighs using the mac may need to be re-sent to
* bgp with updated info
*/
if (seq_change || es_change || !old_local)
- zebra_evpn_process_neigh_on_local_mac_change(
- zevpn, mac, seq_change, es_change);
+ zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac,
+ seq_change,
+ es_change);
if (inform_dataplane && !ipa_len) {
/* program the local mac in the kernel. when the ES
@@ -1772,8 +1841,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
* the activity as we are yet to establish activity
* locally
*/
- zebra_evpn_sync_mac_dp_install(mac, mac_inactive /* set_inactive */,
- false /* force_clear_static */, __func__);
+ zebra_evpn_sync_mac_dp_install(mac, mac_inactive, false,
+ __func__);
}
return mac;
@@ -1783,7 +1852,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
* is detected
*/
static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac *mac,
- struct interface *ifp, vlanid_t vid)
+ struct interface *ifp,
+ vlanid_t vid)
{
struct zebra_if *zif = ifp->info;
bool es_change;
@@ -1825,8 +1895,8 @@ static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
zebra_evpn_mac_send_add_to_client(wctx->zevpn->vni,
- &zmac->macaddr, zmac->flags,
- zmac->loc_seq, zmac->es);
+ &zmac->macaddr, zmac->flags,
+ zmac->loc_seq, zmac->es);
}
/* Iterator to Notify Local MACs of a EVPN */
@@ -1840,7 +1910,8 @@ void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevpn)
memset(&wctx, 0, sizeof(wctx));
wctx.zevpn = zevpn;
- hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client, &wctx);
+ hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client,
+ &wctx);
}
void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
@@ -1857,7 +1928,7 @@ void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
* go away, we need to uninstall the MAC.
*/
if (remote_neigh_count(mac) == 0) {
- zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
+ zebra_evpn_rem_mac_uninstall(zevpn, mac, false);
zebra_evpn_es_mac_deref_entry(mac);
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
}
@@ -1917,12 +1988,11 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
/* Ignore if the mac is already present as a gateway mac */
- if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)
- && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
+ if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) &&
+ CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC",
- zevpn->vni, macaddr);
+ zlog_debug("Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC",
+ zevpn->vni, macaddr);
return -1;
}
@@ -1932,13 +2002,11 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
* If so, that needs to be updated first. Note that client could
* install MAC and MACIP separately or just install the latter.
*/
- if (!mac
- || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
- || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
- || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
- || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
- || memcmp(old_esi, esi, sizeof(esi_t))
- || seq != mac->rem_seq)
+ if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ||
+ sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ||
+ remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ||
+ !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) ||
+ memcmp(old_esi, esi, sizeof(esi_t)) || seq != mac->rem_seq)
update_mac = 1;
if (update_mac) {
@@ -1954,7 +2022,8 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
* the sequence number and ignore this update
* if appropriate.
*/
- if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, false))
+ if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq,
+ false))
return -1;
old_es_present = !!mac->es;
@@ -1981,8 +2050,9 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
* MAC is already marked duplicate set dad, then
* is_dup_detect will be set to not install the entry.
*/
- if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && mac->dad_count)
- || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+ if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
+ mac->dad_count) ||
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
do_dad = true;
/* Remove local MAC from BGP. */
@@ -1992,17 +2062,18 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "sync-mac->remote vni %u mac %pEA es %s seq %d f %s",
- zevpn->vni, macaddr,
- mac->es ? mac->es->esi_str : "-",
- mac->loc_seq,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("sync-mac->remote vni %u mac %pEA es %s seq %d f %s",
+ zevpn->vni, macaddr,
+ mac->es ? mac->es->esi_str : "-",
+ 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,
- false /* force */);
+ zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr,
+ mac->flags, false);
}
/* Set "auto" and "remote" forwarding info. */
@@ -2021,8 +2092,10 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
else
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
- zebra_evpn_dup_addr_detect_for_mac(
- zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad, &is_dup_detect, false);
+ zebra_evpn_dup_addr_detect_for_mac(zvrf, mac,
+ mac->fwd_info.r_vtep_ip,
+ do_dad, &is_dup_detect,
+ false);
if (!is_dup_detect) {
zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
@@ -2049,7 +2122,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
bool inform_client = false;
bool upd_neigh = false;
bool is_dup_detect = false;
- struct in_addr vtep_ip = {.s_addr = 0};
+ struct in_addr vtep_ip = { .s_addr = 0 };
bool es_change = false;
bool new_bgp_ready;
/* assume inactive if not present or if not local */
@@ -2064,11 +2137,10 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac) {
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug(
- "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s",
- sticky ? "sticky " : "",
- macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni,
- local_inactive ? " local-inactive" : "");
+ zlog_debug("ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s",
+ sticky ? "sticky " : "", macaddr, ifp->name,
+ ifp->ifindex, vid, zevpn->vni,
+ local_inactive ? " local-inactive" : "");
mac = zebra_evpn_mac_add(zevpn, macaddr);
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
@@ -2080,12 +2152,12 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s",
- sticky ? "sticky " : "",
- macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni,
- local_inactive ? "local-inactive " : "",
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s",
+ sticky ? "sticky " : "", macaddr, ifp->name,
+ ifp->ifindex, vid, zevpn->vni,
+ local_inactive ? "local-inactive " : "",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
@@ -2094,27 +2166,34 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
bool old_static;
zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid);
- old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
- old_local_inactive = !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE);
+ old_bgp_ready =
+ zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+ old_local_inactive = !!(mac->flags &
+ ZEBRA_MAC_LOCAL_INACTIVE);
old_static = zebra_evpn_mac_is_static(mac);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
mac_sticky = true;
- es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid);
+ es_change = zebra_evpn_local_mac_update_fwd_info(mac,
+ ifp,
+ vid);
/*
* Update any changes and if changes are relevant to
* BGP, note it.
*/
- if (mac_sticky == sticky && old_ifp == ifp && old_vid == vid
- && old_local_inactive == local_inactive
- && dp_static == old_static && !es_change) {
+ if (mac_sticky == sticky && old_ifp == ifp &&
+ old_vid == vid &&
+ old_local_inactive == local_inactive &&
+ dp_static == old_static && !es_change) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, "
- "entry exists and has not changed ",
- sticky ? "sticky " : "",
- macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni,
- local_inactive ? " local_inactive" : "");
+ zlog_debug(" Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, "
+ "entry exists and has not changed ",
+ sticky ? "sticky " : "",
+ macaddr, ifp->name,
+ ifp->ifindex, vid, zevpn->vni,
+ local_inactive
+ ? " local_inactive"
+ : "");
return 0;
}
if (mac_sticky != sticky) {
@@ -2139,9 +2218,11 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
/* force drop the peer/sync info as it is
* simply no longer relevant
*/
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ALL_PEER_FLAGS)) {
+ if (CHECK_FLAG(mac->flags,
+ ZEBRA_MAC_ALL_PEER_FLAGS)) {
zebra_evpn_mac_clear_sync_info(mac);
- new_static = zebra_evpn_mac_is_static(mac);
+ new_static =
+ zebra_evpn_mac_is_static(mac);
/* if we clear peer-flags we
* also need to notify the dataplane
* to drop the static flag
@@ -2150,8 +2231,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
inform_dataplane = true;
}
}
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
- || CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ||
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
bool do_dad = false;
/*
@@ -2161,16 +2242,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
* operator error.
*/
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
- flog_warn(
- EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
- "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u",
- macaddr, &mac->fwd_info.r_vtep_ip, zevpn->vni);
+ flog_warn(EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
+ "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u",
+ macaddr, &mac->fwd_info.r_vtep_ip,
+ zevpn->vni);
return 0;
}
/* If an actual move, compute MAC's seq number */
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- mac->loc_seq = MAX(mac->rem_seq + 1, mac->loc_seq);
+ mac->loc_seq = MAX(mac->rem_seq + 1,
+ mac->loc_seq);
vtep_ip = mac->fwd_info.r_vtep_ip;
/* Trigger DAD for remote MAC */
do_dad = true;
@@ -2179,7 +2261,9 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
- es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid);
+ es_change = zebra_evpn_local_mac_update_fwd_info(mac,
+ ifp,
+ vid);
if (sticky)
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
else
@@ -2191,8 +2275,9 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
inform_client = true;
upd_neigh = true;
- zebra_evpn_dup_addr_detect_for_mac(
- zvrf, mac, vtep_ip, do_dad, &is_dup_detect, true);
+ zebra_evpn_dup_addr_detect_for_mac(zvrf, mac, vtep_ip,
+ do_dad,
+ &is_dup_detect, true);
if (is_dup_detect) {
inform_client = false;
upd_neigh = false;
@@ -2218,17 +2303,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
/* if local-activity has changed we need update bgp
* even if bgp already knows about the mac
*/
- if ((old_local_inactive != local_inactive)
- || (new_bgp_ready != old_bgp_ready)) {
+ if ((old_local_inactive != local_inactive) ||
+ (new_bgp_ready != old_bgp_ready)) {
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "local mac vni %u mac %pEA es %s seq %d f %s%s",
- zevpn->vni, macaddr,
- mac->es ? mac->es->esi_str : "", mac->loc_seq,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)),
- local_inactive ? "local-inactive" : "");
+ zlog_debug("local mac vni %u mac %pEA es %s seq %d f %s%s",
+ zevpn->vni, macaddr,
+ mac->es ? mac->es->esi_str : "", mac->loc_seq,
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ local_inactive ? "local-inactive" : "");
}
if (!is_dup_detect)
@@ -2242,16 +2327,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
/* Inform dataplane if required. */
if (inform_dataplane)
- zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
- false /* force_clear_static */, __func__);
+ zebra_evpn_sync_mac_dp_install(mac, false, false, __func__);
/* Inform BGP if required. */
if (inform_client)
- zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready);
+ zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
+ new_bgp_ready);
/* Process all neighbors associated with this MAC, if required. */
if (upd_neigh)
- zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, es_change);
+ zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
+ es_change);
return 0;
}
@@ -2277,24 +2363,25 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac,
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char mac_buf[MAC_BUF_SIZE];
- zlog_debug(
- "re-add sync-mac vni %u mac %pEA es %s seq %d f %s",
- zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-", mac->loc_seq,
- zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)));
+ zlog_debug("re-add sync-mac vni %u mac %pEA es %s seq %d f %s",
+ zevpn->vni, &mac->macaddr,
+ mac->es ? mac->es->esi_str : "-",
+ mac->loc_seq,
+ 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)) {
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);
+ 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 inactive entry in the kernel */
- zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */,
- false /* force_clear_static */, __func__);
+ zebra_evpn_sync_mac_dp_install(mac, true, false, __func__);
return 0;
}
@@ -2307,7 +2394,7 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac,
/* Remove MAC from BGP. */
zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags,
- clear_static /* force */);
+ clear_static);
zebra_evpn_es_mac_deref_entry(mac);
@@ -2329,8 +2416,7 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac,
return 0;
}
-void zebra_evpn_mac_gw_macip_add(struct interface *ifp,
- struct zebra_evpn *zevpn,
+void zebra_evpn_mac_gw_macip_add(struct interface *ifp, struct zebra_evpn *zevpn,
const struct ipaddr *ip,
struct zebra_mac **macp,
const struct ethaddr *macaddr,
@@ -2376,15 +2462,17 @@ void zebra_evpn_mac_svi_del(struct interface *ifp, struct zebra_evpn *zevpn)
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
- if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("SVI %s mac free", ifp->name);
-
- old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
- UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI);
- zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, false);
- zebra_evpn_deref_ip2mac(mac->zevpn, mac);
- }
+
+ if (!mac || CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("SVI %s mac free", ifp->name);
+
+ old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI);
+ zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, false);
+ zebra_evpn_deref_ip2mac(mac->zevpn, mac);
}
void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn)
@@ -2395,8 +2483,8 @@ void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn)
bool old_bgp_ready;
bool new_bgp_ready;
- if (!zebra_evpn_mh_do_adv_svi_mac()
- || !zebra_evpn_send_to_client_ok(zevpn))
+ if (!zebra_evpn_mh_do_adv_svi_mac() ||
+ !zebra_evpn_send_to_client_ok(zevpn))
return;
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
@@ -2410,8 +2498,9 @@ void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn)
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("SVI %s mac add", zif->ifp->name);
- old_bgp_ready =
- (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags)) ? true : false;
+ old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags))
+ ? true
+ : false;
zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false);
diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c
index d84f680e22..07391b7ac7 100644
--- a/zebra/zebra_gr.c
+++ b/zebra/zebra_gr.c
@@ -583,7 +583,7 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info,
uint16_t instance;
struct zserv *s_client;
struct zserv *client;
- time_t restart_time = time(NULL);
+ time_t restart_time;
if ((info == NULL) || (zvrf == NULL))
return -1;
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index d1c9cd54af..9549af5f14 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -37,6 +37,7 @@
DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object");
DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object");
DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object");
+DEFINE_MTYPE_STATIC(ZEBRA, NH_LABEL, "Nexthop label");
bool mpls_enabled;
bool mpls_pw_reach_strict; /* Strict reachability checking */
@@ -50,7 +51,7 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
struct route_node *rn, struct route_entry *re);
static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label);
static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
- mpls_label_t old_label);
+ mpls_label_t old_label, bool uninstall);
static int fec_send(struct zebra_fec *fec, struct zserv *client);
static void fec_update_clients(struct zebra_fec *fec);
static void fec_print(struct zebra_fec *fec, struct vty *vty);
@@ -161,12 +162,14 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
enum lsp_types_t lsp_type;
char buf[BUFSIZ];
int added, changed;
+ bool zvrf_nexthop_resolution;
/* Lookup table. */
lsp_table = zvrf->lsp_table;
if (!lsp_table)
return -1;
+ zvrf_nexthop_resolution = zvrf->zebra_mpls_fec_nexthop_resolution;
lsp_type = lsp_type_from_re_type(re->type);
added = changed = 0;
@@ -180,13 +183,20 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
* the label advertised by the recursive nexthop (plus we don't have the
* logic yet to push multiple labels).
*/
- for (nexthop = re->nhe->nhg.nexthop;
- nexthop; nexthop = nexthop->next) {
- /* Skip inactive and recursive entries. */
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ nexthop = re->nhe->nhg.nexthop;
+ while (nexthop) {
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
+ nexthop =
+ nexthop_next_resolution(nexthop,
+ zvrf_nexthop_resolution);
continue;
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ }
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) {
+ nexthop =
+ nexthop_next_resolution(nexthop,
+ zvrf_nexthop_resolution);
continue;
+ }
nhlfe = nhlfe_find(&lsp->nhlfe_list, lsp_type,
nexthop->type, &nexthop->gate,
@@ -194,9 +204,13 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
if (nhlfe) {
/* Clear deleted flag (in case it was set) */
UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
- if (nexthop_labels_match(nhlfe->nexthop, nexthop))
+ if (nexthop_labels_match(nhlfe->nexthop, nexthop)) {
/* No change */
+ nexthop =
+ nexthop_next_resolution(nexthop,
+ zvrf_nexthop_resolution);
continue;
+ }
if (IS_ZEBRA_DEBUG_MPLS) {
@@ -221,11 +235,18 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
return -1;
if (IS_ZEBRA_DEBUG_MPLS) {
+ char label_str[MPLS_LABEL_STRLEN];
+
nhlfe2str(nhlfe, buf, BUFSIZ);
- zlog_debug(
- "Add LSP in-label %u type %d nexthop %s out-label %u",
- lsp->ile.in_label, lsp_type, buf,
- nexthop->nh_label->label[0]);
+ zlog_debug("Add LSP in-label %u type %d nexthop %s out-label %s",
+ lsp->ile.in_label, lsp_type, buf,
+ mpls_label2str(nexthop->nh_label
+ ->num_labels,
+ nexthop->nh_label->label,
+ label_str,
+ sizeof(label_str),
+ nexthop->nh_label_type,
+ 0));
}
lsp->addr_family = NHLFE_FAMILY(nhlfe);
@@ -234,6 +255,8 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
added++;
}
+ nexthop = nexthop_next_resolution(nexthop,
+ zvrf_nexthop_resolution);
}
/* Queue LSP for processing if necessary. If no NHLFE got added (special
@@ -245,6 +268,8 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
return -1;
} else {
lsp_check_free(lsp_table, &lsp);
+ /* failed to install a new LSP */
+ return -1;
}
return 0;
@@ -353,7 +378,7 @@ static void fec_evaluate(struct zebra_vrf *zvrf)
fec_update_clients(fec);
/* Update label forwarding entries appropriately */
- fec_change_update_lsp(zvrf, fec, old_label);
+ fec_change_update_lsp(zvrf, fec, old_label, false);
}
}
}
@@ -384,7 +409,7 @@ static uint32_t fec_derive_label_from_index(struct zebra_vrf *zvrf,
* entries, as appropriate.
*/
static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
- mpls_label_t old_label)
+ mpls_label_t old_label, bool uninstall)
{
struct route_table *table;
struct route_node *rn;
@@ -416,11 +441,17 @@ static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
break;
}
- if (!re || !zebra_rib_labeled_unicast(re))
+ if (!re || !zebra_rib_labeled_unicast(re)) {
+ if (uninstall)
+ lsp_uninstall(zvrf, fec->label);
return 0;
+ }
- if (lsp_install(zvrf, fec->label, rn, re))
+ if (lsp_install(zvrf, fec->label, rn, re)) {
+ if (uninstall)
+ lsp_uninstall(zvrf, fec->label);
return -1;
+ }
return 0;
}
@@ -448,6 +479,30 @@ static int fec_send(struct zebra_fec *fec, struct zserv *client)
}
/*
+ * Upon reconfiguring nexthop-resolution updates, update the
+ * lsp entries accordingly.
+ */
+void zebra_mpls_fec_nexthop_resolution_update(struct zebra_vrf *zvrf)
+{
+ int af;
+ struct route_node *rn;
+ struct zebra_fec *fec;
+
+ for (af = AFI_IP; af < AFI_MAX; af++) {
+ if (zvrf->fec_table[af] == NULL)
+ continue;
+ for (rn = route_top(zvrf->fec_table[af]); rn;
+ rn = route_next(rn)) {
+ if (!rn->info)
+ continue;
+ fec = rn->info;
+ fec_change_update_lsp(zvrf, fec, MPLS_INVALID_LABEL,
+ true);
+ }
+ }
+}
+
+/*
* Update all registered clients about this FEC. Caller should've updated
* FEC and ensure no duplicate updates.
*/
@@ -1398,7 +1453,31 @@ static int nhlfe_del(struct zebra_nhlfe *nhlfe)
static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
struct mpls_label_stack *nh_label)
{
- nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
+ struct mpls_label_stack *nh_label_tmp;
+ int i;
+
+ /* Enforce limit on label stack size */
+ if (nh_label->num_labels > MPLS_MAX_LABELS)
+ nh_label->num_labels = MPLS_MAX_LABELS;
+
+ /* Resize the array to accommodate the new label stack */
+ if (nh_label->num_labels > nhlfe->nexthop->nh_label->num_labels) {
+ nh_label_tmp = XREALLOC(MTYPE_NH_LABEL, nhlfe->nexthop->nh_label,
+ sizeof(struct mpls_label_stack) +
+ nh_label->num_labels *
+ sizeof(mpls_label_t));
+ if (nh_label_tmp) {
+ nhlfe->nexthop->nh_label = nh_label_tmp;
+ nhlfe->nexthop->nh_label->num_labels =
+ nh_label->num_labels;
+ } else
+ nh_label->num_labels =
+ nhlfe->nexthop->nh_label->num_labels;
+ }
+
+ /* Copy the label stack into the array */
+ for (i = 0; i < nh_label->num_labels; i++)
+ nhlfe->nexthop->nh_label->label[i] = nh_label->label[i];
}
static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
@@ -2117,7 +2196,7 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
/*
* Install dynamic LSP entry.
*/
-int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
+void zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *re)
{
struct route_table *table;
@@ -2125,23 +2204,20 @@ int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
if (!table)
- return -1;
+ return;
/* See if there is a configured label binding for this FEC. */
fec = fec_find(table, &rn->p);
if (!fec || fec->label == MPLS_INVALID_LABEL)
- return 0;
+ return;
/* We cannot install a label forwarding entry if local label is the
* implicit-null label.
*/
if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
- return 0;
-
- if (lsp_install(zvrf, fec->label, rn, re))
- return -1;
+ return;
- return 0;
+ lsp_install(zvrf, fec->label, rn, re);
}
/*
@@ -2345,7 +2421,7 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
}
if (new_client || label_change)
- return fec_change_update_lsp(zvrf, fec, old_label);
+ return fec_change_update_lsp(zvrf, fec, old_label, false);
return 0;
}
@@ -2386,7 +2462,7 @@ int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
list_isempty(fec->client_list)) {
mpls_label_t old_label = fec->label;
fec->label = MPLS_INVALID_LABEL; /* reset */
- fec_change_update_lsp(zvrf, fec, old_label);
+ fec_change_update_lsp(zvrf, fec, old_label, false);
fec_del(fec);
}
@@ -2556,7 +2632,7 @@ int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
fec_update_clients(fec);
/* Update label forwarding entries appropriately */
- ret = fec_change_update_lsp(zvrf, fec, old_label);
+ ret = fec_change_update_lsp(zvrf, fec, old_label, false);
}
return ret;
@@ -2609,7 +2685,7 @@ int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
fec_update_clients(fec);
/* Update label forwarding entries appropriately */
- return fec_change_update_lsp(zvrf, fec, old_label);
+ return fec_change_update_lsp(zvrf, fec, old_label, false);
}
/*
@@ -3794,7 +3870,7 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
if (tt->nrows > 1) {
char *table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
- XFREE(MTYPE_TMP, table);
+ XFREE(MTYPE_TMP_TTABLE, table);
}
ttable_del(tt);
}
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index dd6f960146..27f5bdbc46 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -146,7 +146,7 @@ int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *vrf);
/*
* Install dynamic LSP entry.
*/
-int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
+void zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *re);
/*
@@ -257,6 +257,12 @@ void zebra_mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
const struct zapi_labels *zl);
/*
+ * Upon reconfiguring nexthop-resolution updates, update the
+ * lsp entries accordingly.
+ */
+void zebra_mpls_fec_nexthop_resolution_update(struct zebra_vrf *zvrf);
+
+/*
* Uninstall all NHLFEs bound to a single FEC.
*
* mpls_ftn_uninstall -> Called to enqueue into early label processing
diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c
index eee9323082..0a7ed5db41 100644
--- a/zebra/zebra_nb.c
+++ b/zebra/zebra_nb.c
@@ -884,6 +884,13 @@ const struct frr_yang_module_info frr_zebra_info = {
}
},
{
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/mpls/fec-nexthop-resolution",
+ .cbs = {
+ .modify = lib_vrf_zebra_mpls_fec_nexthop_resolution_modify,
+ .destroy = lib_vrf_zebra_mpls_fec_nexthop_resolution_destroy,
+ }
+ },
+ {
.xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib",
.cbs = {
.get_next = lib_vrf_zebra_ribs_rib_get_next,
diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h
index b40ed68229..785291bc68 100644
--- a/zebra/zebra_nb.h
+++ b/zebra/zebra_nb.h
@@ -309,6 +309,10 @@ int lib_vrf_zebra_netns_table_range_create(struct nb_cb_create_args *args);
int lib_vrf_zebra_netns_table_range_destroy(struct nb_cb_destroy_args *args);
int lib_vrf_zebra_netns_table_range_start_modify(struct nb_cb_modify_args *args);
int lib_vrf_zebra_netns_table_range_end_modify(struct nb_cb_modify_args *args);
+int lib_vrf_zebra_mpls_fec_nexthop_resolution_modify(
+ struct nb_cb_modify_args *args);
+int lib_vrf_zebra_mpls_fec_nexthop_resolution_destroy(
+ struct nb_cb_destroy_args *args);
const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args);
int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args);
const void *
diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c
index ae6232a1bb..09c0091ec6 100644
--- a/zebra/zebra_nb_config.c
+++ b/zebra/zebra_nb_config.c
@@ -3781,6 +3781,59 @@ int lib_vrf_zebra_netns_table_range_end_modify(struct nb_cb_modify_args *args)
}
/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/mpls/fec-nexthop-resolution
+ */
+int lib_vrf_zebra_mpls_fec_nexthop_resolution_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct vrf *vrf;
+ struct zebra_vrf *zvrf;
+ bool fec_nexthop_resolution;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ vrf = nb_running_get_entry(args->dnode, NULL, true);
+ zvrf = vrf->info;
+
+ fec_nexthop_resolution = yang_dnode_get_bool(args->dnode, NULL);
+
+ if (zvrf->zebra_mpls_fec_nexthop_resolution == fec_nexthop_resolution)
+ return NB_OK;
+
+ zvrf->zebra_mpls_fec_nexthop_resolution = fec_nexthop_resolution;
+
+ zebra_mpls_fec_nexthop_resolution_update(zvrf);
+
+ return NB_OK;
+}
+
+int lib_vrf_zebra_mpls_fec_nexthop_resolution_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct vrf *vrf;
+ struct zebra_vrf *zvrf;
+ bool fec_nexthop_resolution;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ vrf = nb_running_get_entry(args->dnode, NULL, true);
+ zvrf = vrf->info;
+
+ fec_nexthop_resolution = DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT;
+
+ if (zvrf->zebra_mpls_fec_nexthop_resolution == fec_nexthop_resolution)
+ return NB_OK;
+
+ zvrf->zebra_mpls_fec_nexthop_resolution = fec_nexthop_resolution;
+
+ zebra_mpls_fec_nexthop_resolution_update(zvrf);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id
*/
int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args)
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index fb326b0ddf..3ac4fdd737 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -42,6 +42,10 @@
#define ZEBRA_NS_POLLING_INTERVAL_MSEC 1000
#define ZEBRA_NS_POLLING_MAX_RETRIES 200
+#if !defined(__GLIBC__)
+#define basename(src) (strrchr(src, '/') ? strrchr(src, '/') + 1 : src)
+#endif
+
DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo");
static struct event *zebra_netns_notify_current;
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 8164e2a56f..81f1411ee5 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -356,18 +356,23 @@ void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
*/
if (nh && (nh->next == NULL)) {
switch (nh->type) {
- case NEXTHOP_TYPE_IFINDEX:
- case NEXTHOP_TYPE_BLACKHOLE:
/*
* This switch case handles setting the afi different
- * for ipv4/v6 routes. Ifindex/blackhole nexthop
+ * for ipv4/v6 routes. Ifindex nexthop
* objects cannot be ambiguous, they must be Address
- * Family specific. If we get here, we will either use
- * the AF of the route, or the one we got passed from
- * here from the kernel.
+ * Family specific as that the kernel relies on these
+ * for some reason. blackholes can be v6 because the
+ * v4 kernel infrastructure allows the usage of v6
+ * blackholes in this case. if we get here, we will
+ * either use the AF of the route, or the one we got
+ * passed from here from the kernel.
*/
+ case NEXTHOP_TYPE_IFINDEX:
nhe->afi = afi;
break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ nhe->afi = AFI_IP6;
+ break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
nhe->afi = AFI_IP;
@@ -414,6 +419,14 @@ struct nhg_hash_entry *zebra_nhe_copy(const struct nhg_hash_entry *orig,
if (orig->backup_info)
nhe->backup_info = nhg_backup_copy(orig->backup_info);
+ /*
+ * This is a special case, Zebra needs to track
+ * whether or not this flag was set on a initial
+ * unresolved NHG
+ */
+ if (CHECK_FLAG(orig->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL))
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL);
+
return nhe;
}
@@ -1088,11 +1101,15 @@ void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
bool valid = false;
/*
- * If I have other nhe's depending on me, then this is a
+ * If I have other nhe's depending on me, or I have nothing
+ * I am depending on then this is a
* singleton nhe so set this nexthops flag as appropriate.
*/
- if (nhg_connected_tree_count(&nhe->nhg_depends))
+ if (nhg_connected_tree_count(&nhe->nhg_depends) ||
+ nhg_connected_tree_count(&nhe->nhg_dependents) == 0) {
+ UNSET_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_FIB);
UNSET_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
/* If anthing else in the group is valid, the group is valid */
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
@@ -1154,7 +1171,8 @@ static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe, bool install)
"%s nh id %u (flags 0x%x) associated dependent NHG %pNG install",
__func__, nhe->id, nhe->flags,
rb_node_dep->nhe);
- zebra_nhg_install_kernel(rb_node_dep->nhe);
+ zebra_nhg_install_kernel(rb_node_dep->nhe,
+ ZEBRA_ROUTE_MAX);
}
}
}
@@ -1173,7 +1191,7 @@ static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe,
(is_delete ? "deleted" : "updated"), nhe);
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
- zebra_nhg_install_kernel(nhe);
+ zebra_nhg_install_kernel(nhe, ZEBRA_ROUTE_MAX);
} else
zebra_nhg_handle_uninstall(nhe);
}
@@ -1417,6 +1435,11 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
*/
nexthop_copy_no_recurse(&lookup, nh, NULL);
+ /*
+ * So this is to intentionally cause the singleton nexthop
+ * to be created with a weight of 1.
+ */
+ lookup.weight = 1;
nhe = zebra_nhg_find_nexthop(0, &lookup, afi, type, from_dplane);
/* The copy may have allocated labels; free them if necessary. */
@@ -2651,13 +2674,6 @@ static unsigned nexthop_active_check(struct route_node *rn,
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
break;
case NEXTHOP_TYPE_IPV6:
- family = AFI_IP6;
- if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
- &mtu, vrf_id))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
- else
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
- break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
/* RFC 5549, v4 prefix with v6 NH */
if (rn->p.family != AF_INET)
@@ -2910,13 +2926,162 @@ static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg)
}
/*
+ * This function takes the start of two comparable nexthops from two different
+ * nexthop groups and walks them to see if they can be considered the same
+ * or not. This is being used to determine if zebra should reuse a nhg
+ * from the old_re to the new_re, when an interface goes down and the
+ * new nhg sent down from the upper level protocol would resolve to it
+ */
+static bool zebra_nhg_nexthop_compare(const struct nexthop *nhop,
+ const struct nexthop *old_nhop,
+ const struct route_node *rn)
+{
+ bool same = true;
+
+ while (nhop && old_nhop) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: %pRN Comparing %pNHvv(%u) to old: %pNHvv(%u)",
+ __func__, rn, nhop, nhop->flags, old_nhop,
+ old_nhop->flags);
+ if (!CHECK_FLAG(old_nhop->flags, NEXTHOP_FLAG_ACTIVE)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: %pRN Old is not active going to the next one",
+ __func__, rn);
+ old_nhop = old_nhop->next;
+ continue;
+ }
+
+ if (nexthop_same(nhop, old_nhop)) {
+ struct nexthop *new_recursive, *old_recursive;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: %pRN New and old are same, continuing search",
+ __func__, rn);
+
+ new_recursive = nhop->resolved;
+ old_recursive = old_nhop->resolved;
+
+ while (new_recursive && old_recursive) {
+ if (!nexthop_same(new_recursive, old_recursive)) {
+ same = false;
+ break;
+ }
+
+ new_recursive = new_recursive->next;
+ old_recursive = old_recursive->next;
+ }
+
+ if (new_recursive)
+ same = false;
+ else if (old_recursive) {
+ while (old_recursive) {
+ if (CHECK_FLAG(old_recursive->flags,
+ NEXTHOP_FLAG_ACTIVE))
+ break;
+ old_recursive = old_recursive->next;
+ }
+
+ if (old_recursive)
+ same = false;
+ }
+
+ if (!same)
+ break;
+
+ nhop = nhop->next;
+ old_nhop = old_nhop->next;
+ continue;
+ } else {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s:%pRN They are not the same, stopping using new nexthop entry",
+ __func__, rn);
+ same = false;
+ break;
+ }
+ }
+
+ if (nhop)
+ same = false;
+ else if (old_nhop) {
+ while (old_nhop) {
+ if (CHECK_FLAG(old_nhop->flags, NEXTHOP_FLAG_ACTIVE))
+ break;
+ old_nhop = old_nhop->next;
+ }
+
+ if (old_nhop)
+ same = false;
+ }
+
+ return same;
+}
+
+static struct nhg_hash_entry *zebra_nhg_rib_compare_old_nhe(
+ const struct route_node *rn, const struct route_entry *re,
+ struct nhg_hash_entry *new_nhe, struct nhg_hash_entry *old_nhe)
+{
+ struct nexthop *nhop, *old_nhop;
+ bool same = true;
+ struct vrf *vrf = vrf_lookup_by_id(re->vrf_id);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
+ char straddr[PREFIX_STRLEN];
+
+ prefix2str(&rn->p, straddr, sizeof(straddr));
+ zlog_debug("%s: %pRN new id: %u old id: %u", __func__, rn,
+ new_nhe->id, old_nhe->id);
+ zlog_debug("%s: %pRN NEW", __func__, rn);
+ for (ALL_NEXTHOPS(new_nhe->nhg, nhop))
+ route_entry_dump_nh(re, straddr, vrf, nhop);
+
+ zlog_debug("%s: %pRN OLD", __func__, rn);
+ for (ALL_NEXTHOPS(old_nhe->nhg, nhop))
+ route_entry_dump_nh(re, straddr, vrf, nhop);
+ }
+
+ nhop = new_nhe->nhg.nexthop;
+ old_nhop = old_nhe->nhg.nexthop;
+
+ same = zebra_nhg_nexthop_compare(nhop, old_nhop, rn);
+
+ if (same) {
+ struct nexthop_group *bnhg, *old_bnhg;
+
+ bnhg = zebra_nhg_get_backup_nhg(new_nhe);
+ old_bnhg = zebra_nhg_get_backup_nhg(old_nhe);
+
+ if (bnhg || old_bnhg) {
+ if (bnhg && !old_bnhg)
+ same = false;
+ else if (!bnhg && old_bnhg)
+ same = false;
+ else
+ same = zebra_nhg_nexthop_compare(bnhg->nexthop,
+ old_bnhg->nexthop,
+ rn);
+ }
+ }
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s:%pRN They are %sthe same, using the %s nhg entry",
+ __func__, rn, same ? "" : "not ",
+ same ? "old" : "new");
+
+ if (same)
+ return old_nhe;
+ else
+ return new_nhe;
+}
+
+/*
* Iterate over all nexthops of the given RIB entry and refresh their
* ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
* the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
*
* Return value is the new number of active nexthops.
*/
-int nexthop_active_update(struct route_node *rn, struct route_entry *re)
+int nexthop_active_update(struct route_node *rn, struct route_entry *re,
+ struct route_entry *old_re)
{
struct nhg_hash_entry *curr_nhe;
uint32_t curr_active = 0, backup_active = 0;
@@ -2972,6 +3137,11 @@ backups_done:
new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi);
+ if (old_re && old_re->type == re->type &&
+ old_re->instance == re->instance)
+ new_nhe = zebra_nhg_rib_compare_old_nhe(rn, re, new_nhe,
+ old_re->nhe);
+
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug(
"%s: re %p CHANGED: nhe %p (%pNG) => new_nhe %p (%pNG)",
@@ -3010,13 +3180,14 @@ backups_done:
* I'm pretty sure we only allow ONE level of group within group currently.
* But making this recursive just in case that ever changes.
*/
-static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp,
- uint8_t curr_index,
+static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp, uint8_t curr_index,
struct nhg_hash_entry *nhe,
+ struct nhg_hash_entry *original,
int max_num)
{
struct nhg_connected *rb_node_dep = NULL;
struct nhg_hash_entry *depend = NULL;
+ struct nexthop *nexthop;
uint8_t i = curr_index;
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
@@ -3043,8 +3214,11 @@ static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp,
if (!zebra_nhg_depends_is_empty(depend)) {
/* This is a group within a group */
- i = zebra_nhg_nhe2grp_internal(grp, i, depend, max_num);
+ i = zebra_nhg_nhe2grp_internal(grp, i, depend, nhe,
+ max_num);
} else {
+ bool found;
+
if (!CHECK_FLAG(depend->flags, NEXTHOP_GROUP_VALID)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED
|| IS_ZEBRA_DEBUG_NHG)
@@ -3085,8 +3259,37 @@ static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp,
continue;
}
+ /*
+ * So we need to create the nexthop group with
+ * the appropriate weights. The nexthops weights
+ * are stored in the fully resolved nexthops for
+ * the nhg so we need to find the appropriate
+ * nexthop associated with this and set the weight
+ * appropriately
+ */
+ found = false;
+ for (ALL_NEXTHOPS_PTR(&original->nhg, nexthop)) {
+ if (CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ if (nexthop_cmp_no_weight(depend->nhg.nexthop,
+ nexthop) != 0)
+ continue;
+
+ found = true;
+ break;
+ }
+
+ if (!found) {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED ||
+ IS_ZEBRA_DEBUG_NHG)
+ zlog_debug("%s: Nexthop ID (%u) unable to find nexthop in Nexthop Gropu Entry, something is terribly wrong",
+ __func__, depend->id);
+ continue;
+ }
grp[i].id = depend->id;
- grp[i].weight = depend->nhg.nexthop->weight;
+ grp[i].weight = nexthop->weight;
i++;
}
}
@@ -3110,10 +3313,10 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
int max_num)
{
/* Call into the recursive function */
- return zebra_nhg_nhe2grp_internal(grp, 0, nhe, max_num);
+ return zebra_nhg_nhe2grp_internal(grp, 0, nhe, nhe, max_num);
}
-void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
+void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe, uint8_t type)
{
struct nhg_connected *rb_node_dep = NULL;
@@ -3126,9 +3329,16 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
nhe);
}
+ if ((type != ZEBRA_ROUTE_CONNECT && type != ZEBRA_ROUTE_LOCAL &&
+ type != ZEBRA_ROUTE_KERNEL) &&
+ CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL)) {
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL);
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ }
+
/* Make sure all depends are installed/queued */
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
- zebra_nhg_install_kernel(rb_node_dep->nhe);
+ zebra_nhg_install_kernel(rb_node_dep->nhe, type);
}
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID) &&
@@ -3152,9 +3362,6 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
nhe);
break;
case ZEBRA_DPLANE_REQUEST_SUCCESS:
- flog_err(EC_ZEBRA_DP_INVALID_RC,
- "DPlane returned an invalid result code for attempt of installation of %pNG into the kernel",
- nhe);
break;
}
}
@@ -3480,7 +3687,7 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
zebra_nhg_set_valid_if_active(new);
- zebra_nhg_install_kernel(new);
+ zebra_nhg_install_kernel(new, ZEBRA_ROUTE_MAX);
if (old) {
/*
@@ -3716,7 +3923,8 @@ void zebra_interface_nhg_reinstall(struct interface *ifp)
"%s install nhe %pNG nh type %u flags 0x%x",
__func__, rb_node_dep->nhe, nh->type,
rb_node_dep->nhe->flags);
- zebra_nhg_install_kernel(rb_node_dep->nhe);
+ zebra_nhg_install_kernel(rb_node_dep->nhe,
+ ZEBRA_ROUTE_MAX);
/* Don't need to modify dependents if installed */
if (CHECK_FLAG(rb_node_dep->nhe->flags,
@@ -3729,6 +3937,17 @@ void zebra_interface_nhg_reinstall(struct interface *ifp)
frr_each_safe (nhg_connected_tree,
&rb_node_dep->nhe->nhg_dependents,
rb_node_dependent) {
+ struct nexthop *nhop_dependent =
+ rb_node_dependent->nhe->nhg.nexthop;
+
+ while (nhop_dependent &&
+ !nexthop_same(nhop_dependent, nh))
+ nhop_dependent = nhop_dependent->next;
+
+ if (nhop_dependent)
+ SET_FLAG(nhop_dependent->flags,
+ NEXTHOP_FLAG_ACTIVE);
+
if (IS_ZEBRA_DEBUG_NHG)
zlog_debug("%s dependent nhe %pNG Setting Reinstall flag",
__func__,
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index 3bb697aa75..435ccb0d01 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -152,6 +152,25 @@ struct nhg_hash_entry {
* when installation is successful.
*/
#define NEXTHOP_GROUP_REINSTALL (1 << 8)
+
+/*
+ * Connected routes and kernel routes received
+ * from the kernel or created by Zebra do no
+ * need to be installed. For connected, this
+ * is because the routes are in the local table
+ * but not imported and we create an amalgram
+ * route for it. For kernel routes if the route
+ * is an pre-nhg route, there is no nexthop associated
+ * with it and we should not create it until it
+ * is used by something else.
+ * The reason for this is because is that this just
+ * fills up the DPlane's nexthop slots when there
+ * are a bunch of interfaces or pre-existing routes
+ * As such let's not initially install it ( but
+ * pretend it was successful ) and if another route
+ * chooses this NHG then we can install it then.
+ */
+#define NEXTHOP_GROUP_INITIAL_DELAY_INSTALL (1 << 9)
};
/* Upper 4 bits of the NHG are reserved for indicating the NHG type */
@@ -364,7 +383,7 @@ extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
int size);
/* Dataplane install/uninstall */
-extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe);
+extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe, uint8_t type);
extern void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe);
extern void zebra_interface_nhg_reinstall(struct interface *ifp);
@@ -385,7 +404,8 @@ extern void zebra_nhg_mark_keep(void);
/* Nexthop resolution processing */
struct route_entry; /* Forward ref to avoid circular includes */
-extern int nexthop_active_update(struct route_node *rn, struct route_entry *re);
+extern int nexthop_active_update(struct route_node *rn, struct route_entry *re,
+ struct route_entry *old_re);
#ifdef _FRR_ATTRIBUTE_PRINTFRR
#pragma FRR printfrr_ext "%pNG" (const struct nhg_hash_entry *)
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 59190e9dd3..2d2be4fc78 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -316,12 +316,18 @@ static ssize_t printfrr_zebra_node(struct fbuf *buf, struct printfrr_eargs *ea,
}
#define rnode_debug(node, vrf_id, msg, ...) \
- zlog_debug("%s: (%u:%pZNt):%pZN: " msg, __func__, vrf_id, node, node, \
- ##__VA_ARGS__)
+ do { \
+ struct vrf *vrf = vrf_lookup_by_id(vrf_id); \
+ zlog_debug("%s: (%s:%pZNt):%pZN: " msg, __func__, \
+ VRF_LOGNAME(vrf), node, node, ##__VA_ARGS__); \
+ } while (0)
#define rnode_info(node, vrf_id, msg, ...) \
- zlog_info("%s: (%u:%pZNt):%pZN: " msg, __func__, vrf_id, node, node, \
- ##__VA_ARGS__)
+ do { \
+ struct vrf *vrf = vrf_lookup_by_id(vrf_id); \
+ zlog_info("%s: (%s:%pZNt):%pZN: " msg, __func__, \
+ VRF_LOGNAME(vrf), node, node, ##__VA_ARGS__); \
+ } while (0)
static char *_dump_re_status(const struct route_entry *re, char *buf,
size_t len)
@@ -605,45 +611,6 @@ struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id,
return re;
}
-struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
-{
- struct route_table *table;
- struct route_node *rn;
- struct route_entry *match = NULL;
- rib_dest_t *dest;
-
- /* Lookup table. */
- table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
- if (!table)
- return 0;
-
- rn = route_node_lookup(table, (struct prefix *)p);
-
- /* No route for this prefix. */
- if (!rn)
- return NULL;
-
- /* Unlock node. */
- route_unlock_node(rn);
- dest = rib_dest_from_rnode(rn);
-
- if (dest && dest->selected_fib
- && !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
- match = dest->selected_fib;
-
- if (!match)
- return NULL;
-
- if (match->type == ZEBRA_ROUTE_CONNECT ||
- match->type == ZEBRA_ROUTE_LOCAL)
- return match;
-
- if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED))
- return match;
-
- return NULL;
-}
-
/*
* Is this RIB labeled-unicast? It must be of type BGP and all paths
* (nexthops) must have a label.
@@ -651,8 +618,10 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
int zebra_rib_labeled_unicast(struct route_entry *re)
{
struct nexthop *nexthop = NULL;
+ struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
- if (re->type != ZEBRA_ROUTE_BGP)
+ if ((re->type != ZEBRA_ROUTE_BGP) &&
+ !zvrf->zebra_mpls_fec_nexthop_resolution)
return 0;
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop))
@@ -688,7 +657,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
/*
* Install the resolved nexthop object first.
*/
- zebra_nhg_install_kernel(re->nhe);
+ zebra_nhg_install_kernel(re->nhe, re->type);
/*
* If this is a replace to a new RE let the originator of the RE
@@ -1305,7 +1274,7 @@ static void rib_process(struct route_node *rn)
*/
if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
proto_re_changed = re;
- if (!nexthop_active_update(rn, re)) {
+ if (!nexthop_active_update(rn, re, old_fib)) {
const struct prefix *p;
struct rib_table_info *info;
@@ -1619,6 +1588,10 @@ static bool rib_compare_routes(const struct route_entry *re1,
* v6 link-locals, and we also support multiple addresses in the same
* subnet on a single interface.
*/
+ if (re1->type == ZEBRA_ROUTE_CONNECT &&
+ (re1->nhe->nhg.nexthop->ifindex == re2->nhe->nhg.nexthop->ifindex))
+ return true;
+
if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL)
return true;
@@ -2863,10 +2836,11 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
/* 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, same_count %d",
- rn, re, zebra_route_string(re->type), same, same_count);
+ rnode_debug(rn, re->vrf_id,
+ "Inserting route rn %p, re %p (%s/%s/%s) existing %p, same_count %d",
+ rn, re, zebra_route_string(re->type),
+ afi2str(ere->afi), safi2str(ere->safi), same,
+ same_count);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
route_entry_dump(
@@ -4105,9 +4079,8 @@ void rib_delnode(struct route_node *rn, struct route_entry *re)
/*
* Helper that debugs a single nexthop within a route-entry
*/
-static void _route_entry_dump_nh(const struct route_entry *re,
- const char *straddr,
- const struct nexthop *nexthop)
+void route_entry_dump_nh(const struct route_entry *re, const char *straddr,
+ const struct vrf *re_vrf, const struct nexthop *nexthop)
{
char nhname[PREFIX_STRLEN];
char backup_str[50];
@@ -4161,35 +4134,32 @@ 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] %svrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s%s",
- straddr, (nexthop->rparent ? " NH" : "NH"), nhname,
- nexthop->ifindex, label_str, vrf ? vrf->name : "Unknown",
- nexthop->vrf_id,
+ zlog_debug("%s(%s): %s %s[%u] %svrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s%s",
+ straddr, VRF_LOGNAME(re_vrf),
+ (nexthop->rparent ? " NH" : "NH"), nhname, nexthop->ifindex,
+ label_str, vrf ? vrf->name : "Unknown", nexthop->vrf_id,
wgt_str, backup_str,
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
- ? "ACTIVE "
- : ""),
- (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
- ? "FIB "
- : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE "
+ : ""),
+ (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "FIB " : ""),
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
- ? "RECURSIVE "
- : ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)
- ? "ONLINK "
- : ""),
+ ? "RECURSIVE "
+ : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK) ? "ONLINK "
+ : ""),
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)
- ? "DUPLICATE "
- : ""),
+ ? "DUPLICATE "
+ : ""),
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED)
- ? "FILTERED " : ""),
+ ? "FILTERED "
+ : ""),
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)
- ? "BACKUP " : ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE)
- ? "SRTE " : ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN)
- ? "EVPN " : ""));
-
+ ? "BACKUP "
+ : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE) ? "SRTE "
+ : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN) ? "EVPN "
+ : ""));
}
/* This function dumps the contents of a given RE entry into
@@ -4218,32 +4188,33 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
is_srcdst ? prefix2str(src_pp, srcaddr, sizeof(srcaddr))
: "",
VRF_LOGNAME(vrf), re->vrf_id);
- 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 == %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: tag == %u, nexthop_num == %u, nexthop_active_num == %u",
- straddr, re->tag, nexthop_group_nexthop_num(&(re->nhe->nhg)),
+ zlog_debug("%s(%s): uptime == %lu, type == %u, instance == %d, table == %d",
+ straddr, VRF_LOGNAME(vrf), (unsigned long)re->uptime,
+ re->type, re->instance, re->table);
+ zlog_debug("%s(%s): metric == %u, mtu == %u, distance == %u, flags == %sstatus == %s",
+ straddr, VRF_LOGNAME(vrf), 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(%s): tag == %u, nexthop_num == %u, nexthop_active_num == %u",
+ straddr, VRF_LOGNAME(vrf), re->tag,
+ nexthop_group_nexthop_num(&(re->nhe->nhg)),
nexthop_group_active_nexthop_num(&(re->nhe->nhg)));
/* Dump nexthops */
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop))
- _route_entry_dump_nh(re, straddr, nexthop);
+ route_entry_dump_nh(re, straddr, vrf, nexthop);
if (zebra_nhg_get_backup_nhg(re->nhe)) {
- zlog_debug("%s: backup nexthops:", straddr);
+ zlog_debug("%s(%s): backup nexthops:", straddr,
+ VRF_LOGNAME(vrf));
nhg = zebra_nhg_get_backup_nhg(re->nhe);
for (ALL_NEXTHOPS_PTR(nhg, nexthop))
- _route_entry_dump_nh(re, straddr, nexthop);
+ route_entry_dump_nh(re, straddr, vrf, nexthop);
}
- zlog_debug("%s: dump complete", straddr);
+ zlog_debug("%s(%s): dump complete", straddr, VRF_LOGNAME(vrf));
}
static int rib_meta_queue_gr_run_add(struct meta_queue *mq, void *data)
@@ -4264,11 +4235,14 @@ static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data)
listnode_add(mq->subq[META_QUEUE_EARLY_ROUTE], data);
mq->size++;
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("Route %pFX(%u) (%s) queued for processing into sub-queue %s",
- &ere->p, ere->re->vrf_id,
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ struct vrf *vrf = vrf_lookup_by_id(ere->re->vrf_id);
+
+ zlog_debug("Route %pFX(%s) (%s) queued for processing into sub-queue %s",
+ &ere->p, VRF_LOGNAME(vrf),
ere->deletion ? "delete" : "add",
subqueue2str(META_QUEUE_EARLY_ROUTE));
+ }
return 0;
}
@@ -4370,19 +4344,55 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
return -1;
/* We either need nexthop(s) or an existing nexthop id */
- if (ng == NULL && re->nhe_id == 0)
+ if (ng == NULL && re->nhe_id == 0) {
+ zebra_rib_route_entry_free(re);
return -1;
+ }
/*
* Use a temporary nhe to convey info to the common/main api.
*/
zebra_nhe_init(&nhe, afi, (ng ? ng->nexthop : NULL));
- if (ng)
+ if (ng) {
nhe.nhg.nexthop = ng->nexthop;
- else if (re->nhe_id > 0)
+
+ if (re->type == ZEBRA_ROUTE_CONNECT ||
+ re->type == ZEBRA_ROUTE_LOCAL ||
+ re->type == ZEBRA_ROUTE_KERNEL)
+ SET_FLAG(nhe.flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL);
+ } else if (re->nhe_id > 0)
nhe.id = re->nhe_id;
n = zebra_nhe_copy(&nhe, 0);
+
+ if (re->type == ZEBRA_ROUTE_KERNEL) {
+ struct interface *ifp;
+ struct connected *connected;
+
+ if (p->family == AF_INET6 &&
+ IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) {
+ zebra_nhg_free(n);
+ zebra_rib_route_entry_free(re);
+ return -1;
+ }
+
+ ifp = if_lookup_prefix(p, re->vrf_id);
+ if (ifp) {
+ connected = connected_lookup_prefix(ifp, p);
+
+ if (connected && !CHECK_FLAG(connected->flags,
+ ZEBRA_IFA_NOPREFIXROUTE)) {
+ zebra_nhg_free(n);
+ zebra_rib_route_entry_free(re);
+ return -1;
+ }
+
+ if (ng && ng->nexthop &&
+ ifp->ifindex == ng->nexthop->ifindex)
+ re->type = ZEBRA_ROUTE_CONNECT;
+ }
+ }
+
ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup);
/* In error cases, free the route also */
@@ -4393,8 +4403,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
}
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,
+ unsigned short instance, uint32_t flags, const struct prefix *p,
+ const 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)
{
@@ -4458,6 +4468,9 @@ static const char *rib_update_event2str(enum rib_update_event event)
const char *ret = "UNKNOWN";
switch (event) {
+ case RIB_UPDATE_INTERFACE_DOWN:
+ ret = "RIB_UPDATE_INTERFACE_DOWN";
+ break;
case RIB_UPDATE_KERNEL:
ret = "RIB_UPDATE_KERNEL";
break;
@@ -4474,15 +4487,56 @@ static const char *rib_update_event2str(enum rib_update_event event)
return ret;
}
+/*
+ * We now keep kernel routes, but we don't have any
+ * trigger events for them when they are implicitly
+ * deleted. Since we are already walking the
+ * entire table on a down event let's look at
+ * the few kernel routes we may have
+ */
+static void
+rib_update_handle_kernel_route_down_possibility(struct route_node *rn,
+ struct route_entry *re)
+{
+ struct nexthop *nexthop = NULL;
+ bool alive = false;
+
+ for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
+ struct interface *ifp = if_lookup_by_index(nexthop->ifindex,
+ nexthop->vrf_id);
+
+ if (ifp && if_is_up(ifp)) {
+ alive = true;
+ break;
+ }
+ }
+
+ if (!alive) {
+ struct rib_table_info *rib_table = srcdest_rnode_table_info(rn);
+ const struct prefix *p;
+ const struct prefix_ipv6 *src_p;
+
+ srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p);
+
+ rib_delete(rib_table->afi, rib_table->safi, re->vrf_id,
+ re->type, re->instance, re->flags, p, src_p, NULL, 0,
+ re->table, re->metric, re->distance, true);
+ }
+}
+
/* Schedule route nodes to be processed if they match the type */
-static void rib_update_route_node(struct route_node *rn, int type)
+static void rib_update_route_node(struct route_node *rn, int type,
+ enum rib_update_event event)
{
struct route_entry *re, *next;
bool re_changed = false;
RNODE_FOREACH_RE_SAFE (rn, re, next) {
- if (type == ZEBRA_ROUTE_ALL || type == re->type) {
+ if (event == RIB_UPDATE_INTERFACE_DOWN && type == re->type &&
+ type == ZEBRA_ROUTE_KERNEL)
+ rib_update_handle_kernel_route_down_possibility(rn, re);
+ else if (type == ZEBRA_ROUTE_ALL || type == re->type) {
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
re_changed = true;
}
@@ -4522,20 +4576,24 @@ void rib_update_table(struct route_table *table, enum rib_update_event event,
/*
* If we are looking at a route node and the node
* has already been queued we don't
- * need to queue it up again
+ * need to queue it up again, unless it is
+ * an interface down event as that we need
+ * to process this no matter what.
*/
- if (rn->info
- && CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
- RIB_ROUTE_ANY_QUEUED))
+ if (rn->info &&
+ CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
+ RIB_ROUTE_ANY_QUEUED) &&
+ event != RIB_UPDATE_INTERFACE_DOWN)
continue;
switch (event) {
+ case RIB_UPDATE_INTERFACE_DOWN:
case RIB_UPDATE_KERNEL:
- rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL);
+ rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL, event);
break;
case RIB_UPDATE_RMAP_CHANGE:
case RIB_UPDATE_OTHER:
- rib_update_route_node(rn, rtype);
+ rib_update_route_node(rn, rtype, event);
break;
case RIB_UPDATE_MAX:
break;
@@ -4543,7 +4601,7 @@ void rib_update_table(struct route_table *table, enum rib_update_event event,
}
}
-static void rib_update_handle_vrf_all(enum rib_update_event event, int rtype)
+void rib_update_handle_vrf_all(enum rib_update_event event, int rtype)
{
struct zebra_router_table *zrt;
@@ -5019,6 +5077,17 @@ static int rib_dplane_results(struct dplane_ctx_list_head *ctxlist)
return 0;
}
+uint32_t zebra_rib_dplane_results_count(void)
+{
+ uint32_t count;
+
+ frr_with_mutex (&dplane_mutex) {
+ count = dplane_ctx_queue_count(&rib_dplane_q);
+ }
+
+ return count;
+}
+
/*
* Ensure there are no empty slots in the route_info array.
* Every route type in zebra should be present there.
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 303a81bb3e..89317be74d 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -1344,13 +1344,17 @@ static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json)
}
if (rnh->state) {
- if (json)
+ if (json) {
json_object_string_add(
json_nht, "resolvedProtocol",
zebra_route_string(rnh->state->type));
- else
- vty_out(vty, " resolved via %s\n",
- zebra_route_string(rnh->state->type));
+ json_object_string_addf(json_nht, "prefix", "%pFX",
+ &rnh->resolved_route);
+ } else {
+ vty_out(vty, " resolved via %s, prefix %pFX\n",
+ zebra_route_string(rnh->state->type),
+ &rnh->resolved_route);
+ }
for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
nexthop = nexthop->next) {
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index 8d6b2f3476..4022c1a26f 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -343,7 +343,7 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack,
#endif
zrouter.asic_notification_nexthop_control = false;
- zrouter.nexthop_weight_scale_value = 255;
+ zrouter.nexthop_weight_scale_value = 254;
#ifdef HAVE_SCRIPTING
zebra_script_init();
diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c
index 1c6d58159e..4b4f523253 100644
--- a/zebra/zebra_snmp.c
+++ b/zebra/zebra_snmp.c
@@ -229,6 +229,8 @@ static int proto_trans(int type)
return 3; /* static route */
case ZEBRA_ROUTE_RIP:
return 8; /* rip */
+ case ZEBRA_ROUTE_ISIS:
+ return 9;
case ZEBRA_ROUTE_RIPNG:
return 1; /* shouldn't happen */
case ZEBRA_ROUTE_OSPF:
@@ -237,6 +239,8 @@ static int proto_trans(int type)
return 1; /* shouldn't happen */
case ZEBRA_ROUTE_BGP:
return 14; /* bgp */
+ case ZEBRA_ROUTE_EIGRP:
+ return 16;
default:
return 1; /* other */
}
@@ -253,9 +257,11 @@ static void check_replace(struct route_node *np2, struct route_entry *re2,
return;
}
- if (prefix_cmp(&(*np)->p, &np2->p) < 0)
+ if (in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4,
+ (uint8_t *)&np2->p.u.prefix4) < 0)
return;
- if (prefix_cmp(&(*np)->p, &np2->p) > 0) {
+ if (in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4,
+ (uint8_t *)&np2->p.u.prefix4) > 0) {
*np = np2;
*re = re2;
return;
@@ -298,14 +304,8 @@ static void get_fwtable_route_node(struct variable *v, oid objid[],
int i;
/* Init index variables */
-
- pnt = (uint8_t *)&dest;
- for (i = 0; i < 4; i++)
- *pnt++ = 0;
-
- pnt = (uint8_t *)&nexthop;
- for (i = 0; i < 4; i++)
- *pnt++ = 0;
+ memset(&dest, 0, sizeof(dest));
+ memset(&nexthop, 0, sizeof(nexthop));
proto = 0;
policy = 0;
@@ -497,23 +497,23 @@ static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len,
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC1:
- result = 0;
+ result = re->metric;
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC2:
- result = 0;
+ result = -1;
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC3:
- result = 0;
+ result = -1;
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC4:
- result = 0;
+ result = -1;
*val_len = sizeof(int);
return (uint8_t *)&result;
case IPFORWARDMETRIC5:
- result = 0;
+ result = -1;
*val_len = sizeof(int);
return (uint8_t *)&result;
default:
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index c664a9c69f..5a80524149 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -969,7 +969,7 @@ static int zebra_sr_config(struct vty *vty)
&srv6->encap_src_addr);
}
}
- if (zebra_srv6_is_enable()) {
+ if (srv6 && zebra_srv6_is_enable()) {
vty_out(vty, " locators\n");
for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
inet_ntop(AF_INET6, &locator->prefix.prefix,
diff --git a/zebra/zebra_trace.h b/zebra/zebra_trace.h
index 17528c4bf1..6451562466 100644
--- a/zebra/zebra_trace.h
+++ b/zebra/zebra_trace.h
@@ -70,20 +70,6 @@ TRACEPOINT_EVENT(
TRACEPOINT_EVENT(
frr_zebra,
- netlink_interface_addr,
- TP_ARGS(
- struct nlmsghdr *, header,
- ns_id_t, ns_id,
- int, startup),
- TP_FIELDS(
- ctf_integer_hex(intptr_t, header, header)
- ctf_integer(uint32_t, ns_id, ns_id)
- ctf_integer(uint32_t, startup, startup)
- )
- )
-
-TRACEPOINT_EVENT(
- frr_zebra,
netlink_route_change_read_unicast,
TP_ARGS(
struct nlmsghdr *, header,
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index 5cbfab1ddc..f97138c811 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -173,6 +173,7 @@ struct zebra_vrf {
bool zebra_rnh_ip_default_route;
bool zebra_rnh_ipv6_default_route;
+ bool zebra_mpls_fec_nexthop_resolution;
};
#define PROTO_RM_NAME(zvrf, afi, rtype) zvrf->proto_rm[afi][rtype].name
#define NHT_RM_NAME(zvrf, afi, rtype) zvrf->nht_rm[afi][rtype].name
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 5742c38e23..3bf20ff42e 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -891,6 +891,9 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
dest = rib_dest_from_rnode(rn);
+ if (longer_prefix_p && !prefix_match(longer_prefix_p, &rn->p))
+ continue;
+
RNODE_FOREACH_RE (rn, re) {
if (use_fib && re != dest->selected_fib)
continue;
@@ -898,10 +901,6 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
if (tag && re->tag != tag)
continue;
- if (longer_prefix_p
- && !prefix_match(longer_prefix_p, &rn->p))
- continue;
-
/* This can only be true when the afi is IPv4 */
if (supernets_only) {
addr = ntohl(rn->p.u.prefix4.s_addr);
@@ -1196,6 +1195,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe,
json_object_string_add(json, "uptime", up_str);
json_object_string_add(json, "vrf",
vrf_id_to_name(nhe->vrf_id));
+ json_object_string_add(json, "afi", afi2str(nhe->afi));
} else {
vty_out(vty, "ID: %u (%s)\n", nhe->id,
@@ -1209,7 +1209,8 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe,
vty_out(vty, "\n");
vty_out(vty, " Uptime: %s\n", up_str);
- vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id));
+ vty_out(vty, " VRF: %s(%s)\n", vrf_id_to_name(nhe->vrf_id),
+ afi2str(nhe->afi));
}
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
@@ -1229,6 +1230,13 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe,
else
vty_out(vty, ", Installed");
}
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL)) {
+ if (json)
+ json_object_boolean_true_add(json,
+ "initialDelay");
+ else
+ vty_out(vty, ", Initial Delay");
+ }
if (!json)
vty_out(vty, "\n");
}
@@ -3909,7 +3917,7 @@ DEFUN (show_zebra,
out = ttable_dump(table, "\n");
vty_out(vty, "%s\n", out);
- XFREE(MTYPE_TMP, out);
+ XFREE(MTYPE_TMP_TTABLE, out);
ttable_del(table);
vty_out(vty,
@@ -4143,12 +4151,6 @@ DEFUN (zebra_show_routing_tables_summary,
return CMD_SUCCESS;
}
-/* Table configuration write function. */
-static int config_write_table(struct vty *vty)
-{
- return 0;
-}
-
/* IPForwarding configuration write function. */
static int config_write_forwarding(struct vty *vty)
{
@@ -4325,14 +4327,6 @@ static struct cmd_node protocol_node = {
.prompt = "",
.config_write = config_write_protocol,
};
-/* table node for routing tables. */
-static int config_write_table(struct vty *vty);
-static struct cmd_node table_node = {
- .name = "table",
- .node = TABLE_NODE,
- .prompt = "",
- .config_write = config_write_table,
-};
static int config_write_forwarding(struct vty *vty);
static struct cmd_node forwarding_node = {
.name = "forwarding",
@@ -4345,7 +4339,6 @@ static struct cmd_node forwarding_node = {
void zebra_vty_init(void)
{
/* Install configuration write function. */
- install_node(&table_node);
install_node(&forwarding_node);
install_element(VIEW_NODE, &show_ip_forwarding_cmd);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index a731f7f278..07e3996643 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -161,9 +161,11 @@ void zserv_log_message(const char *errmsg, struct stream *msg,
if (errmsg)
zlog_debug("%s", errmsg);
if (hdr) {
+ struct vrf *vrf = vrf_lookup_by_id(hdr->vrf_id);
+
zlog_debug(" Length: %d", hdr->length);
zlog_debug("Command: %s", zserv_command_string(hdr->command));
- zlog_debug(" VRF: %u", hdr->vrf_id);
+ zlog_debug(" VRF: %s(%u)", VRF_LOGNAME(vrf), hdr->vrf_id);
}
stream_hexdump(msg);
}
@@ -425,11 +427,13 @@ static void zserv_read(struct event *thread)
}
/* Debug packet information. */
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("zebra message[%s:%u:%u] comes from socket [%d]",
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(hdr.vrf_id);
+
+ zlog_debug("zebra message[%s:%s:%u] comes from socket [%d]",
zserv_command_string(hdr.command),
- hdr.vrf_id, hdr.length,
- sock);
+ VRF_LOGNAME(vrf), hdr.length, sock);
+ }
stream_set_getp(client->ibuf_work, 0);
struct stream *msg = stream_dup(client->ibuf_work);