From d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 17 Nov 2024 07:11:26 +0100 Subject: Merging upstream version 10.2. Signed-off-by: Daniel Baumann --- .clang-format | 6 +- alpine/APKBUILD.in | 2 + babeld/babel_interface.c | 28 +- babeld/babel_interface.h | 1 + babeld/babel_main.c | 4 +- babeld/babeld.c | 9 +- babeld/babeld.h | 1 + babeld/kernel.c | 8 +- babeld/message.c | 16 +- babeld/route.c | 2 +- babeld/util.c | 9 +- babeld/util.h | 8 +- bfdd/bfd.c | 82 +- bfdd/bfd.h | 183 +- bfdd/bfd_packet.c | 4 +- bfdd/bfdctl.h | 157 - bfdd/bfdd.c | 27 +- bfdd/bfdd_cli.c | 52 +- bfdd/bfdd_vty.c | 15 +- bfdd/config.c | 592 --- bfdd/control.c | 844 ---- bfdd/dplane.c | 2 +- bfdd/ptm_adapter.c | 9 +- bfdd/subdir.am | 3 - bgpd/bgp_addpath.c | 6 +- bgpd/bgp_addpath.h | 6 +- bgpd/bgp_attr.c | 376 +- bgpd/bgp_attr.h | 59 +- bgpd/bgp_attr_evpn.c | 36 +- bgpd/bgp_attr_evpn.h | 9 +- bgpd/bgp_bmp.c | 40 +- bgpd/bgp_btoa.c | 2 +- bgpd/bgp_clist.c | 6 +- bgpd/bgp_clist.h | 4 + bgpd/bgp_community.c | 7 +- bgpd/bgp_damp.c | 3 +- bgpd/bgp_debug.c | 4 +- bgpd/bgp_ecommunity.c | 63 +- bgpd/bgp_ecommunity.h | 4 +- bgpd/bgp_evpn.c | 362 +- bgpd/bgp_evpn.h | 4 + bgpd/bgp_evpn_mh.c | 199 +- bgpd/bgp_evpn_mh.h | 2 + bgpd/bgp_evpn_private.h | 2 +- bgpd/bgp_evpn_vty.c | 39 +- bgpd/bgp_flowspec.c | 2 +- bgpd/bgp_flowspec_util.c | 44 +- bgpd/bgp_fsm.c | 439 +- bgpd/bgp_fsm.h | 5 +- bgpd/bgp_label.c | 4 +- bgpd/bgp_mac.c | 7 +- bgpd/bgp_main.c | 36 +- bgpd/bgp_memory.c | 2 + bgpd/bgp_memory.h | 2 + bgpd/bgp_mpath.c | 438 +- bgpd/bgp_mpath.h | 29 +- bgpd/bgp_mplsvpn.c | 401 +- bgpd/bgp_mplsvpn.h | 2 + bgpd/bgp_mplsvpn_snmp.c | 5 + bgpd/bgp_network.c | 9 +- bgpd/bgp_network.h | 1 + bgpd/bgp_nexthop.c | 2 +- bgpd/bgp_nexthop.h | 3 +- bgpd/bgp_nht.c | 84 +- bgpd/bgp_open.c | 103 +- bgpd/bgp_packet.c | 74 +- bgpd/bgp_pbr.c | 200 +- bgpd/bgp_route.c | 528 ++- bgpd/bgp_route.h | 32 +- bgpd/bgp_routemap.c | 134 +- bgpd/bgp_rpki.c | 77 - bgpd/bgp_script.h | 5 +- bgpd/bgp_snmp.c | 22 + bgpd/bgp_snmp_bgp4v2.c | 4 +- bgpd/bgp_updgrp.c | 18 +- bgpd/bgp_updgrp_packet.c | 18 +- bgpd/bgp_vty.c | 826 ++-- bgpd/bgp_vty.h | 52 +- bgpd/bgp_zebra.c | 523 ++- bgpd/bgp_zebra.h | 7 + bgpd/bgpd.c | 508 ++- bgpd/bgpd.h | 147 +- bgpd/rfapi/vnc_export_bgp.c | 46 +- configure.ac | 13 +- doc/developer/bgpd.rst | 1 + doc/developer/conf.py | 43 +- doc/developer/mgmtd-dev.rst | 2 +- doc/developer/northbound/yang-tools.rst | 4 +- doc/developer/ospf-ls-retrans.rst | 69 + doc/developer/ospf.rst | 1 + doc/developer/packaging-debian.rst | 2 + doc/developer/packaging-redhat.rst | 31 +- doc/developer/scripting.rst | 5 +- doc/developer/topotests.rst | 68 +- doc/developer/workflow.rst | 77 +- doc/manpages/bfd-options.rst | 35 +- doc/manpages/conf.py | 2 +- doc/user/about.rst | 533 +++ doc/user/basics.rst | 23 + doc/user/bfd.rst | 34 +- doc/user/bgp.rst | 90 +- doc/user/conf.py | 83 +- doc/user/index.rst | 81 +- doc/user/installation.rst | 31 +- doc/user/introduction.rst | 13 + doc/user/ipv6.rst | 3 +- doc/user/isisd.rst | 2 +- doc/user/ldpd.rst | 2 +- doc/user/nhrpd.rst | 6 + doc/user/ospfd.rst | 12 +- doc/user/overview.rst | 574 --- doc/user/pim.rst | 236 +- doc/user/pimv6.rst | 89 +- doc/user/protocols.rst | 35 + doc/user/routemap.rst | 2 +- doc/user/snmptrap.rst | 6 + doc/user/subdir.am | 2 +- doc/user/zebra.rst | 100 +- docker/alpine/Dockerfile | 6 +- docker/alpine/libyang/APKBUILD | 2 + isisd/isis_adjacency.c | 26 +- isisd/isis_circuit.c | 4 +- isisd/isis_cli.c | 4 +- isisd/isis_events.c | 5 + isisd/isis_lfa.c | 8 +- isisd/isis_lfa.h | 2 +- isisd/isis_lsp.c | 104 +- isisd/isis_lsp.h | 2 + isisd/isis_main.c | 6 + isisd/isis_misc.c | 8 +- isisd/isis_mt.c | 14 +- isisd/isis_nb_config.c | 197 +- isisd/isis_nb_state.c | 2 + isisd/isis_snmp.c | 8 + isisd/isis_spf.c | 275 +- isisd/isis_spf.h | 3 +- isisd/isis_sr.c | 52 +- isisd/isis_srv6.c | 203 +- isisd/isis_srv6.h | 14 +- isisd/isis_te.c | 49 +- isisd/isis_te.h | 3 + isisd/isis_tlvs.c | 934 +---- isisd/isis_zebra.c | 429 +- isisd/isis_zebra.h | 7 + isisd/isisd.c | 42 +- isisd/isisd.h | 3 + lib/agentx.c | 12 + lib/bfd.c | 6 + lib/bfd.h | 8 +- lib/command.c | 6 +- lib/command.h | 26 +- lib/command_graph.c | 3 + lib/command_graph.h | 3 + lib/command_py.c | 253 +- lib/darr.h | 37 + lib/debug.c | 63 +- lib/debug.h | 49 +- lib/elf_py.c | 2 +- lib/event.c | 55 +- lib/flex_algo.c | 21 +- lib/flex_algo.h | 3 +- lib/frrcu.h | 2 +- lib/frrlua.c | 85 +- lib/frrlua.h | 3 + lib/frrscript.c | 13 + lib/frrscript.h | 2 + lib/grammar_sandbox_main.c | 2 +- lib/hash.c | 2 +- lib/hash.h | 12 + lib/libfrr.c | 66 +- lib/libfrr.h | 38 +- lib/libospf.h | 2 + lib/link_state.c | 36 +- lib/link_state.h | 6 + lib/linklist.h | 12 + lib/log.c | 7 +- lib/memory.c | 1 + lib/memory.h | 1 + lib/mgmt_be_client.c | 32 +- lib/mgmt_be_client.h | 5 - lib/mgmt_fe_client.c | 30 +- lib/mgmt_fe_client.h | 5 - lib/mgmt_msg_native.c | 45 + lib/mgmt_msg_native.h | 116 +- lib/module.c | 12 + lib/module.h | 1 + lib/nexthop.c | 48 +- lib/nexthop.h | 4 + lib/nexthop_group.c | 21 +- lib/nexthop_group.h | 5 +- lib/northbound.c | 40 +- lib/northbound.h | 21 +- lib/northbound_cli.c | 106 +- lib/northbound_oper.c | 48 +- lib/northbound_sysrepo.c | 26 +- lib/openbsd-queue.h | 16 + lib/openbsd-tree.h | 15 + lib/routemap_cli.c | 75 +- lib/seqlock.c | 33 + lib/smux.h | 1 + lib/sockopt.h | 10 + lib/srv6.c | 225 +- lib/srv6.h | 139 + lib/subdir.am | 25 +- lib/termtable.c | 54 +- lib/termtable.h | 17 +- lib/vector.c | 51 +- lib/vector.h | 22 +- lib/vty.c | 30 +- lib/vty.h | 7 + lib/yang.c | 16 +- lib/yang.h | 13 +- lib/yang_translator.c | 4 +- lib/zclient.c | 195 +- lib/zclient.h | 52 +- mgmtd/.gitignore | 1 + mgmtd/mgmt.c | 16 +- mgmtd/mgmt_be_adapter.c | 4 +- mgmtd/mgmt_fe_adapter.c | 281 +- mgmtd/mgmt_fe_adapter.h | 12 +- mgmtd/mgmt_main.c | 2 +- mgmtd/mgmt_txn.c | 22 +- mgmtd/mgmt_txn.h | 28 + mgmtd/mgmt_vty.c | 42 - nhrpd/nhrp_interface.c | 2 + nhrpd/nhrp_nhs.c | 4 +- nhrpd/nhrp_packet.c | 27 +- nhrpd/nhrp_peer.c | 162 +- nhrpd/nhrp_protocol.h | 1 + nhrpd/nhrp_shortcut.c | 98 +- nhrpd/nhrp_vty.c | 74 +- nhrpd/nhrpd.h | 17 +- nhrpd/subdir.am | 4 + ospf6d/ospf6_abr.c | 25 +- ospf6d/ospf6_abr.h | 16 - ospf6d/ospf6_asbr.c | 27 +- ospf6d/ospf6_asbr.h | 11 - ospf6d/ospf6_flood.c | 1 + ospf6d/ospf6_gr.c | 13 +- ospf6d/ospf6_gr.h | 53 +- ospf6d/ospf6_gr_helper.c | 31 +- ospf6d/ospf6_interface.c | 3 +- ospf6d/ospf6_intra.c | 260 +- ospf6d/ospf6_intra.h | 76 +- ospf6d/ospf6_lsa.c | 83 +- ospf6d/ospf6_lsa.h | 102 + ospf6d/ospf6_lsdb.c | 3 +- ospf6d/ospf6_message.c | 12 +- ospf6d/ospf6_neighbor.c | 1 + ospf6d/ospf6_nssa.c | 21 +- ospf6d/ospf6_proto.h | 5 +- ospf6d/ospf6_snmp.c | 4 - ospf6d/ospf6_spf.c | 8 +- ospf6d/ospf6_tlv.h | 55 + ospf6d/ospf6_top.c | 1 + ospf6d/ospf6_zebra.c | 1 + ospf6d/ospf6d.c | 1 + ospf6d/subdir.am | 1 + ospfclient/subdir.am | 3 + ospfd/ospf_abr.c | 9 +- ospfd/ospf_asbr.c | 5 +- ospfd/ospf_flood.c | 198 +- ospfd/ospf_flood.h | 35 + ospfd/ospf_interface.c | 49 +- ospfd/ospf_interface.h | 20 +- ospfd/ospf_ism.c | 14 +- ospfd/ospf_lsdb.c | 53 + ospfd/ospf_lsdb.h | 23 + ospfd/ospf_main.c | 30 +- ospfd/ospf_memory.c | 2 + ospfd/ospf_memory.h | 2 + ospfd/ospf_neighbor.c | 8 +- ospfd/ospf_neighbor.h | 7 +- ospfd/ospf_nsm.c | 6 +- ospfd/ospf_packet.c | 346 +- ospfd/ospf_packet.h | 7 +- ospfd/ospf_ri.c | 11 - ospfd/ospf_sr.c | 3 +- ospfd/ospf_vty.c | 361 +- ospfd/ospf_zebra.c | 188 +- ospfd/ospfd.c | 16 +- pathd/path_cli.c | 34 +- pathd/path_pcep.c | 7 +- pathd/path_pcep.h | 35 +- pathd/path_pcep_cli.c | 118 +- pathd/path_ted.c | 42 +- pathd/path_ted.h | 24 +- pathd/pathd.c | 33 +- pathd/pathd.h | 3 - pbrd/pbr_debug.c | 55 +- pbrd/pbr_debug.h | 22 - pbrd/pbr_vrf.c | 2 + pbrd/pbr_vty.c | 27 +- pimd/pim6_cmd.c | 1346 +++++- pimd/pim6_main.c | 3 +- pimd/pim6_mld.c | 12 +- pimd/pim_addr.h | 6 + pimd/pim_autorp.c | 1166 ++++++ pimd/pim_autorp.h | 158 + pimd/pim_bsm.c | 881 +++- pimd/pim_bsm.h | 187 +- pimd/pim_bsr_rpdb.c | 634 +++ pimd/pim_cmd.c | 3727 ++++++++++++++--- pimd/pim_cmd.h | 1 + pimd/pim_cmd_common.c | 574 ++- pimd/pim_cmd_common.h | 27 +- pimd/pim_iface.c | 373 +- pimd/pim_iface.h | 13 +- pimd/pim_igmp.c | 8 +- pimd/pim_igmp.h | 9 + pimd/pim_instance.c | 30 +- pimd/pim_instance.h | 3 + pimd/pim_main.c | 3 +- pimd/pim_memory.c | 2 + pimd/pim_memory.h | 2 + pimd/pim_msdp.c | 64 +- pimd/pim_msdp.h | 37 +- pimd/pim_msdp_packet.c | 164 +- pimd/pim_msdp_packet.h | 2 + pimd/pim_msdp_socket.c | 280 +- pimd/pim_msdp_socket.h | 3 + pimd/pim_msg.h | 2 + pimd/pim_nb.c | 196 +- pimd/pim_nb.h | 90 +- pimd/pim_nb_config.c | 1201 +++++- pimd/pim_nht.c | 82 +- pimd/pim_nht.h | 9 +- pimd/pim_pim.c | 121 +- pimd/pim_pim.h | 5 +- pimd/pim_rp.c | 43 +- pimd/pim_rp.h | 9 +- pimd/pim_sock.c | 30 + pimd/pim_sock.h | 3 + pimd/pim_tib.c | 31 +- pimd/pim_tib.h | 3 + pimd/pim_tlv.c | 6 - pimd/pim_vty.c | 131 +- pimd/pim_zebra.c | 4 + pimd/pimd.h | 4 + pimd/subdir.am | 9 +- python/firstheader.py | 2 +- python/makefile.py | 2 +- python/xref2vtysh.py | 166 +- python/xrelfo.py | 18 +- redhat/frr.logrotate | 8 + redhat/frr.spec.in | 87 +- ripd/ripd.c | 5 +- ripngd/ripngd.c | 5 +- sharpd/sharp_main.c | 9 + sharpd/sharp_vty.c | 16 +- sharpd/sharp_zebra.c | 13 +- sharpd/sharp_zebra.h | 4 +- snapcraft/scripts/bfdd-service | 3 +- snapcraft/snapcraft.yaml.in | 2 +- staticd/static_debug.c | 71 +- staticd/static_debug.h | 16 - staticd/static_vty.c | 10 - tests/bgpd/subdir.am | 11 - tests/bgpd/test_mpath.c | 482 --- tests/bgpd/test_mpath.py | 10 - tests/bgpd/test_peer_attr.c | 4 +- tests/helpers/c/main.c | 4 +- tests/isisd/test_fuzz_isis_tlv_tests.h.gz | Bin 221814 -> 221875 bytes tests/isisd/test_isis_spf.c | 25 +- tests/isisd/test_isis_spf.refout | 4266 +++++++++++--------- tests/lib/cli/common_cli.c | 4 +- tests/lib/cli/test_cli.refout.in | 2 - tests/lib/cli/test_commands.c | 4 +- tests/lib/northbound/test_oper_data.c | 4 +- tests/lib/subdir.am | 2 +- tests/lib/test_atomlist.c | 18 +- tests/lib/test_darr.c | 27 + tests/lib/test_frrlua.c | 16 + tests/lib/test_grpc.cpp | 5 +- tests/lib/test_seqlock.c | 5 +- tests/lib/test_ttable.c | 36 +- tests/ospf6d/test_lsdb.c | 1 + tests/topotests/all_protocol_startup/r1/ip_nht.ref | 32 +- .../all_protocol_startup/r1/ipv4_routes.ref | 40 +- .../topotests/all_protocol_startup/r1/ipv6_nht.ref | 12 +- .../all_protocol_startup/r1/ipv6_routes.ref | 62 +- .../r1/show_ip_ospf_interface.ref | 2 + .../test_all_protocol_startup.py | 65 +- tests/topotests/babel_topo1/test_babel_topo1.py | 2 - tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf | 1 + tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf | 1 + .../bfd_ospf_topo1/test_bfd_ospf_topo1.py | 1 - tests/topotests/bfd_topo3/test_bfd_topo3.py | 2 +- .../topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py | 2 +- .../bgp_accept_own/test_bgp_accept_own.py | 2 +- .../test_bgp_addpath_best_selected.py | 2 +- .../bgp_addpath_graceful_restart/__init__.py | 0 .../bgp_addpath_graceful_restart/r1/frr.conf | 23 + .../bgp_addpath_graceful_restart/r2/frr.conf | 28 + .../bgp_addpath_graceful_restart/r3/frr.conf | 13 + .../test_bgp_addpath_graceful_restart.py | 132 + tests/topotests/bgp_addpath_llgr/__init__.py | 0 tests/topotests/bgp_addpath_llgr/r1/frr.conf | 23 + tests/topotests/bgp_addpath_llgr/r2/frr.conf | 29 + tests/topotests/bgp_addpath_llgr/r3/frr.conf | 14 + .../bgp_addpath_llgr/test_bgp_addpath_llgr.py | 131 + .../test_bgp_addpath_paths_limit.py | 2 +- .../test_bgp_aggregate_address_matching_med.py | 2 +- .../test_bgp_aggregate-address_origin.py | 6 +- .../test_bgp_aggregate-address_route-map.py | 2 +- .../test_bgp_aggregator_zero.py | 4 +- tests/topotests/bgp_aigp/r1/ospfd.conf | 2 +- tests/topotests/bgp_aigp/r2/bgpd.conf | 2 + tests/topotests/bgp_aigp/r2/ospfd.conf | 2 +- tests/topotests/bgp_aigp/r3/bgpd.conf | 2 + tests/topotests/bgp_aigp/r3/ospfd.conf | 2 +- tests/topotests/bgp_aigp/r4/bgpd.conf | 23 +- tests/topotests/bgp_aigp/r4/ospfd.conf | 2 +- tests/topotests/bgp_aigp/r5/bgpd.conf | 16 +- tests/topotests/bgp_aigp/r5/ospfd.conf | 2 +- tests/topotests/bgp_aigp/r6/bgpd.conf | 8 +- tests/topotests/bgp_aigp/r6/ospfd.conf | 2 +- tests/topotests/bgp_aigp/r6/zebra.conf | 1 + tests/topotests/bgp_aigp/test_bgp_aigp.py | 98 +- tests/topotests/bgp_aigp_rr/r1/bgpd.conf | 32 + tests/topotests/bgp_aigp_rr/r1/ospfd.conf | 23 + tests/topotests/bgp_aigp_rr/r1/zebra.conf | 13 + tests/topotests/bgp_aigp_rr/r2/bgpd.conf | 22 + tests/topotests/bgp_aigp_rr/r2/ospfd.conf | 18 + tests/topotests/bgp_aigp_rr/r2/zebra.conf | 11 + tests/topotests/bgp_aigp_rr/r3/bgpd.conf | 11 + tests/topotests/bgp_aigp_rr/r3/ospfd.conf | 18 + tests/topotests/bgp_aigp_rr/r3/zebra.conf | 10 + tests/topotests/bgp_aigp_rr/r4/bgpd.conf | 11 + tests/topotests/bgp_aigp_rr/r4/ospfd.conf | 13 + tests/topotests/bgp_aigp_rr/r4/zebra.conf | 7 + tests/topotests/bgp_aigp_rr/test_bgp_aigp_rr.py | 172 + .../bgp_as_allow_in/test_bgp_as_allow_in.py | 3 +- .../bgp_as_override/test_bgp_as_override.py | 2 +- .../test_bgp_as_wide_bgp_identifier.py | 6 +- .../bgp_asdot_regex/test_bgp_asdot_regex.py | 4 +- .../bgp_aspath_zero/test_bgp_aspath_zero.py | 4 +- tests/topotests/bgp_auth/bgp_auth_common.py | 13 +- tests/topotests/bgp_auth/test_bgp_auth1.py | 6 +- tests/topotests/bgp_auth/test_bgp_auth2.py | 6 +- tests/topotests/bgp_auth/test_bgp_auth3.py | 6 +- tests/topotests/bgp_auth/test_bgp_auth4.py | 6 +- .../test_bgp_basic_functionality.py | 289 -- .../bgp_bfd_down_cease_notification/r1/bfdd.conf | 4 + .../bgp_bfd_down_cease_notification/r1/bgpd.conf | 2 +- .../test_bgp_bfd_down_cease_notification.py | 5 +- ...est_bgp_bfd_down_cease_notification_shutdown.py | 122 + .../test_bgp_blackhole_community.py | 10 +- tests/topotests/bgp_bmp/test_bgp_bmp.py | 1 - .../test_bgp_color_extcommunities.py | 1 - .../test_bgp_comm-list_delete.py | 2 +- .../test_bgp_comm_list_match.py | 2 +- .../test_bgp_communities_topo2.py | 1 - .../test_bgp-community-alias.py | 8 +- .../test_bgp_community_change_update.py | 8 +- .../test_bgp_conditional_advertisement.py | 58 +- ...t_bgp_conditional_advertisement_static_route.py | 3 +- ...est_bgp_conditional_advertisement_track_peer.py | 2 +- .../test_bgp_confederation_astype.py | 2 +- .../test_bgp_dampening_per_peer.py | 1 - tests/topotests/bgp_dampening_per_safi/__init__.py | 0 tests/topotests/bgp_dampening_per_safi/r1/frr.conf | 13 + tests/topotests/bgp_dampening_per_safi/r2/frr.conf | 17 + .../test_bgp_dampening_per_safi.py | 194 + .../test_bgp-default-afi-safi.py | 2 +- .../test_bgp_default_originate_2links.py | 17 +- .../test_bgp_default_originate_topo1_1.py | 16 - .../test_bgp_default_originate_topo1_2.py | 12 - .../test_default_orginate_vrf.py | 26 +- .../test_default_originate_conditional_routemap.py | 1 - .../test_bgp_default_originate_timer.py | 2 +- .../test_bgp_default_originate_withdraw.py | 2 +- .../test_bgp_default-originate.py | 10 +- .../test_bgp_default-originate_route-map_match.py | 6 +- .../test_bgp_default-originate_route-map_match2.py | 10 +- ...st_bgp_default-originate_route-map_match_set.py | 6 +- .../test_bgp_default-originate_route-map_set.py | 2 +- .../test_disable_addpath_rx.py | 6 +- .../bgp_distance_change/test_bgp_admin_dist.py | 9 - .../test_bgp_distance_change.py | 6 +- .../test_bgp_dont_capability_negotiate.py | 2 +- tests/topotests/bgp_dual_as/__init__.py | 0 tests/topotests/bgp_dual_as/r1/frr.conf | 11 + tests/topotests/bgp_dual_as/r2/frr.conf | 10 + tests/topotests/bgp_dual_as/test_bgp_dual_as.py | 92 + tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf | 14 + .../topotests/bgp_duplicate_nexthop/r1/isisd.conf | 26 + .../topotests/bgp_duplicate_nexthop/r1/zebra.conf | 24 + tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf | 17 + .../topotests/bgp_duplicate_nexthop/r3/isisd.conf | 38 + .../topotests/bgp_duplicate_nexthop/r3/zebra.conf | 16 + .../topotests/bgp_duplicate_nexthop/r4/isisd.conf | 30 + .../topotests/bgp_duplicate_nexthop/r4/zebra.conf | 20 + tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf | 20 + .../topotests/bgp_duplicate_nexthop/r5/isisd.conf | 26 + .../topotests/bgp_duplicate_nexthop/r5/zebra.conf | 19 + tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf | 20 + .../topotests/bgp_duplicate_nexthop/r6/isisd.conf | 22 + .../topotests/bgp_duplicate_nexthop/r6/zebra.conf | 20 + .../test_bgp_duplicate_nexthop.py | 458 +++ .../test_bgp_dynamic_capability_addpath.py | 3 +- .../test_bgp_dynamic_capability_fqdn.py | 3 +- ...test_bgp_dynamic_capability_graceful_restart.py | 3 +- .../test_bgp_dynamic_capability_orf.py | 3 +- .../test_bgp_dynamic_capability_role.py | 3 +- ...test_bgp_dynamic_capability_software_version.py | 2 +- ...est_bgp-ebgp-common-subnet-nexthop-unchanged.py | 6 +- .../test_bgp_ebgp_requires_policy.py | 14 +- .../bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py | 5 +- .../test_bgp_evpn_maximum_prefix.py | 3 +- tests/topotests/bgp_evpn_mh/test_evpn_mh.py | 2 +- .../test_bgp_evpn_overlay_index_gateway.py | 2 +- .../test_bgp_evpn_route_map_match.py | 4 +- tests/topotests/bgp_evpn_rt5/r1/bgpd.conf | 4 + tests/topotests/bgp_evpn_rt5/r1/zebra.conf | 1 + tests/topotests/bgp_evpn_rt5/r2/bgpd.conf | 4 + tests/topotests/bgp_evpn_rt5/r2/zebra.conf | 1 + tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py | 125 +- .../test_bgp_extcomm-list_delete.py | 3 +- .../test_bgp_extended_link_bandwidth.py | 3 +- ...test_bgp_extended_optional_parameters_length.py | 2 +- tests/topotests/bgp_features/r1/ip_route.json | 8 +- .../topotests/bgp_features/r1/ip_route_norib.json | 8 +- tests/topotests/bgp_features/test_bgp_features.py | 1 - .../test_bgp_gr_functionality_topo1-1.py | 1 - .../test_bgp_gr_functionality_topo1-2.py | 2 - .../test_bgp_gr_functionality_topo1-3.py | 1 - .../test_bgp_gr_functionality_topo1-4.py | 304 +- .../test_bgp_gr_functionality_topo2-1.py | 5 +- .../test_bgp_gr_functionality_topo2-2.py | 4 +- .../test_bgp_gr_functionality_topo2-3.py | 5 +- .../test_bgp_gr_functionality_topo2-4.py | 7 +- .../test_bgp_gr_functionality_topo3.py | 24 +- tests/topotests/bgp_gr_notification/r1/bgpd.conf | 2 +- tests/topotests/bgp_gr_notification/r2/bgpd.conf | 2 +- .../test_bgp_gr_notification.py | 12 +- ...st_bgp_gr_per_neighbor_restart_retain_routes.py | 2 +- .../test_bgp_gr_restart_retain_routes.py | 2 +- tests/topotests/bgp_gshut/test_bgp_gshut.py | 2 +- .../test_bgp_ipv4_class_e_peer.py | 2 +- .../test_rfc5549_ebgp_unnumbered_nbr.py | 2 +- .../test_bgp_ipv6_ll_peering.py | 2 +- .../test_bgp_l3vpn_label_export.py | 4 +- .../test_bgp_l3vpn_to_bgp_vrf.py | 6 + .../test_bgp_labeled_unicast_addpath.py | 2 +- .../test_bgp_labeled_unicast_default_originate.py | 3 +- .../test_bgp_large_comm_list_match.py | 2 +- tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json | 4 +- tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json | 2 +- tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json | 2 +- tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json | 2 +- tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json | 2 +- tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json | 2 +- tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json | 2 +- tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json | 2 +- tests/topotests/bgp_llgr/test_bgp_llgr.py | 3 +- tests/topotests/bgp_local_as/test_bgp_local_as.py | 2 +- .../test_bgp_local_as_dotplus_private_remove.py | 2 +- .../test_bgp_local_as_private_remove.py | 2 +- .../bgp_local_asn/test_bgp_local_asn_agg.py | 1 - .../bgp_local_asn/test_bgp_local_asn_ecmp.py | 2 - .../bgp_local_asn/test_bgp_local_asn_topo1.py | 1 - .../bgp_local_asn/test_bgp_local_asn_topo2.py | 1 - .../bgp_local_asn/test_bgp_local_asn_vrf_topo1.py | 1 - .../bgp_local_asn/test_bgp_local_asn_vrf_topo2.py | 1 - .../test_bgp_local_asn_dot_agg.py | 1 - .../test_bgp_local_asn_dot_ecmp.py | 2 - .../test_bgp_local_asn_dot_topo1.py | 1 - .../test_bgp_lu_explicitnull.py | 6 +- tests/topotests/bgp_match_peer/__init__.py | 0 tests/topotests/bgp_match_peer/r1/frr.conf | 37 + tests/topotests/bgp_match_peer/r2/frr.conf | 14 + tests/topotests/bgp_match_peer/r3/frr.conf | 14 + tests/topotests/bgp_match_peer/r4/frr.conf | 14 + .../bgp_match_peer/test_bgp_match_peer.py | 88 + .../test_bgp_max_med_on_startup.py | 8 +- .../test_bgp_maximum_prefix_invalid_update.py | 2 +- .../test_bgp_maximum_prefix_out.py | 4 +- .../test_bgp_minimum_holdtime.py | 4 +- .../test_bgp_multi_vrf_topo2.py | 6 +- tests/topotests/bgp_nexthop_ipv6/exabgp.env | 53 + tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf | 22 + .../bgp_nexthop_ipv6/r1/show_bgp_ipv6_step1.json | 162 + .../bgp_nexthop_ipv6/r1/show_bgp_ipv6_step2.json | 162 + tests/topotests/bgp_nexthop_ipv6/r1/zebra.conf | 14 + tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf | 22 + .../bgp_nexthop_ipv6/r2/show_bgp_ipv6_step1.json | 162 + .../bgp_nexthop_ipv6/r2/show_bgp_ipv6_step2.json | 162 + tests/topotests/bgp_nexthop_ipv6/r2/zebra.conf | 14 + tests/topotests/bgp_nexthop_ipv6/r3/exabgp.cfg | 16 + .../bgp_nexthop_ipv6/r3/show_bgp_ipv6_step1.json | 0 .../bgp_nexthop_ipv6/r3/show_bgp_ipv6_step2.json | 0 tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf | 22 + .../bgp_nexthop_ipv6/r4/show_bgp_ipv6_step1.json | 210 + .../bgp_nexthop_ipv6/r4/show_bgp_ipv6_step2.json | 222 + tests/topotests/bgp_nexthop_ipv6/r4/zebra.conf | 14 + tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf | 22 + .../bgp_nexthop_ipv6/r5/show_bgp_ipv6_step1.json | 222 + .../bgp_nexthop_ipv6/r5/show_bgp_ipv6_step2.json | 222 + tests/topotests/bgp_nexthop_ipv6/r5/zebra.conf | 14 + tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf | 22 + .../bgp_nexthop_ipv6/r6/show_bgp_ipv6_step1.json | 162 + .../bgp_nexthop_ipv6/r6/show_bgp_ipv6_step2.json | 162 + tests/topotests/bgp_nexthop_ipv6/r6/zebra.conf | 14 + tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf | 30 + .../bgp_nexthop_ipv6/rr/show_bgp_ipv6_step1.json | 220 + .../bgp_nexthop_ipv6/rr/show_bgp_ipv6_step2.json | 220 + .../bgp_nexthop_ipv6/rr/show_bgp_ipv6_summary.json | 6 + tests/topotests/bgp_nexthop_ipv6/rr/zebra.conf | 18 + .../test_bgp_nexthop_ipv6_topo1.py | 263 ++ .../test_bgp_node_target_extcommunities.py | 4 +- tests/topotests/bgp_oad/r1/frr.conf | 7 +- tests/topotests/bgp_oad/test_bgp_oad.py | 42 +- tests/topotests/bgp_orf/test_bgp_orf.py | 2 +- .../test_bgp_path_attribute_discard.py | 2 +- .../bgp_path_selection/test_bgp_path_selection.py | 2 +- .../test_bgp_peer_graceful_shutdown.py | 2 +- .../bgp_peer_group/test_bgp_peer-group.py | 2 +- tests/topotests/bgp_peer_group_solo/__init__.py | 0 tests/topotests/bgp_peer_group_solo/r1/frr.conf | 21 + tests/topotests/bgp_peer_group_solo/r2/frr.conf | 10 + tests/topotests/bgp_peer_group_solo/r3/frr.conf | 10 + .../test_bgp_peer_group_solo.py | 102 + .../r1/prefix1-eBGP-confed.json | 2 +- .../r1/prefix1-eBGP-iBGP.json | 2 +- tests/topotests/bgp_prefix_list_any/r1/bgpd.conf | 4 + tests/topotests/bgp_prefix_list_any/r2/bgpd.conf | 4 + .../test_bgp_prefix_list_any.py | 2 +- .../bgp_prefix_sid/test_bgp_prefix_sid.py | 8 +- .../bgp_prefix_sid2/test_bgp_prefix_sid2.py | 2 +- .../__init__.py | 0 .../r1/frr.conf | 17 + .../r2/frr.conf | 14 + .../test_bgp_received_routes_with_soft_inbound.py | 103 + .../test_bgp_redistribute_table.py | 2 +- .../bgp_reject_as_sets/test_bgp_reject_as_sets.py | 8 +- tests/topotests/bgp_remote_as_auto/__init__.py | 0 tests/topotests/bgp_remote_as_auto/r1/frr.conf | 23 + tests/topotests/bgp_remote_as_auto/r2/frr.conf | 10 + tests/topotests/bgp_remote_as_auto/r3/frr.conf | 10 + tests/topotests/bgp_remote_as_auto/r4/frr.conf | 10 + .../bgp_remote_as_auto/test_bgp_remote_as_auto.py | 161 + .../test_bgp_remove_private_as.py | 3 +- .../test_bgp_remove_private_as_route_map.py | 5 +- .../test_bgp_rmap_extcommunity_none.py | 6 +- .../test_bgp_roles_capability.py | 21 +- .../test_bgp_roles_filtering.py | 11 +- .../bgp_route_aggregation/test_bgp_aggregation.py | 2 +- .../test_bgp_route_map_delay_timer.py | 2 +- .../bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf | 2 + .../bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf | 2 + .../test_bgp_route_map_match_ipv6_nexthop.py | 4 +- .../test_bgp_route_map_match_source_protocol.py | 73 +- .../test_bgp_route_map_match_tag_untagged.py | 2 +- .../test_bgp_route_map_on_match_next.py | 8 +- .../test_bgp_route_map_vpn_import.py | 3 +- .../test_bgp_route_origin_parser.py | 1 - .../test_bgp_route_server_client.py | 2 +- .../bgp_rpki_topo1/test_bgp_rpki_topo1.py | 2 +- .../bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py | 1 - tests/topotests/bgp_self_prefix/__init__.py | 0 tests/topotests/bgp_self_prefix/r1/frr.conf | 19 + tests/topotests/bgp_self_prefix/r2/frr.conf | 20 + tests/topotests/bgp_self_prefix/r3/frr.conf | 20 + .../bgp_self_prefix/test_bgp_self_prefix.py | 111 + .../test_bgp_sender-as-path-loop-detection.py | 2 +- .../test_bgp_set_aspath_exclude.py | 37 +- .../test_bgp_set_aspath_replace.py | 2 +- .../test_bgp_set_local-preference_add_subtract.py | 6 +- .../bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py | 1 - .../test_bgp_software_version.py | 2 +- tests/topotests/bgp_soo/test_bgp_soo.py | 2 +- .../test_bgp_srv6_sid_reachability.py | 5 - .../test_bgp_srv6l3vpn_over_ipv6.py | 5 - .../test_bgp_srv6l3vpn_route_leak.py | 3 - .../bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py | 5 +- .../test_bgp_srv6l3vpn_to_bgp_vrf.py | 5 +- .../test_bgp_srv6l3vpn_to_bgp_vrf2.py | 6 +- .../test_bgp_srv6l3vpn_to_bgp_vrf3.py | 7 +- .../bgp_suppress_fib/test_bgp_suppress_fib.py | 3 +- tests/topotests/bgp_tcp_mss/r1/bgpd.conf | 3 + tests/topotests/bgp_tcp_mss/r1/zebra.conf | 3 + tests/topotests/bgp_tcp_mss/r2/bgpd.conf | 3 + tests/topotests/bgp_tcp_mss/r2/zebra.conf | 3 + tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py | 36 +- .../topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py | 23 +- .../test_bgp_tcp_mss_passive.py | 4 +- .../bgp_unnumbered/test_bgp_unnumbered.py | 7 +- .../bgp_update_delay/test_bgp_update_delay.py | 20 +- .../test_bgp_vpn_5549_route_map.py | 3 +- .../bgp_vpn_import_nexthop_default_vrf/__init__.py | 0 .../bgp_vpn_import_nexthop_default_vrf/r1/frr.conf | 29 + .../bgp_vpn_import_nexthop_default_vrf/r2/frr.conf | 34 + .../test_bgp_vpn_import_nexthop_default_vrf.py | 145 + .../bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py | 30 +- .../bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py | 14 +- .../r1/ipv4_vrf_all_routes_init.json | 6 + .../r1/ipv4_vrf_all_routes_plus_r1_vrf1.json | 6 + .../r1/ipv4_vrf_all_routes_plus_r2_vrf2.json | 9 + .../r1/ipv4_vrf_all_routes_plus_r2_vrf3.json | 9 + .../bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py | 4 +- .../test_bgp_vpnv4_per_nexthop_label.py | 69 +- .../test_bgp_vpnv6_per_nexthop_label.py | 63 +- .../test_bgp_vrf_dynamic_route_leak_topo2.py | 3 +- .../test_bgp_vrf_dynamic_route_leak_topo3.py | 2 - .../test_bgp_vrf_dynamic_route_leak_topo4-1.py | 6 - .../test_bgp_vrf_dynamic_route_leak_topo4-2.py | 6 - .../test_bgp_vrf_dynamic_route_leak_topo4-3.py | 6 - .../test_bgp_vrf_leaking.py | 3 - .../test_bgp_vrf_lite_best_path_topo1.py | 2 - .../test_bgp_vrf_lite_best_path_topo2.py | 1 - .../bgp_weighted_ecmp_recursive/__init__.py | 0 .../bgp_weighted_ecmp_recursive/r1/frr.conf | 16 + .../bgp_weighted_ecmp_recursive/r2/frr.conf | 20 + .../bgp_weighted_ecmp_recursive/r3/frr.conf | 20 + .../bgp_weighted_ecmp_recursive/r4/frr.conf | 17 + .../bgp_weighted_ecmp_recursive/r5/frr.conf | 17 + .../test_bgp_weighted_ecmp_recursive.py | 109 + tests/topotests/conftest.py | 40 +- tests/topotests/dump_of_bgp/r1/frr.conf | 12 + tests/topotests/dump_of_bgp/r2/frr.conf | 17 + tests/topotests/dump_of_bgp/test_dump_of_bgp.py | 102 + tests/topotests/eigrp_topo1/test_eigrp_topo1.py | 1 - .../evpn_type5_test_topo1/test_evpn_type5_topo1.py | 3 +- tests/topotests/example_munet/r1/frr.conf | 2 +- tests/topotests/example_munet/r2/frr.conf | 4 +- tests/topotests/example_munet/r3/frr.conf | 2 +- tests/topotests/example_munet/test_munet.py | 18 +- tests/topotests/forwarding_on_off/r1/frr.conf | 14 + tests/topotests/forwarding_on_off/r2/frr.conf | 19 + tests/topotests/forwarding_on_off/r3/frr.conf | 15 + .../forwarding_on_off/test_forwarding_on_off.py | 104 + .../topotests/fpm_testing_topo1/test_fpm_topo1.py | 2 - tests/topotests/grpc_basic/test_basic_grpc.py | 3 +- .../test_isis_advertise_high_metrics.py | 3 - .../isis_lfa_topo1/test_isis_lfa_topo1.py | 7 +- .../test_isis_lsp_bits_topo1.py | 2 +- .../isis_rlfa_topo1/test_isis_rlfa_topo1.py | 2 +- tests/topotests/isis_snmp/test_isis_snmp.py | 2 +- .../test_isis_sr_flex_algo_topo1.py | 3 +- .../test_isis_sr_flex_algo_topo2.py | 6 +- .../isis_sr_te_topo1/test_isis_sr_te_topo1.py | 4 +- .../topotests/isis_sr_topo1/test_isis_sr_topo1.py | 2 +- .../rt1/step1/show_srv6_locator_table.ref | 4 - .../rt1/step3/show_srv6_locator_table.ref | 4 - .../rt1/step5/show_srv6_locator_table.ref | 4 - .../rt1/step7/show_srv6_locator_table.ref | 4 - .../rt1/step9/show_srv6_locator_table.ref | 4 - .../rt2/step1/show_srv6_locator_table.ref | 4 - .../rt2/step2/show_srv6_locator_table.ref | 4 - .../rt2/step3/show_srv6_locator_table.ref | 4 - .../rt2/step4/show_srv6_locator_table.ref | 4 - .../rt2/step5/show_srv6_locator_table.ref | 4 - .../rt2/step6/show_srv6_locator_table.ref | 4 - .../rt2/step7/show_srv6_locator_table.ref | 4 - .../rt2/step8/show_srv6_locator_table.ref | 4 - .../rt2/step9/show_srv6_locator_table.ref | 4 - .../rt3/step1/show_srv6_locator_table.ref | 4 - .../rt3/step2/show_srv6_locator_table.ref | 4 - .../rt3/step3/show_srv6_locator_table.ref | 4 - .../rt3/step4/show_srv6_locator_table.ref | 4 - .../rt3/step5/show_srv6_locator_table.ref | 4 - .../rt3/step6/show_srv6_locator_table.ref | 4 - .../rt3/step7/show_srv6_locator_table.ref | 4 - .../rt3/step8/show_srv6_locator_table.ref | 4 - .../rt3/step9/show_srv6_locator_table.ref | 4 - .../rt4/step1/show_srv6_locator_table.ref | 4 - .../rt4/step2/show_srv6_locator_table.ref | 4 - .../rt4/step3/show_srv6_locator_table.ref | 4 - .../rt4/step4/show_srv6_locator_table.ref | 4 - .../rt4/step5/show_srv6_locator_table.ref | 4 - .../rt4/step6/show_srv6_locator_table.ref | 4 - .../rt4/step7/show_srv6_locator_table.ref | 4 - .../rt4/step8/show_srv6_locator_table.ref | 4 - .../rt4/step9/show_srv6_locator_table.ref | 4 - .../rt5/step1/show_srv6_locator_table.ref | 4 - .../rt5/step2/show_srv6_locator_table.ref | 4 - .../rt5/step3/show_srv6_locator_table.ref | 4 - .../rt5/step4/show_srv6_locator_table.ref | 4 - .../rt5/step5/show_srv6_locator_table.ref | 4 - .../rt5/step6/show_srv6_locator_table.ref | 4 - .../rt5/step7/show_srv6_locator_table.ref | 4 - .../rt5/step8/show_srv6_locator_table.ref | 4 - .../rt5/step9/show_srv6_locator_table.ref | 4 - .../rt6/step1/show_srv6_locator_table.ref | 4 - .../rt6/step2/show_srv6_locator_table.ref | 4 - .../rt6/step3/show_srv6_locator_table.ref | 4 - .../rt6/step4/show_srv6_locator_table.ref | 4 - .../rt6/step5/show_srv6_locator_table.ref | 4 - .../rt6/step6/show_srv6_locator_table.ref | 4 - .../rt6/step7/show_srv6_locator_table.ref | 4 - .../rt6/step8/show_srv6_locator_table.ref | 4 - .../rt6/step9/show_srv6_locator_table.ref | 4 - .../isis_srv6_topo1/test_isis_srv6_topo1.py | 5 +- .../isis_tilfa_topo1/test_isis_tilfa_topo1.py | 3 +- tests/topotests/isis_topo1/r1/r1_topology.json | 188 +- tests/topotests/isis_topo1/r2/r2_topology.json | 188 +- tests/topotests/isis_topo1/r3/r3_topology.json | 386 +- tests/topotests/isis_topo1/r4/r4_topology.json | 386 +- tests/topotests/isis_topo1/r5/r5_topology.json | 306 +- tests/topotests/isis_topo1/test_isis_topo1.py | 76 +- tests/topotests/isis_topo1_vrf/r1/r1_topology.json | 156 +- tests/topotests/isis_topo1_vrf/r2/r2_topology.json | 156 +- tests/topotests/isis_topo1_vrf/r3/r3_topology.json | 274 +- tests/topotests/isis_topo1_vrf/r4/r4_topology.json | 274 +- tests/topotests/isis_topo1_vrf/r5/r5_topology.json | 242 +- .../isis_topo1_vrf/test_isis_topo1_vrf.py | 58 +- tests/topotests/key_sendaccept/test_keychain.py | 2 +- tests/topotests/kinds.yaml | 3 +- .../ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py | 2 +- tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py | 2 +- tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py | 2 +- .../test_ldp_sync_isis_topo1.py | 2 +- .../test_ldp_sync_ospf_topo1.py | 2 +- .../ldp_vpls_topo1/test_ldp_vpls_topo1.py | 2 +- tests/topotests/lib/bgp.py | 106 +- tests/topotests/lib/bgprib.py | 112 +- tests/topotests/lib/checkping.py | 2 +- tests/topotests/lib/common_check.py | 65 + tests/topotests/lib/common_config.py | 27 +- tests/topotests/lib/fe_client.py | 115 +- tests/topotests/lib/grpc-query.py | 1 - tests/topotests/lib/ospf.py | 4 +- tests/topotests/lib/pim.py | 264 +- tests/topotests/lib/topogen.py | 24 +- tests/topotests/lib/topotest.py | 54 +- tests/topotests/mgmt_debug_flags/test_debug.py | 2 +- tests/topotests/mgmt_notif/test_notif.py | 9 +- .../oper-results/result-lib-vrf-default.json | 49 +- .../oper-results/result-lib-vrf-nokey.json | 96 +- .../oper-results/result-lib-vrf-zebra-ribs.json | 48 +- .../oper-results/result-lib-vrf-zebra.json | 48 +- .../mgmt_oper/oper-results/result-lib.json | 96 +- .../oper-results/result-ribs-rib-ipv4-unicast.json | 12 +- .../oper-results/result-ribs-rib-nokeys.json | 48 +- tests/topotests/mgmt_oper/oper.py | 21 +- tests/topotests/mgmt_oper/r1/frr-yanglib.conf | 10 + .../simple-results/result-intf-state-mtu.json | 1 + .../simple-results/result-intf-state.json | 1 + .../simple-results/result-lib-vrf-default.json | 12 +- .../simple-results/result-lib-vrf-nokey.json | 24 +- .../simple-results/result-lib-vrf-red.json | 12 +- .../simple-results/result-lib-vrf-zebra-ribs.json | 12 +- .../simple-results/result-lib-vrf-zebra.json | 12 +- .../mgmt_oper/simple-results/result-lib.json | 24 +- .../result-ribs-rib-ipv4-unicast.json | 6 +- .../simple-results/result-ribs-rib-nokeys.json | 12 +- .../result-ribs-rib-route-nokey.json | 6 +- .../result-ribs-rib-route-prefix.json | 3 +- tests/topotests/mgmt_oper/test_oper.py | 6 - tests/topotests/mgmt_oper/test_simple.py | 2 +- tests/topotests/mgmt_oper/test_yanglib.py | 45 + tests/topotests/mgmt_rpc/test_rpc.py | 15 +- tests/topotests/mgmt_tests/test_yang_mgmt.py | 1 - tests/topotests/msdp_topo1/r1/pimd.conf | 4 + tests/topotests/msdp_topo1/r2/pimd.conf | 4 + tests/topotests/msdp_topo1/r4/pimd.conf | 13 + tests/topotests/msdp_topo1/test_msdp_topo1.py | 86 +- tests/topotests/msdp_topo2/r1/bgpd.conf | 8 + tests/topotests/msdp_topo2/r1/pimd.conf | 20 + tests/topotests/msdp_topo2/r1/zebra.conf | 14 + tests/topotests/msdp_topo2/r2/bgpd.conf | 8 + tests/topotests/msdp_topo2/r2/pimd.conf | 16 + tests/topotests/msdp_topo2/r2/zebra.conf | 11 + tests/topotests/msdp_topo2/r3/bgpd.conf | 8 + tests/topotests/msdp_topo2/r3/pimd.conf | 16 + tests/topotests/msdp_topo2/r3/zebra.conf | 11 + tests/topotests/msdp_topo2/r4/bgpd.conf | 8 + tests/topotests/msdp_topo2/r4/pimd.conf | 16 + tests/topotests/msdp_topo2/r4/zebra.conf | 11 + tests/topotests/msdp_topo2/r5/bgpd.conf | 8 + tests/topotests/msdp_topo2/r5/pimd.conf | 20 + tests/topotests/msdp_topo2/r5/zebra.conf | 14 + tests/topotests/msdp_topo2/test_msdp_topo2.py | 376 ++ .../test_multicast_pim6_sm1.py | 2 +- .../test_multicast_pim6_sm2.py | 2 +- .../test_pim_dr_nondr_with_ospf_topo2.py | 11 - .../test_pim_dr_nondr_with_transit_router_topo3.py | 64 + .../test_multicast_pim_sm_topo1.py | 3 +- .../test_multicast_pim_sm_topo2.py | 3 +- .../igmp_group_all_detail.json | 2 +- .../igmp_single_if_group_all_brief.json | 2 - .../igmp_single_if_group_all_detail.json | 2 +- .../igmp_single_if_single_group_brief.json | 1 - .../igmp_single_if_single_group_detail.json | 2 +- .../test_multicast_pim_sm_topo3.py | 5 +- .../test_multicast_pim_sm_topo4.py | 5 +- .../test_multicast_pim_static_rp.py | 7 - .../test_multicast_pim_static_rp1.py | 5 - .../test_multicast_pim_static_rp2.py | 5 - .../test_multicast_pim_uplink_topo1.py | 5 +- .../test_multicast_pim_uplink_topo2.py | 2 +- .../multicast_pim_uplink_topo4.json | 295 ++ .../test_multicast_pim_uplink_topo4.py | 893 ++++ tests/topotests/munet/cli.py | 56 +- tests/topotests/munet/mutini.py | 56 +- tests/topotests/munet/native.py | 8 +- tests/topotests/munet/testing/util.py | 26 +- tests/topotests/nb_config/test_nb_config.py | 2 +- tests/topotests/nhrp_redundancy/host/frr.conf | 4 + tests/topotests/nhrp_redundancy/host/zebra.conf | 4 - tests/topotests/nhrp_redundancy/nhc1/frr.conf | 25 + tests/topotests/nhrp_redundancy/nhc1/nhrpd.conf | 11 - tests/topotests/nhrp_redundancy/nhc1/zebra.conf | 16 - tests/topotests/nhrp_redundancy/nhc2/frr.conf | 25 + tests/topotests/nhrp_redundancy/nhc2/nhrpd.conf | 11 - tests/topotests/nhrp_redundancy/nhc2/zebra.conf | 16 - tests/topotests/nhrp_redundancy/nhs1/frr.conf | 19 + tests/topotests/nhrp_redundancy/nhs1/nhrpd.conf | 9 - tests/topotests/nhrp_redundancy/nhs1/zebra.conf | 12 - tests/topotests/nhrp_redundancy/nhs2/frr.conf | 19 + tests/topotests/nhrp_redundancy/nhs2/nhrpd.conf | 9 - tests/topotests/nhrp_redundancy/nhs2/zebra.conf | 12 - tests/topotests/nhrp_redundancy/nhs3/frr.conf | 19 + tests/topotests/nhrp_redundancy/nhs3/nhrpd.conf | 9 - tests/topotests/nhrp_redundancy/nhs3/zebra.conf | 12 - tests/topotests/nhrp_redundancy/router/frr.conf | 7 + tests/topotests/nhrp_redundancy/router/zebra.conf | 7 - .../nhrp_redundancy/test_nhrp_redundancy.py | 76 +- .../nhrp_topo/r1/nhrp_shortcut_present.json | 14 + tests/topotests/nhrp_topo/r1/nhrpd.conf | 3 +- tests/topotests/nhrp_topo/r1/zebra.conf | 1 + tests/topotests/nhrp_topo/r2/nhrp4_cache.json | 13 +- tests/topotests/nhrp_topo/r2/nhrp_route4.json | 26 +- tests/topotests/nhrp_topo/r2/nhrpd.conf | 3 +- tests/topotests/nhrp_topo/r2/zebra.conf | 3 + tests/topotests/nhrp_topo/r4/nhrp4_cache.json | 30 + tests/topotests/nhrp_topo/r4/nhrp_route4.json | 26 + tests/topotests/nhrp_topo/r4/nhrpd.conf | 11 + tests/topotests/nhrp_topo/r4/zebra.conf | 13 + tests/topotests/nhrp_topo/test_nhrp_topo.py | 259 +- .../ospf6_gr_topo1/test_ospf6_gr_topo1.py | 2 +- .../test_ospf6_loopback_cost.py | 4 +- .../test_ospf6_point_to_multipoint.py | 4 +- tests/topotests/ospf6_topo1/test_ospf6_topo1.py | 6 +- .../ospf6_topo1_vrf/test_ospf6_topo1_vrf.py | 6 +- .../test_ospf_asbr_summary_topo1.py | 4 +- .../test_ospf_asbr_summary_type7_lsa.py | 2 +- .../test_ospf_authentication.py | 2 +- .../ospf_basic_functionality/test_ospf_chaos.py | 2 +- .../ospf_basic_functionality/test_ospf_ecmp.py | 4 +- .../test_ospf_flood_reduction.py | 5 +- .../ospf_basic_functionality/test_ospf_nssa.py | 2 +- .../ospf_basic_functionality/test_ospf_p2mp.py | 2 +- .../test_ospf_routemaps.py | 2 +- .../ospf_basic_functionality/test_ospf_rte_calc.py | 6 +- .../test_ospf_single_area.py | 2 +- .../ospf_dual_stack/test_ospf_dual_stack.py | 2 +- .../ospf_gr_helper/test_ospf_gr_helper1.py | 2 - .../ospf_gr_helper/test_ospf_gr_helper3.py | 2 - .../topotests/ospf_gr_topo1/test_ospf_gr_topo1.py | 2 +- .../test_ospf_instance_redistribute.py | 1 - .../test_ospf_metric_propagation.py | 5 +- .../r1/zebra-vrf-default.txt | 10 +- .../r1/zebra-vrf-neno.txt | 8 +- .../r2/zebra-vrf-default.txt | 10 +- .../r2/zebra-vrf-ray.txt | 10 +- .../r3/zebra-vrf-default.txt | 8 +- .../r4/zebra-vrf-default.txt | 8 +- .../test_ospf_multi_vrf_bgp_route_leak.py | 4 +- tests/topotests/ospf_netns_vrf/r1/zebraroute.txt | 8 +- .../topotests/ospf_netns_vrf/r1/zebraroutedown.txt | 8 +- tests/topotests/ospf_netns_vrf/r2/zebraroute.txt | 8 +- .../topotests/ospf_netns_vrf/r2/zebraroutedown.txt | 8 +- tests/topotests/ospf_netns_vrf/r3/zebraroute.txt | 8 +- .../topotests/ospf_netns_vrf/r3/zebraroutedown.txt | 4 +- .../ospf_netns_vrf/test_ospf_netns_vrf.py | 4 +- .../ospf_nssa_topo1/test_ospf_nssa_topo1.py | 2 +- tests/topotests/ospf_p2mp/r1/frr-p2mp.conf | 6 + tests/topotests/ospf_p2mp/r2/frr-p2mp.conf | 6 + tests/topotests/ospf_p2mp/r3/frr-p2mp.conf | 6 + tests/topotests/ospf_p2mp/r4/frr-p2mp.conf | 6 + .../ospf_p2mp/test_ospf_p2mp_broadcast.py | 146 +- .../ospf_p2mp/test_ospf_p2mp_non_broadcast.py | 24 +- .../test_ospf_prefix_suppression.py | 9 +- .../ospf_single_switch/test_ospf_single_switch.py | 5 +- .../ospf_sr_te_topo1/test_ospf_sr_te_topo1.py | 2 +- .../topotests/ospf_sr_topo1/test_ospf_sr_topo1.py | 2 +- .../ospf_suppress_fa/test_ospf_suppress_fa.py | 1 - .../ospf_tilfa_topo1/test_ospf_tilfa_topo1.py | 2 +- tests/topotests/ospf_topo1/test_ospf_topo1.py | 2 +- tests/topotests/ospf_topo2/test_ospf_topo2.py | 2 +- .../ospf_unnumbered/test_ospf_unnumbered.py | 2 +- .../test_ospf_unnumbered_point_to_multipoint.py | 2 +- tests/topotests/ospfapi/test_ospf_clientapi.py | 4 +- .../test_ospfv3_asbr_summary_topo1.py | 6 +- .../test_ospfv3_authentication.py | 11 +- .../ospfv3_basic_functionality/test_ospfv3_ecmp.py | 4 +- .../test_ospfv3_ecmp_lan.py | 15 +- .../ospfv3_basic_functionality/test_ospfv3_nssa.py | 2 +- .../test_ospfv3_nssa2.py | 14 - .../test_ospfv3_routemaps.py | 2 +- .../test_ospfv3_rte_calc.py | 3 +- .../test_ospfv3_single_area.py | 158 +- tests/topotests/pim_acl/test_pim_acl.py | 2 +- tests/topotests/pim_autorp/__init__.py | 0 tests/topotests/pim_autorp/r1/frr.conf | 16 + tests/topotests/pim_autorp/r2/frr.conf | 16 + tests/topotests/pim_autorp/test_pim_autorp.py | 341 ++ tests/topotests/pim_basic/test_pim.py | 2 +- tests/topotests/pim_basic_igmp_proxy/r1/frr.conf | 29 + tests/topotests/pim_basic_igmp_proxy/r2/frr.conf | 19 + tests/topotests/pim_basic_igmp_proxy/r3/frr.conf | 8 + tests/topotests/pim_basic_igmp_proxy/rp/frr.conf | 16 + .../pim_basic_igmp_proxy/test_pim_igmp_proxy.py | 319 ++ tests/topotests/pim_cand_rp_bsr/__init__.py | 0 tests/topotests/pim_cand_rp_bsr/r1/frr.conf | 49 + tests/topotests/pim_cand_rp_bsr/r2/frr.conf | 48 + tests/topotests/pim_cand_rp_bsr/r3/frr.conf | 52 + tests/topotests/pim_cand_rp_bsr/r4/frr.conf | 66 + tests/topotests/pim_cand_rp_bsr/r5/frr.conf | 34 + tests/topotests/pim_cand_rp_bsr/r6/frr.conf | 42 + .../pim_cand_rp_bsr/test_pim_cand_rp_bsr.py | 506 +++ tests/topotests/pim_igmp_vrf/test_pim_vrf.py | 4 +- tests/topotests/pytest.ini | 3 + .../rip_allow_ecmp/test_rip_allow_ecmp.py | 4 +- .../topotests/rip_bfd_topo1/test_rip_bfd_topo1.py | 1 - .../test_rip_passive_interface.py | 4 +- tests/topotests/rip_topo1/r1/show_ip_rip.ref | 5 +- tests/topotests/rip_topo1/r2/show_ip_rip.ref | 5 +- tests/topotests/rip_topo1/r3/show_ip_rip.ref | 5 +- .../ripng_allow_ecmp/test_ripng_allow_ecmp.py | 4 +- .../ripng_route_map/test_ripng_route_map.py | 5 +- tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref | 5 +- tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref | 5 +- tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref | 5 +- tests/topotests/route_scale/scale_test_common.py | 30 +- tests/topotests/route_scale/test_route_scale1.py | 6 - tests/topotests/route_scale/test_route_scale2.py | 6 - .../topotests/simple_snmp_test/test_simple_snmp.py | 2 +- tests/topotests/srv6_encap_src_addr/r1/zebra.conf | 1 - .../test_srv6_encap_src_addr.py | 3 +- tests/topotests/srv6_locator/test_srv6_locator.py | 6 +- .../test_srv6_locator_custom_bits_length.py | 6 +- .../srv6_locator_usid/test_srv6_locator_usid.py | 6 +- tests/topotests/srv6_sid_manager/ce1/bgpd.conf | 8 + tests/topotests/srv6_sid_manager/ce1/ipv6_rib.json | 58 + tests/topotests/srv6_sid_manager/ce1/zebra.conf | 14 + tests/topotests/srv6_sid_manager/ce2/bgpd.conf | 8 + tests/topotests/srv6_sid_manager/ce2/ipv6_rib.json | 58 + tests/topotests/srv6_sid_manager/ce2/zebra.conf | 14 + tests/topotests/srv6_sid_manager/ce3/bgpd.conf | 8 + tests/topotests/srv6_sid_manager/ce3/ipv6_rib.json | 58 + tests/topotests/srv6_sid_manager/ce3/zebra.conf | 14 + tests/topotests/srv6_sid_manager/ce4/bgpd.conf | 8 + tests/topotests/srv6_sid_manager/ce4/ipv6_rib.json | 58 + tests/topotests/srv6_sid_manager/ce4/zebra.conf | 14 + tests/topotests/srv6_sid_manager/ce5/bgpd.conf | 8 + tests/topotests/srv6_sid_manager/ce5/ipv6_rib.json | 58 + tests/topotests/srv6_sid_manager/ce5/zebra.conf | 14 + tests/topotests/srv6_sid_manager/ce6/bgpd.conf | 8 + tests/topotests/srv6_sid_manager/ce6/ipv6_rib.json | 58 + tests/topotests/srv6_sid_manager/ce6/zebra.conf | 14 + tests/topotests/srv6_sid_manager/dst/sharpd.conf | 0 tests/topotests/srv6_sid_manager/dst/zebra.conf | 22 + tests/topotests/srv6_sid_manager/rt1/bgpd.conf | 66 + tests/topotests/srv6_sid_manager/rt1/isisd.conf | 35 + tests/topotests/srv6_sid_manager/rt1/sharpd.conf | 0 .../srv6_sid_manager/rt1/show_ip_route.ref | 276 ++ .../srv6_sid_manager/rt1/show_ipv6_route.ref | 314 ++ .../rt1/show_srv6_locator_table.ref | 15 + .../rt1/show_yang_interface_isis_adjacencies.ref | 32 + tests/topotests/srv6_sid_manager/rt1/vpnv6_rib.ref | 169 + tests/topotests/srv6_sid_manager/rt1/vrf10_rib.ref | 86 + tests/topotests/srv6_sid_manager/rt1/vrf20_rib.ref | 92 + tests/topotests/srv6_sid_manager/rt1/zebra.conf | 37 + tests/topotests/srv6_sid_manager/rt2/isisd.conf | 48 + .../srv6_sid_manager/rt2/show_ip_route.ref | 320 ++ .../srv6_sid_manager/rt2/show_ipv6_route.ref | 346 ++ .../rt2/show_srv6_locator_table.ref | 15 + .../rt2/show_yang_interface_isis_adjacencies.ref | 70 + tests/topotests/srv6_sid_manager/rt2/zebra.conf | 34 + tests/topotests/srv6_sid_manager/rt3/isisd.conf | 48 + .../srv6_sid_manager/rt3/show_ip_route.ref | 320 ++ .../srv6_sid_manager/rt3/show_ipv6_route.ref | 346 ++ .../rt3/show_srv6_locator_table.ref | 15 + .../rt3/show_yang_interface_isis_adjacencies.ref | 70 + tests/topotests/srv6_sid_manager/rt3/zebra.conf | 33 + tests/topotests/srv6_sid_manager/rt4/isisd.conf | 56 + .../srv6_sid_manager/rt4/show_ip_route.ref | 296 ++ .../srv6_sid_manager/rt4/show_ipv6_route.ref | 346 ++ .../rt4/show_srv6_locator_table.ref | 15 + .../rt4/show_yang_interface_isis_adjacencies.ref | 82 + tests/topotests/srv6_sid_manager/rt4/zebra.conf | 36 + tests/topotests/srv6_sid_manager/rt5/isisd.conf | 56 + .../srv6_sid_manager/rt5/show_ip_route.ref | 296 ++ .../srv6_sid_manager/rt5/show_ipv6_route.ref | 346 ++ .../rt5/show_srv6_locator_table.ref | 15 + .../rt5/show_yang_interface_isis_adjacencies.ref | 82 + tests/topotests/srv6_sid_manager/rt5/zebra.conf | 36 + tests/topotests/srv6_sid_manager/rt6/bgpd.conf | 67 + tests/topotests/srv6_sid_manager/rt6/isisd.conf | 42 + tests/topotests/srv6_sid_manager/rt6/sharpd.conf | 0 .../srv6_sid_manager/rt6/show_ip_route.ref | 273 ++ .../srv6_sid_manager/rt6/show_ipv6_route.ref | 312 ++ .../rt6/show_srv6_locator_table.ref | 15 + .../rt6/show_yang_interface_isis_adjacencies.ref | 44 + tests/topotests/srv6_sid_manager/rt6/vpnv6_rib.ref | 169 + tests/topotests/srv6_sid_manager/rt6/vrf10_rib.ref | 92 + tests/topotests/srv6_sid_manager/rt6/vrf20_rib.ref | 86 + tests/topotests/srv6_sid_manager/rt6/zebra.conf | 45 + .../srv6_sid_manager/test_srv6_sid_manager.py | 421 ++ .../topotests/srv6_static_route/test_srv6_route.py | 4 +- .../test_static_routing_mpls.py | 5 +- .../test_static_routes_topo2_ebgp.py | 2 +- .../test_static_routes_topo3_ebgp.py | 2 +- .../test_static_routes_topo4_ebgp.py | 2 +- .../test_static_routes_topo1_ibgp.py | 2 +- .../test_static_routes_topo2_ibgp.py | 2 +- .../test_static_routes_topo3_ibgp.py | 2 +- .../test_static_routes_topo4_ibgp.py | 2 +- .../topotests/static_simple/test_static_simple.py | 8 +- .../zebra_fec_nexthop_resolution/__init__.py | 0 .../zebra_fec_nexthop_resolution/r1/bgpd.conf | 24 + .../r1/ospfd.conf.after | 25 + .../zebra_fec_nexthop_resolution/r1/zebra.conf | 13 + .../zebra_fec_nexthop_resolution/r2/bgpd.conf | 23 + .../zebra_fec_nexthop_resolution/r2/isisd.conf | 25 + .../r2/ospfd.conf.after | 32 + .../zebra_fec_nexthop_resolution/r2/zebra.conf | 16 + .../zebra_fec_nexthop_resolution/r3/bgpd.conf | 23 + .../zebra_fec_nexthop_resolution/r3/isisd.conf | 25 + .../r3/ospfd.conf.after | 26 + .../zebra_fec_nexthop_resolution/r3/zebra.conf | 19 + .../zebra_fec_nexthop_resolution/r4/bgpd.conf | 24 + .../zebra_fec_nexthop_resolution/r4/isisd.conf | 31 + .../zebra_fec_nexthop_resolution/r4/ospfd.conf | 19 + .../zebra_fec_nexthop_resolution/r4/zebra.conf | 16 + .../zebra_fec_nexthop_resolution/r5/bgpd.conf | 23 + .../zebra_fec_nexthop_resolution/r5/isisd.conf | 26 + .../r5/ospfd.conf.after | 26 + .../zebra_fec_nexthop_resolution/r5/zebra.conf | 19 + .../r6/ospfd.conf.after | 32 + .../zebra_fec_nexthop_resolution/r6/zebra.conf | 22 + .../zebra_fec_nexthop_resolution/r7/bgpd.conf | 24 + .../r7/ospfd.conf.after | 26 + .../zebra_fec_nexthop_resolution/r7/zebra.conf | 14 + .../test_zebra_fec_nexthop_resolution.py | 259 ++ .../r1/ip_route_connected.json | 24 + .../r1/ip_route_kernel.json | 24 + .../r1/ip_route_kernel_blackhole.json | 24 + .../test_zebra_multiple_connected.py | 68 +- .../topotests/zebra_netlink/test_zebra_netlink.py | 4 +- .../test_verify_nh_resolution.py | 2 - tests/topotests/zebra_opaque/test_zebra_opaque.py | 10 +- tests/topotests/zebra_rib/test_zebra_rib.py | 6 +- .../zebra_seg6_route/test_zebra_seg6_route.py | 4 +- .../topotests/zebra_seg6local_route/r1/routes.json | 73 + .../test_zebra_seg6local_route.py | 4 +- tools/checkpatch.pl | 3 +- tools/etc/logrotate.d/frr | 2 +- tools/etc/rsyslog.d/45-frr.conf | 2 + tools/frr-reload.py | 149 +- tools/gen_northbound_callbacks.c | 2 +- tools/gen_yang_deviations.c | 2 +- tools/subdir.am | 11 +- vrrpd/vrrp_debug.c | 88 +- vrrpd/vrrp_debug.h | 8 - vrrpd/vrrp_packet.c | 2 +- vrrpd/vrrp_vty.c | 14 +- vtysh/.gitignore | 1 + vtysh/subdir.am | 3 - vtysh/vtysh.c | 353 +- vtysh/vtysh.h | 2 + vtysh/vtysh_config.c | 20 +- vtysh/vtysh_main.c | 1 - yang/frr-bfdd.yang | 3 - yang/frr-bgp-common.yang | 13 + yang/frr-bgp-route-map.yang | 16 +- yang/frr-eigrpd.yang | 2 +- yang/frr-gmp.yang | 28 +- yang/frr-isisd.yang | 6 +- yang/frr-pim-candidate.yang | 174 + yang/frr-pim-rp.yang | 71 + yang/frr-pim.yang | 49 + yang/frr-route-map.yang | 6 +- yang/frr-zebra.yang | 11 + yang/ietf/ietf-bgp-types.yang | 2 +- yang/subdir.am | 1 + zebra/connected.c | 38 + zebra/dplane_fpm_nl.c | 71 +- zebra/if_ioctl.c | 2 + zebra/if_netlink.c | 214 +- zebra/if_netlink.h | 3 - zebra/if_sysctl.c | 2 + zebra/interface.c | 3 +- zebra/kernel_netlink.c | 15 - zebra/kernel_netlink.h | 8 - zebra/kernel_socket.c | 2 + zebra/main.c | 39 +- zebra/redistribute.c | 5 +- zebra/rib.h | 21 +- zebra/rt_netlink.c | 42 +- zebra/rt_socket.c | 8 +- zebra/rtadv.c | 2 +- zebra/tc_netlink.c | 40 - zebra/tc_netlink.h | 2 - zebra/zapi_msg.c | 216 +- zebra/zapi_msg.h | 10 +- zebra/zebra_cli.c | 38 + zebra/zebra_dplane.c | 201 +- zebra/zebra_dplane.h | 4 +- zebra/zebra_errors.c | 12 + zebra/zebra_errors.h | 2 + zebra/zebra_evpn.c | 3 + zebra/zebra_evpn_mac.c | 857 ++-- zebra/zebra_gr.c | 81 +- zebra/zebra_mpls.c | 134 +- zebra/zebra_mpls.h | 8 +- zebra/zebra_nb.c | 7 + zebra/zebra_nb.h | 4 + zebra/zebra_nb_config.c | 53 + zebra/zebra_nhg.c | 313 +- zebra/zebra_nhg.h | 35 +- zebra/zebra_ns.c | 20 +- zebra/zebra_ns.h | 2 + zebra/zebra_pw.c | 37 +- zebra/zebra_pw.h | 1 + zebra/zebra_rib.c | 405 +- zebra/zebra_rnh.c | 17 +- zebra/zebra_routemap.c | 5 +- zebra/zebra_router.c | 4 +- zebra/zebra_router.h | 10 +- zebra/zebra_snmp.c | 30 +- zebra/zebra_srv6.c | 2087 +++++++++- zebra/zebra_srv6.h | 247 ++ zebra/zebra_srv6_vty.c | 595 ++- zebra/zebra_trace.h | 14 - zebra/zebra_vrf.h | 1 + zebra/zebra_vty.c | 53 +- zebra/zebra_vxlan.c | 78 +- zebra/zebra_vxlan_if.c | 25 +- zebra/zserv.c | 54 +- zebra/zserv.h | 2 + 1234 files changed, 50971 insertions(+), 17888 deletions(-) delete mode 100644 bfdd/bfdctl.h delete mode 100644 bfdd/config.c delete mode 100644 bfdd/control.c create mode 100644 doc/developer/ospf-ls-retrans.rst create mode 100644 doc/user/about.rst create mode 100644 doc/user/basics.rst create mode 100644 doc/user/introduction.rst delete mode 100644 doc/user/overview.rst create mode 100644 doc/user/protocols.rst create mode 100644 ospf6d/ospf6_tlv.h create mode 100644 pimd/pim_autorp.c create mode 100644 pimd/pim_autorp.h create mode 100644 pimd/pim_bsr_rpdb.c delete mode 100644 tests/bgpd/test_mpath.c delete mode 100644 tests/bgpd/test_mpath.py create mode 100644 tests/topotests/bgp_addpath_graceful_restart/__init__.py create mode 100644 tests/topotests/bgp_addpath_graceful_restart/r1/frr.conf create mode 100644 tests/topotests/bgp_addpath_graceful_restart/r2/frr.conf create mode 100644 tests/topotests/bgp_addpath_graceful_restart/r3/frr.conf create mode 100644 tests/topotests/bgp_addpath_graceful_restart/test_bgp_addpath_graceful_restart.py create mode 100644 tests/topotests/bgp_addpath_llgr/__init__.py create mode 100644 tests/topotests/bgp_addpath_llgr/r1/frr.conf create mode 100644 tests/topotests/bgp_addpath_llgr/r2/frr.conf create mode 100644 tests/topotests/bgp_addpath_llgr/r3/frr.conf create mode 100644 tests/topotests/bgp_addpath_llgr/test_bgp_addpath_llgr.py create mode 100644 tests/topotests/bgp_aigp_rr/r1/bgpd.conf create mode 100644 tests/topotests/bgp_aigp_rr/r1/ospfd.conf create mode 100644 tests/topotests/bgp_aigp_rr/r1/zebra.conf create mode 100644 tests/topotests/bgp_aigp_rr/r2/bgpd.conf create mode 100644 tests/topotests/bgp_aigp_rr/r2/ospfd.conf create mode 100644 tests/topotests/bgp_aigp_rr/r2/zebra.conf create mode 100644 tests/topotests/bgp_aigp_rr/r3/bgpd.conf create mode 100644 tests/topotests/bgp_aigp_rr/r3/ospfd.conf create mode 100644 tests/topotests/bgp_aigp_rr/r3/zebra.conf create mode 100644 tests/topotests/bgp_aigp_rr/r4/bgpd.conf create mode 100644 tests/topotests/bgp_aigp_rr/r4/ospfd.conf create mode 100644 tests/topotests/bgp_aigp_rr/r4/zebra.conf create mode 100644 tests/topotests/bgp_aigp_rr/test_bgp_aigp_rr.py create mode 100644 tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py create mode 100644 tests/topotests/bgp_dampening_per_safi/__init__.py create mode 100644 tests/topotests/bgp_dampening_per_safi/r1/frr.conf create mode 100644 tests/topotests/bgp_dampening_per_safi/r2/frr.conf create mode 100644 tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py create mode 100644 tests/topotests/bgp_dual_as/__init__.py create mode 100644 tests/topotests/bgp_dual_as/r1/frr.conf create mode 100644 tests/topotests/bgp_dual_as/r2/frr.conf create mode 100644 tests/topotests/bgp_dual_as/test_bgp_dual_as.py create mode 100644 tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf create mode 100644 tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py create mode 100644 tests/topotests/bgp_match_peer/__init__.py create mode 100644 tests/topotests/bgp_match_peer/r1/frr.conf create mode 100644 tests/topotests/bgp_match_peer/r2/frr.conf create mode 100644 tests/topotests/bgp_match_peer/r3/frr.conf create mode 100644 tests/topotests/bgp_match_peer/r4/frr.conf create mode 100644 tests/topotests/bgp_match_peer/test_bgp_match_peer.py create mode 100644 tests/topotests/bgp_nexthop_ipv6/exabgp.env create mode 100644 tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step1.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step2.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r1/zebra.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step1.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step2.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r2/zebra.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/r3/exabgp.cfg create mode 100644 tests/topotests/bgp_nexthop_ipv6/r3/show_bgp_ipv6_step1.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r3/show_bgp_ipv6_step2.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step1.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step2.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r4/zebra.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step1.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step2.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r5/zebra.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step1.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step2.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/r6/zebra.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_step1.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_step2.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_summary.json create mode 100644 tests/topotests/bgp_nexthop_ipv6/rr/zebra.conf create mode 100644 tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py create mode 100644 tests/topotests/bgp_peer_group_solo/__init__.py create mode 100644 tests/topotests/bgp_peer_group_solo/r1/frr.conf create mode 100644 tests/topotests/bgp_peer_group_solo/r2/frr.conf create mode 100644 tests/topotests/bgp_peer_group_solo/r3/frr.conf create mode 100644 tests/topotests/bgp_peer_group_solo/test_bgp_peer_group_solo.py create mode 100644 tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py create mode 100644 tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf create mode 100644 tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf create mode 100644 tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py create mode 100644 tests/topotests/bgp_remote_as_auto/__init__.py create mode 100644 tests/topotests/bgp_remote_as_auto/r1/frr.conf create mode 100644 tests/topotests/bgp_remote_as_auto/r2/frr.conf create mode 100644 tests/topotests/bgp_remote_as_auto/r3/frr.conf create mode 100644 tests/topotests/bgp_remote_as_auto/r4/frr.conf create mode 100644 tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py create mode 100644 tests/topotests/bgp_self_prefix/__init__.py create mode 100644 tests/topotests/bgp_self_prefix/r1/frr.conf create mode 100644 tests/topotests/bgp_self_prefix/r2/frr.conf create mode 100644 tests/topotests/bgp_self_prefix/r3/frr.conf create mode 100644 tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py create mode 100644 tests/topotests/bgp_vpn_import_nexthop_default_vrf/__init__.py create mode 100644 tests/topotests/bgp_vpn_import_nexthop_default_vrf/r1/frr.conf create mode 100644 tests/topotests/bgp_vpn_import_nexthop_default_vrf/r2/frr.conf create mode 100644 tests/topotests/bgp_vpn_import_nexthop_default_vrf/test_bgp_vpn_import_nexthop_default_vrf.py create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/__init__.py create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf create mode 100644 tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py create mode 100644 tests/topotests/dump_of_bgp/r1/frr.conf create mode 100644 tests/topotests/dump_of_bgp/r2/frr.conf create mode 100644 tests/topotests/dump_of_bgp/test_dump_of_bgp.py create mode 100644 tests/topotests/forwarding_on_off/r1/frr.conf create mode 100644 tests/topotests/forwarding_on_off/r2/frr.conf create mode 100644 tests/topotests/forwarding_on_off/r3/frr.conf create mode 100644 tests/topotests/forwarding_on_off/test_forwarding_on_off.py create mode 100644 tests/topotests/lib/common_check.py create mode 100644 tests/topotests/mgmt_oper/r1/frr-yanglib.conf create mode 100644 tests/topotests/mgmt_oper/test_yanglib.py create mode 100644 tests/topotests/msdp_topo2/r1/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r1/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r1/zebra.conf create mode 100644 tests/topotests/msdp_topo2/r2/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r2/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r2/zebra.conf create mode 100644 tests/topotests/msdp_topo2/r3/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r3/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r3/zebra.conf create mode 100644 tests/topotests/msdp_topo2/r4/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r4/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r4/zebra.conf create mode 100644 tests/topotests/msdp_topo2/r5/bgpd.conf create mode 100644 tests/topotests/msdp_topo2/r5/pimd.conf create mode 100644 tests/topotests/msdp_topo2/r5/zebra.conf create mode 100755 tests/topotests/msdp_topo2/test_msdp_topo2.py create mode 100644 tests/topotests/multicast_pim_uplink_topo4/multicast_pim_uplink_topo4.json create mode 100644 tests/topotests/multicast_pim_uplink_topo4/test_multicast_pim_uplink_topo4.py create mode 100644 tests/topotests/nhrp_redundancy/host/frr.conf delete mode 100644 tests/topotests/nhrp_redundancy/host/zebra.conf create mode 100644 tests/topotests/nhrp_redundancy/nhc1/frr.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhc1/nhrpd.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhc1/zebra.conf create mode 100644 tests/topotests/nhrp_redundancy/nhc2/frr.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhc2/nhrpd.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhc2/zebra.conf create mode 100644 tests/topotests/nhrp_redundancy/nhs1/frr.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhs1/nhrpd.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhs1/zebra.conf create mode 100644 tests/topotests/nhrp_redundancy/nhs2/frr.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhs2/nhrpd.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhs2/zebra.conf create mode 100644 tests/topotests/nhrp_redundancy/nhs3/frr.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhs3/nhrpd.conf delete mode 100644 tests/topotests/nhrp_redundancy/nhs3/zebra.conf create mode 100644 tests/topotests/nhrp_redundancy/router/frr.conf delete mode 100644 tests/topotests/nhrp_redundancy/router/zebra.conf create mode 100644 tests/topotests/nhrp_topo/r1/nhrp_shortcut_present.json create mode 100644 tests/topotests/nhrp_topo/r4/nhrp4_cache.json create mode 100644 tests/topotests/nhrp_topo/r4/nhrp_route4.json create mode 100644 tests/topotests/nhrp_topo/r4/nhrpd.conf create mode 100644 tests/topotests/nhrp_topo/r4/zebra.conf create mode 100755 tests/topotests/pim_autorp/__init__.py create mode 100644 tests/topotests/pim_autorp/r1/frr.conf create mode 100644 tests/topotests/pim_autorp/r2/frr.conf create mode 100644 tests/topotests/pim_autorp/test_pim_autorp.py create mode 100644 tests/topotests/pim_basic_igmp_proxy/r1/frr.conf create mode 100644 tests/topotests/pim_basic_igmp_proxy/r2/frr.conf create mode 100644 tests/topotests/pim_basic_igmp_proxy/r3/frr.conf create mode 100644 tests/topotests/pim_basic_igmp_proxy/rp/frr.conf create mode 100644 tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py create mode 100755 tests/topotests/pim_cand_rp_bsr/__init__.py create mode 100644 tests/topotests/pim_cand_rp_bsr/r1/frr.conf create mode 100644 tests/topotests/pim_cand_rp_bsr/r2/frr.conf create mode 100644 tests/topotests/pim_cand_rp_bsr/r3/frr.conf create mode 100644 tests/topotests/pim_cand_rp_bsr/r4/frr.conf create mode 100644 tests/topotests/pim_cand_rp_bsr/r5/frr.conf create mode 100644 tests/topotests/pim_cand_rp_bsr/r6/frr.conf create mode 100644 tests/topotests/pim_cand_rp_bsr/test_pim_cand_rp_bsr.py create mode 100644 tests/topotests/srv6_sid_manager/ce1/bgpd.conf create mode 100644 tests/topotests/srv6_sid_manager/ce1/ipv6_rib.json create mode 100644 tests/topotests/srv6_sid_manager/ce1/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/ce2/bgpd.conf create mode 100644 tests/topotests/srv6_sid_manager/ce2/ipv6_rib.json create mode 100644 tests/topotests/srv6_sid_manager/ce2/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/ce3/bgpd.conf create mode 100644 tests/topotests/srv6_sid_manager/ce3/ipv6_rib.json create mode 100644 tests/topotests/srv6_sid_manager/ce3/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/ce4/bgpd.conf create mode 100644 tests/topotests/srv6_sid_manager/ce4/ipv6_rib.json create mode 100644 tests/topotests/srv6_sid_manager/ce4/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/ce5/bgpd.conf create mode 100644 tests/topotests/srv6_sid_manager/ce5/ipv6_rib.json create mode 100644 tests/topotests/srv6_sid_manager/ce5/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/ce6/bgpd.conf create mode 100644 tests/topotests/srv6_sid_manager/ce6/ipv6_rib.json create mode 100644 tests/topotests/srv6_sid_manager/ce6/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/dst/sharpd.conf create mode 100644 tests/topotests/srv6_sid_manager/dst/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/rt1/bgpd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt1/isisd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt1/sharpd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt1/show_ip_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt1/show_ipv6_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt1/show_srv6_locator_table.ref create mode 100644 tests/topotests/srv6_sid_manager/rt1/show_yang_interface_isis_adjacencies.ref create mode 100644 tests/topotests/srv6_sid_manager/rt1/vpnv6_rib.ref create mode 100644 tests/topotests/srv6_sid_manager/rt1/vrf10_rib.ref create mode 100644 tests/topotests/srv6_sid_manager/rt1/vrf20_rib.ref create mode 100644 tests/topotests/srv6_sid_manager/rt1/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/rt2/isisd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt2/show_ip_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt2/show_ipv6_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt2/show_srv6_locator_table.ref create mode 100644 tests/topotests/srv6_sid_manager/rt2/show_yang_interface_isis_adjacencies.ref create mode 100644 tests/topotests/srv6_sid_manager/rt2/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/rt3/isisd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt3/show_ip_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt3/show_ipv6_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt3/show_srv6_locator_table.ref create mode 100644 tests/topotests/srv6_sid_manager/rt3/show_yang_interface_isis_adjacencies.ref create mode 100644 tests/topotests/srv6_sid_manager/rt3/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/rt4/isisd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt4/show_ip_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt4/show_ipv6_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt4/show_srv6_locator_table.ref create mode 100644 tests/topotests/srv6_sid_manager/rt4/show_yang_interface_isis_adjacencies.ref create mode 100644 tests/topotests/srv6_sid_manager/rt4/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/rt5/isisd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt5/show_ip_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt5/show_ipv6_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt5/show_srv6_locator_table.ref create mode 100644 tests/topotests/srv6_sid_manager/rt5/show_yang_interface_isis_adjacencies.ref create mode 100644 tests/topotests/srv6_sid_manager/rt5/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/rt6/bgpd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt6/isisd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt6/sharpd.conf create mode 100644 tests/topotests/srv6_sid_manager/rt6/show_ip_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt6/show_ipv6_route.ref create mode 100644 tests/topotests/srv6_sid_manager/rt6/show_srv6_locator_table.ref create mode 100644 tests/topotests/srv6_sid_manager/rt6/show_yang_interface_isis_adjacencies.ref create mode 100644 tests/topotests/srv6_sid_manager/rt6/vpnv6_rib.ref create mode 100644 tests/topotests/srv6_sid_manager/rt6/vrf10_rib.ref create mode 100644 tests/topotests/srv6_sid_manager/rt6/vrf20_rib.ref create mode 100644 tests/topotests/srv6_sid_manager/rt6/zebra.conf create mode 100644 tests/topotests/srv6_sid_manager/test_srv6_sid_manager.py create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/__init__.py create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r1/bgpd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r1/ospfd.conf.after create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r1/zebra.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r2/bgpd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r2/isisd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r2/ospfd.conf.after create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r2/zebra.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r3/bgpd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r3/isisd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r3/ospfd.conf.after create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r3/zebra.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r4/bgpd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r4/isisd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r4/ospfd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r4/zebra.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r5/bgpd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r5/isisd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r5/ospfd.conf.after create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r5/zebra.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r6/ospfd.conf.after create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r6/zebra.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r7/bgpd.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r7/ospfd.conf.after create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/r7/zebra.conf create mode 100644 tests/topotests/zebra_fec_nexthop_resolution/test_zebra_fec_nexthop_resolution.py create mode 100644 tests/topotests/zebra_multiple_connected/r1/ip_route_connected.json create mode 100644 tests/topotests/zebra_multiple_connected/r1/ip_route_kernel.json create mode 100644 tests/topotests/zebra_multiple_connected/r1/ip_route_kernel_blackhole.json create mode 100644 yang/frr-pim-candidate.yang diff --git a/.clang-format b/.clang-format index 06769c96..72018d5a 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 @@ -224,4 +224,8 @@ WhitespaceSensitiveMacros: - "DEFUN_YANG_NOSH" - "DEFUNSH" - "DEFUNSH_HIDDEN" + - "ALIAS" + - "ALIAS_HIDDEN" + - "ALIAS_YANG" + - "ALIAS_DEPRECATED" ... diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 2cb3feec..855b5859 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -33,6 +33,8 @@ _libdir=/usr/lib _user=frr build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" + cd "$builddir" ./configure \ diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index c4349b50..b83c7b19 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -108,6 +108,7 @@ babel_interface_address_add (ZAPI_CALLBACK_ARGS) if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); + assert (babel_ifp != NULL); if (babel_ifp->ipv4 == NULL) { babel_ifp->ipv4 = malloc(4); if (babel_ifp->ipv4 == NULL) { @@ -144,6 +145,7 @@ babel_interface_address_delete (ZAPI_CALLBACK_ARGS) if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); + assert (babel_ifp != NULL); if (babel_ifp->ipv4 != NULL && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, IPV4_MAX_BYTELEN) == 0) { @@ -542,7 +544,10 @@ DEFPY (babel_set_channel, unsigned jitter(babel_interface_nfo *babel_ifp, int urgent) { - unsigned interval = babel_ifp->hello_interval; + unsigned interval; + + assert (babel_ifp != NULL); + interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else @@ -553,7 +558,10 @@ jitter(babel_interface_nfo *babel_ifp, int urgent) unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent) { - unsigned interval = babel_ifp->hello_interval; + unsigned interval; + + assert (babel_ifp != NULL); + interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else @@ -566,10 +574,11 @@ update_jitter(babel_interface_nfo *babel_ifp, int urgent) static int interface_recalculate(struct interface *ifp) { - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned char *tmp = NULL; int mtu, rc; struct ipv6_mreq mreq; + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert (babel_ifp != NULL); if (!IS_ENABLE(ifp)) return -1; @@ -656,6 +665,7 @@ interface_reset(struct interface *ifp) int rc; struct ipv6_mreq mreq; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert (babel_ifp != NULL); if (!CHECK_FLAG(babel_ifp->flags, BABEL_IF_IS_UP)) return 0; @@ -777,6 +787,7 @@ show_babel_interface_sub (struct vty *vty, struct interface *ifp) return; } babel_ifp = babel_get_if_nfo (ifp); + assert (babel_ifp != NULL); vty_out (vty, " Babel protocol is running on this interface\n"); vty_out (vty, " Operating mode is \"%s\"\n", CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless"); @@ -1160,6 +1171,11 @@ DEFUN (show_babel_parameters, return CMD_SUCCESS; } +void babel_if_terminate(void) +{ + vector_free(babel_enable_if); +} + void babel_if_init(void) { @@ -1228,6 +1244,7 @@ interface_config_write (struct vty *vty) if (ifp->desc) vty_out (vty, " description %s\n",ifp->desc); babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); + assert (babel_ifp != NULL); /* wireless is the default*/ if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) { @@ -1330,10 +1347,11 @@ babel_interface_allocate (void) { babel_interface_nfo *babel_ifp; babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); + assert (babel_ifp != NULL); /* 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; @@ -1349,6 +1367,8 @@ babel_interface_allocate (void) static void babel_interface_free (babel_interface_nfo *babel_ifp) { + assert (babel_ifp != NULL); + if (babel_ifp->ipv4){ free(babel_ifp->ipv4); babel_ifp->ipv4 = NULL; diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index a585e23a..ab08ded9 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -94,6 +94,7 @@ struct buffered_update { /* init function */ void babel_if_init(void); +void babel_if_terminate(void); /* Callback functions for zebra client */ int babel_interface_up (int, struct zclient *, zebra_size_t, vrf_id_t); diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 10ab1b53..ddc75f71 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -305,9 +305,9 @@ babel_exit_properly(void) /* Uninstall and flush all routes. */ debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); - flush_all_routes(); - babel_interface_close_all(); + babel_clean_routing_process(); babel_zebra_close_connexion(); + babel_if_terminate(); babel_save_state_file(); debugf(BABEL_DEBUG_COMMON, "Remove pid file."); debugf(BABEL_DEBUG_COMMON, "Done."); diff --git a/babeld/babeld.c b/babeld/babeld.c index 6f0a5a7b..b562f0b7 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)); @@ -299,8 +299,7 @@ babel_initial_noise(void) } /* Delete all the added babel routes, make babeld only speak to zebra. */ -static void -babel_clean_routing_process(void) +void babel_clean_routing_process(void) { flush_all_routes(); babel_interface_close_all(); @@ -444,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/babeld.h b/babeld/babeld.h index 5573719a..17a0381d 100644 --- a/babeld/babeld.h +++ b/babeld/babeld.h @@ -98,5 +98,6 @@ extern int redistribute_filter(const unsigned char *prefix, unsigned short plen, extern int resize_receive_buffer(int size); extern void schedule_neighbours_check(int msecs, int override); extern struct babel *babel_lookup(void); +extern void babel_clean_routing_process(void); #endif /* BABEL_BABELD_H */ diff --git a/babeld/kernel.c b/babeld/kernel.c index aed6dc9c..4957b04e 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 1b83eb9e..5a33d5c2 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 2c7e9237..466f4138 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 4facdabb..f5edb0ed 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 ddc6a70d..2242032c 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/bfd.c b/bfdd/bfd.c index 3096f47d..eb9c3003 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -256,19 +256,8 @@ void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) { - struct bfd_session *bs; - struct peer_label *pl; struct bfd_key key; - /* Try to find label first. */ - if (bpc->bpc_has_label) { - pl = pl_find(bpc->bpc_label); - if (pl != NULL) { - bs = pl->pl_bs; - return bs; - } - } - /* Otherwise fallback to peer/local hash lookup. */ gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, bpc->bpc_localif, bpc->bpc_vrfname); @@ -327,10 +316,8 @@ int bfd_session_enable(struct bfd_session *bs) bs->ifp = ifp; /* Attempt to use data plane. */ - if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) { - control_notify_config(BCM_NOTIFY_CONFIG_ADD, bs); + if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) return 0; - } /* Sanity check: don't leak open sockets. */ if (bs->sock != -1) { @@ -410,8 +397,8 @@ static uint32_t ptm_bfd_gen_ID(void) * random session identification numbers. */ do { - session_id = ((frr_weak_random() << 16) & 0xFFFF0000) - | (frr_weak_random() & 0x0000FFFF); + session_id = CHECK_FLAG((frr_weak_random() << 16), 0xFFFF0000) | + CHECK_FLAG(frr_weak_random(), 0x0000FFFF); } while (session_id == 0 || bfd_id_lookup(session_id) != NULL); return session_id; @@ -502,7 +489,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd) /* Start sending control packets with poll bit immediately. */ ptm_bfd_snd(bfd, 0); - control_notify(bfd, bfd->ses_state); + ptm_bfd_notify(bfd, bfd->ses_state); if (old_state != bfd->ses_state) { bfd->stats.session_up++; @@ -538,7 +525,7 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag) /* only signal clients when going from up->down state */ if (old_state == PTM_BFD_UP) - control_notify(bfd, PTM_BFD_DOWN); + ptm_bfd_notify(bfd, PTM_BFD_DOWN); /* Stop echo packet transmission if they are active */ if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) @@ -690,38 +677,6 @@ struct bfd_session *bfd_session_new(void) return bs; } -int bfd_session_update_label(struct bfd_session *bs, const char *nlabel) -{ - /* New label treatment: - * - Check if the label is taken; - * - Try to allocate the memory for it and register; - */ - if (bs->pl == NULL) { - if (pl_find(nlabel) != NULL) { - /* Someone is already using it. */ - return -1; - } - - pl_new(nlabel, bs); - - return 0; - } - - /* - * Test label change consistency: - * - Do nothing if it's the same label; - * - Check if the future label is already taken; - * - Change label; - */ - if (strcmp(nlabel, bs->pl->pl_label) == 0) - return -1; - if (pl_find(nlabel) != NULL) - return -1; - - strlcpy(bs->pl->pl_label, nlabel, sizeof(bs->pl->pl_label)); - return 0; -} - static void _bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) { @@ -750,9 +705,6 @@ static void _bfd_session_update(struct bfd_session *bs, bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx; } - if (bpc->bpc_has_label) - bfd_session_update_label(bs, bpc->bpc_label); - if (bpc->bpc_cbit) SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT); else @@ -792,8 +744,6 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) _bfd_session_update(bs, bpc); - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); - return 0; } @@ -819,8 +769,6 @@ void bfd_session_free(struct bfd_session *bs) if (bso != NULL) bs_observer_del(bso); - pl_free(bs->pl); - XFREE(MTYPE_BFDD_PROFILE, bs->profile_name); XFREE(MTYPE_BFDD_CONFIG, bs); } @@ -917,8 +865,6 @@ struct bfd_session *bs_registrate(struct bfd_session *bfd) if (bglobal.debug_peer_event) zlog_debug("session-new: %s", bs_to_string(bfd)); - control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd); - return bfd; } @@ -941,8 +887,6 @@ int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc) if (bglobal.debug_peer_event) zlog_debug("%s: %s", __func__, bs_to_string(bs)); - control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs); - bfd_session_free(bs); return 0; @@ -1166,11 +1110,8 @@ void bs_final_handler(struct bfd_session *bs) * When using demand mode we must disable the detection timer * for lost control packets. */ - if (bs->demand_mode) { - /* Notify watchers about changed timers. */ - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); + if (bs->demand_mode) return; - } /* * Calculate transmission time based on new timers. @@ -1189,9 +1130,6 @@ void bs_final_handler(struct bfd_session *bs) /* Apply new transmission timer immediately. */ ptm_bfd_start_xmt_timer(bs, false); - - /* Notify watchers about changed timers. */ - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); } void bs_set_slow_timers(struct bfd_session *bs) @@ -1261,7 +1199,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) if (bs->bdc) { bs->ses_state = PTM_BFD_ADM_DOWN; bfd_dplane_update_session(bs); - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); return; } @@ -1273,7 +1211,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) /* Change and notify state change. */ bs->ses_state = PTM_BFD_ADM_DOWN; - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* Don't try to send packets with a disabled session. */ if (bs->sock != -1) @@ -1289,13 +1227,13 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) if (bs->bdc) { bs->ses_state = PTM_BFD_DOWN; bfd_dplane_update_session(bs); - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); return; } /* Change and notify state change. */ bs->ses_state = PTM_BFD_DOWN; - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* Enable timers if non passive, otherwise stop them. */ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) { diff --git a/bfdd/bfd.h b/bfdd/bfd.h index f4ff884e..2f83b245 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -20,19 +20,73 @@ #include "lib/queue.h" #include "lib/vrf.h" -#include "bfdctl.h" - #ifdef BFD_DEBUG #define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY) #else #define BFDD_JSON_CONV_OPTIONS (0) #endif +#ifndef MAXNAMELEN +#define MAXNAMELEN 32 +#endif + +#define BPC_DEF_DETECTMULTIPLIER 3 +#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ +#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ +#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */ +#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */ + DECLARE_MGROUP(BFDD); -DECLARE_MTYPE(BFDD_CONTROL); -DECLARE_MTYPE(BFDD_NOTIFICATION); +DECLARE_MTYPE(BFDD_CLIENT); +DECLARE_MTYPE(BFDD_CLIENT_NOTIFICATION); + +struct sockaddr_any { + union { + struct sockaddr_in sa_sin; + struct sockaddr_in6 sa_sin6; + }; +}; + +struct bfd_peer_cfg { + bool bpc_mhop; + bool bpc_ipv4; + struct sockaddr_any bpc_peer; + struct sockaddr_any bpc_local; + + bool bpc_has_localif; + char bpc_localif[MAXNAMELEN + 1]; + + bool bpc_has_vrfname; + char bpc_vrfname[MAXNAMELEN + 1]; + + bool bpc_has_detectmultiplier; + uint8_t bpc_detectmultiplier; + + bool bpc_has_recvinterval; + uint64_t bpc_recvinterval; + + bool bpc_has_txinterval; + uint64_t bpc_txinterval; -#define BFDD_SOCK_NAME "%s/bfdd.sock", frr_runstatedir + bool bpc_has_echorecvinterval; + uint64_t bpc_echorecvinterval; + + bool bpc_has_echotxinterval; + uint64_t bpc_echotxinterval; + + bool bpc_has_minimum_ttl; + uint8_t bpc_minimum_ttl; + + bool bpc_echo; + bool bpc_createonly; + bool bpc_shutdown; + + bool bpc_cbit; + bool bpc_passive; + + bool bpc_has_profile; + char bpc_profile[64]; +}; /* bfd Authentication Type. */ #define BFD_AUTH_NULL 0 @@ -97,8 +151,9 @@ struct bfd_echo_pkt { /* Macros for manipulating control packets */ #define BFD_VERMASK 0x07 #define BFD_DIAGMASK 0x1F -#define BFD_GETVER(diag) ((diag >> 5) & BFD_VERMASK) -#define BFD_SETVER(diag, val) ((diag) |= (val & BFD_VERMASK) << 5) +#define BFD_GETVER(diag) (CHECK_FLAG((diag >> 5), BFD_VERMASK)) +#define BFD_SETVER(diag, val) \ + SET_FLAG((diag), CHECK_FLAG(val, BFD_VERMASK) << 5) #define BFD_VERSION 1 #define BFD_PBIT 0x20 #define BFD_FBIT 0x10 @@ -106,36 +161,36 @@ struct bfd_echo_pkt { #define BFD_ABIT 0x04 #define BFD_DEMANDBIT 0x02 #define BFD_MBIT 0x01 -#define BFD_GETMBIT(flags) (flags & BFD_MBIT) +#define BFD_GETMBIT(flags) (CHECK_FLAG(flags, BFD_MBIT)) #define BFD_SETDEMANDBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_DEMANDBIT; \ + SET_FLAG(flags, BFD_DEMANDBIT); \ } #define BFD_SETPBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_PBIT; \ + SET_FLAG(flags, BFD_PBIT); \ } -#define BFD_GETPBIT(flags) (flags & BFD_PBIT) +#define BFD_GETPBIT(flags) (CHECK_FLAG(flags, BFD_PBIT)) #define BFD_SETFBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_FBIT; \ + SET_FLAG(flags, BFD_FBIT); \ } -#define BFD_GETFBIT(flags) (flags & BFD_FBIT) +#define BFD_GETFBIT(flags) (CHECK_FLAG(flags, BFD_FBIT)) #define BFD_SETSTATE(flags, val) \ { \ if ((val)) \ - flags |= (val & 0x3) << 6; \ + SET_FLAG(flags, (CHECK_FLAG(val, 0x3) << 6)); \ } -#define BFD_GETSTATE(flags) ((flags >> 6) & 0x3) +#define BFD_GETSTATE(flags) (CHECK_FLAG((flags >> 6), 0x3)) #define BFD_SETCBIT(flags, val) \ { \ if ((val)) \ - flags |= val; \ + SET_FLAG(flags, val); \ } -#define BFD_GETCBIT(flags) (flags & BFD_CBIT) +#define BFD_GETCBIT(flags) (CHECK_FLAG(flags, BFD_CBIT)) #define BFD_ECHO_VERSION 1 #define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt) @@ -245,9 +300,6 @@ struct bfd_profile { /** Profile list type. */ TAILQ_HEAD(bfdproflist, bfd_profile); -/* bfd_session shortcut label forwarding. */ -struct peer_label; - struct bfd_config_timers { uint32_t desired_min_tx; uint32_t required_min_rx; @@ -325,14 +377,6 @@ struct bfd_session { uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */ }; -struct peer_label { - TAILQ_ENTRY(peer_label) pl_entry; - - struct bfd_session *pl_bs; - char pl_label[MAXNAMELEN]; -}; -TAILQ_HEAD(pllist, peer_label); - struct bfd_diag_str_list { const char *str; int type; @@ -384,64 +428,6 @@ TAILQ_HEAD(obslist, bfd_session_observer); #define BFD_DEF_ECHO_PORT 3785 #define BFD_DEF_MHOP_DEST_PORT 4784 -/* - * control.c - * - * Daemon control code to speak with local consumers. - */ - -/* See 'bfdctrl.h' for client protocol definitions. */ - -struct bfd_control_buffer { - size_t bcb_left; - size_t bcb_pos; - union { - struct bfd_control_msg *bcb_bcm; - uint8_t *bcb_buf; - }; -}; - -struct bfd_control_queue { - TAILQ_ENTRY(bfd_control_queue) bcq_entry; - - struct bfd_control_buffer bcq_bcb; -}; -TAILQ_HEAD(bcqueue, bfd_control_queue); - -struct bfd_notify_peer { - TAILQ_ENTRY(bfd_notify_peer) bnp_entry; - - struct bfd_session *bnp_bs; -}; -TAILQ_HEAD(bnplist, bfd_notify_peer); - -struct bfd_control_socket { - TAILQ_ENTRY(bfd_control_socket) bcs_entry; - - int bcs_sd; - struct event *bcs_ev; - struct event *bcs_outev; - struct bcqueue bcs_bcqueue; - - /* Notification data */ - uint64_t bcs_notify; - struct bnplist bcs_bnplist; - - enum bc_msg_version bcs_version; - enum bc_msg_type bcs_type; - - /* Message buffering */ - struct bfd_control_buffer bcs_bin; - struct bfd_control_buffer *bcs_bout; -}; -TAILQ_HEAD(bcslist, bfd_control_socket); - -int control_init(const char *path); -void control_shutdown(void); -int control_notify(struct bfd_session *bs, uint8_t notify_state); -int control_notify_config(const char *op, struct bfd_session *bs); -void control_accept(struct event *t); - /* * bfdd.c @@ -467,9 +453,6 @@ TAILQ_HEAD(dplane_queue, bfd_dplane_ctx); struct bfd_global { int bg_csock; struct event *bg_csockev; - struct bcslist bg_bcslist; - - struct pllist bg_pllist; struct obslist bg_obslist; @@ -515,27 +498,6 @@ extern const struct bfd_state_str_list state_list[]; void socket_close(int *s); -/* - * config.c - * - * Contains the code related with loading/reloading configuration. - */ -int parse_config(const char *fname); -int config_request_add(const char *jsonstr); -int config_request_del(const char *jsonstr); -char *config_response(const char *status, const char *error); -char *config_notify(struct bfd_session *bs); -char *config_notify_config(const char *op, struct bfd_session *bs); - -typedef int (*bpc_handle)(struct bfd_peer_cfg *, void *arg); -int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, - bpc_handle bh); - -struct peer_label *pl_new(const char *label, struct bfd_session *bs); -struct peer_label *pl_find(const char *label); -void pl_free(struct peer_label *pl); - - /* * logging - alias to zebra log */ @@ -620,7 +582,6 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, bool is_mhop); struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc); -int bfd_session_update_label(struct bfd_session *bs, const char *nlabel); void bfd_set_polling(struct bfd_session *bs); void bs_state_handler(struct bfd_session *bs, int nstate); void bs_echo_timer_handler(struct bfd_session *bs); diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 8110f434..f9397fa1 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -982,7 +982,7 @@ void bfd_recv_cb(struct event *t) } /* Save remote diagnostics before state switch. */ - bfd->remote_diag = cp->diag & BFD_DIAGMASK; + bfd->remote_diag = CHECK_FLAG(cp->diag, BFD_DIAGMASK); /* Update remote timers settings. */ bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx); @@ -1738,7 +1738,7 @@ void bfd_peer_mac_set(int sd, struct bfd_session *bfd, if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET)) return; - if (ifp->flags & IFF_NOARP) + if (CHECK_FLAG(ifp->flags, IFF_NOARP)) return; if (peer->sa_sin.sin_family == AF_INET) { diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h deleted file mode 100644 index f1f8185c..00000000 --- a/bfdd/bfdctl.h +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * bfdctl.h: all BFDd control socket protocol definitions. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#ifndef _BFDCTRL_H_ -#define _BFDCTRL_H_ - -#include - -#include -#include - -/* - * Auxiliary definitions - */ -struct sockaddr_any { - union { - struct sockaddr_in sa_sin; - struct sockaddr_in6 sa_sin6; - }; -}; - -#ifndef MAXNAMELEN -#define MAXNAMELEN 32 -#endif - -#define BPC_DEF_DETECTMULTIPLIER 3 -#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ -#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ -#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */ -#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */ - -/* Peer status */ -enum bfd_peer_status { - BPS_SHUTDOWN = 0, /* == PTM_BFD_ADM_DOWN, "adm-down" */ - BPS_DOWN = 1, /* == PTM_BFD_DOWN, "down" */ - BPS_INIT = 2, /* == PTM_BFD_INIT, "init" */ - BPS_UP = 3, /* == PTM_BFD_UP, "up" */ -}; - -struct bfd_peer_cfg { - bool bpc_mhop; - bool bpc_ipv4; - struct sockaddr_any bpc_peer; - struct sockaddr_any bpc_local; - - bool bpc_has_label; - char bpc_label[MAXNAMELEN]; - - bool bpc_has_localif; - char bpc_localif[MAXNAMELEN + 1]; - - bool bpc_has_vrfname; - char bpc_vrfname[MAXNAMELEN + 1]; - - bool bpc_has_detectmultiplier; - uint8_t bpc_detectmultiplier; - - bool bpc_has_recvinterval; - uint64_t bpc_recvinterval; - - bool bpc_has_txinterval; - uint64_t bpc_txinterval; - - bool bpc_has_echorecvinterval; - uint64_t bpc_echorecvinterval; - - bool bpc_has_echotxinterval; - uint64_t bpc_echotxinterval; - - bool bpc_has_minimum_ttl; - uint8_t bpc_minimum_ttl; - - bool bpc_echo; - bool bpc_createonly; - bool bpc_shutdown; - - bool bpc_cbit; - bool bpc_passive; - - bool bpc_has_profile; - char bpc_profile[64]; - - /* Status information */ - enum bfd_peer_status bpc_bps; - uint32_t bpc_id; - uint32_t bpc_remoteid; - uint8_t bpc_diag; - uint8_t bpc_remotediag; - uint8_t bpc_remote_detectmultiplier; - uint64_t bpc_remote_recvinterval; - uint64_t bpc_remote_txinterval; - uint64_t bpc_remote_echointerval; - uint64_t bpc_lastevent; -}; - - -/* - * Protocol definitions - */ -enum bc_msg_version { - BMV_VERSION_1 = 1, -}; - -enum bc_msg_type { - BMT_RESPONSE = 1, - BMT_REQUEST_ADD = 2, - BMT_REQUEST_DEL = 3, - BMT_NOTIFY = 4, - BMT_NOTIFY_ADD = 5, - BMT_NOTIFY_DEL = 6, -}; - -/* Notify flags to use with bcm_notify. */ -#define BCM_NOTIFY_ALL ((uint64_t)-1) -#define BCM_NOTIFY_PEER_STATE (1ULL << 0) -#define BCM_NOTIFY_CONFIG (1ULL << 1) -#define BCM_NOTIFY_NONE 0 - -/* Response 'status' definitions. */ -#define BCM_RESPONSE_OK "ok" -#define BCM_RESPONSE_ERROR "error" - -/* Notify operation. */ -#define BCM_NOTIFY_PEER_STATUS "status" -#define BCM_NOTIFY_CONFIG_ADD "add" -#define BCM_NOTIFY_CONFIG_DELETE "delete" -#define BCM_NOTIFY_CONFIG_UPDATE "update" - -/* Notification special ID. */ -#define BCM_NOTIFY_ID 0 - -struct bfd_control_msg { - /* Total length without the header. */ - uint32_t bcm_length; - /* - * Message request/response id. - * All requests will have a correspondent response with the - * same id. - */ - uint16_t bcm_id; - /* Message type. */ - uint8_t bcm_type; - /* Message version. */ - uint8_t bcm_ver; - /* Message payload. */ - uint8_t bcm_data[0]; -}; - -#endif diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 243cf5c1..c2d8e926 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -28,8 +28,8 @@ * FRR related code. */ DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon"); -DEFINE_MTYPE(BFDD, BFDD_CONTROL, "control socket memory"); -DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "control notification data"); +DEFINE_MTYPE(BFDD, BFDD_CLIENT, "BFD client data"); +DEFINE_MTYPE(BFDD, BFDD_CLIENT_NOTIFICATION, "BFD client notification data"); /* Master of threads. */ struct event_loop *master; @@ -67,9 +67,6 @@ static void sigterm_handler(void) /* Stop receiving message from zebra. */ bfdd_zclient_stop(); - /* Shutdown controller to avoid receiving anymore commands. */ - control_shutdown(); - /* Shutdown and free all protocol related memory. */ bfd_shutdown(); @@ -132,10 +129,8 @@ FRR_DAEMON_INFO(bfdd, BFD, ); /* clang-format on */ -#define OPTION_CTLSOCK 1001 #define OPTION_DPLANEADDR 2000 static const struct option longopts[] = { - {"bfdctl", required_argument, NULL, OPTION_CTLSOCK}, {"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR}, {0} }; @@ -319,7 +314,6 @@ static void bg_init(void) .cap_num_i = 0, }; - TAILQ_INIT(&bglobal.bg_bcslist); TAILQ_INIT(&bglobal.bg_obslist); memcpy(&bglobal.bfdd_privs, &bfdd_privs, @@ -328,8 +322,7 @@ static void bg_init(void) int main(int argc, char *argv[]) { - char ctl_path[512], dplane_addr[512]; - bool ctlsockused = false; + char dplane_addr[512]; int opt; bglobal.bg_use_dplane = false; @@ -339,7 +332,6 @@ int main(int argc, char *argv[]) frr_preinit(&bfdd_di, argc, argv); frr_opt_add("", longopts, - " --bfdctl Specify bfdd control socket\n" " --dplaneaddr Specify BFD data plane address\n"); while (true) { @@ -348,10 +340,6 @@ int main(int argc, char *argv[]) break; switch (opt) { - case OPTION_CTLSOCK: - strlcpy(ctl_path, optarg, sizeof(ctl_path)); - ctlsockused = true; - break; case OPTION_DPLANEADDR: strlcpy(dplane_addr, optarg, sizeof(dplane_addr)); bglobal.bg_use_dplane = true; @@ -362,15 +350,9 @@ int main(int argc, char *argv[]) } } - if (!ctlsockused) - snprintf(ctl_path, sizeof(ctl_path), BFDD_SOCK_NAME); - /* Initialize FRR infrastructure. */ master = frr_init(); - /* Initialize control socket. */ - control_init(ctl_path); - /* Initialize BFD data structures. */ bfd_initialize(); @@ -381,9 +363,6 @@ int main(int argc, char *argv[]) /* Initialize zebra connection. */ bfdd_zclient_init(&bglobal.bfdd_privs); - event_add_read(master, control_accept, NULL, bglobal.bg_csock, - &bglobal.bg_csockev); - /* Install commands. */ bfdd_vty_init(); diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 75034d22..2e213a22 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 ", + "[no] echo receive-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 ", + "[no] echo receive-interval ![]", + NO_STR "Configure peer echo intervals\n" "Configure required receive interval\n" "Disable echo packets receive\n" diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 496d5019..26554e14 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -84,9 +84,6 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs) if (bs->key.ifname[0]) vty_out(vty, " interface %s", bs->key.ifname); vty_out(vty, "\n"); - - if (bs->pl) - vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label); } static void _display_peer(struct vty *vty, struct bfd_session *bs) @@ -200,9 +197,6 @@ static struct json_object *_peer_json_header(struct bfd_session *bs) if (bs->key.ifname[0]) json_object_string_add(jo, "interface", bs->key.ifname); - if (bs->pl) - json_object_string_add(jo, "label", bs->pl->pl_label); - return jo; } @@ -561,17 +555,11 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, int idx; bool mhop; struct bfd_session *bs = NULL; - struct peer_label *pl; struct bfd_peer_cfg bpc; struct sockaddr_any psa, lsa, *lsap; char errormsg[128]; - /* Look up the BFD peer. */ - if (label) { - pl = pl_find(label); - if (pl) - bs = pl->pl_bs; - } else if (peer_str) { + if (peer_str) { strtosa(peer_str, &psa); if (local_str) { strtosa(local_str, &lsa); @@ -879,7 +867,6 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop, bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL; bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL; bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL; - bpc->bpc_lastevent = monotime(NULL); /* Safety check: when no error buf is provided len must be zero. */ if (ebuf == NULL) diff --git a/bfdd/config.c b/bfdd/config.c deleted file mode 100644 index 22d7d7de..00000000 --- a/bfdd/config.c +++ /dev/null @@ -1,592 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * config.c: implements the BFD daemon configuration handling. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#include - -#include - -#include "lib/json.h" - -#include "bfd.h" - -DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory"); - -/* - * Definitions - */ -enum peer_list_type { - PLT_IPV4, - PLT_IPV6, - PLT_LABEL, -}; - - -/* - * Prototypes - */ -static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg); -static int parse_list(struct json_object *jo, enum peer_list_type plt, - bpc_handle h, void *arg); -static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc); -static int parse_peer_label_config(struct json_object *jo, - struct bfd_peer_cfg *bpc); - -static int config_add(struct bfd_peer_cfg *bpc, void *arg); -static int config_del(struct bfd_peer_cfg *bpc, void *arg); - -static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs); - - -/* - * Implementation - */ -static int config_add(struct bfd_peer_cfg *bpc, - void *arg __attribute__((unused))) -{ - return ptm_bfd_sess_new(bpc) == NULL; -} - -static int config_del(struct bfd_peer_cfg *bpc, - void *arg __attribute__((unused))) -{ - return ptm_bfd_sess_del(bpc) != 0; -} - -static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg) -{ - const char *key, *sval; - struct json_object *jo_val; - struct json_object_iterator joi, join; - int error = 0; - - JSON_FOREACH (jo, joi, join) { - key = json_object_iter_peek_name(&joi); - jo_val = json_object_iter_peek_value(&joi); - - if (strcmp(key, "ipv4") == 0) { - error += parse_list(jo_val, PLT_IPV4, h, arg); - } else if (strcmp(key, "ipv6") == 0) { - error += parse_list(jo_val, PLT_IPV6, h, arg); - } else if (strcmp(key, "label") == 0) { - error += parse_list(jo_val, PLT_LABEL, h, arg); - } else { - sval = json_object_get_string(jo_val); - zlog_warn("%s:%d invalid configuration: %s", __func__, - __LINE__, sval); - error++; - } - } - - /* - * Our callers never call free() on json_object and only expect - * the return value, so lets free() it here. - */ - json_object_put(jo); - - return error; -} - -int parse_config(const char *fname) -{ - struct json_object *jo; - - jo = json_object_from_file(fname); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_add, NULL); -} - -static int parse_list(struct json_object *jo, enum peer_list_type plt, - bpc_handle h, void *arg) -{ - struct json_object *jo_val; - struct bfd_peer_cfg bpc; - int allen, idx; - int error = 0, result; - - allen = json_object_array_length(jo); - for (idx = 0; idx < allen; idx++) { - jo_val = json_object_array_get_idx(jo, idx); - - /* Set defaults. */ - memset(&bpc, 0, sizeof(bpc)); - bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT; - bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX; - bpc.bpc_txinterval = BFD_DEFDESIREDMINTX; - bpc.bpc_echorecvinterval = BFD_DEF_REQ_MIN_ECHO_RX; - bpc.bpc_echotxinterval = BFD_DEF_DES_MIN_ECHO_TX; - - switch (plt) { - case PLT_IPV4: - zlog_debug("ipv4 peers %d:", allen); - bpc.bpc_ipv4 = true; - break; - case PLT_IPV6: - zlog_debug("ipv6 peers %d:", allen); - bpc.bpc_ipv4 = false; - break; - case PLT_LABEL: - zlog_debug("label peers %d:", allen); - if (parse_peer_label_config(jo_val, &bpc) != 0) { - error++; - continue; - } - break; - - default: - error++; - zlog_err("%s:%d: unsupported peer type", __func__, - __LINE__); - break; - } - - result = parse_peer_config(jo_val, &bpc); - error += result; - if (result == 0) - error += (h(&bpc, arg) != 0); - } - - return error; -} - -static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) -{ - const char *key, *sval; - struct json_object *jo_val; - struct json_object_iterator joi, join; - int family_type = (bpc->bpc_ipv4) ? AF_INET : AF_INET6; - int error = 0; - - zlog_debug(" peer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6"); - - JSON_FOREACH (jo, joi, join) { - key = json_object_iter_peek_name(&joi); - jo_val = json_object_iter_peek_value(&joi); - - if (strcmp(key, "multihop") == 0) { - bpc->bpc_mhop = json_object_get_boolean(jo_val); - zlog_debug(" multihop: %s", - bpc->bpc_mhop ? "true" : "false"); - } else if (strcmp(key, "peer-address") == 0) { - sval = json_object_get_string(jo_val); - if (strtosa(sval, &bpc->bpc_peer) != 0 - || bpc->bpc_peer.sa_sin.sin_family != family_type) { - zlog_debug( - "%s:%d failed to parse peer-address '%s'", - __func__, __LINE__, sval); - error++; - } - zlog_debug(" peer-address: %s", sval); - } else if (strcmp(key, "local-address") == 0) { - sval = json_object_get_string(jo_val); - if (strtosa(sval, &bpc->bpc_local) != 0 - || bpc->bpc_local.sa_sin.sin_family - != family_type) { - zlog_debug( - "%s:%d failed to parse local-address '%s'", - __func__, __LINE__, sval); - error++; - } - zlog_debug(" local-address: %s", sval); - } else if (strcmp(key, "local-interface") == 0) { - bpc->bpc_has_localif = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_localif, sval, - sizeof(bpc->bpc_localif)) - > sizeof(bpc->bpc_localif)) { - zlog_debug( - " local-interface: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" local-interface: %s", sval); - } - } else if (strcmp(key, "vrf-name") == 0) { - bpc->bpc_has_vrfname = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_vrfname, sval, - sizeof(bpc->bpc_vrfname)) - > sizeof(bpc->bpc_vrfname)) { - zlog_debug(" vrf-name: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" vrf-name: %s", sval); - } - } else if (strcmp(key, "detect-multiplier") == 0) { - bpc->bpc_detectmultiplier = - json_object_get_int64(jo_val); - bpc->bpc_has_detectmultiplier = true; - zlog_debug(" detect-multiplier: %u", - bpc->bpc_detectmultiplier); - } else if (strcmp(key, "receive-interval") == 0) { - bpc->bpc_recvinterval = json_object_get_int64(jo_val); - bpc->bpc_has_recvinterval = true; - zlog_debug(" receive-interval: %" PRIu64, - bpc->bpc_recvinterval); - } else if (strcmp(key, "transmit-interval") == 0) { - bpc->bpc_txinterval = json_object_get_int64(jo_val); - bpc->bpc_has_txinterval = true; - zlog_debug(" transmit-interval: %" PRIu64, - bpc->bpc_txinterval); - } else if (strcmp(key, "echo-receive-interval") == 0) { - bpc->bpc_echorecvinterval = json_object_get_int64(jo_val); - bpc->bpc_has_echorecvinterval = true; - zlog_debug(" echo-receive-interval: %" PRIu64, - bpc->bpc_echorecvinterval); - } else if (strcmp(key, "echo-transmit-interval") == 0) { - bpc->bpc_echotxinterval = json_object_get_int64(jo_val); - bpc->bpc_has_echotxinterval = true; - zlog_debug(" echo-transmit-interval: %" PRIu64, - bpc->bpc_echotxinterval); - } else if (strcmp(key, "create-only") == 0) { - bpc->bpc_createonly = json_object_get_boolean(jo_val); - zlog_debug(" create-only: %s", - bpc->bpc_createonly ? "true" : "false"); - } else if (strcmp(key, "shutdown") == 0) { - bpc->bpc_shutdown = json_object_get_boolean(jo_val); - zlog_debug(" shutdown: %s", - bpc->bpc_shutdown ? "true" : "false"); - } else if (strcmp(key, "echo-mode") == 0) { - bpc->bpc_echo = json_object_get_boolean(jo_val); - zlog_debug(" echo-mode: %s", - bpc->bpc_echo ? "true" : "false"); - } else if (strcmp(key, "label") == 0) { - bpc->bpc_has_label = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_label, sval, - sizeof(bpc->bpc_label)) - > sizeof(bpc->bpc_label)) { - zlog_debug(" label: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" label: %s", sval); - } - } else { - sval = json_object_get_string(jo_val); - zlog_warn("%s:%d invalid configuration: '%s: %s'", - __func__, __LINE__, key, sval); - error++; - } - } - - if (bpc->bpc_peer.sa_sin.sin_family == 0) { - zlog_debug("%s:%d no peer address provided", __func__, - __LINE__); - error++; - } - - return error; -} - -static int parse_peer_label_config(struct json_object *jo, - struct bfd_peer_cfg *bpc) -{ - struct peer_label *pl; - struct json_object *label; - const char *sval; - - /* Get label and translate it to BFD daemon key. */ - if (!json_object_object_get_ex(jo, "label", &label)) - return 1; - - sval = json_object_get_string(label); - - pl = pl_find(sval); - if (pl == NULL) - return 1; - - zlog_debug(" peer-label: %s", sval); - - /* Translate the label into BFD address keys. */ - bs_to_bpc(pl->pl_bs, bpc); - - return 0; -} - - -/* - * Control socket JSON parsing. - */ -int config_request_add(const char *jsonstr) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_add, NULL); -} - -int config_request_del(const char *jsonstr) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_del, NULL); -} - -char *config_response(const char *status, const char *error) -{ - struct json_object *resp, *jo; - char *jsonstr; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - /* Add 'status' response key. */ - jo = json_object_new_string(status); - if (jo == NULL) { - json_object_put(resp); - return NULL; - } - - json_object_object_add(resp, "status", jo); - - /* Add 'error' response key. */ - if (error != NULL) { - jo = json_object_new_string(error); - if (jo == NULL) { - json_object_put(resp); - return NULL; - } - - json_object_object_add(resp, "error", jo); - } - - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -char *config_notify(struct bfd_session *bs) -{ - struct json_object *resp; - char *jsonstr; - time_t now; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - json_object_string_add(resp, "op", BCM_NOTIFY_PEER_STATUS); - - json_object_add_peer(resp, bs); - - /* Add status information */ - json_object_int_add(resp, "id", bs->discrs.my_discr); - json_object_int_add(resp, "remote-id", bs->discrs.my_discr); - - switch (bs->ses_state) { - case PTM_BFD_UP: - json_object_string_add(resp, "state", "up"); - - now = monotime(NULL); - json_object_int_add(resp, "uptime", now - bs->uptime.tv_sec); - break; - case PTM_BFD_ADM_DOWN: - json_object_string_add(resp, "state", "adm-down"); - break; - case PTM_BFD_DOWN: - json_object_string_add(resp, "state", "down"); - - now = monotime(NULL); - json_object_int_add(resp, "downtime", - now - bs->downtime.tv_sec); - break; - case PTM_BFD_INIT: - json_object_string_add(resp, "state", "init"); - break; - - default: - json_object_string_add(resp, "state", "unknown"); - break; - } - - json_object_int_add(resp, "diagnostics", bs->local_diag); - json_object_int_add(resp, "remote-diagnostics", bs->remote_diag); - - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -char *config_notify_config(const char *op, struct bfd_session *bs) -{ - struct json_object *resp; - char *jsonstr; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - json_object_string_add(resp, "op", op); - - json_object_add_peer(resp, bs); - - /* On peer deletion we don't need to add any additional information. */ - if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0) - goto skip_config; - - json_object_int_add(resp, "detect-multiplier", bs->detect_mult); - json_object_int_add(resp, "receive-interval", - bs->timers.required_min_rx / 1000); - json_object_int_add(resp, "transmit-interval", - bs->timers.desired_min_tx / 1000); - json_object_int_add(resp, "echo-receive-interval", - bs->timers.required_min_echo_rx / 1000); - json_object_int_add(resp, "echo-transmit-interval", - bs->timers.desired_min_echo_tx / 1000); - - json_object_int_add(resp, "remote-detect-multiplier", - bs->remote_detect_mult); - json_object_int_add(resp, "remote-receive-interval", - bs->remote_timers.required_min_rx / 1000); - json_object_int_add(resp, "remote-transmit-interval", - bs->remote_timers.desired_min_tx / 1000); - json_object_int_add(resp, "remote-echo-receive-interval", - bs->remote_timers.required_min_echo / 1000); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) - json_object_boolean_true_add(resp, "echo-mode"); - else - json_object_boolean_false_add(resp, "echo-mode"); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) - json_object_boolean_true_add(resp, "shutdown"); - else - json_object_boolean_false_add(resp, "shutdown"); - -skip_config: - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, - bpc_handle bh) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, bh, bcs); -} - -static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) -{ - char addr_buf[INET6_ADDRSTRLEN]; - - /* Add peer 'key' information. */ - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) - json_object_boolean_true_add(jo, "ipv6"); - else - json_object_boolean_false_add(jo, "ipv6"); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - json_object_boolean_true_add(jo, "multihop"); - json_object_string_add(jo, "peer-address", - inet_ntop(bs->key.family, &bs->key.peer, - addr_buf, sizeof(addr_buf))); - json_object_string_add(jo, "local-address", - inet_ntop(bs->key.family, &bs->key.local, - addr_buf, sizeof(addr_buf))); - if (bs->key.vrfname[0]) - json_object_string_add(jo, "vrf-name", bs->key.vrfname); - } else { - json_object_boolean_false_add(jo, "multihop"); - json_object_string_add(jo, "peer-address", - inet_ntop(bs->key.family, &bs->key.peer, - addr_buf, sizeof(addr_buf))); - if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) - json_object_string_add( - jo, "local-address", - inet_ntop(bs->key.family, &bs->key.local, - addr_buf, sizeof(addr_buf))); - if (bs->key.ifname[0]) - json_object_string_add(jo, "local-interface", - bs->key.ifname); - } - - if (bs->pl) - json_object_string_add(jo, "label", bs->pl->pl_label); - - return 0; -} - - -/* - * Label handling - */ -struct peer_label *pl_find(const char *label) -{ - struct peer_label *pl; - - TAILQ_FOREACH (pl, &bglobal.bg_pllist, pl_entry) { - if (strcmp(pl->pl_label, label) != 0) - continue; - - return pl; - } - - return NULL; -} - -struct peer_label *pl_new(const char *label, struct bfd_session *bs) -{ - struct peer_label *pl; - - pl = XCALLOC(MTYPE_BFDD_LABEL, sizeof(*pl)); - - if (strlcpy(pl->pl_label, label, sizeof(pl->pl_label)) - > sizeof(pl->pl_label)) - zlog_warn("%s:%d: label was truncated", __func__, __LINE__); - - pl->pl_bs = bs; - bs->pl = pl; - - TAILQ_INSERT_HEAD(&bglobal.bg_pllist, pl, pl_entry); - - return pl; -} - -void pl_free(struct peer_label *pl) -{ - if (pl == NULL) - return; - - /* Remove the pointer back. */ - pl->pl_bs->pl = NULL; - - TAILQ_REMOVE(&bglobal.bg_pllist, pl, pl_entry); - XFREE(MTYPE_BFDD_LABEL, pl); -} diff --git a/bfdd/control.c b/bfdd/control.c deleted file mode 100644 index 98fd813e..00000000 --- a/bfdd/control.c +++ /dev/null @@ -1,844 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * control.c: implements the BFD daemon control socket. It will be used - * to talk with clients daemon/scripts/consumers. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#include - -#include -#include - -#include - -#include "bfd.h" - -/* - * Prototypes - */ -static int sock_set_nonblock(int fd); -struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs); -static void control_queue_free(struct bfd_control_socket *bcs, - struct bfd_control_queue *bcq); -static int control_queue_dequeue(struct bfd_control_socket *bcs); -static int control_queue_enqueue(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static int control_queue_enqueue_first(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs, - struct bfd_session *bs); -static void control_notifypeer_free(struct bfd_control_socket *bcs, - struct bfd_notify_peer *bnp); -struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs, - struct bfd_session *bs); - - -struct bfd_control_socket *control_new(int sd); -static void control_free(struct bfd_control_socket *bcs); -static void control_reset_buf(struct bfd_control_buffer *bcb); -static void control_read(struct event *t); -static void control_write(struct event *t); - -static void control_handle_request_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_handle_request_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg); -static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg); -static void control_handle_notify_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_handle_notify_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void _control_handle_notify(struct hash_bucket *hb, void *arg); -static void control_handle_notify(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_response(struct bfd_control_socket *bcs, uint16_t id, - const char *status, const char *error); - -static void _control_notify_config(struct bfd_control_socket *bcs, - const char *op, struct bfd_session *bs); -static void _control_notify(struct bfd_control_socket *bcs, - struct bfd_session *bs); - - -/* - * Functions - */ -static int sock_set_nonblock(int fd) -{ - int flags; - - flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) { - zlog_warn("%s: fcntl F_GETFL: %s", __func__, strerror(errno)); - return -1; - } - - flags |= O_NONBLOCK; - if (fcntl(fd, F_SETFL, flags) == -1) { - zlog_warn("%s: fcntl F_SETFL: %s", __func__, strerror(errno)); - return -1; - } - - return 0; -} - -int control_init(const char *path) -{ - int sd; - mode_t umval; - struct sockaddr_un sun_ = { - .sun_family = AF_UNIX, - }; - - assert(path); - - strlcpy(sun_.sun_path, path, sizeof(sun_.sun_path)); - - /* Remove previously created sockets. */ - unlink(sun_.sun_path); - - sd = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC); - if (sd == -1) { - zlog_err("%s: socket: %s", __func__, strerror(errno)); - return -1; - } - - umval = umask(0); - if (bind(sd, (struct sockaddr *)&sun_, sizeof(sun_)) == -1) { - zlog_err("%s: bind: %s", __func__, strerror(errno)); - close(sd); - return -1; - } - umask(umval); - - if (listen(sd, SOMAXCONN) == -1) { - zlog_err("%s: listen: %s", __func__, strerror(errno)); - close(sd); - return -1; - } - - sock_set_nonblock(sd); - - bglobal.bg_csock = sd; - - return 0; -} - -void control_shutdown(void) -{ - struct bfd_control_socket *bcs; - - event_cancel(&bglobal.bg_csockev); - - socket_close(&bglobal.bg_csock); - - while (!TAILQ_EMPTY(&bglobal.bg_bcslist)) { - bcs = TAILQ_FIRST(&bglobal.bg_bcslist); - control_free(bcs); - } -} - -void control_accept(struct event *t) -{ - int csock, sd = EVENT_FD(t); - - csock = accept(sd, NULL, 0); - if (csock == -1) { - zlog_warn("%s: accept: %s", __func__, strerror(errno)); - return; - } - - control_new(csock); - - event_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev); -} - - -/* - * Client handling - */ -struct bfd_control_socket *control_new(int sd) -{ - struct bfd_control_socket *bcs; - - bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs)); - - /* Disable notifications by default. */ - bcs->bcs_notify = 0; - - bcs->bcs_sd = sd; - event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev); - - TAILQ_INIT(&bcs->bcs_bcqueue); - TAILQ_INIT(&bcs->bcs_bnplist); - TAILQ_INSERT_TAIL(&bglobal.bg_bcslist, bcs, bcs_entry); - - return bcs; -} - -static void control_free(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - struct bfd_notify_peer *bnp; - - event_cancel(&(bcs->bcs_ev)); - event_cancel(&(bcs->bcs_outev)); - - close(bcs->bcs_sd); - - TAILQ_REMOVE(&bglobal.bg_bcslist, bcs, bcs_entry); - - /* Empty output queue. */ - while (!TAILQ_EMPTY(&bcs->bcs_bcqueue)) { - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - control_queue_free(bcs, bcq); - } - - /* Empty notification list. */ - while (!TAILQ_EMPTY(&bcs->bcs_bnplist)) { - bnp = TAILQ_FIRST(&bcs->bcs_bnplist); - control_notifypeer_free(bcs, bnp); - } - - control_reset_buf(&bcs->bcs_bin); - XFREE(MTYPE_BFDD_CONTROL, bcs); -} - -struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_notify_peer *bnp; - - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - return bnp; - - bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp)); - - TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry); - bnp->bnp_bs = bs; - bs->refcount++; - - return bnp; -} - -static void control_notifypeer_free(struct bfd_control_socket *bcs, - struct bfd_notify_peer *bnp) -{ - TAILQ_REMOVE(&bcs->bcs_bnplist, bnp, bnp_entry); - bnp->bnp_bs->refcount--; - XFREE(MTYPE_BFDD_CONTROL, bnp); -} - -struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_notify_peer *bnp; - - TAILQ_FOREACH (bnp, &bcs->bcs_bnplist, bnp_entry) { - if (bnp->bnp_bs == bs) - return bnp; - } - - return NULL; -} - -struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - - bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq)); - - control_reset_buf(&bcq->bcq_bcb); - TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry); - - return bcq; -} - -static void control_queue_free(struct bfd_control_socket *bcs, - struct bfd_control_queue *bcq) -{ - control_reset_buf(&bcq->bcq_bcb); - TAILQ_REMOVE(&bcs->bcs_bcqueue, bcq, bcq_entry); - XFREE(MTYPE_BFDD_NOTIFICATION, bcq); -} - -static int control_queue_dequeue(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - - /* List is empty, nothing to do. */ - if (TAILQ_EMPTY(&bcs->bcs_bcqueue)) - goto empty_list; - - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - control_queue_free(bcs, bcq); - - /* Get the next buffer to send. */ - if (TAILQ_EMPTY(&bcs->bcs_bcqueue)) - goto empty_list; - - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - bcs->bcs_bout = &bcq->bcq_bcb; - - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - - return 1; - -empty_list: - event_cancel(&(bcs->bcs_outev)); - bcs->bcs_bout = NULL; - return 0; -} - -static int control_queue_enqueue(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - struct bfd_control_queue *bcq; - struct bfd_control_buffer *bcb; - - bcq = control_queue_new(bcs); - - bcb = &bcq->bcq_bcb; - bcb->bcb_left = sizeof(struct bfd_control_msg) + ntohl(bcm->bcm_length); - bcb->bcb_pos = 0; - bcb->bcb_bcm = bcm; - - /* If this is the first item, then dequeue and start using it. */ - if (bcs->bcs_bout == NULL) { - bcs->bcs_bout = bcb; - - /* New messages, active write events. */ - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - } - - return 0; -} - -static int control_queue_enqueue_first(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - struct bfd_control_queue *bcq, *bcqn; - struct bfd_control_buffer *bcb; - - /* Enqueue it somewhere. */ - if (control_queue_enqueue(bcs, bcm) == -1) - return -1; - - /* - * The item is either the first or the last. So we must first - * check the best case where the item is already the first. - */ - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - bcb = &bcq->bcq_bcb; - if (bcm == bcb->bcb_bcm) - return 0; - - /* - * The item was not the first, so it is the last. We'll try to - * assign it to the head of the queue, however if there is a - * transfer in progress, then we have to make the item as the - * next one. - * - * Interrupting the transfer of in progress message will cause - * the client to lose track of the message position/data. - */ - bcqn = TAILQ_LAST(&bcs->bcs_bcqueue, bcqueue); - TAILQ_REMOVE(&bcs->bcs_bcqueue, bcqn, bcq_entry); - if (bcb->bcb_pos != 0) { - /* - * First position is already being sent, insert into - * second position. - */ - TAILQ_INSERT_AFTER(&bcs->bcs_bcqueue, bcq, bcqn, bcq_entry); - } else { - /* - * Old message didn't start being sent, we still have - * time to put this one in the head of the queue. - */ - TAILQ_INSERT_HEAD(&bcs->bcs_bcqueue, bcqn, bcq_entry); - bcb = &bcqn->bcq_bcb; - bcs->bcs_bout = bcb; - } - - return 0; -} - -static void control_reset_buf(struct bfd_control_buffer *bcb) -{ - /* Get ride of old data. */ - XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf); - bcb->bcb_pos = 0; - bcb->bcb_left = 0; -} - -static void control_read(struct event *t) -{ - struct bfd_control_socket *bcs = EVENT_ARG(t); - struct bfd_control_buffer *bcb = &bcs->bcs_bin; - int sd = bcs->bcs_sd; - struct bfd_control_msg bcm; - ssize_t bread; - size_t plen; - - /* - * Check if we have already downloaded message content, if so then skip - * to - * download the rest of it and process. - * - * Otherwise download a new message header and allocate the necessary - * memory. - */ - if (bcb->bcb_buf != NULL) - goto skip_header; - - bread = read(sd, &bcm, sizeof(bcm)); - if (bread == 0) { - control_free(bcs); - return; - } - if (bread < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - goto schedule_next_read; - - zlog_warn("%s: read: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - /* Validate header fields. */ - plen = ntohl(bcm.bcm_length); - if (plen < 2) { - zlog_debug("%s: client closed due small message length: %d", - __func__, bcm.bcm_length); - control_free(bcs); - return; - } - -#define FRR_BFD_MAXLEN 10 * 1024 - - if (plen > FRR_BFD_MAXLEN) { - zlog_debug("%s: client closed, invalid message length: %d", - __func__, bcm.bcm_length); - control_free(bcs); - return; - } - - if (bcm.bcm_ver != BMV_VERSION_1) { - zlog_debug("%s: client closed due bad version: %d", __func__, - bcm.bcm_ver); - control_free(bcs); - return; - } - - /* Prepare the buffer to load the message. */ - bcs->bcs_version = bcm.bcm_ver; - bcs->bcs_type = bcm.bcm_type; - - bcb->bcb_pos = sizeof(bcm); - bcb->bcb_left = plen; - bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(bcm) + bcb->bcb_left + 1); - if (bcb->bcb_buf == NULL) { - zlog_warn("%s: not enough memory for message size: %zu", - __func__, bcb->bcb_left); - control_free(bcs); - return; - } - - memcpy(bcb->bcb_buf, &bcm, sizeof(bcm)); - - /* Terminate data string with NULL for later processing. */ - bcb->bcb_buf[sizeof(bcm) + bcb->bcb_left] = 0; - -skip_header: - /* Download the remaining data of the message and process it. */ - bread = read(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); - if (bread == 0) { - control_free(bcs); - return; - } - if (bread < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - goto schedule_next_read; - - zlog_warn("%s: read: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - bcb->bcb_pos += bread; - bcb->bcb_left -= bread; - /* We need more data, return to wait more. */ - if (bcb->bcb_left > 0) - goto schedule_next_read; - - switch (bcb->bcb_bcm->bcm_type) { - case BMT_REQUEST_ADD: - control_handle_request_add(bcs, bcb->bcb_bcm); - break; - case BMT_REQUEST_DEL: - control_handle_request_del(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY: - control_handle_notify(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY_ADD: - control_handle_notify_add(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY_DEL: - control_handle_notify_del(bcs, bcb->bcb_bcm); - break; - - default: - zlog_debug("%s: unhandled message type: %d", __func__, - bcb->bcb_bcm->bcm_type); - control_response(bcs, bcb->bcb_bcm->bcm_id, BCM_RESPONSE_ERROR, - "invalid message type"); - break; - } - - bcs->bcs_version = 0; - bcs->bcs_type = 0; - control_reset_buf(bcb); - -schedule_next_read: - bcs->bcs_ev = NULL; - event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev); -} - -static void control_write(struct event *t) -{ - struct bfd_control_socket *bcs = EVENT_ARG(t); - struct bfd_control_buffer *bcb = bcs->bcs_bout; - int sd = bcs->bcs_sd; - ssize_t bwrite; - - bwrite = write(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); - if (bwrite == 0) { - control_free(bcs); - return; - } - if (bwrite < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - return; - } - - zlog_warn("%s: write: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - bcb->bcb_pos += bwrite; - bcb->bcb_left -= bwrite; - if (bcb->bcb_left > 0) { - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - return; - } - - control_queue_dequeue(bcs); -} - - -/* - * Message processing - */ -static void control_handle_request_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_request_add(json) == 0) - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - else - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "request add failed"); -} - -static void control_handle_request_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_request_del(json) == 0) - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - else - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "request del failed"); -} - -static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc) -{ - struct peer_label *pl; - - if (bpc->bpc_has_label) { - pl = pl_find(bpc->bpc_label); - if (pl) - return pl->pl_bs; - } - - return bs_peer_find(bpc); -} - -static void _control_handle_notify(struct hash_bucket *hb, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = hb->data; - - /* Notify peer configuration. */ - if (bcs->bcs_notify & BCM_NOTIFY_CONFIG) - _control_notify_config(bcs, BCM_NOTIFY_CONFIG_ADD, bs); - - /* Notify peer status. */ - if (bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) - _control_notify(bcs, bs); -} - -static void control_handle_notify(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - memcpy(&bcs->bcs_notify, bcm->bcm_data, sizeof(bcs->bcs_notify)); - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - - /* - * If peer asked for notification configuration, send everything that - * was configured until the moment to sync up. - */ - if (bcs->bcs_notify & (BCM_NOTIFY_CONFIG | BCM_NOTIFY_PEER_STATE)) - bfd_id_iterate(_control_handle_notify, bcs); -} - -static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = _notify_find_peer(bpc); - - if (bs == NULL) - return -1; - - control_notifypeer_new(bcs, bs); - - /* Notify peer status. */ - _control_notify(bcs, bs); - - return 0; -} - -static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = _notify_find_peer(bpc); - struct bfd_notify_peer *bnp; - - if (bs == NULL) - return -1; - - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - control_notifypeer_free(bcs, bnp); - - return 0; -} - -static void control_handle_notify_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_notify_request(bcs, json, notify_add_cb) == 0) { - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - return; - } - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "failed to parse notify data"); -} - -static void control_handle_notify_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_notify_request(bcs, json, notify_del_cb) == 0) { - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - return; - } - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "failed to parse notify data"); -} - - -/* - * Internal functions used by the BFD daemon. - */ -static void control_response(struct bfd_control_socket *bcs, uint16_t id, - const char *status, const char *error) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_response(status, error); - if (jsonstr == NULL) { - zlog_warn("%s: config_response: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_RESPONSE; - bcm->bcm_id = id; - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue_first(bcs, bcm); -} - -static void _control_notify(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_notify(bs); - if (jsonstr == NULL) { - zlog_warn("%s: config_notify: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_NOTIFY; - bcm->bcm_id = htons(BCM_NOTIFY_ID); - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue(bcs, bcm); -} - -int control_notify(struct bfd_session *bs, uint8_t notify_state) -{ - struct bfd_control_socket *bcs; - struct bfd_notify_peer *bnp; - - /* Notify zebra listeners as well. */ - ptm_bfd_notify(bs, notify_state); - - /* - * PERFORMANCE: reuse the bfd_control_msg allocated data for - * all control sockets to avoid wasting memory. - */ - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - /* - * Test for all notifications first, then search for - * specific peers. - */ - if ((bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) == 0) { - bnp = control_notifypeer_find(bcs, bs); - /* - * If the notification is not configured here, - * don't send it. - */ - if (bnp == NULL) - continue; - } - - _control_notify(bcs, bs); - } - - return 0; -} - -static void _control_notify_config(struct bfd_control_socket *bcs, - const char *op, struct bfd_session *bs) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_notify_config(op, bs); - if (jsonstr == NULL) { - zlog_warn("%s: config_notify_config: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_NOTIFY; - bcm->bcm_id = htons(BCM_NOTIFY_ID); - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue(bcs, bcm); -} - -int control_notify_config(const char *op, struct bfd_session *bs) -{ - struct bfd_control_socket *bcs; - struct bfd_notify_peer *bnp; - - /* Remove the control sockets notification for this peer. */ - if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0 && bs->refcount > 0) { - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - control_notifypeer_free(bcs, bnp); - } - } - - /* - * PERFORMANCE: reuse the bfd_control_msg allocated data for - * all control sockets to avoid wasting memory. - */ - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - /* - * Test for all notifications first, then search for - * specific peers. - */ - if ((bcs->bcs_notify & BCM_NOTIFY_CONFIG) == 0) - continue; - - _control_notify_config(bcs, op, bs); - } - - return 0; -} diff --git a/bfdd/dplane.c b/bfdd/dplane.c index d8539812..7f55f340 100644 --- a/bfdd/dplane.c +++ b/bfdd/dplane.c @@ -354,7 +354,7 @@ bfd_dplane_session_state_change(struct bfd_dplane_ctx *bdc, bs->remote_timers.required_min_echo = ntohl(state->required_echo_rx); /* Notify and update counters. */ - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* No state change. */ if (old_state == bs->ses_state) diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index b5ab2ef1..f6ebefb7 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -148,7 +148,6 @@ static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag) "ptm-del-session: [%s] session refcount is zero but it was configured by CLI", bs_to_string(bs)); } else { - control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs); bfd_session_free(bs); } } @@ -892,7 +891,7 @@ static struct ptm_client *pc_new(uint32_t pid) return pc; /* Allocate the client data and save it. */ - pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc)); + pc = XCALLOC(MTYPE_BFDD_CLIENT, sizeof(*pc)); pc->pc_pid = pid; TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry); @@ -910,7 +909,7 @@ static void pc_free(struct ptm_client *pc) pcn_free(pcn); } - XFREE(MTYPE_BFDD_CONTROL, pc); + XFREE(MTYPE_BFDD_CLIENT, pc); } static void pc_free_all(void) @@ -934,7 +933,7 @@ static struct ptm_client_notification *pcn_new(struct ptm_client *pc, return pcn; /* Save the client notification data. */ - pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn)); + pcn = XCALLOC(MTYPE_BFDD_CLIENT_NOTIFICATION, sizeof(*pcn)); TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry); pcn->pcn_pc = pc; @@ -982,5 +981,5 @@ static void pcn_free(struct ptm_client_notification *pcn) pcn->pcn_pc = NULL; TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry); - XFREE(MTYPE_BFDD_NOTIFICATION, pcn); + XFREE(MTYPE_BFDD_CLIENT_NOTIFICATION, pcn); } diff --git a/bfdd/subdir.am b/bfdd/subdir.am index b86a1896..5d2d8fda 100644 --- a/bfdd/subdir.am +++ b/bfdd/subdir.am @@ -17,8 +17,6 @@ bfdd_libbfd_a_SOURCES = \ bfdd/bfdd_vty.c \ bfdd/bfdd_cli.c \ bfdd/bfd_packet.c \ - bfdd/config.c \ - bfdd/control.c \ bfdd/dplane.c \ bfdd/event.c \ bfdd/ptm_adapter.c \ @@ -37,7 +35,6 @@ clippy_scan += \ # end noinst_HEADERS += \ - bfdd/bfdctl.h \ bfdd/bfdd_nb.h \ bfdd/bfd.h \ # end diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index f391c138..aada6e55 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -361,8 +361,7 @@ void bgp_addpath_type_changed(struct bgp *bgp) } } -int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, - uint8_t paths) +int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths) { int action = CAPABILITY_ACTION_UNSET; @@ -392,8 +391,7 @@ int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, * change take effect. */ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, - enum bgp_addpath_strat addpath_type, - uint8_t paths) + enum bgp_addpath_strat addpath_type, uint16_t paths) { struct bgp *bgp = peer->bgp; enum bgp_addpath_strat old_type; diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h index c267ebe4..f1ff98ea 100644 --- a/bgpd/bgp_addpath.h +++ b/bgpd/bgp_addpath.h @@ -62,13 +62,11 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat, * Change the type of addpath used for a peer. */ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, - enum bgp_addpath_strat addpath_type, - uint8_t paths); + enum bgp_addpath_strat addpath_type, uint16_t paths); void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, safi_t safi); void bgp_addpath_type_changed(struct bgp *bgp); -extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, - uint8_t paths); +extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths); #endif diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e4ee589a..1a2fa831 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) { @@ -479,22 +480,11 @@ static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt, int length, return false; } -static uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi) -{ - uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr); - - if (bpi->nexthop) - return aigp + bpi->nexthop->metric; - else - return aigp; -} - -static void stream_put_bgp_aigp_tlv_metric(struct stream *s, - struct bgp_path_info *bpi) +static void stream_put_bgp_aigp_tlv_metric(struct stream *s, uint64_t aigp) { stream_putc(s, BGP_AIGP_TLV_METRIC); stream_putw(s, BGP_AIGP_TLV_METRIC_LEN); - stream_putq(s, bgp_aigp_metric_total(bpi)); + stream_putq(s, aigp); } static bool bgp_attr_aigp_valid(uint8_t *pnt, int length) @@ -549,6 +539,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 +853,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 +881,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 +899,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 +932,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 +1022,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 +1089,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 +1144,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 +1173,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 +1214,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 +1233,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 +1288,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 +1330,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 +1366,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 +1425,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 +1550,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 +1665,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 +1707,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 +1757,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 +1861,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 +1911,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 +1934,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 +1972,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 +2001,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 +2059,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 +2110,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 +2149,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 +2167,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 +2209,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 +2301,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 +2559,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 +2611,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; } @@ -2575,7 +2661,6 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; - uint8_t sticky = 0; bool proxy = false; struct ecommunity *ecomm; @@ -2586,10 +2671,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); @@ -2605,23 +2689,22 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg); /* Extract MAC mobility sequence number, if any. */ - attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky); - attr->sticky = sticky; + attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr); /* Check if this is a Gateway MAC-IP advertisement */ - attr->default_gw = bgp_attr_default_gw(attr); + bgp_attr_default_gw(attr); /* Handle scenario where router flag ecommunity is not * set but default gw ext community is present. * Use default gateway, set and propogate R-bit. */ - if (attr->default_gw) - attr->router_flag = 1; + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER); /* Check EVPN Neighbor advertisement flags, R-bit */ - bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy); + 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)) { @@ -2692,6 +2775,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", @@ -2810,7 +2896,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); } @@ -3202,6 +3295,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) { @@ -3249,6 +3345,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) @@ -3263,6 +3364,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. */ @@ -3291,7 +3395,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); @@ -3299,6 +3403,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) */ @@ -3369,7 +3478,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; @@ -3566,18 +3675,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, @@ -3924,7 +4032,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; @@ -4102,8 +4210,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, @@ -4324,12 +4432,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) { @@ -4440,14 +4548,11 @@ static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer, } /* Make attribute packet. */ -bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, - struct stream *s, struct attr *attr, - struct bpacket_attr_vec_arr *vecarr, - struct prefix *p, afi_t afi, safi_t safi, - struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, uint8_t num_labels, - bool addpath_capable, uint32_t addpath_tx_id, - struct bgp_path_info *bpi) +bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct stream *s, + struct attr *attr, struct bpacket_attr_vec_arr *vecarr, + struct prefix *p, afi_t afi, safi_t safi, struct peer *from, + struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels, + bool addpath_capable, uint32_t addpath_tx_id) { size_t cp; size_t aspath_sizep; @@ -4476,6 +4581,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, bgp_packet_mpattr_end(s, mpattrlen_pos); } + (void)peer_sort(peer); + /* Origin attribute. */ stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_ORIGIN); @@ -4569,15 +4676,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 +4706,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 +4725,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 +4763,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 +4788,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 +4819,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 +4833,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 +4842,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 +5010,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 +5023,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,10 +5031,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } /* AIGP */ - if (bpi && 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)) { + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && AIGP_TRANSMIT_ALLOWED(peer)) { /* 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. @@ -4936,7 +5041,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); stream_putc(s, BGP_ATTR_AIGP); stream_putc(s, attr_len); - stream_put_bgp_aigp_tlv_metric(s, bpi); + stream_put_bgp_aigp_tlv_metric(s, attr->aigp_metric); } /* Unknown transit attribute. */ @@ -5006,6 +5111,7 @@ void bgp_attr_init(void) transit_init(); encap_init(); srv6_init(); + evpn_overlay_init(); } void bgp_attr_finish(void) @@ -5019,6 +5125,7 @@ void bgp_attr_finish(void) transit_finish(); encap_finish(); srv6_finish(); + evpn_overlay_finish(); } /* Make attribute packet. */ @@ -5064,7 +5171,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 +5179,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 +5187,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 +5203,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 +5214,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 +5223,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 +5232,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 +5277,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 +5292,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 +5300,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. @@ -5206,7 +5310,7 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_AIGP); stream_putc(s, attr_len); - stream_put_bgp_aigp_tlv_metric(s, bpi); + stream_put_bgp_aigp_tlv_metric(s, attr->aigp_metric); } /* Return total size of attribute. */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index f353e769..5633c2f8 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -197,9 +197,6 @@ struct attr { #define ATTR_ES_L3_NHG_ACTIVE (1 << 6) #define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) - /* NA router flag (R-bit) support in EVPN */ - uint8_t router_flag; - /* Distance as applied by Route map */ uint8_t distance; @@ -212,7 +209,7 @@ struct attr { /* has the route-map changed any attribute? Used on the peer outbound side. */ - uint32_t rmap_change_flags; + uint16_t rmap_change_flags; /* Multi-Protocol Nexthop, AFI IPv6 */ struct in6_addr mp_nexthop_global; @@ -256,11 +253,12 @@ struct attr { /* MP Nexthop length */ uint8_t mp_nexthop_len; - /* Static MAC for EVPN */ - uint8_t sticky; - - /* Flag for default gateway extended community in EVPN */ - uint8_t default_gw; + /* EVPN flags */ + uint8_t evpn_flags; +#define ATTR_EVPN_FLAG_STICKY (1 << 0) +#define ATTR_EVPN_FLAG_DEFAULT_GW (1 << 1) +/* NA router flag (R-bit) support in EVPN */ +#define ATTR_EVPN_FLAG_ROUTER (1 << 2) /* route tag */ route_tag_t tag; @@ -280,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; @@ -295,7 +293,7 @@ struct attr { /* EVPN local router-mac */ struct ethaddr rmac; - uint16_t encap_tunneltype; + uint8_t encap_tunneltype; /* rmap set table */ uint32_t rmap_table_id; @@ -355,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) @@ -389,12 +387,12 @@ extern struct attr *bgp_attr_aggregate_intern( struct community *community, struct ecommunity *ecommunity, struct lcommunity *lcommunity, struct bgp_aggregate *aggregate, uint8_t atomic_aggregate, const struct prefix *p); -extern bgp_size_t bgp_packet_attribute( - struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, - struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, - safi_t safi, struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, uint8_t num_labels, bool addpath_capable, - uint32_t addpath_tx_id, struct bgp_path_info *bpi); +extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct stream *s, + struct attr *attr, struct bpacket_attr_vec_arr *vecarr, + struct prefix *p, afi_t afi, safi_t safi, struct peer *from, + struct prefix_rd *prd, mpls_label_t *label, + uint8_t num_labels, bool addpath_capable, + uint32_t addpath_tx_id); extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi, const struct prefix *p); extern bool attrhash_cmp(const void *arg1, const void *arg2); @@ -587,6 +585,10 @@ static inline void bgp_attr_set_transit(struct attr *attr, attr->transit = transit; } +#define AIGP_TRANSMIT_ALLOWED(peer) \ + (CHECK_FLAG((peer)->flags, PEER_FLAG_AIGP) || ((peer)->sub_sort == BGP_PEER_EBGP_OAD) || \ + ((peer)->sort != BGP_PEER_EBGP)) + static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr) { return attr->aigp_metric; @@ -595,9 +597,17 @@ static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr) static inline void bgp_attr_set_aigp_metric(struct attr *attr, uint64_t aigp) { attr->aigp_metric = aigp; + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)); +} - if (aigp) - SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)); +static inline uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi) +{ + uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr); + + if (bpi->nexthop) + return aigp + bpi->nexthop->metric; + else + return aigp; } static inline struct cluster_list *bgp_attr_get_cluster(const struct attr *attr) @@ -616,16 +626,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 * @@ -648,5 +658,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 bbc4ba95..a3ffe61e 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))); @@ -115,14 +122,14 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) /* * return true if attr contains default gw extended community */ -uint8_t bgp_attr_default_gw(struct attr *attr) +void bgp_attr_default_gw(struct attr *attr) { struct ecommunity *ecom; uint32_t i; ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) - return 0; + return; /* If there is a default gw extendd community return true otherwise * return 0 */ @@ -136,10 +143,9 @@ uint8_t bgp_attr_default_gw(struct attr *attr) if ((type == ECOMMUNITY_ENCODE_OPAQUE && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW)) - return 1; + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } - - return 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } /* @@ -183,7 +189,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg) * Fetch and return the sequence number from MAC Mobility extended * community, if present, else 0. */ -uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) +uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr) { struct ecommunity *ecom; uint32_t i; @@ -212,10 +218,11 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) continue; flags = *pnt++; - if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) - *sticky = 1; + if (CHECK_FLAG(flags, + ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)) + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); else - *sticky = 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); pnt++; pnt = ptr_get_be32(pnt, &seq_num); @@ -229,8 +236,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) /* * return true if attr contains router flag extended community */ -void bgp_attr_evpn_na_flag(struct attr *attr, - uint8_t *router_flag, bool *proxy) +void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy) { struct ecommunity *ecom; uint32_t i; @@ -253,10 +259,12 @@ void bgp_attr_evpn_na_flag(struct attr *attr, sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) { val = *pnt++; - if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) - *router_flag = 1; + 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 f8d3978b..cc0e3e44 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; @@ -36,12 +37,10 @@ extern void bgp_add_routermac_ecom(struct attr *attr, extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, struct prefix *dst); extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); -extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, - uint8_t *sticky); -extern uint8_t bgp_attr_default_gw(struct attr *attr); +extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr); +extern void bgp_attr_default_gw(struct attr *attr); -extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag, - bool *proxy); +extern void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy); extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg); diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 675e4765..7b67d4b8 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -934,9 +934,8 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd, stream_putw(s, 0); /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */ - total_attr_len = - bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi, - safi, peer, NULL, NULL, 0, 0, 0, NULL); + total_attr_len = bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi, safi, peer, + NULL, NULL, 0, 0, 0); /* space check? */ @@ -1047,7 +1046,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; @@ -1241,11 +1240,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); @@ -1382,7 +1382,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) @@ -1453,10 +1453,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 +2544,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 +2744,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 +2771,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"); } @@ -2828,8 +2829,7 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty) afi2str_lower(afi), safi2str(safi)); } frr_each (bmp_listeners, &bt->listeners, bl) - vty_out(vty, " \n bmp listener %pSU port %d\n", - &bl->addr, bl->port); + vty_out(vty, " bmp listener %pSU port %d\n", &bl->addr, bl->port); frr_each (bmp_actives, &bt->actives, ba) { vty_out(vty, " bmp connect %s port %u min-retry %u max-retry %u", diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index 1d5034ef..32823cc3 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 153cbd6e..61ba5274 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -182,7 +182,7 @@ community_list_insert(struct community_list_handler *ch, const char *name, } /* In case of name is all digit character */ - if (i == strlen(name)) { + if (i == strlen(name) && number <= COMMUNITY_LIST_NUMBER_MAX) { new->sort = COMMUNITY_LIST_NUMBER; /* Set access_list to number list. */ @@ -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_clist.h b/bgpd/bgp_clist.h index 29bd880c..7f35a6d5 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -20,6 +20,10 @@ /* Number and string based community-list name. */ #define COMMUNITY_LIST_STRING 0 #define COMMUNITY_LIST_NUMBER 1 +/* The numbered community-list (including large/ext communities) + * have a range between 1-500. + */ +#define COMMUNITY_LIST_NUMBER_MAX 500 #define COMMUNITY_SEQ_NUMBER_AUTO -1 diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 8e4c4305..602c1437 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 339bfae5..93f5a199 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 6228432b..97c3e574 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 1beb0307..547dcdf7 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 929e4e60..67c16aeb 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 7af6ff7c..0a8ce615 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(); @@ -1159,9 +1159,8 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add MAC mobility (sticky) if needed. */ - if (attr->sticky) { + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY)) { seqnum = 0; - memset(&ecom_sticky, 0, sizeof(ecom_sticky)); encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); ecom_sticky.size = 1; ecom_sticky.unit_size = ECOMMUNITY_SIZE; @@ -1179,8 +1178,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add default gateway, if needed. */ - if (attr->default_gw) { - memset(&ecom_default_gw, 0, sizeof(ecom_default_gw)); + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { encode_default_gw_extcomm(&eval_default_gw); ecom_default_gw.size = 1; ecom_default_gw.unit_size = ECOMMUNITY_SIZE; @@ -1191,9 +1189,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT); - if (attr->router_flag || proxy) { - memset(&ecom_na, 0, sizeof(ecom_na)); - encode_na_flag_extcomm(&eval_na, attr->router_flag, proxy); + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER) || proxy) { + encode_na_flag_extcomm(&eval_na, + CHECK_FLAG(attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER), + proxy); ecom_na.size = 1; ecom_na.unit_size = ECOMMUNITY_SIZE; ecom_na.val = (uint8_t *)eval_na.val; @@ -1278,12 +1278,15 @@ enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn flags = 0; if (pi->sub_type == BGP_ROUTE_IMPORTED) { - if (pi->attr->sticky) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_STICKY)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (pi->attr->default_gw) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_DEFAULT_GW)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); if (is_evpn_prefix_ipaddr_v6(p) && - pi->attr->router_flag) + CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); seq = mac_mobility_seqnum(pi->attr); @@ -1311,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); } @@ -1608,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 @@ -1623,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, @@ -1738,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); } } @@ -1840,7 +1867,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, *active_on_peer = true; } - if (second_best_path->attr->router_flag) + if (CHECK_FLAG(second_best_path->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) *peer_router = true; /* we use both proxy and non-proxy imports to @@ -1883,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); } } @@ -1940,7 +1970,6 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct attr local_attr; struct bgp_labels bgp_labels = {}; int route_change = 1; - uint8_t sticky = 0; const struct prefix_evpn *evp; *pi = NULL; @@ -1972,9 +2001,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, local_attr = *attr; /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = - bgp_attr_mac_mobility_seqnum(&local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(&local_attr); /* Add (or update) attribute to hash. */ attr_new = bgp_attr_intern(&local_attr); @@ -2069,9 +2096,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, BGP_PATH_ATTR_CHANGED); /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum( - &local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = + bgp_attr_mac_mobility_seqnum(&local_attr); attr_new = bgp_attr_intern(&local_attr); @@ -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); + } } /* @@ -2204,21 +2226,23 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0; - attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; - attr.router_flag = CHECK_FLAG(flags, - ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_STICKY); + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); + 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); } @@ -2250,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; @@ -2509,13 +2537,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = (local_pi->attr->sticky) ? 1 : 0; - attr.router_flag = (local_pi->attr->router_flag) ? 1 : 0; + attr.evpn_flags = local_pi->attr->evpn_flags; attr.es_flags = local_pi->attr->es_flags; - if (local_pi->attr->default_gw) { - attr.default_gw = 1; + if (CHECK_FLAG(local_pi->attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); if (is_evpn_prefix_ipaddr_v6(&evp)) - attr.router_flag = 1; + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); } memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t)); bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, @@ -2524,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; @@ -3030,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); @@ -3063,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) @@ -3143,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); } @@ -3267,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); } @@ -3451,9 +3477,8 @@ uninstall_evpn_route_entry_in_vni_mac(struct bgp *bgp, struct bgpevpn *vpn, * Uninstall route entry from the VRF routing table and send message * to zebra, if appropriate. */ -static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, - const struct prefix_evpn *evp, - struct bgp_path_info *parent_pi) +int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, const struct prefix_evpn *evp, + struct bgp_path_info *parent_pi) { struct bgp_dest *dest; struct bgp_path_info *pi; @@ -3631,7 +3656,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); @@ -3698,7 +3723,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); @@ -3820,10 +3845,8 @@ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf, } /* don't import hosts that are locally attached */ -static inline bool -bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf, - const struct prefix_evpn *evp, - struct bgp_path_info *pi, int install) +bool bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf, const struct prefix_evpn *evp, + struct bgp_path_info *pi, int install) { esi_t *esi; @@ -4200,7 +4223,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 @@ -4689,7 +4712,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 */ @@ -4731,9 +4753,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)); } @@ -4791,11 +4813,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: @@ -4835,8 +4857,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 @@ -4885,8 +4906,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; } @@ -4899,7 +4919,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 */ @@ -4914,6 +4935,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; } @@ -4929,12 +4951,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. */ @@ -4949,6 +4968,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; @@ -4961,16 +4981,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; } @@ -4988,20 +5008,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); @@ -5016,7 +5036,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}; @@ -5028,8 +5048,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; @@ -5043,12 +5063,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 */ @@ -5059,7 +5083,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)); @@ -5069,15 +5093,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); @@ -5439,7 +5459,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); @@ -7717,18 +7737,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.h b/bgpd/bgp_evpn.h index dc82bcfb..10eff1dc 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -195,4 +195,8 @@ extern enum zclient_send_status evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p, struct bgp_path_info *pi, bool is_sync); +bool bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf, const struct prefix_evpn *evp, + struct bgp_path_info *pi, int install); +int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, const struct prefix_evpn *evp, + struct bgp_path_info *parent_pi); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index d723a2b1..ad362524 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); @@ -3804,6 +3807,7 @@ int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni) bgp_evpn_ead_evi_route_update(bgp, es, vpn, &p); } + bgp_evpn_local_es_evi_unistall_local_routes_in_vrfs(es, es_evi); /* update EAD-ES */ if (bgp_evpn_local_es_is_active(es)) bgp_evpn_ead_es_route_update(bgp, es); @@ -3924,8 +3928,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 +3977,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 +4010,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 +4039,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 +4063,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 +4094,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 +4104,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 +4123,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 +4520,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 +4817,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; @@ -5053,3 +5059,38 @@ void bgp_evpn_switch_ead_evi_rx(void) } } } + +void bgp_evpn_local_es_evi_unistall_local_routes_in_vrfs(struct bgp_evpn_es *es, + struct bgp_evpn_es_evi *es_evi) +{ + struct listnode *node; + struct bgp_path_es_info *es_info; + struct bgp_path_info *pi; + const struct prefix_evpn *evp; + struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf; + + if (!es_vrf) + return; + + for (ALL_LIST_ELEMENTS_RO(es->macip_global_path_list, node, es_info)) { + pi = es_info->pi; + + if (!bgp_evpn_is_macip_path(pi)) + continue; + + evp = (const struct prefix_evpn *)bgp_dest_get_prefix(pi->net); + + if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID) && pi->type == ZEBRA_ROUTE_BGP && + pi->sub_type == BGP_ROUTE_NORMAL)) + continue; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) + zlog_debug("route %pFX is matched on local esi %s, uninstall from %s route table", + evp, es->esi_str, es_vrf->bgp_vrf->name_pretty); + + if (!bgp_evpn_skip_vrf_import_of_local_es(es_vrf->bgp_vrf, evp, pi, 0)) + continue; + + uninstall_evpn_route_entry_in_vrf(es_vrf->bgp_vrf, evp, pi); + } +} diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index 5d393c37..149bf384 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -459,5 +459,7 @@ extern void bgp_evpn_path_nh_add(struct bgp *bgp_vrf, struct bgp_path_info *pi); extern void bgp_evpn_path_nh_del(struct bgp *bgp_vrf, struct bgp_path_info *pi); extern void bgp_evpn_mh_config_ead_export_rt(struct bgp *bgp, struct ecommunity *ecom, bool del); +extern void bgp_evpn_local_es_evi_unistall_local_routes_in_vrfs(struct bgp_evpn_es *es, + struct bgp_evpn_es_evi *es_evi); #endif /* _FRR_BGP_EVPN_MH_H */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 07bba9b4..b05df3d8 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -382,7 +382,7 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq, } static inline void encode_na_flag_extcomm(struct ecommunity_val *eval, - uint8_t na_flag, bool proxy) + bool na_flag, bool proxy) { memset(eval, 0, sizeof(*eval)); eval->val[0] = ECOMMUNITY_ENCODE_EVPN; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 846a82ba..958a9c64 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 @@ -4840,7 +4845,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd, char *vrf = NULL; char *neighbor = NULL; as_t as = 0; /* 0 means AS filter not set */ - int as_type = AS_UNSPECIFIED; + enum peer_asn_type as_type = AS_UNSPECIFIED; uint16_t show_flags = 0; if (argv_find(argv, argc, "vrf", &idx_vrf)) diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index 6165bf89..bd04970f 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 66426ab3..31e14d41 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 d41ef8ab..94fca23e 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -602,6 +602,7 @@ const char *const peer_down_str[] = { "Socket Error", "Admin. shutdown (RTT)", "Suppress Fib Turned On or Off", + "Password config change", }; static void bgp_graceful_restart_timer_off(struct peer_connection *connection, @@ -687,6 +688,11 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) COMMUNITY_NO_LLGR)) continue; + if (bgp_attr_get_community(pi->attr) && + community_include(bgp_attr_get_community(pi->attr), + COMMUNITY_LLGR_STALE)) + continue; + if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP Long-lived set stale community (LLGR_STALE) for: %pFX", @@ -695,10 +701,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); - - break; + bgp_process(peer->bgp, rm, pi, afi, + safi); } } } else { @@ -715,6 +719,11 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) COMMUNITY_NO_LLGR)) continue; + if (bgp_attr_get_community(pi->attr) && + community_include(bgp_attr_get_community(pi->attr), + COMMUNITY_LLGR_STALE)) + continue; + if (bgp_debug_neighbor_events(peer)) zlog_debug( "%pBP Long-lived set stale community (LLGR_STALE) for: %pFX", @@ -723,10 +732,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); - - break; + bgp_process(peer->bgp, dest, pi, afi, safi); } } } @@ -1482,7 +1488,7 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) EVENT_OFF(connection->t_connect); EVENT_OFF(connection->t_holdtime); EVENT_OFF(connection->t_routeadv); - EVENT_OFF(peer->connection->t_delayopen); + EVENT_OFF(connection->t_delayopen); /* Clear input and output buffer. */ frr_with_mutex (&connection->io_mtx) { @@ -1801,18 +1807,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); } } @@ -2046,9 +2048,10 @@ static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi, } gr_info->eor_required++; /* Send message to RIB indicating route update pending */ - if (gr_info->af_enabled[afi][safi] == false) { - gr_info->af_enabled[afi][safi] = true; - /* Send message to RIB */ + if (gr_info->af_enabled == false) { + gr_info->af_enabled = true; + gr_info->route_sync = false; + bgp->gr_route_sync_pending = true; bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_PENDING); } @@ -2082,7 +2085,7 @@ static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi) if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer)) { /* Check if the forwarding state is preserved */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) { + if (bgp_gr_is_forwarding_preserved(bgp)) { gr_info = &(bgp->gr_info[afi][safi]); ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info); } @@ -2199,8 +2202,7 @@ bgp_establish(struct peer_connection *connection) } else { if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer) && - CHECK_FLAG(peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) + bgp_gr_is_forwarding_preserved(peer->bgp)) peer->bgp->gr_info[afi][safi] .eor_required++; } @@ -2695,53 +2697,61 @@ int bgp_event_update(struct peer_connection *connection, } /* BGP GR Code */ -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state) +static inline void +bgp_peer_inherit_global_gr_mode(struct peer *peer, + enum global_mode global_gr_mode) +{ + switch (global_gr_mode) { + case GLOBAL_HELPER: + BGP_PEER_GR_HELPER_ENABLE(peer); + break; + case GLOBAL_GR: + BGP_PEER_GR_ENABLE(peer); + break; + case GLOBAL_DISABLE: + BGP_PEER_GR_DISABLE(peer); + break; + case GLOBAL_INVALID: + default: + zlog_err("Unexpected Global GR mode %d", global_gr_mode); + } +} + +static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp, + enum global_mode global_new_state) { struct peer *peer = {0}; struct listnode *node = {0}; struct listnode *nnode = {0}; enum peer_mode peer_old_state = PEER_INVALID; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] Peer: (%s) :", __func__, - peer->host); + /* TODO: Need to handle peer-groups. */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { peer_old_state = bgp_peer_gr_mode_get(peer); + if (peer_old_state != PEER_GLOBAL_INHERIT) + continue; - if (peer_old_state == PEER_GLOBAL_INHERIT) { - - /* - *Reset only these peers and send a - *new open message with the change capabilities. - *Considering the mode to be "global_new_state" and - *do all operation accordingly - */ + bgp_peer_inherit_global_gr_mode(peer, global_new_state); + bgp_peer_gr_flags_update(peer); - switch (global_new_state) { - case GLOBAL_HELPER: - BGP_PEER_GR_HELPER_ENABLE(peer); - break; - case GLOBAL_GR: - BGP_PEER_GR_ENABLE(peer); - break; - case GLOBAL_DISABLE: - BGP_PEER_GR_DISABLE(peer); - break; - case GLOBAL_INVALID: - zlog_debug("%s [BGP_GR] GLOBAL_INVALID", - __func__); - return BGP_ERR_GR_OPERATION_FAILED; - } - } - } + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64 + "...resetting session", + peer, peer->peer_gr_new_status_flag, + peer->flags); - bgp->global_gr_present_state = global_new_state; + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - return BGP_GR_SUCCESS; + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. + */ + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset_safe(peer, &nnode); + } } int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) @@ -2749,46 +2759,27 @@ int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) enum global_mode global_new_state = GLOBAL_INVALID; enum global_mode global_old_state = GLOBAL_INVALID; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR]START: global_gr_cmd :%s:", __func__, - print_global_gr_cmd(global_gr_cmd)); - global_old_state = bgp_global_gr_mode_get(bgp); + global_new_state = bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_old_gr_state :%s:", - print_global_gr_mode(global_old_state)); + zlog_debug("%s: Handle GR command %s, current GR state %s, new GR state %s", + bgp->name_pretty, print_global_gr_cmd(global_gr_cmd), + print_global_gr_mode(global_old_state), + print_global_gr_mode(global_new_state)); - if (global_old_state != GLOBAL_INVALID) { - global_new_state = - bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_new_gr_state :%s:", - print_global_gr_mode(global_new_state)); - } else { - zlog_err("%s [BGP_GR] global_old_state == GLOBAL_INVALID", - __func__); + if (global_old_state == GLOBAL_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - } - - if (global_new_state == GLOBAL_INVALID) { - zlog_err("%s [BGP_GR] global_new_state == GLOBAL_INVALID", - __func__); + if (global_new_state == GLOBAL_INVALID) return BGP_ERR_GR_INVALID_CMD; - } - if (global_new_state == global_old_state) { - /* Trace msg */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] global_new_state == global_old_state :%s", - __func__, - print_global_gr_mode(global_new_state)); + if (global_new_state == global_old_state) return BGP_GR_NO_OPERATION; - } - return bgp_gr_lookup_n_update_all_peer(bgp, global_new_state, - global_old_state); + /* Update global GR mode and process all peers in instance. */ + bgp->global_gr_present_state = global_new_state; + bgp_gr_update_mode_of_all_peers(bgp, global_new_state); + + return BGP_GR_SUCCESS; } const char *print_peer_gr_mode(enum peer_mode pr_mode) @@ -2903,179 +2894,102 @@ int bgp_neighbor_graceful_restart(struct peer *peer, { enum peer_mode peer_new_state = PEER_INVALID; enum peer_mode peer_old_state = PEER_INVALID; - struct bgp_peer_gr peer_state; + struct bgp_peer_gr gr_fsm; int result = BGP_GR_FAILURE; - /* - * fetch peer_old_state from peer structure also - * fetch global_old_state from bgp structure, - * peer had a back pointer to bgpo struct ; - */ - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:", - __func__, peer->host, - print_peer_gr_cmd(peer_gr_cmd)); - peer_old_state = bgp_peer_gr_mode_get(peer); + gr_fsm = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; + peer_new_state = gr_fsm.next_state; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] peer_old_state: %d", __func__, - peer_old_state); + zlog_debug("%pBP: Handle GR command %s, current GR state %s, new GR state %s", + peer, print_peer_gr_cmd(peer_gr_cmd), + print_peer_gr_mode(peer_old_state), + print_peer_gr_mode(peer_new_state)); if (peer_old_state == PEER_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; - peer_new_state = peer_state.next_state; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] peer_new_state: %d", __func__, - peer_new_state); - if (peer_new_state == PEER_INVALID) return BGP_ERR_GR_INVALID_CMD; - if (peer_new_state != peer_old_state) { - result = peer_state.action_fun(peer, peer_old_state, - peer_new_state); - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] peer_old_state == peer_new_state !"); + if (peer_new_state == peer_old_state) return BGP_GR_NO_OPERATION; - } - - if (result == BGP_GR_SUCCESS) { - /* Update the mode i.e peer_new_state into the peer structure */ - peer->peer_gr_present_state = peer_new_state; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Successfully change the state of the peer to : %s : !", - print_peer_gr_mode(peer_new_state)); - - return BGP_GR_SUCCESS; - } + result = gr_fsm.action_fun(peer, peer_old_state, peer_new_state); return result; } -unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, - enum peer_mode new_peer_state) +static inline bool gr_mode_matches(enum peer_mode peer_gr_mode, + enum global_mode global_gr_mode) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!", - __func__, print_peer_gr_mode(old_peer_state), - print_peer_gr_mode(new_peer_state)); + if ((peer_gr_mode == PEER_HELPER && global_gr_mode == GLOBAL_HELPER) || + (peer_gr_mode == PEER_GR && global_gr_mode == GLOBAL_GR) || + (peer_gr_mode == PEER_DISABLE && global_gr_mode == GLOBAL_DISABLE)) + return true; + return false; +} - enum global_mode bgp_gr_global_mode = GLOBAL_INVALID; - unsigned int ret = BGP_GR_FAILURE; +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; + bool session_reset = true; - if (old_peer_state == new_peer_state) { - /* Nothing to do over here as the present and old state is the - * same */ + if (old_state == new_state) return BGP_GR_NO_OPERATION; - } - if ((old_peer_state == PEER_INVALID) - || (new_peer_state == PEER_INVALID)) { - /* something bad happend , print error message */ + if ((old_state == PEER_INVALID) || (new_state == PEER_INVALID)) return BGP_ERR_GR_INVALID_CMD; - } - bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp); - - if ((old_peer_state == PEER_GLOBAL_INHERIT) - && (new_peer_state != PEER_GLOBAL_INHERIT)) { - - /* fetch the Mode running in the Global state machine - *from the bgp structure into a variable called - *bgp_gr_global_mode - */ - - /* Here we are checking if the - *1. peer_new_state == global_mode == helper_mode - *2. peer_new_state == global_mode == GR_mode - *3. peer_new_state == global_mode == disabled_mode - */ + global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + if ((old_state == PEER_GLOBAL_INHERIT) && + (new_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer); - if ((int)new_peer_state == (int)bgp_gr_global_mode) { - /* This is incremental updates i.e no tear down - * of the existing session - * as the peer is already working in the same mode. + if (gr_mode_matches(new_state, global_gr_mode)) + /* Peer was inheriting the global state and + * its new state still is the same, so a + * session reset is not needed. */ - ret = BGP_GR_SUCCESS; - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s ", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; - } - } - /* In the case below peer is going into Global inherit mode i.e. - * the peer would work as the mode configured at the global level - */ - else if ((new_peer_state == PEER_GLOBAL_INHERIT) - && (old_peer_state != PEER_GLOBAL_INHERIT)) { - /* Here in this case it would be destructive - * in all the cases except one case when, - * Global GR is configured Disabled - * and present_peer_state is not disable - */ - + session_reset = false; + } else if ((new_state == PEER_GLOBAL_INHERIT) && + (old_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - if ((int)old_peer_state == (int)bgp_gr_global_mode) { - /* This is incremental updates - *i.e no tear down of the existing session - *as the peer is already working in the same mode. - */ - ret = BGP_GR_SUCCESS; - } else { - /* Destructive always */ - /* Tear down the old session - * and send the new capability - * as per the bgp_gr_global_mode + if (gr_mode_matches(old_state, global_gr_mode)) + /* Peer is inheriting the global state and + * its old state was also the same, so a + * session reset is not needed. */ + session_reset = false; + } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); + /* Ensure we move to the new state and update flags */ + bgp_peer_move_to_gr_mode(peer, new_state); - bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode); + if (session_reset) { + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - ret = BGP_GR_SUCCESS; - } - } else { - /* - *This else case, it include all the cases except --> - *(new_peer_state != Peer_Global) && - *( old_peer_state != Peer_Global ) + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset(peer); } - return ret; + return BGP_GR_SUCCESS; } -inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state) { - int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum peer_mode old_state = bgp_peer_gr_mode_get(peer); switch (new_state) { case PEER_HELPER: @@ -3089,57 +3003,38 @@ inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) break; case PEER_GLOBAL_INHERIT: BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - - if (bgp_global_gr_mode == GLOBAL_HELPER) { - BGP_PEER_GR_HELPER_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_GR) { - BGP_PEER_GR_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_DISABLE) { - BGP_PEER_GR_DISABLE(peer); - } else { - zlog_err( - "[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!"); - } + bgp_peer_inherit_global_gr_mode(peer, global_gr_mode); break; + case PEER_INVALID: default: zlog_err( "[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!"); break; } + bgp_peer_gr_flags_update(peer); + peer->peer_gr_present_state = new_state; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !", - new_state); + zlog_debug("%pBP: Peer GR mode changed from %s to %s, GR flags 0x%x peer flags 0x%" PRIx64, + peer, print_peer_gr_mode(old_state), + print_peer_gr_mode(new_state), + peer->peer_gr_new_status_flag, peer->flags); } void bgp_peer_gr_flags_update(struct peer *peer) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] called !", __func__); if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_HELPER) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) SET_FLAG(peer->flags, @@ -3147,28 +3042,28 @@ void bgp_peer_gr_flags_update(struct peer *peer) else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) - ? "Set" - : "UnSet")); - - if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { - zlog_debug("[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!", - peer->host); + zlog_debug("%pBP: Peer flags updated to 0x%" PRIx64 + ", GR flags 0x%x, GR mode %s", + peer, peer->flags, peer->peer_gr_new_status_flag, + print_peer_gr_mode(bgp_peer_gr_mode_get(peer))); + /* + * If GR has been completely disabled for the peer and we were + * acting as the Helper for the peer (i.e., keeping stale routes + * and running the restart timer or stalepath timer), clear those + * states. + */ + if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { - + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP: GR disabled, stopping NSF and clearing stale routes", + peer); peer_nsf_stop(peer); - zlog_debug( - "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!", - peer->host); } } } diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index bcdd4919..85c48896 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -151,7 +151,7 @@ int bgp_neighbor_graceful_restart(struct peer *peer, enum peer_gr_command peer_gr_cmd); unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, enum peer_mode new_peer_state); -void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state); +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state); unsigned int bgp_peer_gr_helper_enable(struct peer *peer); unsigned int bgp_peer_gr_enable(struct peer *peer); unsigned int bgp_peer_gr_global_inherit(struct peer *peer); @@ -160,9 +160,6 @@ enum peer_mode bgp_peer_gr_mode_get(struct peer *peer); enum global_mode bgp_global_gr_mode_get(struct bgp *bgp); enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer); unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer); -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state); void bgp_peer_gr_flags_update(struct peer *peer); const char *print_peer_gr_mode(enum peer_mode pr_mode); const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd); diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index f03b820d..5db36217 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -38,7 +38,7 @@ static void *bgp_labels_hash_alloc(void *p) struct bgp_labels *new; uint8_t i; - new = XMALLOC(MTYPE_BGP_LABELS, sizeof(struct bgp_labels)); + new = XCALLOC(MTYPE_BGP_LABELS, sizeof(struct bgp_labels)); new->num_labels = labels->num_labels; for (i = 0; i < labels->num_labels; i++) @@ -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 28fb4527..86d6281e 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 @@ -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 97658d34..535d2fc5 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); @@ -511,13 +510,18 @@ int main(int argc, char **argv) /* BGP master init. */ 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) bgp_option_set(BGP_OPT_NO_FIB); if (no_zebra_flag) bgp_option_set(BGP_OPT_NO_ZEBRA); + if (bgpd_di.graceful_restart) + SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART); + bgp_error_init(); /* Initializations. */ libagentx_init(); diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index c1804fb7..c2599ade 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 4ae49a2c..1f76945d 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 e12d84b8..609afa42 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 @@ -190,78 +192,6 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, return compare; } -/* - * 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 * @@ -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); } } @@ -313,49 +246,6 @@ bgp_path_info_mpath_get(struct bgp_path_info *path) return path->mpath; } -/* - * 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 * @@ -363,9 +253,16 @@ void bgp_path_info_mpath_dequeue(struct bgp_path_info *path) */ 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,212 +471,105 @@ 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); - 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; + cur_iterator = cur_iterator->next; + } - 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"); + 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); + + 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 - && bgp_path_info_nexthop_cmp(prev_mpath, - cur_mpath)) { - bgp_path_info_mpath_enqueue(prev_mpath, - cur_mpath); - prev_mpath = cur_mpath; - mpath_count++; - 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 { - 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) - && bgp_path_info_nexthop_cmp(prev_mpath, - new_mpath)) { - bgp_path_info_mpath_dequeue(new_mpath); - - bgp_path_info_mpath_enqueue(prev_mpath, - new_mpath); - prev_mpath = new_mpath; - mpath_changed = 1; - mpath_count++; - 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); - } - } - 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 * @@ -816,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 129682d1..c5a009a4 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 e8951baf..df45cf23 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. */ @@ -280,7 +281,8 @@ done: * * Sending this vrf-label association is qualified by a) whether vrf->vpn * exporting is active ("export vpn" is enabled, vpn-policy RD and RT list - * are set) and b) whether vpn-policy label is set. + * are set), b) whether vpn-policy label is set and c) the vrf loopback + * interface is up. * * If any of these conditions do not hold, then we send MPLS_LABEL_NONE * for this vrf, which zebra interprets to mean "delete this vrf-label @@ -288,6 +290,7 @@ done: */ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) { + struct interface *ifp; mpls_label_t label = MPLS_LABEL_NONE; int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); @@ -301,7 +304,9 @@ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) } if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) { - label = bgp->vpn_policy[afi].tovpn_label; + ifp = if_get_vrf_loopback(bgp->vrf_id); + if (ifp && if_is_up(ifp)) + label = bgp->vpn_policy[afi].tovpn_label; } if (debug) { @@ -381,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; @@ -432,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); @@ -470,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) @@ -482,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); } /* @@ -497,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) @@ -510,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); } /* @@ -591,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, @@ -631,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", @@ -744,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); @@ -764,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__, @@ -809,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); @@ -828,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) @@ -872,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__, @@ -885,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); } @@ -899,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__, @@ -912,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); } @@ -1536,8 +1613,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ struct attr static_attr = {0}; struct attr *new_attr = NULL; safi_t safi = SAFI_MPLS_VPN; - mpls_label_t label_val; - mpls_label_t label; + mpls_label_t label_val = { 0 }; + mpls_label_t label = { 0 }; struct bgp_dest *bn; const char *debugmsg; int nexthop_self_flag = 0; @@ -1759,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); @@ -1801,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, @@ -2079,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); @@ -2136,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); @@ -2288,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); @@ -3789,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) | diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 92a9fba8..39fed667 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_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c index 3344e9e0..93d9f672 100644 --- a/bgpd/bgp_mplsvpn_snmp.c +++ b/bgpd/bgp_mplsvpn_snmp.c @@ -590,6 +590,11 @@ static int bgp_vrf_check_update_active(struct bgp *bgp, struct interface *ifp) /* add trap in here */ bgp->snmp_stats->active = new_active; + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) { + bgp_mpls_l3vpn_update_last_changed(bgp); + return 0; + } + /* send relevent trap */ if (bgp->snmp_stats->active) trap = MPLSL3VPNVRFUP; diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index e09dbc22..de57d918 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 7a0b3cc6..ceb6b6f0 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.c b/bgpd/bgp_nexthop.c index 98eb9565..ba6d7071 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1003,7 +1003,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, if (bnc->is_evpn_gwip_nexthop) json_object_boolean_true_add(json_nexthop, "isEvpnGatewayIp"); - json_object_string_addf(json, "resolvedPrefix", "%pFX", + json_object_string_addf(json_nexthop, "resolvedPrefix", "%pFX", &bnc->resolved_prefix); } else { vty_out(vty, " %s valid [IGP metric %d], #paths %d", diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 430c8f17..5014eb8f 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -38,7 +38,7 @@ struct bgp_nexthop_cache { uint32_t metric; /* Nexthop number and nexthop linked list.*/ - uint8_t nexthop_num; + uint16_t nexthop_num; /* This flag is set to TRUE for a bnc that is gateway IP overlay index * nexthop. @@ -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 bdaf9459..9b633b71 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -347,12 +347,11 @@ 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; } @@ -405,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)) @@ -485,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 @@ -503,6 +503,10 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, */ if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) return 1; + else if (safi == SAFI_UNICAST && pi && + pi->sub_type == BGP_ROUTE_IMPORTED && + 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) @@ -602,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))) { @@ -631,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; @@ -647,11 +652,12 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, * we receive from bgp. This is to allow us * to work with v4 routing over v6 nexthops */ - if (peer && !peer->ifp - && CHECK_FLAG(peer->flags, - PEER_FLAG_CAPABILITY_ENHE) - && nhr->prefix.family == AF_INET6 - && nexthop->type != NEXTHOP_TYPE_BLACKHOLE) { + if (peer && !peer->ifp && + CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE) && + !CHECK_FLAG(bnc->bgp->flags, + BGP_FLAG_IPV6_NO_AUTO_RA) && + nhr->prefix.family == AF_INET6 && + nexthop->type != NEXTHOP_TYPE_BLACKHOLE) { struct interface *ifp; ifp = if_lookup_by_index(nexthop->ifindex, @@ -665,8 +671,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; } @@ -690,7 +695,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) @@ -698,7 +703,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; @@ -722,19 +727,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 */ @@ -753,7 +761,7 @@ static void bgp_nht_ifp_table_handle(struct bgp *bgp, { struct bgp_nexthop_cache *bnc; struct nexthop *nhop; - uint8_t other_nh_count; + uint16_t other_nh_count; bool nhop_ll_found = false; bool nhop_found = false; @@ -1176,7 +1184,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) { @@ -1305,11 +1313,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)) { + !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)) { bnc_is_valid_nexthop = bgp_isvalid_nexthop_for_l3vpn(bnc, path) ? true @@ -1520,6 +1530,10 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer) return; bgp = peer->bgp; + + if (CHECK_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA)) + return; + if (!sockunion2hostprefix(&peer->connection->su, &p)) { zlog_warn("%s: Unable to convert sockunion to prefix for %s", __func__, peer->host); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 248d478f..6451c7cf 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -519,20 +519,17 @@ static int bgp_capability_restart(struct peer *peer, UNSET_FLAG(restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; - if (bgp_debug_neighbor_events(peer)) { - zlog_debug( - "%s Peer has%srestarted. Restart Time: %d, N-bit set: %s", - peer->host, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) - ? " " - : " not ", - peer->v_gr_restart, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) - ? "yes" - : "no"); - } + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP OPEN has GR capability, Restart time %d R-bit %s N-bit %s", + peer, peer->v_gr_restart, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) + ? "SET" + : "NOT-SET"); while (stream_get_getp(s) + 4 <= end) { afi_t afi; @@ -556,14 +553,12 @@ static int bgp_capability_restart(struct peer *peer, iana_safi2str(pkt_safi)); } else { if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s Address family %s is%spreserved", - peer->host, get_afi_safi_str(afi, safi, false), - CHECK_FLAG( - peer->af_cap[afi][safi], - PEER_CAP_RESTART_AF_PRESERVE_RCV) - ? " " - : " not "); + zlog_debug("%pBP F-bit %s for %s", peer, + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV) + ? "SET" + : "NOT-SET", + get_afi_safi_str(afi, safi, false)); SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); @@ -1379,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; @@ -1392,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); @@ -1402,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); @@ -1414,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; @@ -1587,15 +1582,12 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, uint32_t restart_time; unsigned long capp = 0; unsigned long rcapp = 0; + struct bgp *bgp = peer->bgp; if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) return; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending helper Capability for Peer :%s :", - peer->host); - SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); capp = stream_get_endp(s); /* Set Capability Len Pointer */ @@ -1605,42 +1597,41 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, /* Set Restart Capability Len Pointer */ rcapp = stream_get_endp(s); stream_putc(s, 0); - restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + restart_time = bgp->restart_time; + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending R-Bit for peer: %s", - peer->host); } - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { SET_FLAG(restart_time, GRACEFUL_RESTART_N_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending N-Bit for peer: %s", - peer->host); } stream_putw(s, restart_time); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Sending GR Capability, Restart time %d R-bit %s, N-bit %s", + peer->host, bgp->restart_time, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV) + ? "SET" + : "NOT-SET"); + /* Send address-family specific graceful-restart capability * only when GR config is present */ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) { - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD) - && BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] F bit Set"); - FOREACH_AFI_SAFI (afi, safi) { + bool f_bit = false; + if (!peer->afc[afi][safi]) continue; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:", - afi, safi); - /* Convert AFI, SAFI to values for * packet. */ @@ -1648,11 +1639,15 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, &pkt_safi); stream_putw(s, pkt_afi); stream_putc(s, pkt_safi); - if (CHECK_FLAG(peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) - stream_putc(s, GRACEFUL_RESTART_F_BIT); - else - stream_putc(s, 0); + + f_bit = bgp_gr_is_forwarding_preserved(bgp); + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("... F-bit %s for %s", + f_bit ? "SET" : "NOT-SET", + get_afi_safi_str(afi, safi, false)); + + stream_putc(s, f_bit ? GRACEFUL_RESTART_F_BIT : 0); } } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 010a31a3..62be7ffb 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -651,6 +651,7 @@ void bgp_open_send(struct peer_connection *connection) uint16_t send_holdtime; as_t local_as; struct peer *peer = connection->peer; + bool ext_opt_params = false; if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) send_holdtime = peer->holdtime; @@ -677,15 +678,17 @@ void bgp_open_send(struct peer_connection *connection) /* Set capabilities */ if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { - (void)bgp_open_capability(s, peer, true); + ext_opt_params = true; + (void)bgp_open_capability(s, peer, ext_opt_params); } else { struct stream *tmp = stream_new(STREAM_SIZE(s)); stream_copy(tmp, s); - if (bgp_open_capability(tmp, peer, false) - > BGP_OPEN_NON_EXT_OPT_LEN) { + if (bgp_open_capability(tmp, peer, ext_opt_params) > + BGP_OPEN_NON_EXT_OPT_LEN) { stream_free(tmp); - (void)bgp_open_capability(s, peer, true); + ext_opt_params = true; + (void)bgp_open_capability(s, peer, ext_opt_params); } else { stream_copy(s, tmp); stream_free(tmp); @@ -696,10 +699,10 @@ void bgp_open_send(struct peer_connection *connection) bgp_packet_set_size(s); if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s sending OPEN, version %d, my as %u, holdtime %d, id %pI4", - peer->host, BGP_VERSION_4, local_as, send_holdtime, - &peer->local_id); + zlog_debug("%pBP fd %d sending OPEN%s, version %d, my as %u, holdtime %d, id %pI4", + peer, peer->connection->fd, + ext_opt_params ? " (Extended)" : "", BGP_VERSION_4, + local_as, send_holdtime, &peer->local_id); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ @@ -982,6 +985,7 @@ static void bgp_notify_send_internal(struct peer_connection *connection, peer->notify.code = bgp_notify.code; peer->notify.subcode = bgp_notify.subcode; peer->notify.length = bgp_notify.length; + peer->notify.hard_reset = hard_reset; if (bgp_notify.length && data) { bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION, @@ -1112,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); @@ -1295,7 +1299,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, stream_putc(s, 0); gr_restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); } @@ -1800,6 +1804,23 @@ static int bgp_open_receive(struct peer_connection *connection, mp_capability = 0; optlen = stream_getc(peer->curr); + /* If we previously had some more capabilities e.g.: + * FQDN, SOFT_VERSION, we MUST clear the values we used + * before, to avoid using stale data. + * Checking peer->cap is enough before checking for the real + * data, but we don't have this check everywhere in the code, + * thus let's clear the data here too before parsing the + * capabilities. + */ + if (peer->hostname) + XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); + + if (peer->domainname) + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + + if (peer->soft_version) + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); + /* Extended Optional Parameters Length for BGP OPEN Message */ if (optlen == BGP_OPEN_NON_EXT_OPT_LEN || CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { @@ -1977,6 +1998,14 @@ static int bgp_open_receive(struct peer_connection *connection, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return BGP_Stop; + } else if (peer->as_type == AS_AUTO) { + if (remote_as == peer->bgp->as) { + peer->as = peer->local_as; + SET_FLAG(peer->as_type, AS_INTERNAL); + } else { + peer->as = remote_as; + SET_FLAG(peer->as_type, AS_EXTERNAL); + } } else if (peer->as_type == AS_INTERNAL) { if (remote_as != peer->bgp->as) { if (bgp_debug_neighbor_events(peer)) @@ -2378,13 +2407,13 @@ static int bgp_update_receive(struct peer_connection *connection, ret = bgp_dump_attr(&attr, peer->rcvd_attr_str, sizeof(peer->rcvd_attr_str)); - peer->stat_upd_7606++; - - if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) + if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) { + peer->stat_upd_7606++; flog_err( EC_BGP_UPDATE_RCV, "%pBP rcvd UPDATE with errors in attr(s)!! Withdrawing route.", peer); + } if (ret && bgp_debug_update(peer, NULL, NULL, 1) && BGP_DEBUG(update, UPDATE_DETAIL)) { @@ -2673,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 43682de4..2d61c0f0 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 666adc47..619252b0 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -525,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; @@ -541,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; @@ -837,8 +833,13 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * with the * sticky flag. */ - if (newattr->sticky != existattr->sticky) { - if (newattr->sticky && !existattr->sticky) { + bool new_sticky = CHECK_FLAG(newattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + bool exist_sticky = CHECK_FLAG(existattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + + if (new_sticky != exist_sticky) { + if (new_sticky && !exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( @@ -847,7 +848,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 1; } - if (!newattr->sticky && existattr->sticky) { + if (!new_sticky && exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( @@ -1063,12 +1064,37 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } } - /* Tie-breaker - AIGP (Metric TLV) attribute */ + /* 3. Local route check. We prefer: + * - BGP_ROUTE_STATIC + * - BGP_ROUTE_AGGREGATE + * - BGP_ROUTE_REDISTRIBUTE + */ + new_origin = !(new->sub_type == BGP_ROUTE_NORMAL || new->sub_type == BGP_ROUTE_IMPORTED); + exist_origin = !(exist->sub_type == BGP_ROUTE_NORMAL || + exist->sub_type == BGP_ROUTE_IMPORTED); + + if (new_origin && !exist_origin) { + *reason = bgp_path_selection_local_route; + if (debug) + zlog_debug("%s: %s wins over %s due to preferred BGP_ROUTE type", pfx_buf, + new_buf, exist_buf); + return 1; + } + + if (!new_origin && exist_origin) { + *reason = bgp_path_selection_local_route; + if (debug) + zlog_debug("%s: %s loses to %s due to preferred BGP_ROUTE type", pfx_buf, + new_buf, exist_buf); + return 0; + } + + /* 3.5. Tie-breaker - AIGP (Metric TLV) attribute */ if (CHECK_FLAG(newattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP)) { - uint64_t new_aigp = bgp_attr_get_aigp_metric(newattr); - uint64_t exist_aigp = bgp_attr_get_aigp_metric(existattr); + uint64_t new_aigp = bgp_aigp_metric_total(new); + uint64_t exist_aigp = bgp_aigp_metric_total(exist); if (new_aigp < exist_aigp) { *reason = bgp_path_selection_aigp; @@ -1093,34 +1119,6 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } } - /* 3. Local route check. We prefer: - * - BGP_ROUTE_STATIC - * - BGP_ROUTE_AGGREGATE - * - BGP_ROUTE_REDISTRIBUTE - */ - new_origin = !(new->sub_type == BGP_ROUTE_NORMAL || - new->sub_type == BGP_ROUTE_IMPORTED); - exist_origin = !(exist->sub_type == BGP_ROUTE_NORMAL || - exist->sub_type == BGP_ROUTE_IMPORTED); - - if (new_origin && !exist_origin) { - *reason = bgp_path_selection_local_route; - if (debug) - zlog_debug( - "%s: %s wins over %s due to preferred BGP_ROUTE type", - pfx_buf, new_buf, exist_buf); - return 1; - } - - if (!new_origin && exist_origin) { - *reason = bgp_path_selection_local_route; - if (debug) - zlog_debug( - "%s: %s loses to %s due to preferred BGP_ROUTE type", - pfx_buf, new_buf, exist_buf); - return 0; - } - /* Here if these are imported routes then get ultimate pi for * path compare. */ @@ -1588,18 +1586,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; } @@ -1780,14 +1776,13 @@ static bool bgp_community_filter(struct peer *peer, struct attr *attr) return true; /* NO_EXPORT check. */ - if (peer->sort == BGP_PEER_EBGP && - community_include(bgp_attr_get_community(attr), - COMMUNITY_NO_EXPORT)) + if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD && + community_include(bgp_attr_get_community(attr), COMMUNITY_NO_EXPORT)) return true; /* NO_EXPORT_SUBCONFED check. */ - if (peer->sort == BGP_PEER_EBGP - || peer->sort == BGP_PEER_CONFED) + if ((peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD) || + peer->sort == BGP_PEER_CONFED) if (community_include(bgp_attr_get_community(attr), COMMUNITY_NO_EXPORT_SUBCONFED)) return true; @@ -2156,6 +2151,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, bool nh_reset = false; uint64_t cum_bw; mpls_label_t label; + bool global_and_ll = false; if (DISABLE_BGP_ANNOUNCE) return false; @@ -2170,8 +2166,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 && @@ -2467,30 +2462,37 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * we do not announce LL address as `::`. */ 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))) { + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) { + /* nexthop local unchanged: only include the link-local nexthop if it + * was already present. + */ + if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) + global_and_ll = true; + } else if (!reflect && !transparent && + IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) && peer->shared_network && + (from == bgp->peer_self || peer->sort == BGP_PEER_EBGP)) + global_and_ll = true; + + if (global_and_ll) { if (safi == SAFI_MPLS_VPN) attr->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL; else attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL; - } + } else + attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* Clear off link-local nexthop in source, whenever it is not * needed to * ensure more prefixes share the same attribute for * announcement. */ - if (!(CHECK_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED))) + if (!(CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) || + !IPV6_ADDR_SAME(&peer->nexthop.v6_global, &from->nexthop.v6_global)) + /* Reset if "nexthop-local unchanged" is not set or originating and destination peer + * does not share the same subnet. + */ memset(&attr->mp_nexthop_local, 0, IPV6_MAX_BYTELEN); } @@ -2814,6 +2816,21 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, false)); } + /* + * Adjust AIGP for propagation when the nexthop is set to ourselves, + * e.g., using "set ip nexthop peer-address" or when advertising to + * EBGP. Note in route reflection the nexthop is usually unmodified + * and the AIGP should not be adjusted in that case. + */ + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && AIGP_TRANSMIT_ALLOWED(peer)) { + if (nh_reset || + CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_NEXTHOP_PEER_ADDRESS)) { + uint64_t aigp = bgp_aigp_metric_total(pi); + + bgp_attr_set_aigp_metric(attr, aigp); + } + } + return true; } @@ -2848,13 +2865,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); @@ -3229,7 +3245,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; } @@ -3242,15 +3259,6 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (!peer_established(pi->peer->connection)) continue; - if (!bgp_path_info_nexthop_cmp(pi, new_select)) { - if (debug) - zlog_debug( - "%pBD(%s): %s has the same nexthop as the bestpath, skip it", - dest, bgp->name_pretty, - path_buf); - continue; - } - bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, mpath_cfg, debug, pfx_buf, afi, safi, &dest->reason); @@ -3261,15 +3269,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); @@ -3624,7 +3631,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) @@ -3763,7 +3779,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, @@ -3872,6 +3889,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) struct bgp_dest *dest; int cnt = 0; struct afi_safi_info *thread_info; + bool route_sync_pending = false; if (bgp->gr_info[afi][safi].t_route_select) { struct event *t = bgp->gr_info[afi][safi].t_route_select; @@ -3881,7 +3899,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) EVENT_OFF(bgp->gr_info[afi][safi].t_route_select); } - if (BGP_DEBUG(update, UPDATE_OUT)) { + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) { zlog_debug("%s: processing route for %s : cnt %d", __func__, get_afi_safi_str(afi, safi, false), bgp->gr_info[afi][safi].gr_deferred); @@ -3914,6 +3932,21 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) /* Send route processing complete message to RIB */ bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); + bgp->gr_info[afi][safi].route_sync = true; + + /* If this instance is all done, check for GR completion overall */ + FOREACH_AFI_SAFI_NSF (afi, safi) { + if (bgp->gr_info[afi][safi].af_enabled && + !bgp->gr_info[afi][safi].route_sync) { + route_sync_pending = true; + break; + } + } + + if (!route_sync_pending) { + bgp->gr_route_sync_pending = false; + bgp_update_gr_completion(); + } return; } @@ -4001,8 +4034,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; @@ -4065,9 +4099,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; @@ -4081,7 +4114,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) @@ -4090,6 +4126,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; @@ -4582,10 +4630,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); } @@ -4624,7 +4672,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; @@ -4747,8 +4810,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 @@ -4772,22 +4836,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) && @@ -5424,7 +5487,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]; @@ -5653,7 +5716,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) @@ -5661,15 +5724,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, @@ -6218,7 +6279,6 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) vpn_leak_to_vrf_withdraw(pi); bgp_rib_remove(rm, pi, peer, afi, safi); - break; } } } else { @@ -6247,7 +6307,6 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) pi); bgp_rib_remove(dest, pi, peer, afi, safi); - break; } } } @@ -6405,16 +6464,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; @@ -6588,7 +6652,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. */ @@ -6698,9 +6762,6 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, if (afi == AFI_IP) attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - if (bgp_static->igpmetric) - bgp_attr_set_aigp_metric(&attr, bgp_static->igpmetric); - if (bgp_static->atomic) attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE); @@ -6719,15 +6780,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) { @@ -8955,9 +9026,6 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); attr.tag = tag; - if (metric) - bgp_attr_set_aigp_metric(&attr, metric); - afi = family2afi(p->family); red = bgp_redist_lookup(bgp, afi, type, instance); @@ -8967,16 +9035,15 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, /* Copy attribute for modification. */ attr_new = attr; - if (red->redist_metric_flag) { + if (red->redist_metric_flag) attr_new.med = red->redist_metric; - bgp_attr_set_aigp_metric(&attr_new, red->redist_metric); - } /* Apply route-map. */ if (red->rmap.name) { memset(&rmap_path, 0, sizeof(rmap_path)); rmap_path.peer = bgp->peer_self; rmap_path.attr = &attr_new; + rmap_path.type = type; SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE); @@ -10091,6 +10158,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; @@ -10156,12 +10224,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; @@ -10496,6 +10566,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(); @@ -10522,12 +10593,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", @@ -10540,8 +10609,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; @@ -10551,31 +10619,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)); + } } } } @@ -11085,9 +11190,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 @@ -11862,10 +11966,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, @@ -11938,10 +12041,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; @@ -12069,7 +12174,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 @@ -12115,6 +12220,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) @@ -12147,7 +12254,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; @@ -12179,7 +12286,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, mpls_lse_decode(dest->local_label, &label, &ttl, &exp, &bos); - has_valid_label = bgp_is_valid_label(&label); + has_valid_label = bgp_is_valid_label(&dest->local_label); if (safi == SAFI_EVPN) { if (!json) { @@ -12365,8 +12472,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"); } } @@ -12405,10 +12518,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)++; @@ -12627,7 +12740,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 @@ -12878,7 +12991,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; @@ -12916,7 +13029,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; @@ -13579,6 +13692,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, }; @@ -13608,6 +13723,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} }; @@ -13657,6 +13774,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); @@ -14272,7 +14398,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; } @@ -14387,7 +14513,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, struct bgp_adj_out *adj = NULL; struct bgp_dest *dest; struct bgp *bgp; - struct attr attr; + struct attr attr, attr_unchanged; int ret; struct update_subgroup *subgrp; struct peer_af *paf = NULL; @@ -14567,6 +14693,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, } attr = *ain->attr; + attr_unchanged = *ain->attr; route_filtered = false; /* Filter prefix using distribute list, @@ -14622,9 +14749,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, json_ar, json_net, "%pFX", rn_p); } else - route_vty_out_tmp(vty, bgp, dest, rn_p, - &attr, safi, use_json, - json_ar, wide); + route_vty_out_tmp(vty, bgp, dest, rn_p, &attr_unchanged, + safi, use_json, json_ar, wide); bgp_attr_flush(&attr); (*output_count)++; } @@ -15774,7 +15900,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 efabbc79..d71bfd3e 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; @@ -802,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. @@ -904,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 4895ddbc..61586ea9 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) @@ -680,9 +680,8 @@ route_match_address_prefix_list(void *rule, afi_t afi, plist = prefix_list_lookup(afi, (char *)rule); if (plist == NULL) { if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "%s: Prefix List %s specified does not exist defaulting to NO_MATCH", - __func__, (char *)rule); + zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH", + __func__, (char *)rule, afi2str(afi)); return RMAP_NOMATCH; } @@ -1237,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; @@ -1252,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; } @@ -1991,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); @@ -3220,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; } @@ -3451,19 +3451,15 @@ route_set_aigp_metric(void *rule, const struct prefix *pfx, void *object) { const char *aigp_metric = rule; struct bgp_path_info *path = object; - uint32_t aigp = 0; - - if (strmatch(aigp_metric, "igp-metric")) { - if (!path->nexthop) - return RMAP_NOMATCH; + uint32_t aigp; - bgp_attr_set_aigp_metric(path->attr, path->nexthop->metric); - } else { + /* Note: the metric is stored as MED for a locally redistributed. */ + if (strmatch(aigp_metric, "igp-metric")) + aigp = path->nexthop ? path->nexthop->metric : path->attr->med; + else aigp = atoi(aigp_metric); - bgp_attr_set_aigp_metric(path->attr, aigp); - } - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AIGP); + bgp_attr_set_aigp_metric(path->attr, aigp); return RMAP_OKAY; } @@ -3949,8 +3945,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, @@ -4076,10 +4071,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)) { @@ -4094,7 +4087,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. @@ -7144,7 +7136,7 @@ DEFUN_YANG (no_set_atomic_aggregate, DEFPY_YANG (set_aigp_metric, set_aigp_metric_cmd, - "set aigp-metric $aigp_metric", + "set aigp-metric $aigp_metric", SET_STR "BGP AIGP attribute (AIGP Metric TLV)\n" "AIGP Metric value from IGP protocol\n" @@ -7164,7 +7156,7 @@ DEFPY_YANG (set_aigp_metric, DEFPY_YANG (no_set_aigp_metric, no_set_aigp_metric_cmd, - "no set aigp-metric []", + "no set aigp-metric []", NO_STR SET_STR "BGP AIGP attribute (AIGP Metric TLV)\n" @@ -7236,43 +7228,6 @@ DEFUN_YANG (no_set_aggregator_as, return nb_cli_apply_changes(vty, NULL); } -DEFUN_YANG (match_ipv6_next_hop, - match_ipv6_next_hop_cmd, - "match ipv6 next-hop ACCESSLIST6_NAME", - MATCH_STR - IPV6_STR - "Match IPv6 next-hop address of route\n" - "IPv6 access-list name\n") -{ - const char *xpath = - "./match-condition[condition='frr-route-map:ipv6-next-hop-list']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/list-name", xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - argv[argc - 1]->arg); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN_YANG (no_match_ipv6_next_hop, - no_match_ipv6_next_hop_cmd, - "no match ipv6 next-hop [ACCESSLIST6_NAME]", - NO_STR - MATCH_STR - IPV6_STR - "Match IPv6 next-hop address of route\n" - "IPv6 access-list name\n") -{ - const char *xpath = - "./match-condition[condition='frr-route-map:ipv6-next-hop-list']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, NULL); -} - DEFUN_YANG (match_ipv6_next_hop_address, match_ipv6_next_hop_address_cmd, "match ipv6 next-hop address X:X::X:X", @@ -7330,45 +7285,6 @@ ALIAS_HIDDEN (no_match_ipv6_next_hop_address, "Match IPv6 next-hop address of route\n" "IPv6 address of next hop\n") -DEFUN_YANG (match_ipv6_next_hop_prefix_list, - match_ipv6_next_hop_prefix_list_cmd, - "match ipv6 next-hop prefix-list PREFIXLIST_NAME", - MATCH_STR - IPV6_STR - "Match IPv6 next-hop address of route\n" - "Match entries by prefix-list\n" - "IPv6 prefix-list name\n") -{ - const char *xpath = - "./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-list']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/list-name", xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - argv[argc - 1]->arg); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN_YANG (no_match_ipv6_next_hop_prefix_list, - no_match_ipv6_next_hop_prefix_list_cmd, - "no match ipv6 next-hop prefix-list [PREFIXLIST_NAME]", - NO_STR - MATCH_STR - IPV6_STR - "Match IPv6 next-hop address of route\n" - "Match entries by prefix-list\n" - "IPv6 prefix-list name\n") -{ - const char *xpath = - "./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-list']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, NULL); -} - DEFPY_YANG (match_ipv4_next_hop, match_ipv4_next_hop_cmd, "match ip next-hop address A.B.C.D", @@ -8041,12 +7957,8 @@ void bgp_route_map_init(void) route_map_install_set(&route_set_ipv6_nexthop_peer_cmd); route_map_install_match(&route_match_rpki_extcommunity_cmd); - install_element(RMAP_NODE, &match_ipv6_next_hop_cmd); install_element(RMAP_NODE, &match_ipv6_next_hop_address_cmd); - install_element(RMAP_NODE, &match_ipv6_next_hop_prefix_list_cmd); - install_element(RMAP_NODE, &no_match_ipv6_next_hop_cmd); install_element(RMAP_NODE, &no_match_ipv6_next_hop_address_cmd); - install_element(RMAP_NODE, &no_match_ipv6_next_hop_prefix_list_cmd); install_element(RMAP_NODE, &match_ipv6_next_hop_old_cmd); install_element(RMAP_NODE, &no_match_ipv6_next_hop_old_cmd); install_element(RMAP_NODE, &match_ipv4_next_hop_cmd); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index f9cbf240..347c5d02 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1920,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 [source $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 $cache TCPPORT [source $bindaddr] preference (1-255)", RPKI_OUTPUT_STRING @@ -2820,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 */ @@ -2844,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 f2f47e94..9feb5501 100644 --- a/bgpd/bgp_script.h +++ b/bgpd/bgp_script.h @@ -7,7 +7,6 @@ #define __BGP_SCRIPT__ #include -#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.c b/bgpd/bgp_snmp.c index 065ea767..eff7c5e0 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -50,6 +50,21 @@ DEFPY(bgp_snmp_traps_rfc4273, bgp_snmp_traps_rfc4273_cmd, return CMD_SUCCESS; } +DEFPY(bgp_snmp_traps_rfc4382, bgp_snmp_traps_rfc4382_cmd, + "[no$no] bgp snmp traps rfc4382", + NO_STR BGP_STR + "Configure BGP SNMP\n" + "Configure SNMP traps for BGP\n" + "Configure use of rfc4382 SNMP traps for BGP\n") +{ + if (no) { + UNSET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); + return CMD_SUCCESS; + } + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); + return CMD_SUCCESS; +} + DEFPY(bgp_snmp_traps_bgp4_mibv2, bgp_snmp_traps_bgp4_mibv2_cmd, "[no$no] bgp snmp traps bgp4-mibv2", NO_STR BGP_STR @@ -69,9 +84,12 @@ static void bgp_snmp_traps_init(void) { install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4273_cmd); install_element(CONFIG_NODE, &bgp_snmp_traps_bgp4_mibv2_cmd); + install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4382_cmd); SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); /* BGP4MIBv2 traps are disabled by default */ + + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); } int bgp_cli_snmp_traps_config_write(struct vty *vty) @@ -86,6 +104,10 @@ int bgp_cli_snmp_traps_config_write(struct vty *vty) vty_out(vty, "bgp snmp traps bgp4-mibv2\n"); write++; } + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) { + vty_out(vty, "no bgp snmp traps rfc4382\n"); + write++; + } return write; } diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index e8c3e651..5f36e298 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -933,7 +933,9 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], else return SNMP_IPADDRESS(bgp_empty_addr); case BGP4V2_NLRI_AS_PATH_CALC_LENGTH: - return SNMP_INTEGER(path->attr->aspath->segments->length); + return SNMP_INTEGER((path->attr->aspath && path->attr->aspath->segments) + ? path->attr->aspath->segments->length + : 0); case BGP4V2_NLRI_AS_PATH: return aspath_snmp_pathseg(path->attr->aspath, var_len); case BGP4V2_NLRI_PATH_ATTR_UNKNOWN: diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 124e7a38..90c43b93 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -343,7 +343,12 @@ static unsigned int updgrp_hash_key_make(const void *p) key = 0; - key = jhash_1word(peer->sort, key); /* EBGP or IBGP */ + /* `remote-as auto` technically uses identical peer->sort. + * After OPEN message is parsed, this is updated accordingly, but + * we need to call the peer_sort() here also to properly create + * separate subgroups. + */ + key = jhash_1word(peer_sort((struct peer *)peer), key); key = jhash_1word(peer->sub_sort, key); /* OAD */ key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key); key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); @@ -778,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) @@ -788,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" : ""); } } @@ -2011,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 534bb752..3ce136ef 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -738,9 +738,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) /* 5: Encode all the attributes, except MP_REACH_NLRI * attr. */ - total_attr_len = bgp_packet_attribute( - NULL, peer, s, adv->baa->attr, &vecarr, NULL, - afi, safi, from, NULL, NULL, 0, 0, 0, path); + total_attr_len = bgp_packet_attribute(NULL, peer, s, adv->baa->attr, + &vecarr, NULL, afi, safi, from, NULL, + NULL, 0, 0, 0); space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s)) @@ -861,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, @@ -1148,12 +1149,9 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp, /* Make place for total attribute length. */ pos = stream_get_endp(s); stream_putw(s, 0); - total_attr_len = - bgp_packet_attribute(NULL, peer, s, attr, &vecarr, &p, afi, - safi, from, NULL, &label, num_labels, - addpath_capable, - BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, - NULL); + total_attr_len = bgp_packet_attribute(NULL, peer, s, attr, &vecarr, &p, afi, safi, from, + NULL, &label, num_labels, addpath_capable, + BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE); /* Set Total Path Attribute Length. */ stream_putw_at(s, pos, total_attr_len); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1a87799a..68ced14d 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)) @@ -1695,15 +1701,18 @@ DEFUN (no_router_bgp, /* Cannot delete default instance if vrf instances exist */ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { - struct listnode *node; + struct listnode *node, *nnode; struct bgp *tmp_bgp; - for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) { + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, tmp_bgp)) { if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; - if (CHECK_FLAG(tmp_bgp->vrf_flags, BGP_VRF_AUTO)) + if (CHECK_FLAG(tmp_bgp->vrf_flags, + BGP_VRF_AUTO)) { bgp_delete(tmp_bgp); + continue; + } if (CHECK_FLAG( tmp_bgp->af_flags[AFI_IP] @@ -2267,9 +2276,9 @@ static int bgp_global_update_delay_config_vty(struct vty *vty, * Note that we only need to check this if this is the first time * setting the global config. */ - if (bm->v_update_delay == BGP_UPDATE_DELAY_DEF) { + if (bm->v_update_delay == BGP_UPDATE_DELAY_DEFAULT) { for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { - if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) { + if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEFAULT) { vty_out(vty, "%% update-delay configuration found in vrf %s\n", bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT @@ -2314,7 +2323,7 @@ static int bgp_global_update_delay_deconfig_vty(struct vty *vty) struct listnode *node, *nnode; struct bgp *bgp; - bm->v_update_delay = BGP_UPDATE_DELAY_DEF; + bm->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; bm->v_establish_wait = bm->v_update_delay; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { @@ -2368,7 +2377,7 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty) "%%Failed: bgp update-delay configured globally. Delete per-vrf not permitted\n"); return CMD_WARNING_CONFIG_FAILED; } - bgp->v_update_delay = BGP_UPDATE_DELAY_DEF; + bgp->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; bgp->v_establish_wait = bgp->v_update_delay; return CMD_SUCCESS; @@ -2928,11 +2937,10 @@ DEFUN(bgp_reject_as_sets, bgp_reject_as_sets_cmd, * with aspath containing AS_SET or AS_CONFED_SET. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return CMD_SUCCESS; @@ -2954,11 +2962,10 @@ DEFUN(no_bgp_reject_as_sets, no_bgp_reject_as_sets_cmd, * with aspath containing AS_SET or AS_CONFED_SET. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return CMD_SUCCESS; @@ -3023,6 +3030,98 @@ DEFUN (no_bgp_deterministic_med, return CMD_SUCCESS; } +static int bgp_inst_gr_config_vty(struct vty *vty, struct bgp *bgp, bool on, + bool disable) +{ + int ret = BGP_GR_FAILURE; + + /* + * Update the instance and all its peers, if appropriate. + * Then, inform zebra of BGP's GR capabilities, if needed. + */ + if (disable) + ret = bgp_gr_update_all(bgp, on ? GLOBAL_DISABLE_CMD + : NO_GLOBAL_DISABLE_CMD); + else + ret = bgp_gr_update_all(bgp, + on ? GLOBAL_GR_CMD : NO_GLOBAL_GR_CMD); + + VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, + ret); + return ret; +} + +static int bgp_global_gr_config_vty(struct vty *vty, bool on, bool disable) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + bool vrf_cfg = false; + int ret = BGP_GR_FAILURE; + + if (disable) { + if ((on && CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) || + (!on && !CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED))) + return CMD_SUCCESS; + } else { + if ((on && CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) || + (!on && !CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER))) + return CMD_SUCCESS; + } + + /* See if GR is set per-vrf and warn user to delete */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_CONFIGURED)) { + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + enum global_mode gr_mode = bgp_global_gr_mode_get(bgp); + + if (gr_mode != GLOBAL_HELPER) { + vty_out(vty, + "%% graceful-restart configuration found in %s, mode %d\n", + bgp->name_pretty, gr_mode); + vrf_cfg = true; + } + } + } + + if (vrf_cfg) { + vty_out(vty, + "%%Failed: global graceful-restart not permitted with per-vrf configuration\n"); + return CMD_WARNING; + } + + /* Set flag globally */ + if (on) { + if (disable) { + UNSET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + SET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + } else { + SET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + UNSET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + } + } else { + if (disable) + UNSET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + else + UNSET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + } + + /* Initiate processing for all BGP instances. */ + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + ret = bgp_inst_gr_config_vty(vty, bgp, on, disable); + if (ret != BGP_GR_SUCCESS) + vty_out(vty, + "%% Applying global graceful-restart %s config to vrf %s failed, error %d\n", + (disable) ? "disable" : "", + bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT + ? "Default" + : bgp->name, + ret); + } + + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + return bgp_vty_return(vty, ret); +} + /* "bgp graceful-restart mode" configuration. */ DEFUN (bgp_graceful_restart, bgp_graceful_restart_cmd, @@ -3031,25 +3130,18 @@ DEFUN (bgp_graceful_restart, GR_CMD ) { - int ret = BGP_GR_FAILURE; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : START "); + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, true, false); + int ret = BGP_GR_FAILURE; VTY_DECLVAR_CONTEXT(bgp, bgp); - ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, true, false); if (ret == BGP_GR_SUCCESS) { - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, - ret); vty_out(vty, "Graceful restart configuration changed, reset all peers to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3061,14 +3153,13 @@ DEFUN (no_bgp_graceful_restart, NO_GR_CMD ) { - VTY_DECLVAR_CONTEXT(bgp, bgp); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : START "); + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, false, false); + VTY_DECLVAR_CONTEXT(bgp, bgp); int ret = BGP_GR_FAILURE; - ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, false, false); if (ret == BGP_GR_SUCCESS) { VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, @@ -3077,9 +3168,6 @@ DEFUN (no_bgp_graceful_restart, "Graceful restart configuration changed, reset all peers to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3091,12 +3179,21 @@ DEFUN (bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t stalepath; stalepath = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->stalepath_time = stalepath; + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + bm->stalepath_time = stalepath; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + bgp->stalepath_time = stalepath; + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->stalepath_time = stalepath; + } return CMD_SUCCESS; } @@ -3108,20 +3205,32 @@ DEFUN (bgp_graceful_restart_restart_time, "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t restart; struct listnode *node, *nnode; struct peer *peer; restart = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->restart_time = restart; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_RESTART, - CAPABILITY_ACTION_SET); + if (vty->node == CONFIG_NODE) { + struct bgp *bgp; + bm->restart_time = restart; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->restart_time = restart; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_SET); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->restart_time = restart; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_SET); + } return CMD_SUCCESS; } @@ -3133,16 +3242,32 @@ DEFUN (bgp_graceful_restart_select_defer_time, "Set the time to defer the BGP route selection after restart\n" "Delay value (seconds, 0 - disable)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t defer_time; defer_time = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->select_defer_time = defer_time; - if (defer_time == 0) - SET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); - else - UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + bm->select_defer_time = defer_time; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->select_defer_time = defer_time; + if (defer_time == 0) + SET_FLAG(bgp->flags, + BGP_FLAG_SELECT_DEFER_DISABLE); + else + UNSET_FLAG(bgp->flags, + BGP_FLAG_SELECT_DEFER_DISABLE); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->select_defer_time = defer_time; + if (defer_time == 0) + SET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + else + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } return CMD_SUCCESS; } @@ -3156,9 +3281,17 @@ DEFUN (no_bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; - bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bm->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + } return CMD_SUCCESS; } @@ -3171,17 +3304,30 @@ DEFUN (no_bgp_graceful_restart_restart_time, "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); struct listnode *node, *nnode; struct peer *peer; - bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + if (vty->node == CONFIG_NODE) { + struct bgp *bgp; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_RESTART, - CAPABILITY_ACTION_UNSET); + bm->restart_time = BGP_DEFAULT_RESTART_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_UNSET); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_UNSET); + } return CMD_SUCCESS; } @@ -3194,10 +3340,21 @@ DEFUN (no_bgp_graceful_restart_select_defer_time, "Set the time to defer the BGP route selection after restart\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; - bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; - UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->select_defer_time = + BGP_DEFAULT_SELECT_DEFERRAL_TIME; + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } return CMD_SUCCESS; } @@ -3209,8 +3366,17 @@ DEFUN (bgp_graceful_restart_preserve_fw, "Graceful restart capability parameters\n" "Sets F-bit indication that fib is preserved while doing Graceful Restart\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); - SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + SET_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD); + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } return CMD_SUCCESS; } @@ -3222,8 +3388,17 @@ DEFUN (no_bgp_graceful_restart_preserve_fw, "Graceful restart capability parameters\n" "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); - UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + UNSET_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD); + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } return CMD_SUCCESS; } @@ -3275,21 +3450,17 @@ DEFUN (bgp_graceful_restart_disable, BGP_STR GR_DISABLE) { + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, true, true); + int ret = BGP_GR_FAILURE; struct listnode *node, *nnode; struct peer *peer; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_graceful_restart_disable_cmd : START "); - VTY_DECLVAR_CONTEXT(bgp, bgp); - ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, true, true); if (ret == BGP_GR_SUCCESS) { - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, - ret); vty_out(vty, "Graceful restart configuration changed, reset all peers to take effect\n"); @@ -3303,9 +3474,6 @@ DEFUN (bgp_graceful_restart_disable, } } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_disable_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3317,27 +3485,18 @@ DEFUN (no_bgp_graceful_restart_disable, NO_GR_DISABLE ) { - VTY_DECLVAR_CONTEXT(bgp, bgp); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_graceful_restart_disable_cmd : START "); + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, false, true); + VTY_DECLVAR_CONTEXT(bgp, bgp); int ret = BGP_GR_FAILURE; - ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD); + ret = bgp_inst_gr_config_vty(vty, bgp, false, true); if (ret == BGP_GR_SUCCESS) { - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, - ret); vty_out(vty, "Graceful restart configuration changed, reset all peers to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_graceful_restart_disable_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3355,13 +3514,14 @@ DEFUN (bgp_neighbor_graceful_restart_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } result = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD); if (result == BGP_GR_SUCCESS) { @@ -3371,15 +3531,7 @@ DEFUN (bgp_neighbor_graceful_restart_set, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END "); - - if (ret != BGP_GR_SUCCESS) - vty_out(vty, - "As part of configuring graceful-restart, capability send to zebra failed\n"); - - return bgp_vty_return(vty, result); + return bgp_vty_return(vty, ret); } DEFUN (no_bgp_neighbor_graceful_restart, @@ -3400,10 +3552,11 @@ DEFUN (no_bgp_neighbor_graceful_restart, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } result = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3413,14 +3566,6 @@ DEFUN (no_bgp_neighbor_graceful_restart, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END "); - - if (ret != BGP_GR_SUCCESS) - vty_out(vty, - "As part of configuring graceful-restart, capability send to zebra failed\n"); - return bgp_vty_return(vty, result); } @@ -3438,15 +3583,14 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); - if (!peer) return CMD_WARNING_CONFIG_FAILED; - + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3456,10 +3600,6 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3481,10 +3621,11 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3494,10 +3635,6 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper, "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3515,29 +3652,24 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_disable_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD); if (ret == BGP_GR_SUCCESS) { - if (peer->bgp->t_startup) + if (peer->bgp->t_startup || bgp_in_graceful_restart()) bgp_peer_gr_flags_update(peer); VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3559,23 +3691,18 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD); if (ret == BGP_GR_SUCCESS) { VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END "); - return bgp_vty_return(vty, ret); } @@ -3590,9 +3717,10 @@ DEFPY (neighbor_graceful_shutdown, afi_t afi; safi_t safi; struct peer *peer; - VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; + VTY_DECLVAR_CONTEXT(bgp, bgp); + peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) return CMD_WARNING_CONFIG_FAILED; @@ -4745,7 +4873,7 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; as_t as; - int as_type = AS_SPECIFIED; + enum peer_asn_type as_type = AS_SPECIFIED; union sockunion su; if (as_str[0] == 'i') { @@ -4754,6 +4882,9 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, } else if (as_str[0] == 'e') { as = 0; as_type = AS_EXTERNAL; + } else if (as_str[0] == 'a') { + as = 0; + as_type = AS_AUTO; } else if (!asn_str2asn(as_str, &as)) as_type = AS_UNSPECIFIED; @@ -4859,13 +4990,14 @@ ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd, DEFUN (neighbor_remote_as, neighbor_remote_as_cmd, - "neighbor remote-as ", + "neighbor remote-as ", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_peer = 1; int idx_remote_as = 3; @@ -4913,6 +5045,27 @@ DEFUN(no_bgp_fast_convergence, no_bgp_fast_convergence_cmd, return CMD_SUCCESS; } +DEFPY (bgp_ipv6_auto_ra, + bgp_ipv6_auto_ra_cmd, + "[no] bgp ipv6-auto-ra", + NO_STR + BGP_STR + "Allow enabling IPv6 ND RA sending\n") +{ + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + COND_FLAG(bm->flags, BM_FLAG_IPV6_NO_AUTO_RA, no); + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + COND_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA, no); + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + COND_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA, no); + } + return CMD_SUCCESS; +} + static int peer_conf_interface_get(struct vty *vty, const char *conf_if, int v6only, const char *peer_group_name, @@ -4920,7 +5073,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, { VTY_DECLVAR_CONTEXT(bgp, bgp); as_t as = 0; - int as_type = AS_UNSPECIFIED; + enum peer_asn_type as_type = AS_UNSPECIFIED; struct peer *peer; struct peer_group *group; int ret = 0; @@ -4937,6 +5090,8 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, as_type = AS_INTERNAL; } else if (as_str[0] == 'e') { as_type = AS_EXTERNAL; + } else if (as_str[0] == 'a') { + as_type = AS_AUTO; } else { /* Get AS number. */ if (asn_str2asn(as_str, &as)) @@ -4980,12 +5135,13 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, else peer_flag_unset(peer, PEER_FLAG_IFPEER_V6ONLY); + peer->last_reset = PEER_DOWN_V6ONLY_CHANGE; + /* v6only flag changed. Reset bgp seesion */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_V6ONLY_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); } @@ -5053,14 +5209,15 @@ DEFUN (neighbor_interface_config_v6only, DEFUN (neighbor_interface_config_remote_as, neighbor_interface_config_remote_as_cmd, - "neighbor WORD interface remote-as ", + "neighbor WORD interface remote-as ", NEIGHBOR_STR "Interface name or neighbor tag\n" "Enable BGP on interface\n" "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_word = 1; int idx_remote_as = 4; @@ -5070,7 +5227,7 @@ DEFUN (neighbor_interface_config_remote_as, DEFUN (neighbor_interface_v6only_config_remote_as, neighbor_interface_v6only_config_remote_as_cmd, - "neighbor WORD interface v6only remote-as ", + "neighbor WORD interface v6only remote-as ", NEIGHBOR_STR "Interface name or neighbor tag\n" "Enable BGP with v6 link-local only\n" @@ -5078,7 +5235,8 @@ DEFUN (neighbor_interface_v6only_config_remote_as, "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_word = 1; int idx_remote_as = 5; @@ -5115,14 +5273,15 @@ DEFUN (neighbor_peer_group, DEFUN (no_neighbor, no_neighbor_cmd, - "no neighbor [remote-as <(1-4294967295)|internal|external>]>", + "no neighbor [remote-as <(1-4294967295)|internal|external|auto>]>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_peer = 2; @@ -5193,7 +5352,7 @@ DEFUN (no_neighbor, DEFUN (no_neighbor_interface_config, no_neighbor_interface_config_cmd, - "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external>]", + "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external|auto>]", NO_STR NEIGHBOR_STR "Interface name\n" @@ -5204,7 +5363,8 @@ DEFUN (no_neighbor_interface_config, "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; @@ -5261,14 +5421,15 @@ DEFUN (no_neighbor_peer_group, DEFUN (no_neighbor_interface_peer_group_remote_as, no_neighbor_interface_peer_group_remote_as_cmd, - "no neighbor WORD remote-as ", + "no neighbor WORD remote-as ", NO_STR NEIGHBOR_STR "Interface name or neighbor tag\n" "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; @@ -5316,7 +5477,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); } @@ -5345,19 +5506,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 local-as ASNUM no-prepend replace-as", + "neighbor 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; @@ -5375,20 +5537,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 local-as [ASNUM [no-prepend [replace-as]]]", + "no neighbor 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; @@ -8282,7 +8445,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" @@ -8291,8 +8454,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); @@ -10310,9 +10472,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); @@ -10322,6 +10484,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); @@ -10425,7 +10589,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); @@ -10435,6 +10601,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); @@ -10442,9 +10610,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 @@ -10452,13 +10630,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) { @@ -10744,7 +10915,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; @@ -10795,6 +10966,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); @@ -11404,7 +11586,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; } @@ -11767,7 +11949,8 @@ static char *bgp_peer_description_stripped(char *desc, uint32_t size) /* Determine whether var peer should be filtered out of the summary. */ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, - struct peer *fpeer, int as_type, + struct peer *fpeer, + enum peer_asn_type as_type, as_t as) { @@ -11778,7 +11961,7 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, /* filter remote-as (internal|external) */ if (as_type != AS_UNSPECIFIED) { if (peer->as_type == AS_SPECIFIED) { - if (as_type == AS_INTERNAL) { + if (CHECK_FLAG(as_type, AS_INTERNAL)) { if (peer->as != peer->local_as) return true; } else if (peer->as == peer->local_as) @@ -11801,8 +11984,8 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, * whitespaces and the whole output will be tricky. */ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, - struct peer *fpeer, int as_type, as_t as, - uint16_t show_flags) + struct peer *fpeer, enum peer_asn_type as_type, + as_t as, uint16_t show_flags) { struct peer *peer; struct listnode *node, *nnode; @@ -11914,6 +12097,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (show_failed && !failed_count) { if (use_json) { + json_object_free(json_peers); + json_object_int_add(json, "failedPeersCount", 0); json_object_int_add(json, "dynamicPeers", dn_count); json_object_int_add(json, "totalPeers", count); @@ -12196,6 +12381,12 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json_object_string_add(json_peer, "domainname", peer->domainname); + json_object_string_add(json_peer, + "softwareVersion", + peer->soft_version + ? peer->soft_version + : "n/a"); + asn_asn2json(json_peer, "remoteAs", peer->as, bgp->asnotation); asn_asn2json(json_peer, "localAs", @@ -12609,10 +12800,9 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, } static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, - safi_t safi, - const char *neighbor, - int as_type, as_t as, - uint16_t show_flags) + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, + as_t as, uint16_t show_flags) { struct listnode *node, *nnode; struct bgp *bgp; @@ -12628,6 +12818,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) @@ -12657,8 +12850,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, } int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, int as_type, - as_t as, uint16_t show_flags) + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, as_t as, + uint16_t show_flags) { struct bgp *bgp; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); @@ -12773,6 +12967,8 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd, as_type = AS_INTERNAL; else if (argv[idx + 1]->arg[0] == 'e') as_type = AS_EXTERNAL; + else if (argv[idx + 1]->arg[0] == 'a') + as_type = AS_AUTO; else if (!asn_str2asn(argv[idx + 1]->arg, &as)) { vty_out(vty, "%% Invalid neighbor remote-as value: %s\n", @@ -13895,10 +14091,15 @@ 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) || - (p->as_type == AS_EXTERNAL) || - (p->as_type == AS_INTERNAL)) { + if (p->as_type == AS_SPECIFIED || + CHECK_FLAG(p->as_type, AS_AUTO) || + CHECK_FLAG(p->as_type, AS_EXTERNAL) || + CHECK_FLAG(p->as_type, AS_INTERNAL)) { vty_out(vty, "remote AS "); vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as); vty_out(vty, ", "); @@ -13908,16 +14109,18 @@ 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) || (p->as_type == AS_INTERNAL)) { + if ((p->as == p->local_as) || (CHECK_FLAG(p->as_type, AS_INTERNAL))) { if (use_json) { if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) json_object_boolean_true_add( @@ -16012,6 +16215,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())) { @@ -16667,6 +16873,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) @@ -16789,7 +16998,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; @@ -16914,7 +17123,7 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, &conf->as); vty_out(vty, "\n"); } - } else if (conf->as_type == AS_INTERNAL) { + } else if (CHECK_FLAG(conf->as_type, AS_INTERNAL)) { if (json) asn_asn2json(json, "remoteAs", group->bgp->as, group->bgp->asnotation); @@ -16926,7 +17135,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) || (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"); @@ -18428,6 +18643,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, } else if (peer->as_type == AS_EXTERNAL) { vty_out(vty, " remote-as external"); if_ras_printed = true; + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " remote-as auto"); + if_ras_printed = true; } vty_out(vty, "\n"); @@ -18450,6 +18668,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s remote-as external\n", addr); + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " neighbor %s remote-as auto\n", + addr); } } @@ -18479,6 +18700,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s remote-as external\n", addr); + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " neighbor %s remote-as auto\n", + addr); } } } @@ -18491,6 +18715,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"); } @@ -18522,11 +18748,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) { @@ -18539,7 +18762,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, } /* TCP max segment size */ - if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS)) + if (peergroup_flag_check(peer, PEER_FLAG_TCP_MSS)) vty_out(vty, " neighbor %s tcp-mss %d\n", addr, peer->tcp_mss); /* passive */ @@ -18772,6 +18995,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; @@ -19077,6 +19304,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) { @@ -19190,11 +19420,12 @@ int bgp_config_write(struct vty *vty) hook_call(bgp_snmp_traps_config_write, vty); + vty_out(vty, "!\n"); if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER) vty_out(vty, "bgp route-map delay-timer %u\n", bm->rmap_update_timer); - if (bm->v_update_delay != BGP_UPDATE_DELAY_DEF) { + if (bm->v_update_delay != BGP_UPDATE_DELAY_DEFAULT) { vty_out(vty, "bgp update-delay %d", bm->v_update_delay); if (bm->v_update_delay != bm->v_establish_wait) vty_out(vty, " %d", bm->v_establish_wait); @@ -19204,6 +19435,30 @@ int bgp_config_write(struct vty *vty) if (bm->wait_for_fib) vty_out(vty, "bgp suppress-fib-pending\n"); + if (bm->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out(vty, "bgp graceful-restart stalepath-time %u\n", + bm->stalepath_time); + + if (bm->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out(vty, "bgp graceful-restart restart-time %u\n", + bm->restart_time); + + if (bm->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) + vty_out(vty, "bgp graceful-restart select-defer-time %u\n", + bm->select_defer_time); + + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) + vty_out(vty, "bgp graceful-restart\n"); + else if (CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) + vty_out(vty, "bgp graceful-restart-disable\n"); + + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + vty_out(vty, "bgp graceful-restart preserve-fw-state\n"); + + if (bm->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + vty_out(vty, "bgp graceful-restart rib-stale-time %u\n", + bm->rib_stale_time); + if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)) vty_out(vty, "bgp graceful-shutdown\n"); @@ -19214,6 +19469,9 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) vty_out(vty, "bgp send-extra-data zebra\n"); + if (CHECK_FLAG(bm->flags, BM_FLAG_IPV6_NO_AUTO_RA)) + vty_out(vty, "no bgp ipv6-auto-ra\n"); + /* DSCP value for outgoing packets in BGP connections */ if (bm->ip_tos != IPTOS_PREC_INTERNETCONTROL) vty_out(vty, "bgp session-dscp %u\n", bm->ip_tos >> 2); @@ -19225,6 +19483,8 @@ int bgp_config_write(struct vty *vty) if (bm->outq_limit != BM_DEFAULT_Q_LIMIT) vty_out(vty, "bgp output-queue-limit %u\n", bm->outq_limit); + vty_out(vty, "!\n"); + /* BGP configuration. */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { @@ -19232,6 +19492,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); @@ -19466,15 +19730,21 @@ int bgp_config_write(struct vty *vty) " bgp long-lived-graceful-restart stale-time %u\n", bgp->llgr_stale_time); - /* BGP graceful-restart. */ - if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) - vty_out(vty, - " bgp graceful-restart stalepath-time %u\n", - bgp->stalepath_time); + /* BGP per-instance graceful-restart. */ + /* BGP-wide settings and per-instance settings are mutually + * exclusive. + */ + if (bm->stalepath_time == BGP_DEFAULT_STALEPATH_TIME) + if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out(vty, + " bgp graceful-restart stalepath-time %u\n", + bgp->stalepath_time); - if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) - vty_out(vty, " bgp graceful-restart restart-time %u\n", - bgp->restart_time); + if (bm->restart_time == BGP_DEFAULT_RESTART_TIME) + if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out(vty, + " bgp graceful-restart restart-time %u\n", + bgp->restart_time); if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION) != SAVE_BGP_GRACEFUL_NOTIFICATION) @@ -19484,30 +19754,34 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); - if (bgp->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) - vty_out(vty, - " bgp graceful-restart select-defer-time %u\n", - bgp->select_defer_time); + if (bm->select_defer_time == BGP_DEFAULT_SELECT_DEFERRAL_TIME) + if (bgp->select_defer_time != + BGP_DEFAULT_SELECT_DEFERRAL_TIME) + vty_out(vty, + " bgp graceful-restart select-defer-time %u\n", + bgp->select_defer_time); - if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR) - vty_out(vty, " bgp graceful-restart\n"); + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_CONFIGURED)) { + if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR) + vty_out(vty, " bgp graceful-restart\n"); - if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE) - vty_out(vty, " bgp graceful-restart-disable\n"); + if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE) + vty_out(vty, " bgp graceful-restart-disable\n"); + } - /* BGP graceful-restart Preserve State F bit. */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) - vty_out(vty, - " bgp graceful-restart preserve-fw-state\n"); + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) + vty_out(vty, + " bgp graceful-restart preserve-fw-state\n"); /* BGP TCP keepalive */ bgp_config_tcp_keepalive(vty, bgp); - /* Stale timer for RIB */ - if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) - vty_out(vty, - " bgp graceful-restart rib-stale-time %u\n", - bgp->rib_stale_time); + if (bm->rib_stale_time == BGP_DEFAULT_RIB_STALE_TIME) + if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + vty_out(vty, + " bgp graceful-restart rib-stale-time %u\n", + bgp->rib_stale_time); /* BGP bestpath method. */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE)) @@ -19585,8 +19859,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); @@ -19618,6 +19893,11 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN)) vty_out(vty, " bgp shutdown\n"); + /* Automatic RA enabling by BGP */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_IPV6_NO_AUTO_RA)) + if (CHECK_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA)) + vty_out(vty, " no bgp ipv6-auto-ra\n"); + if (bgp->allow_martian) vty_out(vty, " bgp allow-martian-nexthop\n"); @@ -20158,6 +20438,12 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_fast_convergence_cmd); install_element(BGP_NODE, &no_bgp_fast_convergence_cmd); + /* global bgp ipv6-auto-ra command */ + install_element(CONFIG_NODE, &bgp_ipv6_auto_ra_cmd); + + /* bgp ipv6-auto-ra command */ + install_element(BGP_NODE, &bgp_ipv6_auto_ra_cmd); + /* global bgp update-delay command */ install_element(CONFIG_NODE, &bgp_global_update_delay_cmd); install_element(CONFIG_NODE, &no_bgp_global_update_delay_cmd); @@ -20166,6 +20452,26 @@ void bgp_vty_init(void) install_element(CONFIG_NODE, &bgp_graceful_shutdown_cmd); install_element(CONFIG_NODE, &no_bgp_graceful_shutdown_cmd); + /* BGP-wide graceful-restart commands. */ + install_element(CONFIG_NODE, &bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_disable_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_disable_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_stalepath_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_stalepath_time_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_restart_time_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_restart_time_cmd); + install_element(CONFIG_NODE, + &bgp_graceful_restart_select_defer_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_select_defer_time_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_preserve_fw_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_preserve_fw_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_rib_stale_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_rib_stale_time_cmd); + /* Dummy commands (Currently not supported) */ install_element(BGP_NODE, &no_synchronization_cmd); install_element(BGP_NODE, &no_auto_summary_cmd); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index addd7175..f88f5c81 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -60,8 +60,6 @@ struct bgp; #define VTY_BGP_GR_ROUTER_DETECT(_bgp, _peer, _peer_list) \ do { \ - if (_peer->bgp->t_startup) \ - bgp_peer_gr_flags_update(_peer); \ for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ if (CHECK_FLAG(peer_loop->flags, \ PEER_FLAG_GRACEFUL_RESTART)) \ @@ -84,30 +82,27 @@ struct bgp; } \ } while (0) -#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \ - _bgp, _peer_list, _ret) \ - do { \ - struct peer *peer_loop; \ - bool gr_router_detected = false; \ - struct listnode *node = {0}; \ - struct listnode *nnode = {0}; \ - for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ - if (peer_loop->bgp->t_startup) \ - bgp_peer_gr_flags_update(peer_loop); \ - if (CHECK_FLAG(peer_loop->flags, \ - PEER_FLAG_GRACEFUL_RESTART)) \ - gr_router_detected = true; \ - } \ - if (gr_router_detected \ - && _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, false)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } else if (!gr_router_detected \ - && _bgp->present_zebra_gr_state \ - == ZEBRA_GR_ENABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, true)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } \ +#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(_bgp, \ + _peer_list, _ret) \ + do { \ + struct peer *peer_loop; \ + bool gr_router_detected = false; \ + struct listnode *node = { 0 }; \ + struct listnode *nnode = { 0 }; \ + for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ + if (CHECK_FLAG(peer_loop->flags, \ + PEER_FLAG_GRACEFUL_RESTART)) \ + gr_router_detected = true; \ + } \ + if (gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, false)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } else if (!gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, true)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } \ } while (0) @@ -166,8 +161,9 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv, int argc, struct bgp **bgp, bool use_json); extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, int as_type, - as_t as, uint16_t show_flags); + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, as_t as, + uint16_t show_flags); extern bool peergroup_flag_check(struct peer *peer, uint64_t flag); extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint64_t flag); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 7d1e9835..9053df31 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -195,7 +195,7 @@ static int bgp_ifp_destroy(struct interface *ifp) bgp = ifp->vrf->info; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf del VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf del VRF %s IF %s", ifp->vrf->name, ifp->name); if (bgp) { @@ -220,8 +220,7 @@ static int bgp_ifp_up(struct interface *ifp) bgp_mac_add_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf->vrf_id, - ifp->name); + zlog_debug("Rx Intf up VRF %s IF %s", ifp->vrf->name, ifp->name); if (!bgp) return 0; @@ -235,7 +234,7 @@ static int bgp_ifp_up(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_up(ifp); - if (bgp_get_default() && if_is_loopback(ifp)) { + if (bgp_get_default() && if_is_vrf(ifp)) { vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); @@ -259,7 +258,7 @@ static int bgp_ifp_down(struct interface *ifp) bgp_mac_del_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf down VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf down VRF %s IF %s", ifp->vrf->name, ifp->name); if (!bgp) @@ -290,7 +289,7 @@ static int bgp_ifp_down(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_down(ifp); - if (bgp_get_default() && if_is_loopback(ifp)) { + if (bgp_get_default() && if_is_vrf(ifp)) { vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP); @@ -319,8 +318,8 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf address add VRF %u IF %s addr %pFX", vrf_id, - ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf address add VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (!bgp) return 0; @@ -398,8 +397,8 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf address del VRF %u IF %s addr %pFX", vrf_id, - ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf address del VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (bgp && if_is_operative(ifc->ifp)) { bgp_connected_delete(bgp, ifc); @@ -450,8 +449,8 @@ static int bgp_interface_nbr_address_add(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf neighbor add VRF %u IF %s addr %pFX", - vrf_id, ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf neighbor add VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (if_is_operative(ifc->ifp)) { bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -473,8 +472,8 @@ static int bgp_interface_nbr_address_delete(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf neighbor del VRF %u IF %s addr %pFX", - vrf_id, ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf neighbor del VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (if_is_operative(ifc->ifp)) { bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -543,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, @@ -556,13 +555,14 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) if (add) { inet_ntop(api.prefix.family, &nexthop, buf, sizeof(buf)); - zlog_debug( - "Rx route ADD VRF %u %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI, - vrf_id, zebra_route_string(api.type), - api.instance, &api.prefix, buf, nhtype, ifindex, - api.metric, api.distance, api.tag); + zlog_debug("Rx route ADD %s %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI, + bgp->name_pretty, + zebra_route_string(api.type), api.instance, + &api.prefix, buf, nhtype, ifindex, + api.metric, api.distance, api.tag); } else { - zlog_debug("Rx route DEL VRF %u %s[%d] %pFX", vrf_id, + zlog_debug("Rx route DEL %s %s[%d] %pFX", + bgp->name_pretty, zebra_route_string(api.type), api.instance, &api.prefix); } @@ -1098,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; @@ -1114,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; @@ -1140,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; @@ -1153,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; @@ -1251,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); @@ -1365,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) @@ -1400,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)); @@ -1526,7 +1530,6 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, struct peer *peer; uint32_t metric; route_tag_t tag; - bool is_add; uint32_t nhg_id = 0; struct bgp_table *table = bgp_dest_table(dest); const struct prefix *p = bgp_dest_get_prefix(dest); @@ -1580,9 +1583,7 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, table->afi, table->safi, &nhg_id, &metric, &tag, &allow_recursion); - is_add = (valid_nh_count || nhg_id) ? true : false; - - if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { + if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { struct bgp_zebra_opaque bzo = {}; const char *reason = bgp_path_selection_reason2str(dest->reason); @@ -1638,18 +1639,17 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, } if (bgp_debug_zebra(p)) { - zlog_debug( - "Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI - " count %d nhg %d", - is_add ? "add" : "delete", bgp->vrf_id, &api.prefix, - api.metric, api.tag, api.nexthop_num, nhg_id); + zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI + " count %d nhg %d", + bgp->name_pretty, api.tableid, &api.prefix, + api.metric, api.tag, api.nexthop_num, nhg_id); bgp_debug_zebra_nh(&api); zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", __func__, p, (allow_recursion ? "" : "NOT ")); } - return zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, - zclient, &api); + + return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } @@ -1731,8 +1731,8 @@ enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, } if (bgp_debug_zebra(p)) - zlog_debug("Tx route delete VRF %u %pFX", bgp->vrf_id, - &api.prefix); + zlog_debug("Tx route delete %s (table id %u) %pFX", + bgp->name_pretty, api.tableid, &api.prefix); return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); } @@ -1778,8 +1778,9 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) } if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("BGP %s route %pBD(%s) with dest %p and flags 0x%x to zebra", - install ? "announcing" : "withdrawing", dest, + zlog_debug("BGP %s%s route %pBD(%s) with dest %p and flags 0x%x to zebra", + install ? "announcing" : "withdrawing", + is_evpn ? " evpn" : " ", dest, table->bgp->name_pretty, dest, dest->flags); if (install) { @@ -2069,8 +2070,8 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, return CMD_SUCCESS; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute add VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), + zlog_debug("Tx redistribute add %s afi %d %s %d", + bgp->name_pretty, afi, zebra_route_string(type), instance); /* Send distribute add message to zebra. */ @@ -2090,8 +2091,8 @@ int bgp_redistribute_resend(struct bgp *bgp, afi_t afi, int type, return -1; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute del/add VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), + zlog_debug("Tx redistribute del/add %s afi %d %s %d", + bgp->name_pretty, afi, zebra_route_string(type), instance); /* Send distribute add message to zebra. */ @@ -2185,9 +2186,9 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type, if (bgp_install_info_to_zebra(bgp)) { /* Send distribute delete message to zebra. */ if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute del VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), - instance); + zlog_debug("Tx redistribute del %s afi %d %s %d", + bgp->name_pretty, afi, + zebra_route_string(type), instance); zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type, instance, bgp->vrf_id); } @@ -2290,7 +2291,7 @@ void bgp_zebra_instance_register(struct bgp *bgp) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Registering VRF %u", bgp->vrf_id); + zlog_debug("Registering %s", bgp->name_pretty); /* Register for router-id, interfaces, redistributed routes. */ zclient_send_reg_requests(zclient, bgp->vrf_id); @@ -2312,7 +2313,7 @@ void bgp_zebra_instance_deregister(struct bgp *bgp) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Deregistering VRF %u", bgp->vrf_id); + zlog_debug("Deregistering %s", bgp->name_pretty); /* For EVPN instance, unregister learning about VNIs, if appropriate. */ if (bgp->advertise_all_vni) @@ -2326,6 +2327,9 @@ void bgp_zebra_initiate_radv(struct bgp *bgp, struct peer *peer) { uint32_t ra_interval = BGP_UNNUM_DEFAULT_RA_INTERVAL; + if (CHECK_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA)) + return; + /* Don't try to initiate if we're not connected to Zebra */ if (zclient->sock < 0) return; @@ -3325,7 +3329,7 @@ static int bgp_ifp_create(struct interface *ifp) struct bgp *bgp; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf add VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf add VRF %s IF %s", ifp->vrf->name, ifp->name); bgp = ifp->vrf->info; @@ -3378,11 +3382,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, ¬e, 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; @@ -3390,10 +3661,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) @@ -3401,7 +3669,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; @@ -3413,6 +3682,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, @@ -3489,10 +3764,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 */ @@ -3503,10 +3780,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 */ @@ -3516,9 +3795,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; + } } } @@ -3555,6 +3835,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) @@ -3582,14 +3863,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) @@ -3963,6 +4247,11 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) return BGP_GR_FAILURE; } + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s(%d): Sending GR capability %s to zebra", + bgp->name_pretty, bgp->vrf_id, + disable ? "disabled" : "enabled"); + /* Check if capability is already sent. If the flag force is set * send the capability since this can be initial bgp configuration */ @@ -3978,8 +4267,8 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api) == ZCLIENT_SEND_FAILURE) { - zlog_err("%s: %s error sending capability", __func__, - bgp->name_pretty); + zlog_err("%s(%d): Error sending GR capability to zebra", + bgp->name_pretty, bgp->vrf_id); ret = BGP_GR_FAILURE; } else { if (disable) @@ -3987,9 +4276,6 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) else bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE; - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: %s send capabilty success", __func__, - bgp->name_pretty); ret = BGP_GR_SUCCESS; } return ret; @@ -4087,6 +4373,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 55a4185b..8deecba7 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 894226ad..58183818 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -149,7 +149,7 @@ void bgp_session_reset(struct peer *peer) * during walk of peer list, we would end up accessing the freed next * node. This function moves the next node along. */ -static void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) +void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) { struct listnode *n; struct peer *npeer; @@ -306,11 +306,11 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id, for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { IPV4_ADDR_COPY(&peer->local_id, id); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_RID_CHANGE; + peer->last_reset = PEER_DOWN_RID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } /* EVPN uses router id in RD, update them */ @@ -440,11 +440,12 @@ void bm_wait_for_fib_set(bool set) */ for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + if (!BGP_IS_VALID_STATE_FOR_NOTIF( peer->connection->status)) continue; - peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -496,10 +497,11 @@ void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set) * let's just start over */ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + if (!BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) continue; - peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -523,11 +525,11 @@ void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CLID_CHANGE; + peer->last_reset = PEER_DOWN_CLID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } } @@ -547,11 +549,11 @@ void bgp_cluster_id_unset(struct bgp *bgp) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CLID_CHANGE; + peer->last_reset = PEER_DOWN_CLID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } } @@ -676,14 +678,12 @@ void bgp_confederation_id_unset(struct bgp *bgp) /* We're looking for peers who's AS is not local */ if (peer_sort(peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; + peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; if (BGP_IS_VALID_STATE_FOR_NOTIF( - peer->connection->status)) { - peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; + peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } - else bgp_session_reset_safe(peer, &nnode); } @@ -1074,10 +1074,10 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) /* Peer-group */ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (peer->as_type == AS_INTERNAL) + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) return BGP_PEER_IBGP; - else if (peer->as_type == AS_EXTERNAL) + if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) return BGP_PEER_EBGP; else if (peer->as_type == AS_SPECIFIED && peer->as) { @@ -1132,17 +1132,20 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; - } else if (peer->group->conf->as_type - == AS_INTERNAL) + } else if (CHECK_FLAG(peer->group->conf->as_type, + AS_INTERNAL)) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; } /* no AS information anywhere, let caller know */ return BGP_PEER_UNSPECIFIED; - } else if (peer->as_type != AS_SPECIFIED) - return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP - : BGP_PEER_EBGP); + } else if (peer->as_type != AS_SPECIFIED) { + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) + return BGP_PEER_IBGP; + else if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) + return BGP_PEER_EBGP; + } return (local_as == 0 ? BGP_PEER_INTERNAL : local_as == peer->as ? BGP_PEER_IBGP @@ -1252,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) @@ -1391,9 +1393,33 @@ int bgp_global_gr_init(struct bgp *bgp) memcpy(bgp->GLOBAL_GR_FSM, local_GLOBAL_GR_FSM, sizeof(local_GLOBAL_GR_FSM)); - bgp->global_gr_present_state = GLOBAL_HELPER; + /* Inherit any BGP-wide configuration. */ + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) + bgp->global_gr_present_state = GLOBAL_GR; + else if (CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) + bgp->global_gr_present_state = GLOBAL_DISABLE; + else + bgp->global_gr_present_state = GLOBAL_HELPER; + + if (bm->restart_time != BGP_DEFAULT_RESTART_TIME) + bgp->restart_time = bm->restart_time; + if (bm->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + bgp->stalepath_time = bm->stalepath_time; + if (bm->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) + bgp->select_defer_time = bm->select_defer_time; + if (bm->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + bgp->rib_stale_time = bm->rib_stale_time; + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + if (CHECK_FLAG(bm->flags, BM_FLAG_IPV6_NO_AUTO_RA)) + SET_FLAG(bgp->flags, BGP_FLAG_IPV6_NO_AUTO_RA); + bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Global GR state is %s", bgp->name_pretty, + print_global_gr_mode(bgp->global_gr_present_state)); + return BGP_GR_SUCCESS; } @@ -1453,9 +1479,7 @@ int bgp_peer_gr_init(struct peer *peer) { PEER_HELPER, bgp_peer_gr_action }, { PEER_GLOBAL_INHERIT, NULL } } }; - memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, - sizeof(local_Peer_GR_FSM)); - peer->peer_gr_present_state = PEER_GLOBAL_INHERIT; + memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, sizeof(local_Peer_GR_FSM)); bgp_peer_move_to_gr_mode(peer, PEER_GLOBAL_INHERIT); return BGP_GR_SUCCESS; @@ -1474,9 +1498,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); @@ -1487,8 +1513,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) { @@ -1500,6 +1528,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. */ @@ -1929,7 +1960,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp) */ struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, + enum peer_asn_type as_type, struct peer_group *group, bool config_node, const char *as_str) { int active; @@ -2061,29 +2092,29 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) } /* Change peer's AS number. */ -void peer_as_change(struct peer *peer, as_t as, int as_specified, +void peer_as_change(struct peer *peer, as_t as, enum peer_asn_type as_type, const char *as_str) { enum bgp_peer_sort origtype, newtype; /* Stop peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; + peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); } origtype = peer_sort_lookup(peer); peer->as = as; - if (as_specified == AS_SPECIFIED && as_str) { + if (as_type == AS_SPECIFIED && as_str) { if (peer->as_pretty) XFREE(MTYPE_BGP_NAME, peer->as_pretty); peer->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); } else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty) XFREE(MTYPE_BGP_NAME, peer->as_pretty); - peer->as_type = as_specified; + peer->as_type = as_type; if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION) && !bgp_confederation_peers_check(peer->bgp, as) @@ -2140,7 +2171,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, /* If peer does not exist, create new one. If peer already exists, set AS number to the peer. */ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, - as_t *as, int as_type, const char *as_str) + as_t *as, enum peer_asn_type as_type, const char *as_str) { struct peer *peer; as_t local_as; @@ -2181,10 +2212,10 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, } } else { /* internal/external used, compare as-types */ - if (((peer_sort_type == BGP_PEER_IBGP) - && (as_type != AS_INTERNAL)) - || ((peer_sort_type == BGP_PEER_EBGP) - && (as_type != AS_EXTERNAL))) { + if (((peer_sort_type == BGP_PEER_IBGP) && + !CHECK_FLAG(as_type, AS_INTERNAL)) || + ((peer_sort_type == BGP_PEER_EBGP) && + !CHECK_FLAG(as_type, AS_EXTERNAL))) { *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } @@ -2260,7 +2291,7 @@ static void peer_group2peer_config_copy_af(struct peer_group *group, flags_tmp = conf->af_flags[afi][safi] & ~pflags_ovrd; flags_tmp ^= conf->af_flags_invert[afi][safi] ^ peer->af_flags_invert[afi][safi]; - flags_tmp &= ~pflags_ovrd; + UNSET_FLAG(flags_tmp, pflags_ovrd); UNSET_FLAG(peer->af_flags[afi][safi], ~pflags_ovrd); SET_FLAG(peer->af_flags[afi][safi], flags_tmp); @@ -2423,6 +2454,8 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) if (!active && peer_active(peer)) { bgp_timer_set(peer->connection); } else { + peer->last_reset = PEER_DOWN_AF_ACTIVATE; + if (peer_established(peer->connection)) { if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 1; @@ -2435,18 +2468,15 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) false); } } else { - peer->last_reset = PEER_DOWN_AF_ACTIVATE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } if (peer->connection->status == OpenSent || - peer->connection->status == OpenConfirm) { - peer->last_reset = PEER_DOWN_AF_ACTIVATE; + peer->connection->status == OpenConfirm) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } /* * If we are turning on a AFI/SAFI locally and we've * started bringing a peer up, we need to tell @@ -2458,11 +2488,9 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) */ other = peer->doppelganger; if (other && (other->connection->status == OpenSent || - other->connection->status == OpenConfirm)) { - other->last_reset = PEER_DOWN_AF_ACTIVATE; + other->connection->status == OpenConfirm)) bgp_notify_send(other->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return 0; @@ -2500,10 +2528,10 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi) group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { - ret |= peer_activate_af(tmp_peer, afi, safi); + SET_FLAG(ret, peer_activate_af(tmp_peer, afi, safi)); } } else { - ret |= peer_activate_af(peer, afi, safi); + SET_FLAG(ret, peer_activate_af(peer, afi, safi)); } /* If this is the first peer to be activated for this @@ -2556,6 +2584,8 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, } if (peer_established(peer->connection)) { + peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; + if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 0; peer->afc_nego[afi][safi] = 0; @@ -2567,13 +2597,11 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, bgp_clear_route(peer, afi, safi); peer->pcount[afi][safi] = 0; } else { - peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } else { - peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -2602,10 +2630,11 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi) group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { - ret |= non_peergroup_deactivate_af(tmp_peer, afi, safi); + SET_FLAG(ret, non_peergroup_deactivate_af(tmp_peer, afi, + safi)); } } else { - ret |= non_peergroup_deactivate_af(peer, afi, safi); + SET_FLAG(ret, non_peergroup_deactivate_af(peer, afi, safi)); } bgp = peer->bgp; @@ -2907,9 +2936,9 @@ static void peer_group2peer_config_copy(struct peer_group *group, peer->gtsm_hops = conf->gtsm_hops; /* peer flags apply */ - flags_tmp = conf->flags & ~peer->flags_override; + flags_tmp = CHECK_FLAG(conf->flags, ~peer->flags_override); flags_tmp ^= conf->flags_invert ^ peer->flags_invert; - flags_tmp &= ~peer->flags_override; + UNSET_FLAG(flags_tmp, peer->flags_override); UNSET_FLAG(peer->flags, ~peer->flags_override); SET_FLAG(peer->flags, flags_tmp); @@ -3001,11 +3030,14 @@ static void peer_group2peer_config_copy(struct peer_group *group, bgp_peer_configure_bfd(peer, false); bgp_peer_config_apply(peer, group); } + /* peer tcp-mss */ + if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TCP_MSS)) + PEER_ATTR_INHERIT(peer, group, tcp_mss); } /* Peer group's remote AS configuration. */ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, - int as_type, const char *as_str) + enum peer_asn_type as_type, const char *as_str) { struct peer_group *group; struct peer *peer; @@ -3322,13 +3354,13 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_RMAP_BIND; + peer->last_reset = PEER_DOWN_RMAP_BIND; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else { + else bgp_session_reset(peer); - } } /* Create a new peer. */ @@ -3393,12 +3425,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) @@ -3452,18 +3490,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, @@ -3484,7 +3528,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; @@ -3499,10 +3544,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); @@ -3519,9 +3564,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); } @@ -3539,7 +3586,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; @@ -3567,17 +3614,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); @@ -3715,10 +3765,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) @@ -3727,14 +3782,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; @@ -3750,11 +3832,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 @@ -3994,6 +4078,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"); @@ -4006,7 +4099,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); @@ -4038,7 +4132,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; } @@ -4048,7 +4142,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. */ @@ -4090,7 +4185,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", @@ -4098,17 +4193,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 */ @@ -4123,7 +4220,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; } @@ -4523,6 +4635,12 @@ bool peer_active(struct peer *peer) { if (BGP_CONNECTION_SU_UNSPEC(peer->connection)) return false; + + if (peer->bfd_config) { + if (bfd_session_is_down(peer->bfd_config->session)) + return false; + } + if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] @@ -4662,6 +4780,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}, @@ -4674,6 +4793,8 @@ 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}, + {PEER_FLAG_TCP_MSS, 0, peer_change_none}, {0, 0, 0}}; static const struct peer_flag_action peer_af_flag_action_list[] = { @@ -4729,7 +4850,7 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, if (match->flag == 0) break; - if (match->flag & flag) { + if (CHECK_FLAG(match->flag, flag)) { found = 1; if (match->type == peer_change_reset_in) @@ -4760,6 +4881,13 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, static void peer_flag_modify_action(struct peer *peer, uint64_t flag) { + if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + else if (flag == PEER_FLAG_PASSIVE) + peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; + else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) + peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; + if (flag == PEER_FLAG_SHUTDOWN) { if (CHECK_FLAG(peer->flags, flag)) { if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) @@ -4808,13 +4936,6 @@ static void peer_flag_modify_action(struct peer *peer, uint64_t flag) BGP_EVENT_ADD(peer->connection, BGP_Stop); } } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) - peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - else if (flag == PEER_FLAG_PASSIVE) - peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; - else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) - peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; - bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else @@ -5056,15 +5177,17 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, ptype = peer_sort(peer); /* Special check for reflector client. */ - if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_REFLECTOR_CLIENT) && + ptype != BGP_PEER_IBGP) return BGP_ERR_NOT_INTERNAL_PEER; /* Special check for remove-private-AS. */ - if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_REMOVE_PRIVATE_AS) && + ptype == BGP_PEER_IBGP) return BGP_ERR_REMOVE_PRIVATE_AS; /* as-override is not allowed for IBGP peers */ - if (flag & PEER_FLAG_AS_OVERRIDE && ptype == BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_AS_OVERRIDE) && ptype == BGP_PEER_IBGP) return BGP_ERR_AS_OVERRIDE; /* Handle flag updates where desired state matches current state. */ @@ -5115,7 +5238,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, * If the peer is a route server client let's not * muck with the nexthop on the way out the door */ - if (flag & PEER_FLAG_RSERVER_CLIENT) { + if (CHECK_FLAG(flag, PEER_FLAG_RSERVER_CLIENT)) { if (set) SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED); @@ -5532,12 +5655,12 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5569,13 +5692,13 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) member->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname); sockunion_free(member->update_source); member->update_source = NULL; + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5603,12 +5726,12 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5639,13 +5762,13 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) SET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE); member->update_source = sockunion_dup(su); XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5691,12 +5814,12 @@ void peer_update_source_unset(struct peer *peer) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5726,13 +5849,13 @@ void peer_update_source_unset(struct peer *peer) sockunion_free(member->update_source); member->update_source = NULL; XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5754,6 +5877,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; @@ -5836,6 +5963,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); @@ -5965,9 +6096,27 @@ void peer_port_unset(struct peer *peer) */ void peer_tcp_mss_set(struct peer *peer, uint32_t tcp_mss) { + struct peer *member; + struct listnode *node, *nnode; + + peer_flag_set(peer, PEER_FLAG_TCP_MSS); peer->tcp_mss = tcp_mss; - SET_FLAG(peer->flags, PEER_FLAG_TCP_MSS); - bgp_tcp_mss_set(peer); + + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + bgp_tcp_mss_set(peer); + return; + } + + for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) { + /* Skip peers with overridden configuration. */ + if (CHECK_FLAG(member->flags_override, PEER_FLAG_TCP_MSS)) + continue; + + /* Set flag and configuration on peer-group member. */ + SET_FLAG(member->flags, PEER_FLAG_TCP_MSS); + PEER_ATTR_INHERIT(member, peer->group, tcp_mss); + bgp_tcp_mss_set(member); + } } /* Reset the TCP-MSS value in the peer structure, @@ -5976,9 +6125,39 @@ void peer_tcp_mss_set(struct peer *peer, uint32_t tcp_mss) */ void peer_tcp_mss_unset(struct peer *peer) { - UNSET_FLAG(peer->flags, PEER_FLAG_TCP_MSS); - peer->tcp_mss = 0; - bgp_tcp_mss_set(peer); + struct peer *member; + struct listnode *node, *nnode; + + /* Inherit configuration from peer-group if peer is member. */ + if (peer_group_active(peer)) { + peer_flag_inherit(peer, PEER_FLAG_TCP_MSS); + PEER_ATTR_INHERIT(peer, peer->group, tcp_mss); + } else { + /* Otherwise remove flag and configuration from peer. */ + peer_flag_unset(peer, PEER_FLAG_TCP_MSS); + peer->tcp_mss = 0; + } + + /* Skip peer-group mechanics for regular peers. */ + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + bgp_tcp_mss_set(peer); + return; + } + + /* + * Remove flag and configuration from all peer-group members, unless + * they are explicitely overriding peer-group configuration. + */ + for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) { + /* Skip peers with overridden configuration. */ + if (CHECK_FLAG(member->flags_override, PEER_FLAG_TCP_MSS)) + continue; + + /* Remove flag and configuration on peer-group member. */ + UNSET_FLAG(member->flags, PEER_FLAG_TCP_MSS); + member->tcp_mss = 0; + bgp_tcp_mss_set(member); + } } /* @@ -6601,9 +6780,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; @@ -6616,14 +6795,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) { @@ -6652,10 +6833,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. */ @@ -6664,6 +6846,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, @@ -6686,24 +6869,26 @@ 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); } /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else BGP_EVENT_ADD(peer->connection, BGP_Stop); /* Skip peer-group mechanics for regular peers. */ @@ -6723,15 +6908,16 @@ 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; /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); } @@ -6758,6 +6944,7 @@ int peer_password_set(struct peer *peer, const char *password) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_PASSWORD_CHANGE; /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, @@ -6795,6 +6982,7 @@ int peer_password_set(struct peer *peer, const char *password) XFREE(MTYPE_PEER_PASSWORD, member->password); member->password = XSTRDUP(MTYPE_PEER_PASSWORD, password); + member->last_reset = PEER_DOWN_PASSWORD_CHANGE; /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, @@ -8401,8 +8589,8 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->start_time = monotime(NULL); bm->t_rmap_update = NULL; bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER; - bm->v_update_delay = BGP_UPDATE_DELAY_DEF; - bm->v_establish_wait = BGP_UPDATE_DELAY_DEF; + bm->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; + bm->v_establish_wait = BGP_UPDATE_DELAY_DEFAULT; bm->terminating = false; bm->socket_buffer = buffer_size; bm->wait_for_fib = false; @@ -8412,6 +8600,10 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->t_bgp_sync_label_manager = NULL; bm->t_bgp_start_label_manager = NULL; bm->t_bgp_zebra_route = NULL; + bm->restart_time = BGP_DEFAULT_RESTART_TIME; + bm->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + bm->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME; bgp_mac_init(); /* init the rd id space. @@ -8763,6 +8955,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 1f8cc533..8aeb0eb4 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -56,10 +56,12 @@ struct bgp_pbr_config; * behavior * in the system. */ -enum { AS_UNSPECIFIED = 0, - AS_SPECIFIED, - AS_INTERNAL, - AS_EXTERNAL, +enum peer_asn_type { + AS_UNSPECIFIED = 1, + AS_SPECIFIED = 2, + AS_INTERNAL = 4, + AS_EXTERNAL = 8, + AS_AUTO = 16, }; /* Zebra Gracaful Restart states */ @@ -129,6 +131,7 @@ struct bgp_master { #define BGP_OPT_NO_ZEBRA (1 << 2) #define BGP_OPT_TRAPS_RFC4273 (1 << 3) #define BGP_OPT_TRAPS_BGP4MIBV2 (1 << 4) +#define BGP_OPT_TRAPS_RFC4382 (1 << 5) uint64_t updgrp_idspace; uint64_t subgrp_idspace; @@ -163,6 +166,24 @@ struct bgp_master { uint32_t flags; #define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0) #define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1) +#define BM_FLAG_MAINTENANCE_MODE (1 << 2) +#define BM_FLAG_GR_RESTARTER (1 << 3) +#define BM_FLAG_GR_DISABLED (1 << 4) +#define BM_FLAG_GR_PRESERVE_FWD (1 << 5) +#define BM_FLAG_GRACEFUL_RESTART (1 << 6) +#define BM_FLAG_GR_COMPLETE (1 << 7) +#define BM_FLAG_IPV6_NO_AUTO_RA (1 << 8) + +#define BM_FLAG_GR_CONFIGURED (BM_FLAG_GR_RESTARTER | BM_FLAG_GR_DISABLED) + + /* BGP-wide graceful restart config params */ + uint32_t restart_time; + uint32_t stalepath_time; + uint32_t select_defer_time; + uint32_t rib_stale_time; + + time_t startup_time; + time_t gr_completion_time; bool terminating; /* global flag that sigint terminate seen */ @@ -250,7 +271,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; }; @@ -293,9 +314,9 @@ struct graceful_restart_info { /* Best route select */ struct event *t_route_select; /* AFI, SAFI enabled */ - bool af_enabled[AFI_MAX][SAFI_MAX]; + bool af_enabled; /* Route update completed */ - bool route_sync[AFI_MAX][SAFI_MAX]; + bool route_sync; }; enum global_mode { @@ -470,9 +491,7 @@ struct bgp { uint32_t restarted_peers; uint32_t implicit_eors; uint32_t explicit_eors; -#define BGP_UPDATE_DELAY_DEF 0 -#define BGP_UPDATE_DELAY_MIN 0 -#define BGP_UPDATE_DELAY_MAX 3600 +#define BGP_UPDATE_DELAY_DEFAULT 0 /* Reference bandwidth for BGP link-bandwidth. Used when * the LB value has to be computed based on some other @@ -532,6 +551,9 @@ 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) +/* Prohibit BGP from enabling IPv6 RA on interfaces */ +#define BGP_FLAG_IPV6_NO_AUTO_RA (1ULL << 40) /* BGP default address-families. * New peers inherit enabled afi/safis from bgp instance. @@ -547,6 +569,9 @@ struct bgp { */ enum zebra_gr_mode present_zebra_gr_state; + /* Is deferred path selection still not complete? */ + bool gr_route_sync_pending; + /* BGP Per AF flags */ uint16_t af_flags[AFI_MAX][SAFI_MAX]; #define BGP_CONFIG_DAMPENING (1 << 0) @@ -815,11 +840,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; @@ -1226,7 +1252,7 @@ struct peer { struct peer_af *peer_af_array[BGP_AF_MAX]; /* Peer's remote AS number. */ - int as_type; + enum peer_asn_type as_type; as_t as; /* for vty as format */ char *as_pretty; @@ -1485,6 +1511,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 @@ -1797,6 +1824,7 @@ struct peer { #define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */ #define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */ #define PEER_DOWN_SUPPRESS_FIB_PENDING 36U /* Suppress fib pending changed */ +#define PEER_DOWN_PASSWORD_CHANGE 37U /* neighbor password command */ /* * Remember to update peer_down_str in bgp_fsm.c when you add * a new value to the last_reset reason @@ -1805,16 +1833,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 { @@ -2132,6 +2157,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, @@ -2261,8 +2287,9 @@ extern bool peer_afc_advertised(struct peer *peer); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); extern struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, - bool config_node, const char *as_str); + enum peer_asn_type as_type, + struct peer_group *group, bool config_node, + const char *as_str); extern struct peer *peer_create_accept(struct bgp *); extern void peer_xfer_config(struct peer *dst, struct peer *src); extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, @@ -2335,13 +2362,13 @@ extern void bgp_listen_limit_unset(struct bgp *bgp); extern bool bgp_update_delay_active(struct bgp *); extern bool bgp_update_delay_configured(struct bgp *); extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); -extern void peer_as_change(struct peer *peer, as_t as, int as_type, - const char *as_str); +extern void peer_as_change(struct peer *peer, as_t as, + enum peer_asn_type as_type, const char *as_str); extern int peer_remote_as(struct bgp *bgp, union sockunion *su, - const char *conf_if, as_t *as, int as_type, - const char *as_str); + const char *conf_if, as_t *as, + enum peer_asn_type as_type, const char *as_str); extern int peer_group_remote_as(struct bgp *bgp, const char *peer_str, as_t *as, - int as_type, const char *as_str); + enum peer_asn_type as_type, const char *as_str); extern int peer_delete(struct peer *peer); extern void peer_notify_unconfig(struct peer *peer); extern int peer_group_delete(struct peer_group *); @@ -2422,7 +2449,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, @@ -2742,12 +2769,67 @@ static inline bool bgp_in_graceful_shutdown(struct bgp *bgp) !!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)); } +static inline bool bgp_in_graceful_restart(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is not complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline bool bgp_is_graceful_restart_complete(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is marked as complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline void bgp_update_gr_completion(void) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + + /* + * Check and mark GR complete. This is done when deferred + * path selection has been completed for all instances and + * route-advertisement/EOR and route-sync with zebra has + * been invoked. + */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)) + return; + + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (bgp->gr_route_sync_pending) + return; + } + + SET_FLAG(bm->flags, BM_FLAG_GR_COMPLETE); + bm->gr_completion_time = monotime(NULL); +} + +static inline bool bgp_gr_is_forwarding_preserved(struct bgp *bgp) +{ + /* + * Is forwarding state preserved? Based either on config + * or if BGP restarted gracefully. + * TBD: Additional AFI/SAFI based checks etc. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)); +} + /* For benefit of rfapi */ 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); @@ -2781,10 +2863,25 @@ extern bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf, extern void srv6_function_free(struct bgp_srv6_function *func); +extern void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode); + #ifdef _FRR_ATTRIBUTE_PRINTFRR /* clang-format off */ #pragma FRR printfrr_ext "%pBP" (struct peer *) /* 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/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index 7decb757..4de23066 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/configure.ac b/configure.ac index 1a5a260d..a177e5cd 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.69]) -AC_INIT([frr], [10.1.1], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [10.2], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" @@ -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 @@ -2913,7 +2919,8 @@ compiler : ${CC} compiler flags : ${CFLAGS} ${WERROR} ${AC_CFLAGS} ${SAN_FLAGS} make : ${MAKE-make} linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} -state file directory : ${e_frr_runstatedir} +local state file dir : ${e_frr_libstatedir} +run state file dir : ${e_frr_runstatedir} config file directory : ${e_frr_sysconfdir} module directory : ${e_moduledir} script directory : ${e_scriptdir} diff --git a/doc/developer/bgpd.rst b/doc/developer/bgpd.rst index a35fa614..f5263ff3 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 495c604a..a5b51481 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -18,6 +18,7 @@ import re import pygments from sphinx.highlighting import lexers from sphinx.util import logging + logger = logging.getLogger(__name__) # If extensions (or modules to document with autodoc) are in another directory, @@ -53,18 +54,26 @@ source_suffix = ".rst" master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +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 +html_context = {} +if os.environ.get("READTHEDOCS", "") == "True": + html_context["READTHEDOCS"] = True # ----------------------------------------------------------------------------- @@ -95,7 +104,7 @@ replace_vars = { # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): @@ -287,7 +296,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR Developer's Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR Developer's Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +324,7 @@ latex_logo = "../figures/frr-logo-medium.png" # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR Developer's Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR Developer's Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +339,7 @@ texinfo_documents = [ ( master_doc, "frr", - u"FRR Developer's Manual", + "FRR Developer's Manual", author, "FRR", "One line description of project.", @@ -358,27 +367,29 @@ texinfo_documents = [ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() -frrfmt_re = re.compile(r'^\s*%(?P[^\s]+)\s+\((?P.*)\)\s*$') +frrfmt_re = re.compile(r"^\s*%(?P[^\s]+)\s+\((?P.*)\)\s*$") + def parse_frrfmt(env, text, node): from sphinx import addnodes m = frrfmt_re.match(text) if not m: - logger.warning('could not parse frrfmt:: %r' % (text), location=node) + logger.warning("could not parse frrfmt:: %r" % (text), location=node) node += addnodes.desc_name(text, text) return text - spec, types = m.group('spec'), m.group('types') + spec, types = m.group("spec"), m.group("types") - node += addnodes.desc_sig_operator('%', '%') - node += addnodes.desc_name(spec + ' ', spec + ' ') + node += addnodes.desc_sig_operator("%", "%") + node += addnodes.desc_name(spec + " ", spec + " ") plist = addnodes.desc_parameterlist() - for typ in types.split(','): + for typ in types.split(","): typ = typ.strip() plist += addnodes.desc_parameter(typ, typ) node += plist - return '%' + spec + return "%" + spec + # custom extensions here def setup(app): diff --git a/doc/developer/mgmtd-dev.rst b/doc/developer/mgmtd-dev.rst index b979af06..4c56cadb 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 fb5a2872..91a767dc 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 \ -f sample-xml-skeleton --sample-xml-skeleton-defaults \ @@ -95,7 +95,7 @@ Generate skeleton instance data: * JSON: - .. code:: sh +.. code:: sh $ pyang -p \ -f jsonxsl module.yang -o module.xsl diff --git a/doc/developer/ospf-ls-retrans.rst b/doc/developer/ospf-ls-retrans.rst new file mode 100644 index 00000000..230d7a1c --- /dev/null +++ b/doc/developer/ospf-ls-retrans.rst @@ -0,0 +1,69 @@ +OSPF Neighor Retransmission List +================================ + +Overview +-------- + +OSPF neighbor link-state retransmission lists are implemented using +both a sparse Link State Database (LSDB) and a doubly-linked list. +Rather than previous per-neighbor periodic timer, a per-neighbor +timer is set to the expiration time of the next scheduled LSA +retransmission. + +Sparse Link State Database (LSDB) +--------------------------------- + +When an explicit or implied acknowledgment is recieved from a +neighbor in 2-way state or higher, the acknowledge LSA must be +removed from the neighbor's link state retransmission list. In order +to do this efficiently, a sparse LSDB is utilized. LSDB entries also +include a pointer to the corresponding list entry so that it may be +efficiently removed from the doubly-linked list. + +The sparse LSDB is implemented using the OSPF functions is +ospf_lsdb.[c,h]. OSPF LSDBs are implemented as an array of route +tables (lib/table.[c,h]). What is unique of the LS Retransmission +list LSDB is that each entry also has a pointer into the doubly-linked +list to facilitate fast deletions. + +Doubly-Linked List +------------------ + +In addition to the sparse LSDB, LSAs on a neighbor LS retransmission +list are also maintained in a linked-list order chronologically +with the LSA scheduled for the next retransmission at the head of +the list. + +The doubly-link list is implemented using the dlist macros in +lib/typesafe.h. + +LSA LS Retransmission List Addition +------------------------------------ + +When an LSA is added to a neighbor retransmission list, it is +added to both the sparse LSDB and the doubly-linked list with a pointer +in the LSDB route-table node to the list entry. The LSA is added to +the tail of the list with the expiration time set to the current time +with the retransmission interval added. If the neighbor retransmission +timer is not set, it is set to expire at the time of the newly added +LSA. + +LSA LS Retransmission List Deletion +----------------------------------- + +When an LSA is deleted from a neighbor retransmission list, it is +deleted from eboth the sparse LSDB and the doubly-linked list with the +pointer the LSDB route-table node used to efficiently delete the entry +from the list. If the LSA at the head of the list was removed, then +the neighbor retransmission timer is reset to the expiration of the +LSA at the head of the list or canceled if the list is empty. + +Neighbor LS Retransmission List Expiration +------------------------------------------ + +When the neighbor retransmission timer expires, the LSA at the top of +list and any in a configured window (e.g., 50 milliseconds) are +retransmitted. The LSAs that have been retransmitted are removed from +the list and readded to the tail of the list with a new expiration time +which is retransmit-interval seconds in the future. + diff --git a/doc/developer/ospf.rst b/doc/developer/ospf.rst index 837a0bd1..da480253 100644 --- a/doc/developer/ospf.rst +++ b/doc/developer/ospf.rst @@ -8,6 +8,7 @@ OSPFD :maxdepth: 2 ospf-api + ospf-ls-retrans ospf-sr cspf diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst index c2c3b7e7..4109057e 100644 --- a/doc/developer/packaging-debian.rst +++ b/doc/developer/packaging-debian.rst @@ -68,6 +68,8 @@ buster.) +----------------+-------------------+-----------------------------------------+ | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (default enabled) | +----------------+-------------------+-----------------------------------------+ + | pkg.frr.grpc | pkg.frr.nogrpc | builds with grpc support (default: no) | + +----------------+-------------------+-----------------------------------------+ * the ``-uc -us`` options to disable signing the packages with your GPG key diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst index d88f4499..80378734 100644 --- a/doc/developer/packaging-redhat.rst +++ b/doc/developer/packaging-redhat.rst @@ -67,24 +67,27 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24. ############### FRRouting (FRR) configure options ################# # with-feature options - %{!?with_pam: %global with_pam 0 } - %{!?with_ospfclient: %global with_ospfclient 1 } - %{!?with_ospfapi: %global with_ospfapi 1 } - %{!?with_irdp: %global with_irdp 1 } - %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_babeld: %global with_babeld 1 } + %{!?with_bfdd: %global with_bfdd 1 } + %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_cumulus: %global with_cumulus 0 } + %{!?with_eigrpd: %global with_eigrpd 1 } + %{!?with_fpm: %global with_fpm 1 } + %{!?with_mgmtd_test_be_client: %global with_mgmtd_test_be_client 0 } %{!?with_ldpd: %global with_ldpd 1 } - %{!?with_nhrpd: %global with_nhrpd 1 } - %{!?with_eigrp: %global with_eigrpd 1 } - %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 256 } - %{!?frr_user: %global frr_user frr } - %{!?vty_group: %global vty_group frrvty } - %{!?with_fpm: %global with_fpm 0 } - %{!?with_watchfrr: %global with_watchfrr 1 } - %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_nhrpd: %global with_nhrpd 1 } + %{!?with_ospfapi: %global with_ospfapi 1 } + %{!?with_ospfclient: %global with_ospfclient 1 } + %{!?with_pam: %global with_pam 0 } + %{!?with_pbrd: %global with_pbrd 1 } %{!?with_pimd: %global with_pimd 1 } %{!?with_pim6d: %global with_pim6d 1 } - %{!?with_rpki: %global with_rpki 0 } + %{!?with_vrrpd: %global with_vrrpd 1 } + %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_watchfrr: %global with_watchfrr 1 } + %{!?with_pathd: %global with_pathd 1 } + %{!?with_grpc: %global with_grpc 0 } 8. Build the RPM:: diff --git a/doc/developer/scripting.rst b/doc/developer/scripting.rst index 7a433144..f51130b1 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 e1702c47..d2308bea 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 @@ -411,6 +412,14 @@ for ``master`` branch: and create ``frr`` user and ``frrvty`` group as shown above. +Newer versions of Address Sanitizers require a sysctl to be changed +to allow for the tests to be successfully run. This is also true +for Undefined behavior Sanitizers as well as Memory Sanitizer. + +.. code:: shell + + sysctl vm.mmap_rnd_bits=28 + Debugging Topotest Failures ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -722,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. @@ -732,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`` @@ -747,9 +756,49 @@ 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 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Generally tests fail but recreating the test failure reliably is not necessarily +easy, or it happens once every 10 runs locally. Here are some generic strategies +that are employed to allow for the test to be reproduced reliably + +.. code:: console + + cd + ln -s test_the_test_name.py test_a.py + ln -s test_the_test_name.py test_b.py + +This allows you to run multiple copies of the same test with one full test run. +Additionally if you need to modify the test you don't need to recopy everything +to make it work. By adding multiple copies of the same occassionally failing test +you raise the odds of it failing again. Additionally you have easily accessible +good and bad runs to compare. + +.. code:: console + + sudo -E python3 -m pytest -n --dist=loadfile + +Choose a n value that is greater than the number of cpu's avalaible on the system. +This changes the timing and may or may not make it more likely that the test fails. +Be aware, though, that this changes memory requirements as well as may make other +tests fail more often as well. You should choose values that do not cause the system +to go into swap usage. + +.. code:: console + + stress -n + +By filling up cpu's with programs that do nothing you also change the timing again and +may cause the problem to happen more often. + +There is no magic bullet here. You as a developer might have to experiment with different +values and different combinations of the above to cause the problem to happen more often. +These are just the tools that we know of at this point in time. + .. _topotests_docker: @@ -1292,6 +1341,15 @@ Example: router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF) +or using unified config (specifying which daemons to run is optional): + +.. code:: py + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)), [ + (TopoRouter.RD_ZEBRA, "-s 90000000"), + (TopoRouter.RD_MGMTD, None), + (TopoRouter.RD_BGP, None)] - The topology definition or build function diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index f720f627..5e22c4cb 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 ========================================== @@ -1306,6 +1349,16 @@ MemorySanitizer to ``configure``. +UndefinedSanitizer + Similar to AddressSanitizer, this tool provides runtime instrumentation for + detecting use of undefined behavior in C. Testing your own code with this + tool before submission is encouraged. You can enable it by passing:: + + --enable-undefined-sanitizer + + to ``configure``. If you run FRR with this you will probably also have + to set ``sudo sysctl vm.mmap_rnd_bits=28`` + All of the above tools are available in the Clang/LLVM toolchain since 3.4. AddressSanitizer and ThreadSanitizer are available in recent versions of GCC, but are no longer actively maintained. MemorySanitizer is not available in GCC. @@ -1315,6 +1368,14 @@ but are no longer actively maintained. MemorySanitizer is not available in GCC. The different Sanitizers are mostly incompatible with each other. Please refer to GCC/LLVM documentation for details. +.. note:: + + The different sanitizers also require setting + + sysctl vm.mmap_rnd_bits=28 + + in order to work properly. + frr-format plugin This is a GCC plugin provided with FRR that does extended type checks for ``%pFX``-style printfrr extensions. To use this plugin, diff --git a/doc/manpages/bfd-options.rst b/doc/manpages/bfd-options.rst index e335ed12..3f109162 100644 --- a/doc/manpages/bfd-options.rst +++ b/doc/manpages/bfd-options.rst @@ -1,10 +1,33 @@ -BFD SOCKET ----------- +BFD +--- -The following option controls the BFD daemon control socket location. +The following options controls the BFD daemon auxiliary sockets. -.. option:: --bfdctl bfd-control-socket +.. option:: --dplaneaddr :
[<:port>] - Opens the BFD daemon control socket located at the pointed location. + Configure the distributed BFD data plane listening socket bind address. - (default: |INSTALL_PREFIX_STATE|/bfdd.sock) + One would expect the data plane to run in the same machine as FRR, so + the suggested configuration would be: + + ``--dplaneaddr unix:/var/run/frr/bfdd_dplane.sock`` + + Or using IPv4: + + ``--dplaneaddr ipv4:127.0.0.1`` + + Or using IPv6: + + ``--dplaneaddr ipv6:[::1]`` + + It is also possible to specify a port (for IPv4/IPv6 only): + + ``--dplaneaddr ipv6:[::1]:50701`` + + (if 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 + the protocol, example: + + ``--dplaneaddr ipv4c:127.0.0.1`` diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py index 73dea094..995885b2 100644 --- a/doc/manpages/conf.py +++ b/doc/manpages/conf.py @@ -91,7 +91,7 @@ replace_vars = { # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): diff --git a/doc/user/about.rst b/doc/user/about.rst new file mode 100644 index 00000000..ba80a324 --- /dev/null +++ b/doc/user/about.rst @@ -0,0 +1,533 @@ +.. _overview: + +********* +About FRR +********* + +FRR provides IP routing services. Its role in a networking stack is to exchange +routing information with other routers, make routing and policy decisions, and +inform other layers of these decisions. In the most common scenario, FRR +installs routing decisions into the OS kernel, allowing the kernel networking +stack to make the corresponding forwarding decisions. + +In addition to dynamic routing FRR supports the full range of L3 configuration, +including static routes, addresses, router advertisements etc. It has some +light L2 functionality as well, but this is mostly left to the platform. This +makes it suitable for deployments ranging from small home networks with static +routes to Internet exchanges running full Internet tables. + +System Requirements +=================== + +System resources needed by FRR are highly dependent on workload. Routing +software performance is particularly susceptible to external factors such as: + +* Kernel networking stack +* Physical NIC +* Peer behavior +* Routing information scale + +Because of these factors - especially the last one - it's difficult to lay out +resource requirements. + +To put this in perspective, FRR can be run on very low resource systems such as +SBCs, provided it is not stressed too much. If you want to set up 4 Raspberry +Pis to play with BGP or OSPF, it should work fine. If you ask a FRR to process +a complete internet routing table on a Raspberry Pi, you will be disappointed. +However, given enough resources, FRR ought to be capable of acting as a core IX +router. Such a use case requires at least 4gb of memory and a recent quad-core +server processor at a minimum. + +If you are new to networking, an important thing to remember is that FRR is +control plane software. It does not itself forward packets - it exchanges +information with peers about how to forward packets. Forwarding plane +performance largely depends on choice of NIC / ASIC. + + +Architecture +============ + +.. index:: + pair: architecture; FRR + +Traditional routing software is made as a one process program which provides +all of the routing protocol functionalities. FRR takes a different approach. +FRR is a suite of daemons that work together to build the routing table. Each +major protocol is implemented in its own daemon, and these daemons talk to a +middleman daemon (*zebra*), which is responsible for coordinating routing +decisions and talking to the dataplane. + +This architecture allows for high resiliency, since an error, crash or exploit +in one protocol daemon will generally not affect the others. It is also +flexible and extensible since the modularity makes it easy to implement new +protocols and tie them into the suite. Additionally, each daemon implements a +plugin system allowing new functionality to be loaded at runtime. + +An illustration of the large scale architecture is given below. + +:: + + +----+ +----+ +-----+ +----+ +----+ +----+ +-----+ + |bgpd| |ripd| |ospfd| |ldpd| |pbrd| |pimd| |.....| + +----+ +----+ +-----+ +----+ +----+ +----+ +-----+ + | | | | | | | + +----v-------v--------v-------v-------v-------v--------v + | | + | Zebra | + | | + +------------------------------------------------------+ + | | | + | | | + +------v------+ +---------v--------+ +------v------+ + | | | | | | + | *NIX Kernel | | Remote dataplane | | ........... | + | | | | | | + +-------------+ +------------------+ +-------------+ + + +All of the FRR daemons can be managed through a single integrated user +interface shell called *vtysh*. *vtysh* connects to each daemon through a UNIX +domain socket and then works as a proxy for user input. In addition to a +unified frontend, *vtysh* also provides the ability to configure all the +daemons using a single configuration file through the integrated configuration +mode. This avoids the overhead of maintaining a separate configuration file for +each daemon. + +FRR is currently implementing a new internal configuration system based on YANG +data models. When this work is completed, FRR will be a fully programmable +routing stack. + + +.. index:: + pair: platforms; FRR + pair: operating systems; FRR + +.. _supported-platforms: + +Platform Support +================ + +Currently FRR supports GNU/Linux and BSD. Porting FRR to other platforms is not +too difficult as platform dependent code should be mostly limited to the +*Zebra* daemon. Protocol daemons are largely platform independent. Please let +us know if you can get FRR to run on a platform which is not listed below: + +- GNU/Linux +- FreeBSD +- NetBSD +- OpenBSD + +Versions of these platforms that are older than around 2 years from the point +of their original release (in case of GNU/Linux, this is since the kernel's +release on https://kernel.org/) may need some work. Similarly, the following +platforms may work with some effort: + +- MacOS + +Recent versions of the following compilers are well tested: + +- GNU's GCC +- LLVM's Clang +- Intel's ICC + +.. _unsupported-platforms: + +Unsupported Platforms +--------------------- + +In General if the platform you are attempting to use is not listed above then +FRR does not support being run on that platform. The only caveat here is that +version 7.5 and before Solaris was supported in a limited fashion. + +.. _feature-matrix: + +Feature Matrix +^^^^^^^^^^^^^^ + +The following table lists all protocols cross-referenced to all operating +systems that have at least CI build tests. Note that for features, only +features with system dependencies are included here; if you don't see the +feature you're interested in, it should be supported on your platform. + +.. role:: mark + +.. comment - the :mark:`X` pieces mesh with a little bit of JavaScript and + CSS in _static/overrides.{js,css} respectively. The JS code looks at the + presence of the 'Y' 'N' '≥' '†' or 'CP' strings. This seemed to be the + best / least intrusive way of getting a nice table in HTML. The table + will look somewhat shoddy on other sphinx targets like PDF or info (but + should still be readable.) + ++-----------------------------------+----------------+--------------+------------+------------+ +| Daemon / Feature | Linux | OpenBSD | FreeBSD | NetBSD | ++===================================+================+==============+============+============+ +| **FRR Core** | | | | | ++-----------------------------------+----------------+--------------+------------+------------+ +| `zebra` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| VRF | :mark:`≥4.8` | :mark:`N` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| MPLS | :mark:`≥4.5` | :mark:`Y` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| `pbrd` (Policy Routing) | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| **WAN / Carrier protocols** | | | | | ++-----------------------------------+----------------+--------------+------------+------------+ +| `bgpd` (BGP) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| VRF / L3VPN | :mark:`≥4.8` | :mark:`CP` | :mark:`CP` | :mark:`CP` | +| | :mark:`†4.3` | | | | ++-----------------------------------+----------------+--------------+------------+------------+ +| EVPN | :mark:`≥4.18` | :mark:`CP` | :mark:`CP` | :mark:`CP` | +| | :mark:`†4.9` | | | | ++-----------------------------------+----------------+--------------+------------+------------+ +| VNC (Virtual Network Control) | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` | ++-----------------------------------+----------------+--------------+------------+------------+ +| Flowspec | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` | ++-----------------------------------+----------------+--------------+------------+------------+ +| `ldpd` (LDP) | :mark:`≥4.5` | :mark:`Y` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| VPWS / PW | :mark:`N` | :mark:`≥5.8` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| VPLS | :mark:`N` | :mark:`≥5.8` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| `nhrpd` (NHRP) | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| **Link-State Routing** | | | | | ++-----------------------------------+----------------+--------------+------------+------------+ +| `ospfd` (OSPFv2) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| Segment Routing | :mark:`≥4.12` | :mark:`N` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| `ospf6d` (OSPFv3) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| `isisd` (IS-IS) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| **Distance-Vector Routing** | | | | | ++-----------------------------------+----------------+--------------+------------+------------+ +| `ripd` (RIPv2) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| `ripngd` (RIPng) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| `babeld` (BABEL) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| `eigrpd` (EIGRP) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| **Multicast Routing** | | | | | ++-----------------------------------+----------------+--------------+------------+------------+ +| `pimd` (PIM) | :mark:`≥4.19` | :mark:`N` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| SSM (Source Specific) | :mark:`Y` | :mark:`N` | :mark:`Y` | :mark:`Y` | ++-----------------------------------+----------------+--------------+------------+------------+ +| ASM (Any Source) | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| EVPN BUM Forwarding | :mark:`≥5.0` | :mark:`N` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ +| `vrrpd` (VRRP) | :mark:`≥5.1` | :mark:`N` | :mark:`N` | :mark:`N` | ++-----------------------------------+----------------+--------------+------------+------------+ + +The indicators have the following semantics: + +* :mark:`Y` - daemon/feature fully functional +* :mark:`≥X.X` - fully functional with kernel version X.X or newer +* :mark:`†X.X` - restricted functionality or impaired performance with kernel version X.X or newer +* :mark:`CP` - control plane only (i.e. BGP route server / route reflector) +* :mark:`N` - daemon/feature not supported by operating system + + +Known Kernel Issues +------------------- + +- Linux < 4.11 + + v6 Route Replacement - Linux kernels before 4.11 can cause issues with v6 + route deletion when you have ECMP routes installed into the kernel. This + especially becomes apparent if the route is being transformed from one ECMP + path to another. + + +.. index:: + pair: rfcs; FRR + +.. _supported-rfcs: + +Supported RFCs +-------------- + +FRR implements the following RFCs: + +.. note:: This list is incomplete. + +BGP +---- + +- :rfc:`1771` + :t:`A Border Gateway Protocol 4 (BGP-4). Y. Rekhter & T. Li. March 1995.` +- :rfc:`1965` + :t:`Autonomous System Confederations for BGP. P. Traina. June 1996.` +- :rfc:`1997` + :t:`BGP Communities Attribute. R. Chandra, P. Traina & T. Li. August 1996.` +- :rfc:`1998` + :t:`An Application of the BGP Community Attribute in Multi-home Routing. E. Chen, T. Bates. August 1996.` +- :rfc:`2385` + :t:`Protection of BGP Sessions via the TCP MD5 Signature Option. A. Heffernan. August 1998.` +- :rfc:`2439` + :t:`BGP Route Flap Damping. C. Villamizar, R. Chandra, R. Govindan. November 1998.` +- :rfc:`2545` + :t:`Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. P. Marques, F. Dupont. March 1999.` +- :rfc:`2796` + :t:`BGP Route Reflection An alternative to full mesh IBGP. T. Bates & R. Chandrasekeran. June 1996.` +- :rfc:`2842` + :t:`Capabilities Advertisement with BGP-4. R. Chandra, J. Scudder. May 2000.` +- :rfc:`2858` + :t:`Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.` +- :rfc:`2918` + :t:`Route Refresh Capability for BGP-4. E. Chen, September 2000.` +- :rfc:`3107` + :t:`Carrying Label Information in BGP-4. Y. Rekhter & E. Rosen. May 2001.` +- :rfc:`3765` + :t:`NOPEER Community for Border Gateway Protocol (BGP) Route Scope Control. G.Huston. April 2001.` +- :rfc:`4271` + :t:`A Border Gateway Protocol 4 (BGP-4). Updates RFC1771. Y. Rekhter, T. Li & S. Hares. January 2006.` +- :rfc:`4360` + :t:`BGP Extended Communities Attribute. S. Sangli, D. Tappan, Y. Rekhter. February 2006.` +- :rfc:`4364` + :t:`BGP/MPLS IP Virtual Private Networks (VPNs). Y. Rekhter. February 2006.` +- :rfc:`4456` + :t:`BGP Route Reflection An alternative to full mesh IBGP. T. Bates, E. Chen, R. Chandra. April 2006.` +- :rfc:`4486` + :t:`Subcodes for BGP Cease Notification Message. E. Chen, V. Gillet. April 2006.` +- :rfc:`4659` + :t:`BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN. J. De Clercq, D. Ooms, M. Carugi, F. Le Faucheur. September 2006.` +- :rfc:`4724` + :t:`Graceful Restart Mechanism for BGP. S. Sangli, E. Chen, R. Fernando, J. Scudder, Y. Rekhter. January 2007.` +- :rfc:`4760` + :t:`Multiprotocol Extensions for BGP-4. T. Bates, R. Chandra, D. Katz, Y. Rekhter. January 2007.` +- :rfc:`4893` + :t:`BGP Support for Four-octet AS Number Space. Q. Vohra, E. Chen May 2007.` +- :rfc:`5004` + :t:`Avoid BGP Best Path Transitions from One External to Another. E. Chen & S. Sangli. September 2007 (Partial support).` +- :rfc:`5065` + :t:`Autonomous System Confederations for BGP. P. Traina, D. McPherson, J. Scudder. August 2007.` +- :rfc:`5082` + :t:`The Generalized TTL Security Mechanism (GTSM). V. Gill, J. Heasley, D. Meyer, P. Savola, C. Pingnataro. October 2007.` +- :rfc:`5291` + :t:`Outbound Route Filtering Capability. E. Chen, Y. Rekhter. August 2008.` +- :rfc:`5292` + :t:`Address-Prefix-Based Outbound Route Filter for BGP-4. E. Chen, S. Sangli. August 2008.` +- :rfc:`5396` + :t:`Textual Representation of Autonomous System (AS) Numbers. G. Michaelson, G. Huston. December 2008.` +- :rfc:`5492` + :t:`Capabilities Advertisement with BGP-4. J. Scudder, R. Chandra. February 2009.` +- :rfc:`5575` + :t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009.` +- :rfc:`5668` + :t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009.` +- :rfc:`5701` + :t:`IPv6 Address Specific BGP Extended Community Attribute. Y. Rekhter. 2009.` +- :rfc:`6286` + :t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan. June 2011.` +- :rfc:`6472` + :t:`Recommendation for Not Using AS_SET and AS_CONFED_SET in BGP. W. Kumari, K. Sriram. December 2011.` +- :rfc:`6608` + :t:`Subcodes for BGP Finite State Machine Error. J. Dong, M. Chen, Huawei Technologies, A. Suryanarayana, Cisco Systems. May 2012.` +- :rfc:`6810` + :t:`The Resource Public Key Infrastructure (RPKI) to Router Protocol. R. Bush, R. Austein. January 2013.` +- :rfc:`6811` + :t:`BGP Prefix Origin Validation. P. Mohapatra, J. Scudder, D. Ward, R. Bush, R. Austein. January 2013.` +- :rfc:`6938` + :t:`Deprecation of BGP Path Attributes: DPA, ADVERTISER, and RCID_PATH / CLUSTER_ID. J. Scudder. May 2013.` +- :rfc:`6996` + :t:`Autonomous System (AS) Reservation for Private Use. J. Mitchell. July 2013.` +- :rfc:`7196` + :t:`Making Route Flap Damping Usable. C. Pelsser, R. Bush, K. Patel, P. Mohapatra, O. Maennel. May 2014.` +- :rfc:`7300` + :t:`Reservation of Last Autonomous System (AS) Numbers. J. Haas, J. Mitchell. July 2014.` +- :rfc:`7313` + :t:`Enhanced Route Refresh Capability for BGP-4. K. Patel, E. Chen, B. Venkatachalapathy. July 2014.` +- :rfc:`7606` + :t:`Revised Error Handling for BGP UPDATE Messages. E. Chen, J. Scudder, P. Mohapatra, K. Patel. August 2015.` +- :rfc:`7607` + :t:`Codification of AS 0 Processing. W. Kumari, R. Bush, H. Schiller, K. Patel. August 2015.` +- :rfc:`7611` + :t:`BGP ACCEPT_OWN Community Attribute. J. Uttaro, P. Mohapatra, D. Smith, R. Raszuk, J. Scudder. August 2015.` +- :rfc:`7911` + :t:`Advertisement of Multiple Paths in BGP. D. Walton, A. Retana, E. Chen, J. Scudder. July 2016.` +- :rfc:`7947` + :t:`Internet Exchange BGP Route Server. E. Jasinska, N. Hilliard, R. Raszuk, N. Bakker. September 2016.` +- :rfc:`7999` + :t:`BLACKHOLE Community. T. King, C. Dietzel, J. Snijders, G. Doering, G. Hankins. October 2016.` +- :rfc:`8050` + :t:`Multi-Threaded Routing Toolkit (MRT) Routing Information Export Format with BGP Additional Path Extensions. C. Petrie, T. King. May 2017.` +- :rfc:`8092` + :t:`BGP Large Communities Attribute. J. Heitz, Ed., J. Snijders, Ed, K. Patel, I. Bagdonas, N. Hilliard. February 2017.` +- :rfc:`8093` + :t:`Deprecation of BGP Path Attribute Values 30, 31, 129, 241, 242, and 243. J. Snijders. February 2017.` +- :rfc:`8097` + :t:`BGP Prefix Origin Validation State Extended Community. P. Mohapatra, K. Patel, J. Scudder, D. Ward, R. Bush. March 2017.` +- :rfc:`8195` + :t:`Use of BGP Large Communities. J. Snijders, J. Heasley, M. Schmidt. June 2017.` +- :rfc:`8203` + :t:`BGP Administrative Shutdown Communication. J. Snijders, J. Heitz, J. Scudder. July 2017.` +- :rfc:`8212` + :t:`Default External BGP (EBGP) Route Propagation Behavior without Policies. J. Mauch, J. Snijders, G. Hankins. July 2017.` +- :rfc:`8277` + :t:`Using BGP to Bind MPLS Labels to Address Prefixes. E. Rosen. October 2017.` +- :rfc:`8538` + :t:`Notification Message Support for BGP Graceful Restart. K. Patel, R. Fernando, J. Scudder, J. Haas. March 2019.` +- :rfc:`8654` + :t:`Extended Message Support for BGP. R. Bush, K. Patel, D. Ward. October 2019.` +- :rfc:`9003` + :t:`Extended BGP Administrative Shutdown Communication. J. Snijders, J. Heitz, J. Scudder, A. Azimov. January 2021.` +- :rfc:`9012` + :t:`The BGP Tunnel Encapsulation Attribute. K. Patel, G. Van de Velde, S. Sangli, J. Scudder. April 2021.` +- :rfc:`9072` + :t:`Extended Optional Parameters Length for BGP OPEN Message. E. Chen, J. Scudder. July 2021.` +- :rfc:`9234` + :t:`Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages. A. Azimov, E. Bogomazov, R. Bush, K. Patel, K. Sriram. May 2022.` +- :rfc:`9384` + :t:`A BGP Cease NOTIFICATION Subcode for Bidirectional Forwarding Detection (BFD). J. Haas. March 2023.` +- :rfc:`9494` + :t:`Long-Lived Graceful Restart for BGP. J. Uttaro, E. Chen, B. Decraene, J. Scudder. November 2023.` + +OSPF +---- + +- :rfc:`2328` + :t:`OSPF Version 2. J. Moy. April 1998.` +- :rfc:`2370` + :t:`The OSPF Opaque LSA Option R. Coltun. July 1998.` +- :rfc:`3101` + :t:`The OSPF Not-So-Stubby Area (NSSA) Option P. Murphy. January 2003.` +- :rfc:`2740` + :t:`OSPF for IPv6. R. Coltun, D. Ferguson, J. Moy. December 1999.` +- :rfc:`3137` + :t:`OSPF Stub Router Advertisement, A. Retana, L. Nguyen, R. White, A. Zinin, D. McPherson. June 2001` + +ISIS +---- + +RIP +---- + +- :rfc:`1058` + :t:`Routing Information Protocol. C.L. Hedrick. Jun-01-1988.` +- :rfc:`2082` + :t:`RIP-2 MD5 Authentication. F. Baker, R. Atkinson. January 1997.` +- :rfc:`2453` + :t:`RIP Version 2. G. Malkin. November 1998.` +- :rfc:`2080` + :t:`RIPng for IPv6. G. Malkin, R. Minnear. January 1997.` + +PIM +---- + +BFD +---- +- :rfc:`5880` + :t:`Bidirectional Forwarding Detection (BFD), D. Katz, D. Ward. June 2010` +- :rfc:`5881` + :t:`Bidirectional Forwarding Detection (BFD) for IPv4 and IPv6 (Single Hop), D. Katz, D. Ward. June 2010` +- :rfc:`5882` + :t:`Generic Application of Bidirectional Forwarding Detection (BFD), D. Katz, D. Ward. June 2010` +- :rfc:`5883` + :t:`Bidirectional Forwarding Detection (BFD) for Multihop Paths, D. Katz, D. Ward. June 2010` + +MPLS +---- + +- :rfc:`2858` + :t:`Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.` +- :rfc:`4364` + :t:`BGP/MPLS IP Virtual Private Networks (VPNs). Y. Rekhter. Feb 2006.` +- :rfc:`4447` + :t:`Pseudowire Setup and Maintenance Using the Label Distribution Protocol (LDP), L. Martini, E. Rosen, N. El-Aawar, T. Smith, and G. Heron. April 2006.` +- :rfc:`4659` + :t:`BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN. J. De Clercq, D. Ooms, M. Carugi, F. Le Faucheur. September 2006` +- :rfc:`4762` + :t:`Virtual Private LAN Service (VPLS) Using Label Distribution Protocol (LDP) Signaling, M. Lasserre and V. Kompella. January 2007.` +- :rfc:`5036` + :t:`LDP Specification, L. Andersson, I. Minei, and B. Thomas. October 2007.` +- :rfc:`5561` + :t:`LDP Capabilities, B. Thomas, K. Raza, S. Aggarwal, R. Aggarwal, and JL. Le Roux. July 2009.` +- :rfc:`5918` + :t:`Label Distribution Protocol (LDP) 'Typed Wildcard' Forward Equivalence Class (FEC), R. Asati, I. Minei, and B. Thomas. August 2010.` +- :rfc:`5919` + :t:`Signaling LDP Label Advertisement Completion, R. Asati, P. Mohapatra, E. Chen, and B. Thomas. August 2010.` +- :rfc:`6667` + :t:`LDP 'Typed Wildcard' Forwarding Equivalence Class (FEC) for PWid and Generalized PWid FEC Elements, K. Raza, S. Boutros, and C. Pignataro. July 2012.` +- :rfc:`6720` + :t:`The Generalized TTL Security Mechanism (GTSM) for the Label Distribution Protocol (LDP), C. Pignataro and R. Asati. August 2012.` +- :rfc:`7552` + :t:`Updates to LDP for IPv6, R. Asati, C. Pignataro, K. Raza, V. Manral, and R. Papneja. June 2015.` + +VRRP +---- + +- :rfc:`3768` + :t:`Virtual Router Redundancy Protocol (VRRP). R. Hinden. April 2004.` +- :rfc:`5798` + :t:`Virtual Router Redundancy Protocol (VRRP) Version 3 for IPv4 and IPv6. S. Nadas. June 2000.` + +SNMP +---- + +**When SNMP support is enabled, the following RFCs are also supported:** + +- :rfc:`1227` + :t:`SNMP MUX protocol and MIB. M.T. Rose. May-01-1991.` +- :rfc:`1657` + :t:`Definitions of Managed Objects for the Fourth Version of the Border + Gateway Protocol (BGP-4) using SMIv2. S. Willis, J. Burruss, J. Chu, Editor. + July 1994.` +- :rfc:`1724` + :t:`RIP Version 2 MIB Extension. G. Malkin & F. Baker. November 1994.` +- :rfc:`1850` + :t:`OSPF Version 2 Management Information Base. F. Baker, R. Coltun. + November 1995.` +- :rfc:`2741` + :t:`Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.` + + +.. index:: + pair: mailing lists; contact + +.. _mailing-lists: + +Mailing Lists +============= + +Italicized lists are private. + ++--------------------------------+------------------------------+ +| Topic | List | ++================================+==============================+ +| Development | dev@lists.frrouting.org | ++--------------------------------+------------------------------+ +| Users & Operators | frog@lists.frrouting.org | ++--------------------------------+------------------------------+ +| Announcements | announce@lists.frrouting.org | ++--------------------------------+------------------------------+ +| *Security* | security@lists.frrouting.org | ++--------------------------------+------------------------------+ +| *Technical Steering Committee* | tsc@lists.frrouting.org | ++--------------------------------+------------------------------+ + +The Development list is used to discuss and document general issues related to +project development and governance. The public `Slack`_ instance and weekly +technical meetings provide a higher bandwidth channel for discussions. The +results of such discussions are reflected in updates, as appropriate, to code +(i.e., merges), `GitHub issues`_ tracked issues, and for governance or process +changes, updates to the Development list and either this file or information +posted at `FRR`_. + + +Bug Reports +=========== + +For information on reporting bugs, please see :ref:`bug-reports`. + +.. _frr: https://frrouting.org +.. _github: https://github.com/frrouting/frr/ +.. _github issues: https://github.com/frrouting/frr/issues +.. _slack: https://frrouting.org/community diff --git a/doc/user/basics.rst b/doc/user/basics.rst new file mode 100644 index 00000000..4504e989 --- /dev/null +++ b/doc/user/basics.rst @@ -0,0 +1,23 @@ +.. _basics: + +###### +Basics +###### + +.. toctree:: + :maxdepth: 2 + + basic + extlog + vtysh + grpc + filter + routemap + affinitymap + ipv6 + kernel + snmp + scripting + nexthop_groups + + diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 3ca104a3..4c142cfb 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -1,12 +1,19 @@ .. _bfd: -********************************** -Bidirectional Forwarding Detection -********************************** +*** +BFD +*** -:abbr:`BFD (Bidirectional Forwarding Detection)` stands for -Bidirectional Forwarding Detection and it is described and extended by -the following RFCs: +:abbr:`BFD (Bidirectional Forwarding Detection)` is: + + a protocol intended to detect faults in the bidirectional path between two + forwarding engines, including interfaces, data link(s), and to the extent + possible the forwarding engines themselves, with potentially very low + latency. + + -- :rfc:`5880` + +It is described and extended by the following RFCs: * :rfc:`5880` * :rfc:`5881` @@ -38,19 +45,6 @@ may also be specified (:ref:`common-invocation-options`). .. program:: bfdd -.. option:: --bfdctl - - Set the BFD daemon control socket location. If using a non-default - socket location:: - - /usr/lib/frr/bfdd --bfdctl /tmp/bfdd.sock - - - The default UNIX socket location is |INSTALL_PREFIX_STATE|/bfdd.sock - - This option overrides the location addition that the -N option provides - to the bfdd.sock - .. option:: --dplaneaddr :
[<:port>] Configure the distributed BFD data plane listening socket bind address. @@ -72,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 150a915e..adf5261f 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 @@ -92,6 +92,12 @@ be specified (:ref:`common-invocation-options`). the operator has turned off communication to zebra and is running bgpd as a complete standalone process. +.. option:: -K, --graceful_restart + + Bgpd will use this option to denote either a planned FRR graceful + restart or a bgpd-only graceful restart, and this will drive the BGP + GR restarting router procedures. + LABEL MANAGER ------------- @@ -154,16 +160,16 @@ bottom until one of the factors can be used. Prefer higher local preference routes to lower. +3. **Local route check** + + Prefer local routes (statics, aggregates, redistributed) to received routes. + If ``bgp bestpath aigp`` is enabled, and both paths that are compared have AIGP attribute, BGP uses AIGP tie-breaking unless both of the paths have the AIGP metric attribute. This means that the AIGP attribute is not evaluated during the best path selection process between two paths when one path does not have the AIGP attribute. -3. **Local route check** - - Prefer local routes (statics, aggregates, redistributed) to received routes. - 4. **AS path length check** Prefer shortest hop-count AS_PATHs. @@ -1080,6 +1086,52 @@ Default global mode is helper and default peer per mode is inherit from global. If per peer mode is configured, the GR mode of this particular peer will override the global mode. +.. _bgp-GR-config-mode-cmd: + +BGP GR Config Mode Commands +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. clicmd:: bgp graceful-restart + + This command will enable BGP graceful restart functionality for all BGP instances. + +.. clicmd:: bgp graceful-restart-disable + + This command will disable both the functionality graceful restart and helper + mode for all BGP instances + +.. clicmd:: bgp graceful-restart select-defer-time (0-3600) + + This is command, will set deferral time to value specified. + +.. clicmd:: bgp graceful-restart rib-stale-time (1-3600) + + This is command, will set the time for which stale routes are kept in RIB. + +.. clicmd:: bgp graceful-restart restart-time (0-4095) + + Set the time to wait to delete stale routes before a BGP open message + is received. + + Using with Long-lived Graceful Restart capability, this is recommended + setting this timer to 0 and control stale routes with + ``bgp long-lived-graceful-restart stale-time``. + + Default value is 120. + +.. clicmd:: bgp graceful-restart stalepath-time (1-4095) + + This is command, will set the max time (in seconds) to hold onto + restarting peer's stale paths. + + It also controls Enhanced Route-Refresh timer. + + If this command is configured and the router does not receive a Route-Refresh EoRR + message, the router removes the stale routes from the BGP table after the timer + expires. The stale path timer is started when the router receives a Route-Refresh + BoRR message + + .. _bgp-GR-global-mode-cmd: BGP GR Global Mode Commands @@ -1230,6 +1282,13 @@ IPv6 Support address family is enabled by default for all new neighbors. +.. clicmd:: bgp ipv6-auto-ra + + By default, bgpd can ask Zebra to enable sending IPv6 router advertisement + messages on interfaces. For example, this happens for unnumbered peers + support or when extended-nexthop capability is used. The ``no`` form of this + command disables such behaviour. + .. _bgp-route-aggregation: Route Aggregation @@ -1509,6 +1568,10 @@ Defining Peers peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN` command the connection will be denied. +.. clicmd:: neighbor PEER remote-as auto + + The neighbor's ASN is detected automatically from the OPEN message. + .. clicmd:: neighbor PEER oad Mark a peer belonging to the One Administrative Domain. @@ -1647,7 +1710,7 @@ Configuring Peers IPv4 session addresses, see the ``neighbor PEER update-source`` command below. -.. clicmd:: neighbor PEER interface remote-as +.. clicmd:: neighbor PEER interface remote-as Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The session will be established via IPv6 link locals. Use ``internal`` for iBGP @@ -1762,7 +1825,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 @@ -1778,6 +1841,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 as-override @@ -1916,12 +1983,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 @@ -2135,8 +2204,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] @@ -2426,7 +2494,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 728f9c93..f9f178f5 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -18,6 +18,8 @@ import re import pygments import sphinx from sphinx.highlighting import lexers +from sphinx.domains.std import GenericObject +from docutils.parsers.rst import directives # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -52,18 +54,28 @@ source_suffix = ".rst" master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +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 +html_context = {} +if os.environ.get("READTHEDOCS", "") == "True": + html_context["READTHEDOCS"] = True # ----------------------------------------------------------------------------- @@ -94,7 +106,7 @@ replace_vars = { # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): @@ -287,7 +299,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR User Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR User Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +327,7 @@ latex_logo = "../figures/frr-logo-medium.png" # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR User Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR User Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +342,7 @@ texinfo_documents = [ ( master_doc, "frr", - u"FRR User Manual", + "FRR User Manual", author, "FRR", "One line description of project.", @@ -358,6 +370,7 @@ texinfo_documents = [ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() + # Parse version string into int array def vparse(s): a = [] @@ -372,11 +385,54 @@ def vparse(s): return a[:3] -# custom extensions here +class ClicmdDirective(GenericObject): + """ + Directive for documenting CLI commands. + + The xref string, if no option is provided, will be the verbatim command + string. If the :daemon: option is provided, then it's + "() )". + + Options: + :daemon: - specify the daemon this command belongs to. Useful for + disambiguating multiple definitions of the same command. + """ + + has_content = True + required_arguments = 1 + optional_arguments = 0 + option_spec = { + **GenericObject.option_spec, + "daemon": directives.unchanged, + } + + def handle_signature(self, sig, signode): + name = super().handle_signature(sig, signode) + daemon = self.options["daemon"] if "daemon" in self.options else "" + prefix = f"({daemon}) " if daemon else "" + return prefix + name + + def run(self): + daemon = self.options["daemon"] if "daemon" in self.options else "" + if daemon: + self.indextemplate = f"pair: ({daemon}) %s; configuration command" + else: + self.indextemplate = f"pair: %s; configuration command" + + nodes = super().run() + + return nodes + + def setup(app): - # object type for FRR CLI commands, can be extended to document parent CLI - # node later on - app.add_object_type("clicmd", "clicmd", indextemplate="pair: %s; configuration command") + # Override the directive that was just created for us + if int(sphinx.__version__.split(".")[0]) >= 2: + app.add_object_type("clicmd", "clicmd", objname="CLI command") + app.add_directive_to_domain("std", "clicmd", ClicmdDirective, override=True) + else: + app.add_object_type( + "clicmd", "clicmd", indextemplate="pair: %s; configuration command" + ) # I dont care how stupid this is if "add_js_file" in dir(app): @@ -389,7 +445,6 @@ def setup(app): else: app.add_stylesheet("overrides.css") - # load Pygments lexer for FRR config syntax # # NB: in Pygments 2.2+ this can be done with `load_lexer_from_file`, but we diff --git a/doc/user/index.rst b/doc/user/index.rst index 4789677a..d3b632a8 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -1,80 +1,31 @@ FRRouting User Guide ==================== -############ -Introduction -############ +FRR is a fully featured, high performance, free software IP routing suite. It +implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and +more (see :ref:`feature-matrix`), as well as many of their extensions. It can +handle full Internet routing tables and is suitable for use on hardware ranging +from cheap SBCs to commercial grade routers, and is actively used in production +by hundreds of companies, universities, research labs and governments. -.. _introduction: -.. toctree:: - :maxdepth: 2 - - overview - installation - setup - -###### -Basics -###### +FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. +Feature support varies by platform; see the :ref:`feature-matrix`. -.. _basics: -.. toctree:: - :maxdepth: 2 +FRR is distributed under GPLv2, with development modeled after the Linux +kernel. Anyone may contribute features, bug fixes, tools, documentation +updates, or anything else. - basic - extlog - vtysh - grpc - filter - routemap - affinitymap - ipv6 - kernel - snmp - scripting - nexthop_groups -.. modules +FRR is a fork of `Quagga `_. -######### -Protocols -######### - -.. _protocols: .. toctree:: :maxdepth: 2 - zebra - bfd - bgp - babeld - fabricd - ldpd - eigrpd - evpn - isisd - nhrpd - ospfd - ospf6d - pathd - pim - pimv6 - pbr - ripd - ripngd - sharp - static - vnc - vrrp - bmp - watchfrr - mgmtd - -######## -Appendix -######## + introduction + basics + protocols -.. _appendix: .. toctree:: + :caption: Appendix :maxdepth: 2 bugs diff --git a/doc/user/installation.rst b/doc/user/installation.rst index e49f1049..4d2017c0 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -3,22 +3,25 @@ single: Installing FRR single: Building FRR -.. _installation: - Installation ============ -This section covers the basics of building, installing and setting up FRR. +This section covers the basics of building, installing and setting up +FRR. +The official FRR website is located at |PACKAGE_URL| and contains further +information, as well as links to additional resources. From Packages ------------- -The project publishes packages for Red Hat, Centos, Debian and Ubuntu on the -`GitHub releases `_. page. External -contributors offer packages for many other platforms including \*BSD, Alpine, -Gentoo, Docker, and others. There is currently no documentation on how to use -those but we hope to add it soon. +Up-to-date Debian & Redhat packages are available at +https://deb.frrouting.org/ & https://rpm.frrouting.org/ respectively. + +Several distributions also provide packages for FRR. Check your +distribution's repositories to find out if a suitable version is +available. + From Snapcraft -------------- @@ -29,12 +32,12 @@ universal Snap images, available at https://snapcraft.io/frr. From Source ----------- -Building FRR from source is the best way to ensure you have the latest features -and bug fixes. Details for each supported platform, including dependency -package listings, permissions, and other gotchas, are in the `developer's -documentation -`_. This -section provides a brief overview on the process. +Building FRR from source is the best way to ensure you have the latest +features and bug fixes. Details for each supported platform, including +dependency package listings, permissions, and other gotchas, are in the +`developer's documentation +`_. +This section provides a brief overview on the process. Getting the Source diff --git a/doc/user/introduction.rst b/doc/user/introduction.rst new file mode 100644 index 00000000..89866b9c --- /dev/null +++ b/doc/user/introduction.rst @@ -0,0 +1,13 @@ +.. _introduction: + +############ +Introduction +############ + +.. toctree:: + :maxdepth: 2 + + about + installation + setup + diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst index 4f01061e..18aae00b 100644 --- a/doc/user/ipv6.rst +++ b/doc/user/ipv6.rst @@ -25,7 +25,8 @@ Router Advertisement .. clicmd:: ipv6 nd suppress-ra Don't send router advertisement messages. The ``no`` form of this command - enables sending RA messages. + enables sending RA messages. Note that while being suppressed, RA messages + might still be enabled by other daemons, such as bgpd or vrrpd. .. clicmd:: ipv6 nd prefix ipv6prefix [valid-lifetime] [preferred-lifetime] [off-link] [no-autoconfig] [router-address] diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 74126118..3a0f277b 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -325,7 +325,7 @@ Showing ISIS information Show topology IS-IS paths to Intermediate Systems, globally, in area (level-1) or domain (level-2). -.. clicmd:: show isis [vrf ] route [level-1|level-2] [prefix-sid|backup] [algorithm [(128-255)]] +.. clicmd:: show isis [vrf ] route [level-1|level-2] [prefix-sid] [backup] [algorithm [(128-255)]] Show the ISIS routing table, as determined by the most recent SPF calculation. diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst index cbed734e..7a000a49 100644 --- a/doc/user/ldpd.rst +++ b/doc/user/ldpd.rst @@ -148,7 +148,7 @@ LDP Configuration configured password. PASSWORD is a clear text password wit its digest sent through the network. -.. clicmd:: neighbor A.B.C.D holdtime HOLDTIME +.. clicmd:: neighbor A.B.C.D session holdtime HOLDTIME The following command located under MPLS router node configures the holdtime value in seconds of the LDP neighbor ID. Configuring it triggers a keepalive diff --git a/doc/user/nhrpd.rst b/doc/user/nhrpd.rst index 54527a0c..648d56d9 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -84,6 +84,12 @@ Configuring NHRP registration requests are sent. By default registrations are sent every one third of the holdtime. +.. clicmd:: ip nhrp authentication PASSWORD + + Enables Cisco style authentication on NHRP packets. This embeds the + plaintext password to the outgoing NHRP packets. + Maximum length of the password is 8 characters. + .. clicmd:: ip nhrp map A.B.C.D|X:X::X:X A.B.C.D|local Map an IP address of a station to the station's NBMA address. diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 70c15e73..b80adba7 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -738,7 +738,17 @@ Interfaces retransmitting Database Description and Link State Request packets. The default value is 5 seconds. -.. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] +.. clicmd:: ip ospf retransmit-window (20-1000) + + + Set number of milliseconds in the window for neighbor LSA retransmission. + When a neighbor Link State (LS) retransmission timer expires, LSAs scheduled + to be retransmitted within the number of milliseconds configured are + retransmitted to the neighbor. Any expiring after the window will be + retransmitted the next time the neighbor LS retransmission timer expires. + The default is 50 milliseconds. + + .. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] Set number of seconds for InfTransDelay value. LSAs' age should be diff --git a/doc/user/overview.rst b/doc/user/overview.rst deleted file mode 100644 index 2ef88acd..00000000 --- a/doc/user/overview.rst +++ /dev/null @@ -1,574 +0,0 @@ -.. _overview: - -******** -Overview -******** - -`FRR`_ is a fully featured, high performance, free software IP routing suite. - -FRR implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and -more (see :ref:`feature-matrix`), as well as many of their extensions. - -FRR is a high performance suite written primarily in C. It can easily handle -full Internet routing tables and is suitable for use on hardware ranging from -cheap SBCs to commercial grade routers. It is actively used in production by -hundreds of companies, universities, research labs and governments. - -FRR is distributed under GPLv2, with development modeled after the Linux -kernel. Anyone may contribute features, bug fixes, tools, documentation -updates, or anything else. - -FRR is a fork of `Quagga `_. - -.. _how-to-get-frr: - -How to get FRR -============== - -The official FRR website is located at |PACKAGE_URL| and contains further -information, as well as links to additional resources. - -Several distributions provide packages for FRR. Check your distribution's -repositories to find out if a suitable version is available. - -Up-to-date Debian & Redhat packages are available at https://deb.frrouting.org/ -& https://rpm.frrouting.org/ respectively. - -For instructions on installing from source, refer to the -`developer documentation `_. - - -.. _about-frr: - -About FRR -========= - -FRR provides IP routing services. Its role in a networking stack is to exchange -routing information with other routers, make routing and policy decisions, and -inform other layers of these decisions. In the most common scenario, FRR -installs routing decisions into the OS kernel, allowing the kernel networking -stack to make the corresponding forwarding decisions. - -In addition to dynamic routing FRR supports the full range of L3 configuration, -including static routes, addresses, router advertisements etc. It has some -light L2 functionality as well, but this is mostly left to the platform. This -makes it suitable for deployments ranging from small home networks with static -routes to Internet exchanges running full Internet tables. - -FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. -Feature support varies by platform; see the :ref:`feature-matrix`. - -System Requirements -------------------- - -System resources needed by FRR are highly dependent on workload. Routing -software performance is particularly susceptible to external factors such as: - -* Kernel networking stack -* Physical NIC -* Peer behavior -* Routing information scale - -Because of these factors - especially the last one - it's difficult to lay out -resource requirements. - -To put this in perspective, FRR can be run on very low resource systems such as -SBCs, provided it is not stressed too much. If you want to set up 4 Raspberry -Pis to play with BGP or OSPF, it should work fine. If you ask a FRR to process -a complete internet routing table on a Raspberry Pi, you will be disappointed. -However, given enough resources, FRR ought to be capable of acting as a core IX -router. Such a use case requires at least 4gb of memory and a recent quad-core -server processor at a minimum. - -If you are new to networking, an important thing to remember is that FRR is -control plane software. It does not itself forward packets - it exchanges -information with peers about how to forward packets. Forwarding plane -performance largely depends on choice of NIC / ASIC. - - -System Architecture -------------------- - -.. index:: - pair: architecture; FRR - -Traditional routing software is made as a one process program which provides -all of the routing protocol functionalities. FRR takes a different approach. -FRR is a suite of daemons that work together to build the routing table. Each -major protocol is implemented in its own daemon, and these daemons talk to a -middleman daemon (*zebra*), which is responsible for coordinating routing -decisions and talking to the dataplane. - -This architecture allows for high resiliency, since an error, crash or exploit -in one protocol daemon will generally not affect the others. It is also -flexible and extensible since the modularity makes it easy to implement new -protocols and tie them into the suite. Additionally, each daemon implements a -plugin system allowing new functionality to be loaded at runtime. - -An illustration of the large scale architecture is given below. - -:: - - +----+ +----+ +-----+ +----+ +----+ +----+ +-----+ - |bgpd| |ripd| |ospfd| |ldpd| |pbrd| |pimd| |.....| - +----+ +----+ +-----+ +----+ +----+ +----+ +-----+ - | | | | | | | - +----v-------v--------v-------v-------v-------v--------v - | | - | Zebra | - | | - +------------------------------------------------------+ - | | | - | | | - +------v------+ +---------v--------+ +------v------+ - | | | | | | - | *NIX Kernel | | Remote dataplane | | ........... | - | | | | | | - +-------------+ +------------------+ +-------------+ - - -All of the FRR daemons can be managed through a single integrated user -interface shell called *vtysh*. *vtysh* connects to each daemon through a UNIX -domain socket and then works as a proxy for user input. In addition to a -unified frontend, *vtysh* also provides the ability to configure all the -daemons using a single configuration file through the integrated configuration -mode. This avoids the overhead of maintaining a separate configuration file for -each daemon. - -FRR is currently implementing a new internal configuration system based on YANG -data models. When this work is completed, FRR will be a fully programmable -routing stack. - - -.. index:: - pair: platforms; FRR - pair: operating systems; FRR - -.. _supported-platforms: - -Supported Platforms -------------------- - - -Currently FRR supports GNU/Linux and BSD. Porting FRR to other platforms is not -too difficult as platform dependent code should be mostly limited to the -*Zebra* daemon. Protocol daemons are largely platform independent. Please let -us know if you can get FRR to run on a platform which is not listed below: - -- GNU/Linux -- FreeBSD -- NetBSD -- OpenBSD - -Versions of these platforms that are older than around 2 years from the point -of their original release (in case of GNU/Linux, this is since the kernel's -release on https://kernel.org/) may need some work. Similarly, the following -platforms may work with some effort: - -- MacOS - -Recent versions of the following compilers are well tested: - -- GNU's GCC -- LLVM's Clang -- Intel's ICC - -.. _unsupported-platforms: - -Unsupported Platforms ---------------------- - -In General if the platform you are attempting to use is not listed above then -FRR does not support being run on that platform. The only caveat here is that -version 7.5 and before Solaris was supported in a limited fashion. - -.. _feature-matrix: - -Feature Matrix -^^^^^^^^^^^^^^ - -The following table lists all protocols cross-referenced to all operating -systems that have at least CI build tests. Note that for features, only -features with system dependencies are included here; if you don't see the -feature you're interested in, it should be supported on your platform. - -.. role:: mark - -.. comment - the :mark:`X` pieces mesh with a little bit of JavaScript and - CSS in _static/overrides.{js,css} respectively. The JS code looks at the - presence of the 'Y' 'N' '≥' '†' or 'CP' strings. This seemed to be the - best / least intrusive way of getting a nice table in HTML. The table - will look somewhat shoddy on other sphinx targets like PDF or info (but - should still be readable.) - -+-----------------------------------+----------------+--------------+------------+------------+ -| Daemon / Feature | Linux | OpenBSD | FreeBSD | NetBSD | -+===================================+================+==============+============+============+ -| **FRR Core** | | | | | -+-----------------------------------+----------------+--------------+------------+------------+ -| `zebra` | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| VRF | :mark:`≥4.8` | :mark:`N` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| MPLS | :mark:`≥4.5` | :mark:`Y` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| `pbrd` (Policy Routing) | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| **WAN / Carrier protocols** | | | | | -+-----------------------------------+----------------+--------------+------------+------------+ -| `bgpd` (BGP) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| VRF / L3VPN | :mark:`≥4.8` | :mark:`CP` | :mark:`CP` | :mark:`CP` | -| | :mark:`†4.3` | | | | -+-----------------------------------+----------------+--------------+------------+------------+ -| EVPN | :mark:`≥4.18` | :mark:`CP` | :mark:`CP` | :mark:`CP` | -| | :mark:`†4.9` | | | | -+-----------------------------------+----------------+--------------+------------+------------+ -| VNC (Virtual Network Control) | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` | -+-----------------------------------+----------------+--------------+------------+------------+ -| Flowspec | :mark:`CP` | :mark:`CP` | :mark:`CP` | :mark:`CP` | -+-----------------------------------+----------------+--------------+------------+------------+ -| `ldpd` (LDP) | :mark:`≥4.5` | :mark:`Y` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| VPWS / PW | :mark:`N` | :mark:`≥5.8` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| VPLS | :mark:`N` | :mark:`≥5.8` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| `nhrpd` (NHRP) | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| **Link-State Routing** | | | | | -+-----------------------------------+----------------+--------------+------------+------------+ -| `ospfd` (OSPFv2) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| Segment Routing | :mark:`≥4.12` | :mark:`N` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| `ospf6d` (OSPFv3) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| `isisd` (IS-IS) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| **Distance-Vector Routing** | | | | | -+-----------------------------------+----------------+--------------+------------+------------+ -| `ripd` (RIPv2) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| `ripngd` (RIPng) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| `babeld` (BABEL) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| `eigrpd` (EIGRP) | :mark:`Y` | :mark:`Y` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| **Multicast Routing** | | | | | -+-----------------------------------+----------------+--------------+------------+------------+ -| `pimd` (PIM) | :mark:`≥4.19` | :mark:`N` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| SSM (Source Specific) | :mark:`Y` | :mark:`N` | :mark:`Y` | :mark:`Y` | -+-----------------------------------+----------------+--------------+------------+------------+ -| ASM (Any Source) | :mark:`Y` | :mark:`N` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| EVPN BUM Forwarding | :mark:`≥5.0` | :mark:`N` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ -| `vrrpd` (VRRP) | :mark:`≥5.1` | :mark:`N` | :mark:`N` | :mark:`N` | -+-----------------------------------+----------------+--------------+------------+------------+ - -The indicators have the following semantics: - -* :mark:`Y` - daemon/feature fully functional -* :mark:`≥X.X` - fully functional with kernel version X.X or newer -* :mark:`†X.X` - restricted functionality or impaired performance with kernel version X.X or newer -* :mark:`CP` - control plane only (i.e. BGP route server / route reflector) -* :mark:`N` - daemon/feature not supported by operating system - - -Known Kernel Issues -------------------- - -- Linux < 4.11 - - v6 Route Replacement - Linux kernels before 4.11 can cause issues with v6 - route deletion when you have ECMP routes installed into the kernel. This - especially becomes apparent if the route is being transformed from one ECMP - path to another. - - -.. index:: - pair: rfcs; FRR - -.. _supported-rfcs: - -Supported RFCs --------------- - -FRR implements the following RFCs: - -.. note:: This list is incomplete. - -BGP ----- - -- :rfc:`1771` - :t:`A Border Gateway Protocol 4 (BGP-4). Y. Rekhter & T. Li. March 1995.` -- :rfc:`1965` - :t:`Autonomous System Confederations for BGP. P. Traina. June 1996.` -- :rfc:`1997` - :t:`BGP Communities Attribute. R. Chandra, P. Traina & T. Li. August 1996.` -- :rfc:`1998` - :t:`An Application of the BGP Community Attribute in Multi-home Routing. E. Chen, T. Bates. August 1996.` -- :rfc:`2385` - :t:`Protection of BGP Sessions via the TCP MD5 Signature Option. A. Heffernan. August 1998.` -- :rfc:`2439` - :t:`BGP Route Flap Damping. C. Villamizar, R. Chandra, R. Govindan. November 1998.` -- :rfc:`2545` - :t:`Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. P. Marques, F. Dupont. March 1999.` -- :rfc:`2796` - :t:`BGP Route Reflection An alternative to full mesh IBGP. T. Bates & R. Chandrasekeran. June 1996.` -- :rfc:`2842` - :t:`Capabilities Advertisement with BGP-4. R. Chandra, J. Scudder. May 2000.` -- :rfc:`2858` - :t:`Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.` -- :rfc:`2918` - :t:`Route Refresh Capability for BGP-4. E. Chen, September 2000.` -- :rfc:`3107` - :t:`Carrying Label Information in BGP-4. Y. Rekhter & E. Rosen. May 2001.` -- :rfc:`3765` - :t:`NOPEER Community for Border Gateway Protocol (BGP) Route Scope Control. G.Huston. April 2001.` -- :rfc:`4271` - :t:`A Border Gateway Protocol 4 (BGP-4). Updates RFC1771. Y. Rekhter, T. Li & S. Hares. January 2006.` -- :rfc:`4360` - :t:`BGP Extended Communities Attribute. S. Sangli, D. Tappan, Y. Rekhter. February 2006.` -- :rfc:`4364` - :t:`BGP/MPLS IP Virtual Private Networks (VPNs). Y. Rekhter. February 2006.` -- :rfc:`4456` - :t:`BGP Route Reflection An alternative to full mesh IBGP. T. Bates, E. Chen, R. Chandra. April 2006.` -- :rfc:`4486` - :t:`Subcodes for BGP Cease Notification Message. E. Chen, V. Gillet. April 2006.` -- :rfc:`4659` - :t:`BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN. J. De Clercq, D. Ooms, M. Carugi, F. Le Faucheur. September 2006.` -- :rfc:`4724` - :t:`Graceful Restart Mechanism for BGP. S. Sangli, E. Chen, R. Fernando, J. Scudder, Y. Rekhter. January 2007.` -- :rfc:`4760` - :t:`Multiprotocol Extensions for BGP-4. T. Bates, R. Chandra, D. Katz, Y. Rekhter. January 2007.` -- :rfc:`4893` - :t:`BGP Support for Four-octet AS Number Space. Q. Vohra, E. Chen May 2007.` -- :rfc:`5004` - :t:`Avoid BGP Best Path Transitions from One External to Another. E. Chen & S. Sangli. September 2007 (Partial support).` -- :rfc:`5065` - :t:`Autonomous System Confederations for BGP. P. Traina, D. McPherson, J. Scudder. August 2007.` -- :rfc:`5082` - :t:`The Generalized TTL Security Mechanism (GTSM). V. Gill, J. Heasley, D. Meyer, P. Savola, C. Pingnataro. October 2007.` -- :rfc:`5291` - :t:`Outbound Route Filtering Capability. E. Chen, Y. Rekhter. August 2008.` -- :rfc:`5292` - :t:`Address-Prefix-Based Outbound Route Filter for BGP-4. E. Chen, S. Sangli. August 2008.` -- :rfc:`5396` - :t:`Textual Representation of Autonomous System (AS) Numbers. G. Michaelson, G. Huston. December 2008.` -- :rfc:`5492` - :t:`Capabilities Advertisement with BGP-4. J. Scudder, R. Chandra. February 2009.` -- :rfc:`5575` - :t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009.` -- :rfc:`5668` - :t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009.` -- :rfc:`6286` - :t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan. June 2011.` -- :rfc:`6472` - :t:`Recommendation for Not Using AS_SET and AS_CONFED_SET in BGP. W. Kumari, K. Sriram. December 2011.` -- :rfc:`6608` - :t:`Subcodes for BGP Finite State Machine Error. J. Dong, M. Chen, Huawei Technologies, A. Suryanarayana, Cisco Systems. May 2012.` -- :rfc:`6810` - :t:`The Resource Public Key Infrastructure (RPKI) to Router Protocol. R. Bush, R. Austein. January 2013.` -- :rfc:`6811` - :t:`BGP Prefix Origin Validation. P. Mohapatra, J. Scudder, D. Ward, R. Bush, R. Austein. January 2013.` -- :rfc:`6938` - :t:`Deprecation of BGP Path Attributes: DPA, ADVERTISER, and RCID_PATH / CLUSTER_ID. J. Scudder. May 2013.` -- :rfc:`6996` - :t:`Autonomous System (AS) Reservation for Private Use. J. Mitchell. July 2013.` -- :rfc:`7196` - :t:`Making Route Flap Damping Usable. C. Pelsser, R. Bush, K. Patel, P. Mohapatra, O. Maennel. May 2014.` -- :rfc:`7300` - :t:`Reservation of Last Autonomous System (AS) Numbers. J. Haas, J. Mitchell. July 2014.` -- :rfc:`7313` - :t:`Enhanced Route Refresh Capability for BGP-4. K. Patel, E. Chen, B. Venkatachalapathy. July 2014.` -- :rfc:`7606` - :t:`Revised Error Handling for BGP UPDATE Messages. E. Chen, J. Scudder, P. Mohapatra, K. Patel. August 2015.` -- :rfc:`7607` - :t:`Codification of AS 0 Processing. W. Kumari, R. Bush, H. Schiller, K. Patel. August 2015.` -- :rfc:`7611` - :t:`BGP ACCEPT_OWN Community Attribute. J. Uttaro, P. Mohapatra, D. Smith, R. Raszuk, J. Scudder. August 2015.` -- :rfc:`7911` - :t:`Advertisement of Multiple Paths in BGP. D. Walton, A. Retana, E. Chen, J. Scudder. July 2016.` -- :rfc:`7947` - :t:`Internet Exchange BGP Route Server. E. Jasinska, N. Hilliard, R. Raszuk, N. Bakker. September 2016.` -- :rfc:`7999` - :t:`BLACKHOLE Community. T. King, C. Dietzel, J. Snijders, G. Doering, G. Hankins. October 2016.` -- :rfc:`8050` - :t:`Multi-Threaded Routing Toolkit (MRT) Routing Information Export Format with BGP Additional Path Extensions. C. Petrie, T. King. May 2017.` -- :rfc:`8092` - :t:`BGP Large Communities Attribute. J. Heitz, Ed., J. Snijders, Ed, K. Patel, I. Bagdonas, N. Hilliard. February 2017.` -- :rfc:`8093` - :t:`Deprecation of BGP Path Attribute Values 30, 31, 129, 241, 242, and 243. J. Snijders. February 2017.` -- :rfc:`8097` - :t:`BGP Prefix Origin Validation State Extended Community. P. Mohapatra, K. Patel, J. Scudder, D. Ward, R. Bush. March 2017.` -- :rfc:`8195` - :t:`Use of BGP Large Communities. J. Snijders, J. Heasley, M. Schmidt. June 2017.` -- :rfc:`8203` - :t:`BGP Administrative Shutdown Communication. J. Snijders, J. Heitz, J. Scudder. July 2017.` -- :rfc:`8212` - :t:`Default External BGP (EBGP) Route Propagation Behavior without Policies. J. Mauch, J. Snijders, G. Hankins. July 2017.` -- :rfc:`8277` - :t:`Using BGP to Bind MPLS Labels to Address Prefixes. E. Rosen. October 2017.` -- :rfc:`8538` - :t:`Notification Message Support for BGP Graceful Restart. K. Patel, R. Fernando, J. Scudder, J. Haas. March 2019.` -- :rfc:`8654` - :t:`Extended Message Support for BGP. R. Bush, K. Patel, D. Ward. October 2019.` -- :rfc:`9003` - :t:`Extended BGP Administrative Shutdown Communication. J. Snijders, J. Heitz, J. Scudder, A. Azimov. January 2021.` -- :rfc:`9012` - :t:`The BGP Tunnel Encapsulation Attribute. K. Patel, G. Van de Velde, S. Sangli, J. Scudder. April 2021.` -- :rfc:`9072` - :t:`Extended Optional Parameters Length for BGP OPEN Message. E. Chen, J. Scudder. July 2021.` -- :rfc:`9234` - :t:`Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages. A. Azimov, E. Bogomazov, R. Bush, K. Patel, K. Sriram. May 2022.` -- :rfc:`9384` - :t:`A BGP Cease NOTIFICATION Subcode for Bidirectional Forwarding Detection (BFD). J. Haas. March 2023.` -- :rfc:`9494` - :t:`Long-Lived Graceful Restart for BGP. J. Uttaro, E. Chen, B. Decraene, J. Scudder. November 2023.` - -OSPF ----- - -- :rfc:`2328` - :t:`OSPF Version 2. J. Moy. April 1998.` -- :rfc:`2370` - :t:`The OSPF Opaque LSA Option R. Coltun. July 1998.` -- :rfc:`3101` - :t:`The OSPF Not-So-Stubby Area (NSSA) Option P. Murphy. January 2003.` -- :rfc:`2740` - :t:`OSPF for IPv6. R. Coltun, D. Ferguson, J. Moy. December 1999.` -- :rfc:`3137` - :t:`OSPF Stub Router Advertisement, A. Retana, L. Nguyen, R. White, A. Zinin, D. McPherson. June 2001` - -ISIS ----- - -RIP ----- - -- :rfc:`1058` - :t:`Routing Information Protocol. C.L. Hedrick. Jun-01-1988.` -- :rfc:`2082` - :t:`RIP-2 MD5 Authentication. F. Baker, R. Atkinson. January 1997.` -- :rfc:`2453` - :t:`RIP Version 2. G. Malkin. November 1998.` -- :rfc:`2080` - :t:`RIPng for IPv6. G. Malkin, R. Minnear. January 1997.` - -PIM ----- - -BFD ----- -- :rfc:`5880` - :t:`Bidirectional Forwarding Detection (BFD), D. Katz, D. Ward. June 2010` -- :rfc:`5881` - :t:`Bidirectional Forwarding Detection (BFD) for IPv4 and IPv6 (Single Hop), D. Katz, D. Ward. June 2010` -- :rfc:`5882` - :t:`Generic Application of Bidirectional Forwarding Detection (BFD), D. Katz, D. Ward. June 2010` -- :rfc:`5883` - :t:`Bidirectional Forwarding Detection (BFD) for Multihop Paths, D. Katz, D. Ward. June 2010` - -MPLS ----- - -- :rfc:`2858` - :t:`Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.` -- :rfc:`4364` - :t:`BGP/MPLS IP Virtual Private Networks (VPNs). Y. Rekhter. Feb 2006.` -- :rfc:`4447` - :t:`Pseudowire Setup and Maintenance Using the Label Distribution Protocol (LDP), L. Martini, E. Rosen, N. El-Aawar, T. Smith, and G. Heron. April 2006.` -- :rfc:`4659` - :t:`BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN. J. De Clercq, D. Ooms, M. Carugi, F. Le Faucheur. September 2006` -- :rfc:`4762` - :t:`Virtual Private LAN Service (VPLS) Using Label Distribution Protocol (LDP) Signaling, M. Lasserre and V. Kompella. January 2007.` -- :rfc:`5036` - :t:`LDP Specification, L. Andersson, I. Minei, and B. Thomas. October 2007.` -- :rfc:`5561` - :t:`LDP Capabilities, B. Thomas, K. Raza, S. Aggarwal, R. Aggarwal, and JL. Le Roux. July 2009.` -- :rfc:`5918` - :t:`Label Distribution Protocol (LDP) 'Typed Wildcard' Forward Equivalence Class (FEC), R. Asati, I. Minei, and B. Thomas. August 2010.` -- :rfc:`5919` - :t:`Signaling LDP Label Advertisement Completion, R. Asati, P. Mohapatra, E. Chen, and B. Thomas. August 2010.` -- :rfc:`6667` - :t:`LDP 'Typed Wildcard' Forwarding Equivalence Class (FEC) for PWid and Generalized PWid FEC Elements, K. Raza, S. Boutros, and C. Pignataro. July 2012.` -- :rfc:`6720` - :t:`The Generalized TTL Security Mechanism (GTSM) for the Label Distribution Protocol (LDP), C. Pignataro and R. Asati. August 2012.` -- :rfc:`7552` - :t:`Updates to LDP for IPv6, R. Asati, C. Pignataro, K. Raza, V. Manral, and R. Papneja. June 2015.` - -VRRP ----- - -- :rfc:`3768` - :t:`Virtual Router Redundancy Protocol (VRRP). R. Hinden. April 2004.` -- :rfc:`5798` - :t:`Virtual Router Redundancy Protocol (VRRP) Version 3 for IPv4 and IPv6. S. Nadas. June 2000.` - -SNMP ----- - -**When SNMP support is enabled, the following RFCs are also supported:** - -- :rfc:`1227` - :t:`SNMP MUX protocol and MIB. M.T. Rose. May-01-1991.` -- :rfc:`1657` - :t:`Definitions of Managed Objects for the Fourth Version of the Border - Gateway Protocol (BGP-4) using SMIv2. S. Willis, J. Burruss, J. Chu, Editor. - July 1994.` -- :rfc:`1724` - :t:`RIP Version 2 MIB Extension. G. Malkin & F. Baker. November 1994.` -- :rfc:`1850` - :t:`OSPF Version 2 Management Information Base. F. Baker, R. Coltun. - November 1995.` -- :rfc:`2741` - :t:`Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.` - - -.. index:: - pair: mailing lists; contact - -.. _mailing-lists: - -Mailing Lists -============= - -Italicized lists are private. - -+--------------------------------+------------------------------+ -| Topic | List | -+================================+==============================+ -| Development | dev@lists.frrouting.org | -+--------------------------------+------------------------------+ -| Users & Operators | frog@lists.frrouting.org | -+--------------------------------+------------------------------+ -| Announcements | announce@lists.frrouting.org | -+--------------------------------+------------------------------+ -| *Security* | security@lists.frrouting.org | -+--------------------------------+------------------------------+ -| *Technical Steering Committee* | tsc@lists.frrouting.org | -+--------------------------------+------------------------------+ - -The Development list is used to discuss and document general issues related to -project development and governance. The public `Slack`_ instance and weekly -technical meetings provide a higher bandwidth channel for discussions. The -results of such discussions are reflected in updates, as appropriate, to code -(i.e., merges), `GitHub issues`_ tracked issues, and for governance or process -changes, updates to the Development list and either this file or information -posted at `FRR`_. - - -Bug Reports -=========== - -For information on reporting bugs, please see :ref:`bug-reports`. - -.. _frr: https://frrouting.org -.. _github: https://github.com/frrouting/frr/ -.. _github issues: https://github.com/frrouting/frr/issues -.. _slack: https://frrouting.org/community diff --git a/doc/user/pim.rst b/doc/user/pim.rst index b19bb9d1..0fe53247 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -55,16 +55,48 @@ Certain signals have special meanings to *pimd*. *pimd* invocation options. Common options that can be specified (:ref:`common-invocation-options`). -.. clicmd:: ip pim rp A.B.C.D A.B.C.D/M +PIM Routers +----------- + +.. clicmd:: router pim [vrf NAME] + + Configure global PIM protocol + +.. clicmd:: rp A.B.C.D A.B.C.D/M In order to use pim, it is necessary to configure a RP for join messages to be sent to. Currently the only methodology to do this is via static rp commands. All routers in the pim network must agree on these values. The first ip address is the RP's address and the second value is the matching prefix of group ranges covered. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + 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] -.. clicmd:: ip pim rp keep-alive-timer (1-65535) + 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. The normal keepalive period for the KAT(S,G) defaults to 210 seconds. @@ -74,41 +106,76 @@ Certain signals have special meanings to *pimd*. max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is - vrf aware, to configure for a vrf, enter the vrf submode. + 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:: ip pim register-accept-list PLIST + +.. 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 to the prefix-list specified, PLIST, and if a permit is received normal processing continues. If a deny is returned for the source address of the register packet a register stop message is sent to the source. -.. clicmd:: ip pim spt-switchover infinity-and-beyond [prefix-list PLIST] +.. 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 configure this command. Optional parameter prefix-list can be use to control which groups to switch or not switch. If a group is PERMIT as per the PLIST, then the SPT switchover does not happen for it and if it is DENY, then the SPT switchover happens. - This command is vrf aware, to configure for a vrf, - enter the vrf submode. + This command is vrf aware, to configure for a vrf, specify the vrf in the + router pim block. -.. clicmd:: ip pim ecmp +.. clicmd:: ecmp If pim has the a choice of ECMP nexthops for a particular RPF, pim will cause S,G flows to be spread out amongst the nexthops. If this command is not specified then the first nexthop found will be used. This command is vrf - aware, to configure for a vrf, enter the vrf submode. + aware, to configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim ecmp rebalance +.. clicmd:: ecmp rebalance If pim is using ECMP and an interface goes down, cause pim to rebalance all S,G flows across the remaining nexthops. If this command is not configured pim only modifies those S,G flows that were using the interface that went - down. This command is vrf aware, to configure for a vrf, enter the vrf - submode. + down. This command is vrf aware, to configure for a vrf, specify the vrf in + the router pim block. -.. clicmd:: ip pim join-prune-interval (1-65535) +.. clicmd:: join-prune-interval (1-65535) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, @@ -116,39 +183,45 @@ Certain signals have special meanings to *pimd*. a value smaller than 60 seconds be aware that this can and will affect convergence at scale. -.. clicmd:: ip pim keep-alive-timer (1-65535) +.. clicmd:: keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim packets (1-255) +.. clicmd:: packets (1-255) When processing packets from a neighbor process the number of packets incoming at one time before moving on to the next task. The default value is 3 packets. This command is only useful at scale when you can possibly have a large number of pim control packets flowing. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim register-suppress-time (1-65535) +.. clicmd:: register-suppress-time (1-65535) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a - vrf, enter the vrf submode. + vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim send-v6-secondary +.. clicmd:: send-v6-secondary When sending pim hello packets tell pim to send any v6 secondary addresses on the interface. This information is used to allow pim to use v6 nexthops in it's decision for RPF lookup. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim ssm prefix-list WORD +.. clicmd:: ssm prefix-list WORD Specify a range of group addresses via a prefix-list that forces pim to - never do SM over. This command is vrf aware, to configure for a vrf, enter - the vrf submode. + never do SM over. This command is vrf aware, to configure for a vrf, specify + the vrf in the router pim block. + +Global Multicast +---------------- + +These commands are valid at the top-level of the configuration (or also per +vrf where indicated), instead of under the 'router pim' submode. .. clicmd:: ip multicast rpf-lookup-mode WORD @@ -242,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) @@ -333,12 +420,16 @@ MSDP can be setup in different ways: .. note:: - MSDP default peer and SA filtering is not implemented. + MSDP default peer is not implemented. +Commands available for MSDP +--------------------------- -Commands available for MSDP: +.. note:: + + MSDP configuration is available under 'router pim'. -.. clicmd:: ip msdp timers (1-65535) (1-65535) [(1-65535)] +.. clicmd:: msdp timers (1-65535) (1-65535) [(1-65535)] Configure global MSDP timers. @@ -354,19 +445,39 @@ Commands available for MSDP: configures the interval between connection attempts. The default value is 30 seconds. -.. clicmd:: ip msdp mesh-group WORD member A.B.C.D +.. clicmd:: msdp mesh-group WORD member A.B.C.D Create or update a mesh group to include the specified MSDP peer. -.. clicmd:: ip msdp mesh-group WORD source A.B.C.D +.. clicmd:: msdp mesh-group WORD source A.B.C.D Create or update a mesh group to set the source address used to connect to peers. -.. clicmd:: ip msdp peer A.B.C.D source A.B.C.D +.. clicmd:: msdp peer A.B.C.D source A.B.C.D Create a regular MSDP session with peer using the specified source address. +.. clicmd:: msdp peer A.B.C.D sa-filter ACL_NAME + + Configure incoming or outgoing SA filtering rule. + + .. note:: + + The filtering will only take effect starting from the command + application. + +.. clicmd:: msdp peer A.B.C.D password WORD + + Use MD5 authentication to connect with the remote peer. + + .. note:: + + The authentication will only take effect when starting a new + connection. + + To apply it immediately call `clear ip msdp peer A.B.C.D`. + .. _show-pim-information: @@ -385,15 +496,9 @@ cause great confusion. .. clicmd:: show ip igmp [vrf NAME] join [json] - Display IGMP static join information for a specific vrf. - -.. index:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] -.. clicmd:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] - - Display IGMP static join information for all the vrfs present. + Display IGMP static join information. -.. index:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] -.. clicmd:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] +.. clicmd:: show ip igmp [vrf NAME] groups [INTERFACE [GROUP]] [detail] [json] Display IGMP groups information. @@ -401,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. @@ -532,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 @@ -572,15 +686,32 @@ 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 +.. 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. -.. clicmd:: show ip pim bsm-database +.. clicmd:: show ip pim bsm-database [vrf NAME] [json] Display all fragments of stored bootstrap message in user readable format. @@ -660,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. @@ -696,6 +831,13 @@ Clear commands reset various variables. removes the next hop tracking for the bsr and resets the upstreams for the dynamically learnt RPs. +.. clicmd:: clear ip msdp peer A.B.C.D + + Reset MSDP peer connection. + + Use this command to set/unset MD5 authentication. + + PIM EVPN configuration ====================== To use PIM in the underlay for overlay BUM forwarding associate a multicast @@ -734,8 +876,9 @@ Sample configuration ! You may want to enable ssmpingd for troubleshooting ! See http://www.venaas.no/multicast/ssmping/ ! - ip ssmpingd 1.1.1.1 - ip ssmpingd 2.2.2.2 + router pim + ssmpingd 1.1.1.1 + ssmpingd 2.2.2.2 ! HINTS: ! - Enable "ip pim ssm" on the interface directly attached to the @@ -750,4 +893,3 @@ Sample configuration interface eth0 ip pim ssm ip igmp - diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst index b8567e48..e4e28d71 100644 --- a/doc/user/pimv6.rst +++ b/doc/user/pimv6.rst @@ -47,21 +47,28 @@ Certain signals have special meanings to *pim6d*. *pim6d* invocation options. Common options that can be specified (:ref:`common-invocation-options`). -.. clicmd:: ipv6 pim rp X:X::X:X Y:Y::Y:Y/M +PIMv6 Router +------------ + +.. clicmd:: router pim6 [vrf NAME] + + Configure the global PIMv6 protocol + +.. clicmd:: rp X:X::X:X Y:Y::Y:Y/M In order to use pimv6, it is necessary to configure a RP for join messages to be sent to. Currently the only methodology to do this is via static rp commands. All routers in the pimv6 network must agree on these values. The first ipv6 address is the RP's address and the second value is the matching prefix of group ranges covered. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim rp X:X::X:X prefix-list WORD +.. clicmd:: rp X:X::X:X prefix-list WORD This CLI helps in configuring RP address for a range of groups specified by the prefix-list. -.. clicmd:: ipv6 pim rp keep-alive-timer (1-65535) +.. clicmd:: rp keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds at RP. The normal keepalive period for the KAT(S,G) defaults to 210 seconds. @@ -71,19 +78,42 @@ Certain signals have special meanings to *pim6d*. max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is - vrf aware, to configure for a vrf, enter the vrf submode. + 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]] -.. clicmd:: ipv6 pim spt-switchover infinity-and-beyond [prefix-list PLIST] + 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 configure this command. Optional parameter prefix-list can be use to control which groups to switch or not switch. If a group is PERMIT as per the PLIST, then the SPT switchover does not happen for it and if it is DENY, then the SPT switchover happens. - This command is vrf aware, to configure for a vrf, - enter the vrf submode. + This command is vrf aware, to configure for a vrf, specify the vrf in the + router pim6 block. -.. clicmd:: ipv6 pim join-prune-interval (1-65535) +.. clicmd:: join-prune-interval (1-65535) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, @@ -91,28 +121,28 @@ Certain signals have special meanings to *pim6d*. a value smaller than 60 seconds be aware that this can and will affect convergence at scale. -.. clicmd:: ipv6 pim keep-alive-timer (1-65535) +.. clicmd:: keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim packets (1-255) +.. clicmd:: packets (1-255) When processing packets from a neighbor process the number of packets incoming at one time before moving on to the next task. The default value is 3 packets. This command is only useful at scale when you can possibly have a large number of pim control packets flowing. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim register-suppress-time (1-65535) +.. clicmd:: register-suppress-time (1-65535) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a - vrf, enter the vrf submode. + vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 ssmpingd [X:X::X:X] +.. clicmd:: ssmpingd [X:X::X:X] Enable ipv6 ssmpingd configuration. A network level management tool to check whether one can receive multicast packets via SSM from host. @@ -384,15 +414,32 @@ 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 +.. 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. -.. clicmd:: show ipv6 pim bsm-database +.. clicmd:: show ipv6 pim bsm-database [vrf NAME] [json] Display all fragments of stored bootstrap message in user readable format. @@ -417,7 +464,7 @@ Clear commands reset various variables. .. clicmd:: clear ipv6 pim [vrf NAME] interface traffic - When this command is issued, resets the information about the + When this command is issued, resets the information about the number of PIM protocol packets sent/received on an interface. .. clicmd:: clear ipv6 pim oil @@ -494,7 +541,7 @@ the config was written out. .. clicmd:: debug mld trace [detail] - This traces mld code and how it is running. + This traces mld code and how it is running. .. clicmd:: debug pimv6 bsm diff --git a/doc/user/protocols.rst b/doc/user/protocols.rst new file mode 100644 index 00000000..e571cd66 --- /dev/null +++ b/doc/user/protocols.rst @@ -0,0 +1,35 @@ +.. _protocols: + +######### +Protocols +######### + +.. toctree:: + :maxdepth: 2 + + zebra + bfd + bgp + babeld + fabricd + ldpd + eigrpd + evpn + isisd + nhrpd + ospfd + ospf6d + pathd + pim + pimv6 + pbr + ripd + ripngd + sharp + static + vnc + vrrp + bmp + watchfrr + mgmtd + diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 1d2f4e35..fbf7b863 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -320,7 +320,7 @@ Route Map Set Command Set the maximum meric for the route. -.. clicmd:: set aigp-metric +.. clicmd:: set aigp-metric Set the BGP attribute AIGP to a specific value. If ``igp-metric`` is specified, then the value is taken from the IGP protocol, otherwise an arbitrary value. diff --git a/doc/user/snmptrap.rst b/doc/user/snmptrap.rst index df534e28..52b19046 100644 --- a/doc/user/snmptrap.rst +++ b/doc/user/snmptrap.rst @@ -215,3 +215,9 @@ possibility to select the MIB he wants to receive traps from: By default, only rfc4273 traps are enabled and sent. .. [Draft-IETF-idr-bgp4-mibv2-11] + +The :rfc:`4382` also defines traps to inform when an L3VPN network changes +the operational status of its VRF interface. The user can choose to suppress +those traps or not. + +.. clicmd:: bgp snmp traps rfc4382 diff --git a/doc/user/subdir.am b/doc/user/subdir.am index 4879f7f7..395ce305 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -29,7 +29,7 @@ user_RSTFILES = \ doc/user/ospf6d.rst \ doc/user/ospfd.rst \ doc/user/ospf_fundamentals.rst \ - doc/user/overview.rst \ + doc/user/about.rst \ doc/user/packet-dumps.rst \ doc/user/pathd.rst \ doc/user/pim.rst \ diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 37644dc8..06a19a61 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 @@ -1021,6 +1031,35 @@ and this section also helps that case. ! ... +.. clicmd:: format NAME + + Specify the SID allocation schema for the SIDs allocated from this locator. Currently, + FRR supports supports the following allocation schemas: + + - `usid-f3216` + - `uncompressed` + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# locators + router(config-srv6-locators)# locator loc1 + router(config-srv6-locator)# prefix fc00:0:1::/48 + router(config-srv6-locator)# format usid-f3216 + + router(config-srv6-locator)# show run + ... + segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:1::/48 + format usid-f3216 + ! + ... + .. clicmd:: encapsulation Configure parameters for SRv6 encapsulation. @@ -1029,6 +1068,61 @@ and this section also helps that case. Configure the source address of the outer encapsulating IPv6 header. +.. clicmd:: formats + + Configure SRv6 SID formats. + +.. clicmd:: format NAME + + Configure SRv6 SID format. + +.. clicmd:: compressed usid + + Enable SRv6 uSID compression and configure SRv6 uSID compression parameters. + +.. clicmd:: local-id-block start START + + Configure the start value for the Local ID Block (LIB). + +.. clicmd:: local-id-block explicit start START end END + + Configure the start/end values for the Explicit LIB (ELIB). + +.. clicmd:: wide-local-id-block start START end END + + Configure the start/end values for the Wide LIB (W-LIB). + +.. clicmd:: wide-local-id-block explicit start START + + Configure the start value for the Explicit Wide LIB (EW-LIB). + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# formats + router(config-srv6-formats)# format usid-f3216 + router(config-srv6-format)# compressed usid + router(config-srv6-format-usid)# local-id-block start 0xD000 + router(config-srv6-format-usid)# local-id-block explicit start 0xF000 end 0xFDFF + router(config-srv6-format-usid)# wide-local-id-block start 0xFFF4 end 0xFFF5 + router(config-srv6-format-usid)# wide-local-id-block explicit start 0xFFF4 + + router(config-srv6-locator)# show run + ... + segment-routing + srv6 + formats + format usid-f3216 + compressed usid + local-id-block start 0xD000 + local-id-block explicit start 0xF000 end 0xFDFF + wide-local-id-block start 0xFFF4 end 0xFFF5 + wide-local-id-block explicit start 0xFFF4 + ! + ... + .. _multicast-rib-commands: Multicast RIB Commands @@ -1553,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 zebra route dump [ VRFNAME] diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 1cff06fe..3f811455 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # Create a basic stage set up to build APKs -FROM alpine:3.19 as alpine-builder +FROM alpine:3.20 as alpine-builder RUN apk add \ --update-cache \ abuild \ @@ -24,7 +24,7 @@ RUN cd /src/libyang \ && abuild -r -P /pkgs/apk # This stage builds a dist tarball from the source -FROM alpine:3.19 as source-builder +FROM alpine:3.20 as source-builder RUN mkdir -p /src/alpine /pkgs/apk COPY alpine/APKBUILD.in /src/alpine COPY --from=alpine-apk-builder-libyang /pkgs/apk/src /pkgs/apk @@ -57,7 +57,7 @@ RUN cd /dist \ && abuild -r -P /pkgs/apk # This stage installs frr from the apk -FROM alpine:3.19 +FROM alpine:3.20 RUN mkdir -p /pkgs/apk COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/ RUN apk add \ diff --git a/docker/alpine/libyang/APKBUILD b/docker/alpine/libyang/APKBUILD index 6973fd62..d8cd4d91 100755 --- a/docker/alpine/libyang/APKBUILD +++ b/docker/alpine/libyang/APKBUILD @@ -11,6 +11,7 @@ makedepends="bison cmake cmocka-dev flex pcre2-dev" checkdepends="expect grep shunit2" subpackages="$pkgname-dev $pkgname-doc" source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkgver.tar.gz" +options="!check" # secfixes: # 1.0.215-r1: @@ -21,6 +22,7 @@ source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkg # - CVE-2021-28906 build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" if [ "$CBUILD" != "$CHOST" ]; then CMAKE_CROSSOPTS="-DCMAKE_SYSTEM_NAME=Linux -DCMAKE_HOST_SYSTEM_NAME=Linux" fi diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index c04f8155..078280ac 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -293,7 +293,7 @@ const char *isis_adj_name(const struct isis_adjacency *adj) struct isis_dynhn *dyn; dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid); - if (dyn) + if (adj->circuit->area->dynhostname && dyn) return dyn->hostname; snprintfrr(buf, sizeof(buf), "%pSY", adj->sysid); @@ -358,12 +358,15 @@ void isis_adj_state_change(struct isis_adjacency **padj, * purposes */ adj->last_flap = time(NULL); adj->flaps++; - } else if (old_state == ISIS_ADJ_UP) { - circuit->adj_state_changes++; + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->adj_state_changes++; - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { listnode_delete( @@ -409,10 +412,13 @@ void isis_adj_state_change(struct isis_adjacency **padj, master, send_l2_csnp, circuit, 0, &circuit->t_send_csnp[1]); } - } else if (old_state == ISIS_ADJ_UP) { - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { if (adj->circuit->u.p2p.neighbor == adj) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 7819b20e..fa1ce300 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -198,8 +198,8 @@ void isis_circuit_del(struct isis_circuit *circuit) ldp_sync_info_free(&circuit->ldp_sync_info); circuit_mt_finish(circuit); - isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1); - isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2); + isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL1); + isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL2); list_delete(&circuit->ip_addrs); list_delete(&circuit->ipv6_link); diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index e6cc794b..93f7bbf7 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -2015,12 +2015,12 @@ void cli_show_isis_prefix_sid_algorithm(struct vty *vty, const char *sid_value_type; const char *sid_value; bool n_flag_clear; - uint32_t algorithm; + uint8_t algorithm; prefix = yang_dnode_get_string(dnode, "prefix"); sid_value_type = yang_dnode_get_string(dnode, "sid-value-type"); sid_value = yang_dnode_get_string(dnode, "sid-value"); - algorithm = yang_dnode_get_uint32(dnode, "algo"); + algorithm = yang_dnode_get_uint8(dnode, "algo"); lh_behavior = yang_dnode_get_string(dnode, "last-hop-behavior"); n_flag_clear = yang_dnode_get_bool(dnode, "n-flag-clear"); diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 32231a07..5574bbc5 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -83,6 +83,7 @@ static void circuit_commence_level(struct isis_circuit *circuit, int level) send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY); circuit->u.bc.lan_neighs[level - 1] = list_new(); + circuit->u.bc.adjdb[level - 1] = list_new(); } } @@ -108,6 +109,10 @@ static void circuit_resign_level(struct isis_circuit *circuit, int level) circuit->u.bc.is_dr[idx] = 0; if (circuit->u.bc.lan_neighs[idx] != NULL) list_delete(&circuit->u.bc.lan_neighs[idx]); + if (circuit->u.bc.adjdb[idx]) { + circuit->u.bc.adjdb[idx]->del = isis_delete_adj; + list_delete(&circuit->u.bc.adjdb[idx]); + } } return; diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index dc8f0b96..e0b3a4dc 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -238,10 +238,10 @@ void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level) * * @param nodes List of SPF nodes */ -void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level) +void isis_lfa_excluded_ifaces_delete(struct isis_circuit *circuit, int level) { - hash_clean(circuit->lfa_excluded_ifaces[level - 1], - lfa_excl_interface_hash_free); + hash_clean_and_free(&circuit->lfa_excluded_ifaces[level - 1], + lfa_excl_interface_hash_free); } /** @@ -1064,7 +1064,7 @@ static void lfa_calc_reach_nodes(struct isis_spftree *spftree, for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, vertex)) { char buf[VID2STR_BUFFER]; - if (!VTYPE_IS(vertex->type)) + if (vertex->type != VTYPE_NONPSEUDO_IS && vertex->type != VTYPE_NONPSEUDO_TE_IS) continue; /* Skip root node. */ diff --git a/isisd/isis_lfa.h b/isisd/isis_lfa.h index 0ba1c1ce..58ff115b 100644 --- a/isisd/isis_lfa.h +++ b/isisd/isis_lfa.h @@ -133,7 +133,7 @@ struct lfa_tiebreaker *isis_lfa_tiebreaker_add(struct isis_area *area, void isis_lfa_tiebreaker_delete(struct isis_area *area, int level, struct lfa_tiebreaker *tie_b); void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level); -void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level); +void isis_lfa_excluded_ifaces_delete(struct isis_circuit *circuit, int level); void isis_lfa_excluded_iface_add(struct isis_circuit *circuit, int level, const char *ifname); void isis_lfa_excluded_iface_delete(struct isis_circuit *circuit, int level, diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index c98cee06..d588af31 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -482,13 +482,19 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, lsp->tlvs = tlvs; - if (area->dynhostname && lsp->tlvs->hostname - && lsp->hdr.rem_lifetime) { - isis_dynhn_insert( - area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname, - (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2 - ? IS_LEVEL_2 - : IS_LEVEL_1); + if (area->dynhostname && lsp->hdr.rem_lifetime) { + if (lsp->tlvs->hostname) { + isis_dynhn_insert(area->isis, lsp->hdr.lsp_id, + lsp->tlvs->hostname, + (lsp->hdr.lsp_bits & LSPBIT_IST) == + IS_LEVEL_1_AND_2 + ? IS_LEVEL_2 + : IS_LEVEL_1); + } else { + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id) && + !LSP_FRAGMENT(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, lsp->hdr.lsp_id); + } } return; @@ -705,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) { @@ -722,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); @@ -745,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))); } @@ -1222,17 +1211,11 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } /* Add SRv6 Locator TLV. */ - if (area->srv6db.config.enabled && - !list_isempty(area->srv6db.srv6_locator_chunks)) { + if (area->srv6db.config.enabled && area->srv6db.srv6_locator) { struct isis_srv6_locator locator = {}; - struct srv6_locator_chunk *chunk; - - /* TODO: support more than one locator */ - chunk = (struct srv6_locator_chunk *)listgetdata( - listhead(area->srv6db.srv6_locator_chunks)); locator.metric = 0; - locator.prefix = chunk->prefix; + locator.prefix = area->srv6db.srv6_locator->prefix; locator.flags = 0; locator.algorithm = 0; @@ -1252,7 +1235,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) isis_tlvs_add_ipv6_reach(lsp->tlvs, isis_area_ipv6_topology(area), - &chunk->prefix, 0, false, NULL); + &area->srv6db.srv6_locator->prefix, 0, + false, NULL); } /* IPv4 address and TE router ID TLVs. @@ -2225,6 +2209,10 @@ void lsp_tick(struct event *thread) &area->lspdb[level], next); + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, + lsp->hdr.lsp_id); + lspdb_del(&area->lspdb[level], lsp); lsp_destroy(lsp); lsp = NULL; @@ -2335,6 +2323,56 @@ static int lsp_handle_adj_state_change(struct isis_adjacency *adj) return 0; } +/* + * Iterate over all SRv6 locator TLVs + */ +int isis_lsp_iterate_srv6_locator(struct isis_lsp *lsp, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg) +{ + bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id); + struct isis_lsp *frag; + struct listnode *node; + + if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0) + return LSP_ITER_CONTINUE; + + /* Parse LSP */ + if (lsp->tlvs) { + if (!pseudo_lsp) { + struct isis_item_list *srv6_locator_reachs; + struct isis_srv6_locator_tlv *r; + + srv6_locator_reachs = + isis_lookup_mt_items(&lsp->tlvs->srv6_locator, + mtid); + + for (r = srv6_locator_reachs + ? (struct isis_srv6_locator_tlv *) + srv6_locator_reachs->head + : NULL; + r; r = r->next) { + if ((*cb)((struct prefix *)&r->prefix, + r->metric, false /* ignore */, + r->subtlvs, arg) == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + } + } + + /* Parse LSP fragments if it is not a fragment itself */ + if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) { + if (!frag->tlvs) + continue; + + if (isis_lsp_iterate_srv6_locator(frag, mtid, cb, + arg) == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + + return LSP_ITER_CONTINUE; +} + /* * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given * address-family and MT-ID. diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 3839a950..15db88b0 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -143,6 +143,8 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid, lsp_ip_reach_iter_cb cb, void *arg); int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid, lsp_is_reach_iter_cb cb, void *arg); +int isis_lsp_iterate_srv6_locator(struct isis_lsp *lsp, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg); #define lsp_flood(lsp, circuit) \ _lsp_flood((lsp), (circuit), __func__, __FILE__, __LINE__) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 8dd3a97a..b7ed8f76 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -103,6 +103,12 @@ static __attribute__((__noreturn__)) void terminate(int i) isis_sr_term(); isis_srv6_term(); isis_zebra_stop(); + + isis_master_terminate(); + route_map_finish(); + vrf_terminate(); + + frr_fini(); exit(i); } diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index e4ef6c8d..833d5143 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -370,18 +370,20 @@ const char *print_sys_hostname(const uint8_t *sysid) struct isis_dynhn *dyn; struct isis *isis = NULL; struct listnode *node; + struct isis_area *area = NULL; if (!sysid) return "nullsysid"; /* For our system ID return our host name */ - isis = isis_lookup_by_sysid(sysid); - if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) + area = isis_area_lookup_by_sysid(sysid); + if (area && area->dynhostname && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) return cmd_hostname_get(); for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { + area = isis_area_lookup_by_sysid(isis->sysid); dyn = dynhn_find_by_id(isis, sysid); - if (dyn) + if (area && area->dynhostname && dyn) return dyn->hostname; } diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index d04a24dc..65ba395f 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_config.c b/isisd/isis_nb_config.c index 763b8b73..fb391534 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -252,11 +252,12 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) return NB_ERR_INCONSISTENCY; listnode_delete(area->area_addrs, addrp); - XFREE(MTYPE_ISIS_AREA_ADDR, addrp); /* * Last area address - reset the SystemID for this router */ - if (listcount(area->area_addrs) == 0) { + if (!memcmp(addrp->area_addr + addrp->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN) && + listcount(area->area_addrs) == 0) { for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (circuit->u.bc.is_dr[lvl - 1]) @@ -268,6 +269,8 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) zlog_debug("Router has no SystemID"); } + XFREE(MTYPE_ISIS_AREA_ADDR, addrp); + return NB_OK; } @@ -2630,14 +2633,14 @@ int isis_instance_segment_routing_algorithm_prefix_sid_create( struct isis_area *area; struct prefix prefix; struct sr_prefix_cfg *pcfg; - uint32_t algorithm; + uint8_t algorithm; if (args->event != NB_EV_APPLY) return NB_OK; area = nb_running_get_entry(args->dnode, NULL, true); yang_dnode_get_prefix(&prefix, args->dnode, "prefix"); - algorithm = yang_dnode_get_uint32(args->dnode, "algo"); + algorithm = yang_dnode_get_uint8(args->dnode, "algo"); pcfg = isis_sr_cfg_prefix_add(area, &prefix, algorithm); pcfg->algorithm = algorithm; @@ -2835,7 +2838,9 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) { struct isis_area *area; struct flex_algo *fa; - bool advertise; + bool advertise, update_te; + struct isis_circuit *circuit; + struct listnode *node; uint32_t algorithm; uint32_t priority = FLEX_ALGO_PRIO_DEFAULT; struct isis_flex_algo_alloc_arg arg; @@ -2848,6 +2853,7 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) area = nb_running_get_entry(args->dnode, NULL, true); arg.algorithm = algorithm; arg.area = area; + update_te = list_isempty(area->flex_algos->flex_algos); fa = flex_algo_alloc(area->flex_algos, algorithm, &arg); fa->priority = priority; fa->advertise_definition = advertise; @@ -2859,6 +2865,12 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) admin_group_allow_explicit_zero( &fa->admin_group_include_all); } + if (update_te) { + 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: @@ -2872,22 +2884,28 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args) { + struct isis_circuit *circuit; + struct listnode *node, *nnode; + struct flex_algo *fa; 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: - flex_algo_delete(area->flex_algos, algorithm); - 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; } @@ -2935,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; } @@ -2962,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; @@ -2992,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; @@ -3013,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; } @@ -3032,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, @@ -3055,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, @@ -3144,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, @@ -3179,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, @@ -3214,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, @@ -3256,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, @@ -3338,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, @@ -3378,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, @@ -3414,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, @@ -3518,10 +3515,10 @@ int isis_instance_segment_routing_srv6_locator_modify( sr_debug("Configured SRv6 locator %s for IS-IS area %s", loc_name, area->area_tag); - sr_debug("Trying to get a chunk from locator %s for IS-IS area %s", - loc_name, area->area_tag); + sr_debug("Trying to get locator %s for IS-IS area %s", loc_name, + area->area_tag); - if (isis_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) + if (isis_zebra_srv6_manager_get_locator(loc_name) < 0) return NB_ERR; return NB_OK; @@ -4300,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 b7c33ed2..da61bcce 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_snmp.c b/isisd/isis_snmp.c index f9e3780e..83a06b69 100644 --- a/isisd/isis_snmp.c +++ b/isisd/isis_snmp.c @@ -2826,6 +2826,13 @@ static int isis_snmp_init(struct event_loop *tm) return 0; } +static int isis_snmp_terminate(void) +{ + smux_terminate(); + + return 0; +} + /* * ISIS notification functions: we have one function per notification */ @@ -3448,6 +3455,7 @@ static int isis_snmp_module_init(void) hook_register(isis_circuit_del_hook, isis_circuit_snmp_id_free); hook_register(frr_late_init, isis_snmp_init); + hook_register(frr_fini, isis_snmp_terminate); return 0; } diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 1197f8c3..8fc0f144 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)) { @@ -2230,21 +2229,35 @@ int _isis_spf_schedule(struct isis_area *area, int level, } static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, - uint8_t *root_sysid) + uint8_t *root_sysid, struct json_object **json) { struct listnode *node; struct isis_vertex *vertex; char buff[VID2STR_BUFFER]; + char vertex_name[VID2STR_BUFFER]; + char vertex_typestr[VID2STR_BUFFER]; + char vertex_interface[VID2STR_BUFFER]; + char vertex_parent[VID2STR_BUFFER + 11]; + char vertex_nexthop[VID2STR_BUFFER]; + char vertex_metricstr[20]; + struct ttable *tt; + char *table; - vty_out(vty, - "Vertex Type Metric Next-Hop Interface Parent\n"); + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Vertex|Type|Metric|Next-Hop|Interface|Parent"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) { if (VTYPE_IS(vertex->type) && memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { - vty_out(vty, "%-20s %-12s %-6s", - print_sys_hostname(root_sysid), "", ""); - vty_out(vty, "%-30s\n", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + print_sys_hostname(root_sysid), "", "", + "", "", ""); continue; } @@ -2254,9 +2267,12 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, struct isis_vertex_adj *vadj; struct isis_vertex *pvertex; - vty_out(vty, "%-20s %-12s %-6u ", - vid2string(vertex, buff, sizeof(buff)), - vtype2string(vertex->type), vertex->d_N); + snprintf(vertex_name, sizeof(vertex_name), "%s", + vid2string(vertex, buff, sizeof(buff))); + snprintf(vertex_typestr, sizeof(vertex_typestr), "%s", + vtype2string(vertex->type)); + snprintf(vertex_metricstr, sizeof(vertex_metricstr), "%u", + vertex->d_N); for (unsigned int i = 0; i < MAX(vertex->Adj_N ? listcount(vertex->Adj_N) : 0, vertex->parents ? listcount(vertex->parents) : 0); @@ -2276,36 +2292,60 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, } if (rows) { - vty_out(vty, "\n"); - vty_out(vty, "%-20s %-12s %-6s ", "", "", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + vertex_name, vertex_typestr, + vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); + + /* store the first 3 elements */ + vertex_name[0] = '\0'; + vertex_typestr[0] = '\0'; + vertex_metricstr[0] = '\0'; } if (vadj) { struct isis_spf_adj *sadj = vadj->sadj; - vty_out(vty, "%-20s %-9s ", - print_sys_hostname(sadj->id), - sadj->adj ? sadj->adj->circuit - ->interface->name - : "-"); + snprintf(vertex_nexthop, sizeof(vertex_nexthop), + "%s", print_sys_hostname(sadj->id)); + snprintf(vertex_interface, + sizeof(vertex_interface), "%s", + sadj->adj ? sadj->adj->circuit + ->interface->name + : "-"); } if (pvertex) { - if (!vadj) - vty_out(vty, "%-20s %-9s ", "", ""); - - vty_out(vty, "%s(%d)", - vid2string(pvertex, buff, sizeof(buff)), - pvertex->type); + if (!vadj) { + vertex_nexthop[0] = '\0'; + vertex_interface[0] = '\0'; + } + snprintf(vertex_parent, sizeof(vertex_parent), + "%s(%d)", + vid2string(pvertex, buff, sizeof(buff)), + pvertex->type); } ++rows; } - vty_out(vty, "\n"); + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", vertex_name, + vertex_typestr, vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); } + if (json == NULL) { + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP_TTABLE, table); + } else + *json = ttable_json_with_json_text( + tt, "ssdsss", + "vertex|type|metric|nextHop|interface|parent"); + ttable_del(tt); } -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json) { const char *tree_id_text = NULL; @@ -2327,14 +2367,18 @@ void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) return; } - vty_out(vty, "IS-IS paths to level-%d routers %s\n", spftree->level, - tree_id_text); - isis_print_paths(vty, &spftree->paths, spftree->sysid); - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "IS-IS paths to level-%d routers %s\n", + spftree->level, tree_id_text); + + isis_print_paths(vty, &spftree->paths, spftree->sysid, json); + if (!json) + vty_out(vty, "\n"); } static void show_isis_topology_common(struct vty *vty, int levels, - struct isis *isis, uint8_t algo) + struct isis *isis, uint8_t algo, + json_object **json) { #ifndef FABRICD struct isis_flex_algo_data *fa_data; @@ -2343,10 +2387,15 @@ static void show_isis_topology_common(struct vty *vty, int levels, struct isis_spftree *spftree; struct listnode *node; struct isis_area *area; + json_object *json_level = NULL, *jstr = NULL, *json_val; + char key[18]; if (!isis->area_list || isis->area_list->count == 0) return; + if (json) + *json = json_object_new_object(); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { #ifndef FABRICD /* @@ -2364,21 +2413,37 @@ static void show_isis_topology_common(struct vty *vty, int levels, fa_data = NULL; #endif /* ifndef FABRICD */ - vty_out(vty, - "Area %s:", area->area_tag ? area->area_tag : "null"); + if (json) { + jstr = json_object_new_string( + area->area_tag ? area->area_tag : "null"); + json_object_object_add(*json, "area", jstr); + json_object_int_add(*json, "algorithm", algo); + } else { + vty_out(vty, "Area %s:", + area->area_tag ? area->area_tag : "null"); #ifndef FABRICD - if (algo != SR_ALGORITHM_SPF) - vty_out(vty, " Algorithm %hhu\n", algo); - else + if (algo != SR_ALGORITHM_SPF) + vty_out(vty, " Algorithm %hhu\n", algo); + else #endif /* ifndef FABRICD */ - vty_out(vty, "\n"); + vty_out(vty, "\n"); + } for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { if ((level & levels) == 0) continue; + if (json) { + json_level = json_object_new_object(); + jstr = json_object_new_string( + area->area_tag ? area->area_tag + : "null"); + json_object_object_add(json_level, "area", jstr); + } + if (area->ip_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV4] @@ -2388,9 +2453,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + } } if (area->ipv6_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV6] @@ -2399,9 +2471,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + } } if (isis_area_ipv6_dstsrc_enabled(area)) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = @@ -2411,18 +2490,36 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + } + } + if (json) { + snprintf(key, sizeof(key), "level-%d", level); + json_object_object_add(*json, key, json_level); } } if (fabricd_spftree(area)) { + json_val = NULL; + vty_out(vty, "IS-IS paths to level-2 routers with hop-by-hop metric\n"); - isis_print_paths(vty, &fabricd_spftree(area)->paths, isis->sysid); - vty_out(vty, "\n"); + isis_print_paths(vty, &fabricd_spftree(area)->paths, + isis->sysid, json ? &json_val : NULL); + if (json && json_val) + json_object_object_add(json_level, + "fabricd-paths", + json_val); + else + vty_out(vty, "\n"); } - - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "\n"); } } @@ -2433,6 +2530,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, " []" " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ + " [json$uj]" , SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" @@ -2443,6 +2541,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, "Show Flex-algo routes\n" "Algorithm number\n" #endif /* ifndef FABRICD */ + JSON_STR ) { int levels = ISIS_LEVELS; @@ -2453,6 +2552,8 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, bool all_algorithm = false; int idx_vrf = 0; uint16_t algorithm = SR_ALGORITHM_SPF; + bool uj = use_json(argc, argv); + json_object *json = NULL, *json_vrf = NULL; #ifndef FABRICD int idx = 0; @@ -2476,21 +2577,33 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, } ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_array(); + if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { if (all_algorithm) { for (algorithm = SR_ALGORITHM_FLEX_MIN; algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) - show_isis_topology_common( - vty, levels, isis, - (uint8_t)algorithm); + show_isis_topology_common(vty, levels, + isis, + (uint8_t)algorithm, + uj ? &json_vrf + : NULL); } else { show_isis_topology_common(vty, levels, isis, - (uint8_t)algorithm); + (uint8_t)algorithm, + uj ? &json_vrf : NULL); + } + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int( + isis->vrf_id)); + json_object_array_add(json, json_vrf); } } - return CMD_SUCCESS; + goto out; } isis = isis_lookup_by_vrfname(vrf_name); if (isis == NULL) @@ -2499,10 +2612,24 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, for (algorithm = SR_ALGORITHM_FLEX_MIN; algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) { show_isis_topology_common(vty, levels, isis, - (uint8_t)algorithm); + (uint8_t)algorithm, + uj ? &json_vrf : NULL); } } else - show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm); + show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm, + uj ? &json_vrf : NULL); + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int(isis->vrf_id)); + json_object_array_add(json, json_vrf); + } +out: + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } @@ -2888,9 +3015,13 @@ 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(tt, prefix_sid ? "sdssdsdd" : "sdsss"); + *json = ttable_json_with_json_text( + tt, prefix_sid ? "sdssdsdd" : "sdsss", + prefix_sid + ? "prefix|metric|interface|nextHop|segmentIdentifier|labelOperation|Algorithm" + : "prefix|metric|interface|nextHop|label(s)"); } ttable_del(tt); } @@ -2974,8 +3105,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -2996,8 +3133,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -3019,8 +3162,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, prefix_sid, backup); @@ -3077,7 +3226,7 @@ DEFUN(show_isis_route, show_isis_route_cmd, #ifndef FABRICD " []" #endif /* ifndef FABRICD */ - " []" + " [prefix-sid] [backup]" #ifndef FABRICD " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ @@ -3308,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_spf.h b/isisd/isis_spf.h index 7e9754d9..ee2d29ab 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -61,7 +61,8 @@ struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb, __FILE__, __LINE__) int _isis_spf_schedule(struct isis_area *area, int level, const char *func, const char *file, int line); -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree); +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json); void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, json_object **json, bool prefix_sid, bool backup); void isis_spf_init(void); diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index f7830380..95ea36c3 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 44fd599c..2348bd04 100644 --- a/isisd/isis_srv6.c +++ b/isisd/isis_srv6.c @@ -102,6 +102,7 @@ bool isis_srv6_locator_unset(struct isis_area *area) struct srv6_locator_chunk *chunk; struct isis_srv6_sid *sid; struct srv6_adjacency *sra; + struct srv6_sid_ctx ctx = {}; if (strncmp(area->srv6db.config.srv6_locator_name, "", sizeof(area->srv6db.config.srv6_locator_name)) == 0) { @@ -120,13 +121,31 @@ bool isis_srv6_locator_unset(struct isis_area *area) * Zebra */ isis_zebra_srv6_sid_uninstall(area, sid); + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + isis_zebra_release_srv6_sid(&ctx); + listnode_delete(area->srv6db.srv6_sids, sid); isis_srv6_sid_free(sid); } /* Uninstall all local Adjacency-SIDs. */ - for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) { + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = sra->nexthop; + isis_zebra_release_srv6_sid(&ctx); + srv6_endx_sid_del(sra); + } /* Inform Zebra that we are releasing the SRv6 locator */ ret = isis_zebra_srv6_manager_release_locator_chunk( @@ -146,6 +165,10 @@ bool isis_srv6_locator_unset(struct isis_area *area) srv6_locator_chunk_free(&chunk); } + /* Clear locator */ + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Clear locator name */ memset(area->srv6db.config.srv6_locator_name, 0, sizeof(area->srv6db.config.srv6_locator_name)); @@ -197,150 +220,36 @@ void isis_srv6_interface_set(struct isis_area *area, const char *ifname) } } -/** - * Encode SID function in the SRv6 SID. - * - * @param sid - * @param func - * @param offset - * @param len - */ -static void encode_sid_func(struct in6_addr *sid, uint32_t func, uint8_t offset, - uint8_t len) -{ - for (uint8_t idx = 0; idx < len; idx++) { - uint8_t tidx = offset + idx; - sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); - if (func >> (len - 1 - idx) & 0x1) - sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); - } -} - -static bool sid_exist(struct isis_area *area, const struct in6_addr *sid) -{ - struct listnode *node; - struct isis_srv6_sid *s; - struct srv6_adjacency *sra; - - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node, s)) - if (sid_same(&s->sid, sid)) - return true; - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_endx_sids, node, sra)) - if (sid_same(&sra->sid, sid)) - return true; - return false; -} - -/** - * Request a SID from the SRv6 locator. - * - * @param area IS-IS area - * @param chunk SRv6 locator chunk - * @param sid_func The FUNCTION part of the SID to be allocated (a negative - * number will allocate the first available SID) - * - * @return First available SID on success or in6addr_any if the SRv6 - * locator chunk is full - */ -static struct in6_addr -srv6_locator_request_sid(struct isis_area *area, - struct srv6_locator_chunk *chunk, int sid_func) -{ - struct in6_addr sid; - uint8_t offset = 0; - uint8_t func_len = 0; - uint32_t func_max; - bool allocated = false; - - if (!area || !chunk) - return in6addr_any; - - sr_debug("ISIS-SRv6 (%s): requested new SID from locator %s", - area->area_tag, chunk->locator_name); - - /* Let's build the SID, step by step. A SID has the following structure - (defined in RFC 8986): LOCATOR:FUNCTION:ARGUMENT.*/ - - /* First, we encode the LOCATOR in the L most significant bits. */ - sid = chunk->prefix.prefix; - - /* The next part of the SID is the FUNCTION. Let's compute the length - * and the offset of the FUNCTION in the SID */ - func_len = chunk->function_bits_length; - offset = chunk->block_bits_length + chunk->node_bits_length; - - /* Then, encode the FUNCTION */ - if (sid_func >= 0) { - /* SID FUNCTION has been specified. We need to allocate a SID - * with the requested FUNCTION. */ - encode_sid_func(&sid, sid_func, offset, func_len); - if (sid_exist(area, &sid)) { - zlog_warn( - "ISIS-SRv6 (%s): the requested SID %pI6 is already used", - area->area_tag, &sid); - return sid; - } - allocated = true; - } else { - /* SID FUNCTION not specified. We need to choose a FUNCTION that - * is not already used. So let's iterate through all possible - * functions and get the first available one. */ - func_max = (1 << func_len) - 1; - for (uint32_t func = 1; func < func_max; func++) { - encode_sid_func(&sid, func, offset, func_len); - if (sid_exist(area, &sid)) - continue; - allocated = true; - break; - } - } - - if (!allocated) { - /* We ran out of available SIDs */ - zlog_warn("ISIS-SRv6 (%s): no SIDs available in locator %s", - area->area_tag, chunk->locator_name); - return in6addr_any; - } - - sr_debug("ISIS-SRv6 (%s): allocating new SID %pI6", area->area_tag, - &sid); - - return sid; -} - /** * Allocate an SRv6 SID from an SRv6 locator. * * @param area IS-IS area - * @param chunk SRv6 locator chunk + * @param locator SRv6 locator * @param behavior SRv6 Endpoint Behavior bound to the SID + * @param sid_value SRv6 SID value * * @result the allocated SID on success, NULL otherwise */ struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, - int sid_func) + struct in6_addr *sid_value) { struct isis_srv6_sid *sid = NULL; - if (!area || !chunk) + if (!area || !locator || !sid_value) return NULL; sid = XCALLOC(MTYPE_ISIS_SRV6_SID, sizeof(struct isis_srv6_sid)); - sid->sid = srv6_locator_request_sid(area, chunk, sid_func); - if (IPV6_ADDR_SAME(&sid->sid, &in6addr_any)) { - isis_srv6_sid_free(sid); - return NULL; - } + sid->sid = *sid_value; sid->behavior = behavior; - sid->structure.loc_block_len = chunk->block_bits_length; - sid->structure.loc_node_len = chunk->node_bits_length; - sid->structure.func_len = chunk->function_bits_length; - sid->structure.arg_len = chunk->argument_bits_length; - sid->locator = chunk; + sid->structure.loc_block_len = locator->block_bits_length; + sid->structure.loc_node_len = locator->node_bits_length; + sid->structure.func_len = locator->function_bits_length; + sid->structure.arg_len = locator->argument_bits_length; + sid->locator = locator; sid->area = area; return sid; @@ -376,9 +285,10 @@ void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level) * @param adj IS-IS Adjacency * @param backup True to initialize backup Adjacency SID * @param nexthops List of backup nexthops (for backup End.X SIDs only) + * @param sid_value SID value associated to be associated with the adjacency */ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, - struct list *nexthops) + struct list *nexthops, struct in6_addr *sid_value) { struct isis_circuit *circuit = adj->circuit; struct isis_area *area = circuit->area; @@ -387,11 +297,10 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, struct isis_srv6_lan_endx_sid_subtlv *ladj_sid; struct in6_addr nexthop; uint8_t flags = 0; - struct srv6_locator_chunk *chunk; + struct srv6_locator *locator; uint32_t behavior; - if (!area || !area->srv6db.srv6_locator_chunks || - list_isempty(area->srv6db.srv6_locator_chunks)) + if (!area || !area->srv6db.srv6_locator) return; sr_debug("ISIS-SRv6 (%s): Add %s End.X SID", area->area_tag, @@ -401,10 +310,7 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (!circuit->ipv6_router || !adj->ll_ipv6_count) return; - chunk = (struct srv6_locator_chunk *)listgetdata( - listhead(area->srv6db.srv6_locator_chunks)); - if (!chunk) - return; + locator = area->srv6db.srv6_locator; nexthop = adj->ll_ipv6_addrs[0]; @@ -415,25 +321,21 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (circuit->ext == NULL) circuit->ext = isis_alloc_ext_subtlvs(); - behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) + behavior = (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) ? SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID : SRV6_ENDPOINT_BEHAVIOR_END_X; sra = XCALLOC(MTYPE_ISIS_SRV6_INFO, sizeof(*sra)); sra->type = backup ? ISIS_SRV6_ADJ_BACKUP : ISIS_SRV6_ADJ_NORMAL; sra->behavior = behavior; - sra->locator = chunk; - sra->structure.loc_block_len = chunk->block_bits_length; - sra->structure.loc_node_len = chunk->node_bits_length; - sra->structure.func_len = chunk->function_bits_length; - sra->structure.arg_len = chunk->argument_bits_length; + sra->locator = locator; + sra->structure.loc_block_len = locator->block_bits_length; + sra->structure.loc_node_len = locator->node_bits_length; + sra->structure.func_len = locator->function_bits_length; + sra->structure.arg_len = locator->argument_bits_length; sra->nexthop = nexthop; - sra->sid = srv6_locator_request_sid(area, chunk, -1); - if (IPV6_ADDR_SAME(&sra->sid, &in6addr_any)) { - XFREE(MTYPE_ISIS_SRV6_INFO, sra); - return; - } + sra->sid = *sid_value; switch (circuit->circ_type) { /* SRv6 LAN End.X SID for Broadcast interface section #8.2 */ @@ -505,9 +407,9 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, * * @param adj IS-IS Adjacency */ -void srv6_endx_sid_add(struct isis_adjacency *adj) +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value) { - srv6_endx_sid_add_single(adj, false, NULL); + srv6_endx_sid_add_single(adj, false, NULL, sid_value); } /** @@ -610,7 +512,7 @@ static int srv6_adj_ip_enabled(struct isis_adjacency *adj, int family, family != AF_INET6) return 0; - srv6_endx_sid_add(adj); + isis_zebra_request_srv6_sid_endx(adj); return 0; } @@ -689,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); } @@ -832,6 +734,9 @@ void isis_srv6_area_term(struct isis_area *area) srv6_locator_chunk_free(&chunk); list_delete(&srv6db->srv6_locator_chunks); + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Free SRv6 SIDs list */ list_delete(&srv6db->srv6_sids); list_delete(&srv6db->srv6_endx_sids); diff --git a/isisd/isis_srv6.h b/isisd/isis_srv6.h index 7f16712a..bde14965 100644 --- a/isisd/isis_srv6.h +++ b/isisd/isis_srv6.h @@ -44,7 +44,7 @@ struct isis_srv6_sid { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Backpointer to IS-IS area */ struct isis_area *area; @@ -89,7 +89,7 @@ struct srv6_adjacency { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Adjacency-SID nexthop information */ struct in6_addr nexthop; @@ -109,6 +109,8 @@ struct srv6_adjacency { /* Per-area IS-IS SRv6 Data Base (SRv6 DB) */ struct isis_srv6_db { + /* List of SRv6 Locator */ + struct srv6_locator *srv6_locator; /* List of SRv6 Locator chunks */ struct list *srv6_locator_chunks; @@ -149,9 +151,9 @@ bool isis_srv6_locator_unset(struct isis_area *area); void isis_srv6_interface_set(struct isis_area *area, const char *ifname); struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, - int sid_func); + struct in6_addr *sid_value); extern void isis_srv6_sid_free(struct isis_srv6_sid *sid); extern void isis_srv6_area_init(struct isis_area *area); @@ -169,8 +171,8 @@ void isis_srv6_locator2tlv(const struct isis_srv6_locator *loc, struct isis_srv6_locator_tlv *loc_tlv); void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, - struct list *nexthops); -void srv6_endx_sid_add(struct isis_adjacency *adj); + struct list *nexthops, struct in6_addr *sid_value); +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value); void srv6_endx_sid_del(struct srv6_adjacency *sra); struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj, enum srv6_adj_type type); diff --git a/isisd/isis_te.c b/isisd/isis_te.c index d8541236..c9af39ce 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -164,8 +164,8 @@ void isis_mpls_te_term(struct isis_area *area) XFREE(MTYPE_ISIS_MPLS_TE, area->mta); } -static void isis_link_params_update_asla(struct isis_circuit *circuit, - struct interface *ifp) +void isis_link_params_update_asla(struct isis_circuit *circuit, + struct interface *ifp) { struct isis_asla_subtlvs *asla; struct listnode *node, *nnode; @@ -1262,8 +1262,11 @@ static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric, if (!args || !prefix) return LSP_ITER_CONTINUE; - te_debug(" |- Process Extended %s Reachability %pFX", - prefix->family == AF_INET ? "IP" : "IPv6", prefix); + if (args->srv6_locator) + te_debug(" |- Process SRv6 Locator %pFX", prefix); + else + te_debug(" |- Process Extended %s Reachability %pFX", + prefix->family == AF_INET ? "IP" : "IPv6", prefix); vertex = args->vertex; @@ -1390,6 +1393,38 @@ static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric, } } + /* Update SRv6 SID and locator if any */ + if (subtlvs && subtlvs->srv6_end_sids.count != 0) { + struct isis_srv6_end_sid_subtlv *psid; + struct ls_srv6_sid sr = {}; + + psid = (struct isis_srv6_end_sid_subtlv *) + subtlvs->srv6_end_sids.head; + sr.behavior = psid->behavior; + sr.flags = psid->flags; + memcpy(&sr.sid, &psid->sid, sizeof(struct in6_addr)); + + if (!CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6) || + memcmp(&ls_pref->srv6, &sr, sizeof(struct ls_srv6_sid))) { + memcpy(&ls_pref->srv6, &sr, sizeof(struct ls_srv6_sid)); + SET_FLAG(ls_pref->flags, LS_PREF_SRV6); + if (subnet->status != NEW) + subnet->status = UPDATE; + } else { + if (subnet->status == ORPHAN) + subnet->status = SYNC; + } + } else { + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + UNSET_FLAG(ls_pref->flags, LS_PREF_SRV6); + if (subnet->status != NEW) + subnet->status = UPDATE; + } else { + if (subnet->status == ORPHAN) + subnet->status = SYNC; + } + } + /* Update status and Export Link State Edge if needed */ if (subnet->status != SYNC) { if (args->export) @@ -1458,12 +1493,18 @@ static void isis_te_parse_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp) &args); /* Process all Extended IP (v4 & v6) in LSP (all fragments) */ + args.srv6_locator = false; isis_lsp_iterate_ip_reach(lsp, AF_INET, ISIS_MT_IPV4_UNICAST, lsp_to_subnet_cb, &args); isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV6_UNICAST, lsp_to_subnet_cb, &args); isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV4_UNICAST, lsp_to_subnet_cb, &args); + args.srv6_locator = true; + isis_lsp_iterate_srv6_locator(lsp, ISIS_MT_STANDARD, lsp_to_subnet_cb, + &args); + isis_lsp_iterate_srv6_locator(lsp, ISIS_MT_IPV6_UNICAST, + lsp_to_subnet_cb, &args); /* Clean remaining Orphan Edges or Subnets */ if (IS_EXPORT_TE(mta)) diff --git a/isisd/isis_te.h b/isisd/isis_te.h index bf1dc2b9..697f03b6 100644 --- a/isisd/isis_te.h +++ b/isisd/isis_te.h @@ -103,6 +103,7 @@ struct isis_te_args { struct ls_ted *ted; struct ls_vertex *vertex; bool export; + bool srv6_locator; }; enum lsp_event { LSP_UNKNOWN, LSP_ADD, LSP_UPD, LSP_DEL, LSP_INC, LSP_TICK }; @@ -112,6 +113,8 @@ void isis_mpls_te_init(void); void isis_mpls_te_create(struct isis_area *area); void isis_mpls_te_disable(struct isis_area *area); void isis_mpls_te_term(struct isis_area *area); +void isis_link_params_update_asla(struct isis_circuit *circuit, + struct interface *ifp); void isis_link_params_update(struct isis_circuit *, struct interface *); int isis_mpls_te_update(struct interface *); void isis_te_lsp_event(struct isis_lsp *lsp, enum lsp_event event); diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 4db97289..b5caf396 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); @@ -990,12 +862,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { 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); @@ -1010,56 +876,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_adj_sid *adj; if (json) { - struct json_object *arr_adj_json, *flags_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); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", - adj->sid); - json_object_int_add(flags_json, "weight", - adj->weight); - json_object_string_add( - flags_json, "flag-f", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); - } - /* end old deprecated key format */ + struct json_object *arr_adj_json, *adj_sid_json; arr_adj_json = json_object_new_array(); json_object_object_add(json, "adjSid", arr_adj_json); @@ -1067,35 +884,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", adj->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", adj->sid); - json_object_int_add(flags_json, "weight", + 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_boolean_add(flags_json, "flagF", + json_object_boolean_add(adj_sid_json, "flagF", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? true : false); - json_object_boolean_add(flags_json, "flagB", + json_object_boolean_add(adj_sid_json, "flagB", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? true : false); - json_object_boolean_add(flags_json, "flagV", + json_object_boolean_add(adj_sid_json, "flagV", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? true : false); - json_object_boolean_add(flags_json, "flagL", + json_object_boolean_add(adj_sid_json, "flagL", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? true : false); - json_object_boolean_add(flags_json, "flagS", + json_object_boolean_add(adj_sid_json, "flagS", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? true : false); - json_object_boolean_add(flags_json, "flagP", + json_object_boolean_add(adj_sid_json, "flagP", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG ? true : false); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + adj_sid_json); } } else for (adj = (struct isis_adj_sid *)exts->adj_sid.head; @@ -1128,63 +947,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { struct isis_lan_adj_sid *lan; if (json) { - struct json_object *arr_adj_json, *flags_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); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", - lan->sid); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add( - flags_json, "flag-f", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); - } - /* end old deprecated key format */ + struct json_object *arr_adj_json, *lan_adj_json; arr_adj_json = json_object_new_array(); json_object_object_add(json, "lanAdjSid", arr_adj_json); @@ -1197,35 +960,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, continue; snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", lan->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", lan->sid); - json_object_int_add(flags_json, "weight", + 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_boolean_add(flags_json, "flagF", + json_object_boolean_add(lan_adj_json, "flagF", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? true : false); - json_object_boolean_add(flags_json, "flagB", + json_object_boolean_add(lan_adj_json, "flagB", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? true : false); - json_object_boolean_add(flags_json, "flagV", + json_object_boolean_add(lan_adj_json, "flagV", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? true : false); - json_object_boolean_add(flags_json, "flagL", + json_object_boolean_add(lan_adj_json, "flagL", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? true : false); - json_object_boolean_add(flags_json, "flagS", + json_object_boolean_add(lan_adj_json, "flagS", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? true : false); - json_object_boolean_add(flags_json, "flagP", + json_object_boolean_add(lan_adj_json, "flagP", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG ? true : false); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + lan_adj_json); } } else @@ -1268,90 +1033,48 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_srv6_endx_sid_subtlv *adj; if (json) { - struct json_object *arr_adj_json, *flags_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", + json_object_object_add(json, "srv6EndXSID", 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); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &adj->sid); - json_object_string_add( - flags_json, "algorithm", - sr_algorithm_string(adj->algorithm)); - json_object_int_add(flags_json, "weight", - adj->weight); - json_object_string_add( - flags_json, "behavior", - seg6local_action2str(adj->behavior)); - json_object_string_add( - flags_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); - if (adj->subsubtlvs) - isis_format_subsubtlvs(adj->subsubtlvs, - NULL, - arr_adj_json, - indent + 4); - } - /* end old deprecated key format */ - - arr_adj_json = json_object_new_array(); - json_object_object_add(json, "srv6EndSID", 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); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &adj->sid); - json_object_string_add(flags_json, "algorithm", + 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(flags_json, "weight", - adj->weight); - json_object_string_add(flags_json, "behavior", + 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_boolean_add( - flags_json, "flagB", + srv6_endx_sid_json, "flagB", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); json_object_boolean_add( - flags_json, "flagS", + srv6_endx_sid_json, "flagS", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); json_object_boolean_add( - flags_json, "flagP", + srv6_endx_sid_json, "flagP", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_endx_sid_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, NULL, - arr_adj_json, + srv6_endx_sid_json, indent + 4); } } else @@ -1384,59 +1107,8 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID)) { struct isis_srv6_lan_endx_sid_subtlv *lan; if (json) { - struct json_object *arr_adj_json, *flags_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); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &lan->sid); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add( - flags_json, "algorithm", - sr_algorithm_string(lan->algorithm)); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add( - flags_json, "behavior", - seg6local_action2str(lan->behavior)); - json_object_string_add( - flags_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_string_addf(flags_json, - "neighbor-id", "%pSY", - lan->neighbor_id); - json_object_array_add(arr_adj_json, flags_json); - if (lan->subsubtlvs) - isis_format_subsubtlvs(lan->subsubtlvs, - NULL, - arr_adj_json, - indent + 4); - } - /* end old deprecated key format */ + struct json_object *arr_adj_json, + *srv6_lan_endx_sid_json; arr_adj_json = json_object_new_array(); json_object_object_add(json, "srv6LanEndxSID", @@ -1446,39 +1118,44 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, lan; lan = lan->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &lan->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &lan->sid); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add(flags_json, "algorithm", + 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(flags_json, "weight", - lan->weight); - json_object_string_add(flags_json, "behavior", + 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_boolean_add( - flags_json, "flagB", + srv6_lan_endx_sid_json, "flagB", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); json_object_boolean_add( - flags_json, "flagS", + srv6_lan_endx_sid_json, "flagS", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); json_object_boolean_add( - flags_json, "flagP", + srv6_lan_endx_sid_json, "flagP", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); - json_object_string_addf(flags_json, - "neighbor-id", "%pSY", + json_object_string_addf(srv6_lan_endx_sid_json, + "neighborID", "%pSY", lan->neighbor_id); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_lan_endx_sid_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, NULL, - arr_adj_json, + srv6_lan_endx_sid_json, indent + 4); } } else @@ -2599,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(); @@ -2774,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", @@ -2881,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); @@ -3191,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", @@ -3371,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); } @@ -3465,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) { @@ -3568,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); } @@ -3646,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); @@ -3748,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) { @@ -3921,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) { @@ -4044,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); @@ -4065,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++) { @@ -4281,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); } @@ -4369,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", @@ -4461,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); } @@ -4542,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) { @@ -4855,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); } @@ -4939,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) { @@ -5122,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", @@ -5292,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", @@ -5538,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)); @@ -5568,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", @@ -5601,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", @@ -5626,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); @@ -6133,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); @@ -6164,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; } @@ -6475,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; } @@ -6498,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: @@ -6523,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; @@ -6655,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); @@ -7216,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); @@ -7544,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_zebra.c b/isisd/isis_zebra.c index 2412ec5e..caf7d3dd 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -644,6 +644,70 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size) return 0; } +/** + * Request an End.X SID for an IS-IS adjacency. + * + * @param adj IS-IS Adjacency + */ +void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj) +{ + struct isis_circuit *circuit = adj->circuit; + struct isis_area *area = circuit->area; + struct in6_addr nexthop; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + bool ret; + + if (!area || !area->srv6db.srv6_locator) + return; + + /* Determine nexthop IP address */ + if (!circuit->ipv6_router || !adj->ll_ipv6_count) + return; + + nexthop = adj->ll_ipv6_addrs[0]; + + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = nexthop; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End.X SID for IS-IS area %s", + __func__, area->area_tag); + return; + } +} + +static void request_srv6_sids(struct isis_area *area) +{ + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct listnode *node; + struct isis_adjacency *adj; + bool ret; + + if (!area || !area->srv6db.config.enabled || !area->srv6db.srv6_locator) + return; + + sr_debug("Requesting SRv6 SIDs for IS-IS area %s", area->area_tag); + + /* Request new SRv6 End SID */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End SID for IS-IS area %s", + __func__, area->area_tag); + return; + } + + /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { + if (adj->ll_ipv6_count > 0) + isis_zebra_request_srv6_sid_endx(adj); + } +} + /** * Release Label Range to the Label Manager. * @@ -1119,99 +1183,47 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra) } /** - * Callback to process an SRv6 locator chunk received from SRv6 Manager (zebra). + * Internal function to process an SRv6 locator * - * @result 0 on success, -1 otherwise + * @param locator The locator to be processed */ -static int isis_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +static int isis_zebra_process_srv6_locator_internal(struct srv6_locator *locator) { struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); - struct stream *s = NULL; - struct listnode *node; struct isis_area *area; - struct srv6_locator_chunk *c; - struct srv6_locator_chunk *chunk = srv6_locator_chunk_alloc(); - struct isis_srv6_sid *sid; - struct isis_adjacency *adj; - enum srv6_endpoint_behavior_codepoint behavior; - bool allocated = false; - - if (!isis) { - srv6_locator_chunk_free(&chunk); - return -1; - } + struct listnode *node; - /* Decode the received zebra message */ - s = zclient->ibuf; - if (zapi_srv6_locator_chunk_decode(s, chunk) < 0) { - srv6_locator_chunk_free(&chunk); + if (!isis || !locator) return -1; - } - sr_debug( - "Received SRv6 locator chunk from zebra: name %s, " - "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", - chunk->locator_name, &chunk->prefix, chunk->block_bits_length, - chunk->node_bits_length, chunk->function_bits_length, - chunk->argument_bits_length); + 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); /* Walk through all areas of the ISIS instance */ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - if (strncmp(area->srv6db.config.srv6_locator_name, - chunk->locator_name, - sizeof(area->srv6db.config.srv6_locator_name)) != 0) + /* + * Check if the IS-IS area is configured to use the received + * locator + */ + if (strncmp(area->srv6db.config.srv6_locator_name, locator->name, + sizeof(area->srv6db.config.srv6_locator_name)) != 0) { + zlog_err("%s: SRv6 Locator name unmatch %s:%s", + __func__, area->srv6db.config.srv6_locator_name, + locator->name); continue; - - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_locator_chunks, - node, c)) { - if (!prefix_cmp(&c->prefix, &chunk->prefix)) { - srv6_locator_chunk_free(&chunk); - return 0; - } - } - - sr_debug( - "SRv6 locator chunk (locator %s, prefix %pFX) assigned to IS-IS area %s", - chunk->locator_name, &chunk->prefix, area->area_tag); - - /* Add the SRv6 Locator chunk to the per-area chunks list */ - listnode_add(area->srv6db.srv6_locator_chunks, chunk); - - /* Decide which behavior to use,depending on the locator type - * (i.e. uSID vs classic locator) */ - behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) - ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID - : SRV6_ENDPOINT_BEHAVIOR_END; - - /* Allocate new SRv6 End SID */ - sid = isis_srv6_sid_alloc(area, chunk, behavior, 0); - if (!sid) - return -1; - - /* Install the new SRv6 End SID in the forwarding plane through - * Zebra */ - isis_zebra_srv6_sid_install(area, sid); - - /* Store the SID */ - listnode_add(area->srv6db.srv6_sids, sid); - - /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ - for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { - if (adj->ll_ipv6_count > 0) - srv6_endx_sid_add(adj); } - /* Regenerate LSPs to advertise the new locator and the SID */ - lsp_regenerate_schedule(area, area->is_type, 0); + sr_debug("SRv6 locator (locator %s, prefix %pFX) set for IS-IS area %s", + locator->name, &locator->prefix, area->area_tag); - allocated = true; - break; - } + /* Store the locator in the IS-IS area */ + area->srv6db.srv6_locator = srv6_locator_alloc(locator->name); + srv6_locator_copy(area->srv6db.srv6_locator, locator); - if (!allocated) { - sr_debug("No IS-IS area configured for the locator %s", - chunk->locator_name); - srv6_locator_chunk_free(&chunk); + /* Request SIDs from the locator */ + request_srv6_sids(area); } return 0; @@ -1226,8 +1238,6 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) { struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); struct srv6_locator loc = {}; - struct listnode *node; - struct isis_area *area; if (!isis) return -1; @@ -1236,33 +1246,7 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) return -1; - sr_debug( - "New SRv6 locator allocated in zebra: name %s, " - "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", - loc.name, &loc.prefix, loc.block_bits_length, - loc.node_bits_length, loc.function_bits_length, - loc.argument_bits_length); - - /* Lookup on the IS-IS areas */ - for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - /* If SRv6 is enabled on this area and the configured locator - * corresponds to the new locator, then request a chunk from the - * locator */ - if (area->srv6db.config.enabled && - strncmp(area->srv6db.config.srv6_locator_name, loc.name, - sizeof(area->srv6db.config.srv6_locator_name)) == 0) { - sr_debug( - "Sending a request to get a chunk from the SRv6 locator %s (%pFX) " - "for IS-IS area %s", - loc.name, &loc.prefix, area->area_tag); - - if (isis_zebra_srv6_manager_get_locator_chunk( - loc.name) < 0) - return -1; - } - } - - return 0; + return isis_zebra_process_srv6_locator_internal(&loc); } /** @@ -1335,6 +1319,9 @@ static int isis_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) } } + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Regenerate LSPs to advertise that the locator no longer * exists */ lsp_regenerate_schedule(area, area->is_type, 0); @@ -1368,6 +1355,232 @@ int isis_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 isis_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 + */ +bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + 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, NULL); + 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 IS-IS no longer intends + * to use the SID. + * + * @param ctx Context to be associated with the SID to be released + */ +void isis_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; + } +} + +static int isis_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct srv6_sid_ctx ctx; + struct in6_addr sid_addr; + enum zapi_srv6_sid_notify note; + uint32_t sid_func; + struct isis_area *area; + struct listnode *node, *nnode, *n; + char buf[256]; + struct srv6_locator *locator; + struct prefix_ipv6 tmp_prefix; + struct srv6_adjacency *sra; + enum srv6_endpoint_behavior_codepoint behavior; + struct isis_srv6_sid *sid; + struct isis_adjacency *adj; + + if (!isis) + return -1; + + /* Decode the received notification message */ + if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, + &sid_func, NULL, ¬e, NULL)) { + zlog_err("%s : error in msg decode", __func__); + return -1; + } + + sr_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 sid_func %u note %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx), &sid_addr, + sid_func, zapi_srv6_sid_notify2str(note)); + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (!area->srv6db.config.enabled || !area->srv6db.srv6_locator) + continue; + + locator = area->srv6db.srv6_locator; + + /* Verify that the received SID belongs to the configured locator */ + if (note == ZAPI_SRV6_SID_ALLOCATED) { + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = sid_addr; + + if (!prefix_match((struct prefix *)&locator->prefix, + (struct prefix *)&tmp_prefix)) { + sr_debug("%s : ignoring SRv6 SID notify: locator (area %s) does not match", + __func__, area->area_tag); + continue; + } + } + + /* Handle notification */ + switch (note) { + case ZAPI_SRV6_SID_ALLOCATED: + sr_debug("SRv6 SID %pI6 %s ALLOCATED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* Remove old End SIDs, if any */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids, + node, nnode, sid)) { + isis_zebra_srv6_sid_uninstall(area, sid); + listnode_delete(area->srv6db.srv6_sids, + sid); + } + + /* Allocate new SRv6 End SID */ + behavior = + (CHECK_FLAG(locator->flags, + SRV6_LOCATOR_USID)) + ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID + : SRV6_ENDPOINT_BEHAVIOR_END; + sid = isis_srv6_sid_alloc(area, + area->srv6db + .srv6_locator, + behavior, &sid_addr); + if (!sid) { + zlog_warn("%s: isis_srv6_sid_alloc failed", + __func__); + return -1; + } + + /* + * Install the new SRv6 End SID in the forwarding plane through + * Zebra + */ + isis_zebra_srv6_sid_install(area, sid); + + /* Store the SID */ + listnode_add(area->srv6db.srv6_sids, sid); + + } else if (ctx.behavior == + ZEBRA_SEG6_LOCAL_ACTION_END_X) { + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, + n, adj)) { + /* Check if the End.X SID is for this adjacecny */ + if (adj->ll_ipv6_count == 0 || + memcmp(&adj->ll_ipv6_addrs[0], + &ctx.nh6, + sizeof(struct in6_addr)) != 0) + continue; + + /* Remove old End.X SIDs, if any */ + for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, + node, nnode, sra)) + srv6_endx_sid_del(sra); + + /* Allocate new End.X SID for the adjacency */ + srv6_endx_sid_add_single(adj, false, + NULL, + &sid_addr); + } + } else { + zlog_warn("%s: unsupported behavior %u", + __func__, ctx.behavior); + return -1; + } + break; + case ZAPI_SRV6_SID_RELEASED: + sr_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + break; + case ZAPI_SRV6_SID_FAIL_ALLOC: + sr_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: + zlog_warn("%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; + } + + /* Regenerate LSPs to advertise the new locator and the SID */ + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return 0; +} + static zclient_handler *const isis_handlers[] = { [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra, [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, @@ -1380,10 +1593,9 @@ static zclient_handler *const isis_handlers[] = { [ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify, - [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = - isis_zebra_process_srv6_locator_chunk, [ZEBRA_SRV6_LOCATOR_ADD] = isis_zebra_process_srv6_locator_add, [ZEBRA_SRV6_LOCATOR_DELETE] = isis_zebra_process_srv6_locator_delete, + [ZEBRA_SRV6_SID_NOTIFY] = isis_zebra_srv6_sid_notify, }; void isis_zebra_init(struct event_loop *master, int instance) @@ -1416,5 +1628,4 @@ void isis_zebra_stop(void) zclient_free(zclient_sync); zclient_stop(zclient); zclient_free(zclient); - frr_fini(); } diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index f1684b7c..79da16ef 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -68,4 +68,11 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra); extern int isis_zebra_srv6_manager_get_locator_chunk(const char *name); extern int isis_zebra_srv6_manager_release_locator_chunk(const char *name); +extern int isis_zebra_srv6_manager_get_locator(const char *name); +extern void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj); +extern bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx); + #endif /* _ZEBRA_ISIS_ZEBRA_H */ diff --git a/isisd/isisd.c b/isisd/isisd.c index 982df083..2863fd91 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -176,6 +176,11 @@ void isis_master_init(struct event_loop *master) im->master = master; } +void isis_master_terminate(void) +{ + list_delete(&im->isis); +} + struct isis *isis_new(const char *vrf_name) { struct vrf *vrf; @@ -272,7 +277,7 @@ void isis_area_del_circuit(struct isis_area *area, struct isis_circuit *circuit) isis_csm_state_change(ISIS_DISABLE, circuit, area); } -static void delete_area_addr(void *arg) +void isis_area_address_delete(void *arg) { struct iso_address *addr = (struct iso_address *)arg; @@ -330,7 +335,7 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->circuit_list = list_new(); area->adjacency_list = list_new(); area->area_addrs = list_new(); - area->area_addrs->del = delete_area_addr; + area->area_addrs->del = isis_area_address_delete; if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) event_add_timer(master, lsp_tick, area, 1, &area->t_tick); @@ -471,6 +476,29 @@ struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id) return NULL; } +struct isis_area *isis_area_lookup_by_sysid(const uint8_t *sysid) +{ + struct isis_area *area; + struct listnode *node; + struct isis *isis; + struct iso_address *addr = NULL; + + isis = isis_lookup_by_sysid(sysid); + if (isis == NULL) + return NULL; + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (listcount(area->area_addrs) > 0) { + addr = listgetdata(listhead(area->area_addrs)); + if (!memcmp(addr->area_addr + addr->addr_len, sysid, + ISIS_SYS_ID_LEN)) + return area; + } + } + + return NULL; +} + int isis_area_get(struct vty *vty, const char *area_tag) { struct isis_area *area; @@ -496,6 +524,7 @@ void isis_area_destroy(struct isis_area *area) { struct listnode *node, *nnode; struct isis_circuit *circuit; + struct iso_address *addr; QOBJ_UNREG(area); @@ -545,6 +574,15 @@ void isis_area_destroy(struct isis_area *area) if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) isis_redist_area_finish(area); + if (listcount(area->area_addrs) > 0) { + addr = listgetdata(listhead(area->area_addrs)); + if (!memcmp(addr->area_addr + addr->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN)) { + memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN); + area->isis->sysid_set = 0; + } + } + list_delete(&area->area_addrs); for (int i = SPF_PREFIX_PRIO_CRITICAL; i <= SPF_PREFIX_PRIO_MEDIUM; diff --git a/isisd/isisd.h b/isisd/isisd.h index f5042e4a..1ae39f0a 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -268,6 +268,7 @@ DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area)); void isis_terminate(void); void isis_master_init(struct event_loop *master); +void isis_master_terminate(void); void isis_vrf_link(struct isis *isis, struct vrf *vrf); void isis_vrf_unlink(struct isis *isis, struct vrf *vrf); struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id); @@ -285,10 +286,12 @@ void isis_area_add_circuit(struct isis_area *area, void isis_area_del_circuit(struct isis_area *area, struct isis_circuit *circuit); +void isis_area_address_delete(void *arg); struct isis_area *isis_area_create(const char *, const char *); struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id); struct isis_area *isis_area_lookup_by_vrf(const char *area_tag, const char *vrf_name); +struct isis_area *isis_area_lookup_by_sysid(const uint8_t *sysid); int isis_area_get(struct vty *vty, const char *area_tag); void isis_area_destroy(struct isis_area *area); void isis_filter_update(struct access_list *access); diff --git a/lib/agentx.c b/lib/agentx.c index 19f2a6b7..2a3ff235 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -377,4 +377,16 @@ void smux_events_update(void) agentx_events_update(); } +static void smux_events_delete_thread(void *arg) +{ + XFREE(MTYPE_TMP, arg); +} + +void smux_terminate(void) +{ + if (events) { + events->del = smux_events_delete_thread; + list_delete(&events); + } +} #endif /* SNMP_AGENTX */ diff --git a/lib/bfd.c b/lib/bfd.c index 2222bb95..4535fc12 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -1334,3 +1334,9 @@ int bfd_nht_update(const struct prefix *match, const struct zapi_route *route) return 0; } + +bool bfd_session_is_down(const struct bfd_session_params *session) +{ + return session->bss.state == BSS_DOWN || + session->bss.state == BSS_ADMIN_DOWN; +} diff --git a/lib/bfd.h b/lib/bfd.h index bfa52873..99790f96 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 */ @@ -464,6 +458,8 @@ extern bool bfd_protocol_integration_shutting_down(void); extern int bfd_nht_update(const struct prefix *match, const struct zapi_route *route); +extern bool bfd_session_is_down(const struct bfd_session_params *session); + #ifdef __cplusplus } #endif diff --git a/lib/command.c b/lib/command.c index 51f2529e..25c9ee9a 100644 --- a/lib/command.c +++ b/lib/command.c @@ -17,6 +17,7 @@ #include #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 e4c575e8..f369a352 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 */ @@ -161,6 +157,9 @@ enum node_type { SRV6_LOCS_NODE, /* SRv6 locators node */ SRV6_LOC_NODE, /* SRv6 locator node */ SRV6_ENCAP_NODE, /* SRv6 encapsulation node */ + SRV6_SID_FORMATS_NODE, /* SRv6 SID formats config node */ + SRV6_SID_FORMAT_USID_F3216_NODE, /* SRv6 uSID f3216 format config node */ + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, /* SRv6 uncompressed f4024 format config node */ VTY_NODE, /* Vty node. */ FPM_NODE, /* Dataplane FPM node. */ LINK_PARAMS_NODE, /* Link-parameters node */ @@ -179,6 +178,8 @@ enum node_type { ISIS_SRV6_NODE_MSD_NODE, /* ISIS SRv6 Node MSDs node */ MGMTD_NODE, /* MGMTD node. */ RPKI_VRF_NODE, /* RPKI node for VRF */ + PIM_NODE, /* PIM protocol mode */ + PIM6_NODE, /* PIM protocol for IPv6 mode */ NODE_TYPE_MAX, /* maximum */ }; /* clang-format on */ @@ -247,9 +248,11 @@ struct cmd_node { /* Argc max counts. */ #define CMD_ARGC_MAX 256 +/* clang-format off */ + /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ - static const struct cmd_element cmdname = { \ + const struct cmd_element cmdname = { \ .string = cmdstr, \ .func = funcname, \ .doc = helpstr, \ @@ -276,7 +279,7 @@ struct cmd_node { /* DEFPY variants */ #define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ funcdecl_##funcname #define DEFPY(funcname, cmdname, cmdstr, helpstr) \ @@ -303,7 +306,7 @@ struct cmd_node { #define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUN(funcname, cmdname, cmdstr, helpstr) \ @@ -340,7 +343,8 @@ struct cmd_node { /* DEFUN + DEFSH */ #define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, \ + daemon) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ @@ -352,7 +356,7 @@ struct cmd_node { /* ALIAS macro which define existing command's alias. */ #define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) #define ALIAS(funcname, cmdname, cmdstr, helpstr) \ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, 0) @@ -371,6 +375,8 @@ struct cmd_node { #define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) +/* clang-format on */ + /* Some macroes */ /* diff --git a/lib/command_graph.c b/lib/command_graph.c index ff3c11db..20ab6b32 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -267,6 +267,9 @@ static bool cmd_nodes_equal(struct graph_node *ga, struct graph_node *gb) case NEG_ONLY_TKN: case WORD_TKN: case ASNUM_TKN: +#ifdef BUILDING_CLIPPY + case CMD_ELEMENT_TKN: +#endif return true; } diff --git a/lib/command_graph.h b/lib/command_graph.h index 25aa47db..313c97fe 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -54,6 +54,9 @@ enum cmd_token_type { END_TKN, // last token in line NEG_ONLY_TKN, // filter token, match if "no ..." command +#ifdef BUILDING_CLIPPY + CMD_ELEMENT_TKN, // python bindings only +#endif SPECIAL_TKN = FORK_TKN, }; /* clang-format on */ diff --git a/lib/command_py.c b/lib/command_py.c index f8abcf8e..a77adcd7 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -29,6 +29,7 @@ struct wrap_graph; static PyObject *graph_to_pyobj(struct wrap_graph *graph, struct graph_node *gn); +static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i); /* * nodes are wrapped as follows: @@ -44,13 +45,6 @@ struct wrap_graph_node { bool allowrepeat; const char *type; - bool deprecated; - bool hidden; - const char *text; - const char *desc; - const char *varname; - long long min, max; - struct graph_node *node; struct wrap_graph *wgraph; size_t idx; @@ -68,6 +62,7 @@ struct wrap_graph { char *definition; struct graph *graph; + size_t n_nodewrappers; struct wrap_graph_node **nodewrappers; }; @@ -84,11 +79,75 @@ static PyObject *refuse_new(PyTypeObject *type, PyObject *args, PyObject *kwds) READONLY, (char *)#name " (" #type ")" \ } static PyMemberDef members_graph_node[] = { - member(allowrepeat, T_BOOL), member(type, T_STRING), - member(deprecated, T_BOOL), member(hidden, T_BOOL), - member(text, T_STRING), member(desc, T_STRING), - member(min, T_LONGLONG), member(max, T_LONGLONG), - member(varname, T_STRING), {}, + /* clang-format off */ + member(type, T_STRING), + member(idx, T_ULONG), + {}, + /* clang-format on */ +}; +#undef member + +static PyObject *graph_node_get_str(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + const char *val = *(const char **)offset; + + if (!val) + Py_RETURN_NONE; + return PyUnicode_FromString(val); +} + +static PyObject *graph_node_get_bool(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + bool val = *(bool *)offset; + + return PyBool_FromLong(val); +} + +static PyObject *graph_node_get_ll(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + long long val = *(long long *)offset; + + return PyLong_FromLongLong(val); +} + +static PyObject *graph_node_get_u8(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + uint8_t val = *(uint8_t *)offset; + + return PyLong_FromUnsignedLong(val); +} + +/* clang-format off */ +#define member(name, variant) \ + { \ + (char *)#name, \ + graph_node_get_##variant, \ + NULL, \ + (char *)#name " (" #variant ")", \ + (void *)offsetof(struct cmd_token, name), \ + } +/* clang-format on */ + +static PyGetSetDef getset_graph_node[] = { + /* clang-format off */ + member(attr, u8), + member(allowrepeat, bool), + member(varname_src, u8), + member(text, str), + member(desc, str), + member(min, ll), + member(max, ll), + member(varname, str), + {}, + /* clang-format on */ }; #undef member @@ -101,12 +160,30 @@ static PyObject *graph_node_next(PyObject *self, PyObject *args) struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; PyObject *pylist; - if (wrap->node->data - && ((struct cmd_token *)wrap->node->data)->type == END_TKN) + if (wrap->node->data && + ((struct cmd_token *)wrap->node->data)->type == CMD_ELEMENT_TKN) return PyList_New(0); pylist = PyList_New(vector_active(wrap->node->to)); for (size_t i = 0; i < vector_active(wrap->node->to); i++) { struct graph_node *gn = vector_slot(wrap->node->to, i); + + PyList_SetItem(pylist, i, graph_to_pyobj(wrap->wgraph, gn)); + } + return pylist; +}; + +static PyObject *graph_node_prev(PyObject *self, PyObject *args) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + PyObject *pylist; + + if (wrap->node->data && + ((struct cmd_token *)wrap->node->data)->type == START_TKN) + return PyList_New(0); + pylist = PyList_New(vector_active(wrap->node->from)); + for (size_t i = 0; i < vector_active(wrap->node->from); i++) { + struct graph_node *gn = vector_slot(wrap->node->from, i); + PyList_SetItem(pylist, i, graph_to_pyobj(wrap->wgraph, gn)); } return pylist; @@ -118,30 +195,60 @@ static PyObject *graph_node_next(PyObject *self, PyObject *args) static PyObject *graph_node_join(PyObject *self, PyObject *args) { struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + struct cmd_token *tok; if (!wrap->node->data || ((struct cmd_token *)wrap->node->data)->type == END_TKN) Py_RETURN_NONE; - struct cmd_token *tok = wrap->node->data; + tok = wrap->node->data; if (tok->type != FORK_TKN) Py_RETURN_NONE; return graph_to_pyobj(wrap->wgraph, tok->forkjoin); }; +static PyObject *graph_node_fork(PyObject *self, PyObject *args) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + struct cmd_token *tok; + + if (!wrap->node->data || + ((struct cmd_token *)wrap->node->data)->type == END_TKN) + Py_RETURN_NONE; + + tok = wrap->node->data; + if (tok->type != JOIN_TKN) + Py_RETURN_NONE; + + return graph_to_pyobj(wrap->wgraph, tok->forkjoin); +}; + static PyMethodDef methods_graph_node[] = { - {"next", graph_node_next, METH_NOARGS, "outbound graph edge list"}, - {"join", graph_node_join, METH_NOARGS, "outbound join node"}, - {}}; + { "next", graph_node_next, METH_NOARGS, "outbound graph edge list" }, + { "prev", graph_node_prev, METH_NOARGS, "inbound graph edge list" }, + { "join", graph_node_join, METH_NOARGS, "outbound join node" }, + { "fork", graph_node_fork, METH_NOARGS, "inbound fork node" }, + {} +}; static void graph_node_wrap_free(void *arg) { struct wrap_graph_node *wrap = arg; + + assert(wrap->idx < wrap->wgraph->n_nodewrappers); wrap->wgraph->nodewrappers[wrap->idx] = NULL; Py_DECREF(wrap->wgraph); } +static PyObject *repr_graph_node(PyObject *arg) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)arg; + + return PyUnicode_FromFormat("<_clippy.GraphNode %p [%zu] %s>", + wrap->node, wrap->idx, wrap->type); +} + static PyTypeObject typeobj_graph_node = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.GraphNode", .tp_basicsize = sizeof(struct wrap_graph_node), @@ -150,13 +257,14 @@ static PyTypeObject typeobj_graph_node = { .tp_new = refuse_new, .tp_free = graph_node_wrap_free, .tp_members = members_graph_node, + .tp_getset = getset_graph_node, .tp_methods = methods_graph_node, + .tp_repr = repr_graph_node, }; static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, struct graph_node *gn) { - struct wrap_graph_node *wrap; size_t i; for (i = 0; i < vector_active(wgraph->graph->nodes); i++) @@ -166,6 +274,24 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, PyErr_SetString(PyExc_ValueError, "cannot find node in graph"); return NULL; } + + return graph_to_pyobj_idx(wgraph, i); +} + +static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i) +{ + struct wrap_graph_node *wrap; + struct graph_node *gn = vector_slot(wgraph->graph->nodes, i); + + if (i >= wgraph->n_nodewrappers) { + wgraph->nodewrappers = + realloc(wgraph->nodewrappers, + (i + 1) * sizeof(wgraph->nodewrappers[0])); + memset(wgraph->nodewrappers + wgraph->n_nodewrappers, 0, + sizeof(wgraph->nodewrappers[0]) * + (i + 1 - wgraph->n_nodewrappers)); + wgraph->n_nodewrappers = i + 1; + } if (wgraph->nodewrappers[i]) { PyObject *obj = (PyObject *)wgraph->nodewrappers[i]; Py_INCREF(obj); @@ -209,19 +335,11 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, item(START_TKN); item(END_TKN); item(NEG_ONLY_TKN); + item(CMD_ELEMENT_TKN); #undef item default: wrap->type = "???"; } - - wrap->deprecated = !!(tok->attr & CMD_ATTR_DEPRECATED); - wrap->hidden = !!(tok->attr & CMD_ATTR_HIDDEN); - wrap->text = tok->text; - wrap->desc = tok->desc; - wrap->varname = tok->varname; - wrap->min = tok->min; - wrap->max = tok->max; - wrap->allowrepeat = tok->allowrepeat; } return (PyObject *)wrap; @@ -246,9 +364,13 @@ static PyObject *graph_first(PyObject *self, PyObject *args) return graph_to_pyobj(gwrap, gn); }; +static PyObject *graph_merge(PyObject *self, PyObject *args); + static PyMethodDef methods_graph[] = { - {"first", graph_first, METH_NOARGS, "first graph node"}, - {}}; + { "first", graph_first, METH_NOARGS, "first graph node" }, + { "merge", graph_merge, METH_VARARGS, "merge graphs" }, + {} +}; static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds); @@ -262,6 +384,30 @@ static void graph_wrap_free(void *arg) free(wgraph->definition); } +static Py_ssize_t graph_length(PyObject *self) +{ + struct wrap_graph *gwrap = (struct wrap_graph *)self; + + return vector_active(gwrap->graph->nodes); +} + +static PyObject *graph_item(PyObject *self, Py_ssize_t idx) +{ + struct wrap_graph *gwrap = (struct wrap_graph *)self; + + if (idx >= vector_active(gwrap->graph->nodes)) + return PyErr_Format(PyExc_IndexError, + "index %zd past graph size %u", idx, + vector_active(gwrap->graph->nodes)); + + return graph_to_pyobj_idx(gwrap, idx); +} + +static PySequenceMethods seq_graph = { + .sq_length = graph_length, + .sq_item = graph_item, +}; + static PyTypeObject typeobj_graph = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.Graph", .tp_basicsize = sizeof(struct wrap_graph), @@ -271,35 +417,62 @@ static PyTypeObject typeobj_graph = { .tp_free = graph_wrap_free, .tp_members = members_graph, .tp_methods = methods_graph, + .tp_as_sequence = &seq_graph, }; +static PyObject *graph_merge(PyObject *self, PyObject *args) +{ + PyObject *py_other; + struct wrap_graph *gwrap = (struct wrap_graph *)self; + struct wrap_graph *gother; + + if (!PyArg_ParseTuple(args, "O!", &typeobj_graph, &py_other)) + return NULL; + + gother = (struct wrap_graph *)py_other; + cmd_graph_merge(gwrap->graph, gother->graph, +1); + Py_RETURN_NONE; +} + /* top call / entrypoint for python code */ static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds) { - const char *def, *doc = NULL; + const char *def, *doc = NULL, *name = NULL; struct wrap_graph *gwrap; - static const char *kwnames[] = {"cmddef", "doc", NULL}; + static const char *const kwnames[] = { "cmddef", "doc", "name", NULL }; gwrap = (struct wrap_graph *)typeobj_graph.tp_alloc(&typeobj_graph, 0); if (!gwrap) return NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", (char **)kwnames, - &def, &doc)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "z|ss", (char **)kwnames, + &def, &doc, &name)) return NULL; struct graph *graph = graph_new(); struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL); graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del); - struct cmd_element cmd = {.string = def, .doc = doc}; - cmd_graph_parse(graph, &cmd); - cmd_graph_names(graph); + if (def) { + struct cmd_element cmd = { .string = def, .doc = doc }; + struct graph_node *last; + + cmd_graph_parse(graph, &cmd); + cmd_graph_names(graph); + + last = vector_slot(graph->nodes, + vector_active(graph->nodes) - 1); + assert(last->data == &cmd); + + last->data = cmd_token_new(CMD_ELEMENT_TKN, 0, name, def); + last->del = (void (*)(void *))cmd_token_del; + + gwrap->definition = strdup(def); + } else { + gwrap->definition = strdup("NULL"); + } gwrap->graph = graph; - gwrap->definition = strdup(def); - gwrap->nodewrappers = calloc(vector_active(graph->nodes), - sizeof(gwrap->nodewrappers[0])); return (PyObject *)gwrap; } diff --git a/lib/darr.h b/lib/darr.h index 404869d9..2b9a0a0c 100644 --- a/lib/darr.h +++ b/lib/darr.h @@ -24,6 +24,8 @@ * - darr_ensure_i * - darr_ensure_i_mt * - darr_free + * - darr_free_free + * - darr_free_func * - darr_insert * - darr_insert_mt * - darr_insertz @@ -217,6 +219,41 @@ void *__darr_resize(void *a, uint count, size_t esize, struct memtype *mt); } \ } while (0) +/** + * Free memory allocated for the dynamic array `A`, calling `darr_free` for + * each element of the array first. + * + * Args: + * A: The dynamic array, can be NULL. + */ +#define darr_free_free(A) \ + do { \ + for (uint __i = 0; __i < darr_len(A); __i++) \ + if ((A)[__i]) { \ + struct darr_metadata *__meta = \ + _darr_meta((A)[__i]); \ + XFREE(__meta->mtype, __meta); \ + } \ + darr_free(A); \ + } while (0) + +/** + * Free memory allocated for the dynamic array `A`, calling `F` routine + * for each element of the array first. + * + * Args: + * A: The dynamic array, can be NULL. + * F: The function to call for each element. + */ + +#define darr_free_func(A, F) \ + do { \ + for (uint __i = 0; __i < darr_len(A); __i++) { \ + F((A)[__i]); \ + } \ + darr_free(A); \ + } while (0) + /** * Make sure that there is room in the dynamic array `A` to add `C` elements. * diff --git a/lib/debug.c b/lib/debug.c index 757a47ab..d25c32d4 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 e9d8a31a..eee314cf 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 2b4fea37..6c63d1f8 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/event.c b/lib/event.c index fc46a11c..d925d0d5 100644 --- a/lib/event.c +++ b/lib/event.c @@ -304,9 +304,6 @@ static uint8_t parse_filter(const char *filterstr) return filter; } -#if CONFDATE > 20240707 - CPP_NOTICE("Remove `show thread ...` commands") -#endif DEFUN_NOSH (show_event_cpu, show_event_cpu_cmd, "show event cpu [FILTER]", @@ -332,14 +329,6 @@ DEFUN_NOSH (show_event_cpu, return CMD_SUCCESS; } -ALIAS(show_event_cpu, - show_thread_cpu_cmd, - "show thread cpu [FILTER]", - SHOW_STR - "Thread information\n" - "Thread CPU usage\n" - "Display filter (rwtex)\n") - DEFPY (service_cputime_stats, service_cputime_stats_cmd, "[no] service cputime-stats", @@ -440,19 +429,15 @@ DEFUN_NOSH (show_event_poll, return CMD_SUCCESS; } -ALIAS(show_event_poll, - show_thread_poll_cmd, - "show thread poll", - SHOW_STR - "Thread information\n" - "Show poll FD's and information\n") - -DEFUN (clear_thread_cpu, - clear_thread_cpu_cmd, - "clear thread cpu [FILTER]", +#if CONFDATE > 20241231 +CPP_NOTICE("Remove `clear thread cpu` command") +#endif +DEFUN (clear_event_cpu, + clear_event_cpu_cmd, + "clear event cpu [FILTER]", "Clear stored data in all pthreads\n" - "Thread information\n" - "Thread CPU usage\n" + "Event information\n" + "Event CPU usage\n" "Display filter (rwtexb)\n") { uint8_t filter = (uint8_t)-1U; @@ -472,6 +457,14 @@ DEFUN (clear_thread_cpu, return CMD_SUCCESS; } +ALIAS (clear_event_cpu, + clear_thread_cpu_cmd, + "clear thread cpu [FILTER]", + "Clear stored data in all pthreads\n" + "Thread information\n" + "Thread CPU usage\n" + "Display filter (rwtexb)\n") + static void show_event_timers_helper(struct vty *vty, struct event_loop *m) { const char *name = m->name ? m->name : "main"; @@ -507,26 +500,17 @@ DEFPY_NOSH (show_event_timers, return CMD_SUCCESS; } -ALIAS(show_event_timers, - show_thread_timers_cmd, - "show thread timers", - SHOW_STR - "Thread information\n" - "Show all timers and how long they have in the system\n") - void event_cmd_init(void) { - install_element(VIEW_NODE, &show_thread_cpu_cmd); install_element(VIEW_NODE, &show_event_cpu_cmd); - install_element(VIEW_NODE, &show_thread_poll_cmd); install_element(VIEW_NODE, &show_event_poll_cmd); install_element(ENABLE_NODE, &clear_thread_cpu_cmd); + install_element(ENABLE_NODE, &clear_event_cpu_cmd); install_element(CONFIG_NODE, &service_cputime_stats_cmd); install_element(CONFIG_NODE, &service_cputime_warning_cmd); install_element(CONFIG_NODE, &service_walltime_warning_cmd); - install_element(VIEW_NODE, &show_thread_timers_cmd); install_element(VIEW_NODE, &show_event_timers_cmd); } /* CLI end ------------------------------------------------------------------ */ @@ -571,8 +555,9 @@ struct event_loop *event_master_create(const char *name) } if (rv->fd_limit > STUPIDLY_LARGE_FD_SIZE) { - zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds also limiting size to %u", - rv->fd_limit, STUPIDLY_LARGE_FD_SIZE); + if (frr_is_daemon()) + zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds also limiting size to %u", + rv->fd_limit, STUPIDLY_LARGE_FD_SIZE); rv->fd_limit = STUPIDLY_LARGE_FD_SIZE; } diff --git a/lib/flex_algo.c b/lib/flex_algo.c index f48117ff..ab0eef67 100644 --- a/lib/flex_algo.c +++ b/lib/flex_algo.c @@ -20,9 +20,6 @@ DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO_DATABASE, "Flex-Algo database"); DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO, "Flex-Algo algorithm information"); -static void _flex_algo_delete(struct flex_algos *flex_algos, - struct flex_algo *fa); - struct flex_algos *flex_algos_alloc(flex_algo_allocator_t allocator, flex_algo_releaser_t releaser) { @@ -42,7 +39,7 @@ void flex_algos_free(struct flex_algos *flex_algos) struct flex_algo *fa; for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa)) - _flex_algo_delete(flex_algos, fa); + flex_algo_free(flex_algos, fa); list_delete(&flex_algos->flex_algos); XFREE(MTYPE_FLEX_ALGO_DATABASE, flex_algos); } @@ -63,8 +60,7 @@ struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos, return fa; } -static void _flex_algo_delete(struct flex_algos *flex_algos, - struct flex_algo *fa) +void flex_algo_free(struct flex_algos *flex_algos, struct flex_algo *fa) { if (flex_algos->releaser) flex_algos->releaser(fa->data); @@ -75,19 +71,6 @@ static void _flex_algo_delete(struct flex_algos *flex_algos, XFREE(MTYPE_FLEX_ALGO, fa); } - -void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm) -{ - struct listnode *node, *nnode; - struct flex_algo *fa; - - for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa)) { - if (fa->algorithm != algorithm) - continue; - _flex_algo_delete(flex_algos, fa); - } -} - /** * @brief Look up the local flex-algo object by its algorithm number. * @param algorithm flex-algo algorithm number diff --git a/lib/flex_algo.h b/lib/flex_algo.h index e617e7ca..54b37783 100644 --- a/lib/flex_algo.h +++ b/lib/flex_algo.h @@ -115,11 +115,10 @@ struct flex_algos *flex_algos_alloc(flex_algo_allocator_t allocator, void flex_algos_free(struct flex_algos *flex_algos); struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos, uint8_t algorithm, void *arg); +void flex_algo_free(struct flex_algos *flex_algos, struct flex_algo *fa); struct flex_algo *flex_algo_lookup(struct flex_algos *flex_algos, uint8_t algorithm); -void flex_algos_free(struct flex_algos *flex_algos); bool flex_algo_definition_cmp(struct flex_algo *fa1, struct flex_algo *fa2); -void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm); bool flex_algo_id_valid(uint16_t algorithm); char *flex_algo_metric_type_print(char *type_str, size_t sz, enum flex_algo_metric_type metric_type); diff --git a/lib/frrcu.h b/lib/frrcu.h index 9f07a69b..81ab5528 100644 --- a/lib/frrcu.h +++ b/lib/frrcu.h @@ -156,7 +156,7 @@ extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action); #define rcu_call(func, ptr, field) \ do { \ typeof(ptr) _ptr = (ptr); \ - void (*fptype)(typeof(ptr)); \ + void (*_fptype)(typeof(ptr)); \ struct rcu_head *_rcu_head = &_ptr->field; \ static const struct rcu_action _rcu_action = { \ .type = RCUA_CALL, \ diff --git a/lib/frrlua.c b/lib/frrlua.c index 2cab1a54..ef081e4b 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 dc0f4d99..e407a449 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 acdd1df6..06460b01 100644 --- a/lib/frrscript.c +++ b/lib/frrscript.c @@ -27,6 +27,16 @@ struct frrscript_names_head frrscript_names_hash; void _lua_decode_noop(lua_State *L, ...) {} +void frrscript_names_config_write(struct vty *vty) +{ + struct frrscript_names_entry *lua_script_entry; + + frr_each (frrscript_names, &frrscript_names_hash, lua_script_entry) + if (lua_script_entry->script_name[0] != '\0') + vty_out(vty, "zebra on-rib-process script %s\n", + lua_script_entry->script_name); +} + /* * Wrapper for frrscript_names_add * Use this to register hook calls when a daemon starts up @@ -348,6 +358,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/frrscript.h b/lib/frrscript.h index ce313a1b..75ac53c6 100644 --- a/lib/frrscript.h +++ b/lib/frrscript.h @@ -44,6 +44,8 @@ struct frrscript_names_entry { extern struct frrscript_names_head frrscript_names_hash; +extern void frrscript_names_config_write(struct vty *vty); + int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1, const struct frrscript_names_entry *snhe2); uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe); diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index abd42f35..05088d52 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 df562439..edbfeec4 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/hash.h b/lib/hash.h index 2d00a334..efa7011b 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -13,6 +13,18 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new hash structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. + */ + /* Default hash table size. */ #define HASH_INITIAL_SIZE 256 /* Expansion threshold */ diff --git a/lib/libfrr.c b/lib/libfrr.c index cc60cfb8..313fe99f 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -102,23 +102,25 @@ static void opt_extend(const struct optspec *os) #define OPTION_SCRIPTDIR 1009 static const struct option lo_always[] = { - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'v'}, - {"daemon", no_argument, NULL, 'd'}, - {"module", no_argument, NULL, 'M'}, - {"profile", required_argument, NULL, 'F'}, - {"pathspace", required_argument, NULL, 'N'}, - {"vrfdefaultname", required_argument, NULL, 'o'}, - {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, - {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, - {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR}, - {"log", required_argument, NULL, OPTION_LOG}, - {"log-level", required_argument, NULL, OPTION_LOGLEVEL}, - {"command-log-always", no_argument, NULL, OPTION_LOGGING}, - {"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS}, - {NULL}}; + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "daemon", no_argument, NULL, 'd' }, + { "module", no_argument, NULL, 'M' }, + { "profile", required_argument, NULL, 'F' }, + { "pathspace", required_argument, NULL, 'N' }, + { "vrfdefaultname", required_argument, NULL, 'o' }, + { "graceful_restart", optional_argument, NULL, 'K' }, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK }, + { "moduledir", required_argument, NULL, OPTION_MODULEDIR }, + { "scriptdir", required_argument, NULL, OPTION_SCRIPTDIR }, + { "log", required_argument, NULL, OPTION_LOG }, + { "log-level", required_argument, NULL, OPTION_LOGLEVEL }, + { "command-log-always", no_argument, NULL, OPTION_LOGGING }, + { "limit-fds", required_argument, NULL, OPTION_LIMIT_FDS }, + { NULL } +}; static const struct optspec os_always = { - "hvdM:F:N:o:", + "hvdM:F:N:o:K::", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" @@ -126,13 +128,15 @@ static const struct optspec os_always = { " -F, --profile Use specified configuration profile\n" " -N, --pathspace Insert prefix into config & socket paths\n" " -o, --vrfdefaultname Set default VRF name.\n" + " -K, --graceful_restart FRR starting in Graceful Restart mode, with optional route-cleanup timer\n" " --vty_socket Override vty socket path\n" " --moduledir Override modules directory\n" " --scriptdir Override scripts directory\n" " --log Set Logging to stdout, syslog, or file:\n" " --log-level Set Logging Level to use, debug, info, warn, etc\n" " --limit-fds Limit number of fds supported\n", - lo_always}; + lo_always +}; static bool logging_to_stdout = false; /* set when --log stdout specified */ @@ -358,6 +362,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst)); di->cli_mode = FRR_CLI_CLASSIC; + di->graceful_restart = false; + di->gr_cleanup_time = 0; /* we may be starting with extra FDs open for whatever purpose, * e.g. logging, some module, etc. Recording them here allows later @@ -520,6 +526,11 @@ static int frr_opt(int opt) di->db_file = optarg; break; #endif + case 'K': + di->graceful_restart = true; + if (optarg) + di->gr_cleanup_time = atoi(optarg); + break; case 'C': if (di->flags & FRR_NO_SPLIT_CONFIG) return 1; @@ -798,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 @@ -808,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; } @@ -1256,6 +1267,8 @@ void frr_fini(void) /* frrmod_init -> nothing needed / hooks */ rcu_shutdown(); + frrmod_terminate(); + /* also log memstats to stderr when stderr goes to a file*/ if (debug_memstats_at_exit || !isatty(STDERR_FILENO)) have_leftovers = log_memstats(stderr, di->name); @@ -1450,7 +1463,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); } @@ -1463,3 +1479,11 @@ const char *frr_vers2str(uint32_t version, char *buf, int buflen) return buf; } + +bool frr_is_daemon(void) +{ + if (di) + return true; + + return false; +} diff --git a/lib/libfrr.h b/lib/libfrr.h index d52ee9ae..df537e2e 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 { @@ -118,6 +123,8 @@ struct frr_daemon_info { bool dryrun; bool daemon_mode; bool terminal; + bool graceful_restart; + int gr_cleanup_time; enum frr_cli_mode cli_mode; struct event *read_in; @@ -188,7 +195,7 @@ extern const char *frr_get_progname(void); extern enum frr_cli_mode frr_get_cli_mode(void); extern uint32_t frr_get_fd_limit(void); extern bool frr_is_startup_fd(int fd); - +extern bool frr_is_daemon(void); /* call order of these hooks is as ordered here */ DECLARE_HOOK(frr_early_init, (struct event_loop * tm), (tm)); DECLARE_HOOK(frr_late_init, (struct event_loop * tm), (tm)); @@ -220,10 +227,39 @@ extern void frr_fini(void); extern char config_default[512]; extern char frr_zclientpath[512]; + +/* refer to lib/config_paths.h (generated during ./configure) for build config + * values of the following: + */ + +/* sysconfdir is generally /etc/frr/, some BSDs may use /usr/local/etc/frr/. + * Will NOT include "pathspace" (namespace) suffix from -N. (libfrr.c handles + * pathspace'ing config files.) Has a slash at the end for "historical" + * reasons. + */ extern const char frr_sysconfdir[]; + +/* runstatedir is *ephemeral* across reboots. It may either be a ramdisk, + * or be wiped during boot. Use only for pid files, sockets, and the like, + * not state. Commonly /run/frr or /var/run/frr. + * Will include "pathspace" (namespace) suffix from -N. + */ extern char frr_runstatedir[256]; + +/* libstatedir is *persistent*. It's the place to put state like sequence + * numbers or databases. Commonly /var/lib/frr. + * Will include "pathspace" (namespace) suffix from -N. + */ extern char frr_libstatedir[256]; + +/* moduledir is something along the lines of /usr/lib/frr/modules or + * /usr/lib/x86_64-linux-gnu/frr/modules. It is not guaranteed to be a + * subdirectory of the directory that the daemon binaries reside in. (e.g. + * the "x86_64-linux-gnu" component will be absent from daemon paths.) + */ extern const char frr_moduledir[]; + +/* scriptdir is for Lua scripts, generally ${frr_sysconfdir}/scripts */ extern const char frr_scriptdir[]; extern char frr_protoname[]; diff --git a/lib/libospf.h b/lib/libospf.h index 0ac490a0..8a208beb 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -58,8 +58,10 @@ extern "C" { #define OSPF_HELLO_DELAY_DEFAULT 10 #define OSPF_ROUTER_PRIORITY_DEFAULT 1 #define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5 +#define OSPF_RETRANSMIT_WINDOW_DEFAULT 50 /* milliseconds */ #define OSPF_TRANSMIT_DELAY_DEFAULT 1 #define OSPF_DEFAULT_BANDWIDTH 10000 /* Mbps */ +#define OSPF_ACK_DELAY_DEFAULT 1 #define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */ diff --git a/lib/link_state.c b/lib/link_state.c index c758b7f5..3d96c75f 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -414,6 +414,13 @@ int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2) || (p1->sr.sid_flag != p2->sr.sid_flag)) return 0; } + if (CHECK_FLAG(p1->flags, LS_PREF_SRV6)) { + if (memcmp(&p1->srv6.sid, &p2->srv6.sid, + sizeof(struct in6_addr)) || + (p1->srv6.flags != p2->srv6.flags) || + (p1->srv6.behavior != p2->srv6.behavior)) + return 0; + } /* OK, p1 & p2 are equal */ return 1; @@ -1388,6 +1395,11 @@ static struct ls_prefix *ls_parse_prefix(struct stream *s) STREAM_GETC(s, ls_pref->sr.sid_flag); STREAM_GETC(s, ls_pref->sr.algo); } + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + STREAM_GET(&ls_pref->srv6.sid, s, sizeof(struct in6_addr)); + STREAM_GETW(s, ls_pref->srv6.behavior); + STREAM_GETC(s, ls_pref->srv6.flags); + } return ls_pref; @@ -1632,6 +1644,11 @@ static int ls_format_prefix(struct stream *s, struct ls_prefix *ls_pref) stream_putc(s, ls_pref->sr.sid_flag); stream_putc(s, ls_pref->sr.algo); } + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + stream_put(s, &ls_pref->srv6.sid, sizeof(struct in6_addr)); + stream_putw(s, ls_pref->srv6.behavior); + stream_putc(s, ls_pref->srv6.flags); + } return 0; } @@ -2748,6 +2765,13 @@ static void ls_show_subnet_vty(struct ls_subnet *subnet, struct vty *vty, sbuf_push(&sbuf, 4, "SID: %d\tAlgorithm: %d\tFlags: 0x%x\n", pref->sr.sid, pref->sr.algo, pref->sr.sid_flag); + if (CHECK_FLAG(pref->flags, LS_PREF_SRV6)) + sbuf_push(&sbuf, 4, + "SIDv6: %pI6\tEndpoint behavior: %s\tFlags: 0x%x\n", + &pref->srv6.sid, + seg6local_action2str(pref->srv6.behavior), + pref->srv6.flags); + end: vty_out(vty, "%s\n", sbuf_buf(&sbuf)); sbuf_free(&sbuf); @@ -2757,7 +2781,7 @@ static void ls_show_subnet_json(struct ls_subnet *subnet, struct json_object *json) { struct ls_prefix *pref; - json_object *jsr; + json_object *jsr, *jsrv6; char buf[INET6_BUFSIZ]; pref = subnet->ls_pref; @@ -2787,6 +2811,16 @@ static void ls_show_subnet_json(struct ls_subnet *subnet, snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->sr.sid_flag); json_object_string_add(jsr, "flags", buf); } + if (CHECK_FLAG(pref->flags, LS_PREF_SRV6)) { + jsrv6 = json_object_new_object(); + json_object_object_add(json, "segment-routing-ipv6", jsrv6); + snprintfrr(buf, INET6_BUFSIZ, "%pI6", &pref->srv6.sid); + json_object_string_add(jsrv6, "sid", buf); + json_object_string_add(jsrv6, "behavior", + seg6local_action2str(pref->srv6.behavior)); + snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->srv6.flags); + json_object_string_add(jsrv6, "flags", buf); + } } void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty, diff --git a/lib/link_state.h b/lib/link_state.h index d819c20d..c54e2ec6 100644 --- a/lib/link_state.h +++ b/lib/link_state.h @@ -243,6 +243,7 @@ struct ls_attributes { #define LS_PREF_EXTENDED_TAG 0x04 #define LS_PREF_METRIC 0x08 #define LS_PREF_SR 0x10 +#define LS_PREF_SRV6 0x20 /* Link State Prefix */ struct ls_prefix { @@ -258,6 +259,11 @@ struct ls_prefix { uint8_t sid_flag; /* Segment Routing Flags */ uint8_t algo; /* Algorithm for Segment Routing */ } sr; + struct ls_srv6_sid { + struct in6_addr sid; /* Segment Routing ID */ + uint16_t behavior; /* Endpoint behavior bound to the SID */ + uint8_t flags; /* Flags */ + } srv6; }; /** diff --git a/lib/linklist.h b/lib/linklist.h index fd953d07..f922891d 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -10,6 +10,18 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new list structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. + */ + /* listnodes must always contain data to be valid. Adding an empty node * to a list is invalid */ diff --git a/lib/log.c b/lib/log.c index 969ca792..04b789b5 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), @@ -436,6 +435,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_SRV6_LOCATOR_DELETE), DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK), DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_SRV6_SID), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID), DESC_ENTRY(ZEBRA_ERROR), DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES), DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE), @@ -461,7 +463,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_TC_CLASS_DELETE), DESC_ENTRY(ZEBRA_TC_FILTER_ADD), DESC_ENTRY(ZEBRA_TC_FILTER_DELETE), - DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY) + DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY), + DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY) }; #undef DESC_ENTRY diff --git a/lib/memory.c b/lib/memory.c index 8fbe5c40..ac39516e 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 65b99a5f..8e8c61da 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 6e2fb05e..f03006ad 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 7ad0589b..6ed8c2a3 100644 --- a/lib/mgmt_be_client.h +++ b/lib/mgmt_be_client.h @@ -121,11 +121,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). * diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c index 8cfb025f..ced2f2e4 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 20c87044..2b5a25fa 100644 --- a/lib/mgmt_fe_client.h +++ b/lib/mgmt_fe_client.h @@ -178,11 +178,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. * diff --git a/lib/mgmt_msg_native.c b/lib/mgmt_msg_native.c index 39ce9aba..b85c7d1b 100644 --- a/lib/mgmt_msg_native.c +++ b/lib/mgmt_msg_native.c @@ -6,6 +6,7 @@ * */ #include +#include "darr.h" #include "mgmt_msg_native.h" DEFINE_MGROUP(MSG_NATIVE, "Native message allocations"); @@ -18,6 +19,33 @@ DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT, "native edit msg"); DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT_REPLY, "native edit reply msg"); DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC, "native RPC msg"); DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC_REPLY, "native RPC reply msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REQ, "native session-req msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REPLY, "native session-reply msg"); + + +size_t mgmt_msg_min_sizes[] = { + [MGMT_MSG_CODE_ERROR] = sizeof(struct mgmt_msg_error), + [MGMT_MSG_CODE_GET_TREE] = sizeof(struct mgmt_msg_get_tree), + [MGMT_MSG_CODE_TREE_DATA] = sizeof(struct mgmt_msg_tree_data), + [MGMT_MSG_CODE_GET_DATA] = sizeof(struct mgmt_msg_get_data), + [MGMT_MSG_CODE_NOTIFY] = sizeof(struct mgmt_msg_notify_data), + [MGMT_MSG_CODE_EDIT] = sizeof(struct mgmt_msg_edit), + [MGMT_MSG_CODE_EDIT_REPLY] = sizeof(struct mgmt_msg_edit_reply), + [MGMT_MSG_CODE_RPC] = sizeof(struct mgmt_msg_rpc), + [MGMT_MSG_CODE_RPC_REPLY] = sizeof(struct mgmt_msg_rpc_reply), + [MGMT_MSG_CODE_NOTIFY_SELECT] = sizeof(struct mgmt_msg_notify_select), + [MGMT_MSG_CODE_SESSION_REQ] = sizeof(struct mgmt_msg_session_req), + [MGMT_MSG_CODE_SESSION_REPLY] = sizeof(struct mgmt_msg_session_reply), +}; +size_t nmgmt_msg_min_sizes = sizeof(mgmt_msg_min_sizes) / + sizeof(*mgmt_msg_min_sizes); + +size_t mgmt_msg_get_min_size(uint code) +{ + if (code >= nmgmt_msg_min_sizes) + return 0; + return mgmt_msg_min_sizes[code]; +} int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id, uint64_t req_id, bool short_circuit_ok, @@ -50,3 +78,20 @@ int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id, mgmt_msg_native_free_msg(msg); return ret; } + +const char **_mgmt_msg_native_strings_decode(const void *_sdata, int sdlen) +{ + const char *sdata = _sdata; + const char **strings = NULL; + int len; + + if (sdata[sdlen - 1] != 0) + return NULL; + + for (; sdlen; sdata += len, sdlen -= len) { + *darr_append(strings) = darr_strdup(sdata); + len = 1 + darr_strlen(strings[darr_lasti(strings)]); + } + + return strings; +} diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index 21f702cc..ef03b66e 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -163,6 +163,8 @@ DECLARE_MTYPE(MSG_NATIVE_EDIT); DECLARE_MTYPE(MSG_NATIVE_EDIT_REPLY); DECLARE_MTYPE(MSG_NATIVE_RPC); DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY); +DECLARE_MTYPE(MSG_NATIVE_SESSION_REQ); +DECLARE_MTYPE(MSG_NATIVE_SESSION_REPLY); /* * Native message codes @@ -176,6 +178,9 @@ DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY); #define MGMT_MSG_CODE_EDIT_REPLY 6 /* Public API */ #define MGMT_MSG_CODE_RPC 7 /* Public API */ #define MGMT_MSG_CODE_RPC_REPLY 8 /* Public API */ +#define MGMT_MSG_CODE_NOTIFY_SELECT 9 /* Public API */ +#define MGMT_MSG_CODE_SESSION_REQ 10 /* Public API */ +#define MGMT_MSG_CODE_SESSION_REPLY 11 /* Public API */ /* * Datastores @@ -378,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[]; }; @@ -426,12 +438,72 @@ _Static_assert(sizeof(struct mgmt_msg_rpc_reply) == offsetof(struct mgmt_msg_rpc_reply, data), "Size mismatch"); +/** + * struct mgmt_msg_notify_select - Add notification selectors for FE client. + * + * Add xpath prefix notification selectors to limit the notifications sent + * to the front-end client. + * + * @selectors: the xpath prefixes to selectors notifications through. + * @replace: if true replace existing selectors with `selectors`. + */ +struct mgmt_msg_notify_select { + struct mgmt_msg_header; + uint8_t replace; + uint8_t resv2[7]; + + alignas(8) char selectors[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_notify_select) == + offsetof(struct mgmt_msg_notify_select, selectors), + "Size mismatch"); + +/** + * struct mgmt_msg_session_req - Create or delete a front-end session. + * + * @refer_id: Zero for create, otherwise the session-id to delete. + * @req_id: For create will use as client-id. + * @client_name: For first session request the client name, otherwise empty. + */ +struct mgmt_msg_session_req { + struct mgmt_msg_header; + uint8_t resv2[8]; /* bug in compiler produces error w/o this */ + + alignas(8) char client_name[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_session_req) == + offsetof(struct mgmt_msg_session_req, client_name), + "Size mismatch"); + +/** + * struct mgmt_msg_session_reply - Reply to session request message. + * + * @created: true if this is a reply to a create request, otherwise 0. + * @refer_id: The session-id for the action (create or delete) just taken. + */ +struct mgmt_msg_session_reply { + struct mgmt_msg_header; + uint8_t created; + uint8_t resv2[7]; +}; + /* * Validate that the message ends in a NUL terminating byte */ #define MGMT_MSG_VALIDATE_NUL_TERM(msgp, len) \ ((len) >= sizeof(*msgp) + 1 && ((char *)msgp)[(len)-1] == 0) +/** + * mgmt_msg_get_min_size() - Get minimum message size given the type + * @code: The type of the message (MGMT_MSG_CODE_*) + * + * Return: + * The minimum size of a message of the given type or 0 if the message + * code is unknown. + */ +size_t mgmt_msg_get_min_size(uint code); /** * Send a native message error to the other end of the connection. @@ -524,6 +596,25 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn, p; \ }) +/** + * mgmt_msg_native_add_str() - Append [another] string to the msg. + * @msg: (IN/OUT) Pointer to the native message, variable may be updated. + * @s: string to append. + * + * Append string @s to the native message @msg. @msg is assumed to have a + * sequence of NUL-terminated strings at the end of it. This function appends + * the string @s and it's NUL terminating octet to the message. + * + * NOTE: Be aware @msg pointer may change as a result of reallocating the + * message to fit the new data. Any other pointers into the old message should + * be discarded. + */ +#define mgmt_msg_native_add_str(msg, s) \ + do { \ + int __len = strlen(s) + 1; \ + mgmt_msg_native_append(msg, s, __len); \ + } while (0) + /** * mgmt_msg_native_send_msg(msg, short_circuit_ok) - Send a native msg. * @conn: the mgmt_msg connection. @@ -689,6 +780,27 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn, #define mgmt_msg_native_data_len_decode(msg, msglen) \ ((msglen) - sizeof(*msg) - msg->vsplit) +/** + * mgmt_msg_native_strings_decode() - Get dynamic array of str ptrs from the msg. + * @msg: Pointer to the native message. + * @msglen: Length of the message. + * @sdata: pointer to the variable length string data at end of @msg. + * + * Given a pointer to a sequence of NUL-terminated strings allocate + * and return a dynamic array of dynamic array strings. This function + * can be used to decode a message that was built using + * mgmt_msg_native_add_str(). + * + * Return: a dynamic array (darr) of string pointers, or NULL if the message + * is corrupt. + */ +#define mgmt_msg_native_strings_decode(msg, msg_len, sdata) \ + _mgmt_msg_native_strings_decode(sdata, \ + (msg_len) - ((sdata) - (char *)(msg))) + +extern const char **_mgmt_msg_native_strings_decode(const void *sdata, + int sdlen); + #ifdef __cplusplus } #endif diff --git a/lib/module.c b/lib/module.c index af7d20c3..9d178bb0 100644 --- a/lib/module.c +++ b/lib/module.c @@ -202,3 +202,15 @@ void frrmod_unload(struct frrmod_runtime *module) { } #endif + +void frrmod_terminate(void) +{ + struct frrmod_runtime *rtinfo = frrmod_list; + + while (rtinfo) { + XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); + XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); + + rtinfo = rtinfo->next; + } +} diff --git a/lib/module.h b/lib/module.h index cd2be474..1810b335 100644 --- a/lib/module.h +++ b/lib/module.h @@ -79,6 +79,7 @@ extern union _frrmod_runtime_u _frrmod_this_module; extern struct frrmod_runtime *frrmod_list; extern void frrmod_init(struct frrmod_runtime *modinfo); +extern void frrmod_terminate(void); extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, void (*pFerrlog)(const void *, const char *), diff --git a/lib/nexthop.c b/lib/nexthop.c index 26c33825..98b05295 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) { @@ -1166,6 +1189,7 @@ void nexthop_json_helper(json_object *json_nexthop, json_object *json_labels = NULL; json_object *json_backups = NULL; json_object *json_seg6local = NULL; + json_object *json_seg6local_context = NULL; json_object *json_seg6 = NULL; json_object *json_segs = NULL; int i; @@ -1331,8 +1355,16 @@ void nexthop_json_helper(json_object *json_nexthop, seg6local_action2str( nexthop->nh_srv6 ->seg6local_action)); + json_seg6local_context = json_object_new_object(); json_object_object_add(json_nexthop, "seg6local", json_seg6local); + + seg6local_context2json(&nexthop->nh_srv6->seg6local_ctx, + nexthop->nh_srv6->seg6local_action, + json_seg6local_context); + json_object_object_add(json_nexthop, "seg6localContext", + json_seg6local_context); + if (nexthop->nh_srv6->seg6_segs && nexthop->nh_srv6->seg6_segs->num_segs == 1) { json_seg6 = json_object_new_object(); diff --git a/lib/nexthop.h b/lib/nexthop.h index 27073b94..02ea4d96 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 3f408e0a..cb1ebb5d 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 822a3543..91032994 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 0bc79d02..a385cc9e 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 34d17a58..97a1d31e 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 4f962cda..f9794bee 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 5f38c970..a3ff3607 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 0ec7610a..1f4d036c 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -19,7 +19,9 @@ #include #include -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/openbsd-queue.h b/lib/openbsd-queue.h index df3bbd72..a2df521f 100644 --- a/lib/openbsd-queue.h +++ b/lib/openbsd-queue.h @@ -16,6 +16,22 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new queue structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. However, + * among converting datastrucutres, the the BSD ones are the lowest + * priority / should be converted last. They are already typesafe and + * use inline linking nodes, so the only gain is consistency. Please + * convert uses of linklist.h and hash.h first. + */ + /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues and XOR simple queues. diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h index 4f3985bb..ecc3a68f 100644 --- a/lib/openbsd-tree.h +++ b/lib/openbsd-tree.h @@ -10,6 +10,21 @@ #ifdef __cplusplus extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new tree structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. However, + * among converting datastrucutres, the the BSD ones are the lowest + * priority / should be converted last. They are already typesafe and + * use inline linking nodes, so the only gain is consistency. Please + * convert uses of linklist.h and hash.h first. + */ /* * This file defines data structures for different types of trees: diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 8e2e497e..f64c3c23 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -417,6 +417,74 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } +DEFUN_YANG (match_ipv6_next_hop, + match_ipv6_next_hop_cmd, + "match ipv6 next-hop ACCESSLIST6_NAME", + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 access-list name\n") +{ + const char *xpath = "./match-condition[condition='frr-route-map:ipv6-next-hop-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-match-condition/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[argc - 1]->arg); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_match_ipv6_next_hop, + no_match_ipv6_next_hop_cmd, + "no match ipv6 next-hop [ACCESSLIST6_NAME]", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 access-list name\n") +{ + const char *xpath = "./match-condition[condition='frr-route-map:ipv6-next-hop-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (match_ipv6_next_hop_prefix_list, + match_ipv6_next_hop_prefix_list_cmd, + "match ipv6 next-hop prefix-list PREFIXLIST_NAME", + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "Match entries by prefix-list\n" + "IPv6 prefix-list name\n") +{ + const char *xpath = "./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-match-condition/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[argc - 1]->arg); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_match_ipv6_next_hop_prefix_list, + no_match_ipv6_next_hop_prefix_list_cmd, + "no match ipv6 next-hop prefix-list [PREFIXLIST_NAME]", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "Match entries by prefix-list\n" + "IPv6 prefix-list name\n") +{ + const char *xpath = "./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + DEFPY_YANG( match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd, "match ipv6 next-hop type $type", @@ -937,7 +1005,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']"; @@ -1665,6 +1733,11 @@ void route_map_cli_init(void) install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd); install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd); + install_element(RMAP_NODE, &match_ipv6_next_hop_cmd); + install_element(RMAP_NODE, &match_ipv6_next_hop_prefix_list_cmd); + install_element(RMAP_NODE, &no_match_ipv6_next_hop_cmd); + install_element(RMAP_NODE, &no_match_ipv6_next_hop_prefix_list_cmd); + install_element(RMAP_NODE, &match_metric_cmd); install_element(RMAP_NODE, &no_match_metric_cmd); diff --git a/lib/seqlock.c b/lib/seqlock.c index 62ce3169..e74e6718 100644 --- a/lib/seqlock.c +++ b/lib/seqlock.c @@ -26,6 +26,39 @@ * OS specific synchronization wrappers * ****************************************/ +#ifndef __has_feature /* not available on old GCC */ +#define __has_feature(x) 0 +#endif + +#if (defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)) +/* TSAN really does not understand what is going on with the low-level + * futex/umtx calls. This leads to a whole bunch of warnings, a lot of which + * also have _extremely_ misleading text - since TSAN does not understand that + * there is in fact a synchronization primitive involved, it can end up pulling + * in completely unrelated things. + * + * What does work is the "unsupported platform" seqlock implementation based + * on a pthread mutex + condvar, since TSAN of course suppports these. + * + * It may be possible to also fix this with TSAN annotations (__tsan_acquire + * and __tsan_release), but using those (correctly) is not easy either, and + * for now just get things rolling. + */ + +#ifdef HAVE_SYNC_LINUX_FUTEX +#undef HAVE_SYNC_LINUX_FUTEX +#endif + +#ifdef HAVE_SYNC_OPENBSD_FUTEX +#undef HAVE_SYNC_OPENBSD_FUTEX +#endif + +#ifdef HAVE_SYNC_UMTX_OP +#undef HAVE_SYNC_UMTX_OP +#endif + +#endif /* TSAN */ + /* * Linux: sys_futex() */ diff --git a/lib/smux.h b/lib/smux.h index 8ec847af..0ed41410 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -101,6 +101,7 @@ extern bool smux_enabled(void); extern void libagentx_init(void); extern void smux_init(struct event_loop *tm); +extern void smux_terminate(void); extern void smux_agentx_enable(void); extern void smux_register_mib(const char *, struct variable *, size_t, int, oid[], size_t); diff --git a/lib/sockopt.h b/lib/sockopt.h index ce7d665f..e6fb78d5 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -60,6 +60,16 @@ extern int setsockopt_ipv6_tclass(int, int); (((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \ ? SOPT_SIZE_CMSG_PKTINFO_IPV6()) +/* + * If not defined then define the value for `TCP_MD5SIG_MAXKEYLEN`. This seems + * to be unavailable for NetBSD 8, FreeBSD 11 and FreeBSD 12. + * + * The value below was copied from `linux/tcp.h` from the Linux kernel headers. + */ +#ifndef TCP_MD5SIG_MAXKEYLEN +#define TCP_MD5SIG_MAXKEYLEN 80 +#endif + extern int setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr, ifindex_t ifindex); extern int setsockopt_ipv4_multicast(int sock, int optname, diff --git a/lib/srv6.c b/lib/srv6.c index a82103e4..e6fc375f 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -10,8 +10,11 @@ #include "log.h" DEFINE_QOBJ_TYPE(srv6_locator); +DEFINE_QOBJ_TYPE(srv6_sid_format); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR, "SRV6 locator"); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR_CHUNK, "SRV6 locator chunk"); +DEFINE_MTYPE_STATIC(LIB, SRV6_SID_FORMAT, "SRv6 SID format"); +DEFINE_MTYPE_STATIC(LIB, SRV6_SID_CTX, "SRv6 SID context"); const char *seg6local_action2str(uint32_t action) { @@ -68,6 +71,44 @@ int snprintf_seg6_segs(char *str, return strlen(str); } +void seg6local_context2json(const struct seg6local_context *ctx, + uint32_t action, json_object *json) +{ + switch (action) { + case ZEBRA_SEG6_LOCAL_ACTION_END: + json_object_boolean_add(json, "USP", true); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + json_object_string_addf(json, "nh6", "%pI6", &ctx->nh6); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + json_object_string_addf(json, "nh4", "%pI4", &ctx->nh4); + return; + 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: + json_object_int_add(json, "table", ctx->table); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: + json_object_boolean_add(json, "none", true); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_B6: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + json_object_string_addf(json, "nh6", "%pI6", &ctx->nh6); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_BM: + case ZEBRA_SEG6_LOCAL_ACTION_END_S: + case ZEBRA_SEG6_LOCAL_ACTION_END_AS: + case ZEBRA_SEG6_LOCAL_ACTION_END_AM: + case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: + default: + json_object_boolean_add(json, "unknown", true); + return; + } +} + const char *seg6local_context2str(char *str, size_t size, const struct seg6local_context *ctx, uint32_t action) @@ -139,6 +180,21 @@ struct srv6_locator_chunk *srv6_locator_chunk_alloc(void) return chunk; } +void srv6_locator_copy(struct srv6_locator *copy, + const struct srv6_locator *locator) +{ + strlcpy(copy->name, locator->name, sizeof(locator->name)); + copy->prefix = locator->prefix; + copy->block_bits_length = locator->block_bits_length; + copy->node_bits_length = locator->node_bits_length; + copy->function_bits_length = locator->function_bits_length; + copy->argument_bits_length = locator->argument_bits_length; + copy->algonum = locator->algonum; + copy->current = locator->current; + copy->status_up = locator->status_up; + copy->flags = locator->flags; +} + void srv6_locator_free(struct srv6_locator *locator) { if (locator) { @@ -154,6 +210,59 @@ void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk) XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk); } +struct srv6_sid_format *srv6_sid_format_alloc(const char *name) +{ + struct srv6_sid_format *format = NULL; + + format = XCALLOC(MTYPE_SRV6_SID_FORMAT, sizeof(struct srv6_sid_format)); + strlcpy(format->name, name, sizeof(format->name)); + + QOBJ_REG(format, srv6_sid_format); + return format; +} + +void srv6_sid_format_free(struct srv6_sid_format *format) +{ + if (!format) + return; + + QOBJ_UNREG(format); + XFREE(MTYPE_SRV6_SID_FORMAT, format); +} + +/** + * Free an SRv6 SID format. + * + * @param val SRv6 SID format to be freed + */ +void delete_srv6_sid_format(void *val) +{ + srv6_sid_format_free((struct srv6_sid_format *)val); +} + +struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior, + struct in_addr *nh4, + struct in6_addr *nh6, vrf_id_t vrf_id) +{ + struct srv6_sid_ctx *ctx = NULL; + + ctx = XCALLOC(MTYPE_SRV6_SID_CTX, sizeof(struct srv6_sid_ctx)); + ctx->behavior = behavior; + if (nh4) + ctx->nh4 = *nh4; + if (nh6) + ctx->nh6 = *nh6; + if (vrf_id) + ctx->vrf_id = vrf_id; + + return ctx; +} + +void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx) +{ + XFREE(MTYPE_SRV6_SID_CTX, ctx); +} + json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) { json_object *jo_root = NULL; @@ -223,23 +332,47 @@ json_object *srv6_locator_json(const struct srv6_locator *loc) /* set prefix */ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); - /* set block_bits_length */ - json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); - - /* set node_bits_length */ - json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); - - /* set function_bits_length */ - json_object_int_add(jo_root, "functionBitsLength", - loc->function_bits_length); - - /* set argument_bits_length */ - json_object_int_add(jo_root, "argumentBitsLength", - loc->argument_bits_length); - - /* set true if the locator is a Micro-segment (uSID) locator */ - if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) - json_object_string_add(jo_root, "behavior", "usid"); + if (loc->sid_format) { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->sid_format->block_len); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->sid_format->node_len); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->sid_format->function_len); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->sid_format->argument_len); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) + json_object_string_add(jo_root, "behavior", "usid"); + } else { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->block_bits_length); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->node_bits_length); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->function_bits_length); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->argument_bits_length); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + } /* set status_up */ json_object_boolean_add(jo_root, "statusUp", @@ -272,23 +405,47 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) /* set prefix */ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); - /* set block_bits_length */ - json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); - - /* set node_bits_length */ - json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); - - /* set function_bits_length */ - json_object_int_add(jo_root, "functionBitsLength", - loc->function_bits_length); - - /* set argument_bits_length */ - json_object_int_add(jo_root, "argumentBitsLength", - loc->argument_bits_length); - - /* set true if the locator is a Micro-segment (uSID) locator */ - if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) - json_object_string_add(jo_root, "behavior", "usid"); + if (loc->sid_format) { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->sid_format->block_len); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->sid_format->node_len); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->sid_format->function_len); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->sid_format->argument_len); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) + json_object_string_add(jo_root, "behavior", "usid"); + } else { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->block_bits_length); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->node_bits_length); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->function_bits_length); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->argument_bits_length); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + } /* set algonum */ json_object_int_add(jo_root, "algoNum", loc->algonum); diff --git a/lib/srv6.h b/lib/srv6.h index 433c5c14..9a041e3d 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -20,6 +20,8 @@ #define SRH_BASE_HEADER_LENGTH 8 #define SRH_SEGMENT_LENGTH 16 +#define SRV6_SID_FORMAT_NAME_SIZE 512 + #ifdef __cplusplus extern "C" { #endif @@ -104,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 { @@ -127,6 +133,12 @@ struct srv6_locator { uint8_t flags; #define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */ + /* Pointer to the SID format. */ + struct srv6_sid_format *sid_format; + + /* Pointer to the parent SID block of the locator. */ + void *sid_block; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(srv6_locator); @@ -183,6 +195,72 @@ struct nexthop_srv6 { struct seg6_seg_stack *seg6_segs; }; +/* SID format type */ +enum srv6_sid_format_type { + SRV6_SID_FORMAT_TYPE_UNSPEC = 0, + /* SRv6 SID uncompressed format */ + SRV6_SID_FORMAT_TYPE_UNCOMPRESSED = 1, + /* SRv6 SID compressed uSID format */ + SRV6_SID_FORMAT_TYPE_USID = 2, +}; + +/* SRv6 SID format */ +struct srv6_sid_format { + /* Name of the format */ + char name[SRV6_SID_FORMAT_NAME_SIZE]; + + /* Format type: uncompressed vs compressed */ + enum srv6_sid_format_type type; + + /* + * Lengths of block/node/function/argument parts of the SIDs allocated + * using this format + */ + uint8_t block_len; + uint8_t node_len; + uint8_t function_len; + uint8_t argument_len; + + union { + /* Configuration settings for compressed uSID format type */ + struct { + /* Start of the Local ID Block (LIB) range */ + uint32_t lib_start; + + /* Start/End of the Explicit LIB range */ + uint32_t elib_start; + uint32_t elib_end; + + /* Start/End of the Wide LIB range */ + uint32_t wlib_start; + uint32_t wlib_end; + + /* Start/End of the Explicit Wide LIB range */ + uint32_t ewlib_start; + } usid; + + /* Configuration settings for uncompressed format type */ + struct { + /* Start of the Explicit range */ + uint32_t explicit_start; + } uncompressed; + } config; + + QOBJ_FIELDS; +}; +DECLARE_QOBJ_TYPE(srv6_sid_format); + +/* Context for an SRv6 SID */ +struct srv6_sid_ctx { + /* Behavior associated with the SID */ + enum seg6local_action_t behavior; + + /* Behavior-specific attributes */ + struct in_addr nh4; + struct in6_addr nh6; + vrf_id_t vrf_id; +}; + static inline const char *seg6_mode2str(enum seg6_mode_t mode) { switch (mode) { @@ -245,6 +323,55 @@ seg6local_action2str(uint32_t action); const char *seg6local_context2str(char *str, size_t size, const struct seg6local_context *ctx, uint32_t action); +void seg6local_context2json(const struct seg6local_context *ctx, + uint32_t action, json_object *json); + +static inline const char *srv6_sid_ctx2str(char *str, size_t size, + const struct srv6_sid_ctx *ctx) +{ + int len = 0; + + len += snprintf(str + len, size - len, "%s", + seg6local_action2str(ctx->behavior)); + + switch (ctx->behavior) { + case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END: + snprintf(str + len, size - len, " USP"); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + snprintfrr(str + len, size - len, " nh6 %pI6", &ctx->nh6); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + 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: + snprintf(str + len, size - len, " vrf_id %u", ctx->vrf_id); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + case ZEBRA_SEG6_LOCAL_ACTION_END_BM: + case ZEBRA_SEG6_LOCAL_ACTION_END_S: + case ZEBRA_SEG6_LOCAL_ACTION_END_AS: + case ZEBRA_SEG6_LOCAL_ACTION_END_AM: + case ZEBRA_SEG6_LOCAL_ACTION_END_BPF: + default: + snprintf(str + len, size - len, " unknown(%s)", __func__); + } + + return str; +} int snprintf_seg6_segs(char *str, size_t size, const struct seg6_segs *segs); @@ -254,12 +381,24 @@ extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void); extern void srv6_locator_free(struct srv6_locator *locator); extern void srv6_locator_chunk_list_free(void *data); extern void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk); +extern void srv6_locator_copy(struct srv6_locator *copy, + const struct srv6_locator *locator); json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk); json_object *srv6_locator_json(const struct srv6_locator *loc); json_object *srv6_locator_detailed_json(const struct srv6_locator *loc); json_object * srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk); +extern struct srv6_sid_format *srv6_sid_format_alloc(const char *name); +extern void srv6_sid_format_free(struct srv6_sid_format *format); +extern void delete_srv6_sid_format(void *format); + +extern struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior, + struct in_addr *nh4, + struct in6_addr *nh6, + vrf_id_t vrf_id); +extern void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx); + #ifdef __cplusplus } #endif diff --git a/lib/subdir.am b/lib/subdir.am index 3264f31a..4bcce9a2 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -504,20 +504,41 @@ SUFFIXES += .xref %.xref: % $(CLIPPY) $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py $(WERROR) $(XRELFO_FLAGS) -o $@ $< +# these run up to a total of 350k lines at the time of writing. That's a lot +# for the compiler to chug down - enough to warrant splitting it up so it can +# benefit from parallel build. +vtysh_cmd_split = \ + vtysh/vtysh_cmd.1.c \ + vtysh/vtysh_cmd.2.c \ + vtysh/vtysh_cmd.3.c \ + vtysh/vtysh_cmd.4.c \ + vtysh/vtysh_cmd.5.c \ + vtysh/vtysh_cmd.6.c \ + vtysh/vtysh_cmd.7.c \ + vtysh/vtysh_cmd.8.c \ + # end + # dependencies added in python/makefile.py frr.xref: - $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ -c vtysh/vtysh_cmd.c $^ + $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^ \ + -c vtysh/vtysh_cmd.c $(vtysh_cmd_split) all-am: frr.xref clean-xref: -rm -rf $(xrefs) frr.xref clean-local: clean-xref -CLEANFILES += vtysh/vtysh_cmd.c vtysh/vtysh_cmd.c: frr.xref @test -f $@ || rm -f frr.xref || true @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) frr.xref +vtysh/vtysh_cmd.%.c: vtysh/vtysh_cmd.c + @test -f $@ || rm -f vtysh/vtysh_cmd.c || true + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) vtysh/vtysh_cmd.c + +nodist_vtysh_vtysh_SOURCES = vtysh/vtysh_cmd.c $(vtysh_cmd_split) +CLEANFILES += vtysh/vtysh_cmd.c $(vtysh_cmd_split) + ## automake's "ylwrap" is a great piece of GNU software... not. .l.c: $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $< diff --git a/lib/termtable.c b/lib/termtable.c index 9b36d5eb..ce197013 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) { @@ -496,7 +496,9 @@ char *ttable_dump(struct ttable *tt, const char *newline) * l int64 * s string (default) */ -json_object *ttable_json(struct ttable *tt, const char *const formats) +static json_object *ttable_json_internal(struct ttable *tt, + const char *const formats, + const char *row_text[]) { struct ttable_cell *row; /* iteration pointers */ json_object *json = NULL; @@ -522,9 +524,55 @@ json_object *ttable_json(struct ttable *tt, const char *const formats) default: val = json_object_new_string(row[j].text); } - json_object_object_add(jobj, tt->table[0][j].text, val); + if (row_text) + json_object_object_add(jobj, row_text[j], val); + else + json_object_object_add(jobj, + tt->table[0][j].text, + val); } } return json; } + +json_object *ttable_json(struct ttable *tt, const char *const formats) +{ + return ttable_json_internal(tt, formats, NULL); +} + +json_object *ttable_json_with_json_text(struct ttable *tt, + const char *const formats, + const char *json_override_text) +{ + char **row_name; /* iteration pointers */ + char *res, *section, *orig; + int col = 0; + int ncols = 0, j; + json_object *json = NULL; + + if (json_override_text) { + /* count how many columns we have */ + for (j = 0; json_override_text[j]; j++) + ncols += !!(json_override_text[j] == '|'); + ncols++; + } + if (json_override_text == NULL || ncols != tt->ncols) + return ttable_json_internal(tt, formats, NULL); + + /* CALLOC a block of cells */ + row_name = XCALLOC(MTYPE_TTABLE, ncols * sizeof(char *)); + orig = XSTRDUP(MTYPE_TTABLE, json_override_text); + res = orig; + while (res && col < ncols) { + section = strsep(&res, "|"); + row_name[col] = XSTRDUP(MTYPE_TTABLE, section); + col++; + } + json = ttable_json_internal(tt, formats, (const char **)row_name); + for (j = 0; j < col; j++) + XFREE(MTYPE_TTABLE, row_name[j]); + XFREE(MTYPE_TTABLE, row_name); + XFREE(MTYPE_TTABLE, orig); + return json; +} diff --git a/lib/termtable.h b/lib/termtable.h index 7258682b..d284c4f3 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. @@ -289,6 +289,21 @@ char *ttable_dump(struct ttable *tt, const char *newline); */ json_object *ttable_json(struct ttable *tt, const char *const formats); +/** + * Convert a table to a JSON array of objects. + * + * Caller must free the returned json_object structure. + * + * @param tt the table to convert + * @param formats an array of characters indicating what JSON type should be + * used. + * @param formats an optinal string of row headers that overrids the first row of the table. + * This is useful to get naming convention that align with caml Format. + */ +json_object *ttable_json_with_json_text(struct ttable *tt, + const char *const formats, + const char *json_override_text); + #ifdef __cplusplus } #endif diff --git a/lib/vector.c b/lib/vector.c index 60d38310..06361549 100644 --- a/lib/vector.c +++ b/lib/vector.c @@ -24,45 +24,44 @@ vector vector_init(unsigned int size) v->alloced = size; v->active = 0; v->count = 0; + v->dynamic = true; v->index = XCALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * size); return v; } void vector_free(vector v) { - XFREE(MTYPE_VECTOR_INDEX, v->index); - XFREE(MTYPE_VECTOR, v); + if (v->alloced) + XFREE(MTYPE_VECTOR_INDEX, v->index); + if (v->dynamic) + XFREE(MTYPE_VECTOR, v); } -vector vector_copy(vector v) -{ - unsigned int size; - vector new = XCALLOC(MTYPE_VECTOR, sizeof(struct _vector)); - - new->active = v->active; - new->alloced = v->alloced; - new->count = v->count; - - size = sizeof(void *) * (v->alloced); - new->index = XCALLOC(MTYPE_VECTOR_INDEX, size); - memcpy(new->index, v->index, size); - - return new; -} - -/* Check assigned index, and if it runs short double index pointer */ +/* resize vector to a minimum of num + * may resize larger to avoid excessive realloc overhead + */ void vector_ensure(vector v, unsigned int num) { + unsigned int newsz; + if (v->alloced > num) return; - v->index = XREALLOC(MTYPE_VECTOR_INDEX, v->index, - sizeof(void *) * (v->alloced * 2)); - memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced); - v->alloced *= 2; + newsz = MAX(v->active * 2, num + 1); + + if (!v->alloced && v->index) { + /* currently using global variable, not malloc'd memory */ + void **orig_index = v->index; - if (v->alloced <= num) - vector_ensure(v, num); + v->index = XMALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * newsz); + memcpy(v->index, orig_index, v->active * sizeof(void *)); + v->alloced = v->active; + } else + v->index = XREALLOC(MTYPE_VECTOR_INDEX, v->index, + sizeof(void *) * newsz); + + memset(&v->index[v->alloced], 0, sizeof(void *) * (newsz - v->alloced)); + v->alloced = newsz; } /* This function only returns next empty slot index. It dose not mean @@ -140,7 +139,7 @@ void *vector_lookup_ensure(vector v, unsigned int i) /* Unset value at specified index slot. */ void vector_unset(vector v, unsigned int i) { - if (i >= v->alloced) + if (i >= v->active) return; if (v->index[i]) diff --git a/lib/vector.h b/lib/vector.h index fcbc1325..ae05d4d3 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -15,9 +15,26 @@ extern "C" { /* struct for vector */ struct _vector { - unsigned int active; /* number of active slots */ - unsigned int alloced; /* number of allocated slot */ + /* active: index of last non-NULL item (+1) + * count: number of non-NULL items (+1) + * + * the two will be different if a slot is set to NULL (without pulling + * up later items in the array). Whether this happens depends on + * which vector functions are used. If no empty slots are used, the + * two fields will be identical. + * + * alloced: size of array pointed to by index. If this is 0, index + * points at a global variable rather than a malloc'd bit of memory. + * The vector code will convert to malloc'd memory if necessary to + * perform updates. + */ + unsigned int active; + unsigned int alloced; unsigned int count; + + /* whether struct _vector itself is dynamically allocated */ + bool dynamic; + void **index; /* index to data */ }; typedef struct _vector *vector; @@ -51,7 +68,6 @@ static inline unsigned int vector_count(vector v) } extern void vector_free(vector v); -extern vector vector_copy(vector v); extern void *vector_lookup(vector, unsigned int); extern void *vector_lookup_ensure(vector, unsigned int); diff --git a/lib/vty.c b/lib/vty.c index d0bbf0e6..256a3bb3 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 c336a816..e511e8e7 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 6a8e5223..b847b8b7 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 57131f47..52857ecf 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 005f6422..b7599e0a 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.c b/lib/zclient.c index 1aab7b48..0e832f0d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1125,6 +1125,10 @@ int zapi_srv6_locator_encode(struct stream *s, const struct srv6_locator *l) stream_put(s, l->name, strlen(l->name)); stream_putw(s, l->prefix.prefixlen); stream_put(s, &l->prefix.prefix, sizeof(l->prefix.prefix)); + stream_putc(s, l->block_bits_length); + stream_putc(s, l->node_bits_length); + stream_putc(s, l->function_bits_length); + stream_putc(s, l->argument_bits_length); stream_putc(s, l->flags); return 0; } @@ -1141,6 +1145,10 @@ int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l) STREAM_GETW(s, l->prefix.prefixlen); STREAM_GET(&l->prefix.prefix, s, sizeof(l->prefix.prefix)); l->prefix.family = AF_INET6; + STREAM_GETC(s, l->block_bits_length); + STREAM_GETC(s, l->node_bits_length); + STREAM_GETC(s, l->function_bits_length); + STREAM_GETC(s, l->argument_bits_length); STREAM_GETC(s, l->flags); return 0; @@ -2125,6 +2133,46 @@ stream_failure: return false; } +bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t *func, + uint32_t *wide_func, + enum zapi_srv6_sid_notify *note, + char **p_locator_name) +{ + uint32_t f, wf; + uint16_t len; + static char locator_name[SRV6_LOCNAME_SIZE] = {}; + + STREAM_GET(note, s, sizeof(*note)); + STREAM_GET(ctx, s, sizeof(struct srv6_sid_ctx)); + STREAM_GET(sid_value, s, sizeof(struct in6_addr)); + STREAM_GETL(s, f); + STREAM_GETL(s, wf); + + if (func) + *func = f; + if (wide_func) + *wide_func = wf; + + STREAM_GETW(s, len); + if (len > SRV6_LOCNAME_SIZE) { + *p_locator_name = NULL; + return false; + } + if (p_locator_name) { + if (len == 0) + *p_locator_name = NULL; + else { + STREAM_GET(locator_name, s, len); + *p_locator_name = locator_name; + } + } + return true; + +stream_failure: + return false; +} + struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) { struct nexthop *n = nexthop_new(); @@ -2134,6 +2182,7 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) n->ifindex = znh->ifindex; n->gate = znh->gate; n->srte_color = znh->srte_color; + n->weight = znh->weight; /* * This function currently handles labels @@ -3268,10 +3317,154 @@ int srv6_manager_release_locator_chunk(struct zclient *zclient, return zclient_send_message(zclient); } +/** + * Function to request a SRv6 locator in an asynchronous way + * + * @param zclient The zclient used to connect to SRv6 Manager (zebra) + * @param locator_name Name of SRv6 locator + * @return 0 on success, -1 otherwise + */ +int srv6_manager_get_locator(struct zclient *zclient, const char *locator_name) +{ + struct stream *s; + size_t len; + + if (!locator_name) + return -1; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return -1; + } + + if (zclient_debug) + zlog_debug("Getting SRv6 Locator %s", locator_name); + + len = strlen(locator_name); + + /* Send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR, VRF_DEFAULT); + + /* Locator name */ + stream_putw(s, len); + stream_put(s, locator_name, len); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +/** + * Function to request an SRv6 SID in an asynchronous way + * + * @param zclient The zclient used to connect to SRv6 manager (zebra) + * @param ctx Context associated with the SRv6 SID + * @param sid_value SRv6 SID value for explicit SID allocation + * @param locator_name Name of the parent locator for dynamic SID allocation + * @param sid_func SID function assigned by the SRv6 Manager + * @result 0 on success, -1 otherwise + */ +int srv6_manager_get_sid(struct zclient *zclient, const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name, + uint32_t *sid_func) +{ + struct stream *s; + uint8_t flags = 0; + size_t len; + char buf[256]; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return ZCLIENT_SEND_FAILURE; + } + + if (zclient_debug) + zlog_debug("Getting SRv6 SID: %s", + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* send request */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_SRV6_SID, VRF_DEFAULT); + + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + + /* Flags */ + if (!sid_zero_ipv6(sid_value)) + SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE); + if (locator_name) + SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR); + stream_putc(s, flags); + + /* SRv6 SID value */ + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) + stream_put(s, sid_value, sizeof(struct in6_addr)); + + /* SRv6 locator */ + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) { + len = strlen(locator_name); + stream_putw(s, len); + stream_put(s, locator_name, len); + } + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + /* Send the request to SRv6 Manager */ + return zclient_send_message(zclient); +} + +/** + * Function to release an SRv6 SID + * + * @param zclient Zclient used to connect to SRv6 manager (zebra) + * @param ctx Context associated with the SRv6 SID to be removed + * @result 0 on success, -1 otherwise + */ +int srv6_manager_release_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx) +{ + struct stream *s; + char buf[256]; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return -1; + } + + if (zclient_debug) + zlog_debug("Releasing SRv6 SID: %s", + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* send request */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID, + VRF_DEFAULT); + + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + /* Send the SID release message */ + return zclient_send_message(zclient); +} + /* * Asynchronous label chunk request * - * @param zclient Zclient used to connect to label manager (zebra) + * @param zclient The zclient used to connect to label manager (zebra) * @param keep Avoid garbage collection * @param chunk_size Amount of labels requested * @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care diff --git a/lib/zclient.h b/lib/zclient.h index 3759f945..91c0c9ed 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, @@ -209,6 +208,9 @@ typedef enum { ZEBRA_SRV6_LOCATOR_DELETE, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, + ZEBRA_SRV6_MANAGER_GET_LOCATOR, + ZEBRA_SRV6_MANAGER_GET_SRV6_SID, + ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -235,6 +237,7 @@ typedef enum { ZEBRA_TC_FILTER_ADD, ZEBRA_TC_FILTER_DELETE, ZEBRA_OPAQUE_NOTIFY, + ZEBRA_SRV6_SID_NOTIFY, } zebra_message_types_t; /* Zebra message types. Please update the corresponding * command_types array with any changes! @@ -761,6 +764,13 @@ enum zapi_iptable_notify_owner { ZAPI_IPTABLE_FAIL_REMOVE, }; +enum zapi_srv6_sid_notify { + ZAPI_SRV6_SID_FAIL_ALLOC = 0, + ZAPI_SRV6_SID_ALLOCATED, + ZAPI_SRV6_SID_RELEASED, + ZAPI_SRV6_SID_FAIL_RELEASE, +}; + enum zclient_send_status { ZCLIENT_SEND_FAILURE = -1, ZCLIENT_SEND_SUCCESS = 0, @@ -813,6 +823,28 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note) return ret; } +static inline const char *zapi_srv6_sid_notify2str(enum zapi_srv6_sid_notify note) +{ + const char *ret = "UNKNOWN"; + + switch (note) { + case ZAPI_SRV6_SID_FAIL_ALLOC: + ret = "ZAPI_SRV6_SID_FAIL_ALLOC"; + break; + case ZAPI_SRV6_SID_ALLOCATED: + ret = "ZAPI_SRV6_SID_ALLOCATED"; + break; + case ZAPI_SRV6_SID_FAIL_RELEASE: + ret = "ZAPI_SRV6_SID_FAIL_RELEASE"; + break; + case ZAPI_SRV6_SID_RELEASED: + ret = "ZAPI_SRV6_SID_RELEASED"; + break; + } + + return ret; +} + /* Zebra MAC types */ #define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ #define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ @@ -1070,10 +1102,23 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start, uint32_t end); + +/* Zebra SRv6 Manager flags */ +#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE 0x01 +#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR 0x02 + extern int srv6_manager_get_locator_chunk(struct zclient *zclient, const char *locator_name); extern int srv6_manager_release_locator_chunk(struct zclient *zclient, const char *locator_name); +extern int srv6_manager_get_locator(struct zclient *zclient, + const char *locator_name); +extern int srv6_manager_get_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name, uint32_t *sid_func); +extern int srv6_manager_release_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx); extern enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd, @@ -1128,6 +1173,11 @@ bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno, bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_notify_owner *note); +bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t *func, + uint32_t *wide_func, + enum zapi_srv6_sid_notify *note, + char **locator_name); /* Nexthop-group message apis */ extern enum zclient_send_status diff --git a/mgmtd/.gitignore b/mgmtd/.gitignore index 7ce107e9..e12bcc08 100644 --- a/mgmtd/.gitignore +++ b/mgmtd/.gitignore @@ -1 +1,2 @@ mgmtd +mgmtd_testc diff --git a/mgmtd/mgmt.c b/mgmtd/mgmt.c index 8d416430..cfadad48 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 c7f4fb9d..93c9bcac 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 fc1bde0b..32f28a57 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -43,6 +43,7 @@ struct mgmt_fe_session_ctx { uint64_t txn_id; uint64_t cfg_txn_id; uint8_t ds_locked[MGMTD_DS_MAX_ID]; + const char **notify_xpaths; struct event *proc_cfg_txn_clnp; struct event *proc_show_txn_clnp; @@ -489,6 +490,26 @@ static int fe_adapter_send_get_reply(struct mgmt_fe_session_ctx *session, return fe_adapter_send_msg(session->adapter, &fe_msg, false); } +static int fe_adapter_conn_send_error(struct msg_conn *conn, + uint64_t session_id, uint64_t req_id, + bool short_circuit_ok, int16_t error, + const char *errfmt, ...) PRINTFRR(6, 7); +static int fe_adapter_conn_send_error(struct msg_conn *conn, uint64_t session_id, + uint64_t req_id, bool short_circuit_ok, + int16_t error, const char *errfmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, errfmt); + + ret = vmgmt_msg_native_send_error(conn, session_id, req_id, + short_circuit_ok, error, errfmt, ap); + va_end(ap); + + return ret; +} + static int fe_adapter_send_error(struct mgmt_fe_session_ctx *session, uint64_t req_id, bool short_circuit_ok, int16_t error, const char *errfmt, ...) @@ -1143,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; @@ -1152,16 +1175,49 @@ 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 " 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), + false); + mgmt_msg_native_free_msg(msg); + + return ret; +} + +static int +fe_adapter_native_send_session_reply(struct mgmt_fe_client_adapter *adapter, + uint64_t req_id, uint64_t session_id, + bool created) +{ + struct mgmt_msg_session_reply *msg; + int ret; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_session_reply, 0, + MTYPE_MSG_NATIVE_SESSION_REPLY); + msg->refer_id = session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_SESSION_REPLY; + msg->created = created; + + __dbg("Sending session-reply from adapter %s to session-id %" PRIu64 " req-id %" PRIu64 " len %u", - session->adapter->name, session->session_id, req_id, + adapter->name, session_id, req_id, mgmt_msg_native_get_msg_len(msg)); - ret = fe_adapter_send_native_msg(session->adapter, msg, + ret = fe_adapter_send_native_msg(adapter, msg, mgmt_msg_native_get_msg_len(msg), false); mgmt_msg_native_free_msg(msg); @@ -1169,6 +1225,60 @@ static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session, return ret; } +/** + * fe_adapter_handle_session_req() - Handle a session-req message from a FE client. + * @msg_raw: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_session_req(struct mgmt_fe_client_adapter *adapter, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_session_req *msg = __msg; + struct mgmt_fe_session_ctx *session; + uint64_t client_id; + + __dbg("Got session-req creating: %u for refer-id %" PRIu64 " from '%s'", + msg->refer_id == 0, msg->refer_id, adapter->name); + + if (msg->refer_id) { + uint64_t session_id = msg->refer_id; + + session = mgmt_session_id2ctx(session_id); + if (!session) { + fe_adapter_conn_send_error( + adapter->conn, session_id, msg->req_id, false, + -EINVAL, + "No session to delete for session-id: %" PRIu64, + session_id); + return; + } + fe_adapter_native_send_session_reply(adapter, msg->req_id, + session_id, false); + mgmt_fe_cleanup_session(&session); + return; + } + + client_id = msg->req_id; + + /* See if we have a client name to register */ + if (msg_len > sizeof(*msg)) { + if (!MGMT_MSG_VALIDATE_NUL_TERM(msg, msg_len)) { + fe_adapter_conn_send_error( + adapter->conn, client_id, msg->req_id, false, + -EINVAL, + "Corrupt session-req message rcvd from client-id: %" PRIu64, + client_id); + return; + } + __dbg("Set client-name to '%s'", msg->client_name); + strlcpy(adapter->name, msg->client_name, sizeof(adapter->name)); + } + + session = mgmt_fe_create_session(adapter, client_id); + fe_adapter_native_send_session_reply(adapter, client_id, + session->session_id, true); +} + /** * fe_adapter_handle_get_data() - Handle a get-tree message from a FE client. * @session: the client session. @@ -1179,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; @@ -1228,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; @@ -1292,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, @@ -1305,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; @@ -1326,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, @@ -1401,10 +1536,44 @@ static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session, } } +/** + * fe_adapter_handle_notify_select() - Handle an Notify Select message. + * @session: the client session. + * @__msg: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_notify_select(struct mgmt_fe_session_ctx *session, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_notify_select *msg = __msg; + uint64_t req_id = msg->req_id; + const char **selectors = NULL; + const char **new; + + if (msg_len >= sizeof(*msg)) { + selectors = mgmt_msg_native_strings_decode(msg, msg_len, + msg->selectors); + if (!selectors) { + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Invalid message"); + return; + } + } + if (msg->replace) { + darr_free_free(session->notify_xpaths); + session->notify_xpaths = selectors; + } else if (selectors) { + new = darr_append_nz(session->notify_xpaths, + darr_len(selectors)); + memcpy(new, selectors, darr_len(selectors) * sizeof(*selectors)); + darr_free(selectors); + } +} + /** * fe_adapter_handle_rpc() - Handle an RPC message from an FE client. * @session: the client session. - * @msg_raw: the message data. + * @__msg: the message data. * @msg_len: the length of the message data. */ static void fe_adapter_handle_rpc(struct mgmt_fe_session_ctx *session, @@ -1493,6 +1662,28 @@ static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter, size_t msg_len) { struct mgmt_fe_session_ctx *session; + size_t min_size = mgmt_msg_get_min_size(msg->code); + + if (msg_len < min_size) { + if (!min_size) + __log_err("adapter %s: recv msg refer-id %" PRIu64 + " unknown message type %u", + adapter->name, msg->refer_id, msg->code); + else + __log_err("adapter %s: recv msg refer-id %" PRIu64 + " short (%zu<%zu) msg for type %u", + adapter->name, msg->refer_id, msg_len, + min_size, msg->code); + return; + } + + if (msg->code == MGMT_MSG_CODE_SESSION_REQ) { + __dbg("adapter %s: session-id %" PRIu64 + " received SESSION_REQ message", + adapter->name, msg->refer_id); + fe_adapter_handle_session_req(adapter, msg, msg_len); + return; + } session = mgmt_session_id2ctx(msg->refer_id); if (!session) { @@ -1503,13 +1694,26 @@ static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter, assert(session->adapter == adapter); switch (msg->code) { - case MGMT_MSG_CODE_GET_DATA: - fe_adapter_handle_get_data(session, msg, msg_len); - break; case MGMT_MSG_CODE_EDIT: + __dbg("adapter %s: session-id %" PRIu64 " received EDIT message", + adapter->name, msg->refer_id); fe_adapter_handle_edit(session, msg, msg_len); break; + case MGMT_MSG_CODE_NOTIFY_SELECT: + __dbg("adapter %s: session-id %" PRIu64 + " received NOTIFY_SELECT message", + adapter->name, msg->refer_id); + fe_adapter_handle_notify_select(session, msg, msg_len); + break; + case MGMT_MSG_CODE_GET_DATA: + __dbg("adapter %s: session-id %" PRIu64 + " received GET_DATA message", + adapter->name, msg->refer_id); + fe_adapter_handle_get_data(session, msg, msg_len); + break; case MGMT_MSG_CODE_RPC: + __dbg("adapter %s: session-id %" PRIu64 " received RPC message", + adapter->name, msg->refer_id); fe_adapter_handle_rpc(session, msg, msg_len); break; default: @@ -1554,14 +1758,48 @@ void mgmt_fe_adapter_send_notify(struct mgmt_msg_notify_data *msg, size_t msglen { struct mgmt_fe_client_adapter *adapter; struct mgmt_fe_session_ctx *session; + struct nb_node *nb_node; + const char **xpath_prefix; + const char *notif; + bool sendit; + uint len; assert(msg->refer_id == 0); + notif = mgmt_msg_native_xpath_decode(msg, msglen); + if (!notif) { + __log_err("Corrupt notify msg"); + return; + } + + /* + * We need the nb_node to obtain a path which does not include any + * specific list entry selectors + */ + nb_node = nb_node_find(notif); + if (!nb_node) { + __log_err("No schema found for notification: %s", notif); + return; + } + FOREACH_ADAPTER_IN_LIST (adapter) { FOREACH_SESSION_IN_LIST (adapter, session) { - msg->refer_id = session->session_id; - (void)fe_adapter_send_native_msg(adapter, msg, msglen, - false); + /* If no selectors then always send */ + sendit = !session->notify_xpaths; + darr_foreach_p (session->notify_xpaths, xpath_prefix) { + len = strlen(*xpath_prefix); + if (!strncmp(*xpath_prefix, notif, len) || + !strncmp(*xpath_prefix, nb_node->xpath, + len)) { + sendit = true; + break; + } + } + if (sendit) { + msg->refer_id = session->session_id; + (void)fe_adapter_send_native_msg(adapter, msg, + msglen, false); + } } } msg->refer_id = 0; @@ -1771,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; @@ -1803,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 61d6cfae..4d94e760 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 e181d0da..1880d944 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 0f0cccbb..ccfdd753 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; }; @@ -741,6 +742,8 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn, txn->commit_cfg_req->req.commit_cfg .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, @@ -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 b6ca2886..37dadc01 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 8ccb4635..876f7035 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_interface.c b/nhrpd/nhrp_interface.c index 7d0ab976..e81a2efb 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -99,6 +99,8 @@ static int nhrp_if_delete_hook(struct interface *ifp) free(nifp->ipsec_fallback_profile); if (nifp->source) free(nifp->source); + if (nifp->auth_token) + zbuf_free(nifp->auth_token); XFREE(MTYPE_NHRP_IF, ifp->info); return 0; diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index f779f934..b8958ba2 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -216,7 +216,7 @@ static void nhrp_reg_send_req(struct event *t) cie->holding_time = htons(if_ad->holdtime); cie->mtu = htons(if_ad->mtu); - nhrp_ext_request(zb, hdr, ifp); + nhrp_ext_request(zb, hdr); /* Cisco NAT detection extension */ if (sockunion_family(&r->proto_addr) != AF_UNSPEC) { @@ -240,7 +240,7 @@ static void nhrp_reg_send_req(struct event *t) cie->mtu = htons(if_ad->mtu); nhrp_ext_complete(zb, ext); - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(r->peer, zb); zbuf_free(zb); } diff --git a/nhrpd/nhrp_packet.c b/nhrpd/nhrp_packet.c index c6bd3bbb..71f5c2f0 100644 --- a/nhrpd/nhrp_packet.c +++ b/nhrpd/nhrp_packet.c @@ -115,14 +115,32 @@ uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len) return (~csum) & 0xffff; } -void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr) +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp) { + nhrp_packet_complete_auth(zb, hdr, ifp, true); +} + +void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp, bool auth) +{ + struct nhrp_interface *nifp = ifp->info; + struct zbuf *auth_token = nifp->auth_token; + struct nhrp_extension_header *dst; unsigned short size; + if (auth && auth_token) { + dst = nhrp_ext_push(zb, hdr, + NHRP_EXTENSION_AUTHENTICATION | + NHRP_EXTENSION_FLAG_COMPULSORY); + zbuf_copy_peek(zb, auth_token, zbuf_size(auth_token)); + nhrp_ext_complete(zb, dst); + } + if (hdr->extension_offset) nhrp_ext_push(zb, hdr, - NHRP_EXTENSION_END - | NHRP_EXTENSION_FLAG_COMPULSORY); + NHRP_EXTENSION_END | + NHRP_EXTENSION_FLAG_COMPULSORY); size = zb->tail - (uint8_t *)hdr; hdr->packet_size = htons(size); @@ -225,8 +243,7 @@ struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, return ext; } -void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, - struct interface *ifp) +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr) { /* Place holders for standard extensions */ nhrp_ext_push(zb, hdr, diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 6e7857c7..fa11980c 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -597,13 +597,19 @@ 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; break; } } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(peer, zb); err: nhrp_peer_unref(peer); @@ -730,7 +736,8 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) } } - nhrp_packet_complete(zb, hdr); + /* auth ext was validated and copied from the request */ + nhrp_packet_complete_auth(zb, hdr, ifp, false); nhrp_peer_send(p->peer, zb); err: zbuf_free(zb); @@ -812,7 +819,7 @@ void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, /* Payload is the packet causing indication */ zbuf_copy(zb, pkt, zbuf_used(pkt)); - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(p, zb); nhrp_peer_unref(p); zbuf_free(zb); @@ -958,9 +965,12 @@ static void nhrp_peer_forward(struct nhrp_peer *p, if (type == NHRP_EXTENSION_END) break; - dst = nhrp_ext_push(zb, hdr, htons(ext->type)); - if (!dst) - goto err; + dst = NULL; + if (type != NHRP_EXTENSION_AUTHENTICATION) { + dst = nhrp_ext_push(zb, hdr, htons(ext->type)); + if (!dst) + goto err; + } switch (type) { case NHRP_EXTENSION_FORWARD_TRANSIT_NHS: @@ -1045,6 +1055,12 @@ static void nhrp_peer_forward(struct nhrp_peer *p, zbuf_put(zb, extpl.head, len); } 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 (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY) /* FIXME: RFC says to just copy, but not @@ -1060,10 +1076,11 @@ static void nhrp_peer_forward(struct nhrp_peer *p, zbuf_copy(zb, &extpl, len); break; } - nhrp_ext_complete(zb, dst); + if (dst) + nhrp_ext_complete(zb, dst); } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete_auth(zb, hdr, pp->ifp, true); nhrp_peer_send(p, zb); zbuf_free(zb); zbuf_free(zb_copy); @@ -1089,8 +1106,7 @@ static void nhrp_packet_debug(struct zbuf *zb, const char *dir) reply = packet_types[hdr->type].type == PACKET_REPLY; debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %pSU -> %pSU", dir, - (packet_types[hdr->type].name ? packet_types[hdr->type].name - : "Unknown"), + (packet_types[hdr->type].name ? : "Unknown"), hdr->type, reply ? &dst_proto : &src_proto, reply ? &src_proto : &dst_proto); } @@ -1106,11 +1122,111 @@ static int proto2afi(uint16_t proto) return AF_UNSPEC; } -struct nhrp_route_info { - int local; - struct interface *ifp; - struct nhrp_vc *vc; -}; +static int nhrp_packet_send_error(struct nhrp_packet_parser *pp, + uint16_t indication_code, uint16_t offset) +{ + union sockunion src_proto, dst_proto; + struct nhrp_packet_header *hdr; + struct zbuf *zb; + + src_proto = pp->src_proto; + dst_proto = pp->dst_proto; + if (packet_types[pp->hdr->type].type != PACKET_REPLY) { + src_proto = pp->dst_proto; + dst_proto = pp->src_proto; + } + /* Create reply */ + zb = zbuf_alloc(1500); + hdr = nhrp_packet_push(zb, NHRP_PACKET_ERROR_INDICATION, &pp->src_nbma, + &src_proto, &dst_proto); + + hdr->u.error.code = htons(indication_code); + hdr->u.error.offset = htons(offset); + hdr->flags = pp->hdr->flags; + hdr->hop_count = 0; /* XXX: cisco returns 255 */ + + /* Payload is the packet causing error */ + /* Don`t add extension according to RFC */ + zbuf_put(zb, pp->hdr, sizeof(*pp->hdr)); + zbuf_put(zb, sockunion_get_addr(&pp->src_nbma), + hdr->src_nbma_address_len); + zbuf_put(zb, sockunion_get_addr(&pp->src_proto), + hdr->src_protocol_address_len); + zbuf_put(zb, sockunion_get_addr(&pp->dst_proto), + hdr->dst_protocol_address_len); + nhrp_packet_complete_auth(zb, hdr, pp->ifp, false); + + nhrp_peer_send(pp->peer, zb); + zbuf_free(zb); + return 0; +} + +static bool nhrp_connection_authorized(struct nhrp_packet_parser *pp) +{ + struct nhrp_cisco_authentication_extension *auth_ext; + struct nhrp_interface *nifp = pp->ifp->info; + struct zbuf *auth = nifp->auth_token; + struct nhrp_extension_header *ext; + struct zbuf *extensions, pl; + int cmp = 1; + int pl_pass_length, auth_pass_length; + size_t auth_size, pl_size; + + extensions = zbuf_alloc(zbuf_used(&pp->extensions)); + zbuf_copy_peek(extensions, &pp->extensions, zbuf_used(&pp->extensions)); + while ((ext = nhrp_ext_pull(extensions, &pl)) != NULL) { + switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_AUTHENTICATION: + /* Size of authentication extensions + * (varies based on password length) + */ + auth_size = zbuf_size(auth); + pl_size = zbuf_size(&pl); + auth_ext = (struct nhrp_cisco_authentication_extension *) + auth->buf; + + if (auth_size == pl_size) + cmp = memcmp(auth_ext, pl.buf, auth_size); + else + cmp = 1; + + if (unlikely(debug_flags & NHRP_DEBUG_COMMON)) { + /* 4 bytes in nhrp_cisco_authentication_extension are allocated + * toward the authentication type. The remaining bytes are used for the + * password - so the password length is just the length of the extension - 4 + */ + auth_pass_length = (auth_size - 4); + pl_pass_length = (pl_size - 4); + /* Because characters are to be printed in HEX, (2* the max pass length) + 1 + * is needed for the string representation + */ + char auth_pass[(2 * NHRP_CISCO_PASS_LEN) + 1] = { 0 }, + pl_pass[(2 * NHRP_CISCO_PASS_LEN) + 1] = { 0 }; + /* Converting bytes in buffer to HEX and saving output as a string - + * Passphrase is converted to HEX in order to avoid printing + * non ACII-compliant characters + */ + for (int i = 0; i < (auth_pass_length); i++) + snprintf(auth_pass + (i * 2), 3, "%02X", + auth_ext->secret[i]); + for (int i = 0; i < (pl_pass_length); i++) + snprintf(pl_pass + (i * 2), 3, "%02X", + ((struct nhrp_cisco_authentication_extension *)pl.buf) + ->secret[i]); + + debugf(NHRP_DEBUG_COMMON, + "Processing Authentication Extension for (%s:%s|%d)", + auth_pass, pl_pass, cmp); + } + break; + default: + /* Ignoring all received extensions except Authentication*/ + break; + } + } + zbuf_free(extensions); + return cmp == 0; +} void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) { @@ -1191,10 +1307,20 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) goto drop; } + /* RFC2332 5.3.4 - Authentication is always done pairwise on an NHRP + * hop-by-hop basis; i.e. regenerated at each hop. */ nhrp_packet_debug(zb, "Recv"); - - /* FIXME: Check authentication here. This extension needs to be - * pre-handled. */ + if (nifp->auth_token && + (hdr->type != NHRP_PACKET_ERROR_INDICATION || + hdr->u.error.code != NHRP_ERROR_AUTHENTICATION_FAILURE)) { + if (!nhrp_connection_authorized(&pp)) { + nhrp_packet_send_error(&pp, + NHRP_ERROR_AUTHENTICATION_FAILURE, + 0); + info = "authentication failure"; + goto drop; + } + } /* Figure out if this is local */ target_addr = (packet_types[hdr->type].type == PACKET_REPLY) diff --git a/nhrpd/nhrp_protocol.h b/nhrpd/nhrp_protocol.h index 8cf1ebbc..a4fb315b 100644 --- a/nhrpd/nhrp_protocol.h +++ b/nhrpd/nhrp_protocol.h @@ -73,6 +73,7 @@ /* NHRP Authentication extension types (ala Cisco) */ #define NHRP_AUTHENTICATION_PLAINTEXT 0x00000001 +#define NHRP_CISCO_PASS_LEN 8 /* NHRP Packet Structures */ struct nhrp_packet_header { diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index e83ce7f5..55d61a90 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))]; @@ -425,7 +462,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) "Shortcut res_req: set cie ht to %u and mtu to %u. shortcut ht is %u", ntohs(cie->holding_time), ntohs(cie->mtu), s->holding_time); - nhrp_ext_request(zb, hdr, ifp); + nhrp_ext_request(zb, hdr); /* Cisco NAT detection extension */ hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT); @@ -438,7 +475,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) nhrp_ext_complete(zb, ext); } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(peer, zb); nhrp_peer_unref(peer); @@ -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 f91fcb53..199f4d75 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -12,6 +12,9 @@ #include "nhrpd.h" #include "netlink.h" +#include "nhrp_protocol.h" + +#include "nhrpd/nhrp_vty_clippy.c" static int nhrp_config_write(struct vty *vty); static struct cmd_node zebra_node = { @@ -292,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); @@ -459,6 +467,58 @@ DEFUN(if_no_nhrp_holdtime, if_no_nhrp_holdtime_cmd, return CMD_SUCCESS; } +DEFPY(if_nhrp_authentication, if_nhrp_authentication_cmd, + AFI_CMD "nhrp authentication PASSWORD$password", + AFI_STR + NHRP_STR + "Specify plain text password used for authenticantion\n" + "Password, plain text, limited to 8 characters\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct nhrp_cisco_authentication_extension *auth; + struct nhrp_interface *nifp = ifp->info; + int pass_len = strlen(password); + + if (pass_len > NHRP_CISCO_PASS_LEN) { + vty_out(vty, "Password size limit exceeded (%d>%d)\n", + pass_len, NHRP_CISCO_PASS_LEN); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nifp->auth_token) { + zbuf_free(nifp->auth_token); + nifp->auth_token = NULL; + } + + nifp->auth_token = zbuf_alloc(pass_len + sizeof(uint32_t)); + auth = (struct nhrp_cisco_authentication_extension *) + nifp->auth_token->buf; + auth->type = htonl(NHRP_AUTHENTICATION_PLAINTEXT); + memcpy(auth->secret, password, pass_len); + + return CMD_SUCCESS; +} + + +DEFPY(if_no_nhrp_authentication, if_no_nhrp_authentication_cmd, + "no " AFI_CMD "nhrp authentication PASSWORD$password", + NO_STR + AFI_STR + NHRP_STR + "Specify plain text password used for authenticantion\n" + "Password, plain text, limited to 8 characters\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct nhrp_interface *nifp = ifp->info; + + if (nifp->auth_token) { + zbuf_free(nifp->auth_token); + nifp->auth_token = NULL; + } + return CMD_SUCCESS; +} + + DEFUN(if_nhrp_mtu, if_nhrp_mtu_cmd, "ip nhrp mtu <(576-1500)|opennhrp>", IP_STR @@ -1053,6 +1113,7 @@ DEFUN(show_dmvpn, show_dmvpn_cmd, static void clear_nhrp_cache(struct nhrp_cache *c, void *data) { struct info_ctx *ctx = data; + if (c->cur.type <= NHRP_CACHE_DYNAMIC) { nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL, NULL); @@ -1129,6 +1190,7 @@ static void interface_config_write_nhrp_map(struct nhrp_cache_config *c, static int interface_config_write(struct vty *vty) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct nhrp_cisco_authentication_extension *auth; struct write_map_ctx mapctx; struct interface *ifp; struct nhrp_interface *nifp; @@ -1155,6 +1217,12 @@ static int interface_config_write(struct vty *vty) if (nifp->source) vty_out(vty, " tunnel source %s\n", nifp->source); + if (nifp->auth_token) { + auth = (struct nhrp_cisco_authentication_extension *) + nifp->auth_token->buf; + vty_out(vty, " ip nhrp authentication %s\n", auth->secret); + } + for (afi = 0; afi < AFI_MAX; afi++) { struct nhrp_afi_data *ad = &nifp->afi[afi]; @@ -1256,6 +1324,8 @@ void nhrp_config_init(void) install_element(INTERFACE_NODE, &if_no_nhrp_network_id_cmd); install_element(INTERFACE_NODE, &if_nhrp_holdtime_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_holdtime_cmd); + install_element(INTERFACE_NODE, &if_nhrp_authentication_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_authentication_cmd); install_element(INTERFACE_NODE, &if_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_nhrp_flags_cmd); diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index e389b748..6cab7b3a 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; @@ -311,6 +314,7 @@ DECLARE_DLIST(nhrp_reglist, struct nhrp_registration, reglist_entry); struct nhrp_interface { struct interface *ifp; + struct zbuf *auth_token; unsigned enabled : 1; char *ipsec_profile, *ipsec_fallback_profile, *source; @@ -480,9 +484,13 @@ struct nhrp_packet_header *nhrp_packet_push(struct zbuf *zb, uint8_t type, const union sockunion *src_nbma, const union sockunion *src_proto, const union sockunion *dst_proto); -void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr); uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len); +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp); +void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp, bool auth); + struct nhrp_packet_header *nhrp_packet_pull(struct zbuf *zb, union sockunion *src_nbma, union sockunion *src_proto, @@ -501,8 +509,7 @@ nhrp_ext_push(struct zbuf *zb, struct nhrp_packet_header *hdr, uint16_t type); void nhrp_ext_complete(struct zbuf *zb, struct nhrp_extension_header *ext); struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, struct zbuf *payload); -void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, - struct interface *); +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr); int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp, struct nhrp_extension_header *ext, struct zbuf *extpayload); diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index 227ff6c6..94fb3bb5 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -42,3 +42,7 @@ noinst_HEADERS += \ nhrpd/zbuf.h \ nhrpd/znl.h \ # end + +clippy_scan += \ + nhrpd/nhrp_vty.c \ + # end diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index 0c5be29f..343dfefc 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 52686ed4..ab9e000d 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 2065527c..8fa85bad 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 21e6d898..ace3ba84 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 b87aa2ff..04ff3508 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 ab119a4e..64eb90d5 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 84ef3aeb..e10d2068 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 f0e5d3a1..da8b829c 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 7f813ce3..60f92385 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 b06796ad..324cd7ab 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 7d154cb4..fafa6d12 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 01775182..622e5f9e 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 4fc2f0dd..b2c83a1d 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 9aca5550..e5de3048 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 a6ee8d8b..33d15e72 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 #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 0e44f2a1..acf15da4 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 ea2be20c..8a5de468 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 4307ee3c..645a4087 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 36864d2a..9ac8b6c1 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 7879dae8..5f2c5a6c 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 00000000..a687a059 --- /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 a3fb2053..ad487f35 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 911f3567..46630130 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 d90a950d..e4e0354f 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 5f89af95..a7bd94bd 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 289ddd00..2bf32544 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 28d52687..93779991 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 9b62f36d..b47c3900 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 e15871ac..e3398af7 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -110,6 +110,9 @@ void ospf_area_update_fr_state(struct ospf_area *area) static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_interface *oi = inbr->oi; + /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgment sent. If interface is in Backup state @@ -122,12 +125,27 @@ static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, worked out previously */ /* Deal with router as BDR */ - if (inbr->oi->state == ISM_Backup && !NBR_IS_DR(inbr)) + if (oi->state == ISM_Backup && !NBR_IS_DR(inbr)) return; - /* Schedule a delayed LSA Ack to be sent */ - listnode_add(inbr->oi->ls_ack, - ospf_lsa_lock(lsa)); /* delayed LSA Ack */ + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &inbr->router_id, + IF_NAME(inbr->oi)); + + /* Add the LSA to the interface delayed Ack list. */ + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&oi->ls_ack_delayed, ls_ack_list_entry); + + /* Set LS Ack timer if it is not already scheduled. */ + if (!oi->t_ls_ack_delayed) + OSPF_ISM_TIMER_ON(oi->t_ls_ack_delayed, + ospf_ls_ack_delayed_timer, + oi->v_ls_ack_delayed); } /* Check LSA is related to external info. */ @@ -779,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 @@ -797,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; } @@ -1015,7 +1041,7 @@ void ospf_ls_request_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) ospf_lsdb_delete(&nbr->ls_req, lsa); } -/* Remove all LSA from neighbor's ls-requenst list. */ +/* Remove all LSAs from neighbor's ls-request list. */ void ospf_ls_request_delete_all(struct ospf_neighbor *nbr) { ospf_lsa_unlock(&nbr->ls_req_last); @@ -1061,58 +1087,124 @@ int ospf_ls_retransmit_isempty(struct ospf_neighbor *nbr) /* Add LSA to be retransmitted to neighbor's ls-retransmit list. */ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - struct ospf_lsa *old; + struct ospf_lsdb_linked_node *ls_rxmt_node; + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct ospf_lsa *old = NULL; + bool rxmt_head_replaced = false; - old = ospf_ls_retransmit_lookup(nbr, lsa); + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + if (ls_rxmt_node) + old = ls_rxmt_node->info; if (ospf_lsa_more_recent(old, lsa) < 0) { if (old) { old->retransmit_counter--; + 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)) - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Old Delete LSA[%s] on Add", ospf_ls_retransmit_count(nbr), &nbr->router_id, ospf_get_name(nbr->oi->ospf), - dump_lsa_key(old)); - ospf_lsdb_delete(&nbr->ls_rxmt, old); + dump_lsa_key(lsa)); + ospf_lsa_unlock(&old); } lsa->retransmit_counter++; + ls_rxmt_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); /* - * We cannot make use of the newly introduced callback function - * "lsdb->new_lsa_hook" to replace debug output below, just - * because - * it seems no simple and smart way to pass neighbor information - * to - * the common function "ospf_lsdb_add()" -- endo. + * Set the LSA retransmission time for the neighbor; */ + monotime(&ls_rxmt_list_entry->list_entry_time); + ls_rxmt_list_entry->list_entry_time.tv_sec += nbr->v_ls_rxmt; + + /* + * Add the LSA to the neighbor retransmission list. + */ + ls_rxmt_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsdb_add(&nbr->ls_rxmt, lsa); + + /* + * Look up the newly added node and set the list pointer. + */ + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + ls_rxmt_node->lsa_list_entry = ls_rxmt_list_entry; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)++, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Add LSA[%s] retrans at (%ld/%ld)", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), - dump_lsa_key(lsa)); - ospf_lsdb_add(&nbr->ls_rxmt, lsa); + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + dump_lsa_key(lsa), + (long)ls_rxmt_list_entry->list_entry_time + .tv_sec, + (long)ls_rxmt_list_entry->list_entry_time + .tv_usec); + /* + * Reset the neighbor LSA retransmission timer if isn't currently + * running or the LSA at the head of the list was updated. + */ + if (!nbr->t_ls_rxmt || rxmt_head_replaced) + ospf_ls_retransmit_set_timer(nbr); } } /* Remove LSA from neibghbor's ls-retransmit list. */ void ospf_ls_retransmit_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - if (ospf_ls_retransmit_lookup(nbr, lsa)) { + struct ospf_lsdb_linked_node *ls_rxmt_node; + + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + + if (ls_rxmt_node) { + bool rxmt_timer_reset; + + if (ls_rxmt_node->lsa_list_entry == + ospf_lsa_list_first(&nbr->ls_rxmt_list)) + rxmt_timer_reset = true; + else + rxmt_timer_reset = false; + lsa->retransmit_counter--; - if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */ - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + + /* 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)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Delete LSA[%s]", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); - ospf_lsdb_delete(&nbr->ls_rxmt, lsa); + ospf_lsa_unlock(&lsa); + + /* + * If the LS retransmission entry at the head of the list was + * deleted, reset the timer. + */ + if (rxmt_timer_reset) + ospf_ls_retransmit_set_timer(nbr); } } /* Clear neighbor's ls-retransmit list. */ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; struct ospf_lsdb *lsdb; int i; @@ -1128,10 +1220,54 @@ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) ospf_ls_retransmit_delete(nbr, lsa); } + frr_each_safe (ospf_lsa_list, &nbr->ls_rxmt_list, ls_rxmt_list_entry) { + ospf_lsa_list_del(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsa_unlock(&ls_rxmt_list_entry->lsa); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_list_entry); + } + ospf_lsa_unlock(&nbr->ls_req_last); nbr->ls_req_last = NULL; } +/* + * Set the neighbor's ls-retransmit timer based on the next + * LSA retransmit time. + */ +void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr) +{ + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + + if (nbr->t_ls_rxmt) + EVENT_OFF(nbr->t_ls_rxmt); + + ls_rxmt_list_entry = ospf_lsa_list_first(&nbr->ls_rxmt_list); + if (ls_rxmt_list_entry) { + struct timeval current_time, delay; + unsigned long delay_milliseconds; + + monotime(¤t_time); + if (timercmp(¤t_time, + &ls_rxmt_list_entry->list_entry_time, >=)) + delay_milliseconds = 10; + else { + timersub(&ls_rxmt_list_entry->list_entry_time, + ¤t_time, &delay); + delay_milliseconds = (delay.tv_sec * 1000) + + (delay.tv_usec / 1000); + } + + event_add_timer_msec(master, ospf_ls_rxmt_timer, nbr, + delay_milliseconds, &nbr->t_ls_rxmt); + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) retrans timer set in %ld msecs - Head LSA(%s)", + ospf_ls_retransmit_count(nbr), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + delay_milliseconds, + dump_lsa_key(ls_rxmt_list_entry->lsa)); + } +} + /* Lookup LSA from neighbor's ls-retransmit list. */ struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h index 3757400d..24120529 100644 --- a/ospfd/ospf_flood.h +++ b/ospfd/ospf_flood.h @@ -7,6 +7,39 @@ #ifndef _ZEBRA_OSPF_FLOOD_H #define _ZEBRA_OSPF_FLOOD_H +#include "typesafe.h" + +/* + * OSPF Temporal LSA List + */ +PREDECL_DLIST(ospf_lsa_list); + +struct ospf_lsa_list_entry { + /* Linkage for LSA List */ + struct ospf_lsa_list_item list_linkage; + + union { + /* + * Time associated with the list entry. For example, for a + * neigbhor link retransmission list, this is the + * retransmission time. + */ + struct timeval list_entry_timeval; + + /* + * Destanation address specific to the LSA list. For example, + * the distination for an associated direct LS acknowledgment. + */ + struct in_addr list_entry_dst_addr; + } u; + + struct ospf_lsa *lsa; +}; +#define list_entry_time u.list_entry_timeval +#define list_entry_dst u.list_entry_dst_addr + +DECLARE_DLIST(ospf_lsa_list, struct ospf_lsa_list_entry, list_linkage); + extern int ospf_flood(struct ospf *, struct ospf_neighbor *, struct ospf_lsa *, struct ospf_lsa *); extern int ospf_flood_through(struct ospf *, struct ospf_neighbor *, @@ -36,6 +69,8 @@ extern void ospf_ls_retransmit_add(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_clear(struct ospf_neighbor *); +extern void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr); + extern struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete_nbr_area(struct ospf_area *, diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 11ac7af7..c4210eb7 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -186,10 +186,12 @@ static void ospf_if_default_variables(struct ospf_interface *oi) oi->crypt_seqnum = 0; - /* This must be short, (less than RxmtInterval) - - RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being - held back for too long - MAG */ - oi->v_ls_ack = 1; + /* + * The OSPF LS ACK Delay timer must be less than the LS Retransmision + * timer. As per RFC 2328 Section 13.5 paragraph 3, Set to 1 second + * to avoid Acks being held back for too long + */ + oi->v_ls_ack_delayed = OSPF_ACK_DELAY_DEFAULT; } /* lookup oi for specified prefix/ifp */ @@ -272,9 +274,9 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, /* Initialize static neighbor list. */ oi->nbr_nbma = list_new(); - /* Initialize Link State Acknowledgment list. */ - oi->ls_ack = list_new(); - oi->ls_ack_direct.ls_ack = list_new(); + /* Initialize Link State Acknowledgment lists. */ + ospf_lsa_list_init(&oi->ls_ack_delayed); + ospf_lsa_list_init(&oi->ls_ack_direct); /* Set default values. */ ospf_if_default_variables(oi); @@ -306,6 +308,22 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, return oi; } +/* + * Cleanup Interface Ack List + */ +static void ospf_if_cleanup_ack_list(struct ospf_lsa_list_head *ls_ack_list) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + /* Restore an interface to its pre UP state Used from ism_interface_down only */ void ospf_if_cleanup(struct ospf_interface *oi) @@ -314,7 +332,6 @@ void ospf_if_cleanup(struct ospf_interface *oi) struct listnode *node, *nnode; struct ospf_neighbor *nbr; struct ospf_nbr_nbma *nbr_nbma; - struct ospf_lsa *lsa; /* oi->nbrs and oi->nbr_nbma should be deleted on InterfaceDown event */ /* delete all static neighbors attached to this interface */ @@ -338,10 +355,9 @@ void ospf_if_cleanup(struct ospf_interface *oi) OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); } - /* Cleanup Link State Acknowlegdment list. */ - for (ALL_LIST_ELEMENTS(oi->ls_ack, node, nnode, lsa)) - ospf_lsa_unlock(&lsa); /* oi->ls_ack */ - list_delete_all_node(oi->ls_ack); + /* Cleanup Link State Delayed Acknowlegdment list. */ + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); oi->crypt_seqnum = 0; @@ -377,8 +393,8 @@ void ospf_if_free(struct ospf_interface *oi) /* Free any lists that should be freed */ list_delete(&oi->nbr_nbma); - list_delete(&oi->ls_ack); - list_delete(&oi->ls_ack_direct.ls_ack); + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ospf interface %s vrf %s id %u deleted", @@ -542,6 +558,7 @@ static struct ospf_if_params *ospf_new_if_params(void) UNSET_IF_PARAM(oip, output_cost_cmd); UNSET_IF_PARAM(oip, transmit_delay); UNSET_IF_PARAM(oip, retransmit_interval); + UNSET_IF_PARAM(oip, retransmit_window); UNSET_IF_PARAM(oip, passive_interface); UNSET_IF_PARAM(oip, v_hello); UNSET_IF_PARAM(oip, fast_hello); @@ -599,6 +616,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) && !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) && !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) && + !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_window) && !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) && !OSPF_IF_PARAM_CONFIGURED(oip, v_hello) && !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) && @@ -695,6 +713,9 @@ int ospf_if_new_hook(struct interface *ifp) IF_DEF_PARAMS(ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), priority); IF_DEF_PARAMS(ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT; diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 45d0b794..78a4fb9e 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -13,6 +13,7 @@ #include "keychain.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" +#include #define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info)) #define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params) @@ -47,6 +48,8 @@ struct ospf_if_params { output_cost_cmd); /* Command Interface Output Cost */ DECLARE_IF_PARAM(uint32_t, retransmit_interval); /* Retransmission Interval */ + DECLARE_IF_PARAM(uint32_t, + retransmit_window); /* Retransmission Window */ DECLARE_IF_PARAM(uint8_t, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to @@ -263,20 +266,20 @@ struct ospf_interface { struct route_table *ls_upd_queue; - struct list *ls_ack; /* Link State Acknowledgment list. */ - - struct { - struct list *ls_ack; - struct in_addr dst; - } ls_ack_direct; + /* + * List of LSAs for delayed and direct link + * state acknowledgment transmission. + */ + struct ospf_lsa_list_head ls_ack_delayed; + struct ospf_lsa_list_head ls_ack_direct; /* Timer values. */ - uint32_t v_ls_ack; /* Delayed Link State Acknowledgment */ + uint32_t v_ls_ack_delayed; /* Delayed Link State Acknowledgment */ /* Threads. */ struct event *t_hello; /* timer */ struct event *t_wait; /* timer */ - struct event *t_ls_ack; /* timer */ + struct event *t_ls_ack_delayed; /* timer */ struct event *t_ls_ack_direct; /* event */ struct event *t_ls_upd_event; /* event */ struct event *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ @@ -296,6 +299,7 @@ struct ospf_interface { uint32_t ls_ack_out; /* LS Ack message output count. */ uint32_t discarded; /* discarded input count by error. */ uint32_t state_change; /* Number of status change. */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmitted. */ uint32_t full_nbrs; diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 878ab725..377e7a6b 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -285,7 +285,7 @@ static void ism_timer_set(struct ospf_interface *oi) reset also. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Loopback: @@ -293,7 +293,7 @@ static void ism_timer_set(struct ospf_interface *oi) unavailable for regular data traffic. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Waiting: @@ -304,7 +304,7 @@ static void ism_timer_set(struct ospf_interface *oi) OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); OSPF_ISM_TIMER_ON(oi->t_wait, ospf_wait_timer, OSPF_IF_PARAM(oi, v_wait)); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); break; case ISM_PointToPoint: /* The interface connects to a physical Point-to-point network @@ -314,8 +314,6 @@ static void ism_timer_set(struct ospf_interface *oi) /* send first hello immediately */ OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DROther: /* The network type of the interface is broadcast or NBMA @@ -324,8 +322,6 @@ static void ism_timer_set(struct ospf_interface *oi) Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_Backup: /* The network type of the interface is broadcast os NBMA @@ -333,8 +329,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DR: /* The network type of the interface is broadcast or NBMA @@ -342,8 +336,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; } } diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index 0111c492..d1b3eb0d 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -34,6 +34,59 @@ void ospf_lsdb_init(struct ospf_lsdb *lsdb) lsdb->type[i].db = route_table_init(); } +static struct route_node * +ospf_lsdb_linked_node_create(route_table_delegate_t *delegate, + struct route_table *table) +{ + struct ospf_lsdb_linked_node *node; + + node = XCALLOC(MTYPE_OSPF_LSDB_NODE, + sizeof(struct ospf_lsdb_linked_node)); + + return (struct route_node *)node; +} + +static void ospf_lsdb_linked_node_destroy(route_table_delegate_t *delegate, + struct route_table *table, + struct route_node *node) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node = + (struct ospf_lsdb_linked_node *)node; + + XFREE(MTYPE_OSPF_LSDB_NODE, lsdb_linked_node); +} + +static route_table_delegate_t ospf_lsdb_linked_table_delegate = { + .create_node = ospf_lsdb_linked_node_create, + .destroy_node = ospf_lsdb_linked_node_destroy, +}; + +void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb) +{ + int i; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + lsdb->type[i].db = route_table_init_with_delegate( + &ospf_lsdb_linked_table_delegate); +} + +struct ospf_lsdb_linked_node *ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, + struct ospf_lsa *lsa) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node; + struct route_table *table; + struct prefix_ls lp; + + table = lsdb->type[lsa->data->type].db; + ls_prefix_set(&lp, lsa); + lsdb_linked_node = (struct ospf_lsdb_linked_node *) + route_node_lookup(table, (struct prefix *)&lp); + if (lsdb_linked_node) + route_unlock_node((struct route_node *)lsdb_linked_node); + + return lsdb_linked_node; +} + void ospf_lsdb_free(struct ospf_lsdb *lsdb) { ospf_lsdb_cleanup(lsdb); diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h index bf295ca8..e5e3be8b 100644 --- a/ospfd/ospf_lsdb.h +++ b/ospfd/ospf_lsdb.h @@ -7,6 +7,9 @@ #ifndef _ZEBRA_OSPF_LSDB_H #define _ZEBRA_OSPF_LSDB_H +#include "prefix.h" +#include "table.h" + /* OSPF LSDB structure. */ struct ospf_lsdb { struct { @@ -43,9 +46,29 @@ struct ospf_lsdb { #define AREA_LSDB(A,T) ((A)->lsdb->type[(T)].db) #define AS_LSDB(O,T) ((O)->lsdb->type[(T)].db) +/* + * Alternate route node structure for LSDB nodes linked to + * list elements. + */ +struct ospf_lsdb_linked_node { + /* + * Caution these must be the very first fields + */ + ROUTE_NODE_FIELDS + + /* + * List entry on an LSA list, e.g., a neighbor + * retransmission list. + */ + struct ospf_lsa_list_entry *lsa_list_entry; +}; + /* OSPF LSDB related functions. */ extern struct ospf_lsdb *ospf_lsdb_new(void); extern void ospf_lsdb_init(struct ospf_lsdb *); +extern void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb); +extern struct ospf_lsdb_linked_node * +ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa); extern void ospf_lsdb_free(struct ospf_lsdb *); extern void ospf_lsdb_cleanup(struct ospf_lsdb *); extern void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index fdb4e5c5..5c110275 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -48,14 +48,20 @@ #include "ospfd/ospf_apiserver.h" #define OSPFD_STATE_NAME "%s/ospfd.json", frr_libstatedir -#define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_runstatedir, i +#define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_libstatedir, i /* this one includes the path... because the instance number was in the path * before :( ... which totally didn't have a mkdir anywhere. + * + * ... and libstatedir & runstatedir got switched around while changing this; + * for non-instance it read the wrong path, for instance it wrote the wrong + * path. (There is no COMPAT2 for non-instance because it was writing to the + * right place, i.e. no extra path to check exists from reading a wrong path.) */ -#define OSPFD_COMPAT_STATE_NAME "%s/ospfd-gr.json", frr_libstatedir -#define OSPFD_COMPAT_INST_STATE_NAME(i) \ +#define OSPFD_COMPAT_STATE_NAME "%s/ospfd-gr.json", frr_runstatedir +#define OSPFD_COMPAT1_INST_STATE_NAME(i) \ "%s-%d/ospfd-gr.json", frr_runstatedir, i +#define OSPFD_COMPAT2_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_runstatedir, i /* ospfd privileges */ zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, @@ -139,10 +145,12 @@ static const struct frr_yang_module_info *const ospfd_yang_modules[] = { /* actual paths filled in main() */ static char state_path[512]; -static char state_compat_path[512]; +static char state_compat1_path[512]; +static char state_compat2_path[512]; static char *state_paths[] = { state_path, - state_compat_path, + state_compat1_path, + state_compat2_path, /* NULLed out if not needed */ NULL, }; @@ -242,12 +250,18 @@ int main(int argc, char **argv) if (ospf_instance) { snprintf(state_path, sizeof(state_path), OSPFD_INST_STATE_NAME(ospf_instance)); - snprintf(state_compat_path, sizeof(state_compat_path), - OSPFD_COMPAT_INST_STATE_NAME(ospf_instance)); + snprintf(state_compat1_path, sizeof(state_compat1_path), + OSPFD_COMPAT1_INST_STATE_NAME(ospf_instance)); + snprintf(state_compat2_path, sizeof(state_compat2_path), + OSPFD_COMPAT2_INST_STATE_NAME(ospf_instance)); } else { snprintf(state_path, sizeof(state_path), OSPFD_STATE_NAME); - snprintf(state_compat_path, sizeof(state_compat_path), + snprintf(state_compat1_path, sizeof(state_compat1_path), OSPFD_COMPAT_STATE_NAME); + /* no COMPAT2 here since it was reading that was broken, + * there is no additional path that would've been written + */ + state_paths[2] = NULL; } /* OSPF master init. */ diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c index 9854c8ca..478af323 100644 --- a/ospfd/ospf_memory.c +++ b/ospfd/ospf_memory.c @@ -45,3 +45,5 @@ DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper"); DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation"); DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space"); DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space"); +DEFINE_MTYPE(OSPFD, OSPF_LSA_LIST, "OSPF LSA List"); +DEFINE_MTYPE(OSPFD, OSPF_LSDB_NODE, "OSPF LSDB Linked Node"); diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h index d11b69ab..e2139b51 100644 --- a/ospfd/ospf_memory.h +++ b/ospfd/ospf_memory.h @@ -44,5 +44,7 @@ DECLARE_MTYPE(OSPF_GR_HELPER); DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR); DECLARE_MTYPE(OSPF_P_SPACE); DECLARE_MTYPE(OSPF_Q_SPACE); +DECLARE_MTYPE(OSPF_LSA_LIST); +DECLARE_MTYPE(OSPF_LSDB_NODE); #endif /* _QUAGGA_OSPF_MEMORY_H */ diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index d47d5816..2514fc0a 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -68,7 +68,7 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); nbr->priority = -1; /* DD flags. */ @@ -80,8 +80,10 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->nbr_nbma = NULL; ospf_lsdb_init(&nbr->db_sum); - ospf_lsdb_init(&nbr->ls_rxmt); + + ospf_lsdb_linked_init(&nbr->ls_rxmt); ospf_lsdb_init(&nbr->ls_req); + ospf_lsa_list_init(&nbr->ls_rxmt_list); nbr->crypt_seqnum = 0; @@ -128,7 +130,7 @@ void ospf_nbr_free(struct ospf_neighbor *nbr) EVENT_OFF(nbr->t_inactivity); EVENT_OFF(nbr->t_db_desc); EVENT_OFF(nbr->t_ls_req); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); /* Cancel all events. */ /* Thread lookup cost would be negligible. */ event_cancel_event(master, nbr); diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 07d095f0..0e041f9e 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -9,6 +9,7 @@ #include #include +#include /* Neighbor Data Structure */ struct ospf_neighbor { @@ -44,6 +45,7 @@ struct ospf_neighbor { /* LSA data. */ struct ospf_lsdb ls_rxmt; + struct ospf_lsa_list_head ls_rxmt_list; struct ospf_lsdb db_sum; struct ospf_lsdb ls_req; struct ospf_lsa *ls_req_last; @@ -54,13 +56,13 @@ struct ospf_neighbor { uint32_t v_inactivity; uint32_t v_db_desc; uint32_t v_ls_req; - uint32_t v_ls_upd; + uint32_t v_ls_rxmt; /* Threads. */ struct event *t_inactivity; struct event *t_db_desc; struct event *t_ls_req; - struct event *t_ls_upd; + struct event *t_ls_rxmt; struct event *t_hello_reply; /* NBMA configured neighbour */ @@ -71,6 +73,7 @@ struct ospf_neighbor { struct timeval ts_last_regress; /* last regressive NSM change */ const char *last_regress_str; /* Event which last regressed NSM */ uint32_t state_change; /* NSM state change counter */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmited. */ /* BFD information */ struct bfd_session_params *bfd_session; diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index c466ddcc..079a1fa5 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -112,18 +112,16 @@ static void nsm_timer_set(struct ospf_neighbor *nbr) case NSM_Init: case NSM_TwoWay: EVENT_OFF(nbr->t_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_ExStart: OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_Exchange: - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, - nbr->v_ls_upd); if (!IS_SET_DD_MS(nbr->dd_flags)) EVENT_OFF(nbr->t_db_desc); break; diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 87aaccad..d35f0a13 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -292,54 +292,66 @@ void ospf_ls_req_event(struct ospf_neighbor *nbr) event_add_event(master, ospf_ls_req_timer, nbr, 0, &nbr->t_ls_req); } -/* Cyclic timer function. Fist registered in ospf_nbr_new () in - ospf_neighbor.c */ -void ospf_ls_upd_timer(struct event *thread) +/* + * OSPF neighbor link state retransmission timer handler. Unicast + * unacknowledged LSAs to the neigbhors. + */ +void ospf_ls_rxmt_timer(struct event *thread) { struct ospf_neighbor *nbr; + int retransmit_interval, retransmit_window, rxmt_lsa_count = 0; nbr = EVENT_ARG(thread); - nbr->t_ls_upd = NULL; + nbr->t_ls_rxmt = NULL; + retransmit_interval = nbr->v_ls_rxmt; + retransmit_window = OSPF_IF_PARAM(nbr->oi, retransmit_window); /* Send Link State Update. */ if (ospf_ls_retransmit_count(nbr) > 0) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct timeval current_time, latest_rxmt_time, next_rxmt_time; + struct timeval rxmt_interval = { retransmit_interval, 0 }; + struct timeval rxmt_window; struct list *update; - struct ospf_lsdb *lsdb; - int i; - int retransmit_interval; - retransmit_interval = - OSPF_IF_PARAM(nbr->oi, retransmit_interval); + /* + * Set the retransmission window based on the configured value + * in milliseconds. + */ + rxmt_window.tv_sec = retransmit_window / 1000; + rxmt_window.tv_usec = (retransmit_window % 1000) * 1000; + + /* + * Calculate the latest retransmit time for LSAs transmited in + * this timer pass by adding the retransmission window to the + * current time. Calculate the next retransmission time by adding + * the retransmit interval to the current time. + */ + monotime(¤t_time); + timeradd(¤t_time, &rxmt_window, &latest_rxmt_time); + timeradd(¤t_time, &rxmt_interval, &next_rxmt_time); - lsdb = &nbr->ls_rxmt; update = list_new(); + while ((ls_rxmt_list_entry = + ospf_lsa_list_first(&nbr->ls_rxmt_list))) { + if (timercmp(&ls_rxmt_list_entry->list_entry_time, + &latest_rxmt_time, >)) + break; - for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { - struct route_table *table = lsdb->type[i].db; - struct route_node *rn; - - for (rn = route_top(table); rn; rn = route_next(rn)) { - struct ospf_lsa *lsa; - - if ((lsa = rn->info) != NULL) { - /* Don't retransmit an LSA if we - received it within - the last RxmtInterval seconds - this - is to allow the - neighbour a chance to acknowledge the - LSA as it may - have ben just received before the - retransmit timer - fired. This is a small tweak to what - is in the RFC, - but it will cut out out a lot of - retransmit traffic - - MAG */ - if (monotime_since(&lsa->tv_recv, NULL) - >= retransmit_interval * 1000000LL) - listnode_add(update, rn->info); - } - } + listnode_add(update, ls_rxmt_list_entry->lsa); + rxmt_lsa_count++; + + /* + * Set the next retransmit time for the LSA and move it + * to the end of the neighbor's retransmission list. + */ + ls_rxmt_list_entry->list_entry_time = next_rxmt_time; + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + nbr->ls_rxmt_lsa++; + nbr->oi->ls_rxmt_lsa++; } if (listcount(update) > 0) @@ -348,23 +360,25 @@ void ospf_ls_upd_timer(struct event *thread) list_delete(&update); } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) timer event - sent %u LSAs", + ospf_ls_retransmit_count(nbr), &nbr->router_id, + ospf_get_name(nbr->oi->ospf), rxmt_lsa_count); + /* Set LS Update retransmission timer. */ - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); + ospf_ls_retransmit_set_timer(nbr); } -void ospf_ls_ack_timer(struct event *thread) +void ospf_ls_ack_delayed_timer(struct event *thread) { struct ospf_interface *oi; oi = EVENT_ARG(thread); - oi->t_ls_ack = NULL; + oi->t_ls_ack_delayed = NULL; /* Send Link State Acknowledgment. */ - if (listcount(oi->ls_ack) > 0) + if (ospf_lsa_list_count(&oi->ls_ack_delayed)) ospf_ls_ack_send_delayed(oi); - - /* Set LS Ack timer. */ - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); } #ifdef WANT_OSPF_WRITE_FRAGMENT @@ -1803,7 +1817,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa) && !current && ospf_check_nbr_status(oi->ospf)) { /* (4a) Response Link State Acknowledgment. */ - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); /* (4b) Discard LSA. */ if (IS_DEBUG_OSPF(lsa, LSA)) { @@ -1828,7 +1842,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa)) { zlog_info("LSA[%s]: Boomerang effect?", dump_lsa_key(lsa)); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); ospf_lsa_discard(lsa); if (current != NULL && !IS_LSA_MAXAGE(current)) @@ -1862,7 +1876,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, SET_FLAG(lsa->flags, OSPF_LSA_SELF); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); if (!ospf->gr_info.restart_in_progress) { ospf_opaque_self_originated_lsa_received( @@ -2001,9 +2015,8 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, */ if (oi->state == ISM_Backup) if (NBR_IS_DR(nbr)) - listnode_add( - oi->ls_ack, - ospf_lsa_lock(lsa)); + ospf_ls_ack_send_direct(nbr, + lsa); DISCARD_LSA(lsa, 6); } else @@ -2012,7 +2025,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, receiving interface. */ { - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); DISCARD_LSA(lsa, 7); } } @@ -2793,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) @@ -2804,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; + } } /* @@ -3314,17 +3334,35 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update, return length; } -static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, - struct stream *s) +static int ospf_make_ls_ack(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct stream *s) { - struct listnode *node, *nnode; + struct ospf_lsa_list_entry *ls_ack_list_first; + struct ospf_lsa_list_entry *ls_ack_list_entry; uint16_t length = OSPF_LS_ACK_MIN_SIZE; - unsigned long delta = OSPF_LSA_HEADER_SIZE; struct ospf_lsa *lsa; + struct in_addr first_dst_addr = { INADDR_ANY }; - for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) { + /* + * For direct LS Acks, assure the destination address doesn't + * change between queued acknowledgments. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + if (ls_ack_list_first) + first_dst_addr.s_addr = + ls_ack_list_first->list_entry_dst.s_addr; + } + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; assert(lsa); + if (direct_ack && (ls_ack_list_entry->list_entry_dst.s_addr != + first_dst_addr.s_addr)) + break; + /* LS Ack packet overflows interface MTU * delta is just number of bytes required for * 1 LS Ack(1 LS Hdr) ospf_packet_max will return @@ -3333,19 +3371,46 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, * against ospf_packet_max to check if it can fit * another ls header in the same packet. */ - if ((length + delta) > ospf_packet_max(oi)) + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) break; stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE); length += OSPF_LSA_HEADER_SIZE; - listnode_delete(ack, lsa); - ospf_lsa_unlock(&lsa); /* oi->ls_ack_direct.ls_ack */ + if (delete_ack) { + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } } return length; } +/* + * On non-braodcast networks, the same LS acks must be sent to multiple + * neighbors and deletion must be deferred until after the LS Ack packet + * is sent to all neighbors. + */ +static void ospf_delete_ls_ack_delayed(struct ospf_interface *oi) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + uint16_t length = OSPF_LS_ACK_MIN_SIZE; + + frr_each_safe (ospf_lsa_list, &oi->ls_ack_delayed, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + assert(lsa); + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) + break; + + length += OSPF_LSA_HEADER_SIZE; + ospf_lsa_list_del(&oi->ls_ack_delayed, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + static void ospf_hello_send_sub(struct ospf_interface *oi, in_addr_t addr) { struct ospf_packet *op; @@ -3917,10 +3982,13 @@ void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag, &oi->t_ls_upd_event); } -static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, +static void ospf_ls_ack_send_list(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct in_addr dst) { struct ospf_packet *op; + struct ospf_lsa_list_entry *ls_ack_list_first; uint16_t length = OSPF_HEADER_SIZE; op = ospf_packet_new(oi->ifp->mtu); @@ -3928,8 +3996,18 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Prepare OSPF common header. */ ospf_make_header(OSPF_MSG_LS_ACK, oi, op->s); + /* Determine the destination address - for direct acks, + * the list entries always include the distination address. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + op->dst.s_addr = ls_ack_list_first->list_entry_dst.s_addr; + } else + op->dst.s_addr = dst.s_addr; + /* Prepare OSPF Link State Acknowledgment body. */ - length += ospf_make_ls_ack(oi, ack, op->s); + length += ospf_make_ls_ack(oi, ls_ack_list, direct_ack, delete_ack, + op->s); /* Fill OSPF header. */ ospf_fill_header(oi, op->s, length); @@ -3937,14 +4015,6 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Set packet length. */ op->length = length; - /* Decide destination address. */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT || - (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && - !oi->p2mp_non_broadcast)) - op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - op->dst.s_addr = dst.s_addr; - /* Add packet to the interface output queue. */ ospf_packet_add(oi, op); @@ -3952,34 +4022,96 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, OSPF_ISM_WRITE_ON(oi->ospf); } -static void ospf_ls_ack_send_event(struct event *thread) +static void ospf_ls_ack_send_direct_event(struct event *thread) { struct ospf_interface *oi = EVENT_ARG(thread); + struct in_addr dst = { INADDR_ANY }; oi->t_ls_ack_direct = NULL; - while (listcount(oi->ls_ack_direct.ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack_direct.ls_ack, - oi->ls_ack_direct.dst); + while (ospf_lsa_list_count(&oi->ls_ack_direct)) + ospf_ls_ack_send_list(oi, &(oi->ls_ack_direct), true, true, dst); } -void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; struct ospf_interface *oi = nbr->oi; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &nbr->router_id, + IF_NAME(nbr->oi)); + + /* + * On Point-to-Multipoint broadcast-capabile interfaces, + * where direct acks from are sent to the ALLSPFRouters + * address and one direct ack send event, may include LSAs + * from multiple neighbors, there is a possibility of the same + * LSA being processed more than once in the same send event. + * In this case, the instances subsequent to the first can be + * ignored. + */ + if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && !oi->p2mp_non_broadcast) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *ack_queue_lsa; + + frr_each (ospf_lsa_list, &oi->ls_ack_direct, ls_ack_list_entry) { + ack_queue_lsa = ls_ack_list_entry->lsa; + if ((lsa == ack_queue_lsa) || + ((lsa->data->type == ack_queue_lsa->data->type) && + (lsa->data->id.s_addr == + ack_queue_lsa->data->id.s_addr) && + (lsa->data->adv_router.s_addr == + ack_queue_lsa->data->adv_router.s_addr) && + (lsa->data->ls_seqnum == + ack_queue_lsa->data->ls_seqnum))) { + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue duplicate", + __func__, lsa->data->type, + &lsa->data->id, + &lsa->data->adv_router, + ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), + &nbr->router_id, + IF_NAME(nbr->oi)); + return; + } + } + } + if (IS_GRACE_LSA(lsa)) { if (IS_DEBUG_OSPF_GR) zlog_debug("%s, Sending GRACE ACK to Restarter.", __func__); } - if (listcount(oi->ls_ack_direct.ls_ack) == 0) - oi->ls_ack_direct.dst = nbr->address.u.prefix4; + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + + /* + * Determine the destination address - Direct LS acknowledgments + * are sent the AllSPFRouters multicast address on Point-to-Point + * and Point-to-Multipoint broadcast-capable interfaces. For all other + * interface types, they are unicast directly to the neighbor. + */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT || + (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && + !oi->p2mp_non_broadcast)) + ls_ack_list_entry->list_entry_dst.s_addr = + htonl(OSPF_ALLSPFROUTERS); + else + ls_ack_list_entry->list_entry_dst.s_addr = + nbr->address.u.prefix4.s_addr; - listnode_add(oi->ls_ack_direct.ls_ack, ospf_lsa_lock(lsa)); + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->oi->ls_ack_direct, ls_ack_list_entry); - event_add_event(master, ospf_ls_ack_send_event, oi, 0, - &oi->t_ls_ack_direct); + if (oi->t_ls_ack_direct == NULL) + event_add_event(master, ospf_ls_ack_send_direct_event, oi, 0, + &oi->t_ls_ack_direct); } /* Send Link State Acknowledgment delayed. */ @@ -3996,33 +4128,39 @@ void ospf_ls_ack_send_delayed(struct ospf_interface *oi) struct ospf_neighbor *nbr; struct route_node *rn; - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { - nbr = rn->info; + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) { + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; - if (!nbr) - continue; + if (!nbr) + continue; - if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list( - oi, oi->ls_ack, - nbr->address.u.prefix4); + if (nbr != oi->nbr_self && + nbr->state >= NSM_Exchange) + ospf_ls_ack_send_list(oi, + &oi->ls_ack_delayed, + false, false, + nbr->address.u + .prefix4); + } + ospf_delete_ls_ack_delayed(oi); } - return; - } - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - dst.s_addr = oi->vl_data->peer_addr.s_addr; - else if (oi->state == ISM_DR || oi->state == ISM_Backup) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - dst.s_addr = htonl(OSPF_ALLDROUTERS); + } else { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + dst.s_addr = oi->vl_data->peer_addr.s_addr; + else if (oi->state == ISM_DR || oi->state == ISM_Backup) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else + dst.s_addr = htonl(OSPF_ALLDROUTERS); - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack, dst); + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) + ospf_ls_ack_send_list(oi, &oi->ls_ack_delayed, false, + true, dst); + } } /* diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h index 23473897..84e4b027 100644 --- a/ospfd/ospf_packet.h +++ b/ospfd/ospf_packet.h @@ -135,13 +135,14 @@ extern void ospf_ls_upd_send(struct ospf_neighbor *, struct list *, int, int); extern void ospf_ls_upd_queue_send(struct ospf_interface *oi, struct list *update, struct in_addr addr, int send_lsupd_now); -extern void ospf_ls_ack_send(struct ospf_neighbor *, struct ospf_lsa *); +extern void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, + struct ospf_lsa *lsa); extern void ospf_ls_ack_send_delayed(struct ospf_interface *); extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *); extern void ospf_ls_req_event(struct ospf_neighbor *); -extern void ospf_ls_upd_timer(struct event *thread); -extern void ospf_ls_ack_timer(struct event *thread); +extern void ospf_ls_rxmt_timer(struct event *thread); +extern void ospf_ls_ack_delayed_timer(struct event *thread); extern void ospf_poll_timer(struct event *thread); extern void ospf_hello_reply_timer(struct event *thread); diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index dbe44f7b..76e6efeb 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 []", @@ -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 198309c1..97dc5786 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 7cb51976..4e1c0838 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -339,6 +339,12 @@ DEFPY (no_ospf_router_id, return CMD_SUCCESS; } +ALIAS_HIDDEN (no_ospf_router_id, + no_router_id_cmd, + "no router-id [A.B.C.D]", + NO_STR + "router-id for the OSPF process\n" + "OSPF router-id in IP address format\n") static void ospf_passive_interface_default_update(struct ospf *ospf, uint8_t newval) @@ -815,6 +821,7 @@ struct ospf_vl_config_data { int del_keychain; int hello_interval; /* Obvious what these are... */ int retransmit_interval; + int retransmit_window; int transmit_delay; int dead_interval; }; @@ -957,6 +964,12 @@ static int ospf_vl_set_timers(struct ospf_vl_data *vl_data, vl_config->retransmit_interval; } + if (vl_config->retransmit_window) { + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = + vl_config->retransmit_window; + } + if (vl_config->transmit_delay) { SET_IF_PARAM(IF_DEF_PARAMS(ifp), transmit_delay); IF_DEF_PARAMS(ifp)->transmit_delay = vl_config->transmit_delay; @@ -1012,14 +1025,16 @@ static int ospf_vl_set(struct ospf *ospf, struct ospf_vl_config_data *vl_config) "Use null authentication\n" \ "Use message-digest authentication\n" -#define VLINK_HELPSTR_TIME_PARAM \ - "Time between HELLO packets\n" \ - "Seconds\n" \ - "Time between retransmitting lost link state advertisements\n" \ - "Seconds\n" \ - "Link state transmit delay\n" \ - "Seconds\n" \ - "Interval time after which a neighbor is declared down\n" \ +#define VLINK_HELPSTR_TIME_PARAM \ + "Time between HELLO packets\n" \ + "Seconds\n" \ + "Time between retransmitting lost link state advertisements\n" \ + "Seconds\n" \ + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" \ + "Milliseconds\n" \ + "Link state transmit delay\n" \ + "Seconds\n" \ + "Interval time after which a neighbor is declared down\n" \ "Seconds\n" #define VLINK_HELPSTR_AUTH_SIMPLE \ @@ -1204,7 +1219,7 @@ DEFUN (no_ospf_area_vlink, DEFUN (ospf_area_vlink_intervals, ospf_area_vlink_intervals_cmd, - "area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-10000)|transmit-delay (1-65535)|dead-interval (1-65535)}", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) { @@ -1236,6 +1251,9 @@ DEFUN (ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = strtol(argv[++idx]->arg, NULL, 10); + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = strtol(argv[++idx]->arg, + NULL, 10); else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = strtol(argv[++idx]->arg, NULL, 10); @@ -1250,7 +1268,7 @@ DEFUN (ospf_area_vlink_intervals, DEFUN (no_ospf_area_vlink_intervals, no_ospf_area_vlink_intervals_cmd, - "no area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "no area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-1000)|transmit-delay (1-65535)|dead-interval (1-65535)}", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) @@ -1282,6 +1300,9 @@ DEFUN (no_ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = + OSPF_RETRANSMIT_WINDOW_DEFAULT; else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; else if (strmatch(argv[idx]->text, "dead-interval")) @@ -2096,7 +2117,7 @@ DEFUN (ospf_abr_type, DEFUN (no_ospf_abr_type, no_ospf_abr_type_cmd, - "no ospf abr-type ", + "no ospf abr-type []", NO_STR "OSPF specific commands\n" "Set OSPF ABR type\n" @@ -2276,6 +2297,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; @@ -3576,8 +3601,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, struct route_node *rn; uint32_t bandwidth = ifp->bandwidth ? ifp->bandwidth : ifp->speed; struct ospf_if_params *params; - json_object *json_ois = NULL; - json_object *json_oi = NULL; /* Is interface up? */ if (use_json) { @@ -3628,33 +3651,17 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, } } - if (use_json) { - json_ois = json_object_new_object(); - json_object_object_add(json_interface_sub, "interfaceIp", - json_ois); - } - for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { struct ospf_interface *oi = rn->info; if (oi == NULL) continue; -#if CONFDATE > 20240601 - CPP_NOTICE( - "Use all fields following ospfEnabled from interfaceIp hierarchy") -#endif - - if (use_json) - json_oi = json_object_new_object(); - if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) { - if (use_json) { + if (use_json) json_object_boolean_true_add(json_interface_sub, "ifUnnumbered"); - json_object_boolean_true_add(json_oi, - "ifUnnumbered"); - } else + else vty_out(vty, " This interface is UNNUMBERED,"); } else { struct in_addr dest; @@ -3668,13 +3675,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "ipAddressPrefixlen", oi->address->prefixlen); - - json_object_string_addf( - json_oi, "ipAddress", "%pI4", - &oi->address->u.prefix4); - json_object_int_add(json_oi, - "ipAddressPrefixlen", - oi->address->prefixlen); } else vty_out(vty, " Internet Address %pFX,", oi->address); @@ -3700,26 +3700,14 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_string_add(json_interface_sub, "ospfIfType", dstr); - json_object_string_add(json_oi, "ospfIfType", - dstr); - - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) json_object_string_addf( json_interface_sub, "vlinkPeer", "%pI4", &dest); - - json_object_string_addf(json_oi, - "vlinkPeer", - "%pI4", &dest); - } else { + else json_object_string_addf( json_interface_sub, "localIfUsed", "%pI4", &dest); - - json_object_string_addf(json_oi, - "localIfUsed", - "%pI4", &dest); - } } else vty_out(vty, " %s %pI4,", dstr, &dest); @@ -3728,16 +3716,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_string_add(json_interface_sub, "area", ospf_area_desc_string(oi->area)); - json_object_string_add(json_oi, "area", - ospf_area_desc_string(oi->area)); - - if (OSPF_IF_PARAM(oi, mtu_ignore)) { - json_object_boolean_true_add( - json_oi, "mtuMismatchDetect"); + if (OSPF_IF_PARAM(oi, mtu_ignore)) json_object_boolean_true_add( json_interface_sub, "mtuMismatchDetect"); - } json_object_string_addf(json_interface_sub, "routerId", "%pI4", &ospf->router_id); @@ -3754,18 +3736,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, oi->state, NULL)); json_object_int_add(json_interface_sub, "priority", PRIORITY(oi)); - - json_object_string_addf(json_oi, "routerId", "%pI4", - &ospf->router_id); - json_object_string_add(json_oi, "networkType", - ospf_network_type_str[oi->type]); - json_object_int_add(json_oi, "cost", oi->output_cost); - json_object_int_add(json_oi, "transmitDelaySecs", - OSPF_IF_PARAM(oi, transmit_delay)); - json_object_string_add(json_oi, "state", - lookup_msg(ospf_ism_state_msg, - oi->state, NULL)); - json_object_int_add(json_oi, "priority", PRIORITY(oi)); json_object_boolean_add( json_interface_sub, "opaqueCapable", OSPF_IF_PARAM(oi, opaque_capable)); @@ -3809,13 +3779,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_interface_sub, "drAddress", "%pI4", &nbr->address.u.prefix4); - - json_object_string_addf( - json_oi, "drId", "%pI4", - &nbr->router_id); - json_object_string_addf( - json_oi, "drAddress", "%pI4", - &nbr->address.u.prefix4); } else { vty_out(vty, " Designated Router (ID) %pI4", @@ -3841,13 +3804,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_interface_sub, "bdrAddress", "%pI4", &nbr->address.u.prefix4); - - json_object_string_addf( - json_oi, "bdrId", "%pI4", - &nbr->router_id); - json_object_string_addf( - json_oi, "bdrAddress", "%pI4", - &nbr->address.u.prefix4); } else { vty_out(vty, " Backup Designated Router (ID) %pI4,", @@ -3863,43 +3819,28 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, if (oi->params && ntohl(oi->params->network_lsa_seqnum) != OSPF_INITIAL_SEQUENCE_NUMBER) { - if (use_json) { + if (use_json) json_object_int_add( json_interface_sub, "networkLsaSequence", ntohl(oi->params->network_lsa_seqnum)); - - json_object_int_add( - json_oi, "networkLsaSequence", - ntohl(oi->params->network_lsa_seqnum)); - } else { + else vty_out(vty, " Saved Network-LSA sequence number 0x%x\n", ntohl(oi->params->network_lsa_seqnum)); - } } if (use_json) { if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS) || OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { - if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) { + if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) json_object_boolean_true_add( json_interface_sub, "mcastMemberOspfAllRouters"); - - json_object_boolean_true_add( - json_oi, - "mcastMemberOspfAllRouters"); - } - if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { + if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) json_object_boolean_true_add( json_interface_sub, "mcastMemberOspfDesignatedRouters"); - - json_object_boolean_true_add( - json_oi, - "mcastMemberOspfDesignatedRouters"); - } } } else { vty_out(vty, " Multicast group memberships:"); @@ -3915,23 +3856,14 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, } if (use_json) { - if (OSPF_IF_PARAM(oi, fast_hello) == 0) { + if (OSPF_IF_PARAM(oi, fast_hello) == 0) json_object_int_add( json_interface_sub, "timerMsecs", OSPF_IF_PARAM(oi, v_hello) * 1000); - - json_object_int_add(json_oi, "timerMsecs", - OSPF_IF_PARAM(oi, v_hello) * - 1000); - } else { + else json_object_int_add( json_interface_sub, "timerMsecs", 1000 / OSPF_IF_PARAM(oi, fast_hello)); - - json_object_int_add( - json_oi, "timerMsecs", - 1000 / OSPF_IF_PARAM(oi, fast_hello)); - } json_object_int_add(json_interface_sub, "timerDeadSecs", OSPF_IF_PARAM(oi, v_wait)); json_object_int_add(json_interface_sub, "timerWaitSecs", @@ -3939,14 +3871,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add( json_interface_sub, "timerRetransmitSecs", OSPF_IF_PARAM(oi, retransmit_interval)); - - json_object_int_add(json_oi, "timerDeadSecs", - OSPF_IF_PARAM(oi, v_wait)); - json_object_int_add(json_oi, "timerWaitSecs", - OSPF_IF_PARAM(oi, v_wait)); - json_object_int_add( - json_oi, "timerRetransmitSecs", - OSPF_IF_PARAM(oi, retransmit_interval)); + json_object_int_add(json_interface_sub, + "timerRetransmitWindowMsecs", + OSPF_IF_PARAM(oi, + retransmit_window)); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); @@ -3975,23 +3903,17 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "timerHelloInMsecs", time_store); - json_object_int_add(json_oi, - "timerHelloInMsecs", - time_store); } else vty_out(vty, " Hello due in %s\n", ospf_timer_dump(oi->t_hello, timebuf, sizeof(timebuf))); } else /* passive-interface is set */ { - if (use_json) { + if (use_json) json_object_boolean_true_add( json_interface_sub, "timerPassiveIface"); - - json_object_boolean_true_add( - json_oi, "timerPassiveIface"); - } else + else vty_out(vty, " No Hellos (Passive interface)\n"); } @@ -4002,11 +3924,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "nbrAdjacentCount", ospf_nbr_count(oi, NSM_Full)); - - json_object_int_add(json_oi, "nbrCount", - ospf_nbr_count(oi, 0)); - json_object_int_add(json_oi, "nbrAdjacentCount", - ospf_nbr_count(oi, NSM_Full)); } else vty_out(vty, " Neighbor Count is %d, Adjacent neighbor count is %d\n", @@ -4016,14 +3933,11 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, params = IF_DEF_PARAMS(ifp); if (params && OSPF_IF_PARAM_CONFIGURED(params, v_gr_hello_delay)) { - if (use_json) { + if (use_json) json_object_int_add(json_interface_sub, "grHelloDelaySecs", params->v_gr_hello_delay); - - json_object_int_add(json_oi, "grHelloDelaySecs", - params->v_gr_hello_delay); - } else + else vty_out(vty, " Graceful Restart hello delay: %us\n", params->v_gr_hello_delay); @@ -4031,85 +3945,64 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, ospf_interface_bfd_show(vty, ifp, json_interface_sub); - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "prefixSuppression", OSPF_IF_PARAM(oi, prefix_suppression)); - json_object_boolean_add(json_oi, "prefixSuppression", - OSPF_IF_PARAM(oi, - prefix_suppression)); - } else { - if (OSPF_IF_PARAM(oi, prefix_suppression)) - vty_out(vty, - " Suppress advertisement of interface IP prefix\n"); - } + else if (OSPF_IF_PARAM(oi, prefix_suppression)) + vty_out(vty, + " Suppress advertisement of interface IP prefix\n"); /* OSPF Authentication information */ ospf_interface_auth_show(vty, oi, json_interface_sub, use_json); - ospf_interface_auth_show(vty, oi, json_oi, use_json); - /* Point-to-Multipoint Interface options. */ if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "p2mpDelayReflood", oi->p2mp_delay_reflood); - - json_object_boolean_add(json_oi, - "p2mpDelayReflood", - oi->p2mp_delay_reflood); - } else { + else vty_out(vty, " %sDelay reflooding LSAs received on P2MP interface\n", oi->p2mp_delay_reflood ? "" : "Don't "); - } - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "p2mpNonBroadcast", oi->p2mp_non_broadcast); - - json_object_boolean_add(json_oi, - "p2mpNonBroadcast", - oi->p2mp_non_broadcast); - } else { + else vty_out(vty, " P2MP interface does %ssupport broadcast\n", oi->p2mp_non_broadcast ? "not " : ""); - } } - /* Add ospf_interface object to main json blob using SIP as key - */ - if (use_json) - json_object_object_addf(json_ois, json_oi, "%pI4", - &oi->address->u.prefix4); - if (oi->nbr_filter) { - if (use_json) { + if (use_json) json_object_string_add(json_interface_sub, "nbrFilterPrefixList", prefix_list_name( oi->nbr_filter)); - json_object_string_add(json_oi, - "nbrFilterPrefixList", - prefix_list_name( - oi->nbr_filter)); - } else + else vty_out(vty, " Neighbor filter prefix-list: %s\n", prefix_list_name(oi->nbr_filter)); } else { - if (use_json) { + if (use_json) json_object_string_add(json_interface_sub, "nbrFilterPrefixList", "N/A"); - json_object_string_add(json_oi, - "nbrFilterPrefixList", - "N/A"); - } } + + /* Non-Traffic interface counters + */ + if (use_json) + json_object_int_add(json_interface_sub, + "lsaRetransmissions", + oi->ls_rxmt_lsa); + else + vty_out(vty, " LSA retransmissions: %u\n", + oi->ls_rxmt_lsa); } } @@ -5323,12 +5216,20 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, lookup_msg(ospf_ism_state_msg, ospf_nbr_ism_state(nbr), NULL)); } + /* Show state changes. */ if (use_json) json_object_int_add(json_neigh, "stateChangeCounter", nbr->state_change); else - vty_out(vty, " %d state changes\n", nbr->state_change); + vty_out(vty, " %d state changes\n", nbr->state_change); + + /* Show LSA retransmissions. */ + if (use_json) + json_object_int_add(json_neigh, "lsaRetransmissions", + nbr->ls_rxmt_lsa); + else + vty_out(vty, " %u LSA retransmissions\n", nbr->ls_rxmt_lsa); if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec) { struct timeval res; @@ -5377,7 +5278,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (DR(oi).s_addr == INADDR_ANY) { if (!use_json) vty_out(vty, - " No designated router on this network\n"); + " No designated router on this network\n"); } else { nbr_dr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi)); if (nbr_dr) { @@ -5396,14 +5297,14 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (nbr_bdr == NULL) { if (!use_json) vty_out(vty, - " No backup designated router on this network\n"); + " No backup designated router on this network\n"); } else { if (use_json) json_object_string_addf(json_neigh, "routerDesignatedBackupId", "%pI4", &nbr_bdr->router_id); else - vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); + vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); } /* Show options. */ @@ -5493,7 +5394,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, /* Show Link State Update Retransmission thread. */ if (use_json) { - if (nbr->t_ls_upd != NULL) + if (nbr->t_ls_rxmt != NULL) json_object_string_add( json_neigh, "threadLinkStateUpdateRetransmission", @@ -5501,7 +5402,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, } else vty_out(vty, " Thread Link State Update Retransmission %s\n\n", - nbr->t_ls_upd != NULL ? "on" : "off"); + nbr->t_ls_rxmt != NULL ? "on" : "off"); if (!use_json) { vty_out(vty, " Graceful restart Helper info:\n"); @@ -8139,7 +8040,7 @@ static void ospf_nbr_timer_update(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); } } @@ -8150,7 +8051,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; @@ -8266,7 +8167,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" @@ -8874,6 +8775,40 @@ DEFUN_HIDDEN (no_ospf_retransmit_interval, return no_ip_ospf_retransmit_interval(self, vty, argc, argv); } +DEFPY(ip_ospf_retransmit_window, ip_ospf_retransmit_window_addr_cmd, + "[no] ip ospf retransmit-window ![(20-1000)]$retransmit-window [A.B.C.D]$ip_addr", NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" + "Milliseconds\n" + "Address of interface\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + + params = IF_DEF_PARAMS(ifp); + + if (ip_addr.s_addr != INADDR_ANY) { + params = ospf_get_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + + if (no) { + UNSET_IF_PARAM(params, retransmit_window); + params->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + } else { + SET_IF_PARAM(params, retransmit_window); + params->retransmit_window = retransmit_window; + } + + /* + * There is nothing to do when the retransmit-window changes, any + * change will take effect the next time the interface LSA retransmision + * timer expires. + */ + return CMD_SUCCESS; +} + DEFPY (ip_ospf_gr_hdelay, ip_ospf_gr_hdelay_cmd, "ip ospf graceful-restart hello-delay (1-1800)", @@ -9921,7 +9856,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); @@ -12356,6 +12291,17 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) vty_out(vty, "\n"); } + /* Retransmit Window print. */ + if (OSPF_IF_PARAM_CONFIGURED(params, retransmit_window) && + params->retransmit_window != + OSPF_RETRANSMIT_WINDOW_DEFAULT) { + vty_out(vty, " ip ospf retransmit-window %u", + params->retransmit_window); + if (params != IF_DEF_PARAMS(ifp) && rn) + vty_out(vty, " %pI4", &rn->p.u.prefix4); + vty_out(vty, "\n"); + } + /* Transmit Delay print. */ if (OSPF_IF_PARAM_CONFIGURED(params, transmit_delay) && params->transmit_delay @@ -12713,19 +12659,22 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf) oi = vl_data->vl_oi; /* timers */ - if (OSPF_IF_PARAM(oi, v_hello) - != OSPF_HELLO_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, v_wait) - != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, retransmit_interval) - != OSPF_RETRANSMIT_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, transmit_delay) - != OSPF_TRANSMIT_DELAY_DEFAULT) + if (OSPF_IF_PARAM(oi, v_hello) != + OSPF_HELLO_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, v_wait) != + OSPF_ROUTER_DEAD_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_interval) != + OSPF_RETRANSMIT_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_window) != + OSPF_RETRANSMIT_WINDOW_DEFAULT || + OSPF_IF_PARAM(oi, transmit_delay) != + OSPF_TRANSMIT_DELAY_DEFAULT) vty_out(vty, - " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d\n", + " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d retransmit-window %d transmit-delay %d dead-interval %d\n", buf, &vl_data->vl_peer, OSPF_IF_PARAM(oi, v_hello), OSPF_IF_PARAM(oi, retransmit_interval), + OSPF_IF_PARAM(oi, retransmit_window), OSPF_IF_PARAM(oi, transmit_delay), OSPF_IF_PARAM(oi, v_wait)); else @@ -13245,6 +13194,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); @@ -13258,6 +13211,9 @@ static void ospf_vty_if_init(void) install_element(INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd); + /* "ip ospf retransmit-window" commands. */ + install_element(INTERFACE_NODE, &ip_ospf_retransmit_window_addr_cmd); + /* "ip ospf transmit-delay" commands. */ install_element(INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); @@ -13674,6 +13630,7 @@ void ospf_vty_init(void) install_element(OSPF_NODE, &ospf_router_id_cmd); install_element(OSPF_NODE, &ospf_router_id_old_cmd); install_element(OSPF_NODE, &no_ospf_router_id_cmd); + install_element(OSPF_NODE, &no_router_id_cmd); /* "passive-interface" commands. */ install_element(OSPF_NODE, &ospf_passive_interface_default_cmd); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 2c518f2c..c7cba1e2 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 1d013b26..d72afec1 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -147,15 +147,10 @@ void ospf_process_refresh_data(struct ospf *ospf, bool reset) /* Select the router ID based on these priorities: 1. Statically assigned router ID is always the first choice. - 2. If there is no statically assigned router ID, then try to stick - with the most recent value, since changing router ID's is very - disruptive. - 3. Last choice: just go with whatever the zebra daemon recommends. + 2. Just go with whatever the zebra daemon recommends. */ if (ospf->router_id_static.s_addr != INADDR_ANY) router_id = ospf->router_id_static; - else if (ospf->router_id.s_addr != INADDR_ANY) - router_id = ospf->router_id; else router_id = ospf->router_id_zebra; @@ -1098,6 +1093,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 e22931c1..bf8a9ea0 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 ec9d8adf..a0a53b0d 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 d6dbcb5c..a4f899df 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 47a811d1..8ceadb3e 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 [$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 df23f931..0f8d3827 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 a1bc784b..7f3b3f59 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 6c13503c..431fe4d1 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); @@ -148,6 +146,16 @@ void srte_segment_list_del(struct srte_segment_list *segment_list) XFREE(MTYPE_PATH_SEGMENT_LIST, segment_list); } +static void srte_segment_list_terminate(void) +{ + while (!RB_EMPTY(srte_segment_list_head, &srte_segment_lists)) { + struct srte_segment_list *sl = RB_ROOT(srte_segment_list_head, + &srte_segment_lists); + + srte_segment_list_del(sl); + } +} + /** * Search for a segment list by name. * @@ -1271,16 +1279,15 @@ 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(); srte_clean_zebra(); + + srte_segment_list_terminate(); + + vrf_terminate(); + frr_fini(); } diff --git a/pathd/pathd.h b/pathd/pathd.h index 73ad4922..75e7eff9 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 b30b54b7..6b0d1d5a 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 09109971..c1ffce99 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_vrf.c b/pbrd/pbr_vrf.c index ef4a4c2c..d8adb91f 100644 --- a/pbrd/pbr_vrf.c +++ b/pbrd/pbr_vrf.c @@ -123,4 +123,6 @@ void pbr_vrf_terminate(void) FOR_ALL_INTERFACES (vrf, ifp) pbr_if_del(ifp); } + + vrf_terminate(); } diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 64d88847..08fe56c7 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 ec912700..f1ebdb55 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -41,45 +41,207 @@ static struct cmd_node debug_node = { .config_write = pim_debug_config_write, }; -DEFPY (ipv6_pim_joinprune_time, - ipv6_pim_joinprune_time_cmd, - "ipv6 pim join-prune-interval (1-65535)$jpi", - IPV6_STR - PIM_STR +DEFPY_NOSH (router_pim6, + router_pim6_cmd, + "router pim6 [vrf NAME]", + "Enable a routing process\n" + "Start PIM6 configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) + return CMD_WARNING_CONFIG_FAILED; + + VTY_PUSH_XPATH(PIM6_NODE, xpath); + + return CMD_SUCCESS; +} + +DEFPY (no_router_pim6, + no_router_pim6_cmd, + "no router pim6 [vrf NAME]", + NO_STR + "Enable a routing process\n" + "Start PIM6 configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY (pim6_joinprune_time, + pim6_joinprune_time_cmd, + "join-prune-interval (1-65535)$jpi", "Join Prune Send Interval\n" "Seconds\n") { return pim_process_join_prune_cmd(vty, jpi_str); } +DEFPY_ATTR(ipv6_joinprune_time, + ipv6_pim_joinprune_time_cmd, + "ipv6 pim join-prune-interval (1-65535)$jpi", + IPV6_STR PIM_STR + "Join Prune Send Interval\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_join_prune_cmd(vty, jpi_str); -DEFPY (no_ipv6_pim_joinprune_time, - no_ipv6_pim_joinprune_time_cmd, - "no ipv6 pim join-prune-interval [(1-65535)]", + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim6_joinprune_time, + no_pim6_joinprune_time_cmd, + "no join-prune-interval [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { return pim_process_no_join_prune_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_joinprune_time, + no_ipv6_pim_joinprune_time_cmd, + "no ipv6 pim join-prune-interval [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_join_prune_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_spt_switchover_infinity, - ipv6_pim_spt_switchover_infinity_cmd, - "ipv6 pim spt-switchover infinity-and-beyond", - IPV6_STR - PIM_STR +DEFPY (pim6_spt_switchover_infinity, + pim6_spt_switchover_infinity_cmd, + "spt-switchover infinity-and-beyond", "SPT-Switchover\n" "Never switch to SPT Tree\n") { return pim_process_spt_switchover_infinity_cmd(vty); } +DEFPY_ATTR(ipv6_spt_switchover_infinity, + ipv6_pim_spt_switchover_infinity_cmd, + "ipv6 pim spt-switchover infinity-and-beyond", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_spt_switchover_infinity_plist, - ipv6_pim_spt_switchover_infinity_plist_cmd, - "ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", - IPV6_STR - PIM_STR + ret = pim_process_spt_switchover_infinity_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_spt_switchover_infinity_plist, + pim6_spt_switchover_infinity_plist_cmd, + "spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", "SPT-Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -87,25 +249,104 @@ DEFPY (ipv6_pim_spt_switchover_infinity_plist, { return pim_process_spt_switchover_prefixlist_cmd(vty, plist); } +DEFPY_ATTR(ipv6_spt_switchover_infinity_plist, + ipv6_pim_spt_switchover_infinity_plist_cmd, + "ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_spt_switchover_infinity, - no_ipv6_pim_spt_switchover_infinity_cmd, - "no ipv6 pim spt-switchover infinity-and-beyond", +DEFPY (no_pim6_spt_switchover_infinity, + no_pim6_spt_switchover_infinity_cmd, + "no spt-switchover infinity-and-beyond", NO_STR - IPV6_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n") { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity, + no_ipv6_pim_spt_switchover_infinity_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, - no_ipv6_pim_spt_switchover_infinity_plist_cmd, - "no ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", +DEFPY (no_pim6_spt_switchover_infinity_plist, + no_pim6_spt_switchover_infinity_plist_cmd, + "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", NO_STR - IPV6_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -113,100 +354,453 @@ DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity_plist, + no_ipv6_pim_spt_switchover_infinity_plist_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_packets, - ipv6_pim_packets_cmd, - "ipv6 pim packets (1-255)", - IPV6_STR - PIM_STR + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_packets, + pim6_packets_cmd, + "packets (1-255)", "packets to process at one time per fd\n" "Number of packets\n") { return pim_process_pim_packet_cmd(vty, packets_str); } +DEFPY_ATTR(ipv6_pim_packets, + ipv6_pim_packets_cmd, + "ipv6 pim packets (1-255)", + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + "Number of packets\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_pim_packet_cmd(vty, packets_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } -DEFPY (no_ipv6_pim_packets, - no_ipv6_pim_packets_cmd, - "no ipv6 pim packets [(1-255)]", + return ret; +} + +DEFPY (no_pim6_packets, + no_pim6_packets_cmd, + "no packets [(1-255)]", NO_STR - IPV6_STR - PIM_STR "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { return pim_process_no_pim_packet_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_packets, + no_ipv6_pim_packets_cmd, + "no ipv6 pim packets [(1-255)]", + NO_STR + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_keep_alive, - ipv6_pim_keep_alive_cmd, - "ipv6 pim keep-alive-timer (1-65535)$kat", - IPV6_STR - PIM_STR + ret = pim_process_no_pim_packet_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_keep_alive, + pim6_keep_alive_cmd, + "keep-alive-timer (1-65535)$kat", "Keep alive Timer\n" "Seconds\n") { return pim_process_keepalivetimer_cmd(vty, kat_str); } +DEFPY_ATTR(ipv6_pim_keep_alive, + ipv6_pim_keep_alive_cmd, + "ipv6 pim keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_keepalivetimer_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_keep_alive, - no_ipv6_pim_keep_alive_cmd, - "no ipv6 pim keep-alive-timer [(1-65535)]", +DEFPY (no_pim6_keep_alive, + no_pim6_keep_alive_cmd, + "no keep-alive-timer [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_keepalivetimer_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_keep_alive, + no_ipv6_pim_keep_alive_cmd, + "no ipv6 pim keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_rp_keep_alive, - ipv6_pim_rp_keep_alive_cmd, - "ipv6 pim rp keep-alive-timer (1-65535)$kat", - IPV6_STR - PIM_STR + ret = pim_process_no_keepalivetimer_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_rp_keep_alive, + pim6_rp_keep_alive_cmd, + "rp keep-alive-timer (1-65535)$kat", "Rendezvous Point\n" "Keep alive Timer\n" "Seconds\n") { return pim_process_rp_kat_cmd(vty, kat_str); } +DEFPY_ATTR(ipv6_pim_rp_keep_alive, + ipv6_pim_rp_keep_alive_cmd, + "ipv6 pim rp keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_kat_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp_keep_alive, - no_ipv6_pim_rp_keep_alive_cmd, - "no ipv6 pim rp keep-alive-timer [(1-65535)]", +DEFPY (no_pim6_rp_keep_alive, + no_pim6_rp_keep_alive_cmd, + "no rp keep-alive-timer [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_rp_kat_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_rp_keep_alive, + no_ipv6_pim_rp_keep_alive_cmd, + "no ipv6 pim rp keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_kat_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_register_suppress, - ipv6_pim_register_suppress_cmd, - "ipv6 pim register-suppress-time (1-65535)$rst", - IPV6_STR - PIM_STR +DEFPY (pim6_register_suppress, + pim6_register_suppress_cmd, + "register-suppress-time (1-65535)$rst", "Register Suppress Timer\n" "Seconds\n") { return pim_process_register_suppress_cmd(vty, rst_str); } +DEFPY_ATTR(ipv6_pim_register_suppress, + ipv6_pim_register_suppress_cmd, + "ipv6 pim register-suppress-time (1-65535)$rst", + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_register_suppress_cmd(vty, rst_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_register_suppress, - no_ipv6_pim_register_suppress_cmd, - "no ipv6 pim register-suppress-time [(1-65535)]", +DEFPY (no_pim6_register_suppress, + no_pim6_register_suppress_cmd, + "no register-suppress-time [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Register Suppress Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_register_suppress_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_register_suppress, + no_ipv6_pim_register_suppress_cmd, + "no ipv6 pim register-suppress-time [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_register_suppress_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (interface_ipv6_pim, interface_ipv6_pim_cmd, @@ -405,11 +999,9 @@ DEFPY (interface_no_ipv6_mroute, source_str); } -DEFPY (ipv6_pim_rp, - ipv6_pim_rp_cmd, - "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", - IPV6_STR - PIM_STR +DEFPY (pim6_rp, + pim6_rp_cmd, + "rp X:X::X:X$rp [X:X::X:X/M]$gp", "Rendezvous Point\n" "ipv6 address of RP\n" "Group Address range to cover\n") @@ -418,13 +1010,53 @@ DEFPY (ipv6_pim_rp, return pim_process_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(ipv6_pim_rp, + ipv6_pim_rp_cmd, + "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp, - no_ipv6_pim_rp_cmd, - "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", +DEFPY (no_pim6_rp, + no_pim6_rp_cmd, + "no rp X:X::X:X$rp [X:X::X:X/M]$gp", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "ipv6 address of RP\n" "Group Address range to cover\n") @@ -433,12 +1065,53 @@ DEFPY (no_ipv6_pim_rp, return pim_process_no_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(no_ipv6_pim_rp, + no_ipv6_pim_rp_cmd, + "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_rp_prefix_list, - ipv6_pim_rp_prefix_list_cmd, - "ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", - IPV6_STR - PIM_STR + ret = pim_process_no_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_rp_prefix_list, + pim6_rp_prefix_list_cmd, + "rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", "Rendezvous Point\n" "ipv6 address of RP\n" "group prefix-list filter\n" @@ -446,13 +1119,53 @@ DEFPY (ipv6_pim_rp_prefix_list, { return pim_process_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(ipv6_pim_rp_prefix_list, + ipv6_pim_rp_prefix_list_cmd, + "ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } -DEFPY (no_ipv6_pim_rp_prefix_list, - no_ipv6_pim_rp_prefix_list_cmd, - "no ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + return ret; +} + +DEFPY (no_pim6_rp_prefix_list, + no_pim6_rp_prefix_list_cmd, + "no rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "ipv6 address of RP\n" "group prefix-list filter\n" @@ -460,6 +1173,49 @@ DEFPY (no_ipv6_pim_rp_prefix_list, { return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(no_ipv6_pim_rp_prefix_list, + no_ipv6_pim_rp_prefix_list_cmd, + "no ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (ipv6_pim_bsm, ipv6_pim_bsm_cmd, @@ -503,10 +1259,65 @@ DEFPY (no_ipv6_pim_ucast_bsm, return pim_process_no_unicast_bsm_cmd(vty); } -DEFPY (ipv6_ssmpingd, - ipv6_ssmpingd_cmd, - "ipv6 ssmpingd [X:X::X:X]$source", - IPV6_STR +DEFPY (pim6_bsr_candidate_bsr, + pim6_bsr_candidate_bsr_cmd, + "[no] bsr candidate-bsr [{priority (0-255)|source
}]", + 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
}]", + 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", CONF_SSMPINGD_STR "Source address\n") { @@ -514,61 +1325,151 @@ DEFPY (ipv6_ssmpingd, return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); } +DEFPY_ATTR(ipv6_ssmpingd, + ipv6_ssmpingd_cmd, + "ipv6 ssmpingd [X:X::X:X]$source", + IPV6_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *src_str = (source_str) ? source_str : "::"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); -DEFPY (no_ipv6_ssmpingd, - no_ipv6_ssmpingd_cmd, - "no ipv6 ssmpingd [X:X::X:X]$source", - NO_STR - IPV6_STR - CONF_SSMPINGD_STR - "Source address\n") + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim6_ssmpingd, + no_pim6_ssmpingd_cmd, + "no ssmpingd [X:X::X:X]$source", + NO_STR + CONF_SSMPINGD_STR + "Source address\n") { const char *src_str = (source_str) ? source_str : "::"; return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); } - -DEFPY (interface_ipv6_mld_join, - interface_ipv6_mld_join_cmd, - "ipv6 mld join X:X::X:X$group [X:X::X:X$source]", - IPV6_STR - IFACE_MLD_STR - "MLD join multicast group\n" - "Multicast group address\n" - "Source address\n") +DEFPY_ATTR(no_ipv6_ssmpingd, + no_ipv6_ssmpingd_cmd, + "no ipv6 ssmpingd [X:X::X:X]$source", + NO_STR + IPV6_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { + int ret; + const char *src_str = (source_str) ? source_str : "::"; + const char *vrfname; 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); + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { return CMD_WARNING_CONFIG_FAILED; } - } else - source_str = "::"; + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } - snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv6", - group_str, source_str); + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return nb_cli_apply_changes(vty, NULL); + return ret; } -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]", +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"); + +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 + "Static multicast group\n" + "Multicast group address\n" "Source address\n") { char xpath[XPATH_MAXLEN]; @@ -581,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); @@ -874,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]", @@ -1733,12 +2718,16 @@ DEFPY (debug_pimv6_bsm, return CMD_SUCCESS; } -void pim_cmd_init(void) -{ - if_cmd_init(pim_interface_config_write); - - install_node(&debug_node); +struct cmd_node pim6_node = { + .name = "pim6", + .node = PIM6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim6)# ", + .config_write = pim_router_config_write, +}; +static void pim_install_deprecated(void) +{ install_element(CONFIG_NODE, &ipv6_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ipv6_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &ipv6_pim_spt_switchover_infinity_cmd); @@ -1753,6 +2742,63 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ipv6_pim_rp_keep_alive_cmd); install_element(CONFIG_NODE, &ipv6_pim_register_suppress_cmd); install_element(CONFIG_NODE, &no_ipv6_pim_register_suppress_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); + install_element(VRF_NODE, &ipv6_ssmpingd_cmd); + install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); + install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); +} + +void pim_cmd_init(void) +{ + if_cmd_init(pim_interface_config_write); + + install_node(&debug_node); + + pim_install_deprecated(); + + install_element(CONFIG_NODE, &router_pim6_cmd); + install_element(CONFIG_NODE, &no_router_pim6_cmd); + + install_node(&pim6_node); + install_default(PIM6_NODE); + + install_element(PIM6_NODE, &pim6_joinprune_time_cmd); + install_element(PIM6_NODE, &no_pim6_joinprune_time_cmd); + install_element(PIM6_NODE, &pim6_spt_switchover_infinity_cmd); + install_element(PIM6_NODE, &pim6_spt_switchover_infinity_plist_cmd); + install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_cmd); + install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_plist_cmd); + install_element(PIM6_NODE, &pim6_packets_cmd); + install_element(PIM6_NODE, &no_pim6_packets_cmd); + install_element(PIM6_NODE, &pim6_keep_alive_cmd); + install_element(PIM6_NODE, &no_pim6_keep_alive_cmd); + install_element(PIM6_NODE, &pim6_rp_keep_alive_cmd); + install_element(PIM6_NODE, &no_pim6_rp_keep_alive_cmd); + install_element(PIM6_NODE, &pim6_register_suppress_cmd); + install_element(PIM6_NODE, &no_pim6_register_suppress_cmd); + install_element(PIM6_NODE, &pim6_rp_cmd); + install_element(PIM6_NODE, &no_pim6_rp_cmd); + install_element(PIM6_NODE, &pim6_rp_prefix_list_cmd); + 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); + install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); + install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_pim_cmd); install_element(INTERFACE_NODE, &interface_ipv6_pim_drprio_cmd); @@ -1764,10 +2810,8 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_no_ipv6_pim_ssm_cmd); install_element(INTERFACE_NODE, &interface_ipv6_pim_sm_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_pim_sm_cmd); - install_element(INTERFACE_NODE, - &interface_ipv6_pim_boundary_oil_cmd); - install_element(INTERFACE_NODE, - &interface_no_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_boundary_oil_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd); /* Install BSM command */ @@ -1775,31 +2819,17 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &no_ipv6_pim_bsm_cmd); install_element(INTERFACE_NODE, &ipv6_pim_ucast_bsm_cmd); install_element(INTERFACE_NODE, &no_ipv6_pim_ucast_bsm_cmd); - install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); - install_element(VRF_NODE, &ipv6_pim_rp_cmd); - install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); - install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); - install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); - install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); - install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); - install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); - install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); - install_element(VRF_NODE, &ipv6_ssmpingd_cmd); - install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); - install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); + 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); install_element(INTERFACE_NODE, &interface_no_ipv6_mld_query_interval_cmd); - install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); - install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); - install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); - install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mld_query_max_response_time_cmd); install_element(INTERFACE_NODE, @@ -1818,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 5ce6985c..07b70ae2 100644 --- a/pimd/pim6_main.c +++ b/pimd/pim6_main.c @@ -94,6 +94,7 @@ struct frr_signal_t pim6d_signals[] = { }, }; +/* clang-format off */ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -102,10 +103,10 @@ 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, }; -/* clang-format off */ FRR_DAEMON_INFO(pim6d, PIM6, .vty_port = PIM6D_VTY_PORT, .proghelp = "Protocol Independent Multicast (RFC7761) for IPv6", diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index a39d1829..a8718377 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_addr.h b/pimd/pim_addr.h index ecba739a..c1416e1d 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -14,16 +14,19 @@ #if PIM_IPV == 4 typedef struct in_addr pim_addr; +typedef struct prefix_ipv4 prefix_pim; #define PIM_ADDRSTRLEN INET_ADDRSTRLEN #define PIM_AF AF_INET #define PIM_AFI AFI_IP #define PIM_PROTO_REG IPPROTO_RAW +#define PIM_IANA_AFI IANA_AFI_IPV4 #define PIM_IPADDR IPADDR_V4 #define ipaddr_pim ipaddr_v4 #define PIM_MAX_BITLEN IPV4_MAX_BITLEN #define PIM_AF_NAME "ip" #define PIM_AF_DBG "pim" +#define PIM_AF_ROUTER "pim" #define GM_AF_DBG "igmp" #define PIM_MROUTE_DBG "mroute" #define PIMREG "pimreg" @@ -44,16 +47,19 @@ union pimprefixconstptr { #else typedef struct in6_addr pim_addr; +typedef struct prefix_ipv6 prefix_pim; #define PIM_ADDRSTRLEN INET6_ADDRSTRLEN #define PIM_AF AF_INET6 #define PIM_AFI AFI_IP6 #define PIM_PROTO_REG IPPROTO_PIM +#define PIM_IANA_AFI IANA_AFI_IPV6 #define PIM_IPADDR IPADDR_V6 #define ipaddr_pim ipaddr_v6 #define PIM_MAX_BITLEN IPV6_MAX_BITLEN #define PIM_AF_NAME "ipv6" #define PIM_AF_DBG "pimv6" +#define PIM_AF_ROUTER "pim6" #define GM_AF_DBG "mld" #define PIM_MROUTE_DBG "mroute6" #define PIMREG "pim6reg" diff --git a/pimd/pim_autorp.c b/pimd/pim_autorp.c new file mode 100644 index 00000000..df4f809b --- /dev/null +++ b/pimd/pim_autorp.c @@ -0,0 +1,1166 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * pim_autorp.c: PIM AutoRP handling routines + * + * Copyright (C) 2024 ATCorp + * Nathan Bahr + */ + +#include + +#include +#include + +#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; + int ret; + + ret = pim_rp_new(autorp->pim, rpaddr, grp, listname, RP_SRC_AUTORP); + /* There may not be a path to the RP right now, but that doesn't mean it failed to add the RP */ + if (ret != PIM_SUCCESS && ret != PIM_RP_NO_PATH) { + 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 00000000..a0b029d0 --- /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 + +#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 " +#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 " +#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 " +#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 df916194..a44e4e08 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -10,6 +10,17 @@ #include "config.h" #endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #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; } @@ -1451,3 +1598,605 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, return 0; } + +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); + + if (!pim_addr_is_any(scope->current_bsr)) { + assertf(scope->cand_bsr_prio >= scope->current_bsr_prio, + "cand_bsr %pPA prio %u is less than current_bsr %pPA prio %u", + &scope->bsr_addrsel.run_addr, scope->current_bsr_prio, &scope->current_bsr, + scope->cand_bsr_prio); + + if (scope->cand_bsr_prio == scope->current_bsr_prio) + assertf(pim_addr_cmp(scope->bsr_addrsel.run_addr, scope->current_bsr) > 0, + "cand_bsr %pPA < current_bsr %pPA", &scope->bsr_addrsel.run_addr, + &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) +{ + 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 fb09e3b1..1eacc1be 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 00000000..3ec9f99c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 a2d756a9..934da2d5 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("", 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_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("", stgrp->group_addr, group_str, + sizeof(group_str)); + pim_inet4_dump("", 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) { @@ -1457,19 +1525,13 @@ static void clear_interfaces(struct pim_instance *pim) static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, const char *gname) { - const char *vrfname; - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; char xpath_member_value[XPATH_MAXLEN]; const struct lyd_node *member_dnode; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return; - /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); /* Group must exists, otherwise just quit. */ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) return; @@ -1477,8 +1539,7 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, /* Group members check: */ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value)); strlcat(xpath_member_value, "/members", sizeof(xpath_member_value)); - if (yang_dnode_exists(vty->candidate_config->dnode, - xpath_member_value)) { + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_member_value)) { member_dnode = yang_dnode_get(vty->candidate_config->dnode, xpath_member_value); if (!member_dnode || !yang_is_last_list_dnode(member_dnode)) @@ -1727,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, @@ -1756,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"); @@ -2633,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]", @@ -2714,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 @@ -2727,39 +2983,142 @@ DEFPY (show_ip_pim_bsrp, return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json); } -DEFPY (show_ip_pim_statistics, - show_ip_pim_statistics_cmd, - "show ip pim [vrf NAME] statistics [interface WORD$word] [json$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 - "PIM statistics\n" - INTERFACE_STR - "PIM interface\n" JSON_STR) { - return pim_show_statistics_helper(vrf, vty, word, !!json); + return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json); } -DEFPY (show_ip_multicast, - show_ip_multicast_cmd, - "show ip multicast [vrf NAME]", +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 - "Multicast global information\n" - VRF_CMD_HELP_STR) + PIM_STR + BSR_STR + "Current PIM router candidate BSR state\n" + VRF_CMD_HELP_STR + JSON_STR) { - return pim_show_multicast_helper(vrf, vty); + 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_multicast_vrf_all, - show_ip_multicast_vrf_all_cmd, - "show ip multicast vrf all", + +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 - "Multicast global information\n" - VRF_CMD_HELP_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]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM statistics\n" + INTERFACE_STR + "PIM interface\n" + JSON_STR) +{ + return pim_show_statistics_helper(vrf, vty, word, !!json); +} + +DEFPY (show_ip_multicast, + show_ip_multicast_cmd, + "show ip multicast [vrf NAME]", + SHOW_STR + IP_STR + "Multicast global information\n" + VRF_CMD_HELP_STR) +{ + return pim_show_multicast_helper(vrf, vty); +} + +DEFPY (show_ip_multicast_vrf_all, + show_ip_multicast_vrf_all_cmd, + "show ip multicast vrf all", + SHOW_STR + IP_STR + "Multicast global information\n" + VRF_CMD_HELP_STR) { return pim_show_multicast_vrf_all_helper(vty); } @@ -2830,6 +3189,40 @@ DEFPY (clear_ip_mroute_count, return clear_ip_mroute_count_command(vty, name); } +DEFPY(clear_ip_msdp_peer, clear_ip_msdp_peer_cmd, + "clear ip msdp peer A.B.C.D$peer [vrf WORD$vrfname]", + CLEAR_STR + IP_STR + MSDP_STR + "Restart MSDP peer\n" + "MSDP peer address\n" + VRF_CMD_HELP_STR) +{ + const struct pim_instance *pim; + const struct listnode *node; + const struct vrf *vrf; + struct pim_msdp_peer *mp; + + if (vrfname) + vrf = vrf_lookup_by_name(vrfname); + else + vrf = vrf_lookup_by_id(VRF_DEFAULT); + + if (vrf == NULL || vrf->info == NULL) + return CMD_WARNING; + + pim = vrf->info; + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) { + if (mp->peer.s_addr != peer.s_addr) + continue; + + pim_msdp_peer_restart(mp); + break; + } + + return CMD_SUCCESS; +} + DEFPY (show_ip_mroute_count, show_ip_mroute_count_cmd, "show ip mroute [vrf NAME] count [json$json]", @@ -2989,22 +3382,108 @@ DEFUN (show_ip_ssmpingd, return CMD_SUCCESS; } -DEFUN (ip_pim_spt_switchover_infinity, - ip_pim_spt_switchover_infinity_cmd, - "ip pim spt-switchover infinity-and-beyond", - IP_STR - PIM_STR +DEFPY_NOSH (router_pim, + router_pim_cmd, + "router pim [vrf NAME]", + "Enable a routing process\n" + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) + return CMD_WARNING_CONFIG_FAILED; + + VTY_PUSH_XPATH(PIM_NODE, xpath); + return CMD_SUCCESS; +} + +DEFPY (no_router_pim, + no_router_pim_cmd, + "no router pim [vrf NAME]", + NO_STR + "Enable a routing process\n" + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + + +DEFPY (pim_spt_switchover_infinity, + pim_spt_switchover_infinity_cmd, + "spt-switchover infinity-and-beyond", "SPT-Switchover\n" "Never switch to SPT Tree\n") { return pim_process_spt_switchover_infinity_cmd(vty); } +DEFPY_ATTR(ip_pim_spt_switchover_infinity, + ip_pim_spt_switchover_infinity_cmd, + "ip pim spt-switchover infinity-and-beyond", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_spt_switchover_infinity_plist, - ip_pim_spt_switchover_infinity_plist_cmd, - "ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", - IP_STR - PIM_STR + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_infinity_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_spt_switchover_infinity_plist, + pim_spt_switchover_infinity_plist_cmd, + "spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", "SPT-Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -3012,25 +3491,104 @@ DEFPY (ip_pim_spt_switchover_infinity_plist, { return pim_process_spt_switchover_prefixlist_cmd(vty, plist); } +DEFPY_ATTR(ip_pim_spt_switchover_infinity_plist, + ip_pim_spt_switchover_infinity_plist_cmd, + "ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_spt_switchover_infinity, - no_ip_pim_spt_switchover_infinity_cmd, - "no ip pim spt-switchover infinity-and-beyond", +DEFPY (no_pim_spt_switchover_infinity, + no_pim_spt_switchover_infinity_cmd, + "no spt-switchover infinity-and-beyond", NO_STR - IP_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n") { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ip_pim_spt_switchover_infinity, + no_ip_pim_spt_switchover_infinity_cmd, + "no ip pim spt-switchover infinity-and-beyond", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_spt_switchover_infinity_plist, - no_ip_pim_spt_switchover_infinity_plist_cmd, - "no ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", +DEFPY (no_pim_spt_switchover_infinity_plist, + no_pim_spt_switchover_infinity_plist_cmd, + "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", NO_STR - IP_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -3038,28 +3596,61 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ip_pim_spt_switchover_infinity_plist, + no_ip_pim_spt_switchover_infinity_plist_cmd, + "no ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (pim_register_accept_list, pim_register_accept_list_cmd, - "[no] ip pim register-accept-list PREFIXLIST4_NAME$word", + "[no] register-accept-list PREFIXLIST4_NAME$word", NO_STR - IP_STR - PIM_STR "Only accept registers from a specific source prefix list\n" "Prefix-List name\n") { - const char *vrfname; char reg_alist_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(reg_alist_xpath, "/register-accept-list", - sizeof(reg_alist_xpath)); + "./register-accept-list"); if (no) nb_cli_enqueue_change(vty, reg_alist_xpath, @@ -3070,123 +3661,560 @@ DEFPY (pim_register_accept_list, return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(ip_pim_register_accept_list, + ip_pim_register_accept_list_cmd, + "[no] ip pim register-accept-list PREFIXLIST4_NAME$word", + NO_STR + IP_STR + PIM_STR + "Only accept registers from a specific source prefix list\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char reg_alist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_joinprune_time, - ip_pim_joinprune_time_cmd, - "ip pim join-prune-interval (1-65535)$jpi", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), + "./register-accept-list"); + + if (no) + nb_cli_enqueue_change(vty, reg_alist_xpath, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, reg_alist_xpath, NB_OP_MODIFY, word); + + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_joinprune_time, + pim_joinprune_time_cmd, + "join-prune-interval (1-65535)$jpi", "Join Prune Send Interval\n" "Seconds\n") { return pim_process_join_prune_cmd(vty, jpi_str); } +DEFPY_ATTR(ip_pim_joinprune_time, + ip_pim_joinprune_time_cmd, + "ip pim join-prune-interval (1-65535)$jpi", + IP_STR + PIM_STR + "Join Prune Send Interval\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_join_prune_cmd(vty, jpi_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_joinprune_time, - no_ip_pim_joinprune_time_cmd, - "no ip pim join-prune-interval [(1-65535)]", +DEFPY (no_pim_joinprune_time, + no_pim_joinprune_time_cmd, + "no join-prune-interval [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { return pim_process_no_join_prune_cmd(vty); } - -DEFPY (ip_pim_register_suppress, - ip_pim_register_suppress_cmd, - "ip pim register-suppress-time (1-65535)$rst", - IP_STR - "pim multicast routing\n" - "Register Suppress Timer\n" - "Seconds\n") +DEFPY_ATTR(no_ip_pim_joinprune_time, + no_ip_pim_joinprune_time_cmd, + "no ip pim join-prune-interval [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - return pim_process_register_suppress_cmd(vty, rst_str); -} + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFUN (no_ip_pim_register_suppress, - no_ip_pim_register_suppress_cmd, - "no ip pim register-suppress-time [(1-65535)]", - NO_STR - IP_STR - "pim multicast routing\n" - "Register Suppress Timer\n" - IGNORED_IN_NO_STR) -{ + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_join_prune_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_register_suppress, + pim_register_suppress_cmd, + "register-suppress-time (1-65535)$rst", + "Register Suppress Timer\n" + "Seconds\n") +{ + return pim_process_register_suppress_cmd(vty, rst_str); +} +DEFPY_ATTR(ip_pim_register_suppress, + ip_pim_register_suppress_cmd, + "ip pim register-suppress-time (1-65535)$rst", + IP_STR + PIM_STR + "Register Suppress Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_register_suppress_cmd(vty, rst_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_register_suppress, + no_pim_register_suppress_cmd, + "no register-suppress-time [(1-65535)]", + NO_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR) +{ return pim_process_no_register_suppress_cmd(vty); } +DEFPY_ATTR(no_ip_pim_register_suppress, + no_ip_pim_register_suppress_cmd, + "no ip pim register-suppress-time [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_rp_keep_alive, - ip_pim_rp_keep_alive_cmd, - "ip pim rp keep-alive-timer (1-65535)$kat", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_register_suppress_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_rp_keep_alive, + pim_rp_keep_alive_cmd, + "rp keep-alive-timer (1-65535)$kat", "Rendezvous Point\n" "Keep alive Timer\n" "Seconds\n") { return pim_process_rp_kat_cmd(vty, kat_str); } +DEFPY_ATTR(ip_pim_rp_keep_alive, + ip_pim_rp_keep_alive_cmd, + "ip pim rp keep-alive-timer (1-65535)$kat", + IP_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_kat_cmd(vty, kat_str); -DEFUN (no_ip_pim_rp_keep_alive, - no_ip_pim_rp_keep_alive_cmd, - "no ip pim rp keep-alive-timer [(1-65535)]", + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_rp_keep_alive, + no_pim_rp_keep_alive_cmd, + "no rp keep-alive-timer [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_rp_kat_cmd(vty); } +DEFPY_ATTR(no_ip_pim_rp_keep_alive, + no_ip_pim_rp_keep_alive_cmd, + "no ip pim rp keep-alive-timer [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_keep_alive, - ip_pim_keep_alive_cmd, - "ip pim keep-alive-timer (1-65535)$kat", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_kat_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_keep_alive, + pim_keep_alive_cmd, + "keep-alive-timer (1-65535)$kat", "Keep alive Timer\n" "Seconds\n") { return pim_process_keepalivetimer_cmd(vty, kat_str); } +DEFPY_ATTR(ip_pim_keep_alive, + ip_pim_keep_alive_cmd, + "ip pim keep-alive-timer (1-65535)$kat", + IP_STR + PIM_STR + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFUN (no_ip_pim_keep_alive, - no_ip_pim_keep_alive_cmd, - "no ip pim keep-alive-timer [(1-65535)]", + ret = pim_process_keepalivetimer_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_keep_alive, + no_pim_keep_alive_cmd, + "no keep-alive-timer [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_keepalivetimer_cmd(vty); } +DEFPY_ATTR(no_ip_pim_keep_alive, + no_ip_pim_keep_alive_cmd, + "no ip pim keep-alive-timer [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_packets, - ip_pim_packets_cmd, - "ip pim packets (1-255)", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_keepalivetimer_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_packets, + pim_packets_cmd, + "packets (1-255)", "packets to process at one time per fd\n" "Number of packets\n") { return pim_process_pim_packet_cmd(vty, packets_str); } +DEFPY_ATTR(ip_pim_packets, + ip_pim_packets_cmd, + "ip pim packets (1-255)", + IP_STR + PIM_STR + "packets to process at one time per fd\n" + "Number of packets\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_pim_packet_cmd(vty, packets_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_packets, - no_ip_pim_packets_cmd, - "no ip pim packets [(1-255)]", +DEFPY (no_pim_packets, + no_pim_packets_cmd, + "no packets [(1-255)]", NO_STR - IP_STR - "pim multicast routing\n" "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { return pim_process_no_pim_packet_cmd(vty); } +DEFPY_ATTR(no_ip_pim_packets, + no_ip_pim_packets_cmd, + "no ip pim packets [(1-255)]", + NO_STR + IP_STR + PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_pim_packet_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (ip_igmp_group_watermark, ip_igmp_group_watermark_cmd, @@ -3217,64 +4245,131 @@ DEFPY (no_ip_igmp_group_watermark, return CMD_SUCCESS; } -DEFUN (ip_pim_v6_secondary, - ip_pim_v6_secondary_cmd, - "ip pim send-v6-secondary", - IP_STR - "pim multicast routing\n" +DEFPY (pim_v6_secondary, + pim_v6_secondary_cmd, + "send-v6-secondary", "Send v6 secondary addresses\n") { - const char *vrfname; char send_v6_secondary_xpath[XPATH_MAXLEN]; + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + "./send-v6-secondary"); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_v6_secondary, + ip_pim_v6_secondary_cmd, + "ip pim send-v6-secondary", + IP_STR + PIM_STR + "Send v6 secondary addresses\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char send_v6_secondary_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(send_v6_secondary_xpath, "/send-v6-secondary", - sizeof(send_v6_secondary_xpath)); - + "./send-v6-secondary"); nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, "true"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_v6_secondary, - no_ip_pim_v6_secondary_cmd, - "no ip pim send-v6-secondary", +DEFPY (no_pim_v6_secondary, + no_pim_v6_secondary_cmd, + "no send-v6-secondary", NO_STR - IP_STR - "pim multicast routing\n" "Send v6 secondary addresses\n") { - const char *vrfname; char send_v6_secondary_xpath[XPATH_MAXLEN]; + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + "./send-v6-secondary"); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_v6_secondary, + no_ip_pim_v6_secondary_cmd, + "no ip pim send-v6-secondary", + NO_STR + IP_STR + PIM_STR + "Send v6 secondary addresses\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char send_v6_secondary_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(send_v6_secondary_xpath, "/send-v6-secondary", - sizeof(send_v6_secondary_xpath)); - + "./send-v6-secondary"); nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY (ip_pim_rp, - ip_pim_rp_cmd, - "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", - IP_STR - "pim multicast routing\n" +DEFPY (pim_rp, + pim_rp_cmd, + "rp A.B.C.D$rp [A.B.C.D/M]$gp", "Rendezvous Point\n" "ip address of RP\n" "Group Address range to cover\n") @@ -3283,12 +4378,52 @@ DEFPY (ip_pim_rp, return pim_process_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(ip_pim_rp, + ip_pim_rp_cmd, + "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_rp_prefix_list, - ip_pim_rp_prefix_list_cmd, - "ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_rp_prefix_list, + pim_rp_prefix_list_cmd, + "rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" @@ -3296,13 +4431,53 @@ DEFPY (ip_pim_rp_prefix_list, { return pim_process_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(ip_pim_rp_prefix_list, + ip_pim_rp_prefix_list_cmd, + "ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ip_pim_rp, - no_ip_pim_rp_cmd, - "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", +DEFPY (no_pim_rp, + no_pim_rp_cmd, + "no rp A.B.C.D$rp [A.B.C.D/M]$gp", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "ip address of RP\n" "Group Address range to cover\n") @@ -3311,13 +4486,54 @@ DEFPY (no_ip_pim_rp, return pim_process_no_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(no_ip_pim_rp, + no_ip_pim_rp_cmd, + "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (no_ip_pim_rp_prefix_list, - no_ip_pim_rp_prefix_list_cmd, - "no ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_rp_prefix_list, + no_pim_rp_prefix_list_cmd, + "no rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" @@ -3325,103 +4541,365 @@ DEFPY (no_ip_pim_rp_prefix_list, { return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(no_ip_pim_rp_prefix_list, + no_ip_pim_rp_prefix_list_cmd, + "no ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFUN (ip_pim_ssm_prefix_list, - ip_pim_ssm_prefix_list_cmd, - "ip pim ssm prefix-list PREFIXLIST4_NAME", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + 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
}]", + 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
}]", + 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", "Source Specific Multicast\n" "group range prefix-list filter\n" "Name of a prefix-list\n") { - const char *vrfname; char ssm_plist_xpath[XPATH_MAXLEN]; + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ssm_prefix_list, + ip_pim_ssm_prefix_list_cmd, + "ip pim ssm prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ssm_plist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, argv[4]->arg); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return nb_cli_apply_changes(vty, NULL); + return ret; } -DEFUN (no_ip_pim_ssm_prefix_list, - no_ip_pim_ssm_prefix_list_cmd, - "no ip pim ssm prefix-list", +DEFPY (no_pim_ssm_prefix_list, + no_pim_ssm_prefix_list_cmd, + "no ssm prefix-list", NO_STR - IP_STR - "pim multicast routing\n" "Source Specific Multicast\n" "group range prefix-list filter\n") { - const char *vrfname; char ssm_plist_xpath[XPATH_MAXLEN]; + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ssm_prefix_list, + no_ip_pim_ssm_prefix_list_cmd, + "no ip pim ssm prefix-list", + NO_STR + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ssm_plist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); - + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ssm_prefix_list_name, - no_ip_pim_ssm_prefix_list_name_cmd, - "no ip pim ssm prefix-list PREFIXLIST4_NAME", +DEFPY (no_pim_ssm_prefix_list_name, + no_pim_ssm_prefix_list_name_cmd, + "no ssm prefix-list PREFIXLIST4_NAME$plist", NO_STR - IP_STR - "pim multicast routing\n" "Source Specific Multicast\n" "group range prefix-list filter\n" "Name of a prefix-list\n") { - const char *vrfname; const struct lyd_node *ssm_plist_dnode; - char ssm_plist_xpath[XPATH_MAXLEN]; + char ssm_plist_xpath[XPATH_MAXLEN + 16]; const char *ssm_plist_name; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", + VTY_CURR_XPATH); ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, ssm_plist_xpath); if (!ssm_plist_dnode) { - vty_out(vty, - "%% pim ssm prefix-list %s doesn't exist\n", - argv[5]->arg); + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); return CMD_WARNING_CONFIG_FAILED; } ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); - if (ssm_plist_name && !strcmp(ssm_plist_name, argv[5]->arg)) { - nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, - NULL); - + if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } - vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg); + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); + + return CMD_WARNING_CONFIG_FAILED; +} +DEFPY_ATTR(no_ip_pim_ssm_prefix_list_name, + no_ip_pim_ssm_prefix_list_name_cmd, + "no ip pim ssm prefix-list PREFIXLIST4_NAME$plist", + NO_STR + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const struct lyd_node *ssm_plist_dnode; + char ssm_plist_xpath[XPATH_MAXLEN + 16]; + const char *ssm_plist_name; + int ret = CMD_WARNING_CONFIG_FAILED; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", + VTY_CURR_XPATH); + ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, + ssm_plist_xpath); + if (ssm_plist_dnode) { + ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); + if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { + nb_cli_enqueue_change(vty, ssm_plist_xpath, + NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + } else { + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", + plist); + } + } else { + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return CMD_WARNING_CONFIG_FAILED; + return ret; } DEFUN (show_ip_pim_ssm_range, @@ -3511,135 +4989,354 @@ DEFPY (show_ip_pim_bsr, return pim_show_bsr_helper(vrf, vty, !!json); } -DEFUN (ip_ssmpingd, - ip_ssmpingd_cmd, - "ip ssmpingd [A.B.C.D]", - IP_STR +DEFPY (pim_ssmpingd, + pim_ssmpingd_cmd, + "ssmpingd [A.B.C.D]$src", CONF_SSMPINGD_STR "Source address\n") { - int idx_ipv4 = 2; - const char *src_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0"; + if (src_str) + return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + else + return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); +} +DEFPY_ATTR(ip_pim_ssmpingd, + ip_ssmpingd_cmd, + "ip ssmpingd [A.B.C.D]$src", + IP_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (src_str) + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + else + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + return ret; } -DEFUN (no_ip_ssmpingd, - no_ip_ssmpingd_cmd, - "no ip ssmpingd [A.B.C.D]", +DEFPY (no_pim_ssmpingd, + no_pim_ssmpingd_cmd, + "no ssmpingd [A.B.C.D]$src", NO_STR - IP_STR CONF_SSMPINGD_STR "Source address\n") { - int idx_ipv4 = 3; - const char *src_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0"; + if (src_str) + return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + else + return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); +} +DEFPY_ATTR(no_ip_pim_ssmpingd, + no_ip_ssmpingd_cmd, + "no ip ssmpingd [A.B.C.D]$src", + NO_STR + IP_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; - return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (src_str) + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + else + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (ip_pim_ecmp, - ip_pim_ecmp_cmd, - "ip pim ecmp", - IP_STR - "pim multicast routing\n" +DEFPY (pim_ecmp, + pim_ecmp_cmd, + "ecmp", "Enable PIM ECMP \n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ecmp, + ip_pim_ecmp_cmd, + "ip pim ecmp", + IP_STR + PIM_STR + "Enable PIM ECMP \n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); - + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); - return nb_cli_apply_changes(vty, NULL); + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ecmp, - no_ip_pim_ecmp_cmd, - "no ip pim ecmp", +DEFPY (no_pim_ecmp, + no_pim_ecmp_cmd, + "no ecmp", NO_STR - IP_STR - "pim multicast routing\n" "Disable PIM ECMP \n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ecmp, + no_ip_pim_ecmp_cmd, + "no ip pim ecmp", + NO_STR + IP_STR + PIM_STR + "Disable PIM ECMP \n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); - + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (ip_pim_ecmp_rebalance, - ip_pim_ecmp_rebalance_cmd, - "ip pim ecmp rebalance", - IP_STR - "pim multicast routing\n" +DEFPY (pim_ecmp_rebalance, + pim_ecmp_rebalance_cmd, + "ecmp rebalance", "Enable PIM ECMP \n" "Enable PIM ECMP Rebalance\n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; char ecmp_rebalance_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + "./ecmp-rebalance"); + + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ecmp_rebalance, + ip_pim_ecmp_rebalance_cmd, + "ip pim ecmp rebalance", + IP_STR + PIM_STR + "Enable PIM ECMP \n" + "Enable PIM ECMP Rebalance\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", - sizeof(ecmp_rebalance_xpath)); - + "./ecmp-rebalance"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ecmp_rebalance, - no_ip_pim_ecmp_rebalance_cmd, - "no ip pim ecmp rebalance", +DEFPY (no_pim_ecmp_rebalance, + no_pim_ecmp_rebalance_cmd, + "no ecmp rebalance", NO_STR - IP_STR - "pim multicast routing\n" "Disable PIM ECMP \n" "Disable PIM ECMP Rebalance\n") { - const char *vrfname; char ecmp_rebalance_xpath[XPATH_MAXLEN]; + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + "./ecmp-rebalance"); + + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ecmp_rebalance, + no_ip_pim_ecmp_rebalance_cmd, + "no ip pim ecmp rebalance", + NO_STR + IP_STR + PIM_STR + "Disable PIM ECMP \n" + "Disable PIM ECMP Rebalance\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", - sizeof(ecmp_rebalance_xpath)); - + "./ecmp-rebalance"); nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } DEFUN (interface_ip_igmp, @@ -3695,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, @@ -4256,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", @@ -4648,15 +6333,24 @@ DEFPY (debug_pim_zebra, return CMD_SUCCESS; } -DEFUN(debug_pim_mlag, debug_pim_mlag_cmd, "debug pim mlag", - DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +DEFUN(debug_pim_mlag, + debug_pim_mlag_cmd, + "debug pim mlag", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_MLAG_STR) { PIM_DO_DEBUG_MLAG; return CMD_SUCCESS; } -DEFUN(no_debug_pim_mlag, no_debug_pim_mlag_cmd, "no debug pim mlag", - NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +DEFUN(no_debug_pim_mlag, + no_debug_pim_mlag_cmd, + "no debug pim mlag", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_MLAG_STR) { PIM_DONT_DEBUG_MLAG; return CMD_SUCCESS; @@ -4798,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, @@ -5016,145 +6733,447 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, "Desired min transmit interval\n") #endif /* !HAVE_BFDD */ -DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, - "ip msdp peer A.B.C.D$peer source A.B.C.D$source", - IP_STR +DEFPY(pim_msdp_peer, pim_msdp_peer_cmd, + "msdp peer A.B.C.D$peer source A.B.C.D$source", CFG_MSDP_STR "Configure MSDP peer\n" "Peer IP address\n" "Source address for TCP connection\n" "Local IP address\n") { - const char *vrfname; - char temp_xpath[XPATH_MAXLEN]; char msdp_peer_source_xpath[XPATH_MAXLEN]; + snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), + "./msdp-peer[peer-ip='%s']/source-ip", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, + source_str); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_peer, + ip_msdp_peer_cmd, + "ip msdp peer A.B.C.D$peer source A.B.C.D$source", + IP_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "Peer IP address\n" + "Source address for TCP connection\n" + "Local IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char msdp_peer_source_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - snprintf(temp_xpath, sizeof(temp_xpath), - "/msdp-peer[peer-ip='%s']/source-ip", peer_str); - strlcat(msdp_peer_source_xpath, temp_xpath, - sizeof(msdp_peer_source_xpath)); - + "./msdp-peer[peer-ip='%s']/source-ip", peer_str); nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, source_str); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(ip_msdp_timers, ip_msdp_timers_cmd, - "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", - IP_STR +DEFPY(msdp_peer_md5, msdp_peer_md5_cmd, + "msdp peer A.B.C.D$peer password WORD$psk", + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "Use MD5 authentication\n" + "MD5 pre shared key\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, "MD5"); + nb_cli_enqueue_change(vty, "./authentication-key", NB_OP_MODIFY, psk); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(no_msdp_peer_md5, no_msdp_peer_md5_cmd, + "no msdp peer A.B.C.D$peer password [WORD]", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "Use MD5 authentication\n" + "MD5 pre shared key\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, + "None"); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(pim_msdp_timers, pim_msdp_timers_cmd, + "msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", CFG_MSDP_STR "MSDP timers configuration\n" "Keep alive period (in seconds)\n" "Hold time period (in seconds)\n" "Connection retry period (in seconds)\n") { + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, + holdtime_str); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, + keepalive_str); + if (connretry_str) + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_MODIFY, connretry_str); + else + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_DESTROY, NULL); + + nb_cli_apply_changes(vty, NULL); + return CMD_SUCCESS; +} +DEFPY_ATTR(ip_pim_msdp_timers, + ip_msdp_timers_cmd, + "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", + IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + "Keep alive period (in seconds)\n" + "Hold time period (in seconds)\n" + "Connection retry period (in seconds)\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, "./hold-time", NB_OP_MODIFY, holdtime_str); - nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_MODIFY, keepalive_str); + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, + holdtime_str); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, + keepalive_str); if (connretry_str) - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_MODIFY, - connretry_str); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_MODIFY, connretry_str); else - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, - NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", - vrfname, "frr-routing:ipv4"); - return CMD_SUCCESS; + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_timers, no_ip_msdp_timers_cmd, - "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", +DEFPY(no_pim_msdp_timers, no_pim_msdp_timers_cmd, + "no msdp timers [(1-65535) (1-65535) [(1-65535)]]", NO_STR - IP_STR CFG_MSDP_STR "MSDP timers configuration\n" IGNORED_IN_NO_STR IGNORED_IN_NO_STR IGNORED_IN_NO_STR) { + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, + NULL); + nb_cli_apply_changes(vty, NULL); + return CMD_SUCCESS; +} +DEFPY_ATTR(no_ip_pim_msdp_timers, + no_ip_msdp_timers_cmd, + "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", + NO_STR + IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, "./hold-time", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, + NULL); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", - vrfname, "frr-routing:ipv4"); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return CMD_SUCCESS; + return ret; } -DEFUN (no_ip_msdp_peer, - no_ip_msdp_peer_cmd, - "no ip msdp peer A.B.C.D", +DEFPY (no_pim_msdp_peer, + no_pim_msdp_peer_cmd, + "no msdp peer A.B.C.D", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP peer\n" "peer ip address\n") { - const char *vrfname; char msdp_peer_xpath[XPATH_MAXLEN]; - char temp_xpath[XPATH_MAXLEN]; + + snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), + "./msdp-peer[peer-ip='%s']", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_msdp_peer, + no_ip_msdp_peer_cmd, + "no ip msdp peer A.B.C.D", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP peer\n" + "peer ip address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char msdp_peer_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - snprintf(temp_xpath, sizeof(temp_xpath), - "/msdp-peer[peer-ip='%s']", - argv[4]->arg); + "./msdp-peer[peer-ip='%s']", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - strlcat(msdp_peer_xpath, temp_xpath, sizeof(msdp_peer_xpath)); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + return ret; +} - return nb_cli_apply_changes(vty, NULL); +DEFPY(msdp_peer_sa_filter, msdp_peer_sa_filter_cmd, + "msdp peer A.B.C.D$peer sa-filter ACL_NAME$acl_name $dir", + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "SA access-list filter\n" + "SA access-list name\n" + "Filter incoming SAs\n" + "Filter outgoing SAs\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + if (strcmp(dir, "in") == 0) + nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_MODIFY, + acl_name); + else + nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_MODIFY, + acl_name); + + return nb_cli_apply_changes(vty, "%s", xpath); } -DEFPY(ip_msdp_mesh_group_member, - ip_msdp_mesh_group_member_cmd, - "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", - IP_STR +DEFPY(no_msdp_peer_sa_filter, no_ip_msdp_peer_sa_filter_cmd, + "no msdp peer A.B.C.D$peer sa-filter ACL_NAME $dir", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "SA access-list filter\n" + "SA access-list name\n" + "Filter incoming SAs\n" + "Filter outgoing SAs\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + if (strcmp(dir, "in") == 0) + nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_DESTROY, + NULL); + else + nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(pim_msdp_mesh_group_member, + pim_msdp_mesh_group_member_cmd, + "msdp mesh-group WORD$gname member A.B.C.D$maddr", CFG_MSDP_STR "Configure MSDP mesh-group\n" "Mesh group name\n" "Mesh group member\n" "Peer IP address\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group member. */ + strlcat(xpath_value, "/members[address='", sizeof(xpath_value)); + strlcat(xpath_value, maddr_str, sizeof(xpath_value)); + strlcat(xpath_value, "']", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_mesh_group_member, + ip_msdp_mesh_group_member_cmd, + "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", + IP_STR + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); /* Create mesh group member. */ @@ -5162,33 +7181,32 @@ DEFPY(ip_msdp_mesh_group_member, strlcat(xpath_value, maddr_str, sizeof(xpath_value)); strlcat(xpath_value, "']", sizeof(xpath_value)); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group_member, - no_ip_msdp_mesh_group_member_cmd, - "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", +DEFPY(no_pim_msdp_mesh_group_member, + no_pim_msdp_mesh_group_member_cmd, + "no msdp mesh-group WORD$gname member A.B.C.D$maddr", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group member\n" "Mesh group name\n" "Mesh group member\n" "Peer IP address\n") { - const char *vrfname; - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; char xpath_member_value[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { vty_out(vty, "%% mesh-group does not exist\n"); @@ -5217,59 +7235,221 @@ DEFPY(no_ip_msdp_mesh_group_member, return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(no_ip_pim_msdp_mesh_group_member, + no_ip_msdp_mesh_group_member_cmd, + "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group member\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN + 26]; + char xpath_member_value[XPATH_MAXLEN]; + int ret = CMD_WARNING_CONFIG_FAILED; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY(ip_msdp_mesh_group_source, - ip_msdp_mesh_group_source_cmd, - "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", - IP_STR + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { + /* Remove mesh group member. */ + strlcpy(xpath_member_value, xpath_value, + sizeof(xpath_member_value)); + strlcat(xpath_member_value, "/members[address='", + sizeof(xpath_member_value)); + strlcat(xpath_member_value, maddr_str, + sizeof(xpath_member_value)); + strlcat(xpath_member_value, "']", sizeof(xpath_member_value)); + if (yang_dnode_exists(vty->candidate_config->dnode, + xpath_member_value)) { + nb_cli_enqueue_change(vty, xpath_member_value, + NB_OP_DESTROY, NULL); + + /* + * If this is the last member, then we must remove the group altogether + * to not break legacy CLI behaviour. + */ + pim_cli_legacy_mesh_group_behavior(vty, gname); + ret = nb_cli_apply_changes(vty, NULL); + } else { + vty_out(vty, "%% mesh-group member does not exist\n"); + } + } else { + vty_out(vty, "%% mesh-group does not exist\n"); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY(pim_msdp_mesh_group_source, + pim_msdp_mesh_group_source_cmd, + "msdp mesh-group WORD$gname source A.B.C.D$saddr", CFG_MSDP_STR "Configure MSDP mesh-group\n" "Mesh group name\n" "Mesh group local address\n" "Source IP address for the TCP connection\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group source. */ + strlcat(xpath_value, "/source", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_mesh_group_source, + ip_msdp_mesh_group_source_cmd, + "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", + IP_STR + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group local address\n" + "Source IP address for the TCP connection\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); - /* Create mesh group source. */ strlcat(xpath_value, "/source", sizeof(xpath_value)); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group_source, - no_ip_msdp_mesh_group_source_cmd, - "no ip msdp mesh-group WORD$gname source [A.B.C.D]", +DEFPY(no_pim_msdp_mesh_group_source, + no_pim_msdp_mesh_group_source_cmd, + "no msdp mesh-group WORD$gname source [A.B.C.D]", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group source\n" "Mesh group name\n" "Mesh group source\n" "Mesh group local address\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group source. */ + strlcat(xpath_value, "/source", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + + /* + * If this is the last member, then we must remove the group altogether + * to not break legacy CLI behaviour. + */ + pim_cli_legacy_mesh_group_behavior(vty, gname); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_msdp_mesh_group_source, + no_ip_msdp_mesh_group_source_cmd, + "no ip msdp mesh-group WORD$gname source [A.B.C.D]", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group source\n" + "Mesh group name\n" + "Mesh group source\n" + "Mesh group local address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); /* Create mesh group source. */ @@ -5281,36 +7461,83 @@ DEFPY(no_ip_msdp_mesh_group_source, * to not break legacy CLI behaviour. */ pim_cli_legacy_mesh_group_behavior(vty, gname); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group, - no_ip_msdp_mesh_group_cmd, - "no ip msdp mesh-group WORD$gname", +DEFPY(no_pim_msdp_mesh_group, + no_pim_msdp_mesh_group_cmd, + "no msdp mesh-group WORD$gname", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group\n" "Mesh group name\n") { - const char *vrfname; - char xpath_value[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; + char xpath_value[XPATH_MAXLEN + 26]; /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) return CMD_SUCCESS; nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(no_ip_pim_msdp_mesh_group, + no_ip_msdp_mesh_group_cmd, + "no ip msdp mesh-group WORD$gname", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group\n" + "Mesh group name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN + 26]; + int ret = CMD_SUCCESS; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, struct json_object *json) @@ -5329,7 +7556,8 @@ static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, if (json) { /* currently there is only one mesh group but we should still * make - * it a dict with mg-name as key */ + * it a dict with mg-name as key + */ json_mg_row = json_object_new_object(); json_object_string_add(json_mg_row, "name", mg->mesh_group_name); @@ -6311,119 +8539,224 @@ DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work, return CMD_SUCCESS; } -DEFUN_HIDDEN (no_ip_pim_mlag, - no_ip_pim_mlag_cmd, - "no ip pim mlag", +DEFPY_HIDDEN (no_pim_mlag, + no_pim_mlag_cmd, + "no mlag", NO_STR - IP_STR - PIM_STR "MLAG\n") { char mlag_xpath[XPATH_MAXLEN]; - snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath)); + snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); + nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_mlag, + no_ip_pim_mlag_cmd, + "no ip pim mlag", + NO_STR + IP_STR + PIM_STR + "MLAG\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char mlag_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY_HIDDEN (pim_mlag, + pim_mlag_cmd, + "mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", + "MLAG\n" + "peerlink sub interface\n" + "MLAG role\n" + "MLAG role primary\n" + "MLAG role secondary\n" + "peer session state\n" + "peer session state up\n" + "peer session state down\n" + "configure PIP\n" + "unique ip address\n") +{ + char mlag_peerlink_rif_xpath[XPATH_MAXLEN]; + char mlag_my_role_xpath[XPATH_MAXLEN]; + char mlag_peer_state_xpath[XPATH_MAXLEN]; + char mlag_reg_address_xpath[XPATH_MAXLEN]; + + snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), + "./mlag/peerlink-rif"); + nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); + + snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), + "./mlag/my-role"); + if (!strcmp(role, "primary")) { + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_PRIMARY"); + } else if (!strcmp(role, "secondary")) { + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_SECONDARY"); + } else { + vty_out(vty, "unknown MLAG role %s\n", role); + return CMD_WARNING; + } + + snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), + "./mlag/peer-state"); + if (!strcmp(state, "up")) { + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "true"); + } else if (strcmp(state, "down")) { + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "false"); + } else { + vty_out(vty, "unknown MLAG state %s\n", state); + return CMD_WARNING; + } + snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), + "./mlag/reg-address"); + nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, + addr_str); return nb_cli_apply_changes(vty, NULL); } - -DEFUN_HIDDEN (ip_pim_mlag, - ip_pim_mlag_cmd, - "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D", - IP_STR - PIM_STR - "MLAG\n" - "peerlink sub interface\n" - "MLAG role\n" - "MLAG role primary\n" - "MLAG role secondary\n" - "peer session state\n" - "peer session state up\n" - "peer session state down\n" - "configure PIP\n" - "unique ip address\n") +DEFPY_ATTR(ip_pim_mlag, + ip_pim_mlag_cmd, + "ip pim mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", + IP_STR + PIM_STR + "MLAG\n" + "peerlink sub interface\n" + "MLAG role\n" + "MLAG role primary\n" + "MLAG role secondary\n" + "peer session state\n" + "peer session state up\n" + "peer session state down\n" + "configure PIP\n" + "unique ip address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - int idx; char mlag_peerlink_rif_xpath[XPATH_MAXLEN]; char mlag_my_role_xpath[XPATH_MAXLEN]; char mlag_peer_state_xpath[XPATH_MAXLEN]; char mlag_reg_address_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; - snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif", - sizeof(mlag_peerlink_rif_xpath)); + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } - idx = 3; - nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, - argv[idx]->arg); + snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), + "./mlag/peerlink-rif"); + nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_my_role_xpath, "/mlag/my-role", - sizeof(mlag_my_role_xpath)); - - idx += 2; - if (!strcmp(argv[idx]->arg, "primary")) { + "./mlag/my-role"); + if (!strcmp(role, "primary")) { nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, "MLAG_ROLE_PRIMARY"); - - } else if (!strcmp(argv[idx]->arg, "secondary")) { + } else if (!strcmp(role, "secondary")) { nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, "MLAG_ROLE_SECONDARY"); - } else { - vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg); - return CMD_WARNING; + vty_out(vty, "unknown MLAG role %s\n", role); + ret = CMD_WARNING; + goto done; } snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_peer_state_xpath, "/mlag/peer-state", - sizeof(mlag_peer_state_xpath)); - - idx += 2; - if (!strcmp(argv[idx]->arg, "up")) { + "./mlag/peer-state"); + if (!strcmp(state, "up")) { nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, "true"); - - } else if (strcmp(argv[idx]->arg, "down")) { + } else if (strcmp(state, "down")) { nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, "false"); - } else { - vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg); - return CMD_WARNING; + vty_out(vty, "unknown MLAG state %s\n", state); + ret = CMD_WARNING; + goto done; } snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_reg_address_xpath, "/mlag/reg-address", - sizeof(mlag_reg_address_xpath)); - - idx += 2; + "./mlag/reg-address"); nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, - argv[idx]->arg); + addr_str); - return nb_cli_apply_changes(vty, NULL); -} + ret = nb_cli_apply_changes(vty, NULL); -void pim_cmd_init(void) -{ - if_cmd_init(pim_interface_config_write); +done: + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - install_node(&debug_node); + return ret; +} - install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); +struct cmd_node pim_node = { + .name = "pim", + .node = PIM_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim)# ", + .config_write = pim_router_config_write, +}; +/* This function installs all of the deprecated PIM configuration commands that live in the global config and/or VRF nodes + * This configuration has been moved to the new 'router pim' config node instead like all the other routing protocols. + * No new commands should be added here. + */ +static void pim_install_deprecated(void) +{ install_element(CONFIG_NODE, &ip_pim_rp_cmd); install_element(VRF_NODE, &ip_pim_rp_cmd); install_element(CONFIG_NODE, &no_ip_pim_rp_cmd); @@ -6449,8 +8782,8 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); - install_element(CONFIG_NODE, &pim_register_accept_list_cmd); - install_element(VRF_NODE, &pim_register_accept_list_cmd); + install_element(CONFIG_NODE, &ip_pim_register_accept_list_cmd); + install_element(VRF_NODE, &ip_pim_register_accept_list_cmd); install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd); @@ -6467,14 +8800,6 @@ void pim_cmd_init(void) install_element(VRF_NODE, &ip_pim_v6_secondary_cmd); install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd); install_element(VRF_NODE, &no_ip_pim_v6_secondary_cmd); - install_element(CONFIG_NODE, &ip_ssmpingd_cmd); - install_element(VRF_NODE, &ip_ssmpingd_cmd); - install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); - install_element(VRF_NODE, &no_ip_ssmpingd_cmd); - install_element(CONFIG_NODE, &ip_msdp_peer_cmd); - install_element(VRF_NODE, &ip_msdp_peer_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); - install_element(VRF_NODE, &no_ip_msdp_peer_cmd); install_element(CONFIG_NODE, &ip_pim_ecmp_cmd); install_element(VRF_NODE, &ip_pim_ecmp_cmd); install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd); @@ -6485,15 +8810,104 @@ void pim_cmd_init(void) install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd); install_element(CONFIG_NODE, &ip_pim_mlag_cmd); install_element(CONFIG_NODE, &no_ip_pim_mlag_cmd); - install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); - install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); - install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); - install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); + + install_element(CONFIG_NODE, &ip_ssmpingd_cmd); + install_element(VRF_NODE, &ip_ssmpingd_cmd); + install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); + install_element(VRF_NODE, &no_ip_ssmpingd_cmd); + + install_element(CONFIG_NODE, &ip_msdp_peer_cmd); + install_element(VRF_NODE, &ip_msdp_peer_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); + install_element(VRF_NODE, &no_ip_msdp_peer_cmd); + install_element(CONFIG_NODE, &ip_msdp_timers_cmd); + install_element(VRF_NODE, &ip_msdp_timers_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); + install_element(VRF_NODE, &no_ip_msdp_timers_cmd); + install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); +} + +void pim_cmd_init(void) +{ + if_cmd_init(pim_interface_config_write); + + install_node(&debug_node); + + install_element(CONFIG_NODE, &router_pim_cmd); + install_element(CONFIG_NODE, &no_router_pim_cmd); + + install_node(&pim_node); + install_default(PIM_NODE); + + install_element(PIM_NODE, &pim_rp_cmd); + 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); + install_element(PIM_NODE, &pim_register_suppress_cmd); + install_element(PIM_NODE, &no_pim_register_suppress_cmd); + install_element(PIM_NODE, &pim_spt_switchover_infinity_cmd); + install_element(PIM_NODE, &pim_spt_switchover_infinity_plist_cmd); + install_element(PIM_NODE, &no_pim_spt_switchover_infinity_cmd); + install_element(PIM_NODE, &no_pim_spt_switchover_infinity_plist_cmd); + install_element(PIM_NODE, &pim_register_accept_list_cmd); + install_element(PIM_NODE, &pim_joinprune_time_cmd); + install_element(PIM_NODE, &no_pim_joinprune_time_cmd); + install_element(PIM_NODE, &pim_keep_alive_cmd); + install_element(PIM_NODE, &pim_rp_keep_alive_cmd); + install_element(PIM_NODE, &no_pim_keep_alive_cmd); + install_element(PIM_NODE, &no_pim_rp_keep_alive_cmd); + install_element(PIM_NODE, &pim_packets_cmd); + install_element(PIM_NODE, &no_pim_packets_cmd); + install_element(PIM_NODE, &pim_v6_secondary_cmd); + install_element(PIM_NODE, &no_pim_v6_secondary_cmd); + install_element(PIM_NODE, &pim_ecmp_cmd); + install_element(PIM_NODE, &no_pim_ecmp_cmd); + install_element(PIM_NODE, &pim_ecmp_rebalance_cmd); + install_element(PIM_NODE, &no_pim_ecmp_rebalance_cmd); + install_element(PIM_NODE, &pim_mlag_cmd); + install_element(PIM_NODE, &no_pim_mlag_cmd); + + install_element(PIM_NODE, &pim_ssmpingd_cmd); + install_element(PIM_NODE, &no_pim_ssmpingd_cmd); + + install_element(PIM_NODE, &pim_msdp_peer_cmd); + install_element(PIM_NODE, &no_pim_msdp_peer_cmd); + install_element(PIM_NODE, &msdp_peer_md5_cmd); + install_element(PIM_NODE, &no_msdp_peer_md5_cmd); + install_element(PIM_NODE, &pim_msdp_timers_cmd); + install_element(PIM_NODE, &no_pim_msdp_timers_cmd); + install_element(PIM_NODE, &msdp_peer_sa_filter_cmd); + install_element(PIM_NODE, &no_ip_msdp_peer_sa_filter_cmd); + install_element(PIM_NODE, &pim_msdp_mesh_group_member_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_member_cmd); + install_element(PIM_NODE, &pim_msdp_mesh_group_source_cmd); + 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); @@ -6515,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); @@ -6534,10 +8949,32 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_ip_mroute_cmd); install_element(INTERFACE_NODE, &interface_no_ip_mroute_cmd); + install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); + install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); + /* Install BSM command */ + install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); + install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); + /* Install BFD command */ + install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); + install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); +#if HAVE_BFDD == 0 + install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); +#endif /* !HAVE_BFDD */ + 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); @@ -6572,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); @@ -6589,9 +9028,29 @@ 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); + install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); + install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); + install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); + install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); + install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); + + install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd); + install_element(ENABLE_NODE, &clear_ip_msdp_peer_cmd); install_element(ENABLE_NODE, &clear_ip_interfaces_cmd); install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); install_element(ENABLE_NODE, &clear_ip_mroute_cmd); @@ -6604,134 +9063,102 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &show_debugging_pim_cmd); install_element(ENABLE_NODE, &debug_igmp_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_cmd); - install_element(ENABLE_NODE, &debug_igmp_events_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); - install_element(ENABLE_NODE, &debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); - install_element(ENABLE_NODE, &debug_mroute_cmd); - install_element(ENABLE_NODE, &debug_mroute_detail_cmd); - install_element(ENABLE_NODE, &no_debug_mroute_cmd); - install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); - install_element(ENABLE_NODE, &debug_pim_static_cmd); - install_element(ENABLE_NODE, &no_debug_pim_static_cmd); - install_element(ENABLE_NODE, &debug_pim_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); - install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); - install_element(ENABLE_NODE, &debug_pim_events_cmd); - install_element(ENABLE_NODE, &debug_pim_packets_cmd); - install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); - install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); - install_element(ENABLE_NODE, &debug_pim_trace_cmd); - install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); - install_element(ENABLE_NODE, &debug_ssmpingd_cmd); - install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); - install_element(ENABLE_NODE, &debug_pim_zebra_cmd); - install_element(ENABLE_NODE, &debug_pim_mlag_cmd); - install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); - install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); - install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); - install_element(ENABLE_NODE, &debug_msdp_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_cmd); - install_element(ENABLE_NODE, &debug_msdp_events_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); - install_element(ENABLE_NODE, &debug_msdp_packets_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); - install_element(ENABLE_NODE, &debug_mtrace_cmd); - install_element(ENABLE_NODE, &no_debug_mtrace_cmd); - install_element(ENABLE_NODE, &debug_bsm_cmd); - install_element(ENABLE_NODE, &no_debug_bsm_cmd); - install_element(CONFIG_NODE, &debug_igmp_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_cmd); install_element(CONFIG_NODE, &no_debug_igmp_cmd); + install_element(ENABLE_NODE, &debug_igmp_events_cmd); install_element(CONFIG_NODE, &debug_igmp_events_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); install_element(CONFIG_NODE, &no_debug_igmp_events_cmd); + install_element(ENABLE_NODE, &debug_igmp_packets_cmd); install_element(CONFIG_NODE, &debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); install_element(CONFIG_NODE, &no_debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &debug_igmp_trace_cmd); install_element(CONFIG_NODE, &debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); install_element(CONFIG_NODE, &no_debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); install_element(CONFIG_NODE, &debug_igmp_trace_detail_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); install_element(CONFIG_NODE, &no_debug_igmp_trace_detail_cmd); + install_element(ENABLE_NODE, &debug_mroute_cmd); install_element(CONFIG_NODE, &debug_mroute_cmd); + install_element(ENABLE_NODE, &debug_mroute_detail_cmd); install_element(CONFIG_NODE, &debug_mroute_detail_cmd); + install_element(ENABLE_NODE, &no_debug_mroute_cmd); install_element(CONFIG_NODE, &no_debug_mroute_cmd); + install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); install_element(CONFIG_NODE, &no_debug_mroute_detail_cmd); + install_element(ENABLE_NODE, &debug_pim_static_cmd); install_element(CONFIG_NODE, &debug_pim_static_cmd); + install_element(ENABLE_NODE, &no_debug_pim_static_cmd); install_element(CONFIG_NODE, &no_debug_pim_static_cmd); + install_element(ENABLE_NODE, &debug_pim_cmd); install_element(CONFIG_NODE, &debug_pim_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_cmd); install_element(CONFIG_NODE, &debug_pim_nht_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); install_element(CONFIG_NODE, &debug_pim_nht_det_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); install_element(CONFIG_NODE, &debug_pim_nht_rp_cmd); + install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); install_element(CONFIG_NODE, &no_debug_pim_nht_rp_cmd); + install_element(ENABLE_NODE, &debug_pim_events_cmd); install_element(CONFIG_NODE, &debug_pim_events_cmd); + install_element(ENABLE_NODE, &debug_pim_packets_cmd); install_element(CONFIG_NODE, &debug_pim_packets_cmd); + install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); install_element(CONFIG_NODE, &debug_pim_packetdump_send_cmd); + install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); install_element(CONFIG_NODE, &debug_pim_packetdump_recv_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_cmd); install_element(CONFIG_NODE, &debug_pim_trace_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); 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); install_element(CONFIG_NODE, &debug_pim_zebra_cmd); + install_element(ENABLE_NODE, &debug_pim_mlag_cmd); install_element(CONFIG_NODE, &debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &debug_pim_vxlan_cmd); + install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd); + install_element(ENABLE_NODE, &debug_msdp_cmd); install_element(CONFIG_NODE, &debug_msdp_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_cmd); install_element(CONFIG_NODE, &no_debug_msdp_cmd); + install_element(ENABLE_NODE, &debug_msdp_events_cmd); install_element(CONFIG_NODE, &debug_msdp_events_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); install_element(CONFIG_NODE, &no_debug_msdp_events_cmd); + install_element(ENABLE_NODE, &debug_msdp_packets_cmd); install_element(CONFIG_NODE, &debug_msdp_packets_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd); + install_element(ENABLE_NODE, &debug_mtrace_cmd); install_element(CONFIG_NODE, &debug_mtrace_cmd); + install_element(ENABLE_NODE, &no_debug_mtrace_cmd); install_element(CONFIG_NODE, &no_debug_mtrace_cmd); + install_element(ENABLE_NODE, &debug_bsm_cmd); 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_msdp_timers_cmd); - install_element(VRF_NODE, &ip_msdp_timers_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); - install_element(VRF_NODE, &no_ip_msdp_timers_cmd); - install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); - install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); - install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); - install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); - install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); - install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); - install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); - install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); - install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); - install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); - install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); - install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); - /* Install BSM command */ - install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); - install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); - /* Install BFD command */ - install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); - install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); -#if HAVE_BFDD == 0 - install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); -#endif /* !HAVE_BFDD */ + install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); + install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); + install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); + install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); + + pim_install_deprecated(); } diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index d39d77cd..17cf4bb3 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 5e50a093..02ddea82 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -100,25 +100,13 @@ int pim_process_no_join_prune_cmd(struct vty *vty) int pim_process_spt_switchover_infinity_cmd(struct vty *vty) { - const char *vrfname; - char spt_plist_xpath[XPATH_MAXLEN]; - char spt_action_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; + char spt_plist_xpath[XPATH_MAXLEN + 40]; + char spt_action_xpath[XPATH_MAXLEN + 26]; snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "%s/spt-switchover/spt-infinity-prefix-list", VTY_CURR_XPATH); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "%s/spt-switchover/spt-action", VTY_CURR_XPATH); if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath)) nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, @@ -132,55 +120,30 @@ int pim_process_spt_switchover_infinity_cmd(struct vty *vty) int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty, const char *plist) { - const char *vrfname; char spt_plist_xpath[XPATH_MAXLEN]; char spt_action_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "./spt-switchover/spt-infinity-prefix-list"); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "./spt-switchover/spt-action"); nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, "PIM_SPT_INFINITY"); - nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, - plist); + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, plist); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_spt_switchover_cmd(struct vty *vty) { - const char *vrfname; char spt_plist_xpath[XPATH_MAXLEN]; char spt_action_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "./spt-switchover/spt-infinity-prefix-list"); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "./spt-switchover/spt-action"); nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, @@ -217,35 +180,20 @@ int pim_process_no_pim_packet_cmd(struct vty *vty) int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat) { - const char *vrfname; char ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); - nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, - kat); + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, kat); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_keepalivetimer_cmd(struct vty *vty) { - const char *vrfname; char ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL); @@ -254,35 +202,25 @@ int pim_process_no_keepalivetimer_cmd(struct vty *vty) int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat) { - const char *vrfname; char rp_ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); + "./rp-keep-alive-timer"); - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - rpkat); + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rpkat); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_rp_kat_cmd(struct vty *vty) { - const char *vrfname; char rp_ka_timer[6]; char rp_ka_timer_xpath[XPATH_MAXLEN]; uint v; char rs_timer_xpath[XPATH_MAXLEN]; - snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), - FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL); + snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); strlcat(rs_timer_xpath, "/register-suppress-time", sizeof(rs_timer_xpath)); @@ -301,18 +239,10 @@ int pim_process_no_rp_kat_cmd(struct vty *vty) v = UINT16_MAX; snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v); - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); + "./rp-keep-alive-timer"); - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - rp_ka_timer); + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rp_ka_timer); return nb_cli_apply_changes(vty, NULL); } @@ -490,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) { @@ -531,9 +472,7 @@ int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, int pim_process_rp_cmd(struct vty *vty, const char *rp_str, const char *group_str) { - const char *vrfname; char group_xpath[XPATH_MAXLEN]; - char rp_xpath[XPATH_MAXLEN]; int printed; int result = 0; struct prefix group; @@ -575,14 +514,9 @@ int pim_process_rp_cmd(struct vty *vty, const char *rp_str, } #endif - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); printed = snprintf(group_xpath, sizeof(group_xpath), - "%s/group-list[.='%s']", rp_xpath, group_str); + "./" FRR_PIM_STATIC_RP_XPATH "/group-list[.='%s']", + rp_str, group_str); if (printed >= (int)(sizeof(group_xpath))) { vty_out(vty, "Xpath too long (%d > %u)", printed + 1, @@ -599,17 +533,12 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, const char *group_str) { char group_xpath[XPATH_MAXLEN]; - char rp_xpath[XPATH_MAXLEN]; + char rp_xpath[XPATH_MAXLEN + 47]; int printed; - const char *vrfname; const struct lyd_node *group_dnode; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, + VTY_CURR_XPATH, rp_str); printed = snprintf(group_xpath, sizeof(group_xpath), "%s/group-list[.='%s']", rp_xpath, group_str); @@ -636,16 +565,10 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list) { - const char *vrfname; char rp_plist_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), - FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL, rp_str); + "./" FRR_PIM_STATIC_RP_XPATH, rp_str); strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list); @@ -656,21 +579,14 @@ int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list) { - char rp_xpath[XPATH_MAXLEN]; - char plist_xpath[XPATH_MAXLEN]; - const char *vrfname; + char rp_xpath[XPATH_MAXLEN + 47]; + char plist_xpath[XPATH_MAXLEN + 1070]; const struct lyd_node *plist_dnode; const char *plist; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); - - snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, + VTY_CURR_XPATH, rp_str); + snprintf(plist_xpath, sizeof(plist_xpath), "%s", rp_xpath); strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); @@ -679,7 +595,7 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, return NB_OK; } - plist = yang_dnode_get_string(plist_dnode, "%s", plist_xpath); + plist = yang_dnode_get_string(plist_dnode, NULL); if (strcmp(prefix_list, plist)) { vty_out(vty, "%% Unable to find specified RP\n"); return NB_OK; @@ -690,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) || @@ -969,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); } } @@ -1021,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); } @@ -1275,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 } @@ -1508,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); } } @@ -1585,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); } } @@ -1664,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); } } @@ -1846,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); } } @@ -1926,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); } @@ -2069,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); } } @@ -2174,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); } } @@ -2357,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); } @@ -2829,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; @@ -3309,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); } } @@ -3408,21 +3483,11 @@ int gm_process_no_last_member_query_interval_cmd(struct vty *vty) int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation, const char *src_str) { - const char *vrfname; - char ssmpingd_ip_xpath[XPATH_MAXLEN]; char ssmpingd_src_ip_xpath[XPATH_MAXLEN]; int printed; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); printed = snprintf(ssmpingd_src_ip_xpath, sizeof(ssmpingd_src_ip_xpath), - "%s/ssm-pingd-source-ip[.='%s']", ssmpingd_ip_xpath, - src_str); + "./ssm-pingd-source-ip[.='%s']", src_str); if (printed >= (int)sizeof(ssmpingd_src_ip_xpath)) { vty_out(vty, "Xpath too long (%d > %u)", printed + 1, XPATH_MAXLEN); @@ -3494,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) { @@ -3605,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); } } @@ -4044,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); } } @@ -4127,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); } } @@ -4263,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; @@ -5293,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)); } @@ -5312,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, @@ -5430,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; } @@ -5484,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) @@ -5521,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) { @@ -5705,3 +5938,34 @@ int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj) return CMD_SUCCESS; } + +int pim_router_config_write(struct vty *vty) +{ + struct vrf *vrf; + struct pim_instance *pim; + int writes = 0; + char framestr[64] = { 0 }; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + pim = vrf->info; + + if (!pim) + continue; + + snprintfrr(framestr, sizeof(framestr), "router %s", + PIM_AF_ROUTER); + if (vrf->vrf_id != VRF_DEFAULT) { + strlcat(framestr, " vrf ", sizeof(framestr)); + strlcat(framestr, vrf->name, sizeof(framestr)); + } + vty_frame(vty, "%s\n", framestr); + ++writes; + + writes += pim_global_config_write_worker(pim, vty); + + vty_endframe(vty, "exit\n"); + ++writes; + } + + return writes; +} diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h index e30203fa..d7c97e31 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,10 @@ 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); + /* * Special Macro to allow us to get the correct pim_instance; */ diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index dcb61160..20e3ba18 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("", ij->group_addr, - group_str, - sizeof(group_str)); - pim_inet4_dump( - "", 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("", ij->group_addr, group_str, + sizeof(group_str)); + pim_inet4_dump("", 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 0312f719..95bac084 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 063ba6ed..1ba9bc45 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 a1f19b3c..83524e39 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 b3410d15..f7c5ea3b 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; } @@ -201,6 +209,7 @@ static int pim_vrf_config_write(struct vty *vty) { struct vrf *vrf; struct pim_instance *pim; + char spaces[10]; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { pim = vrf->info; @@ -208,10 +217,24 @@ static int pim_vrf_config_write(struct vty *vty) if (!pim) continue; - if (vrf->vrf_id != VRF_DEFAULT) + if (vrf->vrf_id != VRF_DEFAULT) { vty_frame(vty, "vrf %s\n", vrf->name); - - pim_global_config_write_worker(pim, vty); + snprintf(spaces, sizeof(spaces), "%s", " "); + } else { + snprintf(spaces, sizeof(spaces), "%s", ""); + } + + /* Global IGMP/MLD configuration */ + if (pim->gm_watermark_limit != 0) { +#if PIM_IPV == 4 + vty_out(vty, + "%s" PIM_AF_NAME " igmp watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#else + vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#endif + } if (vrf->vrf_id != VRF_DEFAULT) vty_endframe(vty, "exit-vrf\n!\n"); @@ -238,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 ec331332..f484d847 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 400db396..f88aca71 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -59,6 +59,7 @@ struct zebra_privs_t pimd_privs = { .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; +/* clang-format off */ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -67,10 +68,10 @@ 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, }; -/* clang-format off */ FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT, .proghelp = "Implementation of the PIM routing protocol.", diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index 85780f01..2c35bc64 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"); @@ -26,6 +27,7 @@ DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info"); DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info"); DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name"); +DEFINE_MTYPE(PIMD, PIM_MSDP_AUTH_KEY, "PIM MSDP authentication key"); DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr"); diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index 41730e75..b44d3e19 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); @@ -28,6 +29,7 @@ DECLARE_MTYPE(PIM_MSDP_MG_NAME); DECLARE_MTYPE(PIM_MSDP_SA); DECLARE_MTYPE(PIM_MSDP_MG); DECLARE_MTYPE(PIM_MSDP_MG_MBR); +DECLARE_MTYPE(PIM_MSDP_AUTH_KEY); DECLARE_MTYPE(PIM_SEC_ADDR); DECLARE_MTYPE(PIM_JP_AGG_GROUP); DECLARE_MTYPE(PIM_JP_AGG_SOURCE); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index ea8c84cc..215cc3c5 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -773,7 +773,10 @@ static void pim_msdp_peer_listen(struct pim_msdp_peer *mp) * first listening peer is configured; but don't bother tearing it down * when * all the peers go down */ - pim_msdp_sock_listen(mp->pim); + if (mp->auth_type == MSDP_AUTH_NONE) + pim_msdp_sock_listen(mp->pim); + else + pim_msdp_sock_auth_listen(mp); } /* 11.2.A4 and 11.2.A5: transition active or passive peer to @@ -1045,6 +1048,7 @@ struct pim_msdp_peer *pim_msdp_peer_add(struct pim_instance *pim, mp->state = PIM_MSDP_INACTIVE; mp->fd = -1; + mp->auth_listen_sock = -1; strlcpy(mp->last_reset, "-", sizeof(mp->last_reset)); /* higher IP address is listener */ if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) { @@ -1100,6 +1104,12 @@ static void pim_msdp_peer_free(struct pim_msdp_peer *mp) stream_fifo_free(mp->obuf); } + /* Free authentication data. */ + event_cancel(&mp->auth_listen_ev); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + if (mp->auth_listen_sock != -1) + close(mp->auth_listen_sock); + XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name); mp->pim = NULL; @@ -1128,19 +1138,32 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp) *mp = NULL; } -void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, - const struct in_addr *addr) +void pim_msdp_peer_restart(struct pim_msdp_peer *mp) { - pim_msdp_peer_stop_tcp_conn(mp, true); + /* Stop auth listening socket if any. */ + event_cancel(&mp->auth_listen_ev); + if (mp->auth_listen_sock != -1) { + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; + } - mp->local = *addr; + /* Stop previously running connection. */ + pim_msdp_peer_stop_tcp_conn(mp, true); + /* Start connection again. */ if (PIM_MSDP_PEER_IS_LISTENER(mp)) pim_msdp_peer_listen(mp); else pim_msdp_peer_connect(mp); } +void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, + const struct in_addr *addr) +{ + mp->local = *addr; + pim_msdp_peer_restart(mp); +} + /* peer hash and peer list helpers */ static unsigned int pim_msdp_peer_hash_key_make(const void *p) { @@ -1274,8 +1297,7 @@ static void pim_msdp_src_del(struct pim_msdp_mg *mg) } /*********************** MSDP feature APIs *********************************/ -int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces) +int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty) { struct pim_msdp_mg *mg; struct listnode *mbrnode; @@ -1290,14 +1312,14 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, if (mg->src_ip.s_addr != INADDR_ANY) { pim_inet4_dump("", mg->src_ip, src_str, sizeof(src_str)); - vty_out(vty, "%sip msdp mesh-group %s source %s\n", - spaces, mg->mesh_group_name, src_str); + vty_out(vty, " msdp mesh-group %s source %s\n", + mg->mesh_group_name, src_str); ++count; } for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) { - vty_out(vty, "%sip msdp mesh-group %s member %pI4\n", - spaces, mg->mesh_group_name, &mbr->mbr_ip); + vty_out(vty, " msdp mesh-group %s member %pI4\n", + mg->mesh_group_name, &mbr->mbr_ip); ++count; } } @@ -1305,8 +1327,7 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, return count; } -bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, - const char *spaces) +bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) { struct pim_msdp_peer *mp; struct listnode *node; @@ -1317,8 +1338,21 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, if (mp->flags & PIM_MSDP_PEERF_IN_GROUP) continue; - vty_out(vty, "%sip msdp peer %pI4 source %pI4\n", spaces, - &mp->peer, &mp->local); + vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer, + &mp->local); + + if (mp->auth_type == MSDP_AUTH_MD5) + vty_out(vty, " msdp peer %pI4 password %s\n", &mp->peer, + mp->auth_key); + + if (mp->acl_in) + vty_out(vty, " msdp peer %pI4 sa-filter %s in\n", + &mp->peer, mp->acl_in); + + if (mp->acl_out) + vty_out(vty, " msdp peer %pI4 sa-filter %s out\n", + &mp->peer, mp->acl_out); + written = true; } diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index ddc015f9..f77b0e1a 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -89,6 +89,11 @@ enum pim_msdp_peer_flags { PIM_MSDP_PEERF_IN_GROUP = (1 << 2), }; +enum msdp_auth_type { + MSDP_AUTH_NONE = 0, + MSDP_AUTH_MD5 = 1, +}; + struct pim_msdp_peer { struct pim_instance *pim; @@ -98,6 +103,13 @@ struct pim_msdp_peer { char *mesh_group_name; char key_str[INET_ADDRSTRLEN]; + /* Authentication data. */ + enum msdp_auth_type auth_type; + char *auth_key; + + int auth_listen_sock; + struct event *auth_listen_ev; + /* state */ enum pim_msdp_peer_state state; enum pim_msdp_peer_flags flags; @@ -138,6 +150,11 @@ struct pim_msdp_peer { /* timestamps */ int64_t uptime; + + /** SA input access list name. */ + char *acl_in; + /** SA output access list name. */ + char *acl_out; }; struct pim_msdp_mg_mbr { @@ -228,10 +245,8 @@ void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp); void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state); void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str); void pim_msdp_write(struct event *thread); -int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces); -bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, - const char *spaces); +int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty); +bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim); void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp); void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, pim_sgaddr *sg, struct in_addr rp); @@ -306,6 +321,15 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp); void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, const struct in_addr *addr); +/** + * Restart peer's connection. + * + * This is used internally in MSDP and should be used by northbound + * when wanting to immediately apply connections settings such as + * authentication. + */ +void pim_msdp_peer_restart(struct pim_msdp_peer *mp); + #else /* PIM_IPV == 6 */ static inline void pim_msdp_init(struct pim_instance *pim, struct event_loop *master) @@ -339,14 +363,13 @@ static inline void pim_msdp_sa_local_del(struct pim_instance *pim, } static inline int pim_msdp_config_write(struct pim_instance *pim, - struct vty *vty, const char *spaces) + struct vty *vty) { return 0; } static inline bool pim_msdp_peer_config_write(struct vty *vty, - struct pim_instance *pim, - const char *spaces) + struct pim_instance *pim) { return false; } diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index 4324a96b..27f4966a 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include "frrevent.h" #include @@ -322,8 +324,8 @@ void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp) pim_msdp_pkt_send(mp, s); } -static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim, - struct pim_msdp_peer *mp) +static void pim_msdp_pkt_sa_push(struct pim_instance *pim, + struct pim_msdp_peer *mp) { struct stream *s; @@ -338,25 +340,6 @@ static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim, } } -/* push the stream into the obuf fifo of all the peers */ -static void pim_msdp_pkt_sa_push(struct pim_instance *pim, - struct pim_msdp_peer *mp) -{ - struct listnode *mpnode; - - if (mp) { - pim_msdp_pkt_sa_push_to_one_peer(pim, mp); - } else { - for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) { - if (PIM_DEBUG_MSDP_INTERNAL) { - zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push", - mp->key_str); - } - pim_msdp_pkt_sa_push_to_one_peer(pim, mp); - } - } -} - static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt, struct in_addr rp) { @@ -384,6 +367,90 @@ static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa) stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr); } +static bool msdp_cisco_match(const struct filter *filter, + const struct in_addr *source, + const struct in_addr *group) +{ + const struct filter_cisco *cfilter = &filter->u.cfilter; + uint32_t source_addr; + uint32_t group_addr; + + group_addr = group->s_addr & ~cfilter->mask_mask.s_addr; + + if (cfilter->extended) { + source_addr = source->s_addr & ~cfilter->addr_mask.s_addr; + if (group_addr == cfilter->mask.s_addr && + source_addr == cfilter->addr.s_addr) + return true; + } else if (group_addr == cfilter->addr.s_addr) + return true; + + return false; +} + +static enum filter_type msdp_access_list_apply(struct access_list *access, + const struct in_addr *source, + const struct in_addr *group) +{ + struct filter *filter; + struct prefix group_prefix; + + if (access == NULL) + return FILTER_DENY; + + for (filter = access->head; filter; filter = filter->next) { + if (filter->cisco) { + if (msdp_cisco_match(filter, source, group)) + return filter->type; + } else { + group_prefix.family = AF_INET; + group_prefix.prefixlen = IPV4_MAX_BITLEN; + group_prefix.u.prefix4.s_addr = group->s_addr; + if (access_list_apply(access, &group_prefix)) + return filter->type; + } + } + + return FILTER_DENY; +} + +bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, + const struct pim_msdp_sa *sa) +{ + struct access_list *acl; + + /* No output filter configured, just quit. */ + if (mp->acl_out == NULL) + return false; + + /* Find access list and test it. */ + acl = access_list_lookup(AFI_IP, mp->acl_out); + if (msdp_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY) + return true; + + return false; +} + +/** Count the number of SAs to be sent for a specific peer. */ +static size_t pim_msdp_peer_sa_count(const struct pim_instance *pim, + const struct pim_msdp_peer *peer) +{ + const struct pim_msdp_sa *sa; + const struct listnode *node; + size_t sa_count = 0; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, node, sa)) { + if (!CHECK_FLAG(sa->flags, PIM_MSDP_SAF_LOCAL)) + continue; + if (msdp_peer_sa_filter(peer, sa)) + continue; + + sa_count++; + } + + return sa_count; +} + static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, struct pim_msdp_peer *mp) { @@ -393,7 +460,7 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, struct prefix group_all; struct in_addr rp; int sa_count; - int local_cnt = pim->msdp.local_cnt; + int local_cnt = pim_msdp_peer_sa_count(pim, mp); sa_count = 0; if (PIM_DEBUG_MSDP_INTERNAL) { @@ -418,6 +485,15 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, * peers */ continue; } + + if (msdp_peer_sa_filter(mp, sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out %s", + &mp->peer, sa->sg_str); + + continue; + } + /* add sa into scratch pad */ pim_msdp_pkt_sa_fill_one(sa); ++sa_count; @@ -457,15 +533,32 @@ static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim) void pim_msdp_pkt_sa_tx(struct pim_instance *pim) { - pim_msdp_pkt_sa_gen(pim, NULL /* mp */); + struct pim_msdp_peer *mp; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) + pim_msdp_pkt_sa_gen(pim, mp); + pim_msdp_pkt_sa_tx_done(pim); } void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa) { + struct pim_msdp_peer *mp; + struct listnode *node; + pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp); pim_msdp_pkt_sa_fill_one(sa); - pim_msdp_pkt_sa_push(sa->pim, NULL); + for (ALL_LIST_ELEMENTS_RO(sa->pim->msdp.peer_list, node, mp)) { + if (msdp_peer_sa_filter(mp, sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out %s", + &mp->peer, sa->sg_str); + continue; + } + + pim_msdp_pkt_sa_push(sa->pim, mp); + } pim_msdp_pkt_sa_tx_done(sa->pim); } @@ -487,6 +580,15 @@ void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, /* Fills the message contents. */ sa.pim = mp->pim; sa.sg = sg; + + /* Don't push it if filtered. */ + if (msdp_peer_sa_filter(mp, &sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out (%pI4, %pI4)", + &mp->peer, &sa.sg.src, &sa.sg.grp); + return; + } + pim_msdp_pkt_sa_fill_one(&sa); /* Pushes the message. */ @@ -511,6 +613,7 @@ static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len) static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) { + struct access_list *acl; int prefix_len; pim_sgaddr sg; struct listnode *peer_node; @@ -534,6 +637,19 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) if (PIM_DEBUG_MSDP_PACKETS) { zlog_debug(" sg %pSG", &sg); } + + /* Filter incoming SA with configured access list. */ + if (mp->acl_in) { + acl = access_list_lookup(AFI_IP, mp->acl_in); + if (msdp_access_list_apply(acl, &sg.src, &sg.grp) == + FILTER_DENY) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA in (%pI4, %pI4)", + &mp->peer, &sg.src, &sg.grp); + return; + } + } + pim_msdp_sa_ref(mp->pim, mp, &sg, rp); /* Forwards the SA to the peers that are not in the RPF to the RP nor in diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h index 1584a245..3af8d936 100644 --- a/pimd/pim_msdp_packet.h +++ b/pimd/pim_msdp_packet.h @@ -57,5 +57,7 @@ void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa); void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp); void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, struct in_addr rp, pim_sgaddr sg); +bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, + const struct pim_msdp_sa *sa); #endif diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c index fe8d5e93..2fb0bb87 100644 --- a/pimd/pim_msdp_socket.c +++ b/pimd/pim_msdp_socket.c @@ -49,6 +49,192 @@ static void pim_msdp_update_sock_send_buffer_size(int fd) } } +/** + * Helper function to reduce code duplication. + * + * \param vrf VRF pointer (`NULL` means default VRF) + * \param mp the MSDP session pointer. + * \returns valid file descriptor otherwise `-1`. + */ +static int _pim_msdp_sock_listen(const struct vrf *vrf, + const struct pim_msdp_peer *mp) +{ + const struct interface *ifp; + int sock; + int rv; + socklen_t socklen; + struct sockaddr_in sin = {}; + union sockunion su_peer = {}; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + zlog_warn("%s: socket: %s", __func__, strerror(errno)); + return -1; + } + + socklen = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(PIM_MSDP_TCP_PORT); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sin.sin_len = socklen; +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + if (mp) + sin.sin_addr = mp->local; + + sockopt_reuseaddr(sock); + sockopt_reuseport(sock); + + /* Bind socket to VRF/address. */ + if (vrf && vrf->vrf_id != VRF_DEFAULT) { + ifp = if_lookup_by_name(vrf->name, vrf->vrf_id); + if (ifp == NULL) { + flog_err(EC_LIB_INTERFACE, + "%s: Unable to lookup vrf interface: %s", + __func__, vrf->name); + close(sock); + return -1; + } + + if (vrf_bind(vrf->vrf_id, sock, ifp->name) == -1) { + flog_err_sys(EC_LIB_SOCKET, + "%s: Unable to bind to socket: %s", + __func__, safe_strerror(errno)); + close(sock); + return -1; + } + } + + frr_with_privs (&pimd_privs) { + rv = bind(sock, (struct sockaddr *)&sin, socklen); + } + if (rv == -1) { + flog_err_sys(EC_LIB_SOCKET, + "pim_msdp_socket bind to port %d: %s", + ntohs(sin.sin_port), safe_strerror(errno)); + close(sock); + return -1; + } + + /* Set MD5 authentication. */ + if (mp && mp->auth_key) { + su_peer = mp->su_peer; + frr_with_privs (&pimd_privs) { + sockopt_tcp_signature(sock, &su_peer, mp->auth_key); + } + } + + + /* Start listening. */ + rv = listen(sock, SOMAXCONN); + if (rv == -1) { + flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s", + safe_strerror(errno)); + close(sock); + return -1; + } + + /* Set socket DSCP byte */ + if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) { + zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", + sock, safe_strerror(errno)); + } + + return sock; +} + +static void pim_msdp_sock_auth_accept(struct event *t) +{ + struct pim_msdp_peer *mp = EVENT_ARG(t); + int sock; + socklen_t sinlen; + struct sockaddr_in sin = {}; + + /* accept client connection. */ + sinlen = sizeof(sin); + sock = accept(mp->auth_listen_sock, (struct sockaddr *)&sin, &sinlen); + if (sock == -1) { + flog_err_sys(EC_LIB_SOCKET, "pim_msdp_sock_accept failed (%s)", + safe_strerror(errno)); + + /* Accept failed, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + /* + * Previous connection still going. + * + * We must wait for the user to close the previous connection in order + * to establish the new one. User can manually force that by calling + * `clear ip msdp peer A.B.C.D`. + */ + if (mp->fd != -1) { + ++mp->pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer connection refused from %pI4: old connection still running", + &sin.sin_addr); + } + close(sock); + + /* Unexpected connection, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + /* Unexpected client connected. */ + if (mp->peer.s_addr != sin.sin_addr.s_addr) { + ++mp->pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer connection refused from %pI4", + &sin.sin_addr); + } + close(sock); + + /* Unexpected peer, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + if (PIM_DEBUG_MSDP_INTERNAL) + zlog_debug("MSDP peer %s accept success", mp->key_str); + + /* Configure socket. */ + mp->fd = sock; + set_nonblocking(mp->fd); + pim_msdp_update_sock_send_buffer_size(mp->fd); + pim_msdp_peer_established(mp); + + /* Stop listening. */ + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; +} + +int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp) +{ + /* Clear any listening connection if it exists. */ + event_cancel(&mp->auth_listen_ev); + if (mp->auth_listen_sock != -1) { + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; + } + + /* Start new listening socket. */ + mp->auth_listen_sock = _pim_msdp_sock_listen(mp->pim->vrf, mp); + if (mp->auth_listen_sock == -1) + return -1; + + /* Listen for connections and connected only with the expected end. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + + return 0; +} + /* passive peer socket accept */ static void pim_msdp_sock_accept(struct event *thread) { @@ -91,6 +277,21 @@ static void pim_msdp_sock_accept(struct event *thread) return; } + /* + * If authentication is configured then we can not accept + * unauthenticated connections. + */ + if (mp->auth_type != MSDP_AUTH_NONE) { + ++pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer unauthenticated connection refused from %pSU", + &su); + } + close(msdp_sock); + return; + } + if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP peer %s accept success%s", mp->key_str, mp->fd >= 0 ? "(dup)" : ""); @@ -116,9 +317,6 @@ static void pim_msdp_sock_accept(struct event *thread) int pim_msdp_sock_listen(struct pim_instance *pim) { int sock; - int socklen; - struct sockaddr_in sin; - int rc; struct pim_msdp_listener *listener = &pim->msdp.listener; if (pim->msdp.flags & PIM_MSDPF_LISTENER) { @@ -126,72 +324,20 @@ int pim_msdp_sock_listen(struct pim_instance *pim) return 0; } - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - flog_err_sys(EC_LIB_SOCKET, "socket: %s", safe_strerror(errno)); - return sock; - } + sock = _pim_msdp_sock_listen(pim->vrf, NULL); + if (sock == -1) + return -1; - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_port = htons(PIM_MSDP_TCP_PORT); - socklen = sizeof(struct sockaddr_in); + + memset(&listener->su.sin, 0, sizeof(listener->su.sin)); + listener->su.sin.sin_family = AF_INET; + listener->su.sin.sin_port = htons(PIM_MSDP_TCP_PORT); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin.sin_len = socklen; + listener->su.sin.sin_len = sizeof(listener->su.sin); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sockopt_reuseaddr(sock); - sockopt_reuseport(sock); - - if (pim->vrf->vrf_id != VRF_DEFAULT) { - struct interface *ifp = - if_lookup_by_name(pim->vrf->name, pim->vrf->vrf_id); - if (!ifp) { - flog_err(EC_LIB_INTERFACE, - "%s: Unable to lookup vrf interface: %s", - __func__, pim->vrf->name); - close(sock); - return -1; - } - if (pim_socket_bind(sock, ifp)) { - flog_err_sys(EC_LIB_SOCKET, - "%s: Unable to bind to socket: %s", - __func__, safe_strerror(errno)); - close(sock); - return -1; - } - } - - frr_with_privs(&pimd_privs) { - /* bind to well known TCP port */ - rc = bind(sock, (struct sockaddr *)&sin, socklen); - } - - if (rc < 0) { - flog_err_sys(EC_LIB_SOCKET, - "pim_msdp_socket bind to port %d: %s", - ntohs(sin.sin_port), safe_strerror(errno)); - close(sock); - return rc; - } - - rc = listen(sock, 3 /* backlog */); - if (rc < 0) { - flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s", - safe_strerror(errno)); - close(sock); - return rc; - } - - /* Set socket DSCP byte */ - if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) { - zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", - sock, safe_strerror(errno)); - } - /* add accept thread */ listener->fd = sock; - memcpy(&listener->su, &sin, socklen); event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock, &listener->thread); @@ -272,6 +418,14 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp) mp->fd, safe_strerror(errno)); } + /* Set authentication (if configured). */ + if (mp->auth_key) { + frr_with_privs (&pimd_privs) { + sockopt_tcp_signature(mp->fd, &mp->su_peer, + mp->auth_key); + } + } + /* Connect to the remote mp. */ return (sockunion_connect(mp->fd, &mp->su_peer, htons(PIM_MSDP_TCP_PORT), 0)); diff --git a/pimd/pim_msdp_socket.h b/pimd/pim_msdp_socket.h index ae31664f..d2c60140 100644 --- a/pimd/pim_msdp_socket.h +++ b/pimd/pim_msdp_socket.h @@ -6,6 +6,9 @@ #ifndef PIM_MSDP_SOCKET_H #define PIM_MSDP_SOCKET_H +struct pim_msdp_peer; + +int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp); int pim_msdp_sock_listen(struct pim_instance *pim); int pim_msdp_sock_connect(struct pim_msdp_peer *mp); #endif diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index 56923b7e..1f916af8 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 339935f8..66001d14 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -163,6 +163,33 @@ const struct frr_yang_module_info frr_pim_info = { .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in", + .cbs = { + .modify = pim_msdp_peer_sa_filter_in_modify, + .destroy = pim_msdp_peer_sa_filter_in_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out", + .cbs = { + .modify = pim_msdp_peer_sa_filter_out_modify, + .destroy = pim_msdp_peer_sa_filter_out_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type", + .cbs = { + .modify = pim_msdp_peer_authentication_type_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key", + .cbs = { + .modify = pim_msdp_peer_authentication_key_modify, + .destroy = pim_msdp_peer_authentication_key_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag", .cbs = { @@ -352,6 +379,161 @@ const struct frr_yang_module_info frr_pim_rp_info = { .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy, } }, + { + .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, }, @@ -414,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, @@ -425,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 0321d076..befad4ef 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*/ @@ -65,6 +66,13 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify( struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( @@ -151,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( @@ -175,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( @@ -193,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']/" \ @@ -207,17 +285,17 @@ int routing_control_plane_protocols_name_validate( "./frr-pim:pim/address-family[address-family='%s']/" \ "mroute[source-addr='%s'][group-addr='%s']" #define FRR_PIM_STATIC_RP_XPATH \ - "/frr-routing:routing/control-plane-protocols/" \ - "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ - "frr-pim:pim/address-family[address-family='%s']/" \ "frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']" +#define FRR_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']" -#define FRR_PIM_MSDP_XPATH FRR_PIM_VRF_XPATH "/msdp" #endif /* _FRR_PIM_NB_H_ */ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index be0be858..ea8b56fe 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -9,12 +9,14 @@ #include "pimd.h" #include "pim_nb.h" #include "lib/northbound_cli.h" +#include "lib/sockopt.h" #include "pim_igmpv3.h" #include "pim_neighbor.h" #include "pim_nht.h" #include "pim_pim.h" #include "pim_mlag.h" #include "pim_bfd.h" +#include "pim_msdp_socket.h" #include "pim_static.h" #include "pim_ssm.h" #include "pim_ssmpingd.h" @@ -24,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) \ @@ -144,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; } @@ -925,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; } } @@ -955,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; } @@ -1053,6 +1060,9 @@ pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address nb_cb_destroy_args); pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); #if PIM_IPV != 6 /* @@ -1154,6 +1164,81 @@ int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type + */ +int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + mp->auth_type = yang_dnode_get_enum(args->dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key + */ +int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + if (strlen(yang_dnode_get_string(args->dnode, NULL)) > + TCP_MD5SIG_MAXKEYLEN) { + snprintf(args->errmsg, args->errmsg_len, + "MD5 authentication key too long"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + mp->auth_key = XSTRDUP(MTYPE_PIM_MSDP_AUTH_KEY, + yang_dnode_get_string(args->dnode, NULL)); + + /* We must start listening the new authentication key now. */ + if (PIM_MSDP_PEER_IS_LISTENER(mp)) + pim_msdp_sock_auth_listen(mp); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + break; + } + + return NB_OK; +} /* * XPath: @@ -1286,6 +1371,94 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms } #endif /* PIM_IPV != 6 */ +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in + */ +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + mp->acl_in = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out + */ +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + mp->acl_out = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + break; + } + + return NB_OK; +} + /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag */ @@ -1890,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; @@ -1915,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); @@ -2504,24 +2685,42 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp } /* - * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/discovery-enabled */ -int lib_interface_gmp_address_family_create(struct nb_cb_create_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) { +#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 lib_interface_gmp_address_family_destroy(struct nb_cb_destroy_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) { - struct interface *ifp; +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + bool enabled; switch (args->event) { case NB_EV_VALIDATE: @@ -2529,65 +2728,77 @@ int lib_interface_gmp_address_family_destroy(struct nb_cb_destroy_args *args) case NB_EV_ABORT: break; case NB_EV_APPLY: - ifp = nb_running_get_entry(args->dnode, NULL, true); - pim_gm_interface_delete(ifp); + 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-interface:lib/interface/frr-gmp:gmp/address-family/enable + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-scope */ -int lib_interface_gmp_address_family_enable_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify( struct nb_cb_modify_args *args) { - struct interface *ifp; - bool gm_enable; - int mcast_if_count; - const char *ifp_name; - const struct lyd_node *if_dnode; +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + uint8_t scope; switch (args->event) { case NB_EV_VALIDATE: - if_dnode = yang_dnode_get_parent(args->dnode, "interface"); - mcast_if_count = - yang_get_list_elements_count(if_dnode); - /* Limiting mcast interfaces to number of VIFs */ - if (mcast_if_count == MAXVIFS) { - ifp_name = yang_dnode_get_string(if_dnode, "name"); - snprintf( - args->errmsg, args->errmsg_len, - "Max multicast interfaces(%d) Reached. Could not enable %s on interface %s", - MAXVIFS, GM, ifp_name); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - ifp = nb_running_get_entry(args->dnode, NULL, true); - gm_enable = yang_dnode_get_bool(args->dnode, NULL); + 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 - if (gm_enable) - return pim_cmd_gm_start(ifp); + 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; - else - pim_gm_interface_delete(ifp); + 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-interface:lib/interface/frr-gmp:gmp/address-family/igmp-version + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-interval */ -int lib_interface_gmp_address_family_igmp_version_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify( struct nb_cb_modify_args *args) { - struct interface *ifp; - struct pim_interface *pim_ifp; - int igmp_version, old_version = 0; +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + uint16_t interval; switch (args->event) { case NB_EV_VALIDATE: @@ -2595,33 +2806,21 @@ int lib_interface_gmp_address_family_igmp_version_modify( case NB_EV_ABORT: break; case NB_EV_APPLY: - ifp = nb_running_get_entry(args->dnode, NULL, true); - pim_ifp = ifp->info; - - if (!pim_ifp) - return NB_ERR_INCONSISTENCY; - - igmp_version = yang_dnode_get_uint8(args->dnode, NULL); - old_version = pim_ifp->igmp_version; - pim_ifp->igmp_version = igmp_version; - - /* Current and new version is different refresh existing - * membership. Going from 3 -> 2 or 2 -> 3. - */ - if (old_version != igmp_version) - pim_if_membership_refresh(ifp); - - break; + 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 lib_interface_gmp_address_family_igmp_version_destroy( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy( struct nb_cb_destroy_args *args) { - struct interface *ifp; - struct pim_interface *pim_ifp; +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; switch (args->event) { case NB_EV_VALIDATE: @@ -2629,9 +2828,735 @@ int lib_interface_gmp_address_family_igmp_version_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - ifp = nb_running_get_entry(args->dnode, NULL, true); - pim_ifp = ifp->info; - pim_ifp->igmp_version = IGMP_DEFAULT_VERSION; + 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) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_gmp_address_family_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *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_gm_interface_delete(ifp); + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/enable + */ +int lib_interface_gmp_address_family_enable_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + bool gm_enable; + int mcast_if_count; + const char *ifp_name; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + mcast_if_count = + yang_get_list_elements_count(if_dnode); + /* Limiting mcast interfaces to number of VIFs */ + if (mcast_if_count == MAXVIFS) { + ifp_name = yang_dnode_get_string(if_dnode, "name"); + snprintf( + args->errmsg, args->errmsg_len, + "Max multicast interfaces(%d) Reached. Could not enable %s on interface %s", + MAXVIFS, GM, ifp_name); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + gm_enable = yang_dnode_get_bool(args->dnode, NULL); + + if (gm_enable) + return pim_cmd_gm_start(ifp); + + else + pim_gm_interface_delete(ifp); + } + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/igmp-version + */ +int lib_interface_gmp_address_family_igmp_version_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int igmp_version, old_version = 0; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + + if (!pim_ifp) + return NB_ERR_INCONSISTENCY; + + igmp_version = yang_dnode_get_uint8(args->dnode, NULL); + old_version = pim_ifp->igmp_version; + pim_ifp->igmp_version = igmp_version; + + /* Current and new version is different refresh existing + * membership. Going from 3 -> 2 or 2 -> 3. + */ + if (old_version != igmp_version) + pim_if_membership_refresh(ifp); + + break; + } + + return NB_OK; +} + +int lib_interface_gmp_address_family_igmp_version_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->igmp_version = IGMP_DEFAULT_VERSION; break; } @@ -2821,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; @@ -2871,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"); @@ -2881,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; @@ -2900,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 32cdf4bf..f2dbfa97 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -161,18 +161,27 @@ void pim_nht_bsr_add(struct pim_instance *pim, pim_addr addr) pnc->bsr_count++; } +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc; + + pnc = pim_nht_get(pim, addr); + + pnc->candrp_count++; + return CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID); +} + static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cache *pnc) { if (PIM_DEBUG_PIM_NHT) - zlog_debug( - "%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u", - __func__, &pnc->rpf.rpf_addr, pim->vrf->name, - pnc->rp_list->count, pnc->upstream_hash->count, - pnc->bsr_count); + zlog_debug("%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u Cand-RP count:%u", + __func__, &pnc->rpf.rpf_addr, pim->vrf->name, + pnc->rp_list->count, pnc->upstream_hash->count, + pnc->bsr_count, pnc->candrp_count); - if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 - && pnc->bsr_count == 0) { + if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 && + pnc->bsr_count == 0 && pnc->candrp_count == 0) { struct zclient *zclient = pim_zebra_zclient_get(); pim_sendmsg_zebra_rnh(pim, zclient, pnc, @@ -258,6 +267,27 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr addr) pim_nht_drop_maybe(pim, pnc); } +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc = NULL; + struct pim_nexthop_cache lookup; + + lookup.rpf.rpf_addr = addr; + + pnc = hash_lookup(pim->rpf_hash, &lookup); + + if (!pnc) { + zlog_warn("attempting to delete nonexistent NHT C-RP entry %pPA", + &addr); + return; + } + + assertf(pnc->candrp_count > 0, "addr=%pPA", &addr); + pnc->candrp_count--; + + pim_nht_drop_maybe(pim, pnc); +} + bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip) { @@ -312,8 +342,19 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, nbr = pim_neighbor_find(ifp, znh->nexthop_addr, true); if (!nbr) continue; - - return znh->ifindex == src_ifp->ifindex; + /* Are we on the correct interface? */ + if (znh->ifindex == src_ifp->ifindex) { + /* Do we have the correct NH ? */ + if (!pim_addr_cmp(znh->nexthop_addr, src_ip)) + return true; + /* + * check If the packet came from the neighbor, + * and the dst is a secondary address on the connected interface + */ + return (!pim_addr_cmp(nbr->source_addr, src_ip) && + pim_if_connected_to_source(ifp, znh->nexthop_addr)); + } + return false; } return false; } @@ -374,13 +415,23 @@ 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; + /* Are we on the correct interface? */ + if (nh->ifindex == src_ifp->ifindex) { + /* Do we have the correct NH ? */ + if (!pim_addr_cmp(nhaddr, src_ip)) + return true; + /* + * check If the packet came from the neighbor, + * and the dst is a secondary address on the connected interface + */ + return (!pim_addr_cmp(nbr->source_addr, src_ip) && + pim_if_connected_to_source(ifp, nhaddr)); + } + return false; } return false; } @@ -543,7 +594,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, ifindex_t first_ifindex; struct interface *ifp = NULL; uint32_t hash_val = 0, mod_val = 0; - uint8_t nh_iter = 0, found = 0; + uint16_t nh_iter = 0, found = 0; uint32_t i, num_nbrs = 0; struct pim_interface *pim_ifp; @@ -900,6 +951,9 @@ void pim_nexthop_update(struct vrf *vrf, struct prefix *match, pim_update_rp_nh(pim, pnc); if (pnc->upstream_hash->count) pim_update_upstream_nh(pim, pnc); + + if (pnc->candrp_count) + pim_crp_nht_update(pim, pnc); } int pim_ecmp_nexthop_lookup(struct pim_instance *pim, @@ -914,7 +968,7 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, struct interface *ifps[router->multipath], *ifp; int first_ifindex; int found = 0; - uint8_t i = 0; + uint16_t i = 0; uint32_t hash_val = 0, mod_val = 0; uint32_t num_nbrs = 0; struct pim_interface *pim_ifp; diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index a1feb76e..d064f714 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -23,7 +23,7 @@ struct pim_nexthop_cache { uint32_t metric; uint32_t distance; /* Nexthop number and nexthop linked list. */ - uint8_t nexthop_num; + uint16_t nexthop_num; struct nexthop *nexthop; int64_t last_update; uint16_t flags; @@ -38,6 +38,7 @@ struct pim_nexthop_cache { * same BSR */ uint32_t bsr_count; + uint32_t candrp_count; }; struct pnc_hash_walk_data { @@ -71,4 +72,10 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr bsr_addr); bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip); void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp); + +/* wrappers for usage with Candidate RPs in BSMs */ +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr); +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr); +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc); + #endif diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 1bc265b1..a41bbace 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); + +static void pim_sock_read(struct event *t) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int fd; - result = 0; /* good */ + 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) @@ -636,17 +661,15 @@ static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex, int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, int pim_msg_size, struct interface *ifp) { - struct pim_interface *pim_ifp; - - - pim_ifp = ifp->info; + if (ifp) { + struct pim_interface *pim_ifp = ifp->info; - if (pim_ifp->pim_passive_enable) { - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "skip sending PIM message on passive interface %s", - ifp->name); - return 0; + if (pim_ifp->pim_passive_enable) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("skip sending PIM message on passive interface %s", + ifp->name); + return 0; + } } #if PIM_IPV == 4 @@ -710,7 +733,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, if (PIM_DEBUG_PIM_PACKETS) zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x", - __func__, &dst, ifp->name, pim_msg_size, + __func__, &dst, ifp ? ifp->name : "*", pim_msg_size, header->checksum); if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { @@ -718,7 +741,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, } pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to, - tolen, ifp->name); + tolen, ifp ? ifp->name : "*"); return 0; #else @@ -727,7 +750,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, iovector[0].iov_base = pim_msg; iovector[0].iov_len = pim_msg_size; - pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd); + pim_msg_send_frame(src, dst, ifp ? ifp->ifindex : 0, &iovector[0], fd); return 0; #endif diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h index 35e69301..39b27bce 100644 --- a/pimd/pim_pim.h +++ b/pimd/pim_pim.h @@ -10,6 +10,7 @@ #include #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 d8d25712..0c47bc15 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -543,6 +543,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_all); + if (rp_all->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_all->rp.rpf_addr, &rp_all->group); pim_rp_refresh_group_to_rp_mapping(pim); pim_find_or_track_nexthop(pim, nht_p, NULL, rp_all, NULL); @@ -634,6 +637,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_info); + if (rp_info->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_info->rp.rpf_addr, &rp_info->group); pim_rp_refresh_group_to_rp_mapping(pim); /* Register addr with Zebra NHT */ @@ -1101,16 +1107,17 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, pim_addr source, pim_addr group) { struct rp_info *rp_info; - struct prefix g; + struct prefix g = {}; - memset(&g, 0, sizeof(g)); + if (!pim_addr_is_any(source)) { + *up = source; + return 1; + } pim_addr_to_prefix(&g, group); - rp_info = pim_rp_find_match_group(pim, &g); - if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) && - (pim_addr_is_any(source)))) { + if (!rp_info || pim_rpf_addr_is_inaddr_any(&rp_info->rp)) { if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __func__); @@ -1118,16 +1125,11 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, return 0; } - if (pim_addr_is_any(source)) - *up = rp_info->rp.rpf_addr; - else - *up = source; - + *up = rp_info->rp.rpf_addr; return 1; } -int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces) +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty) { struct listnode *node; struct rp_info *rp_info; @@ -1138,18 +1140,17 @@ 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; if (rp_info->plist) - vty_out(vty, - "%s" PIM_AF_NAME - " pim rp %pPA prefix-list %s\n", - spaces, &rp_addr, rp_info->plist); + vty_out(vty, " rp %pPA prefix-list %s\n", &rp_addr, + rp_info->plist); else - vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n", - spaces, &rp_addr, &rp_info->group); + vty_out(vty, " rp %pPA %pFX\n", &rp_addr, + &rp_info->group); count++; } @@ -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 9416a9a8..24832d0d 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; @@ -46,8 +42,7 @@ int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr, void pim_rp_prefix_list_update(struct pim_instance *pim, struct prefix_list *plist); -int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces); +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty); void pim_rp_setup(struct pim_instance *pim); diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 3476c177..8900652d 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 04ab8647..0a81c694 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 4081786c..ac07154f 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 081ad908..a41d0a84 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 c463fa22..dd1bf2c0 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 0f6547ee..b633e81d 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; } @@ -172,89 +177,70 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) { int writes = 0; struct pim_ssm *ssm = pim->ssm_info; - char spaces[10]; - - if (pim->vrf->vrf_id == VRF_DEFAULT) - snprintf(spaces, sizeof(spaces), "%s", ""); - else - snprintf(spaces, sizeof(spaces), "%s", " "); - writes += pim_msdp_peer_config_write(vty, pim, spaces); - writes += pim_msdp_config_write(pim, vty, spaces); + writes += pim_msdp_peer_config_write(vty, pim); + writes += pim_msdp_config_write(pim, vty); if (!pim->send_v6_secondary) { - vty_out(vty, "%sno ip pim send-v6-secondary\n", spaces); + vty_out(vty, " no send-v6-secondary\n"); ++writes; } - writes += pim_rp_config_write(pim, vty, spaces); + 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 != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) { - vty_out(vty, "%s" PIM_AF_NAME " pim register-suppress-time %d\n", - spaces, router->register_suppress_time); + vty_out(vty, " register-suppress-time %d\n", + router->register_suppress_time); ++writes; } if (router->t_periodic != PIM_DEFAULT_T_PERIODIC) { - vty_out(vty, "%s" PIM_AF_NAME " pim join-prune-interval %d\n", - spaces, router->t_periodic); + vty_out(vty, " join-prune-interval %d\n", + router->t_periodic); ++writes; } if (router->packet_process != PIM_DEFAULT_PACKET_PROCESS) { - vty_out(vty, "%s" PIM_AF_NAME " pim packets %d\n", spaces, - router->packet_process); + vty_out(vty, " packets %d\n", router->packet_process); ++writes; } } if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) { - vty_out(vty, "%s" PIM_AF_NAME " pim keep-alive-timer %d\n", - spaces, pim->keep_alive_time); + vty_out(vty, " keep-alive-timer %d\n", pim->keep_alive_time); ++writes; } if (pim->rp_keep_alive_time != (unsigned int)PIM_RP_KEEPALIVE_PERIOD) { - vty_out(vty, "%s" PIM_AF_NAME " pim rp keep-alive-timer %d\n", - spaces, pim->rp_keep_alive_time); + vty_out(vty, " rp keep-alive-timer %d\n", + pim->rp_keep_alive_time); ++writes; } if (ssm->plist_name) { - vty_out(vty, "%sip pim ssm prefix-list %s\n", spaces, - ssm->plist_name); + vty_out(vty, " ssm prefix-list %s\n", ssm->plist_name); ++writes; } if (pim->register_plist) { - vty_out(vty, "%sip pim register-accept-list %s\n", spaces, - pim->register_plist); + vty_out(vty, " register-accept-list %s\n", pim->register_plist); ++writes; } if (pim->spt.switchover == PIM_SPT_INFINITY) { if (pim->spt.plist) vty_out(vty, - "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond prefix-list %s\n", - spaces, pim->spt.plist); + " spt-switchover infinity-and-beyond prefix-list %s\n", + pim->spt.plist); else - vty_out(vty, - "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond\n", - spaces); + vty_out(vty, " spt-switchover infinity-and-beyond\n"); ++writes; } if (pim->ecmp_rebalance_enable) { - vty_out(vty, "%sip pim ecmp rebalance\n", spaces); + vty_out(vty, " ecmp rebalance\n"); ++writes; } else if (pim->ecmp_enable) { - vty_out(vty, "%sip pim ecmp\n", spaces); - ++writes; - } - - if (pim->gm_watermark_limit != 0) { -#if PIM_IPV == 4 - vty_out(vty, "%s" PIM_AF_NAME " igmp watermark-warn %u\n", - spaces, pim->gm_watermark_limit); -#else - vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", - spaces, pim->gm_watermark_limit); -#endif + vty_out(vty, " ecmp\n"); ++writes; } @@ -263,8 +249,7 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) struct ssmpingd_sock *ss; ++writes; for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) { - vty_out(vty, "%s" PIM_AF_NAME " ssmpingd %pPA\n", - spaces, &ss->source_addr); + vty_out(vty, " ssmpingd %pPA\n", &ss->source_addr); ++writes; } } @@ -272,8 +257,8 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) if (pim->msdp.hold_time != PIM_MSDP_PEER_HOLD_TIME || pim->msdp.keep_alive != PIM_MSDP_PEER_KA_TIME || pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) { - vty_out(vty, "%sip msdp timers %u %u", spaces, - pim->msdp.hold_time, pim->msdp.keep_alive); + vty_out(vty, " msdp timers %u %u", pim->msdp.hold_time, + pim->msdp.keep_alive); if (pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) vty_out(vty, " %u", pim->msdp.connection_retry); @@ -293,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); @@ -330,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 @@ -382,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 e25eafc2..ce4d85a2 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -157,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; } @@ -205,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 3d931895..461b7d08 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 1e787a35..bda594e5 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/python/firstheader.py b/python/firstheader.py index 06e28958..1a3cadfd 100644 --- a/python/firstheader.py +++ b/python/firstheader.py @@ -15,7 +15,7 @@ argp.add_argument("--autofix", action="store_const", const=True) argp.add_argument("--warn-empty", action="store_const", const=True) argp.add_argument("--pipe", action="store_const", const=True) -include_re = re.compile('^#\s*include\s+["<]([^ ">]+)[">]', re.M) +include_re = re.compile(r'^#\s*include\s+["<]([^ ">]+)[">]', re.M) ignore = [ lambda fn: fn.startswith("tools/"), diff --git a/python/makefile.py b/python/makefile.py index 573871fb..45f03229 100644 --- a/python/makefile.py +++ b/python/makefile.py @@ -91,7 +91,7 @@ lines = before.splitlines() autoderp = "#AUTODERP# " out_lines = [] bcdeps = [] -make_rule_re = re.compile("^([^:\s]+):\s*([^:\s]+)\s*($|\n)") +make_rule_re = re.compile(r"^([^:\s]+):\s*([^:\s]+)\s*($|\n)") while lines: line = lines.pop(0) diff --git a/python/xref2vtysh.py b/python/xref2vtysh.py index 75d9ccf3..0cfb11e7 100644 --- a/python/xref2vtysh.py +++ b/python/xref2vtysh.py @@ -26,6 +26,8 @@ try: except ImportError: pass +import _clippy + frr_top_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # vtysh needs to know which daemon(s) to send commands to. For lib/, this is @@ -58,6 +60,16 @@ vtysh_cmd_head = """/* autogenerated file, DO NOT EDIT! */ #include "linklist.h" #include "vtysh/vtysh.h" + +#pragma GCC visibility push(internal) + +#define MAKE_VECTOR(name, len, ...) \\ + static void * name ## _vitems[] = { __VA_ARGS__ }; \\ + static struct _vector name = { \\ + .active = len, \\ + .count = len, \\ + .index = name ## _vitems, \\ + } """ if sys.stderr.isatty(): @@ -335,23 +347,159 @@ class CommandEntry: ofd.write(entry.get_def()) @classmethod - def output_install(cls, ofd, nodes): - ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + def output_node_graph(cls, ofd, node, cmds, splitfile): + graph = _clippy.Graph(None) + + for _, cmd in sorted(cmds.items()): + cg = _clippy.Graph(cmd.cmd, cmd._spec["doc"], cmd.name) + graph.merge(cg) + + if len(graph) <= 2: + return [] + + ofd.write("\n") + ofd.write(f"static struct cmd_token ctkn_{node}[];\n") + ofd.write(f"static struct graph_node gn_{node}[];\n") + ofd.write("\n") + + vectors = [] + cmdels = set() + + ofd.write(f"static struct cmd_token ctkn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + vectors.append( + ( + list(i.idx for i in token.next()), + list(i.idx for i in token.prev()), + ) + ) - for name, items in sorted(nodes.items_named()): - for item in sorted(items.values(), key=lambda i: i.name): - ofd.write("\tinstall_element(%s, &%s_vtysh);\n" % (name, item.name)) + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t{'{'} /* [{i}] = {token.text} */ {'}'},\n") + cmdels.add(token.text) + continue + + ofd.write(f"\t{'{'} /* [{i}] */\n\t\t.type = {token.type},\n") + if token.attr: + ofd.write(f"\t\t.attr = {token.attr},\n") + if token.allowrepeat: + ofd.write(f"\t\t.allowrepeat = true,\n") + if token.varname_src: + ofd.write(f"\t\t.varname_src = {token.varname_src},\n") + if token.text: + ofd.write(f'\t\t.text = (char *)"{c_escape(token.text)}",\n') + if token.desc: + ofd.write(f'\t\t.desc = (char *)"{c_escape(token.desc)}",\n') + if token.min: + ofd.write(f"\t\t.min = {token.min},\n") + if token.max: + ofd.write(f"\t\t.max = {token.max},\n") + if token.varname: + ofd.write(f'\t\t.varname = (char *)"{c_escape(token.varname)}",\n') + + if token.type == "FORK_TKN": + fj = token.join() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + if token.type == "JOIN_TKN": + fj = token.fork() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + + ofd.write(f"\t{'}'},\n") + + ofd.write("};\n\n") + + if splitfile: + for cmdel in sorted(cmdels): + ofd.write(f"extern struct cmd_element {cmdel}_vtysh;\n") + ofd.write("\n") + + for i, next_prev in enumerate(vectors): + n, p = next_prev + items = ", ".join(f"&gn_{node}[{i}]" for i in n) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_next, {len(n)}, {items});\n") + items = ", ".join(f"&gn_{node}[{i}]" for i in p) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_prev, {len(p)}, {items});\n") + + ofd.write(f"\nstatic struct graph_node gn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + ofd.write("\t{\n") + ofd.write(f"\t\t.from = &gn_{node}_{i}_prev,\n") + ofd.write(f"\t\t.to = &gn_{node}_{i}_next,\n") + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t\t.data = (void *)&{token.text}_vtysh,\n") + else: + ofd.write(f"\t\t.data = &ctkn_{node}[{i}],\n") + ofd.write("\t},\n") + ofd.write("};\n") + + items = ", ".join(f"&gn_{node}[{i}]" for i in range(0, len(graph))) + ofd.write(f"MAKE_VECTOR(gvec_{node}, {len(graph)}, {items});\n") + + ofd.write( + f""" +{"extern " if splitfile else "static "}void install_{node}(void);\n +{"" if splitfile else "static "}void install_{node}(void)\n +{'{'} + unsigned node_id = {node}; + struct cmd_node *node; + + assert(node_id < vector_active(cmdvec)); + node = vector_slot(cmdvec, node_id); + assert(node); + assert(vector_active(node->cmdgraph->nodes) == 1); + graph_delete_node(node->cmdgraph, vector_slot(node->cmdgraph->nodes, 0)); + vector_free(node->cmdgraph->nodes); + node->cmdgraph->nodes = &gvec_{node}; +{'}'} +""" + ) - ofd.write("}\n") + return [node] @classmethod - def run(cls, xref, ofd): - ofd.write(vtysh_cmd_head) + def run(cls, xref, ofds): + for ofd in ofds: + ofd.write(vtysh_cmd_head) + + ofd = ofds.pop(0) NodeDict.load_nodenames() nodes = cls.load(xref) cls.output_defs(ofd) - cls.output_install(ofd, nodes) + + out_nodes = [] + for nodeid, cmds in nodes.items(): + node = nodes.nodename(nodeid) + + if ofds: + gfd, splitfile = ofds[nodeid % len(ofds)], True + else: + gfd, splitfile = ofd, False + + # install_element(VIEW_NODE, x) implies install_element(ENABLE_NODE, x) + # this needs to be handled here. + if node == "ENABLE_NODE": + nodeid_view = list( + k for k, v in nodes.nodenames.items() if v == "VIEW_NODE" + ) + assert len(nodeid_view) == 1 + cmds.update(nodes[nodeid_view[0]]) + + out_nodes.extend(cls.output_node_graph(gfd, node, cmds, splitfile)) + + out_nodes.sort() + + if ofds: + ofd.write("\n") + for name in out_nodes: + ofd.write(f"extern void install_{name}(void);\n") + + ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + + for name in out_nodes: + ofd.write(f"\tinstall_{name}();\n") + + ofd.write("}\n") def main(): diff --git a/python/xrelfo.py b/python/xrelfo.py index 07cd7407..5f7616f2 100644 --- a/python/xrelfo.py +++ b/python/xrelfo.py @@ -447,7 +447,9 @@ def main(): argp = argparse.ArgumentParser(description="FRR xref ELF extractor") argp.add_argument("-o", dest="output", type=str, help="write JSON output") argp.add_argument("--out-by-file", type=str, help="write by-file JSON output") - argp.add_argument("-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c") + argp.add_argument( + "-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c", nargs="*" + ) argp.add_argument("-Wlog-format", action="store_const", const=True) argp.add_argument("-Wlog-args", action="store_const", const=True) argp.add_argument("-Werror", action="store_const", const=True) @@ -528,9 +530,17 @@ def _main(args): os.rename(args.out_by_file + ".tmp", args.out_by_file) if args.vtysh_cmds: - with open(args.vtysh_cmds + ".tmp", "w") as fd: - CommandEntry.run(out, fd) - os.rename(args.vtysh_cmds + ".tmp", args.vtysh_cmds) + fds = [] + for filename in args.vtysh_cmds: + fds.append(open(filename + ".tmp", "w")) + + CommandEntry.run(out, fds) + + while fds: + fds.pop(0).close() + for filename in args.vtysh_cmds: + os.rename(filename + ".tmp", filename) + if args.Werror and CommandEntry.warn_counter: sys.exit(1) diff --git a/redhat/frr.logrotate b/redhat/frr.logrotate index 31061e3a..1224a332 100644 --- a/redhat/frr.logrotate +++ b/redhat/frr.logrotate @@ -78,6 +78,14 @@ endscript } +/var/log/frr/mgmtd.log { + notifempty + missingok + postrotate + /bin/kill -USR1 `cat /var/run/frr/mgmtd.pid 2> /dev/null` 2> /dev/null || true + endscript +} + /var/log/frr/nhrpd.log { notifempty missingok diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index e979b7f0..9286cb81 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -30,6 +30,7 @@ %{!?with_rtadv: %global with_rtadv 1 } %{!?with_watchfrr: %global with_watchfrr 1 } %{!?with_pathd: %global with_pathd 1 } +%{!?with_grpc: %global with_grpc 0 } # user and group %{!?frr_user: %global frr_user frr } @@ -201,6 +202,12 @@ BuildRequires: python3-devel BuildRequires: python3-sphinx %endif %endif +%if %{with_grpc} +BuildRequires: grpc-devel >= 1.16.1 +BuildRequires: protobuf-devel >= 3.6.1 +BuildRequires: protobuf-compiler >= 3.6.1 +BuildRequires: protobuf-c-devel +%endif %if 0%{?rhel} > 7 #platform-python-devel is needed for /usr/bin/pathfix.py BuildRequires: platform-python-devel @@ -301,6 +308,17 @@ through the AgentX protocol. Provides read-only access to current routing state through standard SNMP MIBs. +%if %{with_grpc} +%package grpc +Summary: GRPC support for FRR daemons +Group: System Environment/Daemons +License: GPLv3+ +Requires: %{name} = %{version}-%{release} + +%description grpc +Adds GRPC support to the individual FRR daemons. +%endif + %prep %setup -q -n frr-%{frrversion} @@ -424,6 +442,11 @@ routing state through standard SNMP MIBs. --enable-pathd \ %else --disable-pathd \ +%endif +%if %{with_grpc} + --enable-grpc \ +%else + --disable-grpc \ %endif --enable-snmp # end @@ -783,6 +806,12 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %{_libdir}/frr/modules/*snmp.so +%if %{with_grpc} +%files grpc +%{_libdir}/libfrrgrpc_pb.* +%{_libdir}/frr/modules/grpc.so +%endif + %files devel %{_libdir}/lib*.so %dir %{_includedir}/%{name} @@ -805,50 +834,20 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %changelog -* Wed Sep 11 2024 Martin Winter - %{version} - -* Wed Sep 11 2024 Donatas Abraitis - 10.1.1 -- bgpd -- Fix as-path exclude modify crash -- Fix labels static-analyser -- Fix, do not access peer->notify.data when it is null -- Fix crash at no rpki -- Fix memory type for static->prd_pretty -- Revert "topotests: add an ebgp 6vpe test" -- Revert "topotests: add bgp_nexthop_mp_ipv4_6 test" -- Revert "bgpd: optimize bgp_interface_address_del" -- Revert "bgpd: fix removing ipv6 global nexhop" -- Revert "bgpd: fix "used" json key on link-local nexthop" -- Revert "tests: ipv6 global removal in bgp_nexthop_mp_ipv4_6" -- Revert "bgpd: set ipv4-mapped ipv6 for ipv4 with ipv6 nexthop" -- Revert "bgpd: prefer link-local to a ipv4-mapped ipv6 global" -- Revert "topotests: update bgp_vrf_leaking_5549_routes" -- Revert "bgpd: optimize bgp_interface_address_add" -- Revert "bgpd: reduce bgp_interface_address_add indentation" -- Revert "bgpd: log new ipv6 global in bgp_interface_address_add" -- Revert "bgpd: fix sending ipv6 local nexthop if global present" -- isisd -- Fix crash when reading asla -- Add missing `exit` statement -- Fix update link params after circuit is up -- Fix crash at flex-algo without mpls-te -- Fix memory handling in isis_adj_process_threeway() -- nhrpd -- Fix show nhrp shortcut json -- Fix sending /32 shortcut -- pimd -- Fix crash in pimd -- mgmtd -- Don't add implicit state data when reading config from file -- lib -- Fix distribute-list deletion -- Fix crash on distribute-list delete -- Fix LYD_NEW_PATH_OUTPUT issue to support libyang v3.x -- ripd -- Fix show run output for distribute-list -- zebra -- Ensure non-equal id's are not same nhg's -- Mimic GNU basename() API for non-glibc library e.g. musl +* Tue Nov 12 2024 Jafar Al-Gharaibeh - %{version} + +* Tue Nov 12 2024 Jafar Al-Gharaibeh - 10.2 +- PIM candidate BSR/RP [#16438] +- Static IGMP join without an IGMP report [1#6450] +- PIM AutoRP discovery/announcements [#16634] +- IGMP proxy [#16861] +- SRv6 SID Manager [#15604] +- Add `bgp ipv6-auto-ra` command [#16354] +- Implement `neighbor x remote-as auto` for BGP [#16345] +- Implement `bgp dual-as` for BGP [#16816] +- Implement BGP-wide configuration for graceful restart [#16099] +- Handle kernel routes appropriately (should fix recent NOPREFIXROUTE issue) [#16300] +- Add `cisco-authentication` password support for NHRP [#16172] * Fri Jul 26 2024 Jafar Al-Gharaibeh - 10.1 - Breaking changes diff --git a/ripd/ripd.c b/ripd/ripd.c index ab4ffe5a..8768819f 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -3054,7 +3054,10 @@ DEFUN (show_ip_rip, } vty_out(vty, - "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface\n\n" diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index f4dadf37..0aa2a9e4 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -2070,7 +2070,10 @@ DEFUN (show_ipv6_ripng, /* Header of display. */ vty_out(vty, - "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface, (a/S) - aggregated/Suppressed\n\n" diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index f4ce1479..2e72a4b9 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -65,9 +65,18 @@ static void sharp_global_init(void) sg.srv6_locators = list_new(); } +static void sharp_srv6_locators_list_delete(void *item) +{ + struct sharp_srv6_locator *loc = item; + + list_delete(&loc->chunks); +} + static void sharp_global_destroy(void) { list_delete(&sg.nhs); + + sg.srv6_locators->del = sharp_srv6_locators_list_delete; list_delete(&sg.srv6_locators); } diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 21c596bf..c9211a15 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -82,7 +82,7 @@ DEFPY(watch_redistribute, watch_redistribute_cmd, } DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch [vrf NAME$vrf_name] [connected$connected]", + "sharp watch [vrf NAME$vrf_name] [connected$connected] [mrib$mrib]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" @@ -91,7 +91,8 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, "The v6 nexthop to signal for watching\n" "Watch for import check changes\n" "The v6 prefix to signal for watching\n" - "Should the route be connected\n") + "Should the route be connected\n" + "In the Multicast rib\n") { struct vrf *vrf; struct prefix p; @@ -119,14 +120,13 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, } sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, - true, !!connected); + sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, true, !!connected, !!mrib); return CMD_SUCCESS; } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch [vrf NAME$vrf_name] [connected$connected]", + "sharp watch [vrf NAME$vrf_name] [connected$connected] [mrib$mrib]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" @@ -135,7 +135,8 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, "The v4 address to signal for watching\n" "Watch for import check changes\n" "The v4 prefix for import check to watch\n" - "Should the route be connected\n") + "Should the route be connected\n" + "In the Multicast rib\n") { struct vrf *vrf; struct prefix p; @@ -164,8 +165,7 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, } sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, - true, !!connected); + sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, true, !!connected, !!mrib); return CMD_SUCCESS; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 133da918..4447b69b 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -247,12 +247,12 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, memcpy(&api.prefix, p, sizeof(*p)); api.flags = flags; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); /* Only send via ID if nhgroup has been successfully installed */ if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) { zapi_route_set_nhg_id(&api, &nhgid); } else { + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); for (ALL_NEXTHOPS_PTR(nhg, nh)) { /* Check if we set a VNI label */ if (nh->nh_label && @@ -618,18 +618,19 @@ void nhg_del(uint32_t id) zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg); } -void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, - bool watch, bool connected) +void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, bool watch, + bool connected, bool mrib) { - int command; + int command = ZEBRA_NEXTHOP_REGISTER; + safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST; command = ZEBRA_NEXTHOP_REGISTER; if (!watch) command = ZEBRA_NEXTHOP_UNREGISTER; - if (zclient_send_rnh(zclient, command, p, SAFI_UNICAST, connected, - false, vrf_id) == ZCLIENT_SEND_FAILURE) + if (zclient_send_rnh(zclient, command, p, safi, connected, false, vrf_id) == + ZCLIENT_SEND_FAILURE) zlog_warn("%s: Failure to send nexthop to zebra", __func__); } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 5cbcc146..7a86897b 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -18,8 +18,8 @@ extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); extern void nhg_add(uint32_t id, const struct nexthop_group *nhg, const struct nexthop_group *backup_nhg); extern void nhg_del(uint32_t id); -extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, - bool import, bool watch, bool connected); +extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, bool watch, + bool connected, bool mrib); extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t nhgid, diff --git a/snapcraft/scripts/bfdd-service b/snapcraft/scripts/bfdd-service index f94a7abb..5e41d1ae 100644 --- a/snapcraft/scripts/bfdd-service +++ b/snapcraft/scripts/bfdd-service @@ -9,6 +9,5 @@ exec $SNAP/sbin/bfdd \ -f $SNAP_DATA/bfdd.conf \ --pid_file $SNAP_DATA/bfdd.pid \ --socket $SNAP_DATA/zsock \ - --vty_socket $SNAP_DATA \ - --bfdctl $SNAP_DATA/bfdd.sock + --vty_socket $SNAP_DATA diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index d90236f7..eea9bfc0 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -249,7 +249,7 @@ apps: - network-bind - network-control bfdd-debug: - command: sbin/bfdd -f $SNAP_DATA/bfdd.conf --pid_file $SNAP_DATA/bfdd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA --bfdctl $SNAP_DATA/bfdd.sock + command: sbin/bfdd -f $SNAP_DATA/bfdd.conf --pid_file $SNAP_DATA/bfdd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA plugs: - network - network-bind diff --git a/staticd/static_debug.c b/staticd/static_debug.c index a65752c9..618ba91d 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 c9100680..b990f7bc 100644 --- a/staticd/static_debug.h +++ b/staticd/static_debug.h @@ -28,22 +28,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. * diff --git a/staticd/static_vty.c b/staticd/static_vty.c index a18028ed..07b8bc3d 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 5148e7e4..97845ec1 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 ebbe3ac3..00000000 --- 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 - -#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 582fd25c..00000000 --- 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 767c41cf..17002464 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -5,6 +5,7 @@ */ #include +#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 fdda7f1e..344af82f 100644 --- a/tests/helpers/c/main.c +++ b/tests/helpers/c/main.c @@ -6,6 +6,7 @@ #include #include +#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 195a7dd8..05e9f723 100644 Binary files a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz and b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz differ diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 4ea28cda..e5a8f7a5 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -55,7 +55,7 @@ static void test_run_spf(struct vty *vty, const struct isis_topology *topology, isis_run_spf(spftree); /* Print the SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, NULL); isis_print_routes(vty, spftree, NULL, false, false); /* Cleanup SPF tree. */ @@ -85,7 +85,7 @@ static void test_run_lfa(struct vty *vty, const struct isis_topology *topology, isis_lfa_compute(area, NULL, spftree_self, protected_resource); /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -148,7 +148,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, vty_out(vty, "\n"); /* Print the post-convergence SPT. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); /* * Activate the computed RLFAs (if any) using artificial LDP labels for @@ -164,7 +164,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, } /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -228,7 +228,7 @@ static void test_run_ti_lfa(struct vty *vty, /* * Print the post-convergence SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); isis_print_routes(vty, spftree_self, NULL, false, true); /* Cleanup everything. */ @@ -245,12 +245,25 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, struct isis_area *area; struct lfa_protected_resource protected_resource = {}; uint8_t fail_id[ISIS_SYS_ID_LEN] = {}; + static char sysidstr[ISO_SYSID_STRLEN]; + char net_title[255]; + uint8_t buff[255]; + struct iso_address *addr = NULL; /* Init topology. */ area = isis_area_create("1", NULL); memcpy(area->isis->sysid, root->sysid, sizeof(area->isis->sysid)); area->is_type = IS_LEVEL_1_AND_2; area->srdb.enabled = true; + area->area_addrs = list_new(); + area->area_addrs->del = isis_area_address_delete; + addr = XMALLOC(MTYPE_ISIS_AREA_ADDR, sizeof(struct iso_address)); + snprintfrr(sysidstr, sizeof(sysidstr), "%pSY", area->isis->sysid); + snprintf(net_title, sizeof(net_title), "49.%s.00", sysidstr); + addr->addr_len = dotformat2buff(buff, net_title); + memcpy(addr->area_addr, buff, addr->addr_len); + addr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN); + listnode_add(area->area_addrs, addr); if (test_topology_load(topology, area, area->lspdb) != 0) { vty_out(vty, "%% Failed to load topology\n"); return CMD_WARNING; @@ -533,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/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout index 23d41b9e..255d920c 100644 --- a/tests/isisd/test_isis_spf.refout +++ b/tests/isisd/test_isis_spf.refout @@ -1,20 +1,22 @@ test# test isis topology 1 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -29,21 +31,23 @@ IS-IS L1 IPv4 routing table: - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -59,22 +63,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) - rt5 - -10.0.255.3/32 IP TE 40 rt3 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt5 - rt6(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -89,22 +95,24 @@ IS-IS L1 IPv4 routing table: - rt5 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) - rt5 - -2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt5 - rt6(4) + 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -120,19 +128,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -147,23 +157,25 @@ IS-IS L1 IPv4 routing table: test# test isis topology 4 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -180,25 +192,27 @@ IS-IS L1 IPv4 routing table: test# test isis topology 5 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -216,33 +230,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 6 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -rt5 TE-IS 40 rt2 - rt6(4) - rt3 - -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - -rt7 TE-IS 50 rt2 - rt5(4) - rt3 - rt8(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) - rt3 - -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - -10.0.255.7/32 IP TE 60 rt2 - rt7(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + rt5 TE-IS 40 rt2 - rt6(4) + rt3 - rt6(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt3 - rt8(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + rt3 - rt5(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + rt3 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -264,34 +280,36 @@ IS-IS L1 IPv4 routing table: test# test isis topology 7 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt5(4) -rt6 TE-IS 30 rt4 - rt5(4) -rt8 TE-IS 30 rt4 - rt5(4) - rt7(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt10 TE-IS 40 rt4 - rt7(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt6(4) -rt9 TE-IS 40 rt4 - rt8(4) -rt11 TE-IS 40 rt4 - rt8(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) -10.0.255.6/32 IP TE 40 rt4 - rt6(4) -10.0.255.8/32 IP TE 40 rt4 - rt8(4) -rt12 TE-IS 50 rt4 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 50 rt4 - rt10(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) -10.0.255.9/32 IP TE 50 rt4 - rt9(4) -10.0.255.11/32 IP TE 50 rt4 - rt11(4) -10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 TE-IS 30 rt4 - rt5(4) + rt7(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt10 TE-IS 40 rt4 - rt7(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt6(4) + rt9 TE-IS 40 rt4 - rt8(4) + rt11 TE-IS 40 rt4 - rt8(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + 10.0.255.8/32 IP TE 40 rt4 - rt8(4) + rt12 TE-IS 50 rt4 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 50 rt4 - rt10(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + 10.0.255.9/32 IP TE 50 rt4 - rt9(4) + 10.0.255.11/32 IP TE 50 rt4 - rt11(4) + 10.0.255.12/32 IP TE 60 rt4 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -312,33 +330,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 8 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt3 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt2 - rt2(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt6 TE-IS 30 rt2 - rt3(4) - rt5(4) -rt8 TE-IS 30 rt2 - rt5(4) -rt10 TE-IS 30 rt4 - rt7(4) -10.0.255.3/32 IP TE 30 rt2 - rt3(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt9 TE-IS 40 rt2 - rt8(4) -rt11 TE-IS 40 rt2 - rt8(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) -10.0.255.10/32 IP TE 40 rt4 - rt10(4) -rt12 TE-IS 50 rt2 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.11/32 IP TE 50 rt2 - rt11(4) -10.0.255.12/32 IP TE 60 rt2 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt3 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt2 - rt2(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt6 TE-IS 30 rt2 - rt3(4) + rt5(4) + rt8 TE-IS 30 rt2 - rt5(4) + rt10 TE-IS 30 rt4 - rt7(4) + 10.0.255.3/32 IP TE 30 rt2 - rt3(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt9 TE-IS 40 rt2 - rt8(4) + rt11 TE-IS 40 rt2 - rt8(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + 10.0.255.10/32 IP TE 40 rt4 - rt10(4) + rt12 TE-IS 50 rt2 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.11/32 IP TE 50 rt2 - rt11(4) + 10.0.255.12/32 IP TE 60 rt2 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -359,28 +379,30 @@ IS-IS L1 IPv4 routing table: test# test isis topology 9 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.6/32 IP TE 60 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -10.0.255.8/32 IP TE 60 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.6/32 IP TE 60 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + 10.0.255.8/32 IP TE 60 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -397,28 +419,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 50 - rt2 16090 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) -2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) -2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) + 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) + 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -436,23 +460,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -rt8 TE-IS 30 rt2 - rt5(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.4/32 IP TE 30 rt4 - rt4(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt4 - rt7(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + rt8 TE-IS 30 rt2 - rt5(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.4/32 IP TE 30 rt4 - rt4(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt4 - rt7(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -468,23 +494,25 @@ IS-IS L1 IPv4 routing table: 10.0.255.8/32 40 - rt2 16080 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -rt8 TE-IS 30 rt2 - rt5(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) -2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + rt8 TE-IS 30 rt2 - rt5(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) + 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -501,22 +529,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -531,22 +561,24 @@ IS-IS L1 IPv4 routing table: - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -562,27 +594,29 @@ IS-IS L1 IPv6 routing table: test# test isis topology 12 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -rt9 TE-IS 40 rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt10 TE-IS 50 rt2 - rt8(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) -10.0.255.9/32 IP TE 50 rt3 - rt9(4) -10.0.255.10/32 IP TE 60 rt2 - rt10(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt9 TE-IS 40 rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt10 TE-IS 50 rt2 - rt8(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + 10.0.255.9/32 IP TE 50 rt3 - rt9(4) + 10.0.255.10/32 IP TE 60 rt2 - rt10(4) + IS-IS L1 IPv4 routing table: @@ -601,24 +635,26 @@ IS-IS L1 IPv4 routing table: test# test isis topology 13 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -636,23 +672,25 @@ IS-IS L1 IPv4 routing table: test# test# test isis topology 4 root rt1 reverse-spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -669,21 +707,23 @@ IS-IS L1 IPv4 routing table: test# test isis topology 11 root rt1 reverse-spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt4(4) - rt5(4) -10.0.255.4/32 IP TE 30 rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt4(4) + rt5(4) + 10.0.255.4/32 IP TE 30 rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -695,21 +735,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt4(4) - rt5(4) -2001:db8::4/128 IP6 internal 30 rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt4(4) + rt5(4) + 2001:db8::4/128 IP6 internal 30 rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -723,21 +765,23 @@ IS-IS L1 IPv6 routing table: test# test# test isis topology 1 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -756,21 +800,23 @@ Backup: IS-IS L1 IPv4 routing table: IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -790,21 +836,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt1 pseudonode-id 1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -826,21 +874,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 50 - rt2 implicit-null IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -2001:db8::4/128 IP6 internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt4 + 2001:db8::4/128 IP6 internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -863,21 +913,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -899,21 +951,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 30 - rt5 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -2001:db8::4/128 IP6 internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt4 + 2001:db8::4/128 IP6 internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -936,19 +990,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -973,10 +1029,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -986,19 +1044,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1020,10 +1080,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.3/32 30 - rt2 16030 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -1033,34 +1095,36 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt1 lfa system-id rt4 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt5(4) -rt6 TE-IS 30 rt4 - rt5(4) -rt8 TE-IS 30 rt4 - rt5(4) - rt7(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt10 TE-IS 40 rt4 - rt7(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt6(4) -rt9 TE-IS 40 rt4 - rt8(4) -rt11 TE-IS 40 rt4 - rt8(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) -10.0.255.6/32 IP TE 40 rt4 - rt6(4) -10.0.255.8/32 IP TE 40 rt4 - rt8(4) -rt12 TE-IS 50 rt4 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 50 rt4 - rt10(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) -10.0.255.9/32 IP TE 50 rt4 - rt9(4) -10.0.255.11/32 IP TE 50 rt4 - rt11(4) -10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 TE-IS 30 rt4 - rt5(4) + rt7(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt10 TE-IS 40 rt4 - rt7(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt6(4) + rt9 TE-IS 40 rt4 - rt8(4) + rt11 TE-IS 40 rt4 - rt8(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + 10.0.255.8/32 IP TE 40 rt4 - rt8(4) + rt12 TE-IS 50 rt4 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 50 rt4 - rt10(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + 10.0.255.9/32 IP TE 50 rt4 - rt9(4) + 10.0.255.11/32 IP TE 50 rt4 - rt11(4) + 10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Main: IS-IS L1 IPv4 routing table: @@ -1098,10 +1162,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 90 - rt2 16120 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 40 rt2 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 40 rt2 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -1111,40 +1177,42 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt7 lfa system-id rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt7 -10.0.255.7/32 IP internal 0 rt7(4) -rt4 TE-IS 10 rt4 - rt7(4) -rt8 TE-IS 10 rt8 - rt7(4) -rt10 TE-IS 20 rt10 - rt7(4) -rt1 TE-IS 20 rt4 - rt4(4) -rt5 TE-IS 20 rt4 - rt4(4) - rt8 - rt8(4) -rt9 TE-IS 20 rt8 - rt8(4) -rt11 TE-IS 20 rt8 - rt8(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -rt2 TE-IS 30 rt4 - rt5(4) - rt8 - -rt6 TE-IS 30 rt4 - rt5(4) - rt8 - -rt12 TE-IS 30 rt8 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 30 rt10 - rt10(4) -10.0.255.1/32 IP TE 30 rt4 - rt1(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) - rt8 - -10.0.255.9/32 IP TE 30 rt8 - rt9(4) -10.0.255.11/32 IP TE 30 rt8 - rt11(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt8 - rt6(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) - rt8 - -10.0.255.6/32 IP TE 40 rt4 - rt6(4) - rt8 - -10.0.255.12/32 IP TE 40 rt8 - rt12(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) - rt8 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt7 + 10.0.255.7/32 IP internal 0 rt7(4) + rt4 TE-IS 10 rt4 - rt7(4) + rt8 TE-IS 10 rt8 - rt7(4) + rt10 TE-IS 20 rt10 - rt7(4) + rt1 TE-IS 20 rt4 - rt4(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt8 - rt8(4) + rt9 TE-IS 20 rt8 - rt8(4) + rt11 TE-IS 20 rt8 - rt8(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt8 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 - rt5(4) + rt12 TE-IS 30 rt8 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 30 rt10 - rt10(4) + 10.0.255.1/32 IP TE 30 rt4 - rt1(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + rt8 - rt5(4) + 10.0.255.9/32 IP TE 30 rt8 - rt9(4) + 10.0.255.11/32 IP TE 30 rt8 - rt11(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt8 - rt6(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + rt8 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + rt8 - rt6(4) + 10.0.255.12/32 IP TE 40 rt8 - rt12(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + rt8 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -1179,11 +1247,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 50 - rt10 16120 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt7 -rt4 TE-IS 10 rt4 - rt7(4) -rt8 TE-IS 10 rt8 - rt7(4) -rt10 TE-IS 20 rt10 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt7 + rt4 TE-IS 10 rt4 - rt7(4) + rt8 TE-IS 10 rt8 - rt7(4) + rt10 TE-IS 20 rt10 - rt7(4) + Main: IS-IS L1 IPv6 routing table: @@ -1193,38 +1263,40 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt8 lfa system-id rt11 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt8 -10.0.255.8/32 IP internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt7 TE-IS 10 rt7 - rt8(4) -rt9 TE-IS 10 rt9 - rt8(4) -rt11 TE-IS 10 rt11 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -rt4 TE-IS 20 rt5 - rt5(4) - rt7 - rt7(4) -rt6 TE-IS 20 rt5 - rt5(4) -rt12 TE-IS 20 rt9 - rt9(4) - rt11 - rt11(4) -rt10 TE-IS 20 rt11 - rt11(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -10.0.255.9/32 IP TE 20 rt9 - rt9(4) -10.0.255.11/32 IP TE 20 rt11 - rt11(4) -rt3 TE-IS 30 rt5 - rt2(4) - rt6(4) -rt1 TE-IS 30 rt5 - rt4(4) - rt7 - -10.0.255.2/32 IP TE 30 rt5 - rt2(4) -10.0.255.4/32 IP TE 30 rt5 - rt4(4) - rt7 - -10.0.255.6/32 IP TE 30 rt5 - rt6(4) -10.0.255.12/32 IP TE 30 rt9 - rt12(4) - rt11 - -10.0.255.10/32 IP TE 30 rt11 - rt10(4) -10.0.255.3/32 IP TE 40 rt5 - rt3(4) -10.0.255.1/32 IP TE 40 rt5 - rt1(4) - rt7 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt8 + 10.0.255.8/32 IP internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt7 TE-IS 10 rt7 - rt8(4) + rt9 TE-IS 10 rt9 - rt8(4) + rt11 TE-IS 10 rt11 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + rt4 TE-IS 20 rt5 - rt5(4) + rt7 - rt7(4) + rt6 TE-IS 20 rt5 - rt5(4) + rt12 TE-IS 20 rt9 - rt9(4) + rt11 - rt11(4) + rt10 TE-IS 20 rt11 - rt11(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + 10.0.255.9/32 IP TE 20 rt9 - rt9(4) + 10.0.255.11/32 IP TE 20 rt11 - rt11(4) + rt3 TE-IS 30 rt5 - rt2(4) + rt6(4) + rt1 TE-IS 30 rt5 - rt4(4) + rt7 - rt4(4) + 10.0.255.2/32 IP TE 30 rt5 - rt2(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + rt7 - rt4(4) + 10.0.255.6/32 IP TE 30 rt5 - rt6(4) + 10.0.255.12/32 IP TE 30 rt9 - rt12(4) + rt11 - rt12(4) + 10.0.255.10/32 IP TE 30 rt11 - rt10(4) + 10.0.255.3/32 IP TE 40 rt5 - rt3(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + rt7 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -1255,12 +1327,14 @@ IS-IS L1 IPv4 routing table: 10.0.255.10/32 40 - rt7 16100 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt8 -rt5 TE-IS 10 rt5 - rt8(4) -rt7 TE-IS 10 rt7 - rt8(4) -rt9 TE-IS 10 rt9 - rt8(4) -rt11 TE-IS 10 rt11 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt8 + rt5 TE-IS 10 rt5 - rt8(4) + rt7 TE-IS 10 rt7 - rt8(4) + rt9 TE-IS 10 rt9 - rt8(4) + rt11 TE-IS 10 rt11 - rt8(4) + Main: IS-IS L1 IPv6 routing table: @@ -1270,28 +1344,30 @@ IS-IS L1 IPv6 routing table: test# test isis topology 9 root rt3 lfa system-id rt1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt3 -10.0.255.3/32 IP internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 20 rt1 - rt1(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -rt4 TE-IS 30 rt1 - rt2(4) -10.0.255.2/32 IP TE 30 rt1 - rt2(4) -rt5 TE-IS 40 rt1 - rt4(4) -10.0.255.4/32 IP TE 40 rt1 - rt4(4) -rt9 TE-IS 50 rt1 - rt5(4) -10.0.255.5/32 IP TE 50 rt1 - rt5(4) -rt6 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt7 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt8 TE-IS 60 rt1 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 60 rt1 - rt9(4) -10.0.255.6/32 IP TE 70 rt1 - rt6(4) -10.0.255.7/32 IP TE 70 rt1 - rt7(4) -10.0.255.8/32 IP TE 70 rt1 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt3 + 10.0.255.3/32 IP internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 20 rt1 - rt1(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + rt4 TE-IS 30 rt1 - rt2(4) + 10.0.255.2/32 IP TE 30 rt1 - rt2(4) + rt5 TE-IS 40 rt1 - rt4(4) + 10.0.255.4/32 IP TE 40 rt1 - rt4(4) + rt9 TE-IS 50 rt1 - rt5(4) + 10.0.255.5/32 IP TE 50 rt1 - rt5(4) + rt6 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt7 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt8 TE-IS 60 rt1 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 60 rt1 - rt9(4) + 10.0.255.6/32 IP TE 70 rt1 - rt6(4) + 10.0.255.7/32 IP TE 70 rt1 - rt7(4) + 10.0.255.8/32 IP TE 70 rt1 - rt8(4) + Main: IS-IS L1 IPv4 routing table: @@ -1323,28 +1399,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 130 - rt4 16090 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt3 -2001:db8::3/128 IP6 internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 20 rt1 - rt1(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -rt4 TE-IS 30 rt1 - rt2(4) -2001:db8::2/128 IP6 internal 30 rt1 - rt2(4) -rt5 TE-IS 40 rt1 - rt4(4) -2001:db8::4/128 IP6 internal 40 rt1 - rt4(4) -rt9 TE-IS 50 rt1 - rt5(4) -2001:db8::5/128 IP6 internal 50 rt1 - rt5(4) -rt6 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt7 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt8 TE-IS 60 rt1 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 60 rt1 - rt9(4) -2001:db8::6/128 IP6 internal 70 rt1 - rt6(4) -2001:db8::7/128 IP6 internal 70 rt1 - rt7(4) -2001:db8::8/128 IP6 internal 70 rt1 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt3 + 2001:db8::3/128 IP6 internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 20 rt1 - rt1(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + rt4 TE-IS 30 rt1 - rt2(4) + 2001:db8::2/128 IP6 internal 30 rt1 - rt2(4) + rt5 TE-IS 40 rt1 - rt4(4) + 2001:db8::4/128 IP6 internal 40 rt1 - rt4(4) + rt9 TE-IS 50 rt1 - rt5(4) + 2001:db8::5/128 IP6 internal 50 rt1 - rt5(4) + rt6 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt7 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt8 TE-IS 60 rt1 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 60 rt1 - rt9(4) + 2001:db8::6/128 IP6 internal 70 rt1 - rt6(4) + 2001:db8::7/128 IP6 internal 70 rt1 - rt7(4) + 2001:db8::8/128 IP6 internal 70 rt1 - rt8(4) + Main: IS-IS L1 IPv6 routing table: @@ -1377,23 +1455,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt8 lfa system-id rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt8 -10.0.255.8/32 IP internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt1 TE-IS 30 rt5 - rt2(4) -10.0.255.2/32 IP TE 30 rt5 - rt2(4) -10.0.255.1/32 IP TE 40 rt5 - rt1(4) -rt6 TE-IS 50 rt6 - rt8(4) -rt7 TE-IS 50 rt7 - rt8(4) -rt3 TE-IS 50 rt5 - rt1(4) -rt4 TE-IS 50 rt5 - rt1(4) -10.0.255.6/32 IP TE 60 rt6 - rt6(4) -10.0.255.7/32 IP TE 60 rt7 - rt7(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) -10.0.255.4/32 IP TE 60 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt8 + 10.0.255.8/32 IP internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt1 TE-IS 30 rt5 - rt2(4) + 10.0.255.2/32 IP TE 30 rt5 - rt2(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + rt6 TE-IS 50 rt6 - rt8(4) + rt7 TE-IS 50 rt7 - rt8(4) + rt3 TE-IS 50 rt5 - rt1(4) + rt4 TE-IS 50 rt5 - rt1(4) + 10.0.255.6/32 IP TE 60 rt6 - rt6(4) + 10.0.255.7/32 IP TE 60 rt7 - rt7(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + 10.0.255.4/32 IP TE 60 rt5 - rt4(4) + Main: IS-IS L1 IPv4 routing table: @@ -1426,23 +1506,25 @@ IS-IS L1 IPv4 routing table: - rt7 16050 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt8 -2001:db8::8/128 IP6 internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -rt1 TE-IS 30 rt5 - rt2(4) -2001:db8::2/128 IP6 internal 30 rt5 - rt2(4) -2001:db8::1/128 IP6 internal 40 rt5 - rt1(4) -rt6 TE-IS 50 rt6 - rt8(4) -rt7 TE-IS 50 rt7 - rt8(4) -rt3 TE-IS 50 rt5 - rt1(4) -rt4 TE-IS 50 rt5 - rt1(4) -2001:db8::6/128 IP6 internal 60 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt7 - rt7(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) -2001:db8::4/128 IP6 internal 60 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt8 + 2001:db8::8/128 IP6 internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + rt1 TE-IS 30 rt5 - rt2(4) + 2001:db8::2/128 IP6 internal 30 rt5 - rt2(4) + 2001:db8::1/128 IP6 internal 40 rt5 - rt1(4) + rt6 TE-IS 50 rt6 - rt8(4) + rt7 TE-IS 50 rt7 - rt8(4) + rt3 TE-IS 50 rt5 - rt1(4) + rt4 TE-IS 50 rt5 - rt1(4) + 2001:db8::6/128 IP6 internal 60 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt7 - rt7(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + 2001:db8::4/128 IP6 internal 60 rt5 - rt4(4) + Main: IS-IS L1 IPv6 routing table: @@ -1476,22 +1558,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt3 lfa system-id rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt3 -10.0.255.3/32 IP internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 10 rt2 - rt3(4) -rt5 TE-IS 10 rt5 - rt3(4) -rt2 pseudo_TE-IS 20 rt1 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt5 - rt5(4) -rt6 TE-IS 20 rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt5 - -10.0.255.6/32 IP TE 30 rt5 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt3 + 10.0.255.3/32 IP internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 10 rt2 - rt3(4) + rt5 TE-IS 10 rt5 - rt3(4) + rt2 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 - rt5(4) + rt6 TE-IS 20 rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 - rt4(4) + 10.0.255.6/32 IP TE 30 rt5 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1515,22 +1599,24 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt2 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt3 -2001:db8::3/128 IP6 internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 10 rt2 - rt3(4) -rt5 TE-IS 10 rt5 - rt3(4) -rt2 pseudo_TE-IS 20 rt1 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt5 - rt5(4) -rt6 TE-IS 20 rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) - rt5 - -2001:db8::6/128 IP6 internal 30 rt5 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt3 + 2001:db8::3/128 IP6 internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 10 rt2 - rt3(4) + rt5 TE-IS 10 rt5 - rt3(4) + rt2 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 - rt5(4) + rt6 TE-IS 20 rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt5 - rt4(4) + 2001:db8::6/128 IP6 internal 30 rt5 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -1555,24 +1641,26 @@ IS-IS L1 IPv6 routing table: test# test isis topology 13 root rt4 lfa system-id rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt3 - rt1(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -1599,11 +1687,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.7/32 120 - rt5 16070 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt5 TE-IS 100 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt4 + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt5 TE-IS 100 rt5 - rt4(4) + Main: IS-IS L1 IPv6 routing table: @@ -1613,18 +1703,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Main: IS-IS L1 IPv4 routing table: @@ -1641,18 +1733,20 @@ Backup: IS-IS L1 IPv4 routing table: IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Main: IS-IS L1 IPv6 routing table: @@ -1670,18 +1764,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Main: IS-IS L1 IPv4 routing table: @@ -1702,18 +1798,20 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 30 - rt3 - IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Main: IS-IS L1 IPv6 routing table: @@ -1735,19 +1833,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt5 lfa system-id rt4 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt1 pseudo_TE-IS 20 rt4 - rt4(4) -rt1 TE-IS 20 rt4 - rt1(2) -rt3 TE-IS 20 rt4 - rt1(2) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt1(4) - rt3(4) -10.0.255.1/32 IP TE 30 rt4 - rt1(4) -10.0.255.3/32 IP TE 30 rt4 - rt3(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt1 pseudo_TE-IS 20 rt4 - rt4(4) + rt1 TE-IS 20 rt4 - rt1(2) + rt3 TE-IS 20 rt4 - rt1(2) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt1(4) + rt3(4) + 10.0.255.1/32 IP TE 30 rt4 - rt1(4) + 10.0.255.3/32 IP TE 30 rt4 - rt3(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + Main: IS-IS L1 IPv4 routing table: @@ -1771,19 +1871,21 @@ IS-IS L1 IPv4 routing table: 10.0.255.4/32 70 - rt3 - IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt1 pseudo_TE-IS 20 rt4 - rt4(4) -rt1 TE-IS 20 rt4 - rt1(2) -rt3 TE-IS 20 rt4 - rt1(2) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt1(4) - rt3(4) -2001:db8::1/128 IP6 internal 30 rt4 - rt1(4) -2001:db8::3/128 IP6 internal 30 rt4 - rt3(4) -2001:db8::2/128 IP6 internal 40 rt4 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt1 pseudo_TE-IS 20 rt4 - rt4(4) + rt1 TE-IS 20 rt4 - rt1(2) + rt3 TE-IS 20 rt4 - rt1(2) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt1(4) + rt3(4) + 2001:db8::1/128 IP6 internal 30 rt4 - rt1(4) + 2001:db8::3/128 IP6 internal 30 rt4 - rt3(4) + 2001:db8::2/128 IP6 internal 40 rt4 - rt2(4) + Main: IS-IS L1 IPv6 routing table: @@ -1823,36 +1925,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -10.0.255.2/32 IP TE 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + 10.0.255.2/32 IP TE 60 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1890,36 +1996,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) -2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) + 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -1964,39 +2074,43 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -10.0.255.1/32 IP TE 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) -10.0.255.2/32 IP TE 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 10.0.255.1/32 IP TE 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + 10.0.255.2/32 IP TE 55 rt6 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt1 TE-IS 10 rt1 - rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt4 - rt4(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt3 - rt5(4) - rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) - rt1 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt1 TE-IS 10 rt1 - rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 - rt4(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt3 - rt5(4) + rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -2041,39 +2155,43 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt1 TE-IS 10 rt1 - rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt4 - rt4(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt3 - rt5(4) - rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) - rt1 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt1 TE-IS 10 rt1 - rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 - rt4(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt3 - rt5(4) + rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -2123,38 +2241,42 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) -rt2 TE-IS 30 rt6 - rt4(4) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt1 TE-IS 40 rt3 - rt3(4) - rt6 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -10.0.255.2/32 IP TE 40 rt6 - rt2(4) -10.0.255.1/32 IP TE 50 rt3 - rt1(4) - rt6 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt2 TE-IS 30 rt6 - rt4(4) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt1 TE-IS 40 rt3 - rt3(4) + rt6 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + 10.0.255.2/32 IP TE 40 rt6 - rt2(4) + 10.0.255.1/32 IP TE 50 rt3 - rt1(4) + rt6 - rt1(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) - rt4 - rt2(4) -rt1 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) - rt4 - -10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt4 - rt2(4) + rt1 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 - rt3(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2210,36 +2332,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 TE-IS 30 rt4 - rt2(4) -rt3 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.1/32 IP TE 40 rt4 - rt1(4) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 TE-IS 30 rt4 - rt2(4) + rt3 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) - rt4 - rt2(4) -rt1 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) - rt4 - -10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt4 - rt2(4) + rt1 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 - rt3(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2276,44 +2402,48 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt3 - rt7(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 50 rt3 - rt8(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt4 TE-IS 60 rt3 - rt6(4) -10.0.255.6/32 IP TE 60 rt3 - rt6(4) -rt2 TE-IS 70 rt3 - rt4(4) -10.0.255.4/32 IP TE 70 rt3 - rt4(4) -10.0.255.2/32 IP TE 80 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt3 - rt7(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 50 rt3 - rt8(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt4 TE-IS 60 rt3 - rt6(4) + 10.0.255.6/32 IP TE 60 rt3 - rt6(4) + rt2 TE-IS 70 rt3 - rt4(4) + 10.0.255.4/32 IP TE 70 rt3 - rt4(4) + 10.0.255.2/32 IP TE 80 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + Main: IS-IS L1 IPv4 routing table: @@ -2362,46 +2492,50 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt2 - rt1(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt2 - rt1(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) - rt3 - -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt3 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -2452,64 +2586,68 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt9 TE-IS 20 rt12 - rt12(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt7 TE-IS 30 rt10 - rt10(4) -rt8 TE-IS 30 rt12 - rt9(4) -10.0.255.9/32 IP TE 30 rt12 - rt9(4) -rt4 TE-IS 40 rt10 - rt7(4) -rt5 TE-IS 40 rt12 - rt8(4) -10.0.255.7/32 IP TE 40 rt10 - rt7(4) -10.0.255.8/32 IP TE 40 rt12 - rt8(4) -rt6 TE-IS 50 rt12 - rt9(4) - rt5(4) -rt1 TE-IS 50 rt10 - rt4(4) -rt2 TE-IS 50 rt12 - rt5(4) -10.0.255.4/32 IP TE 50 rt10 - rt4(4) -10.0.255.5/32 IP TE 50 rt12 - rt5(4) -rt3 TE-IS 60 rt12 - rt6(4) - rt2(4) -10.0.255.6/32 IP TE 60 rt12 - rt6(4) -10.0.255.1/32 IP TE 60 rt10 - rt1(4) -10.0.255.2/32 IP TE 60 rt12 - rt2(4) -10.0.255.3/32 IP TE 70 rt12 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt9 TE-IS 20 rt12 - rt12(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt7 TE-IS 30 rt10 - rt10(4) + rt8 TE-IS 30 rt12 - rt9(4) + 10.0.255.9/32 IP TE 30 rt12 - rt9(4) + rt4 TE-IS 40 rt10 - rt7(4) + rt5 TE-IS 40 rt12 - rt8(4) + 10.0.255.7/32 IP TE 40 rt10 - rt7(4) + 10.0.255.8/32 IP TE 40 rt12 - rt8(4) + rt6 TE-IS 50 rt12 - rt9(4) + rt5(4) + rt1 TE-IS 50 rt10 - rt4(4) + rt2 TE-IS 50 rt12 - rt5(4) + 10.0.255.4/32 IP TE 50 rt10 - rt4(4) + 10.0.255.5/32 IP TE 50 rt12 - rt5(4) + rt3 TE-IS 60 rt12 - rt6(4) + rt2(4) + 10.0.255.6/32 IP TE 60 rt12 - rt6(4) + 10.0.255.1/32 IP TE 60 rt10 - rt1(4) + 10.0.255.2/32 IP TE 60 rt12 - rt2(4) + 10.0.255.3/32 IP TE 70 rt12 - rt3(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt8 TE-IS 10 rt8 - rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt5 TE-IS 20 rt8 - rt8(4) -rt7 TE-IS 20 rt8 - rt8(4) -rt9 TE-IS 20 rt8 - rt8(4) - rt12 - rt12(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt2 TE-IS 30 rt8 - rt5(4) -rt4 TE-IS 30 rt8 - rt5(4) - rt7(4) -rt6 TE-IS 30 rt8 - rt5(4) -10.0.255.5/32 IP TE 30 rt8 - rt5(4) -10.0.255.7/32 IP TE 30 rt8 - rt7(4) -10.0.255.9/32 IP TE 30 rt8 - rt9(4) - rt12 - -rt3 TE-IS 40 rt8 - rt2(4) - rt6(4) -rt1 TE-IS 40 rt8 - rt4(4) -10.0.255.2/32 IP TE 40 rt8 - rt2(4) -10.0.255.4/32 IP TE 40 rt8 - rt4(4) -10.0.255.6/32 IP TE 40 rt8 - rt6(4) -10.0.255.3/32 IP TE 50 rt8 - rt3(4) -10.0.255.1/32 IP TE 50 rt8 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt8 TE-IS 10 rt8 - rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt5 TE-IS 20 rt8 - rt8(4) + rt7 TE-IS 20 rt8 - rt8(4) + rt9 TE-IS 20 rt8 - rt8(4) + rt12 - rt12(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt2 TE-IS 30 rt8 - rt5(4) + rt4 TE-IS 30 rt8 - rt5(4) + rt7(4) + rt6 TE-IS 30 rt8 - rt5(4) + 10.0.255.5/32 IP TE 30 rt8 - rt5(4) + 10.0.255.7/32 IP TE 30 rt8 - rt7(4) + 10.0.255.9/32 IP TE 30 rt8 - rt9(4) + rt12 - rt9(4) + rt3 TE-IS 40 rt8 - rt2(4) + rt6(4) + rt1 TE-IS 40 rt8 - rt4(4) + 10.0.255.2/32 IP TE 40 rt8 - rt2(4) + 10.0.255.4/32 IP TE 40 rt8 - rt4(4) + 10.0.255.6/32 IP TE 40 rt8 - rt6(4) + 10.0.255.3/32 IP TE 50 rt8 - rt3(4) + 10.0.255.1/32 IP TE 50 rt8 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2577,73 +2715,77 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt9 TE-IS 30 rt9 - rt6(4) -rt5 TE-IS 30 rt3 - rt2(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) -rt8 TE-IS 40 rt9 - rt9(4) - rt3 - rt5(4) -rt12 TE-IS 40 rt9 - rt9(4) -rt4 TE-IS 40 rt3 - rt5(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt7 TE-IS 50 rt9 - rt8(4) - rt3 - rt4(4) -rt11 TE-IS 50 rt9 - rt8(4) - rt3 - rt12(4) -rt1 TE-IS 50 rt3 - rt4(4) -10.0.255.8/32 IP TE 50 rt9 - rt8(4) - rt3 - -10.0.255.12/32 IP TE 50 rt9 - rt12(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -rt10 TE-IS 60 rt9 - rt11(4) - rt3 - -10.0.255.7/32 IP TE 60 rt9 - rt7(4) - rt3 - -10.0.255.11/32 IP TE 60 rt9 - rt11(4) - rt3 - -10.0.255.1/32 IP TE 60 rt3 - rt1(4) -10.0.255.10/32 IP TE 70 rt9 - rt10(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 TE-IS 30 rt3 - rt2(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt8 TE-IS 40 rt9 - rt9(4) + rt3 - rt5(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt4 TE-IS 40 rt3 - rt5(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt7 TE-IS 50 rt9 - rt8(4) + rt3 - rt4(4) + rt11 TE-IS 50 rt9 - rt8(4) + rt3 - rt12(4) + rt1 TE-IS 50 rt3 - rt4(4) + 10.0.255.8/32 IP TE 50 rt9 - rt8(4) + rt3 - rt8(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + rt10 TE-IS 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.7/32 IP TE 60 rt9 - rt7(4) + rt3 - rt7(4) + 10.0.255.11/32 IP TE 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.1/32 IP TE 60 rt3 - rt1(4) + 10.0.255.10/32 IP TE 70 rt9 - rt10(4) + rt3 - rt10(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt5 TE-IS 10 rt5 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt4 TE-IS 20 rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt9 TE-IS 30 rt9 - rt6(4) - rt5 - rt8(4) -rt1 TE-IS 30 rt5 - rt4(4) -rt7 TE-IS 30 rt5 - rt4(4) - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) - rt5 - -10.0.255.4/32 IP TE 30 rt5 - rt4(4) -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt12 TE-IS 40 rt9 - rt9(4) - rt5 - rt11(4) -rt10 TE-IS 40 rt5 - rt11(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) - rt5 - -10.0.255.1/32 IP TE 40 rt5 - rt1(4) -10.0.255.7/32 IP TE 40 rt5 - rt7(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.12/32 IP TE 50 rt9 - rt12(4) - rt5 - -10.0.255.10/32 IP TE 50 rt5 - rt10(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt5 TE-IS 10 rt5 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt4 TE-IS 20 rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 - rt8(4) + rt1 TE-IS 30 rt5 - rt4(4) + rt7 TE-IS 30 rt5 - rt4(4) + rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt5 - rt2(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt5 - rt11(4) + rt10 TE-IS 40 rt5 - rt11(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + rt5 - rt9(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + 10.0.255.7/32 IP TE 40 rt5 - rt7(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + rt5 - rt12(4) + 10.0.255.10/32 IP TE 50 rt5 - rt10(4) + Main: IS-IS L1 IPv4 routing table: @@ -2706,62 +2848,66 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt5 TE-IS 30 rt3 - rt6(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt8 TE-IS 40 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt9 TE-IS 50 rt3 - rt8(4) -rt11 TE-IS 50 rt3 - rt8(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt12 TE-IS 60 rt3 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 60 rt3 - rt9(4) -10.0.255.11/32 IP TE 60 rt3 - rt11(4) -10.0.255.12/32 IP TE 70 rt3 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt5 TE-IS 30 rt3 - rt6(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt8 TE-IS 40 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt9 TE-IS 50 rt3 - rt8(4) + rt11 TE-IS 50 rt3 - rt8(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt12 TE-IS 60 rt3 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 60 rt3 - rt9(4) + 10.0.255.11/32 IP TE 60 rt3 - rt11(4) + 10.0.255.12/32 IP TE 70 rt3 - rt12(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt5 TE-IS 10 rt5 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt9 TE-IS 30 rt5 - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) - rt5 - -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt12 TE-IS 40 rt5 - rt9(4) - rt11(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.9/32 IP TE 40 rt5 - rt9(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.12/32 IP TE 50 rt5 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt5 TE-IS 10 rt5 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt9 TE-IS 30 rt5 - rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt5 - rt6(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt12 TE-IS 40 rt5 - rt9(4) + rt11(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.9/32 IP TE 40 rt5 - rt9(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.12/32 IP TE 50 rt5 - rt12(4) + Main: IS-IS L1 IPv4 routing table: @@ -2815,36 +2961,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -10.0.255.1/32 IP TE 60 rt1 - rt1(4) -10.0.255.3/32 IP TE 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -10.0.255.5/32 IP TE 70 rt3 - rt5(4) -10.0.255.4/32 IP TE 80 rt3 - rt4(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 10.0.255.1/32 IP TE 60 rt1 - rt1(4) + 10.0.255.3/32 IP TE 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 10.0.255.5/32 IP TE 70 rt3 - rt5(4) + 10.0.255.4/32 IP TE 80 rt3 - rt4(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt4 TE-IS 10 rt4 - rt2(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt6 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt3 TE-IS 30 rt4 - rt5(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) -rt2 -rt1 TE-IS 40 rt4 - rt2(2) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) -10.0.255.1/32 IP TE 50 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt4 TE-IS 10 rt4 - rt2(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt6 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt3 TE-IS 30 rt4 - rt5(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt2 + rt1 TE-IS 40 rt4 - rt2(2) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + 10.0.255.1/32 IP TE 50 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2893,36 +3043,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) -2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) -2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) + 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt4 TE-IS 10 rt4 - rt2(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt6 TE-IS 20 rt4 - rt4(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -rt3 TE-IS 30 rt4 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) -rt2 -rt1 TE-IS 40 rt4 - rt2(2) -2001:db8::3/128 IP6 internal 40 rt4 - rt3(4) -2001:db8::1/128 IP6 internal 50 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt4 TE-IS 10 rt4 - rt2(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt6 TE-IS 20 rt4 - rt4(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + rt3 TE-IS 30 rt4 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt2 + rt1 TE-IS 40 rt4 - rt2(2) + 2001:db8::3/128 IP6 internal 40 rt4 - rt3(4) + 2001:db8::1/128 IP6 internal 50 rt4 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -2966,42 +3120,46 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt5 TE-IS 40 rt2 - rt3(4) -rt6 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) - rt6(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.6/32 IP TE 50 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 TE-IS 40 rt2 - rt3(4) + rt6 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt6(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.6/32 IP TE 50 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -3044,19 +3202,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -10.0.255.2/32 IP TE 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + 10.0.255.2/32 IP TE 60 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3080,19 +3240,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) -2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) + 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -3127,22 +3289,24 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) - rt5 - -rt3 TE-IS 50 rt5 - rt5(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt5 - rt6(4) + rt3 TE-IS 50 rt5 - rt5(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3175,22 +3339,24 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) - rt5 - -rt3 TE-IS 50 rt5 - rt5(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt5 - rt6(4) + rt3 TE-IS 50 rt5 - rt5(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -3217,20 +3383,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -rt4 TE-IS 55 rt2 - rt2(4) -rt1 -rt6 TE-IS 65 rt2 - rt4(4) -rt5 TE-IS 65 rt2 - rt1(2) -10.0.255.4/32 IP TE 65 rt2 - rt4(4) -10.0.255.6/32 IP TE 75 rt2 - rt6(4) -10.0.255.5/32 IP TE 75 rt2 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 TE-IS 55 rt2 - rt2(4) + rt1 + rt6 TE-IS 65 rt2 - rt4(4) + rt5 TE-IS 65 rt2 - rt1(2) + 10.0.255.4/32 IP TE 65 rt2 - rt4(4) + 10.0.255.6/32 IP TE 75 rt2 - rt6(4) + 10.0.255.5/32 IP TE 75 rt2 - rt5(4) + IS-IS L1 IPv4 routing table: @@ -3258,20 +3426,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) -rt4 TE-IS 55 rt2 - rt2(4) -rt1 -rt6 TE-IS 65 rt2 - rt4(4) -rt5 TE-IS 65 rt2 - rt1(2) -2001:db8::4/128 IP6 internal 65 rt2 - rt4(4) -2001:db8::6/128 IP6 internal 75 rt2 - rt6(4) -2001:db8::5/128 IP6 internal 75 rt2 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + rt4 TE-IS 55 rt2 - rt2(4) + rt1 + rt6 TE-IS 65 rt2 - rt4(4) + rt5 TE-IS 65 rt2 - rt1(2) + 2001:db8::4/128 IP6 internal 65 rt2 - rt4(4) + 2001:db8::6/128 IP6 internal 75 rt2 - rt6(4) + 2001:db8::5/128 IP6 internal 75 rt2 - rt5(4) + IS-IS L1 IPv6 routing table: @@ -3303,20 +3473,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -10.0.255.1/32 IP TE 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) -10.0.255.2/32 IP TE 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 10.0.255.1/32 IP TE 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + 10.0.255.2/32 IP TE 55 rt6 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3347,20 +3519,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -3396,21 +3570,23 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) -rt2 TE-IS 30 rt6 - rt4(4) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt1 TE-IS 40 rt3 - rt3(4) - rt6 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -10.0.255.2/32 IP TE 40 rt6 - rt2(4) -10.0.255.1/32 IP TE 50 rt3 - rt1(4) - rt6 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt2 TE-IS 30 rt6 - rt4(4) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt1 TE-IS 40 rt3 - rt3(4) + rt6 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + 10.0.255.2/32 IP TE 40 rt6 - rt2(4) + 10.0.255.1/32 IP TE 50 rt3 - rt1(4) + rt6 - rt1(4) + IS-IS L1 IPv4 routing table: @@ -3450,19 +3626,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 TE-IS 30 rt4 - rt2(4) -rt3 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.1/32 IP TE 40 rt4 - rt1(4) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 TE-IS 30 rt4 - rt2(4) + rt3 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3484,23 +3662,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 70 rt3 - rt5(4) -rt4 TE-IS 80 rt3 - rt6(4) -rt8 TE-IS 80 rt3 - rt6(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) -rt2 TE-IS 90 rt3 - rt4(4) -10.0.255.4/32 IP TE 90 rt3 - rt4(4) -10.0.255.8/32 IP TE 90 rt3 - rt8(4) -10.0.255.2/32 IP TE 100 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 70 rt3 - rt5(4) + rt4 TE-IS 80 rt3 - rt6(4) + rt8 TE-IS 80 rt3 - rt6(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + rt2 TE-IS 90 rt3 - rt4(4) + 10.0.255.4/32 IP TE 90 rt3 - rt4(4) + 10.0.255.8/32 IP TE 90 rt3 - rt8(4) + 10.0.255.2/32 IP TE 100 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3531,23 +3711,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt1(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -rt5 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -rt6 TE-IS 90 rt2 - rt5(4) -rt8 TE-IS 100 rt2 - rt6(4) -10.0.255.6/32 IP TE 100 rt2 - rt6(4) -10.0.255.8/32 IP TE 110 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt1(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt5 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + rt6 TE-IS 90 rt2 - rt5(4) + rt8 TE-IS 100 rt2 - rt6(4) + 10.0.255.6/32 IP TE 100 rt2 - rt6(4) + 10.0.255.8/32 IP TE 110 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -3575,23 +3757,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt3 - rt7(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 50 rt3 - rt8(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt4 TE-IS 60 rt3 - rt6(4) -10.0.255.6/32 IP TE 60 rt3 - rt6(4) -rt2 TE-IS 70 rt3 - rt4(4) -10.0.255.4/32 IP TE 70 rt3 - rt4(4) -10.0.255.2/32 IP TE 80 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt3 - rt7(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 50 rt3 - rt8(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt4 TE-IS 60 rt3 - rt6(4) + 10.0.255.6/32 IP TE 60 rt3 - rt6(4) + rt2 TE-IS 70 rt3 - rt4(4) + 10.0.255.4/32 IP TE 70 rt3 - rt4(4) + 10.0.255.2/32 IP TE 80 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3624,24 +3808,26 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt2 - rt1(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt2 - rt1(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -3676,33 +3862,35 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt9 TE-IS 20 rt12 - rt12(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt7 TE-IS 30 rt10 - rt10(4) -rt8 TE-IS 30 rt12 - rt9(4) -10.0.255.9/32 IP TE 30 rt12 - rt9(4) -rt4 TE-IS 40 rt10 - rt7(4) -rt5 TE-IS 40 rt12 - rt8(4) -10.0.255.7/32 IP TE 40 rt10 - rt7(4) -10.0.255.8/32 IP TE 40 rt12 - rt8(4) -rt6 TE-IS 50 rt12 - rt9(4) - rt5(4) -rt1 TE-IS 50 rt10 - rt4(4) -rt2 TE-IS 50 rt12 - rt5(4) -10.0.255.4/32 IP TE 50 rt10 - rt4(4) -10.0.255.5/32 IP TE 50 rt12 - rt5(4) -rt3 TE-IS 60 rt12 - rt6(4) - rt2(4) -10.0.255.6/32 IP TE 60 rt12 - rt6(4) -10.0.255.1/32 IP TE 60 rt10 - rt1(4) -10.0.255.2/32 IP TE 60 rt12 - rt2(4) -10.0.255.3/32 IP TE 70 rt12 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt9 TE-IS 20 rt12 - rt12(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt7 TE-IS 30 rt10 - rt10(4) + rt8 TE-IS 30 rt12 - rt9(4) + 10.0.255.9/32 IP TE 30 rt12 - rt9(4) + rt4 TE-IS 40 rt10 - rt7(4) + rt5 TE-IS 40 rt12 - rt8(4) + 10.0.255.7/32 IP TE 40 rt10 - rt7(4) + 10.0.255.8/32 IP TE 40 rt12 - rt8(4) + rt6 TE-IS 50 rt12 - rt9(4) + rt5(4) + rt1 TE-IS 50 rt10 - rt4(4) + rt2 TE-IS 50 rt12 - rt5(4) + 10.0.255.4/32 IP TE 50 rt10 - rt4(4) + 10.0.255.5/32 IP TE 50 rt12 - rt5(4) + rt3 TE-IS 60 rt12 - rt6(4) + rt2(4) + 10.0.255.6/32 IP TE 60 rt12 - rt6(4) + 10.0.255.1/32 IP TE 60 rt10 - rt1(4) + 10.0.255.2/32 IP TE 60 rt12 - rt2(4) + 10.0.255.3/32 IP TE 70 rt12 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3750,39 +3938,41 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt9 TE-IS 30 rt9 - rt6(4) -rt5 TE-IS 30 rt3 - rt2(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) -rt8 TE-IS 40 rt9 - rt9(4) - rt3 - rt5(4) -rt12 TE-IS 40 rt9 - rt9(4) -rt4 TE-IS 40 rt3 - rt5(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt7 TE-IS 50 rt9 - rt8(4) - rt3 - rt4(4) -rt11 TE-IS 50 rt9 - rt8(4) - rt3 - rt12(4) -rt1 TE-IS 50 rt3 - rt4(4) -10.0.255.8/32 IP TE 50 rt9 - rt8(4) - rt3 - -10.0.255.12/32 IP TE 50 rt9 - rt12(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -rt10 TE-IS 60 rt9 - rt11(4) - rt3 - -10.0.255.7/32 IP TE 60 rt9 - rt7(4) - rt3 - -10.0.255.11/32 IP TE 60 rt9 - rt11(4) - rt3 - -10.0.255.1/32 IP TE 60 rt3 - rt1(4) -10.0.255.10/32 IP TE 70 rt9 - rt10(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 TE-IS 30 rt3 - rt2(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt8 TE-IS 40 rt9 - rt9(4) + rt3 - rt5(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt4 TE-IS 40 rt3 - rt5(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt7 TE-IS 50 rt9 - rt8(4) + rt3 - rt4(4) + rt11 TE-IS 50 rt9 - rt8(4) + rt3 - rt12(4) + rt1 TE-IS 50 rt3 - rt4(4) + 10.0.255.8/32 IP TE 50 rt9 - rt8(4) + rt3 - rt8(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + rt10 TE-IS 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.7/32 IP TE 60 rt9 - rt7(4) + rt3 - rt7(4) + 10.0.255.11/32 IP TE 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.1/32 IP TE 60 rt3 - rt1(4) + 10.0.255.10/32 IP TE 70 rt9 - rt10(4) + rt3 - rt10(4) + IS-IS L1 IPv4 routing table: @@ -3829,34 +4019,36 @@ Q-space: rt10 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt5 TE-IS 10 rt5 - rt2(4) -rt6 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt9 TE-IS 30 rt5 - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) - rt5 - -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt12 TE-IS 40 rt5 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 40 rt5 - rt9(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.12/32 IP TE 50 rt5 - rt12(4) -rt10 TE-IS 60 rt5 - rt11(4) -rt7 TE-IS 70 rt5 - rt10(4) -10.0.255.10/32 IP TE 70 rt5 - rt10(4) -rt4 TE-IS 80 rt5 - rt7(4) -10.0.255.7/32 IP TE 80 rt5 - rt7(4) -rt1 TE-IS 90 rt5 - rt4(4) -10.0.255.4/32 IP TE 90 rt5 - rt4(4) -10.0.255.1/32 IP TE 100 rt5 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt5 TE-IS 10 rt5 - rt2(4) + rt6 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt9 TE-IS 30 rt5 - rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt5 - rt6(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt12 TE-IS 40 rt5 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 40 rt5 - rt9(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.12/32 IP TE 50 rt5 - rt12(4) + rt10 TE-IS 60 rt5 - rt11(4) + rt7 TE-IS 70 rt5 - rt10(4) + 10.0.255.10/32 IP TE 70 rt5 - rt10(4) + rt4 TE-IS 80 rt5 - rt7(4) + 10.0.255.7/32 IP TE 80 rt5 - rt7(4) + rt1 TE-IS 90 rt5 - rt4(4) + 10.0.255.4/32 IP TE 90 rt5 - rt4(4) + 10.0.255.1/32 IP TE 100 rt5 - rt1(4) + IS-IS L1 IPv4 routing table: @@ -3894,32 +4086,34 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt5 TE-IS 30 rt3 - rt6(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt8 TE-IS 40 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt9 TE-IS 50 rt3 - rt8(4) -rt11 TE-IS 50 rt3 - rt8(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt12 TE-IS 60 rt3 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 60 rt3 - rt9(4) -10.0.255.11/32 IP TE 60 rt3 - rt11(4) -10.0.255.12/32 IP TE 70 rt3 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt5 TE-IS 30 rt3 - rt6(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt8 TE-IS 40 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt9 TE-IS 50 rt3 - rt8(4) + rt11 TE-IS 50 rt3 - rt8(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt12 TE-IS 60 rt3 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 60 rt3 - rt9(4) + 10.0.255.11/32 IP TE 60 rt3 - rt11(4) + 10.0.255.12/32 IP TE 70 rt3 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -3954,28 +4148,30 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt5 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.6/32 IP TE 60 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -10.0.255.8/32 IP TE 60 rt2 - rt8(4) -rt3 TE-IS 120 rt2 - rt4(4) -10.0.255.3/32 IP TE 130 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt5 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.6/32 IP TE 60 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + 10.0.255.8/32 IP TE 60 rt2 - rt8(4) + rt3 TE-IS 120 rt2 - rt4(4) + 10.0.255.3/32 IP TE 130 rt2 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4005,28 +4201,30 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt5 TE-IS 30 rt2 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) -2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) -2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) -rt3 TE-IS 120 rt2 - rt4(4) -2001:db8::3/128 IP6 internal 130 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt5 TE-IS 30 rt2 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) + 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) + 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + rt3 TE-IS 120 rt2 - rt4(4) + 2001:db8::3/128 IP6 internal 130 rt2 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4051,28 +4249,30 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt4 TE-IS 110 rt3 - rt3(4) -rt2 TE-IS 120 rt3 - rt4(4) -rt5 TE-IS 120 rt3 - rt4(4) -10.0.255.4/32 IP TE 120 rt3 - rt4(4) -rt9 TE-IS 130 rt3 - rt5(4) -10.0.255.2/32 IP TE 130 rt3 - rt2(4) -10.0.255.5/32 IP TE 130 rt3 - rt5(4) -rt6 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt7 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt8 TE-IS 140 rt3 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 140 rt3 - rt9(4) -10.0.255.6/32 IP TE 150 rt3 - rt6(4) -10.0.255.7/32 IP TE 150 rt3 - rt7(4) -10.0.255.8/32 IP TE 150 rt3 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt4 TE-IS 110 rt3 - rt3(4) + rt2 TE-IS 120 rt3 - rt4(4) + rt5 TE-IS 120 rt3 - rt4(4) + 10.0.255.4/32 IP TE 120 rt3 - rt4(4) + rt9 TE-IS 130 rt3 - rt5(4) + 10.0.255.2/32 IP TE 130 rt3 - rt2(4) + 10.0.255.5/32 IP TE 130 rt3 - rt5(4) + rt6 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt7 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt8 TE-IS 140 rt3 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 140 rt3 - rt9(4) + 10.0.255.6/32 IP TE 150 rt3 - rt6(4) + 10.0.255.7/32 IP TE 150 rt3 - rt7(4) + 10.0.255.8/32 IP TE 150 rt3 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -4102,28 +4302,30 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt4 TE-IS 110 rt3 - rt3(4) -rt2 TE-IS 120 rt3 - rt4(4) -rt5 TE-IS 120 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 120 rt3 - rt4(4) -rt9 TE-IS 130 rt3 - rt5(4) -2001:db8::2/128 IP6 internal 130 rt3 - rt2(4) -2001:db8::5/128 IP6 internal 130 rt3 - rt5(4) -rt6 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt7 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt8 TE-IS 140 rt3 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 140 rt3 - rt9(4) -2001:db8::6/128 IP6 internal 150 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 150 rt3 - rt7(4) -2001:db8::8/128 IP6 internal 150 rt3 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt4 TE-IS 110 rt3 - rt3(4) + rt2 TE-IS 120 rt3 - rt4(4) + rt5 TE-IS 120 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 120 rt3 - rt4(4) + rt9 TE-IS 130 rt3 - rt5(4) + 2001:db8::2/128 IP6 internal 130 rt3 - rt2(4) + 2001:db8::5/128 IP6 internal 130 rt3 - rt5(4) + rt6 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt7 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt8 TE-IS 140 rt3 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 140 rt3 - rt9(4) + 2001:db8::6/128 IP6 internal 150 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 150 rt3 - rt7(4) + 2001:db8::8/128 IP6 internal 150 rt3 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -4160,45 +4362,47 @@ Q-space: rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt9 -10.0.255.9/32 IP internal 0 rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt8 TE-IS 10 rt8 - rt9(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -rt4 TE-IS 40 rt6 - rt6(4) - rt7 - rt7(4) - rt8 - rt8(4) -rt2 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -rt5 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -10.0.255.4/32 IP TE 50 rt6 - rt4(4) - rt7 - - rt8 - -rt1 TE-IS 60 rt6 - rt2(4) - rt7 - - rt8 - -10.0.255.2/32 IP TE 60 rt6 - rt2(4) - rt7 - - rt8 - -10.0.255.5/32 IP TE 60 rt6 - rt5(4) - rt7 - - rt8 - -rt3 TE-IS 70 rt6 - rt1(4) - rt7 - - rt8 - -10.0.255.1/32 IP TE 70 rt6 - rt1(4) - rt7 - - rt8 - -10.0.255.3/32 IP TE 80 rt6 - rt3(4) - rt7 - - rt8 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt9 + 10.0.255.9/32 IP internal 0 rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt8 TE-IS 10 rt8 - rt9(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + rt4 TE-IS 40 rt6 - rt6(4) + rt7 - rt7(4) + rt8 - rt8(4) + rt2 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt5 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + 10.0.255.4/32 IP TE 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt1 TE-IS 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 10.0.255.2/32 IP TE 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 10.0.255.5/32 IP TE 60 rt6 - rt5(4) + rt7 - rt5(4) + rt8 - rt5(4) + rt3 TE-IS 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 10.0.255.1/32 IP TE 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 10.0.255.3/32 IP TE 80 rt6 - rt3(4) + rt7 - rt3(4) + rt8 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4242,45 +4446,47 @@ Q-space: rt5 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt9 -2001:db8::9/128 IP6 internal 0 rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt8 TE-IS 10 rt8 - rt9(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) -2001:db8::8/128 IP6 internal 20 rt8 - rt8(4) -rt4 TE-IS 40 rt6 - rt6(4) - rt7 - rt7(4) - rt8 - rt8(4) -rt2 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -rt5 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -2001:db8::4/128 IP6 internal 50 rt6 - rt4(4) - rt7 - - rt8 - -rt1 TE-IS 60 rt6 - rt2(4) - rt7 - - rt8 - -2001:db8::2/128 IP6 internal 60 rt6 - rt2(4) - rt7 - - rt8 - -2001:db8::5/128 IP6 internal 60 rt6 - rt5(4) - rt7 - - rt8 - -rt3 TE-IS 70 rt6 - rt1(4) - rt7 - - rt8 - -2001:db8::1/128 IP6 internal 70 rt6 - rt1(4) - rt7 - - rt8 - -2001:db8::3/128 IP6 internal 80 rt6 - rt3(4) - rt7 - - rt8 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt9 + 2001:db8::9/128 IP6 internal 0 rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt8 TE-IS 10 rt8 - rt9(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) + 2001:db8::8/128 IP6 internal 20 rt8 - rt8(4) + rt4 TE-IS 40 rt6 - rt6(4) + rt7 - rt7(4) + rt8 - rt8(4) + rt2 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt5 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt1 TE-IS 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 2001:db8::2/128 IP6 internal 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 2001:db8::5/128 IP6 internal 60 rt6 - rt5(4) + rt7 - rt5(4) + rt8 - rt5(4) + rt3 TE-IS 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 2001:db8::1/128 IP6 internal 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 2001:db8::3/128 IP6 internal 80 rt6 - rt3(4) + rt7 - rt3(4) + rt8 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4329,25 +4535,27 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt9 -10.0.255.9/32 IP internal 0 rt9(4) -rt5 TE-IS 10 rt5 - rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt4 TE-IS 20 rt5 - rt5(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -rt2 TE-IS 30 rt5 - rt4(4) -10.0.255.4/32 IP TE 30 rt5 - rt4(4) -rt1 TE-IS 40 rt5 - rt2(4) -10.0.255.2/32 IP TE 40 rt5 - rt2(4) -rt8 TE-IS 50 rt5 - rt4(4) -rt3 TE-IS 50 rt5 - rt1(4) -10.0.255.1/32 IP TE 50 rt5 - rt1(4) -10.0.255.8/32 IP TE 60 rt5 - rt8(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt9 + 10.0.255.9/32 IP internal 0 rt9(4) + rt5 TE-IS 10 rt5 - rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt4 TE-IS 20 rt5 - rt5(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + rt2 TE-IS 30 rt5 - rt4(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + rt1 TE-IS 40 rt5 - rt2(4) + 10.0.255.2/32 IP TE 40 rt5 - rt2(4) + rt8 TE-IS 50 rt5 - rt4(4) + rt3 TE-IS 50 rt5 - rt1(4) + 10.0.255.1/32 IP TE 50 rt5 - rt1(4) + 10.0.255.8/32 IP TE 60 rt5 - rt8(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4381,25 +4589,27 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt9 -2001:db8::9/128 IP6 internal 0 rt9(4) -rt5 TE-IS 10 rt5 - rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt4 TE-IS 20 rt5 - rt5(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) -rt2 TE-IS 30 rt5 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt5 - rt4(4) -rt1 TE-IS 40 rt5 - rt2(4) -2001:db8::2/128 IP6 internal 40 rt5 - rt2(4) -rt8 TE-IS 50 rt5 - rt4(4) -rt3 TE-IS 50 rt5 - rt1(4) -2001:db8::1/128 IP6 internal 50 rt5 - rt1(4) -2001:db8::8/128 IP6 internal 60 rt5 - rt8(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt9 + 2001:db8::9/128 IP6 internal 0 rt9(4) + rt5 TE-IS 10 rt5 - rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt4 TE-IS 20 rt5 - rt5(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) + rt2 TE-IS 30 rt5 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt5 - rt4(4) + rt1 TE-IS 40 rt5 - rt2(4) + 2001:db8::2/128 IP6 internal 40 rt5 - rt2(4) + rt8 TE-IS 50 rt5 - rt4(4) + rt3 TE-IS 50 rt5 - rt1(4) + 2001:db8::1/128 IP6 internal 50 rt5 - rt1(4) + 2001:db8::8/128 IP6 internal 60 rt5 - rt8(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4428,29 +4638,31 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.4/32 IP TE 30 rt4 - rt4(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt4 - rt7(4) -rt8 TE-IS 80 rt3 - rt6(4) - rt4 - rt7(4) -rt5 TE-IS 90 rt3 - rt8(4) - rt4 - -10.0.255.8/32 IP TE 90 rt3 - rt8(4) - rt4 - -rt2 TE-IS 100 rt3 - rt5(4) - rt4 - -10.0.255.5/32 IP TE 100 rt3 - rt5(4) - rt4 - -10.0.255.2/32 IP TE 110 rt3 - rt2(4) - rt4 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.4/32 IP TE 30 rt4 - rt4(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt4 - rt7(4) + rt8 TE-IS 80 rt3 - rt6(4) + rt4 - rt7(4) + rt5 TE-IS 90 rt3 - rt8(4) + rt4 - rt8(4) + 10.0.255.8/32 IP TE 90 rt3 - rt8(4) + rt4 - rt8(4) + rt2 TE-IS 100 rt3 - rt5(4) + rt4 - rt5(4) + 10.0.255.5/32 IP TE 100 rt3 - rt5(4) + rt4 - rt5(4) + 10.0.255.2/32 IP TE 110 rt3 - rt2(4) + rt4 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -4483,29 +4695,31 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) -rt8 TE-IS 80 rt3 - rt6(4) - rt4 - rt7(4) -rt5 TE-IS 90 rt3 - rt8(4) - rt4 - -2001:db8::8/128 IP6 internal 90 rt3 - rt8(4) - rt4 - -rt2 TE-IS 100 rt3 - rt5(4) - rt4 - -2001:db8::5/128 IP6 internal 100 rt3 - rt5(4) - rt4 - -2001:db8::2/128 IP6 internal 110 rt3 - rt2(4) - rt4 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) + rt8 TE-IS 80 rt3 - rt6(4) + rt4 - rt7(4) + rt5 TE-IS 90 rt3 - rt8(4) + rt4 - rt8(4) + 2001:db8::8/128 IP6 internal 90 rt3 - rt8(4) + rt4 - rt8(4) + rt2 TE-IS 100 rt3 - rt5(4) + rt4 - rt5(4) + 2001:db8::5/128 IP6 internal 100 rt3 - rt5(4) + rt4 - rt5(4) + 2001:db8::2/128 IP6 internal 110 rt3 - rt2(4) + rt4 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -4540,23 +4754,25 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt8 TE-IS 30 rt2 - rt5(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) -rt7 TE-IS 80 rt2 - rt8(4) -rt4 TE-IS 90 rt2 - rt7(4) -10.0.255.7/32 IP TE 90 rt2 - rt7(4) -10.0.255.4/32 IP TE 100 rt2 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt8 TE-IS 30 rt2 - rt5(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + rt7 TE-IS 80 rt2 - rt8(4) + rt4 TE-IS 90 rt2 - rt7(4) + 10.0.255.7/32 IP TE 90 rt2 - rt7(4) + 10.0.255.4/32 IP TE 100 rt2 - rt4(4) + IS-IS L1 IPv4 routing table: @@ -4586,23 +4802,25 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt8 TE-IS 30 rt2 - rt5(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) -rt7 TE-IS 80 rt2 - rt8(4) -rt4 TE-IS 90 rt2 - rt7(4) -2001:db8::7/128 IP6 internal 90 rt2 - rt7(4) -2001:db8::4/128 IP6 internal 100 rt2 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt8 TE-IS 30 rt2 - rt5(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + rt7 TE-IS 80 rt2 - rt8(4) + rt4 TE-IS 90 rt2 - rt7(4) + 2001:db8::7/128 IP6 internal 90 rt2 - rt7(4) + 2001:db8::4/128 IP6 internal 100 rt2 - rt4(4) + IS-IS L1 IPv6 routing table: @@ -4633,20 +4851,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -10.0.255.1/32 IP TE 60 rt1 - rt1(4) -10.0.255.3/32 IP TE 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -10.0.255.5/32 IP TE 70 rt3 - rt5(4) -10.0.255.4/32 IP TE 80 rt3 - rt4(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 10.0.255.1/32 IP TE 60 rt1 - rt1(4) + 10.0.255.3/32 IP TE 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 10.0.255.5/32 IP TE 70 rt3 - rt5(4) + 10.0.255.4/32 IP TE 80 rt3 - rt4(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -4679,20 +4899,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) -2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) -2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) + 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -4723,27 +4945,29 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -rt10 TE-IS 50 rt2 - rt8(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) -10.0.255.10/32 IP TE 60 rt2 - rt10(4) -rt7 TE-IS 140 rt2 - rt8(4) -rt9 TE-IS 150 rt2 - rt7(4) -10.0.255.7/32 IP TE 150 rt2 - rt7(4) -10.0.255.9/32 IP TE 160 rt2 - rt9(4) -rt5 TE-IS 340 rt2 - rt7(4) -10.0.255.5/32 IP TE 350 rt2 - rt5(4) -rt3 TE-IS 740 rt2 - rt5(4) -10.0.255.3/32 IP TE 750 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt10 TE-IS 50 rt2 - rt8(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + 10.0.255.10/32 IP TE 60 rt2 - rt10(4) + rt7 TE-IS 140 rt2 - rt8(4) + rt9 TE-IS 150 rt2 - rt7(4) + 10.0.255.7/32 IP TE 150 rt2 - rt7(4) + 10.0.255.9/32 IP TE 160 rt2 - rt9(4) + rt5 TE-IS 340 rt2 - rt7(4) + 10.0.255.5/32 IP TE 350 rt2 - rt5(4) + rt3 TE-IS 740 rt2 - rt5(4) + 10.0.255.3/32 IP TE 750 rt2 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4770,22 +4994,24 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt5 TE-IS 40 rt2 - rt3(4) -rt6 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) - rt6(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.6/32 IP TE 50 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 TE-IS 40 rt2 - rt3(4) + rt6 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt6(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.6/32 IP TE 50 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -4796,5 +5022,5 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt2 16040/16060 10.0.255.7/32 60 - rt2 16040/16070 -test# -end. +test# +end. diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index f9f584f4..342a91cc 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -9,6 +9,7 @@ #include #include +#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 84365810..222abcda 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 ea84120f..9873383f 100644 --- a/tests/lib/cli/test_commands.c +++ b/tests/lib/cli/test_commands.c @@ -21,6 +21,7 @@ #include #include +#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 321f1586..fdc9e53c 100644 --- a/tests/lib/northbound/test_oper_data.c +++ b/tests/lib/northbound/test_oper_data.c @@ -7,6 +7,7 @@ #include #include +#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/subdir.am b/tests/lib/subdir.am index 185b8950..1a21684f 100644 --- a/tests/lib/subdir.am +++ b/tests/lib/subdir.am @@ -100,7 +100,7 @@ check_PROGRAMS += tests/lib/cli/test_commands tests_lib_cli_test_commands_CFLAGS = $(TESTS_CFLAGS) tests_lib_cli_test_commands_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD) -nodist_tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands_defun.c +nodist_tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands_defun.c $(vtysh_cmd_split) tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands.c tests/helpers/c/prng.c tests/lib/cli/test_commands_defun.c: vtysh/vtysh_cmd.c @$(MKDIR_P) tests/lib/cli diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c index b50216cf..afcfa987 100644 --- a/tests/lib/test_atomlist.c +++ b/tests/lib/test_atomlist.c @@ -62,7 +62,7 @@ static struct asort_head shead; static struct testthread { pthread_t pt; struct seqlock sqlo; - size_t counter, nullops; + _Atomic size_t counter, nullops; } thr[NTHREADS]; struct testrun { @@ -97,10 +97,10 @@ static void trfunc_##name(unsigned int offset) \ { \ size_t i = 0, n = 0; -#define endtestrun \ - thr[offset].counter = i; \ - thr[offset].nullops = n; \ -} +#define endtestrun \ + atomic_store_explicit(&thr[offset].counter, i, memory_order_seq_cst); \ + atomic_store_explicit(&thr[offset].nullops, n, memory_order_seq_cst); \ + } deftestrun(add, "add vs. add", 0, false) for (; i < NITEM / NTHREADS; i++) @@ -288,10 +288,10 @@ static void run_tr(struct testrun *tr) sv = seqlock_bump(&sqlo) - SEQLOCK_INCR; for (size_t i = 0; i < NTHREADS; i++) { seqlock_wait(&thr[i].sqlo, seqlock_cur(&sqlo)); - s += thr[i].counter; - n += thr[i].nullops; - thr[i].counter = 0; - thr[i].nullops = 0; + s += atomic_load_explicit(&thr[i].counter, memory_order_seq_cst); + n += atomic_load_explicit(&thr[i].nullops, memory_order_seq_cst); + atomic_store_explicit(&thr[i].counter, 0, memory_order_seq_cst); + atomic_store_explicit(&thr[i].nullops, 0, memory_order_seq_cst); } delta = monotime_since(&tv, NULL); diff --git a/tests/lib/test_darr.c b/tests/lib/test_darr.c index 74aedac4..87f9e3e5 100644 --- a/tests/lib/test_darr.c +++ b/tests/lib/test_darr.c @@ -20,6 +20,8 @@ * [x] - darr_foreach_i * [x] - darr_foreach_p * [x] - darr_free + * [x] - darr_free_free + * [x] - darr_free_func * [x] - darr_insert * [ ] - darr_insertz * [x] - darr_insert_n @@ -318,6 +320,8 @@ static void test_string(void) uint addlen = strlen(add); char *da1 = NULL; char *da2 = NULL; + const char **strings = NULL; + uint sum = 0; assert(darr_strlen(da1) == 0); @@ -412,6 +416,29 @@ static void test_string(void) da1 = darr_in_strcatf(da1, "0123456789: %08x", 0xDEADBEEF); assert(!strcmp("0123456789: deadbeef", da1)); darr_free(da1); + + sum = 0; + *darr_append(strings) = "1"; + *darr_append(strings) = "2"; + *darr_append(strings) = "3"; +#define adder(x) (sum += atoi(x)) + darr_free_func(strings, adder); + assert(sum == 6); + assert(strings == NULL); + + sum = 0; + darr_free_func(strings, adder); + assert(sum == 0); + assert(strings == NULL); + + *darr_append(strings) = NULL; + *darr_append(strings) = darr_strdup("2"); + *darr_append(strings) = darr_strdup("3"); + darr_free_free(strings); + assert(strings == NULL); + + darr_free_free(strings); + assert(strings == NULL); } int main(int argc, char **argv) diff --git a/tests/lib/test_frrlua.c b/tests/lib/test_frrlua.c index 2760a273..4aa8c8a8 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 20231360..379a8688 100644 --- a/tests/lib/test_grpc.cpp +++ b/tests/lib/test_grpc.cpp @@ -9,6 +9,7 @@ #include #include +#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_seqlock.c b/tests/lib/test_seqlock.c index 288d4a8c..937b3f34 100644 --- a/tests/lib/test_seqlock.c +++ b/tests/lib/test_seqlock.c @@ -82,11 +82,11 @@ int main(int argc, char **argv) assert(seqlock_held(&sqlo)); assert(seqlock_cur(&sqlo) == 1); - assert(seqlock_bump(&sqlo) == 1); - assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 5); + assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 9); assert(seqlock_bump(&sqlo) == 13); + assert(seqlock_bump(&sqlo) == 17); assert(seqlock_cur(&sqlo) == 17); assert(seqlock_held(&sqlo)); @@ -111,4 +111,5 @@ int main(int argc, char **argv) writestr("main @release\n"); seqlock_release(&sqlo); sleep(1); + pthread_join(thr1, NULL); } diff --git a/tests/lib/test_ttable.c b/tests/lib/test_ttable.c index 562ddf9d..7ac0e351 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 f9df7353..9cec4a31 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 a2f3d3b0..2b4363b6 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 a4a4aba3..33c44780 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 100a36a8..3f03d6fe 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 a25b53aa..f5c1d6d7 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/all_protocol_startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref index f52b51d9..e4e32901 100644 --- a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref +++ b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref @@ -11,6 +11,7 @@ r1-eth0 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 r1-eth3 is up ifindex X, MTU 1500 bytes, BW XX Mbit Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0 @@ -24,3 +25,4 @@ r1-eth3 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py index b4bc1e14..80bd2505 100644 --- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py +++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py @@ -38,9 +38,10 @@ from lib.common_config import ( required_linux_kernel_version, ) -from lib.topolog import logger import json +import functools +# Global that must be set on a failure to stop subsequent tests from being run fatal_error = "" @@ -153,7 +154,6 @@ def test_error_messages_vtysh(): print("\n\n** Check for error messages on VTYSH") print("******************************************\n") - failures = 0 for i in range(1, 2): # # First checking Standard Output @@ -402,17 +402,27 @@ def test_converge_protocols(): def route_get_nhg_id(route_str): - net = get_topogen().net - output = net["r1"].cmd( - 'vtysh -c "show ip route {} nexthop-group"'.format(route_str) - ) - match = re.search(r"Nexthop Group ID: (\d+)", output) - assert match is not None, "Nexthop Group ID not found for sharpd route {}".format( - route_str - ) + global fatal_error + + def get_func(route_str): + net = get_topogen().net + output = net["r1"].cmd( + 'vtysh -c "show ip route {} nexthop-group"'.format(route_str) + ) + match = re.search(r"Nexthop Group ID: (\d+)", output) + if match is not None: + nhg_id = int(match.group(1)) + return nhg_id + else: + return None - nhg_id = int(match.group(1)) - return nhg_id + test_func = functools.partial(get_func, route_str) + _, nhg_id = topotest.run_and_expect_type(test_func, int, count=30, wait=1) + if nhg_id == None: + fatal_error = "Nexthop Group ID not found for route {}".format(route_str) + assert nhg_id != None, fatal_error + else: + return nhg_id def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): @@ -489,8 +499,12 @@ def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): def verify_route_nexthop_group(route_str, recursive=False, ecmp=0): + global fatal_error + # Verify route and that zebra created NHGs for and they are valid/installed + nhg_id = route_get_nhg_id(route_str) + verify_nexthop_group(nhg_id, recursive, ecmp) @@ -1650,8 +1664,13 @@ def test_mpls_interfaces(): def test_resilient_nexthop_group(): + global fatal_error net = get_topogen().net + # Skip if previous fatal error condition is raised + if fatal_error != "": + pytest.skip(fatal_error) + result = required_linux_kernel_version("5.19") if result is not True: pytest.skip("Kernel requirements are not met, kernel version should be >= 5.19") @@ -1660,8 +1679,18 @@ def test_resilient_nexthop_group(): 'vtysh -c "conf" -c "nexthop-group resilience" -c "resilient buckets 64 idle-timer 128 unbalanced-timer 256" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"' ) - output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"') - buckets = re.findall(r"Buckets", output) + # Temporary helper function + def _show_func(): + output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"') + buckets = re.findall(r"Buckets", output) + + return len(buckets) + + _, result = topotest.run_and_expect(_show_func, 1, count=30, wait=1) + if result != 1: + fatal_error = "Resilient NHG not created in zebra" + + assert result == 1, fatal_error output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp json"') @@ -1674,8 +1703,14 @@ def test_resilient_nexthop_group(): if "buckets" in n: break + if "buckets" not in n: + fatal_error = "Resilient NHG not found in json output" + assert "buckets" in n, fatal_error + verify_nexthop_group(int(nhgid)) - assert len(buckets) == 1, "Resilient NHG not created in zebra" + + # Remove NHG + net["r1"].cmd('vtysh -c "conf" -c "no nexthop-group resilience"') def test_shutdown_check_stderr(): diff --git a/tests/topotests/babel_topo1/test_babel_topo1.py b/tests/topotests/babel_topo1/test_babel_topo1.py index decf0c2a..13bbe5bd 100644 --- a/tests/topotests/babel_topo1/test_babel_topo1.py +++ b/tests/topotests/babel_topo1/test_babel_topo1.py @@ -15,7 +15,6 @@ test_babel_topo1.py: Testing BABEL """ import os -import re import sys import pytest import json @@ -130,7 +129,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: assertmsg = "Zebra IPv4 Routing Table verification failed for router {}".format( diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf index f8ad1f3a..054b1283 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf @@ -7,6 +7,7 @@ router bgp 101 bgp graceful-restart neighbor 2001:db8:4::1 remote-as 102 neighbor 2001:db8:4::1 timers 3 10 + neighbor 2001:db8:4::1 timers connect 1 neighbor 2001:db8:4::1 remote-as external neighbor 2001:db8:4::1 bfd neighbor 2001:db8:4::1 bfd check-control-plane-failure diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf index 42953a07..d7e10210 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf @@ -11,6 +11,7 @@ router bgp 102 bgp graceful-restart restart-time 900 neighbor 2001:db8:1::1 remote-as 101 neighbor 2001:db8:1::1 timers 3 10 + neighbor 2001:db8:1::1 timers connect 1 neighbor 2001:db8:1::1 remote-as external neighbor 2001:db8:1::1 update-source 2001:db8:4::1 neighbor 2001:db8:1::1 bfd diff --git a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py index b9e8b73c..6919371a 100755 --- a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py +++ b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py @@ -59,7 +59,6 @@ import os import sys import pytest import json -from time import sleep from functools import partial # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bfd_topo3/test_bfd_topo3.py b/tests/topotests/bfd_topo3/test_bfd_topo3.py index d7b2542f..a899a2b4 100644 --- a/tests/topotests/bfd_topo3/test_bfd_topo3.py +++ b/tests/topotests/bfd_topo3/test_bfd_topo3.py @@ -95,7 +95,7 @@ def expect_route_missing(router, iptype, route): "show {} route json".format(iptype), {route: None}, ) - rv, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assertmsg = '"{}" convergence failure'.format(router) assert result is None, assertmsg diff --git a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py index 9e5a68f0..f6adff61 100644 --- a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py @@ -61,7 +61,7 @@ def setup_module(mod): router_list = tgen.routers() # check for zebra capability - for rname, router in router_list.items(): + for _, router in router_list.items(): if router.check_capability(TopoRouter.RD_ZEBRA, "--vrfwnetns") == False: return pytest.skip( "Skipping BFD Topo1 VRF NETNS feature. VRF NETNS backend not available on FRR" diff --git a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py index d294da09..11b24baa 100644 --- a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py +++ b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py @@ -68,7 +68,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py index 2a610c90..3d17a2b7 100644 --- a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py +++ b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_addpath_graceful_restart/__init__.py b/tests/topotests/bgp_addpath_graceful_restart/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/topotests/bgp_addpath_graceful_restart/r1/frr.conf b/tests/topotests/bgp_addpath_graceful_restart/r1/frr.conf new file mode 100644 index 00000000..0644cf63 --- /dev/null +++ b/tests/topotests/bgp_addpath_graceful_restart/r1/frr.conf @@ -0,0 +1,23 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +int r1-eth1 + ip address 192.168.2.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as auto + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.2.2 remote-as auto + neighbor 192.168.2.2 timers 1 3 + neighbor 192.168.2.2 timers connect 1 + neighbor r1-eth1 interface remote-as auto + neighbor r1-eth1 timers 1 3 + neighbor r1-eth1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.1/32 + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_graceful_restart/r2/frr.conf b/tests/topotests/bgp_addpath_graceful_restart/r2/frr.conf new file mode 100644 index 00000000..ad236e06 --- /dev/null +++ b/tests/topotests/bgp_addpath_graceful_restart/r2/frr.conf @@ -0,0 +1,28 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +int r2-eth1 + ip address 192.168.2.2/24 +! +int r2-eth2 + ip address 192.168.3.2/24 +! +router bgp 65002 + bgp graceful-restart + bgp graceful-restart preserve-fw-state + bgp graceful-restart restart-time 10 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.2.1 remote-as auto + neighbor 192.168.2.1 timers 1 3 + neighbor 192.168.2.1 timers connect 1 + neighbor 192.168.3.3 remote-as auto + neighbor 192.168.3.3 timers 1 3 + neighbor 192.168.3.3 timers connect 1 + address-family ipv4 unicast + neighbor 192.168.3.3 addpath-tx-all-paths + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_graceful_restart/r3/frr.conf b/tests/topotests/bgp_addpath_graceful_restart/r3/frr.conf new file mode 100644 index 00000000..e864003f --- /dev/null +++ b/tests/topotests/bgp_addpath_graceful_restart/r3/frr.conf @@ -0,0 +1,13 @@ +! +int r3-eth0 + ip address 192.168.3.3/24 +! +router bgp 65003 + bgp graceful-restart + bgp graceful-restart preserve-fw-state + bgp graceful-restart restart-time 10 + no bgp ebgp-requires-policy + neighbor 192.168.3.2 remote-as auto + neighbor 192.168.3.2 timers 1 3 + neighbor 192.168.3.2 timers connect 1 +! diff --git a/tests/topotests/bgp_addpath_graceful_restart/test_bgp_addpath_graceful_restart.py b/tests/topotests/bgp_addpath_graceful_restart/test_bgp_addpath_graceful_restart.py new file mode 100644 index 00000000..9088c44b --- /dev/null +++ b/tests/topotests/bgp_addpath_graceful_restart/test_bgp_addpath_graceful_restart.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +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 kill_router_daemons + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2"), "s2": ("r1", "r2"), "s3": ("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_addpath_graceful_restart(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast summary json")) + expected = { + "peers": { + "192.168.1.1": { + "hostname": "r1", + "remoteAs": 65001, + "localAs": 65002, + "pfxRcd": 1, + "state": "Established", + }, + "192.168.2.1": { + "hostname": "r1", + "remoteAs": 65001, + "localAs": 65002, + "pfxRcd": 1, + "state": "Established", + }, + "192.168.3.3": { + "hostname": "r3", + "remoteAs": 65003, + "localAs": 65002, + "pfxSnt": 2, + "state": "Established", + }, + } + } + 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, "Initial peering failed" + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + def _bgp_check_stale_routes(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.0.0.1/32": [ + { + "stale": True, + "valid": True, + }, + { + "stale": True, + "valid": True, + "multipath": True, + }, + ] + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_stale_routes, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see stale routes" + + def _bgp_check_stale_routes_cleared(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.0.0.1/32": None, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_stale_routes_cleared, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see stale routes" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_addpath_llgr/__init__.py b/tests/topotests/bgp_addpath_llgr/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/topotests/bgp_addpath_llgr/r1/frr.conf b/tests/topotests/bgp_addpath_llgr/r1/frr.conf new file mode 100644 index 00000000..0644cf63 --- /dev/null +++ b/tests/topotests/bgp_addpath_llgr/r1/frr.conf @@ -0,0 +1,23 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +int r1-eth1 + ip address 192.168.2.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as auto + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.2.2 remote-as auto + neighbor 192.168.2.2 timers 1 3 + neighbor 192.168.2.2 timers connect 1 + neighbor r1-eth1 interface remote-as auto + neighbor r1-eth1 timers 1 3 + neighbor r1-eth1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.1/32 + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_llgr/r2/frr.conf b/tests/topotests/bgp_addpath_llgr/r2/frr.conf new file mode 100644 index 00000000..7f6fff0f --- /dev/null +++ b/tests/topotests/bgp_addpath_llgr/r2/frr.conf @@ -0,0 +1,29 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +int r2-eth1 + ip address 192.168.2.2/24 +! +int r2-eth2 + ip address 192.168.3.2/24 +! +router bgp 65002 + bgp graceful-restart + bgp graceful-restart preserve-fw-state + bgp graceful-restart restart-time 0 + bgp long-lived-graceful-restart stale-time 10 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.2.1 remote-as auto + neighbor 192.168.2.1 timers 1 3 + neighbor 192.168.2.1 timers connect 1 + neighbor 192.168.3.3 remote-as auto + neighbor 192.168.3.3 timers 1 3 + neighbor 192.168.3.3 timers connect 1 + address-family ipv4 unicast + neighbor 192.168.3.3 addpath-tx-all-paths + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_llgr/r3/frr.conf b/tests/topotests/bgp_addpath_llgr/r3/frr.conf new file mode 100644 index 00000000..f36492d7 --- /dev/null +++ b/tests/topotests/bgp_addpath_llgr/r3/frr.conf @@ -0,0 +1,14 @@ +! +int r3-eth0 + ip address 192.168.3.3/24 +! +router bgp 65003 + bgp graceful-restart + bgp graceful-restart preserve-fw-state + bgp graceful-restart restart-time 0 + bgp long-lived-graceful-restart stale-time 10 + no bgp ebgp-requires-policy + neighbor 192.168.3.2 remote-as auto + neighbor 192.168.3.2 timers 1 3 + neighbor 192.168.3.2 timers connect 1 +! diff --git a/tests/topotests/bgp_addpath_llgr/test_bgp_addpath_llgr.py b/tests/topotests/bgp_addpath_llgr/test_bgp_addpath_llgr.py new file mode 100644 index 00000000..fa031430 --- /dev/null +++ b/tests/topotests/bgp_addpath_llgr/test_bgp_addpath_llgr.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +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 kill_router_daemons + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2"), "s2": ("r1", "r2"), "s3": ("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_addpath_llgr(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast summary json")) + expected = { + "peers": { + "192.168.1.1": { + "hostname": "r1", + "remoteAs": 65001, + "localAs": 65002, + "pfxRcd": 1, + "state": "Established", + }, + "192.168.2.1": { + "hostname": "r1", + "remoteAs": 65001, + "localAs": 65002, + "pfxRcd": 1, + "state": "Established", + }, + "192.168.3.3": { + "hostname": "r3", + "remoteAs": 65003, + "localAs": 65002, + "pfxSnt": 2, + "state": "Established", + }, + } + } + 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, "Initial peering failed" + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + def _bgp_check_stale_llgr_routes(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "stale": True, + "valid": True, + "community": {"string": "llgr-stale", "list": ["llgrStale"]}, + }, + { + "stale": True, + "valid": True, + "community": {"string": "llgr-stale", "list": ["llgrStale"]}, + }, + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_stale_llgr_routes, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see stale LLGR routes" + + def _bgp_check_stale_routes_cleared(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.0.0.1/32": None, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_stale_routes_cleared, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see stale routes" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py index b7a1cfbb..fb863e45 100644 --- a/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py +++ b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py @@ -20,7 +20,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py index 5a4a5fb6..0520b5e1 100644 --- a/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py +++ b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py b/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py index 739685d4..188bbd0b 100644 --- a/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py +++ b/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -89,12 +89,12 @@ def test_bgp_aggregate_address_origin(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_aggregate_address_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py index eeac7146..2343440a 100644 --- a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py +++ b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py @@ -52,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py b/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py index d9ef3e1c..1a52f8c9 100644 --- a/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py +++ b/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py @@ -73,7 +73,7 @@ def test_bgp_aggregator_zero(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r1"]) @@ -99,7 +99,7 @@ def test_bgp_aggregator_zero(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_has_correct_aggregator_route_with_good_asn) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Aggregator AS attribute not found in "{}"'.format( tgen.gears["r1"] diff --git a/tests/topotests/bgp_aigp/r1/ospfd.conf b/tests/topotests/bgp_aigp/r1/ospfd.conf index 38aa11d0..098bf57b 100644 --- a/tests/topotests/bgp_aigp/r1/ospfd.conf +++ b/tests/topotests/bgp_aigp/r1/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r1-eth0 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r2/bgpd.conf b/tests/topotests/bgp_aigp/r2/bgpd.conf index 4db46875..4539016f 100644 --- a/tests/topotests/bgp_aigp/r2/bgpd.conf +++ b/tests/topotests/bgp_aigp/r2/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 10.0.0.1 remote-as internal neighbor 10.0.0.1 timers 1 3 neighbor 10.0.0.1 timers connect 1 @@ -11,5 +12,6 @@ router bgp 65001 neighbor 192.168.24.4 aigp address-family ipv4 redistribute connected + neighbor 10.0.0.1 next-hop-self force exit-address-family ! diff --git a/tests/topotests/bgp_aigp/r2/ospfd.conf b/tests/topotests/bgp_aigp/r2/ospfd.conf index ed31941f..106a4625 100644 --- a/tests/topotests/bgp_aigp/r2/ospfd.conf +++ b/tests/topotests/bgp_aigp/r2/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r2-eth0 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r3/bgpd.conf b/tests/topotests/bgp_aigp/r3/bgpd.conf index 5ab712ea..bdaa5cf5 100644 --- a/tests/topotests/bgp_aigp/r3/bgpd.conf +++ b/tests/topotests/bgp_aigp/r3/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 10.0.0.1 remote-as internal neighbor 10.0.0.1 timers 1 3 neighbor 10.0.0.1 timers connect 1 @@ -11,5 +12,6 @@ router bgp 65001 neighbor 192.168.35.5 aigp address-family ipv4 redistribute connected + neighbor 10.0.0.1 next-hop-self force exit-address-family ! diff --git a/tests/topotests/bgp_aigp/r3/ospfd.conf b/tests/topotests/bgp_aigp/r3/ospfd.conf index f971ad6f..9ede3a1f 100644 --- a/tests/topotests/bgp_aigp/r3/ospfd.conf +++ b/tests/topotests/bgp_aigp/r3/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r3-eth0 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r4/bgpd.conf b/tests/topotests/bgp_aigp/r4/bgpd.conf index aa88bac9..2cdf84a1 100644 --- a/tests/topotests/bgp_aigp/r4/bgpd.conf +++ b/tests/topotests/bgp_aigp/r4/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 192.168.24.2 remote-as internal neighbor 192.168.24.2 timers 1 3 neighbor 192.168.24.2 timers connect 1 @@ -11,7 +12,25 @@ router bgp 65001 neighbor 10.0.0.6 timers connect 1 neighbor 10.0.0.6 update-source lo address-family ipv4 - redistribute connected - redistribute ospf + redistribute connected route-map connected-to-bgp + redistribute ospf route-map ospf-to-bgp + neighbor 192.168.24.2 route-map set-nexthop out exit-address-family ! +ip prefix-list p66 seq 5 permit 10.0.6.6/32 +! +route-map ospf-to-bgp permit 10 + match ip address prefix-list p66 + set aigp igp-metric +! +! Two OSPF domains should be isolated - otherwise the connected routes +! on r4 would be advertised to r3 (via r4 -> r6 -> r5 -> r3), and can +! mess up bgp bestpath calculation (igp metrics for the BGP nexthops). +! +route-map connected-to-bgp permit 10 + set community no-advertise +! +route-map set-nexthop permit 10 + set ip next-hop peer-address +exit +! diff --git a/tests/topotests/bgp_aigp/r4/ospfd.conf b/tests/topotests/bgp_aigp/r4/ospfd.conf index c9e6796f..237b5e18 100644 --- a/tests/topotests/bgp_aigp/r4/ospfd.conf +++ b/tests/topotests/bgp_aigp/r4/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r4-eth1 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r5/bgpd.conf b/tests/topotests/bgp_aigp/r5/bgpd.conf index 4fde2620..3d1f5e85 100644 --- a/tests/topotests/bgp_aigp/r5/bgpd.conf +++ b/tests/topotests/bgp_aigp/r5/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 192.168.35.3 remote-as internal neighbor 192.168.35.3 timers 1 3 neighbor 192.168.35.3 timers connect 1 @@ -11,7 +12,18 @@ router bgp 65001 neighbor 10.0.0.6 timers connect 1 neighbor 10.0.0.6 update-source lo address-family ipv4 - redistribute connected - redistribute ospf + redistribute connected route-map connected-to-bgp + neighbor 192.168.35.3 route-map set-nexthop out exit-address-family ! +! Two OSPF domains should be isolated - otherwise the connected routes +! on r5 would be advertised to r2 (via r5 -> r6 -> r4 -> r2), and can +! mess up bgp bestpath calculation (igp metrics for the BGP nexthops). +! +route-map connected-to-bgp permit 10 + set community no-advertise +! +route-map set-nexthop permit 10 + set ip next-hop peer-address +exit +! diff --git a/tests/topotests/bgp_aigp/r5/ospfd.conf b/tests/topotests/bgp_aigp/r5/ospfd.conf index b853c741..65a213df 100644 --- a/tests/topotests/bgp_aigp/r5/ospfd.conf +++ b/tests/topotests/bgp_aigp/r5/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r5-eth1 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r6/bgpd.conf b/tests/topotests/bgp_aigp/r6/bgpd.conf index 2faae772..2d5f7a89 100644 --- a/tests/topotests/bgp_aigp/r6/bgpd.conf +++ b/tests/topotests/bgp_aigp/r6/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 10.0.0.4 remote-as internal neighbor 10.0.0.4 timers 1 3 neighbor 10.0.0.4 timers connect 1 @@ -15,6 +16,11 @@ router bgp 65001 neighbor 192.168.67.7 timers 1 3 neighbor 192.168.67.7 timers connect 1 address-family ipv4 - redistribute ospf + neighbor 10.0.0.4 route-map set-nexthop out + neighbor 10.0.0.5 route-map set-nexthop out exit-address-family ! +route-map set-nexthop permit 10 + set ip next-hop peer-address +exit +! diff --git a/tests/topotests/bgp_aigp/r6/ospfd.conf b/tests/topotests/bgp_aigp/r6/ospfd.conf index 46b29331..89cbefa8 100644 --- a/tests/topotests/bgp_aigp/r6/ospfd.conf +++ b/tests/topotests/bgp_aigp/r6/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r6-eth0 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r6/zebra.conf b/tests/topotests/bgp_aigp/r6/zebra.conf index f8ca5f8b..b6456cac 100644 --- a/tests/topotests/bgp_aigp/r6/zebra.conf +++ b/tests/topotests/bgp_aigp/r6/zebra.conf @@ -1,6 +1,7 @@ ! interface lo ip address 10.0.0.6/32 + ip address 10.0.6.6/32 ! interface r6-eth0 ip address 192.168.46.6/24 diff --git a/tests/topotests/bgp_aigp/test_bgp_aigp.py b/tests/topotests/bgp_aigp/test_bgp_aigp.py index 655e9ad1..19425373 100644 --- a/tests/topotests/bgp_aigp/test_bgp_aigp.py +++ b/tests/topotests/bgp_aigp/test_bgp_aigp.py @@ -12,9 +12,9 @@ r7 sets aigp-metric for 10.0.0.71/32 to 71, and 72 for 10.0.0.72/32. r6 receives those routes with aigp-metric TLV. r2 and r3 receives those routes with aigp-metric TLV increased by 20, -and 30 appropriately. +and 10 appropriately. -r1 receives routes with aigp-metric TLV 111,131 and 112,132 appropriately. +r1 receives routes with aigp-metric TLV 81, 91 and 82, 92 respectively. """ import os @@ -29,7 +29,6 @@ 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] @@ -73,7 +72,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -109,15 +108,29 @@ def test_bgp_aigp(): expected = { "paths": [ { - "aigpMetric": 111, + "aigpMetric": 81, "valid": True, - "nexthops": [{"hostname": "r3", "accessible": True}], + "nexthops": [ + { + "ip": "10.0.0.3", + "hostname": "r3", + "metric": 30, + "accessible": True, + } + ], }, { - "aigpMetric": 131, + "aigpMetric": 91, "valid": True, - "bestpath": {"selectionReason": "Neighbor IP"}, - "nexthops": [{"hostname": "r2", "accessible": True}], + "bestpath": {"selectionReason": "IGP Metric"}, + "nexthops": [ + { + "ip": "10.0.0.2", + "hostname": "r2", + "metric": 10, + "accessible": True, + } + ], }, ] } @@ -141,30 +154,58 @@ def test_bgp_aigp(): "10.0.0.71/32": { "paths": [ { - "aigpMetric": 111, - "bestpath": {"selectionReason": "AIGP"}, + "aigpMetric": 81, "valid": True, - "nexthops": [{"hostname": "r3", "accessible": True}], + "nexthops": [ + { + "ip": "10.0.0.3", + "hostname": "r3", + "metric": 30, + "accessible": True, + } + ], }, { - "aigpMetric": 131, + "aigpMetric": 91, "valid": True, - "nexthops": [{"hostname": "r2", "accessible": True}], + "bestpath": {"selectionReason": "AIGP"}, + "nexthops": [ + { + "ip": "10.0.0.2", + "hostname": "r2", + "metric": 10, + "accessible": True, + } + ], }, ], }, "10.0.0.72/32": { "paths": [ { - "aigpMetric": 112, - "bestpath": {"selectionReason": "AIGP"}, + "aigpMetric": 82, "valid": True, - "nexthops": [{"hostname": "r3", "accessible": True}], + "nexthops": [ + { + "ip": "10.0.0.3", + "hostname": "r3", + "metric": 30, + "accessible": True, + } + ], }, { - "aigpMetric": 132, + "aigpMetric": 92, "valid": True, - "nexthops": [{"hostname": "r2", "accessible": True}], + "bestpath": {"selectionReason": "AIGP"}, + "nexthops": [ + { + "ip": "10.0.0.2", + "hostname": "r2", + "metric": 10, + "accessible": True, + } + ], }, ], }, @@ -186,6 +227,11 @@ def test_bgp_aigp(): """ ) + # r4, 10.0.6.6/32 with aigp-metric 20 + test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.6.6/32", 20) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.6.6/32 is not 20" + # r4, 10.0.0.71/32 with aigp-metric 71 test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.0.71/32", 71) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) @@ -196,17 +242,17 @@ def test_bgp_aigp(): _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assert result is None, "aigp-metric for 10.0.0.72/32 is not 72" - # r2, 10.0.0.71/32 with aigp-metric 101 (71 + 30) - test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.0.71/32", 101) + # r2, 10.0.0.71/32 with aigp-metric 101 (71 + 20) + test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.0.71/32", 91) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) - assert result is None, "aigp-metric for 10.0.0.71/32 is not 101" + assert result is None, "aigp-metric for 10.0.0.71/32 is not 91" - # r3, 10.0.0.72/32 with aigp-metric 92 (72 + 20) - test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.0.72/32", 92) + # r3, 10.0.0.72/32 with aigp-metric 92 (72 + 10) + test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.0.72/32", 82) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) - assert result is None, "aigp-metric for 10.0.0.72/32 is not 92" + assert result is None, "aigp-metric for 10.0.0.72/32 is not 82" - # r1, check if AIGP is considered in best-path selection (lowest wins) + # r1, check if AIGP is considered in best-path selection (lowest wins: aigp + nexthop-metric) test_func = functools.partial(_bgp_check_aigp_metric_bestpath) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assert result is None, "AIGP attribute is not considered in best-path selection" diff --git a/tests/topotests/bgp_aigp_rr/r1/bgpd.conf b/tests/topotests/bgp_aigp_rr/r1/bgpd.conf new file mode 100644 index 00000000..4099a248 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r1/bgpd.conf @@ -0,0 +1,32 @@ +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + bgp route-reflector allow-outbound-policy + neighbor 10.0.0.2 remote-as internal + neighbor 10.0.0.2 update-source lo + neighbor 10.0.0.2 timers 1 3 + neighbor 10.0.0.2 timers connect 1 + neighbor 10.0.0.2 route-reflector-client + neighbor 10.0.0.3 remote-as internal + neighbor 10.0.0.3 update-source lo + neighbor 10.0.0.3 timers 1 3 + neighbor 10.0.0.3 timers connect 1 + neighbor 10.0.0.3 route-reflector-client + neighbor 10.0.0.4 remote-as internal + neighbor 10.0.0.4 update-source lo + neighbor 10.0.0.4 timers 1 3 + neighbor 10.0.0.4 timers connect 1 + neighbor 10.0.0.4 route-reflector-client + address-family ipv4 + network 10.0.1.2/32 route-map set-aigp + neighbor 10.0.0.4 route-map set-nexthop out + exit-address-family +! +route-map set-nexthop permit 10 + set ip next-hop peer-address +exit +! +route-map set-aigp permit 10 + set aigp 50 + set weight 0 +! diff --git a/tests/topotests/bgp_aigp_rr/r1/ospfd.conf b/tests/topotests/bgp_aigp_rr/r1/ospfd.conf new file mode 100644 index 00000000..b5b43c76 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r1/ospfd.conf @@ -0,0 +1,23 @@ +! +interface lo + ip ospf passive +! +interface r1-eth0 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +interface r1-eth1 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +interface r1-eth2 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +router ospf + router-id 10.0.0.1 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_aigp_rr/r1/zebra.conf b/tests/topotests/bgp_aigp_rr/r1/zebra.conf new file mode 100644 index 00000000..bf4a3497 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r1/zebra.conf @@ -0,0 +1,13 @@ +! +interface lo + ip address 10.0.0.1/32 +! +interface r1-eth0 + ip address 192.168.12.1/24 +! +interface r1-eth1 + ip address 192.168.13.1/24 +! +interface r1-eth2 + ip address 192.168.14.1/24 +! diff --git a/tests/topotests/bgp_aigp_rr/r2/bgpd.conf b/tests/topotests/bgp_aigp_rr/r2/bgpd.conf new file mode 100644 index 00000000..0159dc8e --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r2/bgpd.conf @@ -0,0 +1,22 @@ +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.1 remote-as internal + neighbor 10.0.0.1 update-source lo + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + address-family ipv4 + redistribute connected route-map connected-to-bgp + network 10.0.1.2/32 route-map set-aigp + neighbor 10.0.0.1 next-hop-self + exit-address-family +! +ip prefix-list p22 seq 5 permit 10.0.2.2/32 +! +route-map connected-to-bgp permit 10 + match ip address prefix-list p22 + set aigp 2 +! +route-map set-aigp permit 10 + set aigp 10 +! diff --git a/tests/topotests/bgp_aigp_rr/r2/ospfd.conf b/tests/topotests/bgp_aigp_rr/r2/ospfd.conf new file mode 100644 index 00000000..dd91101d --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r2/ospfd.conf @@ -0,0 +1,18 @@ +! +interface lo + ip ospf passive +! +interface r2-eth0 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +interface r2-eth1 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +router ospf + router-id 10.0.0.2 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_aigp_rr/r2/zebra.conf b/tests/topotests/bgp_aigp_rr/r2/zebra.conf new file mode 100644 index 00000000..6e2130f7 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r2/zebra.conf @@ -0,0 +1,11 @@ +! +interface lo + ip address 10.0.0.2/32 + ip address 10.0.2.2/32 +! +interface r2-eth0 + ip address 192.168.12.2/24 +! +interface r2-eth1 + ip address 192.168.23.2/24 +! diff --git a/tests/topotests/bgp_aigp_rr/r3/bgpd.conf b/tests/topotests/bgp_aigp_rr/r3/bgpd.conf new file mode 100644 index 00000000..b8a36c5a --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r3/bgpd.conf @@ -0,0 +1,11 @@ +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.1 remote-as internal + neighbor 10.0.0.1 update-source lo + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + address-family ipv4 + neighbor 10.0.0.1 next-hop-self + exit-address-family +! diff --git a/tests/topotests/bgp_aigp_rr/r3/ospfd.conf b/tests/topotests/bgp_aigp_rr/r3/ospfd.conf new file mode 100644 index 00000000..48702e4e --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r3/ospfd.conf @@ -0,0 +1,18 @@ +! +interface lo + ip ospf passive +! +interface r3-eth0 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +interface r3-eth1 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +router ospf + router-id 10.0.0.3 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_aigp_rr/r3/zebra.conf b/tests/topotests/bgp_aigp_rr/r3/zebra.conf new file mode 100644 index 00000000..ea666372 --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r3/zebra.conf @@ -0,0 +1,10 @@ +! +interface lo + ip address 10.0.0.3/32 +! +interface r3-eth0 + ip address 192.168.13.3/24 +! +interface r3-eth1 + ip address 192.168.23.3/24 +! diff --git a/tests/topotests/bgp_aigp_rr/r4/bgpd.conf b/tests/topotests/bgp_aigp_rr/r4/bgpd.conf new file mode 100644 index 00000000..b8a36c5a --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r4/bgpd.conf @@ -0,0 +1,11 @@ +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.1 remote-as internal + neighbor 10.0.0.1 update-source lo + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + address-family ipv4 + neighbor 10.0.0.1 next-hop-self + exit-address-family +! diff --git a/tests/topotests/bgp_aigp_rr/r4/ospfd.conf b/tests/topotests/bgp_aigp_rr/r4/ospfd.conf new file mode 100644 index 00000000..1d95b2ac --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r4/ospfd.conf @@ -0,0 +1,13 @@ +! +interface lo + ip ospf passive +! +interface r4-eth0 + ip ospf dead-interval 4 + ip ospf hello-interval 1 + ip ospf cost 10 +! +router ospf + router-id 10.0.0.4 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_aigp_rr/r4/zebra.conf b/tests/topotests/bgp_aigp_rr/r4/zebra.conf new file mode 100644 index 00000000..d7a7dece --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/r4/zebra.conf @@ -0,0 +1,7 @@ +! +interface lo + ip address 10.0.0.4/32 +! +interface r4-eth0 + ip address 192.168.14.4/24 +! diff --git a/tests/topotests/bgp_aigp_rr/test_bgp_aigp_rr.py b/tests/topotests/bgp_aigp_rr/test_bgp_aigp_rr.py new file mode 100644 index 00000000..206e229b --- /dev/null +++ b/tests/topotests/bgp_aigp_rr/test_bgp_aigp_rr.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2024, Palo Alto Networks, Inc. +# Enke Chen +# + +""" +r1, r2, and r3 are directly connectd to each other. +r4 is only connected to r1 directly. + +r1 is the route reflector. +r1 sets the nexthop to itself when advertising routes to r4. + +r2 sources 10.0.2.2/32 with agigp-metric 2. + +Results: + +r1, r2 and r3 should have aigp-meric 2. +r4 should have aigp-metric 12, i.e., aigp + nexthop-metric. +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_aigp_rr(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] + + def _bgp_check_aigp_metric(router, prefix, aigp): + output = json.loads( + router.vtysh_cmd("show bgp ipv4 unicast {} json".format(prefix)) + ) + expected = {"paths": [{"aigpMetric": aigp, "valid": True}]} + return topotest.json_cmp(output, expected) + + def _bgp_check_aigp_bestpath(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.0.1.2/32 json")) + expected = { + "prefix": "10.0.1.2/32", + "paths": [ + { + "aigpMetric": 50, + "valid": True, + "sourced": True, + "local": True, + "bestpath": {"overall": True, "selectionReason": "Local Route"}, + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "metric": 0, + "accessible": True, + "used": True, + } + ], + }, + { + "aigpMetric": 10, + "valid": True, + "nexthops": [ + { + "ip": "10.0.0.2", + "hostname": "r2", + "afi": "ipv4", + "metric": 10, + "accessible": True, + "used": True, + } + ], + }, + ], + } + return topotest.json_cmp(output, expected) + + # r2, 10.0.2.2/32 with aigp-metric 2 + test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.2.2/32", 2) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.2.2/32 is not 2" + + # r1, 10.0.2.2/32 with aigp-metric 2 + test_func = functools.partial(_bgp_check_aigp_metric, r1, "10.0.2.2/32", 2) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.2.2/32 is not 2" + + # r3, 10.0.2.2/32 with aigp-metric 2 + test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.2.2/32", 2) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.2.2/32 is not 2" + + # r4, 10.0.2.2/32 with aigp-metric 12: aigp + nexthop-metric + test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.2.2/32", 12) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.2.2/32 is not 12" + + # r1, check if the local route is favored over AIGP comparison + test_func = functools.partial(_bgp_check_aigp_bestpath) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "Local route is not favored over AIGP in best-path selection" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py index c49a2e53..537ccc9d 100644 --- a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py +++ b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py @@ -28,7 +28,6 @@ Following tests are covered to test bgp allowas-in functionality: import os import sys import time -import json import pytest # Save the Current Working Directory to find configuration files. @@ -59,7 +58,7 @@ from lib.bgp import ( create_router_bgp, verify_bgp_rib, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_as_override/test_bgp_as_override.py b/tests/topotests/bgp_as_override/test_bgp_as_override.py index 7cb4f81c..dbbdf2c8 100644 --- a/tests/topotests/bgp_as_override/test_bgp_as_override.py +++ b/tests/topotests/bgp_as_override/test_bgp_as_override.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py index 5c09a6b0..e8e3b417 100644 --- a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py +++ b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -85,12 +85,12 @@ def test_bgp_as_wide_bgp_identifier(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, tgen.gears["r1"]) - success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Failed to converge: "{}"'.format(tgen.gears["r1"]) test_func = functools.partial(_bgp_failed, tgen.gears["r3"]) - success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Bad BGP Identifier notification not sent: "{}"'.format( tgen.gears["r3"] diff --git a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py index 4883e847..09803dfa 100644 --- a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py +++ b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py @@ -60,7 +60,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -97,7 +97,7 @@ def test_bgp_asdot_regex(): logger.info("Check if neighbor sessions are up in {}".format(router1.name)) test_func = partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) logger.info("BGP neighbor session is up in {}".format(router1.name)) diff --git a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py index 0f1a0830..fe89a876 100644 --- a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py +++ b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py @@ -73,7 +73,7 @@ def test_bgp_aggregator_zero(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "More than one prefix seen at r1, SHOULD be only one." def _bgp_has_correct_routes_without_asn_0(): @@ -82,7 +82,7 @@ def test_bgp_aggregator_zero(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_has_correct_routes_without_asn_0) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed listing 192.168.100.101/32, SHOULD be accepted." diff --git a/tests/topotests/bgp_auth/bgp_auth_common.py b/tests/topotests/bgp_auth/bgp_auth_common.py index 824498ef..7ba3169c 100644 --- a/tests/topotests/bgp_auth/bgp_auth_common.py +++ b/tests/topotests/bgp_auth/bgp_auth_common.py @@ -34,16 +34,9 @@ for bgp instances import json import os -import platform -import sys -from time import sleep - -from lib import common_config, topotest -from lib.common_config import ( - save_initial_config_on_routers, - reset_with_new_configs, -) -from lib.topogen import Topogen, TopoRouter, get_topogen + +from lib import common_config +from lib.topogen import get_topogen CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp_auth/test_bgp_auth1.py b/tests/topotests/bgp_auth/test_bgp_auth1.py index 9d47106c..b0389474 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth1.py +++ b/tests/topotests/bgp_auth/test_bgp_auth1.py @@ -32,14 +32,12 @@ for bgp instances """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -156,7 +154,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth2.py b/tests/topotests/bgp_auth/test_bgp_auth2.py index 6b920367..2b8f4673 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth2.py +++ b/tests/topotests/bgp_auth/test_bgp_auth2.py @@ -32,14 +32,12 @@ for bgp instances """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -156,7 +154,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth3.py b/tests/topotests/bgp_auth/test_bgp_auth3.py index 2237c6b1..d103d807 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth3.py +++ b/tests/topotests/bgp_auth/test_bgp_auth3.py @@ -32,14 +32,12 @@ for bgp instances """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -155,7 +153,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth4.py b/tests/topotests/bgp_auth/test_bgp_auth4.py index d6fe4250..792aa80d 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth4.py +++ b/tests/topotests/bgp_auth/test_bgp_auth4.py @@ -32,14 +32,12 @@ for bgp instances """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -155,7 +153,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") 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 c97fc5f0..5662e593 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_bfd_down_cease_notification/r1/bfdd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf index 0ae384eb..1033b27c 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf +++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf @@ -1,5 +1,9 @@ bfd + profile r1 + exit + ! peer 192.168.255.2 interface r1-eth0 + profile r1 exit ! exit diff --git a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf index e855f75c..58a90d1a 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf +++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf @@ -3,7 +3,7 @@ router bgp 65001 neighbor 192.168.255.2 remote-as external neighbor 192.168.255.2 timers 3 10 neighbor 192.168.255.2 timers connect 1 - neighbor 192.168.255.2 bfd + neighbor 192.168.255.2 bfd profile r1 neighbor 192.168.255.2 passive address-family ipv4 redistribute connected diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py index 00142981..f18e8bd3 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py +++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -89,6 +89,9 @@ def test_bgp_bfd_down_notification(): "192.168.255.1": { "lastNotificationReason": "Cease/BFD Down", "lastNotificationHardReset": True, + "peerBfdInfo": { + "status": "Up", + }, } } return topotest.json_cmp(output, expected) diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py new file mode 100644 index 00000000..5ffeed50 --- /dev/null +++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# bgp_bfd_down_cease_notification_shutdown.py +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Check if Cease/BFD Down notification message is sent/received +when the BFD is down (administratively). +""" + +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 kill_router_daemons, step + +pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_bfd_down_notification_shutdown(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}}, + "peerBfdInfo": {"status": "Up"}, + } + } + return topotest.json_cmp(output, expected) + + def _bgp_bfd_down_notification(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "lastNotificationReason": "Cease/BFD Down", + "lastNotificationHardReset": True, + "peerBfdInfo": { + "status": "Down", + }, + } + } + return topotest.json_cmp(output, expected) + + step("Initial BGP converge") + 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 BGP convergence on R2" + + r1.vtysh_cmd( + """ + configure + bfd + profile r1 + shutdown + """ + ) + + step("Check if we received Cease/BFD Down notification message") + test_func = functools.partial(_bgp_bfd_down_notification) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see BGP Cease/BFD Down notification message on R2" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py index 9f5c0ef9..05a9a1e7 100644 --- a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py +++ b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -125,14 +125,14 @@ def test_bgp_blackhole_community(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"]) step("Check if 172.16.255.254/32 is not advertised to eBGP peers") test_func = functools.partial(_bgp_no_advertise_ebgp) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None @@ -142,7 +142,7 @@ def test_bgp_blackhole_community(): step("Check if 172.16.255.254/32 is advertised to iBGP peers") test_func = functools.partial(_bgp_no_advertise_ibgp) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None @@ -152,7 +152,7 @@ def test_bgp_blackhole_community(): step("Verify if the nexthop set via route-map on r4 is marked valid") test_func = functools.partial(_bgp_verify_nexthop_validity) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Nexthops are not valid "{}"'.format(tgen.gears["r4"]) diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp.py b/tests/topotests/bgp_bmp/test_bgp_bmp.py index 02de8050..80e291b2 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp.py @@ -26,7 +26,6 @@ from functools import partial from ipaddress import ip_network import json import os -import platform import pytest import sys diff --git a/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py b/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py index e0c1b495..09091198 100644 --- a/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py +++ b/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py @@ -16,7 +16,6 @@ import os import sys import json import functools -from functools import partial import pytest # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py index efc8f200..2064dac6 100644 --- a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py +++ b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py index de69ea93..d0cab26e 100644 --- a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py +++ b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py @@ -56,7 +56,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py index 324f53f3..82a67a0b 100644 --- a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py +++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py @@ -171,7 +171,6 @@ def test_bgp_no_export_local_as_communities_p0(request): ) for comm_type in ["no-export", "local-AS"]: - step("Create a route-map on R1 to set community as {}".format(comm_type)) seq_id = 10 diff --git a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py index fdae9a3a..9df73a51 100644 --- a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py +++ b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -92,7 +92,7 @@ def test_bgp_community_alias(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP community aliases at r1" def _bgp_show_prefixes_by_alias(router): @@ -118,7 +118,7 @@ def test_bgp_community_alias(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_show_prefixes_by_alias, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP prefixes by community alias at r1" def _bgp_show_prefixes_by_large_community_list(router): @@ -129,7 +129,7 @@ def test_bgp_community_alias(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_show_prefixes_by_large_community_list, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP prefixes by large community list at r1" diff --git a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py index 5ad15e06..c0a92efb 100644 --- a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py +++ b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py @@ -97,7 +97,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -133,7 +133,7 @@ def test_bgp_community_update_path_change(): step("Check if an initial topology is converged") test_func = functools.partial(_bgp_converge_initial) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in c1" step("Disable link between y1 and y2") @@ -146,7 +146,7 @@ def test_bgp_community_update_path_change(): step("Check if a topology is converged after a link down between y1 and y2") test_func = functools.partial(_bgp_converge_link_disabled) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in y1" def _bgp_check_for_duplicate_updates(): @@ -193,7 +193,7 @@ def test_bgp_community_update_path_change(): step("Check if a topology is converged after a link up between y1 and y2") test_func = functools.partial(_bgp_converge_link_enabled) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in y1" step( diff --git a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py index 0128c883..577bf9fd 100644 --- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py +++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py @@ -159,7 +159,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -426,7 +426,7 @@ def test_bgp_conditional_advertisement_tc_2_1(): ) test_func = functools.partial(exist_map_routes_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC21: exist-map routes present in "router2" BGP table - ' assert result is None, msg + failed @@ -455,7 +455,7 @@ def test_bgp_conditional_advertisement_tc_2_2(): ) test_func = functools.partial(exist_map_routes_not_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC22: exist-map routes not present in "router2" BGP table - ' assert result is None, msg + failed @@ -484,7 +484,7 @@ def test_bgp_conditional_advertisement_tc_2_3(): ) test_func = functools.partial(default_route_withdrawn, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC23: advertise-map with exist-map configuration is removed from peer - " assert result is None, msg + failed @@ -513,7 +513,7 @@ def test_bgp_conditional_advertisement_tc_3_1(): ) test_func = functools.partial(non_exist_map_routes_not_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC31: non-exist-map routes not present in "router2" BGP table - ' assert result is None, msg + failed @@ -542,7 +542,7 @@ def test_bgp_conditional_advertisement_tc_3_2(): ) test_func = functools.partial(non_exist_map_routes_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC32: non-exist-map routes present in "router2" BGP table - ' assert result is None, msg + failed @@ -571,7 +571,7 @@ def test_bgp_conditional_advertisement_tc_3_3(): ) test_func = functools.partial(all_routes_advertised, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = ( "TC33: advertise-map with non-exist-map configuration is removed from a peer - " @@ -603,7 +603,7 @@ def test_bgp_conditional_advertisement_tc_4_1(): ) test_func = functools.partial(non_exist_map_no_condition_route_map, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC41: non-exist-map route-map removed in "router2" - ' assert result is None, msg + failed @@ -632,7 +632,7 @@ def test_bgp_conditional_advertisement_tc_4_2(): ) test_func = functools.partial(exist_map_no_condition_route_map, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC42: exist-map route-map removed in "router2" - ' assert result is None, msg + failed @@ -665,7 +665,7 @@ def test_bgp_conditional_advertisement_tc_5_1(): ) test_func = functools.partial(exist_map_routes_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC51: exist-map routes present with route-map filter - " assert result is None, msg + failed @@ -694,7 +694,7 @@ def test_bgp_conditional_advertisement_tc_5_2(): ) test_func = functools.partial(exist_map_routes_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC52: exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -724,7 +724,7 @@ def test_bgp_conditional_advertisement_tc_5_3(): ) test_func = functools.partial(non_exist_map_routes_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC53: non-exist-map routes present, with route-map filter - " assert result is None, msg + failed @@ -753,7 +753,7 @@ def test_bgp_conditional_advertisement_tc_5_4(): ) test_func = functools.partial(non_exist_map_routes_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC54: non-exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -791,7 +791,7 @@ def test_bgp_conditional_advertisement_tc_6_1(): ) test_func = functools.partial(exist_map_routes_not_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC61: exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -820,7 +820,7 @@ def test_bgp_conditional_advertisement_tc_6_2(): ) test_func = functools.partial(exist_map_routes_not_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC62: exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -850,7 +850,7 @@ def test_bgp_conditional_advertisement_tc_6_3(): ) test_func = functools.partial(non_exist_map_routes_not_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC63: non-exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -881,7 +881,7 @@ def test_bgp_conditional_advertisement_tc_6_4(): test_func = functools.partial( non_exist_map_routes_not_present_no_rmap_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC64: non-exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -919,7 +919,7 @@ def test_bgp_conditional_advertisement_tc_7_1(): ) test_func = functools.partial(exist_map_routes_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC71: exist-map routes present, route-map filter - " assert result is None, msg + failed @@ -948,7 +948,7 @@ def test_bgp_conditional_advertisement_tc_7_2(): ) test_func = functools.partial(exist_map_routes_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC72: exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -978,7 +978,7 @@ def test_bgp_conditional_advertisement_tc_7_3(): ) test_func = functools.partial(non_exist_map_routes_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC73: non-exist-map routes present, route-map filter - " assert result is None, msg + failed @@ -1007,7 +1007,7 @@ def test_bgp_conditional_advertisement_tc_7_4(): ) test_func = functools.partial(non_exist_map_routes_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC74: non-exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -1045,7 +1045,7 @@ def test_bgp_conditional_advertisement_tc_8_1(): ) test_func = functools.partial(exist_map_routes_not_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC81: exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -1074,7 +1074,7 @@ def test_bgp_conditional_advertisement_tc_8_2(): ) test_func = functools.partial(exist_map_routes_not_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC82: exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -1106,7 +1106,7 @@ def test_bgp_conditional_advertisement_tc_8_3(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC83: non-exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -1137,7 +1137,7 @@ def test_bgp_conditional_advertisement_tc_8_4(): test_func = functools.partial( non_exist_map_routes_not_present_no_rmap2_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC84: non-exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -1175,7 +1175,7 @@ def test_bgp_conditional_advertisement_tc_9_1(): ) test_func = functools.partial(exist_map_routes_present_rmap2_network, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC91: exist-map routes present, route-map filter and network - " assert result is None, msg + failed @@ -1204,7 +1204,7 @@ def test_bgp_conditional_advertisement_tc_9_2(): ) test_func = functools.partial(exist_map_routes_present_rmap2_no_network, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC92: exist-map routes present, route-map filter and no network - " assert result is None, msg + failed @@ -1244,7 +1244,7 @@ def test_bgp_conditional_advertisement_tc_9_3(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_network, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC93: non-exist-map routes not present, route-map filter and network - " assert result is None, msg + failed @@ -1275,7 +1275,7 @@ def test_bgp_conditional_advertisement_tc_9_4(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_no_network, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC94: non-exist-map routes not present, route-map filter and no network - " assert result is None, msg + failed diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py index e9114bdb..ea0f53cc 100644 --- a/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py +++ b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py @@ -11,7 +11,6 @@ if we modify the prefix-lists. """ import os -import re import sys import json import pytest @@ -24,7 +23,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py index e7630729..bb98e2fa 100644 --- a/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py +++ b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py index 7bc00501..44b1a2f7 100644 --- a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py +++ b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py @@ -35,7 +35,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py b/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py index 2066d848..f8916e1c 100644 --- a/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py +++ b/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py @@ -6,7 +6,6 @@ # import os -import re import sys import json import pytest diff --git a/tests/topotests/bgp_dampening_per_safi/__init__.py b/tests/topotests/bgp_dampening_per_safi/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/topotests/bgp_dampening_per_safi/r1/frr.conf b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf new file mode 100644 index 00000000..b4e82f58 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf @@ -0,0 +1,13 @@ +! +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 + address-family ipv4 unicast + bgp dampening 1 1 1 1 + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_safi/r2/frr.conf b/tests/topotests/bgp_dampening_per_safi/r2/frr.conf new file mode 100644 index 00000000..d68d13d0 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/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/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py new file mode 100644 index 00000000..c8d7e675 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import re +import sys +import json +import pytest +import functools + +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_dampening_per_peer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _show_dampening_parameters(): + output = json.loads(r1.vtysh_cmd("show ip bgp dampening parameters json")) + expected = { + "halfLifeSecs": 60, + "reusePenalty": 1, + "suppressPenalty": 1, + "maxSuppressTimeSecs": 60, + "maxSuppressPenalty": 2, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _show_dampening_parameters, + ) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=1) + assert result is None, "Can't show BGP per-safi dampening parameters" + + 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" + + #### + # Withdraw 10.10.10.10/32, and check if it's flagged as history. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + no redistribute connected + """ + ) + + def _check_bgp_dampening_history(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "dampeningHistoryEntry": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_history, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as history entry" + + #### + # Reannounce 10.10.10.10/32, and check if it's flagged as dampened. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + redistribute connected + """ + ) + + def _check_bgp_dampening_dampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningSuppressed": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_dampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as dampened entry" + + #### + # Check if the route becomes non-dampened again after some time. + #### + def _check_bgp_dampening_undampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningHistoryEntry": None, + "dampeningSuppressed": None, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_undampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=10) + assert result is None, "10.10.10.10/32 is flagged as history/dampened" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py index 05e07486..48dddb46 100644 --- a/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py +++ b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) 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 75e66566..bcdd9878 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 @@ -17,7 +17,6 @@ import sys import time import pytest import datetime -from copy import deepcopy from lib.topolog import logger from time import sleep @@ -214,7 +213,6 @@ def get_rib_route_uptime(tgen, addr_type, dut, input_dict): logger.info("Entering lib API: get_rib_route_uptime()") route_time = [] - out_route_dict = {} router_list = tgen.routers() for routerInput in input_dict.keys(): for router, rnode in router_list.items(): @@ -234,7 +232,6 @@ def get_rib_route_uptime(tgen, addr_type, dut, input_dict): for static_route in static_routes: if "vrf" in static_route and static_route["vrf"] is not None: - logger.info( "[DUT: {}]: Verifying routes for VRF:" " {}".format(router, static_route["vrf"]) @@ -269,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 ) ) @@ -307,7 +304,6 @@ def get_best_path_route_in_FIB(tgen, topo, dut, network): on failure : return error message with boolean False """ is_ipv4_best_path_found = False - is_ipv6_best_path_found = False rnode = tgen.routers()[dut] ipv4_show_bgp_json = run_frr_cmd(rnode, "sh ip bgp json ", isjson=True) ipv6_show_bgp_json = run_frr_cmd( @@ -1031,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) @@ -1078,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, @@ -1097,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) @@ -1575,7 +1572,7 @@ def test_verify_default_originate_with_2way_ecmp_p2(request): ipv_dict = get_best_path_route_in_FIB(tgen, topo, dut="r2", network=network) dut_links = topo["routers"]["r1"]["links"] active_interface = None - for key, values in dut_links.items(): + for key, _ in dut_links.items(): ipv4_address = dut_links[key]["ipv4"].split("/")[0] ipv6_address = dut_links[key]["ipv6"].split("/")[0] if ipv_dict["ipv4"] == ipv4_address and ipv_dict["ipv6"] == ipv6_address: diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py index 50a1938a..142b3e43 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py @@ -18,8 +18,6 @@ import os import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -30,32 +28,18 @@ from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, - verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, get_prefix_count_route, get_dut_as_number, verify_rib_default_route, - verify_fib_default_route, - verify_bgp_advertised_routes_from_neighbor, - verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_fib_routes, - kill_router_daemons, - start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py index 4e8bda55..a6918916 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py @@ -17,8 +17,6 @@ import os import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -31,13 +29,8 @@ from lib.bgp import ( verify_bgp_convergence, verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, - get_prefix_count_route, get_dut_as_number, verify_rib_default_route, verify_fib_default_route, @@ -45,16 +38,12 @@ from lib.bgp import ( verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_fib_routes, kill_router_daemons, start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, @@ -65,7 +54,6 @@ from lib.common_config import ( reset_config_on_routers, create_static_routes, check_router_status, - delete_route_maps, ) 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 4dedac55..905c3e2b 100644 --- a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py +++ b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py @@ -10,8 +10,6 @@ import os import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -22,32 +20,17 @@ from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, - verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, get_prefix_count_route, get_dut_as_number, - verify_rib_default_route, - verify_fib_default_route, - verify_bgp_advertised_routes_from_neighbor, - verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_rib, - kill_router_daemons, - start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, @@ -58,7 +41,6 @@ from lib.common_config import ( reset_config_on_routers, create_static_routes, check_router_status, - delete_route_maps, ) pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] @@ -564,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_default_originate/test_default_originate_conditional_routemap.py b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py index f67a431c..97a7e62e 100644 --- a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py +++ b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py @@ -19,7 +19,6 @@ import os import sys import time import pytest -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 diff --git a/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py b/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py index b2ba936f..c7c40c1b 100644 --- a/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py +++ b/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py index e25f85af..cd4acc9a 100644 --- a/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py +++ b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_route/test_bgp_default-originate.py b/tests/topotests/bgp_default_route/test_bgp_default-originate.py index 333beb06..e805d06a 100644 --- a/tests/topotests/bgp_default_route/test_bgp_default-originate.py +++ b/tests/topotests/bgp_default_route/test_bgp_default-originate.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -85,19 +85,19 @@ def test_bgp_default_originate_route_map(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_check_if_received) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "No 0.0.0.0/0 at r2 from r1" test_func = functools.partial(_bgp_check_if_originated) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "No 0.0.0.0/0 from r1 to r2" test_func = functools.partial(_bgp_route_is_valid, tgen.gears["r2"], "0.0.0.0/0") - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see 0.0.0.0/0 in r2" test_func = functools.partial(_bgp_route_is_valid, tgen.gears["r2"], "0.0.0.0/1") - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see 0.0.0.0/1 in r2" diff --git a/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py b/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py index 9dcb5a1e..d866b95f 100644 --- a/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py +++ b/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -80,12 +80,12 @@ def test_bgp_default_originate_route_map(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py b/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py index 965d348b..5a99878b 100644 --- a/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py +++ b/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -84,7 +84,7 @@ def test_bgp_default_originate_route_map(): step("Converge network") test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see bgp convergence at r2" step("Withdraw 10.0.0.0/22 from R2") @@ -94,7 +94,7 @@ def test_bgp_default_originate_route_map(): step("Check if we don't have 0.0.0.0/0 at R2") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) assert result is not None, "0.0.0.0/0 exists at r2" step("Announce 10.0.0.0/22 from R2") @@ -102,7 +102,7 @@ def test_bgp_default_originate_route_map(): step("Check if we have 0.0.0.0/0 at R2") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "0.0.0.0/0 does not exist at r2" step("Withdraw 10.0.0.0/22 from R2 again") @@ -112,7 +112,7 @@ def test_bgp_default_originate_route_map(): step("Check if we don't have 0.0.0.0/0 at R2 again") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) assert result is not None, "0.0.0.0/0 exists at r2" diff --git a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py index f94620b2..3a374c6e 100644 --- a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py +++ b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -90,12 +90,12 @@ def test_bgp_default_originate_route_map(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_default_route_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py b/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py index e633b61d..ba278295 100644 --- a/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py +++ b/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py b/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py index 70562ce3..69780087 100644 --- a/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py +++ b/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -98,7 +98,7 @@ def test_bgp_disable_addpath_rx(): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_advertised_routes, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "AddPath TX not working." step("Check if AddPath RX is disabled on r1 and we receive only 2 paths.") @@ -120,7 +120,7 @@ def test_bgp_disable_addpath_rx(): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_disabled_addpath_rx, r1) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "AddPath RX advertised, but should not." diff --git a/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py b/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py index 0bd3d281..0307ee2f 100755 --- a/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py +++ b/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py @@ -215,7 +215,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Configure static route in R4 and R5, redistribute in bgp") for addr_type in ADDR_TYPES: - input_dict = { "r4": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -228,7 +227,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): ) for addr_type in ADDR_TYPES: - input_dict = { "r5": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -268,7 +266,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Configure the static route in R3 (Dut).") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -305,7 +302,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step(" Configure the admin distance of 254 to static route in R3.") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -571,7 +567,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Reconfigure the static route without admin distance") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -993,7 +988,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Configure static route Without any admin distance") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -1009,7 +1003,6 @@ def test_bgp_admin_distance_ibgp_p0(): protocol = "static" for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -1023,7 +1016,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Configure static route with admin distance of 253") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -1086,7 +1078,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Delete the static route.") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ diff --git a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py index 2ca50aa5..87802511 100644 --- a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py +++ b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -101,14 +101,14 @@ def test_bgp_maximum_prefix_invalid(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) _bgp_distance_change(router) test_func = functools.partial(_bgp_check_distance_change, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see applied BGP distance in RIB "{}"'.format( router diff --git a/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py b/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py index 82693222..28d6b563 100644 --- a/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py +++ b/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_dual_as/__init__.py b/tests/topotests/bgp_dual_as/__init__.py new file mode 100644 index 00000000..e69de29b 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 00000000..9dcfe05d --- /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 00000000..a901d49a --- /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 00000000..b202d781 --- /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 +# + +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_duplicate_nexthop/r1/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf new file mode 100644 index 00000000..80849625 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf @@ -0,0 +1,14 @@ +router bgp 64500 + bgp router-id 192.0.2.1 + timers bgp 3 9 + no bgp ebgp-requires-policy + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver timers connect 2 + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + neighbor rrserver next-hop-self + neighbor rrserver activate + exit-address-family +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf new file mode 100644 index 00000000..9660577f --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf @@ -0,0 +1,26 @@ +hostname r1 +interface lo + ip router isis 1 + isis passive +! +interface r1-eth1 + ip router isis 1 + isis network point-to-point +! +interface r1-eth2 + ip router isis 1 + isis network point-to-point +! +interface r1-eth4 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0001.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.1/32 index 1 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf new file mode 100644 index 00000000..2e3549a5 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf @@ -0,0 +1,24 @@ +log stdout +interface lo + ip address 192.0.2.1/32 +! +interface r1-eth0 + ip address 172.31.10.1/24 +! +interface r1-eth1 + ip address 172.31.0.1/24 + mpls enable +! +interface r1-eth2 + ip address 172.31.2.1/24 + mpls enable +! +interface r1-eth3 + ip address 172.31.11.1/24 + mpls enable +! +interface r1-eth4 + ip address 172.31.8.1/24 + mpls enable +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf new file mode 100644 index 00000000..7312dba4 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf @@ -0,0 +1,17 @@ +router bgp 64500 view one + timers bgp 3 9 + bgp router-id 192.0.2.3 + neighbor rr peer-group + neighbor rr remote-as 64500 + neighbor rr update-source lo + neighbor 192.0.2.1 peer-group rr + neighbor 192.0.2.5 peer-group rr + neighbor 192.0.2.6 peer-group rr + neighbor 192.0.2.8 peer-group rr + ! + address-family ipv4 unicast + neighbor rr activate + neighbor rr route-reflector-client + neighbor rr addpath-tx-all-paths + exit-address-family +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf new file mode 100644 index 00000000..ae6bddee --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf @@ -0,0 +1,38 @@ +hostname r3 +interface lo + ip router isis 1 + isis passive +! +interface r3-eth0 + ip router isis 1 + isis network point-to-point +! +interface r3-eth1 + ip router isis 1 + isis network point-to-point +! +interface r3-eth2 + ip router isis 1 + isis network point-to-point +! +interface r3-eth3 + ip router isis 1 + isis network point-to-point +! +interface r3-eth4 + ip router isis 1 + isis network point-to-point +! +interface r3-eth5 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0003.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.3/32 index 3 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf new file mode 100644 index 00000000..05b3769f --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf @@ -0,0 +1,16 @@ +log stdout +interface lo + ip address 192.0.2.3/32 +! +interface r3-eth0 + ip address 172.31.0.3/24 + mpls enable +! +interface r3-eth1 + ip address 172.31.4.3/24 + mpls enable +! +interface r3-eth2 + ip address 172.31.5.3/24 + mpls enable +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf new file mode 100644 index 00000000..4d49d0de --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf @@ -0,0 +1,30 @@ +hostname r4 +interface lo + ip router isis 1 + isis passive +! +interface r4-eth0 + ip router isis 1 + isis network point-to-point +! +interface r4-eth1 + ip router isis 1 + isis network point-to-point +! +interface r4-eth2 + ip router isis 1 + isis network point-to-point +! +interface r4-eth3 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0004.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.4/32 index 4 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf new file mode 100644 index 00000000..9ea1b7ec --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf @@ -0,0 +1,20 @@ +log stdout +interface lo + ip address 192.0.2.4/32 +! +interface r4-eth0 + ip address 172.31.2.4/24 + mpls enable +! +interface r4-eth1 + ip address 172.31.6.4/24 + mpls enable +! +interface r4-eth2 + ip address 172.31.7.4/24 + mpls enable +! +interface r4-eth3 + mpls enable +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf new file mode 100644 index 00000000..e46d7c5e --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf @@ -0,0 +1,20 @@ +router bgp 64500 + timers bgp 3 9 + bgp router-id 192.0.2.5 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver timers connect 2 + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + network 192.0.2.9/32 + network 192.0.2.8/32 route-map rmap + neighbor rrserver activate + neighbor rrserver addpath-tx-all-paths + exit-address-family +! +route-map rmap permit 1 + set ip next-hop 192.0.2.9 +exit diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf new file mode 100644 index 00000000..46556d9a --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf @@ -0,0 +1,26 @@ +hostname r5 +interface lo + ip router isis 1 + isis passive +! +interface r5-eth1 + ip router isis 1 + isis network point-to-point +! +interface r5-eth2 + ip router isis 1 + isis network point-to-point +! +interface r5-eth3 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0005.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.5/32 index 55 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf new file mode 100644 index 00000000..6f326561 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf @@ -0,0 +1,19 @@ +log stdout +mpls label dynamic-block 5000 5999 +interface lo + ip address 192.0.2.5/32 +! +interface r5-eth0 + ip address 172.31.12.5/24 +! +interface r5-eth1 + ip address 172.31.4.5/24 + mpls enable +! +interface r5-eth2 + ip address 172.31.7.5/24 + mpls enable +! +interface r5-eth3 + ip address 172.31.21.5/24 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf new file mode 100644 index 00000000..3aa9adb1 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf @@ -0,0 +1,20 @@ +router bgp 64500 + timers bgp 3 9 + bgp router-id 192.0.2.6 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver bfd + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + network 192.0.2.9/32 + network 192.0.2.8/32 route-map rmap + neighbor rrserver activate + neighbor rrserver addpath-tx-all-paths + exit-address-family +! +route-map rmap permit 1 + set ip next-hop 192.0.2.9 +exit diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf new file mode 100644 index 00000000..5126a648 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf @@ -0,0 +1,22 @@ +hostname r6 +interface lo + ip router isis 1 + isis passive +! +interface r6-eth1 + ip router isis 1 + isis network point-to-point +! +interface r6-eth2 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0006.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.6/32 index 6 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf new file mode 100644 index 00000000..cda62d7e --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf @@ -0,0 +1,20 @@ +log stdout +mpls label dynamic-block 6000 6999 +interface lo + ip address 192.0.2.6/32 +! +interface r6-eth0 + ip address 172.31.13.6/24 +! +interface r6-eth1 + ip address 172.31.5.6/24 + mpls enable +! +interface r6-eth2 + ip address 172.31.6.6/24 + mpls enable +! +interface r6-eth3 + ip address 172.31.22.6/24 +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py new file mode 100644 index 00000000..5c125869 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py @@ -0,0 +1,458 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_bgp_duplicate_nexthop.py +# +# Copyright 2024 6WIND S.A. +# + +r""" + test_bgp_nhg_duplicate_nexthop.py: + Check that the FRR BGP daemon on r1 selects updates with same nexthops + + ++---+----+ +---+----+ +--------+ +| | | + | | +| r1 +----------+ r3 +----------+ r5 + +| | | rr + +-----+ | ++++-+----+ +--------+\ / +--------+ + | \/ + | /\ + | +--------+/ \ +--------+ + | | + +-----+ + + +---------------+ r4 +----------+ r6 + + | | | | + +--------+ +--------+ +""" + +import os +import sys +import json +from functools import partial +import pytest +import functools + +# 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.common_check import ip_check_path_selection, iproute2_check_path_selection +from lib.common_config import step +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + "Build function" + + # Create 7 PE routers. + tgen.add_router("r1") + tgen.add_router("r3") + tgen.add_router("r4") + tgen.add_router("r5") + tgen.add_router("r6") + + # switch + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s9") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s10") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s11") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s12") + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s13") + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s14") + switch.add_link(tgen.gears["r1"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + if rname in ("r1", "r3", "r5", "r6"): + 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 check_ipv4_prefix_with_multiple_nexthops(prefix, multipath=True): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info( + f"Check that {prefix} unicast entry is installed with paths for r5 and r6" + ) + + r5_nh = [ + { + "ip": "192.0.2.5", + "active": True, + "recursive": True, + }, + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16055, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16055, + ], + }, + ] + + r6_nh = [ + { + "ip": "192.0.2.6", + "active": True, + "recursive": True, + }, + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16006, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16006, + ], + }, + ] + + expected = { + prefix: [ + { + "prefix": prefix, + "protocol": "bgp", + "metric": 0, + "table": 254, + "nexthops": [], + } + ] + } + for nh in r5_nh: + expected[prefix][0]["nexthops"].append(nh) + if multipath: + for nh in r6_nh: + expected[prefix][0]["nexthops"].append(nh) + + test_func = functools.partial( + ip_check_path_selection, tgen.gears["r1"], prefix, expected + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} uses the IGP label 16055 and 16006" + + +def get_nh_formatted(nexthop, fib=True, duplicate=False): + nh = dict(nexthop) + if duplicate: + nh.update({"duplicate": True}) + if fib: + nh.update({"fib": True}) + return nh + + +def check_ipv4_prefix_recursive_with_multiple_nexthops( + prefix, recursive_nexthop, multipath=True +): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + logger.info( + f"Check that {prefix} unicast entry is correctly recursive via {recursive_nexthop} with paths for r5 and r6" + ) + + r5_nh = [ + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16055, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16055, + ], + }, + ] + + r6_nh = [ + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16006, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16006, + ], + }, + ] + + expected = { + prefix: [ + { + "prefix": prefix, + "protocol": "bgp", + "metric": 0, + "table": 254, + "nexthops": [], + } + ] + } + + recursive_nh = [ + { + "ip": recursive_nexthop, + "active": True, + "recursive": True, + }, + ] + for nh in recursive_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh, fib=False)) + + for nh in r5_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh)) + + if multipath: + for nh in r6_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh)) + + for nh in recursive_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + for nh in r5_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + for nh in r6_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + test_func = functools.partial( + ip_check_path_selection, tgen.gears["r1"], prefix, expected, check_fib=True + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} is correctly recursive via {recursive_nexthop}" + + +def check_ipv4_prefix_with_multiple_nexthops_linux(prefix): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step( + f"Check that {prefix} unicast entry is installed with paths for r5 and r6 on Linux" + ) + + r5_nh = [ + { + "encap": "mpls", + "dst": "16055", + "gateway": "172.31.0.3", + "dev": "r1-eth1", + }, + { + "encap": "mpls", + "dst": "16055", + "gateway": "172.31.2.4", + "dev": "r1-eth2", + }, + ] + + r6_nh = [ + { + "encap": "mpls", + "dst": "16006", + "gateway": "172.31.0.3", + "dev": "r1-eth1", + }, + { + "encap": "mpls", + "dst": "16006", + "gateway": "172.31.2.4", + "dev": "r1-eth2", + }, + ] + + expected = [ + { + "dst": prefix, + "protocol": "bgp", + "metric": 20, + "nexthops": [], + } + ] + + # only one path + for nh in r5_nh: + expected[0]["nexthops"].append(nh) + for nh in r6_nh: + expected[0]["nexthops"].append(nh) + + test_func = functools.partial( + iproute2_check_path_selection, tgen.routers()["r1"], prefix, expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} unicast entry is installed with paths for r5 and r6 on Linux" + + +def test_bgp_ipv4_convergence(): + """ + Check that R1 has received the 192.0.2.9/32 prefix from R5, and R6 + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Ensure that the 192.0.2.9/32 route is available") + check_ipv4_prefix_with_multiple_nexthops("192.0.2.9/32") + + check_ipv4_prefix_with_multiple_nexthops_linux("192.0.2.9") + + +def test_bgp_ipv4_recursive_routes(): + """ + Check that R1 has received the recursive routes, and duplicate nexthops are in zebra, but are not installed + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ipv4_prefix_recursive_with_multiple_nexthops("192.0.2.8/32", "192.0.2.9") + + check_ipv4_prefix_with_multiple_nexthops_linux("192.0.2.8") + + +def test_bgp_ipv4_recursive_routes_when_no_mpath(): + """ + Unconfigure multipath ibgp + Check that duplicate nexthops are not in zebra + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + router bgp + address family ipv4 unicast + maximum-paths ibgp 1 + """, + isjson=False, + ) + tgen.gears["r1"].vtysh_cmd("clear bgp ipv4 *") + check_ipv4_prefix_with_multiple_nexthops("192.0.2.9/32", multipath=False) + + check_ipv4_prefix_recursive_with_multiple_nexthops( + "192.0.2.8/32", "192.0.2.9", multipath=False + ) + + +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_dynamic_capability/test_bgp_dynamic_capability_addpath.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py index 4d7d46c3..91df89b1 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py @@ -14,7 +14,6 @@ T4: Disable Addpath capability and check if it's exchanged dynamically """ import os -import re import sys import json import pytest @@ -27,7 +26,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen def setup_module(mod): diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py index 26fae17c..bf05ce8e 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py @@ -10,7 +10,6 @@ Test if fqdn capability is exchanged dynamically. """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py index d67bfea4..514b29cd 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py @@ -12,7 +12,6 @@ via BGP dynamic capability. """ import os -import re import sys import json import pytest @@ -25,7 +24,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py index 9e1f26f2..39e7ded1 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py @@ -10,7 +10,6 @@ Test if ORF capability is adjusted dynamically. """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py index f6c1e25f..7d366347 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py @@ -10,7 +10,6 @@ Test if role capability is exchanged dynamically. """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py index 128283bb..591fc5a8 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py @@ -23,7 +23,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py b/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py index d9ccd697..a4ac249c 100644 --- a/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py +++ b/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py @@ -52,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -90,7 +90,7 @@ def test_bgp_ebgp_common_subnet_nh_unchanged(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, r3) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(r3) @@ -100,7 +100,7 @@ def test_bgp_ebgp_common_subnet_nh_unchanged(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_nh_unchanged, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Wrong next-hop in "{}"'.format(r2) diff --git a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py index 6e3b2859..f7c0f704 100644 --- a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py +++ b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py @@ -71,7 +71,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -125,31 +125,31 @@ def test_ebgp_requires_policy(): # Scenario 1. logger.info("Scenario 1: r2 receives 192.168.255.1/32 from r1") test_func = functools.partial(_bgp_converge, "r2") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r2)" test_func = functools.partial(_bgp_has_routes, "r2") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r2 does not receive 192.168.255.1/32" # Scenario 2. logger.info("Scenario 2: r3 must not send 192.168.255.1/32 to r4") test_func = functools.partial(_bgp_converge, "r4") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r4)" test_func = functools.partial(_bgp_advertised_routes, "r3") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r3 announced 192.168.255.1/32 to r4" # Scenario 3. logger.info("Scenario 3: r6 receives 192.168.255.1/32 from r5 (iBGP)") test_func = functools.partial(_bgp_converge, "r6") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r6)" test_func = functools.partial(_bgp_has_routes, "r6") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r6 does not receive 192.168.255.1/32" diff --git a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py index b347042d..5991f2e7 100644 --- a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py +++ b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py @@ -106,7 +106,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format( BGP_CONVERGENCE @@ -153,7 +153,6 @@ def teardown_module(): def static_or_nw(tgen, topo, tc_name, test_type, dut): - if test_type == "redist_static": input_dict_static = { dut: { @@ -363,7 +362,6 @@ def test_ecmp_remove_redistribute_static(request): reset_config_on_routers(tgen) static_or_nw(tgen, topo, tc_name, "redist_static", "r2") for addr_type in ADDR_TYPES: - # Verifying RIB routes dut = "r3" protocol = "bgp" @@ -406,7 +404,6 @@ def test_ecmp_remove_redistribute_static(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - # Verifying RIB routes dut = "r3" protocol = "bgp" diff --git a/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py b/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py index 5469eff1..876c205f 100644 --- a/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py +++ b/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py @@ -6,7 +6,6 @@ # import os -import re import sys import json import pytest @@ -17,7 +16,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py index b033e9c2..ba2fb626 100644 --- a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py +++ b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py @@ -455,7 +455,7 @@ def check_remote_es(esi, vtep_ips, dut_name, down_vteps): else: tor_ips_rack = tor_ips_rack_1 - for tor_name, tor_ip in tor_ips_rack.items(): + for _, tor_ip in tor_ips_rack.items(): remote_ips.append(tor_ip) # remove down VTEPs from the remote check list diff --git a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py index 603f069f..d441a256 100755 --- a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py +++ b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py @@ -241,7 +241,7 @@ def evpn_gateway_ip_show_op_check(trigger=" "): expected_op = json.loads(open(expected_op_file).read()) test_func = partial(topotest.router_json_cmp, pe, command, expected_op) - ret, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assertmsg = '"{0}" JSON output mismatch for {1}'.format(name, command) if result is not None: return result, assertmsg diff --git a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py index 2df0fd0e..36c79d6b 100644 --- a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py +++ b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py @@ -10,7 +10,6 @@ Test if route-map match by EVPN route-type works. """ import os -import re import sys import json import pytest @@ -23,8 +22,7 @@ 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 +from lib.topogen import Topogen, get_topogen def setup_module(mod): diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf index ccbeae6e..c8c4faf2 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf @@ -20,7 +20,11 @@ router bgp 65000 vrf r1-vrf-101 address-family ipv4 unicast network 192.168.102.21/32 exit-address-family + address-family ipv6 unicast + network fd00::1/128 + exit-address-family address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! diff --git a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf index 4f1804c6..c3d508c2 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf @@ -17,6 +17,7 @@ interface r1-eth0 ! interface loop101 vrf r1-vrf-101 ip address 192.168.102.21/32 + ipv6 address fd00::1/128 ! diff --git a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf index 744c259d..de5a0efc 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf @@ -21,7 +21,11 @@ router bgp 65000 vrf r2-vrf-101 address-family ipv4 unicast network 192.168.101.41/32 exit-address-family + address-family ipv6 unicast + network fd00::2/128 + exit-address-family address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! diff --git a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf index 7d19a5b3..7db40cb5 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf @@ -11,6 +11,7 @@ vrf r2-vrf-101 ! interface loop101 vrf r2-vrf-101 ip address 192.168.101.41/32 + ipv6 address fd00::2/128 ! interface r2-eth0 ip address 192.168.100.41/24 diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py index d9177b4d..2d027081 100644 --- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py +++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py @@ -25,6 +25,8 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest +from lib.bgp import verify_bgp_rib +from lib.common_config import apply_raw_config from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger @@ -179,12 +181,18 @@ def test_protocols_convergence(): output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101 ipv4", isjson=False) logger.info("==== result from show bgp vrf r1-vrf-101 ipv4") logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101 ipv6", isjson=False) + logger.info("==== result from show bgp vrf r1-vrf-101 ipv6") + logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101", isjson=False) logger.info("==== result from show bgp vrf r1-vrf-101 ") logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show ip route vrf r1-vrf-101", isjson=False) logger.info("==== result from show ip route vrf r1-vrf-101") logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show ipv6 route vrf r1-vrf-101", isjson=False) + logger.info("==== result from show ipv6 route vrf r1-vrf-101") + logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show evpn vni detail", isjson=False) logger.info("==== result from show evpn vni detail") logger.info(output) @@ -192,8 +200,49 @@ def test_protocols_convergence(): logger.info("==== result from show evpn next-hops vni all") logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show evpn rmac vni all", isjson=False) - logger.info("==== result from show evpn next-hops vni all") + logger.info("==== result from show evpn rmac vni all") logger.info(output) + + expected = { + "fd00::2/128": [ + { + "prefix": "fd00::2/128", + "vrfName": "r1-vrf-101", + "nexthops": [ + { + "ip": "::ffff:c0a8:6429", + } + ], + } + ] + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show ipv6 route vrf r1-vrf-101 fd00::2/128 json", expected + ) + assert result is None, "ipv6 route check failed" + + expected = { + "101": { + "numNextHops": 2, + "192.168.100.41": { + "nexthopIp": "192.168.100.41", + }, + "::ffff:c0a8:6429": { + "nexthopIp": "::ffff:c0a8:6429", + }, + } + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn next-hops vni all json", expected + ) + assert result is None, "evpn next-hops check failed" + + expected = {"101": {"numRmacs": 1}} + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn rmac vni all json", expected + ) + assert result is None, "evpn rmac number check failed" + # Check IPv4 and IPv6 connectivity between r1 and r2 ( routing vxlan evpn) pingrouter = tgen.gears["r1"] logger.info( @@ -209,6 +258,80 @@ def test_protocols_convergence(): else: logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK") + logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(r2-vrf-101 = fd00::2)") + output = pingrouter.run("ip netns exec r1-vrf-101 ping fd00::2 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assert 0, "expected ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) should be ok" + else: + logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) OK") + + config_no_ipv6 = { + "r2": { + "raw_config": [ + "router bgp 65000 vrf r2-vrf-101", + "address-family ipv6 unicast", + "no network fd00::2/128", + ] + } + } + + logger.info("==== Remove IPv6 network on R2") + result = apply_raw_config(tgen, config_no_ipv6) + assert result is True, "Failed to remove IPv6 network on R2, Error: {} ".format( + result + ) + ipv6_routes = { + "r1": { + "static_routes": [ + { + "vrf": "r1-vrf-101", + "network": ["fd00::2/128"], + } + ] + } + } + result = verify_bgp_rib(tgen, "ipv6", "r1", ipv6_routes, expected=False) + assert result is not True, "expect IPv6 route fd00::2/128 withdrawn" + output = tgen.gears["r1"].vtysh_cmd("show evpn next-hops vni all", isjson=False) + logger.info("==== result from show evpn next-hops vni all") + logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show evpn rmac vni all", isjson=False) + logger.info("==== result from show evpn next-hops vni all") + logger.info(output) + + expected = { + "101": { + "numNextHops": 1, + "192.168.100.41": { + "nexthopIp": "192.168.100.41", + }, + } + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn next-hops vni all json", expected + ) + assert result is None, "evpn next-hops check failed" + + expected = {"101": {"numRmacs": 1}} + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn rmac vni all json", expected + ) + assert result is None, "evpn rmac number check failed" + + logger.info( + "Check Ping IPv4 from R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)" + ) + output = pingrouter.run("ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = ( + "expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok" + ) + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK") + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py index a5e5bdce..e4d330e1 100644 --- a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py +++ b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py @@ -25,7 +25,6 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from lib import topotest @@ -47,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py index e7058f53..e9006b81 100644 --- a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py +++ b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py @@ -6,7 +6,6 @@ # import os -import re import sys import json import pytest @@ -17,7 +16,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py index a5db20e4..c67bc91f 100644 --- a/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py +++ b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_features/r1/ip_route.json b/tests/topotests/bgp_features/r1/ip_route.json index 34c58033..3f95e270 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 f6536d1e..b8e0fc28 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_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py index 43f4905d..0f5d9dea 100644 --- a/tests/topotests/bgp_features/test_bgp_features.py +++ b/tests/topotests/bgp_features/test_bgp_features.py @@ -18,7 +18,6 @@ import functools import os import sys import pytest -import re import time # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py index 5e2b2f37..2e2c8119 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py @@ -102,7 +102,6 @@ from lib.bgp import ( verify_graceful_restart, create_router_bgp, verify_r_bit, - verify_f_bit, verify_bgp_convergence, verify_bgp_convergence_from_running_config, ) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py index 13c5ba53..9f79c52e 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py @@ -117,8 +117,6 @@ from lib.common_config import ( check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py index 1a8f8302..0873c24b 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py @@ -117,7 +117,6 @@ from lib.common_config import ( check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, step, get_frr_ipv6_linklocal, required_linux_kernel_version, diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py index 31aaa0b8..710514b0 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py @@ -81,6 +81,8 @@ import os import sys import time import pytest +import functools +import json # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -91,6 +93,7 @@ sys.path.append(os.path.join("../lib/")) # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from lib.topolog import logger +from lib import topotest # Required to instantiate the topology builder class. @@ -101,8 +104,6 @@ from lib.bgp import ( verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, - verify_f_bit, verify_bgp_convergence, verify_bgp_convergence_from_running_config, ) @@ -117,7 +118,6 @@ from lib.common_config import ( check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, step, get_frr_ipv6_linklocal, required_linux_kernel_version, @@ -1680,6 +1680,304 @@ def BGP_GR_TC_52_p1(request): write_test_footer(tc_name) +def test_BGP_GR_TC_53_p1(request): + """ + Test Objective : Peer-level inherit from BGP wide Restarting + Global Mode : GR Restart + PerPeer Mode : None + GR Mode effective : GR Restart + + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Check router status + check_router_status(tgen) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Configure R1 as GR restarting node in global level") + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart + ! + """ + ) + + step("Verify that R2 receives GR restarting capabilities" " from R1") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGPd on router R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step( + "Verify that R1 keeps the stale entries in FIB and R2 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Configure graceful-restart-disable at config global level verify that the functionality works + step("Bring up BGP on R1 and configure graceful-restart-disable") + + start_router_daemons(tgen, "r1", ["bgpd"]) + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart-disable": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart-disable + ! + """ + ) + + step("Verify on R2 that R1 does't advertise any GR capabilities") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGP on R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step("Verify on R2 and R1 that none of the routers keep stale entries") + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib( + tgen, addr_type, dut, input_topo, next_hop, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} BGP RIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + step( + "Bring up BGP on R1, enable GR and configure bgp graceful-restart restart-time at global level" + ) + + start_router_daemons(tgen, "r1", ["bgpd"]) + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + no bgp graceful-restart-disable + bgp graceful-restart + bgp graceful-restart stalepath-time 420 + bgp graceful-restart restart-time 240 + bgp graceful-restart select-defer-time 420 + ! + """ + ) + + step("Verify on R2 that R1 sent the updated GR restart-time") + + def _bgp_check_if_gr_restart_time_was_updated(): + output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + "fd00::1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_restart_time_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "R2 did not receive the updated GR restart-time of 240s" + + def _bgp_check_if_gr_timer_on_restarting_node_was_updated(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv4Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + "fd00::2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv6Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_timer_on_restarting_node_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "R1 did not update the GR select-deferral and stale-path timer to 420s" + + write_test_footer(tc_name) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py index cb6bf569..01ab10b8 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py @@ -94,13 +94,10 @@ from lib.bgp import ( verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, verify_eor, - verify_f_bit, verify_bgp_convergence, verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -169,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py index cf9a474a..989d2d55 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py @@ -95,7 +95,6 @@ from lib.bgp import ( verify_graceful_restart, create_router_bgp, verify_r_bit, - verify_eor, verify_f_bit, verify_bgp_convergence, verify_gr_address_family, @@ -114,7 +113,6 @@ from lib.common_config import ( check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -169,7 +167,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py index 4746d71a..05fb8bf7 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py @@ -98,9 +98,7 @@ from lib.bgp import ( verify_eor, verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -114,7 +112,6 @@ from lib.common_config import ( check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -169,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py index 1c41df98..950733c3 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py @@ -96,13 +96,9 @@ from lib.bgp import ( verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, verify_eor, - verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -116,7 +112,6 @@ from lib.common_config import ( check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -171,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py b/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py index 593a8d64..e24f31d8 100644 --- a/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py +++ b/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py @@ -12,7 +12,6 @@ import time import pytest from time import sleep -import traceback import ipaddress # Save the Current Working Directory to find configuration files. @@ -34,37 +33,21 @@ from lib.bgp import ( verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, - verify_eor, - verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, - modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) # Import common_config to use commomnly used APIs from lib.common_config import ( - create_common_configuration, - InvalidCLIError, - retry, generate_ips, - FRRCFG_FILE, - find_interface_with_greater_ip, check_address_types, validate_ip_address, run_frr_cmd, - get_frr_ipv6_linklocal, ) from lib.common_config import ( write_test_header, - reset_config_on_routers, start_topology, - kill_router_daemons, - start_router_daemons, - verify_rib, check_address_types, write_test_footer, check_router_status, @@ -154,9 +137,6 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict): """ logger.debug("Entering lib API: verify_stale_routes_list()") router_list = tgen.routers() - additional_nexthops_in_required_nhs = [] - list1 = [] - list2 = [] found_hops = [] for routerInput in input_dict.keys(): for router, rnode in router_list.items(): @@ -266,7 +246,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE @@ -442,7 +422,7 @@ def test_bgp_gr_stale_routes(request): ) assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - for iteration in range(5): + for _ in range(5): step("graceful-restart-disable:True at R3") input_dict = { "r3": { diff --git a/tests/topotests/bgp_gr_notification/r1/bgpd.conf b/tests/topotests/bgp_gr_notification/r1/bgpd.conf index 6119f674..0af042f6 100644 --- a/tests/topotests/bgp_gr_notification/r1/bgpd.conf +++ b/tests/topotests/bgp_gr_notification/r1/bgpd.conf @@ -3,7 +3,7 @@ router bgp 65001 bgp graceful-restart neighbor 192.168.255.2 remote-as external neighbor 192.168.255.2 timers 1 3 - neighbor 192.168.255.2 timers connect 1 + neighbor 192.168.255.2 timers delayopen 10 address-family ipv4 redistribute connected exit-address-family diff --git a/tests/topotests/bgp_gr_notification/r2/bgpd.conf b/tests/topotests/bgp_gr_notification/r2/bgpd.conf index 05e17f05..8325e21d 100644 --- a/tests/topotests/bgp_gr_notification/r2/bgpd.conf +++ b/tests/topotests/bgp_gr_notification/r2/bgpd.conf @@ -4,7 +4,7 @@ router bgp 65002 bgp graceful-restart neighbor 192.168.255.1 remote-as external neighbor 192.168.255.1 timers 1 3 - neighbor 192.168.255.1 timers connect 1 + neighbor 192.168.255.1 timers delayopen 10 address-family ipv4 redistribute connected exit-address-family diff --git a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py index 2ffcb723..5d8338d6 100644 --- a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py +++ b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -195,16 +195,16 @@ def test_bgp_administrative_reset_gr(): step("Reset and shutdown R1") _bgp_clear_r1_and_shutdown() - step("Check if Hard Reset notification wasn't sent from R2") - test_func = functools.partial(_bgp_check_hard_reset) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) - assert result is None, "Failed to send Administrative Reset notification from R2" - step("Check if stale routes are retained on R1") test_func = functools.partial(_bgp_check_gr_notification_stale) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see retained stale routes on R1" + step("Check if Hard Reset notification wasn't sent from R2") + test_func = functools.partial(_bgp_check_hard_reset) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to send Administrative Reset notification from R2" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py index 2354c0cd..e61efefa 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py +++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py @@ -22,7 +22,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step, stop_router pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py index abf737ff..d7ae4333 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py +++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py @@ -21,7 +21,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step, stop_router pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_gshut/test_bgp_gshut.py b/tests/topotests/bgp_gshut/test_bgp_gshut.py index 61a0fe63..cfe63d20 100644 --- a/tests/topotests/bgp_gshut/test_bgp_gshut.py +++ b/tests/topotests/bgp_gshut/test_bgp_gshut.py @@ -108,7 +108,7 @@ def setup_module(mod): r2.run("ip link set r2-eth3 master vrf1") # Load FRR config and initialize all routers - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py index c7cb213d..66eeeb46 100644 --- a/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py +++ b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py index 395ef2d9..803b51c0 100644 --- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py +++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py @@ -23,7 +23,7 @@ sys.path.append(os.path.join(CWD, "../../")) from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import ( write_test_header, diff --git a/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py b/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py index ea974b53..aaa68ea3 100644 --- a/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py +++ b/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py index 7c23a3e8..a0871a49 100644 --- a/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py +++ b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py @@ -56,7 +56,7 @@ def setup_module(mod): ) tgen.gears["r{}".format(rtr)].run("sysctl -w net.mpls.conf.vrf1.input=1") - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -146,7 +146,7 @@ def check_mpls_table(label, protocol): if label == "auto" and protocol: output_copy = deepcopy(output) - for key, data in output_copy.items(): + for _, data in output_copy.items(): for nexthop in data.get("nexthops", []): if nexthop.get("type", None) != protocol: continue 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 60d959fd..53476042 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_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py b/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py index f4bb487e..25fd0dbb 100644 --- a/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py +++ b/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py @@ -57,7 +57,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py index 34c23d9b..009b39ee 100644 --- a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py +++ b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py @@ -22,7 +22,6 @@ 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] @@ -42,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py index 7023e3a5..49681c6a 100644 --- a/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py +++ b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py @@ -61,7 +61,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) 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 bb50bc96..5773d860 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 57726ce4..a65eb8f5 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 f2368dfd..a1546f57 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 7b4da2a8..0444d2d6 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 3062d1cf..dd84a0f3 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 662b7f71..63b7a6b5 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 d9b5a899..edd764a8 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 53be1171..05928b11 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_llgr/test_bgp_llgr.py b/tests/topotests/bgp_llgr/test_bgp_llgr.py index d7897cfc..547c998c 100644 --- a/tests/topotests/bgp_llgr/test_bgp_llgr.py +++ b/tests/topotests/bgp_llgr/test_bgp_llgr.py @@ -32,7 +32,6 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.common_config import ( kill_router_daemons, - start_router_daemons, step, ) @@ -65,7 +64,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as/test_bgp_local_as.py b/tests/topotests/bgp_local_as/test_bgp_local_as.py index 9e5f146b..e61bb0d1 100644 --- a/tests/topotests/bgp_local_as/test_bgp_local_as.py +++ b/tests/topotests/bgp_local_as/test_bgp_local_as.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py index 930fd791..c58322a4 100644 --- a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py +++ b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py @@ -63,7 +63,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py index 9d22a799..23eb80f3 100644 --- a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py +++ b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py index c84fce6a..214b24ee 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py @@ -25,7 +25,6 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py index 8a115705..ce448329 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py @@ -21,7 +21,6 @@ import os import sys import time import pytest -import platform # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -31,7 +30,6 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py index 25c9bee9..ff1a8147 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py @@ -39,7 +39,6 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py index 0c10c640..5d290ce4 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py @@ -31,7 +31,6 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py index ea6ab59b..0c7e7cf5 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py @@ -26,7 +26,6 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py index b1204bf5..5a0f3413 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py @@ -24,7 +24,6 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py index cfaab9bb..453f0582 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py @@ -38,7 +38,6 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py index 6937a61c..d52ed4c3 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py @@ -34,7 +34,6 @@ import os import sys import time import pytest -import platform # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -44,7 +43,6 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py index bacef476..4ee112eb 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py @@ -52,7 +52,6 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py b/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py index 0656e1ed..18ffc6a1 100644 --- a/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py +++ b/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py @@ -142,7 +142,7 @@ def test_converge_bgplu(): "192.168.2.2/32", "0", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, prefix 192.168.2.2/32 from r2 not present" # Check r2 gets prefix 192.168.2.1/32 @@ -153,7 +153,7 @@ def test_converge_bgplu(): "192.168.2.1/32", "0", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, prefix 192.168.2.1/32 from r1 not present" @@ -178,7 +178,7 @@ def test_traffic_connectivity(): tgen = get_topogen() func = functools.partial(_check_ping, "r1", "192.168.2.2", "192.168.2.1") # tgen.mininet_cli() - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "r1, ping to 192.168.2.2 from 192.168.2.1 fails" diff --git a/tests/topotests/bgp_match_peer/__init__.py b/tests/topotests/bgp_match_peer/__init__.py new file mode 100644 index 00000000..e69de29b 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 00000000..f30da3b8 --- /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 00000000..86dd8e33 --- /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 00000000..978f967a --- /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 00000000..6fb0bc66 --- /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 00000000..4eb7473d --- /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 +# + +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_max_med_on_startup/test_bgp_max_med_on_startup.py b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py index a9810ba2..545d7bd2 100644 --- a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py +++ b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -82,17 +82,17 @@ def test_bgp_max_med_on_startup(): # Check session is established test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed bgp convergence on r2" # Check metric has value of max-med test_func = functools.partial(_bgp_has_routes, router2, 777) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 777" # Check that when the max-med timer expires, metric is updated test_func = functools.partial(_bgp_has_routes, router2, 0) - success, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) assert result is None, "r2 does not receive routes with metric 0" diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py index c6bdbc3c..5edc0b55 100644 --- a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py +++ b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py index 0b346f63..aad5f364 100644 --- a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py +++ b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -177,7 +177,7 @@ def test_bgp_maximum_prefix_out(): router1.vtysh_cmd(cmd) test_func = functools.partial(_bgp_converge, router2, exp_prfxs) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(router2) diff --git a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py index 9f4d9682..c9ff2ffc 100755 --- a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py +++ b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -76,7 +76,7 @@ def test_bgp_minimum_holdtime(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_neighbor_check_if_notification_sent) - success, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) assert result is None, "Failed to send notification message\n" diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index 40a28fbc..012b643d 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -1845,7 +1845,7 @@ def test_vrf_vlan_routing_table_p1(request): dut = "r3" vrf = "RED_A" - for c_link, c_data in topo["routers"][dut]["links"].items(): + for _, c_data in topo["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue @@ -2634,7 +2634,7 @@ def test_delete_and_re_add_vrf_p1(request): vrfs = ["RED_A", "BLUE_A"] for vrf in vrfs: - for c_link, c_data in topo["routers"][dut]["links"].items(): + for _, c_data in topo["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue @@ -3584,7 +3584,7 @@ def test_vrf_name_significance_p1(request): vrfs = ["GREY_A", "PINK_A"] for vrf in vrfs: - for c_link, c_data in topo_modify["routers"][dut]["links"].items(): + for _, c_data in topo_modify["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue diff --git a/tests/topotests/bgp_nexthop_ipv6/exabgp.env b/tests/topotests/bgp_nexthop_ipv6/exabgp.env new file mode 100644 index 00000000..28e64236 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/exabgp.env @@ -0,0 +1,53 @@ +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' +##daemonize = false + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf new file mode 100644 index 00000000..7efa1b79 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf @@ -0,0 +1,22 @@ +router bgp 65000 + no bgp ebgp-requires-policy + neighbor fd00:0:2::9 remote-as internal + neighbor fd00:0:2::9 timers 3 10 + address-family ipv4 unicast + redistribute connected route-map RMAP4 + ! + address-family ipv6 unicast + redistribute connected route-map RMAP6 + neighbor fd00:0:2::9 activate + +ip prefix-list RANGE4 seq 10 permit 172.16.0.0/16 le 24 +ip prefix-list RANGE4 seq 20 permit 10.0.0.0/8 ge 32 + +ipv6 prefix-list RANGE6 seq 10 permit fd00:100::0/64 +ipv6 prefix-list RANGE6 seq 20 permit 2001:db8::0/64 ge 128 + +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_ipv6/r1/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step1.json new file mode 100644 index 00000000..9923edb3 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step1.json @@ -0,0 +1,162 @@ +{ + "routerId": "10.1.1.1", + "localAS": 65000, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r1", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r1", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step2.json new file mode 100644 index 00000000..9923edb3 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r1/show_bgp_ipv6_step2.json @@ -0,0 +1,162 @@ +{ + "routerId": "10.1.1.1", + "localAS": 65000, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r1", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r1", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r1/zebra.conf b/tests/topotests/bgp_nexthop_ipv6/r1/zebra.conf new file mode 100644 index 00000000..d06a3e19 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r1/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +ipv6 forwarding + +int eth-dummy + ip addr 172.16.1.1/24 + ip addr fd00:100::1/64 + +int eth-sw + ip addr 192.168.2.1/24 + ipv6 address fd00:0:2::1/64 + +int lo + ip addr 10.1.1.1/32 + ipv6 address 2001:db8::1/128 diff --git a/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf new file mode 100644 index 00000000..4d4ae44e --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf @@ -0,0 +1,22 @@ +router bgp 65000 + no bgp ebgp-requires-policy + neighbor fd00:0:2::9 remote-as internal + neighbor fd00:0:2::9 timers 3 10 + address-family ipv4 unicast + redistribute connected route-map RMAP4 + ! + address-family ipv6 unicast + redistribute connected route-map RMAP6 + neighbor fd00:0:2::9 activate + +ip prefix-list RANGE4 seq 10 permit 172.16.0.0/16 le 24 +ip prefix-list RANGE4 seq 20 permit 10.0.0.0/8 ge 32 + +ipv6 prefix-list RANGE6 seq 10 permit fd00:200::0/64 +ipv6 prefix-list RANGE6 seq 20 permit 2001:db8::0/64 ge 128 + +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_ipv6/r2/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step1.json new file mode 100644 index 00000000..bb2efa16 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step1.json @@ -0,0 +1,162 @@ +{ + "routerId": "10.2.2.2", + "localAS": 65000, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r2", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r2", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step2.json new file mode 100644 index 00000000..bb2efa16 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r2/show_bgp_ipv6_step2.json @@ -0,0 +1,162 @@ +{ + "routerId": "10.2.2.2", + "localAS": 65000, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r2", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r2", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r2/zebra.conf b/tests/topotests/bgp_nexthop_ipv6/r2/zebra.conf new file mode 100644 index 00000000..de8746df --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r2/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +ipv6 forwarding + +int eth-dummy + ip addr 172.16.2.2/24 + ip addr fd00:200::1/64 + +int eth-sw + ip addr 192.168.2.2/24 + ipv6 address fd00:0:2::2/64 + +int lo + ip addr 10.2.2.2/32 + ipv6 address 2001:db8::2/128 \ No newline at end of file diff --git a/tests/topotests/bgp_nexthop_ipv6/r3/exabgp.cfg b/tests/topotests/bgp_nexthop_ipv6/r3/exabgp.cfg new file mode 100644 index 00000000..373169bc --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r3/exabgp.cfg @@ -0,0 +1,16 @@ +neighbor fd00:0:2::9 { + router-id 10.3.3.3; + local-address fd00:0:2::3; + local-as 65000; + peer-as 65000; + + family { + ipv6 unicast; + } + + static { + route fd00:300::0/64 next-hop fd00:0:2::3; + route 2001:db8::3/128 next-hop fd00:0:2::3; + } + hold-time 10; +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r3/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r3/show_bgp_ipv6_step1.json new file mode 100644 index 00000000..e69de29b diff --git a/tests/topotests/bgp_nexthop_ipv6/r3/show_bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_ipv6/r3/show_bgp_ipv6_step2.json new file mode 100644 index 00000000..e69de29b diff --git a/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf new file mode 100644 index 00000000..b14c9bac --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf @@ -0,0 +1,22 @@ +router bgp 65001 + no bgp ebgp-requires-policy + neighbor fd00:0:2::9 remote-as external + neighbor fd00:0:2::9 timers 3 10 + address-family ipv4 unicast + redistribute connected route-map RMAP4 + ! + address-family ipv6 unicast + redistribute connected route-map RMAP6 + neighbor fd00:0:2::9 activate + +ip prefix-list RANGE4 seq 10 permit 172.16.0.0/16 le 24 +ip prefix-list RANGE4 seq 20 permit 10.0.0.0/8 ge 32 + +ipv6 prefix-list RANGE6 seq 10 permit fd00:400::0/64 +ipv6 prefix-list RANGE6 seq 20 permit 2001:db8::0/64 ge 128 + +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_ipv6/r4/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step1.json new file mode 100644 index 00000000..dd8603f4 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step1.json @@ -0,0 +1,210 @@ +{ + "routerId": "10.4.4.4", + "localAS": 65001, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r1:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r2:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r4", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r1:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r2:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r4", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step2.json new file mode 100644 index 00000000..35a31e63 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step2.json @@ -0,0 +1,222 @@ +{ + "routerId": "10.4.4.4", + "localAS": 65001, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r4", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r4", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-sw", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r4/zebra.conf b/tests/topotests/bgp_nexthop_ipv6/r4/zebra.conf new file mode 100644 index 00000000..edc39684 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r4/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +ipv6 forwarding + +int eth-dummy + ip addr 172.16.4.4/24 + ip addr fd00:400::4/64 + +int eth-sw + ip addr 192.168.2.4/24 + ipv6 address fd00:0:2::4/64 + +int lo + ip addr 10.4.4.4/32 + ipv6 address 2001:db8::4/128 \ No newline at end of file diff --git a/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf new file mode 100644 index 00000000..becea2bb --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf @@ -0,0 +1,22 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor fd00:0:3::9 remote-as external + neighbor fd00:0:3::9 timers 3 10 + address-family ipv4 unicast + redistribute connected route-map RMAP4 + ! + address-family ipv6 unicast + redistribute connected route-map RMAP6 + neighbor fd00:0:3::9 activate + +ip prefix-list RANGE4 seq 10 permit 172.16.0.0/16 le 24 +ip prefix-list RANGE4 seq 20 permit 10.0.0.0/8 ge 32 + +ipv6 prefix-list RANGE6 seq 10 permit fd00:500::0/64 +ipv6 prefix-list RANGE6 seq 20 permit 2001:db8::0/64 ge 128 + +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_ipv6/r5/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step1.json new file mode 100644 index 00000000..d0875474 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step1.json @@ -0,0 +1,222 @@ +{ + "routerId": "10.5.5.5", + "localAS": 65002, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r5", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r5", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step2.json new file mode 100644 index 00000000..d0875474 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step2.json @@ -0,0 +1,222 @@ +{ + "routerId": "10.5.5.5", + "localAS": 65002, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r5", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r5", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::9", + "hostname": "rr", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:rr:eth-r5", + "hostname": "rr", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r5/zebra.conf b/tests/topotests/bgp_nexthop_ipv6/r5/zebra.conf new file mode 100644 index 00000000..d278889e --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r5/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +ipv6 forwarding + +int eth-dummy + ip addr 172.16.5.5/24 + ip addr fd00:500::5/64 + +int eth-rr + ip addr 192.168.3.5/24 + ipv6 address fd00:0:3::5/64 + +int lo + ip addr 10.5.5.5/32 + ipv6 address 2001:db8::5/128 diff --git a/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf new file mode 100644 index 00000000..801736ab --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf @@ -0,0 +1,22 @@ +router bgp 65000 + no bgp ebgp-requires-policy + neighbor fd00:0:4::9 remote-as internal + neighbor fd00:0:4::9 timers 3 10 + address-family ipv4 unicast + redistribute connected route-map RMAP4 + ! + address-family ipv6 unicast + redistribute connected route-map RMAP6 + neighbor fd00:0:4::9 activate + +ip prefix-list RANGE4 seq 10 permit 172.16.0.0/16 le 24 +ip prefix-list RANGE4 seq 20 permit 10.0.0.0/8 ge 32 + +ipv6 prefix-list RANGE6 seq 10 permit fd00:600::0/64 +ipv6 prefix-list RANGE6 seq 20 permit 2001:db8::0/64 ge 128 + +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_ipv6/r6/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step1.json new file mode 100644 index 00000000..cd48dd46 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step1.json @@ -0,0 +1,162 @@ +{ + "routerId": "10.6.6.6", + "localAS": 65000, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r6", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r6", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step2.json new file mode 100644 index 00000000..cd48dd46 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r6/show_bgp_ipv6_step2.json @@ -0,0 +1,162 @@ +{ + "routerId": "10.6.6.6", + "localAS": 65000, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r6", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "rr", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "::", + "hostname": "r6", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/r6/zebra.conf b/tests/topotests/bgp_nexthop_ipv6/r6/zebra.conf new file mode 100644 index 00000000..84bbb95a --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/r6/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +ipv6 forwarding + +int eth-dummy + ip addr 172.16.6.6/24 + ip addr fd00:600::6/64 + +int eth-rr + ip addr 192.168.4.6/24 + ipv6 address fd00:0:4::6/64 + +int lo + ip addr 10.6.6.6/32 + ipv6 address 2001:db8::6/128 diff --git a/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf new file mode 100644 index 00000000..6dcded15 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf @@ -0,0 +1,30 @@ +router bgp 65000 + no bgp ebgp-requires-policy + neighbor fd00:0:2::1 remote-as internal + neighbor fd00:0:2::1 timers 3 10 + neighbor fd00:0:2::2 remote-as internal + neighbor fd00:0:2::2 timers 3 10 + neighbor fd00:0:2::3 remote-as internal + neighbor fd00:0:2::3 timers 3 10 + neighbor fd00:0:2::4 remote-as external + neighbor fd00:0:2::4 timers 3 10 + neighbor fd00:0:3::5 remote-as external + neighbor fd00:0:3::5 timers 3 10 + neighbor fd00:0:4::6 remote-as internal + neighbor fd00:0:4::6 timers 3 10 + address-family ipv4 unicast + neighbor fd00:0:2::1 route-reflector-client + neighbor fd00:0:2::2 route-reflector-client + neighbor fd00:0:2::3 route-reflector-client + neighbor fd00:0:4::6 route-reflector-client + address-family ipv6 unicast + neighbor fd00:0:2::1 route-reflector-client + neighbor fd00:0:2::1 activate + neighbor fd00:0:2::2 route-reflector-client + neighbor fd00:0:2::2 activate + neighbor fd00:0:2::3 route-reflector-client + neighbor fd00:0:2::3 activate + neighbor fd00:0:2::4 nexthop-local unchanged + neighbor fd00:0:2::4 activate + neighbor fd00:0:3::5 activate + neighbor fd00:0:4::6 activate diff --git a/tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_step1.json b/tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_step1.json new file mode 100644 index 00000000..c8b8e1e8 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_step1.json @@ -0,0 +1,220 @@ +{ + "routerId": "10.9.9.9", + "localAS": 65000, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "r1", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r1:eth-sw", + "hostname": "r1", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "r2", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r2:eth-sw", + "hostname": "r2", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "r4", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r4:eth-sw", + "hostname": "r4", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "r5", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r5:eth-rr", + "hostname": "r5", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "r6", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r6:eth-rr", + "hostname": "r6", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "r1", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r1:eth-sw", + "hostname": "r1", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "r2", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r2:eth-sw", + "hostname": "r2", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "r4", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r4:eth-sw", + "hostname": "r4", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "r5", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r5:eth-rr", + "hostname": "r5", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "r6", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r6:eth-rr", + "hostname": "r6", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_step2.json new file mode 100644 index 00000000..c8b8e1e8 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_step2.json @@ -0,0 +1,220 @@ +{ + "routerId": "10.9.9.9", + "localAS": 65000, + "routes": { + "2001:db8::1/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "r1", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r1:eth-sw", + "hostname": "r1", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::2/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "r2", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r2:eth-sw", + "hostname": "r2", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::3/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "2001:db8::4/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "r4", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r4:eth-sw", + "hostname": "r4", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::5/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "r5", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r5:eth-rr", + "hostname": "r5", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "2001:db8::6/128": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "r6", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r6:eth-rr", + "hostname": "r6", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:100::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::1", + "hostname": "r1", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r1:eth-sw", + "hostname": "r1", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:200::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::2", + "hostname": "r2", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r2:eth-sw", + "hostname": "r2", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:300::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::3", + "afi": "ipv6", + "scope": "global", + "used": true + } + ] + } + ], + "fd00:400::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:2::4", + "hostname": "r4", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r4:eth-sw", + "hostname": "r4", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:500::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:3::5", + "hostname": "r5", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r5:eth-rr", + "hostname": "r5", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ], + "fd00:600::/64": [ + { + "nexthops": [ + { + "ip": "fd00:0:4::6", + "hostname": "r6", + "afi": "ipv6", + "scope": "global" + }, + { + "ip": "link-local:r6:eth-rr", + "hostname": "r6", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_summary.json b/tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_summary.json new file mode 100644 index 00000000..ceac9121 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/rr/show_bgp_ipv6_summary.json @@ -0,0 +1,6 @@ +{ + "ipv6Unicast": { + "failedPeers": 0, + "totalPeers": 6 + } +} diff --git a/tests/topotests/bgp_nexthop_ipv6/rr/zebra.conf b/tests/topotests/bgp_nexthop_ipv6/rr/zebra.conf new file mode 100644 index 00000000..21d44f3a --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/rr/zebra.conf @@ -0,0 +1,18 @@ +ip forwarding +ipv6 forwarding + +int eth-sw + ip addr 192.168.2.9/24 + ipv6 address fd00:0:2::9/64 + +int eth-r5 + ip addr 192.168.3.9/24 + ipv6 address fd00:0:3::9/64 + +int eth-r6 + ip addr 192.168.4.9/24 + ipv6 address fd00:0:4::9/64 + +int lo + ip addr 10.9.9.9/32 + ipv6 address 2001:db8::9/128 diff --git a/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py new file mode 100644 index 00000000..24d71f56 --- /dev/null +++ b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_bgp_nexthop_ipv6_topo1.py +# +# Copyright (c) 2024 by +# Cumulus Networks, Inc. +# 6WIND S.A. +# + +""" +Ensure that BGP ipv6 nexthops are correct +""" + +import os +import sys +import pytest +from functools import partial +import json + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + """ + All peers are FRR BGP peers except r3 that is a exabgp peer. + rr is a route-reflector for AS 65000 iBGP peers. + Exabgp does not send any IPv6 Link-Local nexthop + + iBGP peers | eBGP peers + | + AS 65000 | + | + +---+ | + | r6| | + +---+ | + | | + fd00:0:3::0/64 | + | | AS 65002 + +---+ | +---+ + |rr |----fd00:0:4::0/64---| r5| + +---+ |_________+---+ + | | +---+ + fd00:0:2::0/64----------------| r4| + / | \ | +---+ + +---+ +---+ +---+ | AS 65001 + | r1| | r2| |r3 | | + +---+ +---+ +---+ + """ + + 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)) + + def connect_dummy(tgen, rname, switch): + if rname not in tgen.routers().keys(): + tgen.add_router(rname) + + switch.add_link(tgen.gears[rname], nodeif="eth-dummy") + + # sw_du switch is for a dummy interface (for local network) + for i in range(1, 7): + if i == 3: + # r3 is an exabgp peer + continue + sw_du = tgen.add_switch("sw%s" % i) + connect_dummy(tgen, "r%s" % i, sw_du) + + # sw switch is for interconnecting peers on the same subnet + sw = tgen.add_switch("sw") + connect_switchs(tgen, "rr", sw) + connect_switchs(tgen, "r1", sw) + connect_switchs(tgen, "r2", sw) + connect_switchs(tgen, "r4", sw) + + # directly connected without switch routers + connect_routers(tgen, "rr", "r5") + connect_routers(tgen, "rr", "r6") + + ## Add iBGP ExaBGP neighbor + peer_ip = "fd00:0:2::3" ## peer + peer_route = "via fd00:0:2::9" ## router + r3 = tgen.add_exabgp_peer("r3", ip=peer_ip, defaultRoute=peer_route) + sw.add_link(r3) + + +##################################################### +## +## Tests starting +## +##################################################### + + +def setup_module(module): + "Setup topology" + tgen = Topogen(build_topo, module.__name__) + tgen.start_topology() + + # This is a sample of configuration loading. + router_list = tgen.routers() + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + # Start r3 exabgp peer + r3 = tgen.gears["r3"] + r3.start(os.path.join(CWD, "r3"), os.path.join(CWD, "exabgp.env")) + + +def get_link_local(rname, ifname, cache): + ip = cache.get(rname, {}).get(ifname) + if ip: + return ip + + tgen = get_topogen() + out = tgen.gears[rname].vtysh_cmd("show interface %s json" % ifname, isjson=True) + for address in out[ifname]["ipAddresses"]: + if not address["address"].startswith("fe80::"): + continue + ip = address["address"].split("/")[0] + cache.setdefault(rname, {})[ifname] = ip + return ip + + +def replace_link_local(expected, cache): + for prefix, prefix_info in expected.get("routes", {}).items(): + for nexthop in prefix_info[0].get("nexthops", []): + ip = nexthop.get("ip", "") + if not ip.startswith("link-local:"): + continue + rname = ip.split(":")[1] + ifname = ip.split(":")[2] + ip = get_link_local(rname, ifname, cache) + nexthop["ip"] = ip + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_converge_protocols(): + "Wait for protocol convergence" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + rr = tgen.gears["rr"] + ref_file = "{}/{}/show_bgp_ipv6_summary.json".format(CWD, rr.name) + expected = json.loads(open(ref_file).read()) + + test_func = partial( + topotest.router_json_cmp, + rr, + "show bgp ipv6 summary json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = "{}: BGP convergence".format(rr.name) + assert res is None, assertmsg + + +def test_bgp_ipv6_table_step1(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + global link_local_cache + link_local_cache = {} + router_list = tgen.routers().values() + for router in router_list: + # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) + ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + replace_link_local(expected, link_local_cache) + + 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(router.name) + assert res is None, assertmsg + + +def test_bgp_ipv6_table_step2(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + rr = tgen.gears["rr"] + rr.vtysh_cmd( + """ +configure terminal +router bgp 65000 + address-family ipv6 unicast + no neighbor fd00:0:2::4 nexthop-local unchanged +""" + ) + + router_list = tgen.routers().values() + for router in router_list: + # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) + ref_file = "{}/{}/show_bgp_ipv6_step2.json".format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + replace_link_local(expected, link_local_cache) + + 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(router.name) + assert res is None, assertmsg + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py index 23e820b4..32f78c44 100644 --- a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py +++ b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py @@ -24,7 +24,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_oad/r1/frr.conf b/tests/topotests/bgp_oad/r1/frr.conf index 39045ba6..f00bdfe7 100644 --- a/tests/topotests/bgp_oad/r1/frr.conf +++ b/tests/topotests/bgp_oad/r1/frr.conf @@ -4,6 +4,7 @@ int r1-eth0 ! router bgp 65001 no bgp ebgp-requires-policy + no bgp network import-check neighbor 192.168.1.2 remote-as external neighbor 192.168.1.2 timers 1 3 neighbor 192.168.1.2 timers connect 1 @@ -12,10 +13,14 @@ router bgp 65001 neighbor 192.168.1.4 timers 1 3 neighbor 192.168.1.4 timers connect 1 address-family ipv4 unicast + network 10.10.10.1/32 route-map local neighbor 192.168.1.4 route-map r4 in exit-address-family ! route-map r4 permit 10 set local-preference 123 set metric 123 -exit +! +route-map local permit 10 + set community no-export +! diff --git a/tests/topotests/bgp_oad/test_bgp_oad.py b/tests/topotests/bgp_oad/test_bgp_oad.py index a2ca37a2..b2ea7e0f 100644 --- a/tests/topotests/bgp_oad/test_bgp_oad.py +++ b/tests/topotests/bgp_oad/test_bgp_oad.py @@ -8,10 +8,11 @@ """ Test if local-preference is passed between different EBGP peers when EBGP-OAD is configured. + +Also check if no-export community is passed to the EBGP-OAD peer. """ import os -import re import sys import json import pytest @@ -24,8 +25,7 @@ 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 +from lib.topogen import Topogen, get_topogen def setup_module(mod): @@ -46,13 +46,16 @@ def teardown_module(mod): tgen.stop_topology() -def test_bgp_dynamic_capability_role(): +def test_bgp_oad(): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] def _bgp_converge(): output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) @@ -87,6 +90,37 @@ def test_bgp_dynamic_capability_role(): _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, "Can't converge" + def _bgp_check_no_export(router, arg=[{"valid": True}]): + output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.10.10.1/32": arg, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_no_export, + r2, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.1/32 should be advertised to r2" + + test_func = functools.partial( + _bgp_check_no_export, + r3, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.1/32 should be advertised to r3" + + test_func = functools.partial( + _bgp_check_no_export, + r4, + None, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.1/32 should not be advertised to r4 (not OAD peer)" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_orf/test_bgp_orf.py b/tests/topotests/bgp_orf/test_bgp_orf.py index 47c05568..bc6a85b4 100644 --- a/tests/topotests/bgp_orf/test_bgp_orf.py +++ b/tests/topotests/bgp_orf/test_bgp_orf.py @@ -37,7 +37,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py index bd8cd8e1..adc92f59 100644 --- a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py +++ b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py @@ -23,7 +23,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_path_selection/test_bgp_path_selection.py b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py index 30083b4d..d486a87e 100644 --- a/tests/topotests/bgp_path_selection/test_bgp_path_selection.py +++ b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py @@ -57,7 +57,7 @@ def setup_module(mod): tgen.gears["r2"].cmd("ip address add dev vrf1 192.0.2.8/32") tgen.gears["r3"].cmd("ip address add dev vrf1 192.0.2.8/32") - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py index 92698262..c6ee9aa7 100644 --- a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py +++ b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py index 5cbcd19b..7d476b05 100644 --- a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py +++ b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py @@ -47,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) 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 00000000..e69de29b 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 00000000..53959aa1 --- /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 00000000..ba99827a --- /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 00000000..ed06170b --- /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 00000000..cdbc1e02 --- /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 +# + +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_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json index 22ec2c29..483165c0 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json @@ -23,7 +23,7 @@ "recursive":true }, { - "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json index facddcda..638a8253 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json @@ -23,7 +23,7 @@ "recursive":true }, { - "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } diff --git a/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf b/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf index 14c28ca9..593442a4 100644 --- a/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf +++ b/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf @@ -4,6 +4,10 @@ router bgp 65001 no bgp network import-check neighbor 192.168.1.2 remote-as external neighbor 2001:db8:1::2 remote-as external + neighbor 192.168.1.2 timers 3 10 + neighbor 192.168.1.2 timers connect 1 + neighbor 2001:db8:1::2 timers 3 10 + neighbor 2001:db8:1::2 timers connect 1 address-family ipv4 unicast network 192.168.0.1/32 no neighbor 2001:db8:1::2 activate diff --git a/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf b/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf index 73320592..0de5bd33 100644 --- a/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf +++ b/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf @@ -6,6 +6,10 @@ router bgp 65002 no bgp network import-check neighbor 192.168.1.1 remote-as external neighbor 2001:db8:1::1 remote-as external + neighbor 192.168.1.1 timers 3 10 + neighbor 192.168.1.1 timers connect 1 + neighbor 2001:db8:1::1 timers 3 10 + neighbor 2001:db8:1::1 timers connect 1 address-family ipv4 unicast network 10.10.10.1/32 network 10.10.10.2/32 diff --git a/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py b/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py index 5d6440ce..1871d3ef 100644 --- a/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py +++ b/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py @@ -33,7 +33,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py index 1e6e731a..fca60e8c 100644 --- a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py +++ b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py @@ -93,11 +93,11 @@ def test_r1_receive_and_advertise_prefix_sid_type1(): return topotest.json_cmp(output, expected) test_func = functools.partial(_check_type1_r1, router, "3.0.0.1/32", 800001, 1) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router) test_func = functools.partial(_check_type1_r1, router, "3.0.0.2/32", 800002, 2) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router) @@ -160,11 +160,11 @@ def test_peer2_receive_prefix_sid_type1(): return topotest.json_cmp(output, expected) test_func = functools.partial(_check_type1_peer2, "3.0.0.1/32", label=8001) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_peer2 in "{}"'.format("peer2") test_func = functools.partial(_check_type1_peer2, "3.0.0.2/32", label=8002) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_peer2 in "{}"'.format("peer2") diff --git a/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py index d6b94329..cf0c9fea 100755 --- a/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py +++ b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py @@ -90,7 +90,7 @@ def test_r1_rib(): 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) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" check("r1", "show bgp ipv6 vpn 2001:1::/64 json", "r1/vpnv6_rib_entry1.json") diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py b/tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf b/tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf new file mode 100644 index 00000000..01dd4f3c --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf @@ -0,0 +1,17 @@ +! +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 + address-family ipv4 unicast + neighbor 192.168.1.2 route-map r2 in + neighbor 192.168.1.2 soft-reconfiguration inbound + exit-address-family +! +route-map r2 permit 10 + set as-path prepend 65000 65000 65000 +exit +! diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf b/tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf new file mode 100644 index 00000000..86dd8e33 --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/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_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py b/tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py new file mode 100644 index 00000000..0b933add --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +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")} + 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_received_routes_with_soft_inbound(): + 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.2/32": [ + { + "valid": True, + "path": "65000 65000 65000 65002", + "nexthops": [ + { + "ip": "192.168.1.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" + + def _bgp_check_receveived_routes(): + output = json.loads( + r1.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.1.2 received-routes json" + ) + ) + expected = { + "receivedRoutes": { + "10.0.0.2/32": { + "valid": True, + "path": "65002", + "nextHop": "192.168.1.2", + } + } + } + + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_receveived_routes, + ) + _, 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_redistribute_table/test_bgp_redistribute_table.py b/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py index 08b70ae0..614610cc 100644 --- a/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py +++ b/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py @@ -86,7 +86,7 @@ def _router_json_cmp_exact_filter(router, cmd, expected): json_output = json.loads(output) # filter out tableVersion, version, nhVrfId and vrfId - for route, attrs in json_output.items(): + for _, attrs in json_output.items(): for attr in attrs: if "table" in attr: attr.pop("table") diff --git a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py index 97366ebd..b9d8ce68 100644 --- a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py +++ b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py @@ -56,7 +56,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -114,19 +114,19 @@ def test_bgp_reject_as_sets(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(router) test_func = functools.partial( _bgp_has_aggregated_route_with_stripped_as_set, router ) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed to see an aggregated route in "{}"'.format(router) test_func = functools.partial(_bgp_announce_route_without_as_sets, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_remote_as_auto/__init__.py b/tests/topotests/bgp_remote_as_auto/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/topotests/bgp_remote_as_auto/r1/frr.conf b/tests/topotests/bgp_remote_as_auto/r1/frr.conf new file mode 100644 index 00000000..2f1bcd27 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r1/frr.conf @@ -0,0 +1,23 @@ +! +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 192.168.1.2 remote-as auto + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.3 remote-as auto + neighbor 192.168.1.3 timers 1 3 + neighbor 192.168.1.3 timers connect 1 + neighbor r1-eth1 interface remote-as auto + neighbor r1-eth1 timers 1 3 + neighbor r1-eth1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.1/32 + exit-address-family +! diff --git a/tests/topotests/bgp_remote_as_auto/r2/frr.conf b/tests/topotests/bgp_remote_as_auto/r2/frr.conf new file mode 100644 index 00000000..f8d19a0b --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r2/frr.conf @@ -0,0 +1,10 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/r3/frr.conf b/tests/topotests/bgp_remote_as_auto/r3/frr.conf new file mode 100644 index 00000000..fc686276 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/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 auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/r4/frr.conf b/tests/topotests/bgp_remote_as_auto/r4/frr.conf new file mode 100644 index 00000000..e280a6c6 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r4/frr.conf @@ -0,0 +1,10 @@ +! +int r4-eth0 + ip address 192.168.14.4/24 +! +router bgp 65004 + no bgp ebgp-requires-policy + neighbor r4-eth0 interface remote-as auto + neighbor r4-eth0 timers 1 3 + neighbor r4-eth0 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py new file mode 100644 index 00000000..1db6d98a --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +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"), "s2": ("r1", "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_remote_as_auto(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json")) + expected = { + "peers": { + "r1-eth1": { + "hostname": "r4", + "remoteAs": 65004, + "localAs": 65001, + "state": "Established", + }, + "192.168.1.2": { + "hostname": "r2", + "remoteAs": 65001, + "localAs": 65001, + "state": "Established", + }, + "192.168.1.3": { + "hostname": "r3", + "remoteAs": 65003, + "localAs": 65001, + "state": "Established", + }, + } + } + 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 see automatic iBGP/eBGP peerings" + + def _bgp_converge_internal(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "Local", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "internal", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_internal, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic iBGP peering" + + def _bgp_converge_external(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic eBGP peering" + + def _bgp_converge_external_unnumbered(): + output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external_unnumbered, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic unnumbered eBGP peering" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py index e48f81c5..8b965a16 100644 --- a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py +++ b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py @@ -32,7 +32,6 @@ All conditions are tested against an eBGP peer in a public ASN. import os import sys import json -import time import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -109,7 +108,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, f"{rname}/zebra.conf") ) diff --git a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py index d9402f27..10896e2b 100644 --- a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py +++ b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py @@ -10,7 +10,6 @@ Test if private AS is removed from AS_PATH attribute when route-map is used (pre """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen def build_topo(tgen): @@ -41,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py b/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py index ef7c94bb..2e5592e2 100644 --- a/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py +++ b/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -86,7 +86,7 @@ def test_bgp_extcommunity_none(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "BGP Converge failed" def _bgp_extcommunity_strip(router): @@ -111,7 +111,7 @@ def test_bgp_extcommunity_none(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_extcommunity_strip, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to strip incoming extended communities from r2" diff --git a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py index 52fda695..9223cbd7 100644 --- a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py +++ b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py @@ -24,8 +24,7 @@ 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.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.bgpd] @@ -38,7 +37,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_BGP, "bgpd.conf") tgen.start_router() @@ -82,9 +81,7 @@ def test_correct_pair(tgen): check_r2_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( - check_r2_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r2_established, True, count=20, wait=3) assert success, "Session with r2 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -100,7 +97,7 @@ def test_role_pair_mismatch(tgen): router = tgen.gears["r3"] neighbor_ip = "192.168.3.1" check_r3_mismatch = functools.partial(check_role_mismatch, router, neighbor_ip) - success, result = topotest.run_and_expect(check_r3_mismatch, True, count=20, wait=3) + success, _ = topotest.run_and_expect(check_r3_mismatch, True, count=20, wait=3) assert success, "Session between r1 and r3 was not correctly closed" @@ -111,9 +108,7 @@ def test_single_role_advertising(tgen): check_r4_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( - check_r4_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r4_established, True, count=20, wait=3) assert success, "Session with r4 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -129,9 +124,7 @@ def test_single_role_receiving(tgen): check_r1_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( - check_r1_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r1_established, True, count=20, wait=3) assert success, "Session with r1 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -145,7 +138,7 @@ def test_role_strict_mode(tgen): router = tgen.gears["r5"] neighbor_ip = "192.168.5.1" check_r5_mismatch = functools.partial(check_role_mismatch, router, neighbor_ip) - success, result = topotest.run_and_expect(check_r5_mismatch, True, count=20, wait=3) + success, _ = topotest.run_and_expect(check_r5_mismatch, True, count=20, wait=3) assert success, "Session between r1 and r5 was not correctly closed" diff --git a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py index b3715863..ffbf454d 100644 --- a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py +++ b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py @@ -16,7 +16,6 @@ test_bgp_roles_filtering: test leaks prevention and mitigation with roles import json import os import sys -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -24,9 +23,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.bgp import verify_bgp_convergence_from_running_config -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.bgpd] @@ -39,7 +36,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_BGP, "bgpd.conf") tgen.start_router() @@ -69,9 +66,7 @@ def test_r10_routes(tgen): ] return output == expected - success, result = topotest.run_and_expect( - _routes_half_converged, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(_routes_half_converged, True, count=20, wait=3) assert success, "Routes did not converged" routes_with_otc = list() diff --git a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py index d50d67b6..94bf092c 100644 --- a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py +++ b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py @@ -119,7 +119,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py b/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py index f7a66fda..d791ef48 100644 --- a/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py +++ b/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py @@ -32,7 +32,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf index 8b743bd3..11e57ca9 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf @@ -11,6 +11,8 @@ router bgp 65001 bgp router-id 10.10.10.1 no bgp ebgp-requires-policy neighbor 2001:db8::2 remote-as external + neighbor 2001:db8::2 timers 3 10 + neighbor 2001:db8::2 timers connect 1 address-family ipv6 unicast neighbor 2001:db8::2 activate neighbor 2001:db8::2 route-map r2 in diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf index 61c36d36..abd0ab9a 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf @@ -5,6 +5,8 @@ router bgp 65002 bgp router-id 10.10.10.2 no bgp ebgp-requires-policy neighbor 2001:db8::1 remote-as external + neighbor 2001:db8::1 timers 3 10 + neighbor 2001:db8::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8::1 activate diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py index 93a514bf..35ce0926 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -97,7 +97,7 @@ def test_bgp_route_map_match_ipv6_next_hop_access_list(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Can't match routes using ipv6 next-hop access-list" diff --git a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py index 28287964..f7b69f21 100644 --- a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py +++ b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py @@ -46,8 +46,15 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): - router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config( + os.path.join(CWD, "{}/frr.conf".format(rname)), + [ + (TopoRouter.RD_ZEBRA, None), + (TopoRouter.RD_SHARP, None), + (TopoRouter.RD_BGP, None), + ], + ) tgen.start_router() @@ -109,6 +116,68 @@ def test_bgp_route_map_match_source_protocol(): _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, "Failed to filter routes by source-protocol for r3" + def _bgp_check_advertised_routes_r4(): + # Remove match source-protocol towards Nbr out policy for Nbr 192.168.1.2 so it receives all routes + tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + route-map r2 permit 10 + no match source-protocol + """ + ) + + tgen.gears["r1"].vtysh_cmd( + "sharp install route 192.168.11.0 nexthop 172.16.255.1 5" + ) + + # Configure a r4 with source protocol sharp and apply it to all redistribute cmds + tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + route-map r4 permit 10 + match source-protocol sharp + router bgp 65001 + address-family ipv4 unicast + redistribute connected route-map r4 + redistribute static route-map r4 + redistribute sharp route-map r4 + """ + ) + + # Since match protocol is sharp, only sharp protocol routes are to be advertised + output = json.loads( + tgen.gears["r1"].vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.1.2 advertised-routes json" + ) + ) + + expected = { + "advertisedRoutes": { + "192.168.11.0/32": { + "valid": True, + }, + "192.168.11.1/32": { + "valid": True, + }, + "192.168.11.2/32": { + "valid": True, + }, + "192.168.11.3/32": { + "valid": True, + }, + "192.168.11.4/32": { + "valid": True, + }, + }, + "totalPrefixCounter": 5, + } + + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_advertised_routes_r4) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to match the source-protocol for redistribute cmds" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py b/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py index 7dd63fda..6ffa078f 100644 --- a/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py +++ b/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py @@ -17,7 +17,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py index 8fe45a34..5b5256f4 100644 --- a/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py +++ b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -83,12 +83,12 @@ def test_bgp_route_map_on_match_next(): # Check thst session is established test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed bgp convergence on r2" # Check that metric is 0 and weight is 100 for the received prefix test_func = functools.partial(_bgp_has_routes, router2, 0, 100) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 0 and weight 100" # Update the route-map and add "on-match next" to entry 10 @@ -102,7 +102,7 @@ def test_bgp_route_map_on_match_next(): # Check that metric is 20 and weight is 100 for the received prefix test_func = functools.partial(_bgp_has_routes, router2, 20, 100) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 20 and weight 100" diff --git a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py index 37082b48..a6641348 100644 --- a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py +++ b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py @@ -24,7 +24,6 @@ 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] @@ -61,7 +60,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py b/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py index 673efc2c..16afda8b 100644 --- a/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py +++ b/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py @@ -11,7 +11,6 @@ import os import sys -import json import pytest import functools diff --git a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py index 18b7831a..29d9842d 100644 --- a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py +++ b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py @@ -44,7 +44,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py index f52b28a0..7b40bbda 100644 --- a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py +++ b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py @@ -44,7 +44,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py index 9984abaa..5022a4a4 100644 --- a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py +++ b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py @@ -132,7 +132,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: output = router.vtysh_cmd("show ip route json", isjson=True) diff --git a/tests/topotests/bgp_self_prefix/__init__.py b/tests/topotests/bgp_self_prefix/__init__.py new file mode 100644 index 00000000..e69de29b 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 00000000..879afb19 --- /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 00000000..eb0db356 --- /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 00000000..e2348f4a --- /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 00000000..10458003 --- /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 +# + +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_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py index db6dbc61..6983a351 100644 --- a/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py +++ b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) 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 85e7b967..a5232ad6 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 @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -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_set_aspath_replace/test_bgp_set_aspath_replace.py b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py index c0e19fa3..fe4eda60 100644 --- a/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py +++ b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py b/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py index 292cf70d..e201ec9f 100644 --- a/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py +++ b/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py @@ -47,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -100,12 +100,12 @@ def test_bgp_set_local_preference(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) test_func = functools.partial(_bgp_check_local_preference, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see applied BGP local-preference in "{}"'.format( router diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py index 0131e125..09eef513 100755 --- a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py +++ b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py @@ -325,7 +325,6 @@ def router_interface_get_ifindex(router, interface): def generate_vrf_ifindex_oid(vrf, ifindex): - intoid = snmp_uint32_to_oid(int(ifindex)) vrfoid = snmp_str_to_oid(vrf) oid = "{}.{}".format(vrfoid, intoid) diff --git a/tests/topotests/bgp_software_version/test_bgp_software_version.py b/tests/topotests/bgp_software_version/test_bgp_software_version.py index c867208d..9aff53a0 100644 --- a/tests/topotests/bgp_software_version/test_bgp_software_version.py +++ b/tests/topotests/bgp_software_version/test_bgp_software_version.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_soo/test_bgp_soo.py b/tests/topotests/bgp_soo/test_bgp_soo.py index 967bed02..b0c70f20 100644 --- a/tests/topotests/bgp_soo/test_bgp_soo.py +++ b/tests/topotests/bgp_soo/test_bgp_soo.py @@ -73,7 +73,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py index 92315bce..f8385401 100755 --- a/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py +++ b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py @@ -8,10 +8,7 @@ # import os -import re import sys -import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -19,9 +16,7 @@ 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 from lib.checkping import check_ping diff --git a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py index 14b9ba84..0b52c87d 100755 --- a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py +++ b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py @@ -9,10 +9,7 @@ # import os -import re import sys -import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,9 +17,7 @@ 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 from lib.checkping import check_ping diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py index f0c91442..4bd5fdf1 100755 --- a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py @@ -6,10 +6,8 @@ # import os -import re import sys import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,7 +18,6 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py index 984cf97e..8d303a77 100755 --- a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py +++ b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py @@ -20,7 +20,6 @@ # import os -import re import sys import json import functools @@ -106,7 +105,7 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() router_list = tgen.routers() - for i, (rname, router) in enumerate(tgen.routers().items(), 1): + for _, (rname, router) in enumerate(tgen.routers().items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -180,7 +179,7 @@ def check_rib(name, cmd, expected_file): 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) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py index 4afaeaf7..a6938668 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py @@ -92,7 +92,8 @@ def setup_module(mod): tgen.start_topology() router_list = tgen.routers() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -147,7 +148,7 @@ def check_rib(name, cmd, expected_file): 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) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py index 914c29f0..c4798074 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py @@ -9,7 +9,6 @@ # import os -import re import sys import json import functools @@ -56,7 +55,8 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -109,7 +109,7 @@ def check_rib(name, cmd, expected_file): 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) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" 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 8a7b558b..bba00618 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] @@ -53,7 +53,8 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -106,7 +107,7 @@ def check_rib(name, cmd, expected_file): 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) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" 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 c1bc6400..3932c29b 100644 --- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py +++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py @@ -15,7 +15,6 @@ import sys import json import pytest from functools import partial -from time import sleep from lib.topolog import logger CWD = os.path.dirname(os.path.realpath(__file__)) @@ -47,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_tcp_mss/r1/bgpd.conf b/tests/topotests/bgp_tcp_mss/r1/bgpd.conf index 07cfe2e2..12e5df28 100644 --- a/tests/topotests/bgp_tcp_mss/r1/bgpd.conf +++ b/tests/topotests/bgp_tcp_mss/r1/bgpd.conf @@ -1,5 +1,8 @@ router bgp 65000 no bgp ebgp-requires-policy + neighbor aaa peer-group + neighbor aaa remote-as 65001 + neighbor 192.168.254.2 peer-group aaa neighbor 192.168.255.2 remote-as 65001 neighbor 192.168.255.2 timers 3 10 exit-address-family diff --git a/tests/topotests/bgp_tcp_mss/r1/zebra.conf b/tests/topotests/bgp_tcp_mss/r1/zebra.conf index 6e9b0b4a..57958c44 100644 --- a/tests/topotests/bgp_tcp_mss/r1/zebra.conf +++ b/tests/topotests/bgp_tcp_mss/r1/zebra.conf @@ -2,5 +2,8 @@ interface r1-eth0 ip address 192.168.255.1/24 ! +interface r1-eth1 + ip address 192.168.254.1/24 +! ip forwarding ! diff --git a/tests/topotests/bgp_tcp_mss/r2/bgpd.conf b/tests/topotests/bgp_tcp_mss/r2/bgpd.conf index b2d94558..8a5a4062 100644 --- a/tests/topotests/bgp_tcp_mss/r2/bgpd.conf +++ b/tests/topotests/bgp_tcp_mss/r2/bgpd.conf @@ -1,5 +1,8 @@ router bgp 65001 no bgp ebgp-requires-policy + neighbor aaa peer-group + neighbor aaa remote-as 65000 + neighbor 192.168.254.1 peer-group aaa neighbor 192.168.255.1 remote-as 65000 neighbor 192.168.255.1 timers 3 10 exit-address-family diff --git a/tests/topotests/bgp_tcp_mss/r2/zebra.conf b/tests/topotests/bgp_tcp_mss/r2/zebra.conf index 6c14de58..f2daa523 100644 --- a/tests/topotests/bgp_tcp_mss/r2/zebra.conf +++ b/tests/topotests/bgp_tcp_mss/r2/zebra.conf @@ -2,5 +2,8 @@ interface r2-eth0 ip address 192.168.255.2/24 ! +interface r2-eth1 + ip address 192.168.254.2/24 +! ip forwarding ! diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py index 4855d5c7..30449a39 100644 --- a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py +++ b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py @@ -45,6 +45,10 @@ def build_topo(tgen): switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) @@ -52,7 +56,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -78,12 +82,16 @@ def test_bgp_tcp_mss(): router2 = tgen.gears["r2"] def _bgp_converge(router): - output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json")) + output = json.loads(router.vtysh_cmd("show ip bgp neighbor json")) expected = { "192.168.255.2": { "bgpState": "Established", "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 0}}, - } + }, + "192.168.254.2": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 0}}, + }, } return topotest.json_cmp(output, expected) @@ -108,7 +116,7 @@ def test_bgp_tcp_mss(): logger.info("Check if neighbor sessions are up in {}".format(router1.name)) test_func = functools.partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=1) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) logger.info("BGP neighbor session is up in {}".format(router1.name)) @@ -117,19 +125,21 @@ def test_bgp_tcp_mss(): "Configure tcp-mss 500 on {} and reset the session".format(router1.name) ) _bgp_conf_tcp_mss(router1, "65000", "192.168.255.2") + _bgp_conf_tcp_mss(router1, "65000", "aaa") _bgp_clear_session(router1) logger.info( "Configure tcp-mss 500 on {} and reset the session".format(router2.name) ) _bgp_conf_tcp_mss(router2, "65001", "192.168.255.1") + _bgp_conf_tcp_mss(router2, "65001", "aaa") _bgp_clear_session(router2) logger.info( "Check if neighbor session is up after reset in {}".format(router1.name) ) test_func = functools.partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=1) assert result is None, 'Failed to see BGP convergence after reset in "{}"'.format( router1.name ) @@ -138,7 +148,13 @@ def test_bgp_tcp_mss(): "Verify if TCP MSS value is synced with neighbor in {}".format(router1.name) ) test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router1, "192.168.255.2") - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=1) + assert ( + result is None + ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router1.name) + + test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router1, "192.168.254.2") + success, result = topotest.run_and_expect(test_func, None, count=15, wait=1) assert ( result is None ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router1.name) @@ -148,7 +164,13 @@ def test_bgp_tcp_mss(): "Verify if TCP MSS value is synced with neighbor in {}".format(router2.name) ) test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router2, "192.168.255.1") - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=1) + assert ( + result is None + ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router2.name) + + test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router2, "192.168.254.1") + success, result = topotest.run_and_expect(test_func, None, count=15, wait=1) assert ( result is None ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router2.name) diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py index aeb9bf52..4a03cb0a 100644 --- a/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py +++ b/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py @@ -17,12 +17,7 @@ Need to verify if the tcp-mss value is reflected in the TCP session and in VRF. import os import sys -import json import pytest -import functools -import platform -import socket -import subprocess # add after imports, before defining classes or functions: pytestmark = [pytest.mark.bgpd] @@ -31,43 +26,27 @@ 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.topogen import Topogen, get_topogen from lib.topojson import build_config_from_json -from lib.topolog import logger import time from lib.bgp import ( clear_bgp, - clear_bgp_and_verify, create_router_bgp, - modify_as_number, - verify_as_numbers, verify_bgp_convergence, verify_bgp_rib, - verify_bgp_timers_and_functionality, - verify_router_id, verify_tcp_mss, ) from lib.common_config import ( kill_router_daemons, start_router_daemons, - addKernelRoute, apply_raw_config, check_address_types, check_router_status, - create_prefix_lists, - create_route_maps, create_static_routes, required_linux_kernel_version, - reset_config_on_routers, start_topology, step, - verify_admin_distance_for_static_routes, - verify_bgp_community, - verify_fib_routes, - verify_rib, write_test_footer, - write_test_header, ) # Global variables diff --git a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py index cd405f7b..44336efe 100644 --- a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py +++ b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py @@ -21,7 +21,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py index 2a53547f..09b13e6a 100644 --- a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py +++ b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py @@ -27,7 +27,6 @@ pytestmark = [pytest.mark.bgpd] def build_topo(tgen): - tgen.add_router("r1") tgen.add_router("r2") @@ -42,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -84,7 +83,7 @@ def test_bgp_unnumbered_removal(): step("Ensure Convergence of BGP") test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"]) @@ -109,7 +108,7 @@ def test_bgp_unnumbered_removal(): step("Ensure that BGP does not crash") test_func = functools.partial(_bgp_nexthop_cache) - success, result = topotest.run_and_expect(test_func, True, count=10, wait=1) + _, result = topotest.run_and_expect(test_func, True, count=10, wait=1) assert result is True, "BGP did not crash on r1" diff --git a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py index 4e66cf55..59f4bcd3 100644 --- a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py +++ b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py @@ -90,7 +90,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -169,7 +169,7 @@ def test_bgp_update_delay(): # Check r2 initial convergence in default table test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed bgp convergence in "{}"'.format(router2) @@ -195,7 +195,7 @@ def test_bgp_update_delay(): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_update_delay_in_progress, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay max-delay timer "{}"'.format( router2 @@ -203,7 +203,7 @@ def test_bgp_update_delay(): # Check that r2 only installs route learned from r4 after the max-delay timer expires test_func = functools.partial(_bgp_check_route_install, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to install route after update-delay "{}"'.format( router2 @@ -219,7 +219,7 @@ def test_bgp_update_delay(): ) test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None @@ -229,7 +229,7 @@ def test_bgp_update_delay(): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router3) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None @@ -250,7 +250,7 @@ def test_bgp_update_delay(): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to remove update-delay delay timing "{}"'.format( router2 @@ -266,14 +266,14 @@ def test_bgp_update_delay(): # Check that r2 default instance and vrf1 have the max-delay and establish set test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay in default instance "{}"'.format( router2 ) test_func = functools.partial(_bgp_check_vrf_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay in vrf1 "{}"'.format(router2) @@ -281,7 +281,7 @@ def test_bgp_update_delay(): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router3) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None diff --git a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py index eb29875d..08d6e140 100644 --- a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py +++ b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py @@ -22,7 +22,6 @@ 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] @@ -67,7 +66,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) 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 00000000..e69de29b 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 00000000..2a2288cf --- /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 00000000..6fe07f56 --- /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 00000000..ccea88b2 --- /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 +# + +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_asbr/test_bgp_vpnv4_asbr.py b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py index 39865eb1..5467cf4d 100644 --- a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py +++ b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py @@ -203,7 +203,7 @@ def bgp_vpnv4_prefix_check(router, rd, prefix, label, nexthop): ) func = functools.partial(_check, router, prefix, rd, label, nexthop) - success, result = topotest.run_and_expect(func, None, count=20, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=20, wait=0.5) assert_msg = "{}, show bgp ipv4 vpn {}, rd {}, label {} nexthop {}".format( router.name, prefix, rd, label, nexthop ) @@ -312,7 +312,7 @@ def check_show_bgp_vpn_ok(router, vpnv4_entries): return "{0}, {1}, route distinguisher not present".format( router.name, prefix ) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: if "remoteLabel" not in path.keys(): return "{0}, {1}, remoteLabel not present".format( @@ -324,7 +324,7 @@ def check_show_bgp_vpn_ok(router, vpnv4_entries): for prefix, rname_to_test in vpnv4_entries.items(): func = functools.partial(_check_nexthop_available, router, prefix) - success, result = topotest.run_and_expect(func, None, count=20, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=20, wait=0.5) assert result is None, "Failed to detect prefix {} on router {}".format( prefix, router.name ) @@ -456,7 +456,7 @@ def test_r3_prefixes_removed(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) # diagnostic @@ -491,7 +491,7 @@ def test_r3_prefixes_removed(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) logger.info( @@ -502,7 +502,7 @@ def test_r3_prefixes_removed(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, label_ip_entries[prefix] ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with in_label {} still present".format( label_ip_entries[prefix] ) @@ -536,7 +536,7 @@ def test_r3_prefixes_added_back(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} not present".format(router.name, prefix) logger.info( @@ -564,7 +564,7 @@ def test_r3_prefixes_added_back(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} not present".format(router.name, prefix) # diagnostic @@ -611,7 +611,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, label ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry for {} with in_label {} still present".format( prefix, label ) @@ -626,7 +626,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): "444:3", label=label, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, mpls vpn update {} label {} is present".format( router.name, prefix, label ) @@ -639,7 +639,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): "444:3", nexthop="192.168.1.3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, mpls vpn update {} label {} is present".format( router.name, prefix, label ) @@ -727,7 +727,7 @@ def test_declare_vpn_network_with_different_label(): label=label, nexthop="192.168.1.3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, label {} not present".format( router.name, prefix, label ) @@ -787,7 +787,7 @@ def test_filter_vpn_network_from_r1(): "172.31.0.0/24", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, is still present".format( router.name, prefix ) @@ -804,7 +804,7 @@ def test_filter_vpn_network_from_r1(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, int(label) ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry for {} with in_label {} still present".format( prefix, label ) @@ -833,7 +833,7 @@ def test_unfilter_vpn_network_from_r1(): test_func = functools.partial( check_show_bgp_vpn_prefix_found, router, "ipv4", prefix, "444:1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, is not present".format(router.name, prefix) vpnv4_checks = { diff --git a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py index 18982431..dd9d5474 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py +++ b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py @@ -245,7 +245,7 @@ router bgp 65500 vrf vrf1 prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) @@ -279,7 +279,7 @@ route-map RMAP permit 1 prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) @@ -309,7 +309,7 @@ route-map RMAP permit 1 prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) @@ -339,7 +339,7 @@ router bgp 65500 vrf vrf1 prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) @@ -371,7 +371,7 @@ route-map RMAP permit 1 prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) @@ -400,7 +400,7 @@ route-map RMAP permit 1 prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) @@ -482,7 +482,7 @@ router bgp 65501 expected, exact=True, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.1 still present" 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 2769c6eb..cb072e3c 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 488dc4aa..43100aad 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 b751756f..b11b16bc 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 49d4066e..643aae40 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_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py index 037dd403..6237decf 100644 --- a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py +++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py @@ -141,7 +141,7 @@ def router_json_cmp_exact_filter(router, cmd, expected): # filter out tableVersion, version and nhVrfID json_output.pop("tableVersion") for rd, data in json_output["routes"]["routeDistinguishers"].items(): - for prefix, attrs in data.items(): + for _, attrs in data.items(): for attr in attrs: if "nhVrfId" in attr: attr.pop("nhVrfId") @@ -171,7 +171,7 @@ def router_vrf_json_cmp_exact_filter(router, cmd, expected): data.pop("tableVersion") if "routes" not in data: continue - for route, attrs in data["routes"].items(): + for _, attrs in data["routes"].items(): for attr in attrs: if "nhVrfId" in attr: attr.pop("nhVrfId") diff --git a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py index d4c355a4..146687d5 100644 --- a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py @@ -151,17 +151,28 @@ def teardown_module(_mod): tgen.stop_topology() -def check_bgp_vpnv4_prefix_presence(router, prefix): +def check_bgp_vpnv4_prefix_presence(router, prefix, table_version): "Check the presence of a prefix" tgen = get_topogen() dump = router.vtysh_cmd("show bgp ipv4 vpn {} json".format(prefix), isjson=True) if not dump: return "{}, prefix ipv4 vpn {} is not installed yet".format(router.name, prefix) + + for _, paths in dump.items(): + for path in paths["paths"]: + new_version = path["version"] + if new_version <= table_version: + return "{}, prefix ipv4 vpn {} has not been updated yet".format( + router.name, prefix + ) + return None -def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=None): +def bgp_vpnv4_table_check( + router, group, label_list=None, label_value_expected=None, table_version=0 +): """ Dump and check that vpnv4 entries have the same MPLS label value * 'router': the router to check @@ -173,8 +184,10 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: - test_func = functools.partial(check_bgp_vpnv4_prefix_presence, router, prefix) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + test_func = functools.partial( + check_bgp_vpnv4_prefix_presence, router, prefix, table_version + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv4 vpn {} is not installed yet".format( router.name, prefix ) @@ -183,7 +196,7 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N assert dump, "{0}, {1}, route distinguisher not present".format( router.name, prefix ) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: assert ( "remoteLabel" in path.keys() @@ -218,7 +231,7 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N ) -def bgp_vpnv4_table_check_all(router, label_list=None, same=False): +def bgp_vpnv4_table_check_all(router, label_list=None, same=False, table_version=0): """ Dump and check that vpnv4 entries are correctly configured with specific label values * 'router': the router to check @@ -236,6 +249,7 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False): + PREFIXES_REDIST + PREFIXES_CONNECTED, label_list=label_list, + table_version=table_version, ) else: for group in ( @@ -245,7 +259,9 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False): PREFIXES_REDIST, PREFIXES_CONNECTED, ): - bgp_vpnv4_table_check(router, group=group, label_list=label_list) + bgp_vpnv4_table_check( + router, group=group, label_list=label_list, table_version=table_version + ) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -350,6 +366,11 @@ def check_show_mpls_table_entry_label_not_found(router, inlabel): return None +def get_table_version(router): + table = router.vtysh_cmd("show bgp ipv4 vpn json", isjson=True) + return table["tableVersion"] + + def mpls_entry_get_interface(router, label): """ Assert that the label is in MPLS table @@ -450,7 +471,7 @@ def test_flapping_bgp_vrf_down(): test_func = functools.partial( _bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv4", "172.31.0.11/32" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r1, prefix 172.31.0.11/32 from r11 did not disappear. r11 still connected to rr ?" @@ -488,7 +509,7 @@ def test_flapping_bgp_vrf_up(): "172.31.0.11/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, prefix 172.31.0.11/32 from r11 not present. r11 still disconnected from rr ?" @@ -518,7 +539,7 @@ def test_recursive_route(): "172.31.0.30/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.30 not found" bgp_vpnv4_table_check(tgen.gears["r2"], group=PREFIXES_R11 + ["172.31.0.30/32"]) @@ -544,7 +565,7 @@ def test_recursive_route(): "172.31.0.30/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.30 still present" @@ -570,7 +591,7 @@ def test_prefix_changes_interface(): "172.31.0.50/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.50 not found" # diagnostic @@ -616,7 +637,7 @@ def test_prefix_changes_interface(): "444:1", label=oldlabel, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, vpnv4 update 172.31.0.50 with old label {0} still present".format(oldlabel) @@ -633,7 +654,7 @@ def test_prefix_changes_interface(): "172.31.0.50/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.50 not found" label_list = set() @@ -686,6 +707,7 @@ def test_changing_default_label_value(): old_len != 1 ), "r1, number of labels used should be greater than 1, oberved {} ".format(old_len) + table_version = get_table_version(router) logger.info("r1, vrf1, changing the default MPLS label value to export to 222") router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nlabel vpn export 222\n", @@ -699,13 +721,13 @@ def test_changing_default_label_value(): test_func = functools.partial( check_show_mpls_table_entry_label_found, router, 222, "vrf1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 222 not found" # check label repartition is ok logger.info("r1, vpnv4 table, check the number of labels used after modification") label_list = set() - bgp_vpnv4_table_check_all(router, label_list) + bgp_vpnv4_table_check_all(router, label_list, table_version=table_version) new_len = len(label_list) assert ( old_len == new_len @@ -734,6 +756,7 @@ def test_unconfigure_allocation_mode_nexthop(): logger.info("Unconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + table_version = get_table_version(router) router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nno label vpn export allocation-mode per-nexthop\n", isjson=False, @@ -746,13 +769,15 @@ def test_unconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list, same=True) + bgp_vpnv4_table_check_all( + router, label_list=label_list, same=True, table_version=table_version + ) assert len(label_list) == 1, "r1, multiple Label values found for vpnv4 updates" new_label = label_list.pop() @@ -782,6 +807,8 @@ def test_reconfigure_allocation_mode_nexthop(): logger.info("Reconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + + table_version = get_table_version(router) router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nlabel vpn export allocation-mode per-nexthop\n", isjson=False, @@ -794,13 +821,15 @@ def test_reconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list) + bgp_vpnv4_table_check_all( + router, label_list=label_list, table_version=table_version + ) assert len(label_list) != 1, "r1, only 1 label values found for vpnv4 updates" # Check mpls table with all values diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py index 3d5f8f64..5fef6e9e 100644 --- a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py @@ -150,17 +150,28 @@ def teardown_module(_mod): tgen.stop_topology() -def check_bgp_vpnv6_prefix_presence(router, prefix): +def check_bgp_vpnv6_prefix_presence(router, prefix, table_version): "Check the presence of a prefix" tgen = get_topogen() dump = router.vtysh_cmd("show bgp ipv6 vpn {} json".format(prefix), isjson=True) if not dump: return "{}, prefix ipv6 vpn {} is not installed yet".format(router.name, prefix) + + for _, paths in dump.items(): + for path in paths["paths"]: + new_version = path["version"] + if new_version <= table_version: + return "{}, prefix ipv6 vpn {} has not been updated yet".format( + router.name, prefix + ) + return None -def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=None): +def bgp_vpnv6_table_check( + router, group, label_list=None, label_value_expected=None, table_version=0 +): """ Dump and check that vpnv6 entries have the same MPLS label value * 'router': the router to check @@ -172,14 +183,16 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: - test_func = functools.partial(check_bgp_vpnv6_prefix_presence, router, prefix) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + test_func = functools.partial( + check_bgp_vpnv6_prefix_presence, router, prefix, table_version + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv6 vpn {} is not installed yet".format( router.name, prefix ) dump = router.vtysh_cmd("show bgp ipv6 vpn {} json".format(prefix), isjson=True) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: assert ( "remoteLabel" in path.keys() @@ -214,7 +227,7 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N ) -def bgp_vpnv6_table_check_all(router, label_list=None, same=False): +def bgp_vpnv6_table_check_all(router, label_list=None, same=False, table_version=0): """ Dump and check that vpnv6 entries are correctly configured with specific label values * 'router': the router to check @@ -231,6 +244,7 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False): + PREFIXES_REDIST_R14 + PREFIXES_CONNECTED, label_list=label_list, + table_version=table_version, ) else: for group in ( @@ -239,7 +253,9 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False): PREFIXES_REDIST_R14, PREFIXES_CONNECTED, ): - bgp_vpnv6_table_check(router, group=group, label_list=label_list) + bgp_vpnv6_table_check( + router, group=group, label_list=label_list, table_version=table_version + ) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -345,6 +361,11 @@ def check_show_mpls_table_entry_label_not_found(router, inlabel): return None +def get_table_version(router): + table = router.vtysh_cmd("show bgp ipv6 vpn json", isjson=True) + return table["tableVersion"] + + def mpls_entry_get_interface(router, label): """ Assert that the label is in MPLS table @@ -446,7 +467,7 @@ def test_flapping_bgp_vrf_down(): test_func = functools.partial( _bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv6", "172:31::11/128" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r1, prefix 172:31::11/128 from r11 did not disappear. r11 still connected to rr ?" @@ -488,7 +509,7 @@ def test_flapping_bgp_vrf_up(): "172:31::11/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, prefix 172:31::11/128 from r11 not present. r11 still disconnected from rr ?" @@ -526,7 +547,7 @@ def test_recursive_route(): # Check r2 received vpnv6 update with 172:31::30 test_func = functools.partial(_prefix30_found, tgen.gears["r2"]) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::30 not found" # that route should be sent along with label for 192::2:11 @@ -549,7 +570,7 @@ def test_recursive_route(): # Check r2 removed 172:31::30 vpnv6 update test_func = functools.partial(_prefix30_not_found, tgen.gears["r2"]) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::30 still present" @@ -575,7 +596,7 @@ def test_prefix_changes_interface(): "172:31::50/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::50 not found" # diagnostic @@ -621,7 +642,7 @@ def test_prefix_changes_interface(): "444:1", label=oldlabel, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, vpnv6 update 172:31::50 with old label {0} still present".format(oldlabel) @@ -638,7 +659,7 @@ def test_prefix_changes_interface(): "172:31::50/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv6 update 172:31::50 not found" label_list = set() @@ -691,6 +712,7 @@ def test_changing_default_label_value(): old_len != 1 ), "r1, number of labels used should be greater than 1, oberved {} ".format(old_len) + table_version = get_table_version(router) logger.info("r1, vrf1, changing the default MPLS label value to export to 222") router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export 222\n", @@ -704,13 +726,13 @@ def test_changing_default_label_value(): test_func = functools.partial( check_show_mpls_table_entry_label_found, router, 222, "vrf1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 222 not found" # check label repartition is ok logger.info("r1, VPNv6 table, check the number of labels used after modification") label_list = set() - bgp_vpnv6_table_check_all(router, label_list) + bgp_vpnv6_table_check_all(router, label_list, table_version=table_version) new_len = len(label_list) assert ( old_len == new_len @@ -750,7 +772,7 @@ def test_unconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv6 routes from r1 @@ -786,6 +808,7 @@ def test_reconfigure_allocation_mode_nexthop(): logger.info("Reconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + table_version = get_table_version(router) dump = router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export allocation-mode per-nexthop\n", isjson=False, @@ -798,13 +821,15 @@ def test_reconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv6 routes from r1 logger.info("Checking VPNv6 routes on r1") label_list = set() - bgp_vpnv6_table_check_all(router, label_list=label_list) + bgp_vpnv6_table_check_all( + router, label_list=label_list, table_version=table_version + ) assert len(label_list) != 1, "r1, only 1 label values found for VPNv6 updates" # Check mpls table with all values diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py index 32643c27..8d73e5f8 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py @@ -18,7 +18,6 @@ Following tests are covered to test BGP Multi-VRF Dynamic Route Leaking: import os import sys -import json import time import pytest import platform @@ -58,7 +57,7 @@ from lib.bgp import ( verify_best_path_as_per_bgp_attribute, verify_bgp_rib, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py index 726afcb6..25a73b58 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py @@ -23,7 +23,6 @@ import sys import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -49,7 +48,6 @@ from lib.common_config import ( create_static_routes, create_prefix_lists, create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py index 45d7b030..53f0239c 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py @@ -24,7 +24,6 @@ import sys import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ from lib.common_config import ( reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py index d29edf59..7b0eac3f 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py @@ -24,7 +24,6 @@ import sys import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ from lib.common_config import ( reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py index c118ffc0..ec7b25c7 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py @@ -24,7 +24,6 @@ import sys import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ from lib.common_config import ( reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py b/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py index b2081926..3539d06a 100755 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py @@ -6,10 +6,8 @@ # import os -import re import sys import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,7 +18,6 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py index f3521969..3790446d 100644 --- a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py @@ -49,9 +49,7 @@ from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, - clear_bgp, verify_best_path_as_per_bgp_attribute, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py index 3cb31809..262cacd1 100644 --- a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py @@ -19,7 +19,6 @@ import sys import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/__init__.py b/tests/topotests/bgp_weighted_ecmp_recursive/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf new file mode 100644 index 00000000..f7c591f7 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf @@ -0,0 +1,16 @@ +! +int r1-eth0 + ip address 192.168.12.1/24 +! +int r1-eth1 + ip address 192.168.13.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.12.2 remote-as internal + neighbor 192.168.12.2 timers 1 3 + neighbor 192.168.12.2 timers connect 1 + neighbor 192.168.13.3 remote-as internal + neighbor 192.168.13.3 timers 1 3 + neighbor 192.168.13.3 timers connect 1 +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf new file mode 100644 index 00000000..dc25d478 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf @@ -0,0 +1,20 @@ +! +int r2-eth0 + ip address 192.168.12.2/24 +! +int r2-eth1 + ip address 192.168.24.2/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.12.1 remote-as internal + neighbor 192.168.12.1 timers 1 3 + neighbor 192.168.12.1 timers connect 1 + neighbor 192.168.24.4 remote-as internal + neighbor 192.168.24.4 timers 1 3 + neighbor 192.168.24.4 timers connect 1 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.12.1 route-reflector-client + exit-address-family +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf new file mode 100644 index 00000000..bdeb35b5 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf @@ -0,0 +1,20 @@ +! +int r3-eth0 + ip address 192.168.13.3/24 +! +int r3-eth1 + ip address 192.168.35.3/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.13.1 remote-as internal + neighbor 192.168.13.1 timers 1 3 + neighbor 192.168.13.1 timers connect 1 + neighbor 192.168.35.5 remote-as internal + neighbor 192.168.35.5 timers 1 3 + neighbor 192.168.35.5 timers connect 1 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.13.1 route-reflector-client + exit-address-family +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf new file mode 100644 index 00000000..0662a4dc --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf @@ -0,0 +1,17 @@ +! +int r4-eth0 + ip address 192.168.24.4/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.24.2 remote-as internal + neighbor 192.168.24.2 timers 1 3 + neighbor 192.168.24.2 timers connect 1 + address-family ipv4 unicast + network 10.10.10.10/32 route-map rmap + exit-address-family +! +route-map rmap permit 10 + set extcommunity bandwidth 4000 +exit diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf new file mode 100644 index 00000000..bc24a96b --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf @@ -0,0 +1,17 @@ +! +int r5-eth0 + ip address 192.168.35.5/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.35.3 remote-as internal + neighbor 192.168.35.3 timers 1 3 + neighbor 192.168.35.3 timers connect 1 + address-family ipv4 unicast + network 10.10.10.10/32 route-map rmap + exit-address-family +! +route-map rmap permit 10 + set extcommunity bandwidth 5000 +exit 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 new file mode 100644 index 00000000..5dc917bd --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Test if weighted ECMP works and recursive weight (link bandwidth) is +inherited to non-recursive next-hops. +""" + +import os +import re +import sys +import json +import pytest +import functools + +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, TopoRouter, get_topogen +from lib.common_config import step + + +def setup_module(mod): + topodef = { + "s1": ("r1", "r2"), + "s2": ("r1", "r3"), + "s3": ("r2", "r4"), + "s4": ("r3", "r5"), + } + 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_weighted_ecmp_recursive(): + 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 ip route 10.10.10.10/32 json")) + expected = { + "10.10.10.10/32": [ + { + "selected": True, + "installed": True, + "nexthops": [ + { + "ip": "192.168.24.4", + "active": True, + "recursive": True, + "weight": 203, + }, + { + "ip": "192.168.12.2", + "active": True, + "resolver": True, + "weight": 203, + }, + { + "ip": "192.168.35.5", + "active": True, + "recursive": True, + "weight": 254, + }, + { + "ip": "192.168.13.3", + "active": True, + "resolver": True, + "weight": 254, + }, + ], + } + ] + } + 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/conftest.py b/tests/topotests/conftest.py index a2315138..44536e94 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 00000000..d677e200 --- /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 00000000..d68d13d0 --- /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 00000000..1359c57f --- /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 + +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/eigrp_topo1/test_eigrp_topo1.py b/tests/topotests/eigrp_topo1/test_eigrp_topo1.py index b3152f43..7ab1572d 100644 --- a/tests/topotests/eigrp_topo1/test_eigrp_topo1.py +++ b/tests/topotests/eigrp_topo1/test_eigrp_topo1.py @@ -143,7 +143,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: output = router.vtysh_cmd("show ip route json", isjson=True) diff --git a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py index 10d216ab..beb4de43 100644 --- a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py +++ b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py @@ -22,7 +22,6 @@ Following tests are covered to test EVPN-Type5 functionality: import os import sys -import json import time import pytest import platform @@ -69,7 +68,7 @@ from lib.bgp import ( verify_attributes_for_evpn_routes, verify_evpn_routes, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/example_munet/r1/frr.conf b/tests/topotests/example_munet/r1/frr.conf index 468bda5e..692e4ceb 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 77d98924..da3f15b8 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 e0839e6d..84527b34 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 0d9599fa..71052099 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 00000000..677ba8f6 --- /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 00000000..b6da6e22 --- /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 00000000..ea05f184 --- /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 00000000..fa048388 --- /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/fpm_testing_topo1/test_fpm_topo1.py b/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py index 22fc50b9..66cefcc2 100644 --- a/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py +++ b/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py @@ -14,7 +14,6 @@ test_fpm_topo1.py: Testing FPM module """ import os -import re import sys import pytest import json @@ -28,7 +27,6 @@ sys.path.append(os.path.join(CWD, "../")) # Import topogen and topotest helpers from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger pytestmark = [pytest.mark.fpm, pytest.mark.sharpd] diff --git a/tests/topotests/grpc_basic/test_basic_grpc.py b/tests/topotests/grpc_basic/test_basic_grpc.py index cf1c6d0e..5ff2894f 100644 --- a/tests/topotests/grpc_basic/test_basic_grpc.py +++ b/tests/topotests/grpc_basic/test_basic_grpc.py @@ -19,7 +19,6 @@ import pytest from lib.common_config import step from lib.micronet import commander from lib.topogen import Topogen, TopoRouter -from lib.topolog import logger from lib.topotest import json_cmp CWD = os.path.dirname(os.path.realpath(__file__)) @@ -60,7 +59,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf", f"-M grpc:{GRPCP_ZEBRA}") router.load_config(TopoRouter.RD_STATIC, "", f"-M grpc:{GRPCP_STATICD}") # router.load_config(TopoRouter.RD_BFDD, "", f"-M grpc:{GRPCP_BFDD}") diff --git a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py index ada8c0f5..ad896b74 100644 --- a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py +++ b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py @@ -30,8 +30,6 @@ import re import sys import pytest import json -from time import sleep -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -39,7 +37,6 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest from lib.common_config import ( retry, stop_router, diff --git a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py index 44b3dd0b..af28dbdf 100755 --- a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py +++ b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py @@ -42,7 +42,6 @@ import os import sys import pytest import json -import time import tempfile from functools import partial @@ -169,7 +168,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -832,7 +831,7 @@ def test_rib_ipv6_step18(): rname = "rt1" router = tgen.gears[rname] test_func = partial(_rt2_neigh_down, router) - success, result = topotest.run_and_expect(test_func, None, count=200, wait=0.05) + _, result = topotest.run_and_expect(test_func, None, count=200, wait=0.05) assert result is None, 'rt2 neighbor is still present on "{}"'.format(router) router_compare_json_output( @@ -1034,7 +1033,7 @@ def test_rib_ipv6_step24(): rname = "rt1" router = tgen.gears[rname] test_func = partial(_bfd_down, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.3) assert result is None, 'BFD session is still up on "{}"'.format(router) router_compare_json_output( diff --git a/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py b/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py index c4ce6a30..6f4653d2 100755 --- a/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py +++ b/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py @@ -131,7 +131,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py index 15327fe0..f97c7d2c 100755 --- a/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py +++ b/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py @@ -170,7 +170,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_snmp/test_isis_snmp.py b/tests/topotests/isis_snmp/test_isis_snmp.py index ddef0800..81c96b3d 100755 --- a/tests/topotests/isis_snmp/test_isis_snmp.py +++ b/tests/topotests/isis_snmp/test_isis_snmp.py @@ -147,7 +147,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py b/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py index c81f6394..d1fc6829 100755 --- a/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py +++ b/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py @@ -37,7 +37,6 @@ import os import sys import pytest import json -import tempfile from copy import deepcopy from functools import partial @@ -121,7 +120,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py index 6689cf4c..7d063910 100755 --- a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py +++ b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py @@ -47,7 +47,6 @@ import os import sys import pytest import json -import time from functools import partial # Save the Current Working Directory to find configuration files. @@ -67,7 +66,6 @@ pytestmark = [pytest.mark.isisd] def build_topo(tgen): "Build function" - routers = [] for i in range(0, 10): rt = tgen.add_router("rt{}".format(i)) rt.run("sysctl -w net.ipv4.fib_multipath_hash_policy=1") @@ -140,7 +138,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -174,7 +172,7 @@ def check_rib(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=120, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=120, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py b/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py index fc2ce7cb..cb4f4ffa 100755 --- a/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py +++ b/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py @@ -164,7 +164,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -641,7 +641,7 @@ def test_srte_route_map_with_sr_policy_check_nextop_step5(): ) # (re-)build the SR Policy two times to ensure that reinstalling still works - for i in [1, 2]: + for _ in [1, 2]: cmp_json_output( "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_inactive_srte.ref" ) diff --git a/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py b/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py index 9a4085ab..baf7e98b 100644 --- a/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py +++ b/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py @@ -137,7 +137,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref index bb10aba9..c4a5d750 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref index bb10aba9..c4a5d750 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref index bb10aba9..c4a5d750 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref index bb10aba9..c4a5d750 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref index bb10aba9..c4a5d750 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref index f3399319..f8a5d93f 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref index f3399319..f8a5d93f 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref index f3399319..f8a5d93f 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref index f3399319..f8a5d93f 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref index f3399319..f8a5d93f 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref index f3399319..f8a5d93f 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref index f3399319..f8a5d93f 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref index f3399319..f8a5d93f 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref index f3399319..f8a5d93f 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref index ffa62612..c6287058 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref index ffa62612..c6287058 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref index ffa62612..c6287058 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref index ffa62612..c6287058 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref index ffa62612..c6287058 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref index ffa62612..c6287058 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref index ffa62612..c6287058 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref index ffa62612..c6287058 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref index ffa62612..c6287058 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref index 189943f7..cb052dbb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref index 189943f7..cb052dbb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref index 189943f7..cb052dbb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref index 189943f7..cb052dbb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref index 189943f7..cb052dbb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref index 189943f7..cb052dbb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref index 189943f7..cb052dbb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref index 189943f7..cb052dbb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref index 189943f7..cb052dbb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref index 54780fce..ec55f24d 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref index 54780fce..ec55f24d 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref index 54780fce..ec55f24d 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref index 54780fce..ec55f24d 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref index 54780fce..ec55f24d 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref index 54780fce..ec55f24d 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref index 54780fce..ec55f24d 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref index 54780fce..ec55f24d 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref index 54780fce..ec55f24d 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref index 35aa61d8..abcdedde 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref index 35aa61d8..abcdedde 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref index 35aa61d8..abcdedde 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref index 35aa61d8..abcdedde 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref index 35aa61d8..abcdedde 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref index 35aa61d8..abcdedde 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref index 35aa61d8..abcdedde 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref index 35aa61d8..abcdedde 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref index 35aa61d8..abcdedde 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py index 1a7505dd..9c1a23f5 100644 --- a/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py +++ b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py @@ -60,7 +60,6 @@ test_isis_srv6_topo1.py: """ import os -import re import sys import json import functools @@ -212,7 +211,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" # Teardown the topology @@ -250,7 +249,7 @@ def check_ping6(name, dest_addr, expect_connected): 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) + _, result = topotest.run_and_expect(func, None, count=10, wait=1) assert result is None, "Failed" diff --git a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py index aaf6af0b..c8e66bef 100755 --- a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py @@ -54,7 +54,6 @@ import os import sys import pytest import json -import tempfile from functools import partial from time import sleep @@ -144,7 +143,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_topo1/r1/r1_topology.json b/tests/topotests/isis_topo1/r1/r1_topology.json index 337d6bf5..6b3374cc 100644 --- a/tests/topotests/isis_topo1/r1/r1_topology.json +++ b/tests/topotests/isis_topo1/r1/r1_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r1" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r2/r2_topology.json b/tests/topotests/isis_topo1/r2/r2_topology.json index de90fb5a..8720bc1c 100644 --- a/tests/topotests/isis_topo1/r2/r2_topology.json +++ b/tests/topotests/isis_topo1/r2/r2_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r2" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r3/r3_topology.json b/tests/topotests/isis_topo1/r3/r3_topology.json index 2d36f9b4..568b6dfe 100644 --- a/tests/topotests/isis_topo1/r3/r3_topology.json +++ b/tests/topotests/isis_topo1/r3/r3_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.254.0.1/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "metric": "10", - "interface": "r3-eth0", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::1/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.254.0.1/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "metric": 10, + "interface": "r3-eth0", + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::1/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r4/r4_topology.json b/tests/topotests/isis_topo1/r4/r4_topology.json index e7d78419..9a53955c 100644 --- a/tests/topotests/isis_topo1/r4/r4_topology.json +++ b/tests/topotests/isis_topo1/r4/r4_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.254.0.2/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "metric": "10", - "interface": "r4-eth0", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::2/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.254.0.2/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "metric": 10, + "interface": "r4-eth0", + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::2/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r5/r5_topology.json b/tests/topotests/isis_topo1/r5/r5_topology.json index 3d887b7c..64590d8e 100644 --- a/tests/topotests/isis_topo1/r5/r5_topology.json +++ b/tests/topotests/isis_topo1/r5/r5_topology.json @@ -1,156 +1,154 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index b629757d..1cec2f16 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -104,7 +104,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -120,19 +120,13 @@ def test_isis_convergence(): pytest.skip(tgen.errors) logger.info("waiting for ISIS protocol to converge") - # Code to generate the json files. - # for rname, router in tgen.routers().items(): - # open('/tmp/{}_topology.json'.format(rname), 'w').write( - # json.dumps(show_isis_topology(router), indent=2, sort_keys=True) - # ) - for rname, router in tgen.routers().items(): filename = "{0}/{1}/{1}_topology.json".format(CWD, rname) expected = json.loads(open(filename).read()) def compare_isis_topology(router, expected): "Helper function to test ISIS topology convergence." - actual = show_isis_topology(router) + actual = json.loads(router.vtysh_cmd("show isis topology json")) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -160,7 +154,7 @@ def test_isis_route_installation(): return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_installed_routes, router, expected) - (result, diff) = topotest.run_and_expect(test_func, None, wait=1, count=10) + (result, _) = topotest.run_and_expect(test_func, None, wait=1, count=10) assertmsg = "Router '{}' routes mismatch".format(rname) assert result, assertmsg @@ -205,7 +199,7 @@ def test_isis_route6_installation(): test_func = functools.partial( compare_isis_v6_installed_routes, router, expected ) - (result, diff) = topotest.run_and_expect(test_func, None, wait=1, count=10) + (result, _) = topotest.run_and_expect(test_func, None, wait=1, count=10) assertmsg = "Router '{}' routes mismatch".format(rname) assert result, assertmsg @@ -237,7 +231,7 @@ def test_isis_summary_json(): pytest.skip(tgen.errors) logger.info("Checking 'show isis summary json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True) assertmsg = "Test isis summary json failed in '{}' data '{}'".format( @@ -257,7 +251,7 @@ def test_isis_interface_json(): pytest.skip(tgen.errors) logger.info("Checking 'show isis interface json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis interface json", isjson=True @@ -294,7 +288,7 @@ def test_isis_neighbor_json(): # tgen.mininet_cli() logger.info("Checking 'show isis neighbor json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis neighbor json", isjson=True @@ -330,7 +324,7 @@ def test_isis_database_json(): # tgen.mininet_cli() logger.info("Checking 'show isis database json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis database json", isjson=True @@ -685,6 +679,9 @@ def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected): ) database_json = json.loads(isis_database_output) + if "lsps" not in database_json["areas"][0]["levels"][1]: + return "The LSP of {} has not been synchronized yet ".format(router.name) + att_p_ol = database_json["areas"][0]["levels"][1]["lsps"][0]["attPOl"] if att_p_ol == att_p_ol_expected: return True @@ -755,7 +752,7 @@ def dict_merge(dct, merge_dct): Source: https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 """ - for k, v in merge_dct.items(): + for k, _ in merge_dct.items(): if k in dct and isinstance(dct[k], dict) and topotest.is_mapping(merge_dct[k]): dict_merge(dct[k], merge_dct[k]) else: @@ -845,52 +842,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-1") - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-2") - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 diff --git a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json index 666fa52b..da537c55 100644 --- a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json +++ b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r1" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json index c26ad1ee..bf965659 100644 --- a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json +++ b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r2" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json index 044a6c04..94592b50 100644 --- a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json +++ b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + } + ] }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json index d40008aa..b8295e87 100644 --- a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json +++ b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + } + ] }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json index 2a088cae..8b5159cb 100644 --- a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json +++ b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json @@ -1,124 +1,122 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py index 032319c4..afc6864b 100644 --- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py @@ -118,7 +118,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() # move back rx-eth0 to default VRF @@ -141,8 +141,9 @@ def test_isis_convergence(): def compare_isis_topology(router, expected): "Helper function to test ISIS vrf topology convergence." - actual = show_isis_topology(router) - + actual = json.loads( + router.vtysh_cmd(f"show isis vrf {router.name}-cust1 topology json") + ) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -287,7 +288,7 @@ def dict_merge(dct, merge_dct): Source: https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 """ - for k, v in merge_dct.items(): + for k, _ in merge_dct.items(): if k in dct and isinstance(dct[k], dict) and topotest.is_mapping(merge_dct[k]): dict_merge(dct[k], merge_dct[k]) else: @@ -377,52 +378,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS vrf topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name)) - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name)) - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 diff --git a/tests/topotests/key_sendaccept/test_keychain.py b/tests/topotests/key_sendaccept/test_keychain.py index b11d31b9..1d24c170 100644 --- a/tests/topotests/key_sendaccept/test_keychain.py +++ b/tests/topotests/key_sendaccept/test_keychain.py @@ -27,7 +27,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/kinds.yaml b/tests/topotests/kinds.yaml index 5f4b61d4..20c819c7 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/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py index c2bcaa84..8123e049 100644 --- a/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py +++ b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py @@ -117,7 +117,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py index 387fd89c..bfb93d55 100644 --- a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py +++ b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py @@ -116,7 +116,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py b/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py index 52a67d8b..ea404bea 100644 --- a/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py +++ b/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py @@ -136,7 +136,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py b/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py index cb6b784d..f2c41ebe 100644 --- a/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py +++ b/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py @@ -129,7 +129,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py b/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py index 760b4e3d..9e41e06c 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py +++ b/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py @@ -128,7 +128,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py index 1f4a4b5f..c14c79e6 100644 --- a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py @@ -129,7 +129,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 3a16ed5a..bcd1c748 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -333,7 +333,7 @@ def __create_bgp_global(tgen, input_dict, router, build=False): else: del_action = False - for rs_timer, value in timer.items(): + for rs_timer, _ in timer.items(): rs_timer_value = timer.setdefault(rs_timer, None) if rs_timer_value and rs_timer != "delete": @@ -1229,7 +1229,7 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict): # Copy bgp config file to /etc/frr for dut in input_dict.keys(): router_list = tgen.routers() - for router, rnode in router_list.items(): + for router, _ in router_list.items(): if router != dut: continue @@ -1750,7 +1750,7 @@ def verify_as_numbers(tgen, topo, input_dict, expected=True): for bgp_neighbor, peer_data in bgp_neighbors.items(): remote_as = input_dict[bgp_neighbor]["bgp"]["local_as"] - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): neighbor_ip = None data = topo["routers"][bgp_neighbor]["links"] @@ -1833,7 +1833,7 @@ def verify_bgp_convergence_from_running_config(tgen, dut=None, expected=True): return errormsg for vrf, addr_family_data in show_bgp_json.items(): - for address_family, neighborship_data in addr_family_data.items(): + for _, neighborship_data in addr_family_data.items(): total_peer = 0 no_of_peer = 0 @@ -1980,7 +1980,7 @@ def clear_bgp_and_verify(tgen, topo, router, rid=None): bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] for bgp_neighbor, peer_data in bgp_neighbors.items(): - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3231,7 +3231,7 @@ def verify_graceful_restart( if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3266,27 +3266,43 @@ def verify_graceful_restart( lmode = None rmode = None + # Local GR mode - if "address_family" in input_dict[dut]["bgp"]: - bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ - "unicast" - ]["neighbor"][peer]["dest_link"] + if "bgp" not in input_dict[dut] and "graceful-restart" in input_dict[dut]: + if ( + "graceful-restart" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart"] + ): + lmode = "Restart*" + elif ( + "graceful-restart-disable" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart-disable"] + ): + lmode = "Disable*" + else: + lmode = "Helper*" - for dest_link, data in bgp_neighbors.items(): - if ( - "graceful-restart-helper" in data - and data["graceful-restart-helper"] - ): - lmode = "Helper" - elif "graceful-restart" in data and data["graceful-restart"]: - lmode = "Restart" - elif ( - "graceful-restart-disable" in data - and data["graceful-restart-disable"] - ): - lmode = "Disable" - else: - lmode = None + if lmode is None: + if "address_family" in input_dict[dut]["bgp"]: + bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ + "unicast" + ]["neighbor"][peer]["dest_link"] + + for dest_link, data in bgp_neighbors.items(): + if ( + "graceful-restart-helper" in data + and data["graceful-restart-helper"] + ): + lmode = "Helper" + elif "graceful-restart" in data and data["graceful-restart"]: + lmode = "Restart" + elif ( + "graceful-restart-disable" in data + and data["graceful-restart-disable"] + ): + lmode = "Disable" + else: + lmode = None if lmode is None: if "graceful-restart" in input_dict[dut]["bgp"]: @@ -3314,7 +3330,11 @@ def verify_graceful_restart( return True # Remote GR mode - if "address_family" in input_dict[peer]["bgp"]: + + if ( + "bgp" in input_dict[peer] + and "address_family" in input_dict[peer]["bgp"] + ): bgp_neighbors = input_dict[peer]["bgp"]["address_family"][addr_type][ "unicast" ]["neighbor"][dut]["dest_link"] @@ -3336,7 +3356,10 @@ def verify_graceful_restart( rmode = None if rmode is None: - if "graceful-restart" in input_dict[peer]["bgp"]: + if ( + "bgp" in input_dict[peer] + and "graceful-restart" in input_dict[peer]["bgp"] + ): if ( "graceful-restart" in input_dict[peer]["bgp"]["graceful-restart"] @@ -3355,6 +3378,27 @@ def verify_graceful_restart( rmode = "Disable" else: rmode = "Helper" + + if rmode is None: + if ( + "bgp" not in input_dict[peer] + and "graceful-restart" in input_dict[peer] + ): + if ( + "graceful-restart" in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"]["graceful-restart"] + ): + rmode = "Restart" + elif ( + "graceful-restart-disable" + in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"][ + "graceful-restart-disable" + ] + ): + rmode = "Disable" + else: + rmode = "Helper" else: rmode = "Helper" @@ -3479,7 +3523,7 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3597,7 +3641,7 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3762,7 +3806,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3890,7 +3934,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer) if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: diff --git a/tests/topotests/lib/bgprib.py b/tests/topotests/lib/bgprib.py index 699c7a4d..f01a440b 100644 --- a/tests/topotests/lib/bgprib.py +++ b/tests/topotests/lib/bgprib.py @@ -64,10 +64,9 @@ class BgpRib: self.log("missing route: pfx=" + want["p"] + ", nh=" + want["n"]) return 0 - def RequireVpnRoutes(self, target, title, wantroutes, debug=0): + def RequireVpnRoutesOne(self, target, title, wantroutes, debug=0): import json - logstr = "RequireVpnRoutes " + str(wantroutes) # non json form for humans luCommand( target, @@ -86,11 +85,18 @@ class BgpRib: if re.search(r"^\s*$", ret): # degenerate case: empty json means no routes if len(wantroutes) > 0: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False + return True rib = json.loads(ret) - rds = rib["routes"]["routeDistinguishers"] + try: + rds = rib["routes"]["routeDistinguishers"] + except KeyError as err: + # KeyError: 'routes' probably means missing/bad VRF + # This error also happens if we are too quick and the routing + # table has not been fully populated yet. + if debug: + self.log("KeyError, no routes") + return False for want in wantroutes: found = 0 if debug: @@ -105,11 +111,39 @@ class BgpRib: found = 1 break if not found: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False + return True + + def RequireVpnRoutes( + self, target, title, wantroutes, debug=0, wait=10, wait_time=0.5 + ): + import time + import math + + logstr = "RequireVpnRoutes " + str(wantroutes) + found = False + n = 0 + startt = time.time() + + # Calculate the amount of `sleep`s we are going to peform. + wait_count = int(math.ceil(wait / wait_time)) + 1 + + while wait_count > 0: + n += 1 + found = self.RequireVpnRoutesOne(target, title, wantroutes, debug) + if found is not False: + break - def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): + wait_count -= 1 + if wait_count > 0: + time.sleep(wait_time) + + delta = time.time() - startt + self.log("Done after %d loops, time=%s, Found=%s" % (n, delta, found)) + luResult(target, found, title, logstr) + return found + + def RequireUnicastRoutesOne(self, target, afi, vrf, title, wantroutes, debug=0): logstr = "RequireUnicastRoutes %s" % str(wantroutes) vrfstr = "" if vrf != "": @@ -129,9 +163,8 @@ class BgpRib: if re.search(r"^\s*$", ret): # degenerate case: empty json means no routes if len(wantroutes) > 0: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False, "" + return True, "" rib = json.loads(ret) try: table = rib["routes"] @@ -141,25 +174,60 @@ class BgpRib: errstr = "-script ERROR: check if wrong vrf (%s)" % (vrf) else: errstr = "-script ERROR: check if vrf missing" - luResult(target, False, title + errstr, logstr) - return + self.log(errstr) + return False, errstr # if debug: # self.log("table=%s" % table) for want in wantroutes: if debug: self.log("want=%s" % want) if not self.routes_include_wanted(table, want, debug): - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False, "" + return True, "" + + def RequireUnicastRoutes( + self, target, afi, vrf, title, wantroutes, debug=0, wait=10, wait_time=0.5 + ): + import time + import math + + logstr = "RequireUnicastRoutes %s" % str(wantroutes) + found = False + n = 0 + startt = time.time() + errstr = "" + + # Calculate the amount of `sleep`s we are going to peform. + wait_count = int(math.ceil(wait / wait_time)) + 1 + + while wait_count > 0: + n += 1 + found, errstr = self.RequireUnicastRoutesOne( + target, afi, vrf, title, wantroutes, debug + ) + if found is not False: + break + + wait_count -= 1 + if wait_count > 0: + time.sleep(wait_time) + + delta = time.time() - startt + self.log("Done after %d loops, time=%s, Found=%s" % (n, delta, found)) + luResult(target, found, title + errstr, logstr) + return found BgpRib = BgpRib() -def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0): - BgpRib.RequireVpnRoutes(target, title, wantroutes, debug) +def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0, wait=10, wait_time=0.5): + BgpRib.RequireVpnRoutes(target, title, wantroutes, debug, wait, wait_time) -def bgpribRequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug=0): - BgpRib.RequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug) +def bgpribRequireUnicastRoutes( + target, afi, vrf, title, wantroutes, debug=0, wait=10, wait_time=0.5 +): + BgpRib.RequireUnicastRoutes( + target, afi, vrf, title, wantroutes, debug, wait, wait_time + ) diff --git a/tests/topotests/lib/checkping.py b/tests/topotests/lib/checkping.py index 5500807f..aa95f45b 100644 --- a/tests/topotests/lib/checkping.py +++ b/tests/topotests/lib/checkping.py @@ -33,5 +33,5 @@ def check_ping(name, dest_addr, expect_connected, count, wait, source_addr=None) logger.info("[+] check {} {} {}".format(name, dest_addr, match)) tgen = get_topogen() func = functools.partial(_check, name, dest_addr, source_addr, match) - success, result = topotest.run_and_expect(func, None, count=count, wait=wait) + _, result = topotest.run_and_expect(func, None, count=count, wait=wait) assert result is None, "Failed" diff --git a/tests/topotests/lib/common_check.py b/tests/topotests/lib/common_check.py new file mode 100644 index 00000000..b04b9de4 --- /dev/null +++ b/tests/topotests/lib/common_check.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC +# +# common_check.py +# +# Copyright 2024 6WIND S.A. + +# +import json +from lib import topotest + + +def ip_check_path_selection( + router, ipaddr_str, expected, vrf_name=None, check_fib=False +): + if vrf_name: + cmdstr = f"show ip route vrf {vrf_name} {ipaddr_str} json" + else: + cmdstr = f"show ip route {ipaddr_str} json" + try: + output = json.loads(router.vtysh_cmd(cmdstr)) + except: + output = {} + + ret = topotest.json_cmp(output, expected) + if ret is None: + num_nh_expected = len(expected[ipaddr_str][0]["nexthops"]) + num_nh_observed = len(output[ipaddr_str][0]["nexthops"]) + if num_nh_expected == num_nh_observed: + if check_fib: + # special case: when fib flag is unset, + # an extra test should be done to check that the flag is really unset + for nh_output, nh_expected in zip( + output[ipaddr_str][0]["nexthops"], + expected[ipaddr_str][0]["nexthops"], + ): + if ( + "fib" in nh_output.keys() + and nh_output["fib"] + and ("fib" not in nh_expected.keys() or not nh_expected["fib"]) + ): + return "{}, prefix {} nexthop {} has the fib flag set, whereas it is not expected".format( + router.name, ipaddr_str, nh_output["ip"] + ) + return ret + return "{}, prefix {} does not have the correct number of nexthops : observed {}, expected {}".format( + router.name, ipaddr_str, num_nh_observed, num_nh_expected + ) + return ret + + +def iproute2_check_path_selection(router, ipaddr_str, expected, vrf_name=None): + if not topotest.iproute2_is_json_capable(): + return None + + if vrf_name: + cmdstr = f"ip -json route show vrf {vrf_name} {ipaddr_str}" + else: + cmdstr = f"ip -json route show {ipaddr_str}" + try: + output = json.loads(router.cmd(cmdstr)) + except: + output = [] + + return topotest.json_cmp(output, expected) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 7787b6f7..f34c48b8 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -7,7 +7,6 @@ import functools import ipaddress -import json import os import platform import socket @@ -442,7 +441,7 @@ def check_router_status(tgen): try: router_list = tgen.routers() - for router, rnode in router_list.items(): + for _, rnode in router_list.items(): result = rnode.check_router_running() if result != "": daemons = [] @@ -686,7 +685,7 @@ def prep_load_config_to_routers(tgen, *config_name_list): """ routers = tgen.routers() - for rname, router in routers.items(): + for rname, _ in routers.items(): destname = "{}/{}/{}".format(tgen.logdir, rname, FRRCFG_FILE) wmode = "w" for cfbase in config_name_list: @@ -871,7 +870,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): """ router_list = tgen.routers() - for rname, rnode in router_list.items(): + for rname, _ in router_list.items(): if rname != router: continue @@ -887,7 +886,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): cmd = "show interface vrf {}".format(vrf) else: cmd = "show interface" - for chk_ll in range(0, 60): + for _ in range(0, 60): sleep(1 / 4) ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd)) # Fix newlines (make them all the same) @@ -937,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 @@ -1848,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) @@ -1869,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: @@ -3095,7 +3100,7 @@ def configure_brctl(tgen, topo, input_dict): "{} dev {} master {}".format(ip_cmd, brctl_name, vrf) ) - for intf_name, data in topo["routers"][dut]["links"].items(): + for _, data in topo["routers"][dut]["links"].items(): if "vrf" not in data: continue @@ -3366,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 @@ -4942,7 +4947,7 @@ def scapy_send_raw_packet(tgen, topo, senderRouter, intf, packet=None): sender_interface = intf rnode = tgen.routers()[senderRouter] - for destLink, data in topo["routers"][senderRouter]["links"].items(): + for _, data in topo["routers"][senderRouter]["links"].items(): if "type" in data and data["type"] == "loopback": continue diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py index a4754463..784f7d17 100755 --- a/tests/topotests/lib/fe_client.py +++ b/tests/topotests/lib/fe_client.py @@ -9,7 +9,6 @@ # noqa: E501 # import argparse -import json import logging import os import socket @@ -18,6 +17,8 @@ import sys import time from pathlib import Path +from munet.base import Timeout + CWD = os.path.dirname(os.path.realpath(__file__)) # This is painful but works if you have installed protobuf would be better if we @@ -80,6 +81,13 @@ GET_DATA_FLAG_EXACT = 0x4 MSG_NOTIFY_FMT = "=B7x" NOTIFY_FIELD_RESULT_TYPE = 0 +MSG_NOTIFY_SELECT_FMT = "=B7x" + +MSG_SESSION_REQ_FMT = "=8x" + +MSG_SESSION_REPLY_FMT = "=B7x" +SESSION_REPLY_FIELD_CREATED = 0 + # # Native message codes # @@ -88,6 +96,9 @@ MSG_CODE_ERROR = 0 MSG_CODE_TREE_DATA = 2 MSG_CODE_GET_DATA = 3 MSG_CODE_NOTIFY = 4 +MSG_CODE_NOTIFY_SELECT = 9 +MSG_CODE_SESSION_REQ = 10 +MSG_CODE_SESSION_REPLY = 11 msg_native_formats = { MSG_CODE_ERROR: MSG_ERROR_FMT, @@ -95,6 +106,9 @@ msg_native_formats = { MSG_CODE_TREE_DATA: MSG_TREE_DATA_FMT, MSG_CODE_GET_DATA: MSG_GET_DATA_FMT, MSG_CODE_NOTIFY: MSG_NOTIFY_FMT, + MSG_CODE_NOTIFY_SELECT: MSG_NOTIFY_SELECT_FMT, + MSG_CODE_SESSION_REQ: MSG_SESSION_REQ_FMT, + MSG_CODE_SESSION_REPLY: MSG_SESSION_REPLY_FMT, } @@ -177,27 +191,44 @@ class Session: client_id = 1 - def __init__(self, sock): + def __init__(self, sock, use_protobuf): self.sock = sock self.next_req_id = 1 - req = mgmt_pb2.FeMessage() - req.register_req.client_name = "test-client" - self.send_pb_msg(req) - logging.debug("Sent FeRegisterReq: %s", req) + if use_protobuf: + req = mgmt_pb2.FeMessage() + req.register_req.client_name = "test-client" + self.send_pb_msg(req) + logging.debug("Sent FeRegisterReq: %s", req) - req = mgmt_pb2.FeMessage() - req.session_req.create = 1 - req.session_req.client_conn_id = Session.client_id - Session.client_id += 1 - self.send_pb_msg(req) - logging.debug("Sent FeSessionReq: %s", req) + req = mgmt_pb2.FeMessage() + req.session_req.create = 1 + req.session_req.client_conn_id = Session.client_id + Session.client_id += 1 + self.send_pb_msg(req) + logging.debug("Sent FeSessionReq: %s", req) - reply = self.recv_pb_msg(mgmt_pb2.FeMessage()) - logging.debug("Received FeSessionReply: %s", repr(reply)) + reply = self.recv_pb_msg(mgmt_pb2.FeMessage()) + logging.debug("Received FeSessionReply: %s", repr(reply)) - assert reply.session_reply.success - self.sess_id = reply.session_reply.session_id + assert reply.session_reply.success + self.sess_id = reply.session_reply.session_id + else: + self.sess_id = 0 + mdata, _ = self.get_native_msg_header(MSG_CODE_SESSION_REQ) + mdata += struct.pack(MSG_SESSION_REQ_FMT) + mdata += "test-client".encode("utf-8") + b"\x00" + + self.send_native_msg(mdata) + logging.debug("Sent native SESSION-REQ") + + mhdr, mfixed, mdata = self.recv_native_msg() + if mhdr[HDR_FIELD_CODE] == MSG_CODE_SESSION_REPLY: + logging.debug("Recv native SESSION-REQ Message: %s: %s", mfixed, mdata) + else: + raise Exception(f"Recv NON-SESSION-REPLY Message: {mfixed}: {mdata}") + assert mfixed[0] + self.sess_id = mhdr[HDR_FIELD_SESS_ID] def close(self, clean=True): if clean: @@ -292,7 +323,7 @@ class Session: def get_data(self, query, data=True, config=False): # Create the message - mdata, req_id = self.get_native_msg_header(MSG_CODE_GET_DATA) + mdata, _ = self.get_native_msg_header(MSG_CODE_GET_DATA) flags = GET_DATA_FLAG_STATE if data else 0 flags |= GET_DATA_FLAG_CONFIG if config else 0 mdata += struct.pack(MSG_GET_DATA_FMT, MSG_FORMAT_JSON, flags) @@ -301,24 +332,29 @@ class Session: self.send_native_msg(mdata) logging.debug("Sent GET-TREE") - mhdr, mfixed, mdata = self.recv_native_msg() + _, mfixed, mdata = self.recv_native_msg() assert mdata[-1] == 0 result = mdata[:-1].decode("utf-8") logging.debug("Received GET: %s: %s", mfixed, mdata) return result - # def subscribe(self, notif_xpath): - # # Create the message - # mdata, req_id = self.get_native_msg_header(MSG_CODE_SUBSCRIBE) - # mdata += struct.pack(MSG_SUBSCRIBE_FMT, MSG_FORMAT_JSON) - # mdata += notif_xpath.encode("utf-8") + b"\x00" + def add_notify_select(self, replace, notif_xpaths): + # Create the message + mdata, _ = self.get_native_msg_header(MSG_CODE_NOTIFY_SELECT) + mdata += struct.pack(MSG_NOTIFY_SELECT_FMT, replace) + + for xpath in notif_xpaths: + mdata += xpath.encode("utf-8") + b"\x00" - # self.send_native_msg(mdata) - # logging.debug("Sent SUBSCRIBE") + self.send_native_msg(mdata) + logging.debug("Sent NOTIFY_SELECT") def recv_notify(self, xpaths=None): - while True: + if xpaths: + self.add_notify_select(True, xpaths) + + for _ in Timeout(60): logging.debug("Waiting for Notify Message") mhdr, mfixed, mdata = self.recv_native_msg() if mhdr[HDR_FIELD_CODE] == MSG_CODE_NOTIFY: @@ -328,19 +364,11 @@ class Session: vsplit = mhdr[HDR_FIELD_VSPLIT] assert mdata[vsplit - 1] == 0 - xpath = mdata[: vsplit - 1].decode("utf-8") - assert mdata[-1] == 0 - result = mdata[vsplit:-1].decode("utf-8") - - if not xpaths: - return result - js = json.loads(result) - key = [x for x in js.keys()][0] - for xpath in xpaths: - if key.startswith(xpath): - return result - logging.debug("'%s' didn't match xpath filters", key) + # xpath = mdata[: vsplit - 1].decode("utf-8") + return mdata[vsplit:-1].decode("utf-8") + else: + raise TimeoutError("Timeout waiting for notifications") def __parse_args(): @@ -365,6 +393,9 @@ def __parse_args(): "-q", "--query", nargs="+", metavar="XPATH", help="xpath[s] to query" ) parser.add_argument("-s", "--server", default=MPATH, help="path to server socket") + parser.add_argument( + "--use-protobuf", action="store_true", help="Use protobuf when there's a choice" + ) parser.add_argument("-v", "--verbose", action="store_true", help="Be verbose") args = parser.parse_args() @@ -381,13 +412,15 @@ def __server_connect(spath): logging.warn("retry server connection in .5s (%s)", os.strerror(ec)) time.sleep(0.5) logging.info("Connected to server on %s", spath) + # Set a timeout of 5 minutes for socket operations. + sock.settimeout(60 * 5) return sock def __main(): args = __parse_args() sock = __server_connect(Path(args.server)) - sess = Session(sock) + sess = Session(sock, use_protobuf=args.use_protobuf) if args.query: # Performa an xpath query @@ -412,8 +445,12 @@ def main(): __main() except KeyboardInterrupt: logging.info("Exiting") + except TimeoutError as error: + logging.error("Timeout: %s", error) + sys.exit(2) except Exception as error: logging.error("Unexpected error exiting: %s", error, exc_info=True) + sys.exit(1) if __name__ == "__main__": diff --git a/tests/topotests/lib/grpc-query.py b/tests/topotests/lib/grpc-query.py index 13b63614..cc7b1ad2 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/ospf.py b/tests/topotests/lib/ospf.py index 5b18f8b6..2c876e19 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -1545,7 +1545,7 @@ def verify_ospf_database( ) return errormsg if ospf_external_lsa: - for ospf_ext_lsa, ext_lsa_data in ospf_external_lsa.items(): + for ospf_ext_lsa, _ in ospf_external_lsa.items(): if ospf_ext_lsa in show_ospf_json["AS External Link States"]: logger.info( "[DUT: %s] OSPF LSDB:External LSA %s", router, ospf_ext_lsa @@ -2509,7 +2509,7 @@ def verify_ospf_gr_helper(tgen, topo, dut, input_dict=None): raise ValueError(errormsg) return errormsg - for ospf_gr, gr_data in input_dict.items(): + for ospf_gr, _ in input_dict.items(): try: if input_dict[ospf_gr] == show_ospf_json[ospf_gr]: logger.info( diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py index f7440efd..369a794e 100644 --- a/tests/topotests/lib/pim.py +++ b/tests/topotests/lib/pim.py @@ -149,7 +149,7 @@ def _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict): # At least one interface must be enabled for PIM on the router pim_if_enabled = False pim6_if_enabled = False - for destLink, data in topo[dut]["links"].items(): + for _, data in topo[dut]["links"].items(): if "pim" in data: pim_if_enabled = True if "pim6" in data: @@ -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": @@ -603,7 +610,7 @@ def find_rp_details(tgen, topo): # ip address of RP rp_addr = rp_dict["rp_addr"] - for link, data in topo["routers"][router]["links"].items(): + for _, data in topo["routers"][router]["links"].items(): if data["ipv4"].split("/")[0] == rp_addr: rp_details[router] = rp_addr @@ -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: @@ -1738,6 +1745,49 @@ def verify_pim_rp_info( return True +@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, @@ -2089,7 +2139,7 @@ def verify_pim_interface( ) return True else: - for destLink, data in topo["routers"][dut]["links"].items(): + for _, data in topo["routers"][dut]["links"].items(): if "type" in data and data["type"] == "loopback": continue @@ -2292,7 +2342,7 @@ def clear_pim_interfaces(tgen, dut): # Waiting for maximum 60 sec fail_intf = [] - for retry in range(1, 13): + for _ in range(1, 13): sleep(5) logger.info("[DUT: %s]: Waiting for 5 sec for PIM neighbors" " to come up", dut) run_json_after = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True) @@ -2368,7 +2418,7 @@ def clear_igmp_interfaces(tgen, dut): total_groups_before_clear = igmp_json["totalGroups"] - for key, value in igmp_json.items(): + for _, value in igmp_json.items(): if type(value) is not dict: continue @@ -2381,7 +2431,7 @@ def clear_igmp_interfaces(tgen, dut): result = run_frr_cmd(rnode, "clear ip igmp interfaces") # Waiting for maximum 60 sec - for retry in range(1, 13): + for _ in range(1, 13): logger.info( "[DUT: %s]: Waiting for 5 sec for igmp interfaces" " to come up", 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!!]") @@ -2460,7 +2511,7 @@ def clear_mroute_verify(tgen, dut, expected=True): # RFC 3376: 8.2. Query Interval - Default: 125 seconds # So waiting for maximum 130 sec to get the igmp report - for retry in range(1, 26): + for _ in range(1, 26): logger.info("[DUT: %s]: Waiting for 2 sec for mroutes" " to come up", dut) sleep(5) keys_json1 = mroute_json_1.keys() @@ -2671,7 +2722,7 @@ def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping): try: config_data = [] - for group, rp_list in rp_mapping.items(): + for _, rp_list in rp_mapping.items(): for _rp in rp_list: config_data.append("interface {}".format(interface)) config_data.append("ip address {}".format(_rp)) @@ -2720,7 +2771,7 @@ def scapy_send_bsr_raw_packet(tgen, topo, senderRouter, receiverRouter, packet=N script_path = os.path.join(CWD, "send_bsr_packet.py") node = tgen.net[senderRouter] - for destLink, data in topo["routers"][senderRouter]["links"].items(): + for _, data in topo["routers"][senderRouter]["links"].items(): if "type" in data and data["type"] == "loopback": continue @@ -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 @@ -2795,12 +2888,12 @@ def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None): # RP with lowest priority if len(priority_dict) != 1: - rp_p, lowest_priority = sorted(rp_priority.items(), key=lambda x: x[1])[0] + rp_p, _ = sorted(rp_priority.items(), key=lambda x: x[1])[0] rp_details[group] = rp_p # RP with highest hash value if len(priority_dict) == 1: - rp_h, highest_hash = sorted(rp_hash.items(), key=lambda x: x[1])[-1] + rp_h, _ = sorted(rp_hash.items(), key=lambda x: x[1])[-1] rp_details[group] = rp_h # RP with highest IP address @@ -3239,7 +3332,7 @@ def verify_pim_join( interface_json = show_pim_join_json[interface] grp_addr = grp_addr.split("/")[0] - for source, data in interface_json[grp_addr].items(): + for _, data in interface_json[grp_addr].items(): # Verify pim join if pim_join: if data["group"] == grp_addr and data["channelJoinName"] == "JOIN": @@ -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 f49e30ea..b1da2963 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: @@ -824,6 +833,8 @@ class TopoRouter(TopoGear): Loads the unified configuration file source Start the daemons in the list If daemons is None, try to infer daemons from the config file + `daemons` is a tuple (daemon, param) of daemons to start, e.g.: + (TopoRouter.RD_ZEBRA, "-s 90000000"). """ source_path = self.load_config(self.RD_FRR, source) if not daemons: @@ -832,16 +843,17 @@ 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, "") else: - for daemon in daemons: - self.load_config(daemon, "") + for item in daemons: + daemon, param = item + self.load_config(daemon, "", param) def load_config(self, daemon, source=None, param=None): """Loads daemon configuration from the specified source diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 087d8454..bd989583 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( @@ -602,6 +610,30 @@ def is_linux(): return False +def iproute2_is_json_capable(): + """ + Checks if the iproute2 version installed on the system is capable of + handling JSON outputss + + Returns True if capability can be detected, returns False otherwise. + """ + if is_linux(): + try: + subp = subprocess.Popen( + ["ip", "-json", "route", "show"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) + iproute2_err = subp.communicate()[1].splitlines()[0].split()[0] + + if iproute2_err != "Error:": + return True + except Exception: + pass + return False + + def iproute2_is_vrf_capable(): """ Checks if the iproute2 version installed on the system is capable of @@ -1212,8 +1244,8 @@ def _sysctl_assure(commander, variable, value): def sysctl_atleast(commander, variable, min_value, raises=False): try: if commander is None: - logger = logging.getLogger("topotest") - commander = micronet.Commander("sysctl", logger=logger) + topotest_logger = logging.getLogger("topotest") + commander = micronet.Commander("sysctl", logger=topotest_logger) return _sysctl_atleast(commander, variable, min_value) except subprocess.CalledProcessError as error: @@ -1230,8 +1262,8 @@ def sysctl_atleast(commander, variable, min_value, raises=False): def sysctl_assure(commander, variable, value, raises=False): try: if commander is None: - logger = logging.getLogger("topotest") - commander = micronet.Commander("sysctl", logger=logger) + topotest_logger = logging.getLogger("topotest") + commander = micronet.Commander("sysctl", logger=topotest_logger) return _sysctl_assure(commander, variable, value) except subprocess.CalledProcessError as error: logger.warning( @@ -1406,7 +1438,7 @@ class Router(Node): self.daemondir = None self.hasmpls = False self.routertype = "frr" - self.unified_config = None + self.unified_config = False self.daemons = { "zebra": 0, "ripd": 0, @@ -1629,7 +1661,7 @@ class Router(Node): # print "Daemons before:", self.daemons if daemon in self.daemons.keys() or daemon == "frr": if daemon == "frr": - self.unified_config = 1 + self.unified_config = True else: self.daemons[daemon] = 1 if param is not None: diff --git a/tests/topotests/mgmt_debug_flags/test_debug.py b/tests/topotests/mgmt_debug_flags/test_debug.py index e49d9b7b..fe659e54 100644 --- a/tests/topotests/mgmt_debug_flags/test_debug.py +++ b/tests/topotests/mgmt_debug_flags/test_debug.py @@ -27,7 +27,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() - for rname, router in tgen.routers().items(): + for _, router in tgen.routers().items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/mgmt_notif/test_notif.py b/tests/topotests/mgmt_notif/test_notif.py index c85e7ba7..e5286faa 100644 --- a/tests/topotests/mgmt_notif/test_notif.py +++ b/tests/topotests/mgmt_notif/test_notif.py @@ -10,7 +10,6 @@ Test YANG Notifications """ import json -import logging import os import pytest @@ -35,7 +34,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() @@ -51,7 +50,7 @@ def test_frontend_notification(tgen): check_kernel_32(r1, "11.11.11.11", 1, "") - fe_client_path = CWD + "/../lib/fe_client.py" + fe_client_path = CWD + "/../lib/fe_client.py --verbose" rc, _, _ = r1.cmd_status(fe_client_path + " --help") if rc: @@ -61,7 +60,7 @@ def test_frontend_notification(tgen): # So we filter to avoid that, all the rest are frr-ripd:authentication-failure # making our test deterministic output = r1.cmd_raises( - fe_client_path + " --listen frr-ripd:authentication-failure" + fe_client_path + " --listen /frr-ripd:authentication-failure" ) jsout = json.loads(output) @@ -69,7 +68,7 @@ def test_frontend_notification(tgen): result = json_cmp(jsout, expected) assert result is None - output = r1.cmd_raises(fe_client_path + " --listen") + output = r1.cmd_raises(fe_client_path + " --use-protobuf --listen") jsout = json.loads(output) expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}} 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 435d7336..948f4e6c 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 1a1f6480..30daecf1 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 2e2b8ec7..b1124bd7 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 2e2b8ec7..70c8798b 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 1a1f6480..0b2a9fa4 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 956d3a89..769c1f73 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 2e2b8ec7..c740f592 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 162c1eb5..f54e64ae 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): @@ -146,7 +151,7 @@ def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): # logger.debug("checking kernel routing table%s:\n%s", vrfstr, kernel) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if not add: assert str(net) not in kernel continue @@ -233,7 +238,7 @@ def do_config( if vrf: f.write("vrf {}\n".format(vrf)) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if add: f.write("ip route {} {}\n".format(net, via)) else: 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 00000000..f37766b1 --- /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 60359716..018ed99f 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 981df024..35669fd5 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 cea4bf5a..f85b163b 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 75414ca0..e2cfec97 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 05382316..3567f35a 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 4f40820b..d9ca58d2 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 4f40820b..d9ca58d2 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 75414ca0..e2cfec97 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 7ce60c3b..11766ce9 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 4f40820b..d9ca58d2 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 7ce60c3b..11766ce9 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 833d418f..ef4a4ab1 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_oper.py b/tests/topotests/mgmt_oper/test_oper.py index 8b8a51c2..e4ceabf3 100644 --- a/tests/topotests/mgmt_oper/test_oper.py +++ b/tests/topotests/mgmt_oper/test_oper.py @@ -12,17 +12,11 @@ Test static route functionality import ipaddress import math -import time import pytest from lib.topogen import Topogen from oper import check_kernel_32, do_oper_test -try: - from deepdiff import DeepDiff as dd_json_cmp -except ImportError: - dd_json_cmp = None - pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] diff --git a/tests/topotests/mgmt_oper/test_simple.py b/tests/topotests/mgmt_oper/test_simple.py index 3b115f62..2b3d6ff6 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 00000000..e094ca54 --- /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 +# +# 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/mgmt_rpc/test_rpc.py b/tests/topotests/mgmt_rpc/test_rpc.py index 618d9022..4d073fd0 100644 --- a/tests/topotests/mgmt_rpc/test_rpc.py +++ b/tests/topotests/mgmt_rpc/test_rpc.py @@ -14,6 +14,7 @@ import os import threading import pytest +from lib.common_config import retry from lib.topogen import Topogen from lib.topotest import json_cmp @@ -32,7 +33,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() @@ -40,12 +41,20 @@ def tgen(request): tgen.stop_topology() +# Verify the backend test client has connected +@retry(retry_timeout=10) +def check_client_connect(r1): + out = r1.vtysh_cmd("show mgmt backend-adapter all") + assert "mgmtd-testc" in out + + def test_backend_rpc(tgen): if tgen.routers_have_failure(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] + # Run the backend test client which registers to handle the `clear ip rip` command. be_client_path = "/usr/lib/frr/mgmtd_testc" rc, _, _ = r1.net.cmd_status(be_client_path + " --help") @@ -63,6 +72,10 @@ def test_backend_rpc(tgen): t = threading.Thread(target=run_testc) t.start() + # We need to wait for mgmtd_testc to connect before issuing the command. + res = check_client_connect(r1) + assert res is None + r1.vtysh_cmd("clear ip rip vrf testname") t.join() diff --git a/tests/topotests/mgmt_tests/test_yang_mgmt.py b/tests/topotests/mgmt_tests/test_yang_mgmt.py index 605c1428..52f6ba4d 100644 --- a/tests/topotests/mgmt_tests/test_yang_mgmt.py +++ b/tests/topotests/mgmt_tests/test_yang_mgmt.py @@ -66,7 +66,6 @@ from lib.common_config import ( start_router_daemons, ) from lib.topolog import logger -from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd, pytest.mark.mgmtd] diff --git a/tests/topotests/msdp_topo1/r1/pimd.conf b/tests/topotests/msdp_topo1/r1/pimd.conf index 5bb268eb..3c116a00 100644 --- a/tests/topotests/msdp_topo1/r1/pimd.conf +++ b/tests/topotests/msdp_topo1/r1/pimd.conf @@ -20,3 +20,7 @@ ip msdp peer 192.168.0.2 source 192.168.0.1 ip msdp peer 192.168.1.2 source 192.168.1.1 ip pim rp 10.254.254.1 ip pim join-prune-interval 5 +! +router pim + msdp peer 192.168.0.2 password 1234 +! diff --git a/tests/topotests/msdp_topo1/r2/pimd.conf b/tests/topotests/msdp_topo1/r2/pimd.conf index 733bd6f2..4ea2c823 100644 --- a/tests/topotests/msdp_topo1/r2/pimd.conf +++ b/tests/topotests/msdp_topo1/r2/pimd.conf @@ -16,3 +16,7 @@ ip msdp peer 192.168.0.1 source 192.168.0.2 ip msdp peer 192.168.2.2 source 192.168.2.1 ip pim rp 10.254.254.2 ip pim join-prune-interval 5 +! +router pim + msdp peer 192.168.0.1 password 1234 +! diff --git a/tests/topotests/msdp_topo1/r4/pimd.conf b/tests/topotests/msdp_topo1/r4/pimd.conf index 28085913..46de4fbe 100644 --- a/tests/topotests/msdp_topo1/r4/pimd.conf +++ b/tests/topotests/msdp_topo1/r4/pimd.conf @@ -20,3 +20,16 @@ ip msdp peer 192.168.2.1 source 192.168.2.2 ip msdp peer 192.168.3.1 source 192.168.3.2 ip pim rp 10.254.254.4 ip pim join-prune-interval 5 +! +access-list forbidden-multicast seq 5 deny 229.2.1.0 0.0.0.255 +access-list forbidden-multicast seq 1000 permit any +access-list local-only-multicast seq 5 deny 229.3.1.0 0.0.0.255 +access-list local-only-multicast seq 6 deny ip 192.168.4.100 0.0.0.0 229.10.1.0 0.0.0.255 +access-list local-only-multicast seq 1000 permit any +! +router pim + msdp peer 192.168.2.1 sa-filter forbidden-multicast in + msdp peer 192.168.2.1 sa-filter local-only-multicast out + msdp peer 192.168.3.1 sa-filter forbidden-multicast in + msdp peer 192.168.3.1 sa-filter local-only-multicast out +! diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 2fbff440..ff80052d 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -66,7 +66,9 @@ def build_topo(tgen): # Create a host connected and direct at r4: tgen.add_host("h1", "192.168.4.100/24", "via 192.168.4.1") + tgen.add_host("h3", "192.168.4.120/24", "via 192.168.4.1") switch.add_link(tgen.gears["h1"]) + switch.add_link(tgen.gears["h3"]) # Create a host connected and direct at r1: switch = tgen.add_switch("s6") @@ -82,7 +84,6 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): - daemon_file = "{}/{}/zebra.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_ZEBRA, daemon_file) @@ -101,7 +102,7 @@ def setup_module(mod): app_helper.init(tgen) -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() app_helper.cleanup() @@ -428,6 +429,87 @@ def test_msdp(): assert val is None, "multicast route convergence failure" +def test_msdp_sa_filter(): + "Start a number of multicast streams and check if filtering works" + + tgen = get_topogen() + + # Flow from r1 -> r4 + for multicast_address in ["229.2.1.1", "229.2.1.2", "229.2.2.1"]: + app_helper.run("h1", [multicast_address, "h1-eth0"]) + app_helper.run("h2", ["--send=0.7", multicast_address, "h2-eth0"]) + + # Flow from r4 -> r1 + for multicast_address in ["229.3.1.1", "229.3.1.2", "229.3.2.1"]: + app_helper.run("h1", ["--send=0.7", multicast_address, "h1-eth0"]) + app_helper.run("h2", [multicast_address, "h2-eth0"]) + + # Flow from r4 -> r1 but with more sources + for multicast_address in ["229.10.1.1", "229.11.1.1"]: + app_helper.run("h1", ["--send=0.7", multicast_address, "h1-eth0"]) + app_helper.run("h2", [multicast_address, "h2-eth0"]) + app_helper.run("h3", ["--send=0.7", multicast_address, "h3-eth0"]) + + # Test that we don't learn any filtered multicast streams. + r4_sa_expected = { + "229.2.1.1": None, + "229.2.1.2": None, + "229.2.2.1": { + "192.168.10.100": { + "local": "no", + "sptSetup": "yes", + } + }, + } + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r4"], + "show ip msdp sa json", + r4_sa_expected, + ) + logger.info("Waiting for r4 MDSP SA data") + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + # Test that we don't send any filtered multicast streams. + r1_sa_expected = { + "229.3.1.1": None, + "229.3.1.2": None, + "229.3.2.1": { + "192.168.4.100": { + "local": "no", + "sptSetup": "yes", + } + }, + "229.10.1.1": { + "192.168.4.100": None, + "192.168.4.120": { + "local": "no", + "sptSetup": "yes", + }, + }, + "229.11.1.1": { + "192.168.4.100": { + "local": "no", + "sptSetup": "yes", + }, + "192.168.4.120": { + "local": "no", + "sptSetup": "yes", + }, + }, + } + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + "show ip msdp sa json", + r1_sa_expected, + ) + logger.info("Waiting for r1 MDSP SA data") + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/msdp_topo2/r1/bgpd.conf b/tests/topotests/msdp_topo2/r1/bgpd.conf new file mode 100644 index 00000000..67f04d8e --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as 65002 + neighbor 192.168.3.3 remote-as 65003 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r1/pimd.conf b/tests/topotests/msdp_topo2/r1/pimd.conf new file mode 100644 index 00000000..58a4c21e --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/pimd.conf @@ -0,0 +1,20 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.1 +! +interface r1-eth0 + ip pim +! +interface r1-eth1 + ip pim +! +interface r1-eth2 + ip pim + ip igmp +! +ip msdp peer 192.168.1.2 source 192.168.1.1 +ip msdp peer 192.168.3.3 source 192.168.3.1 +ip pim rp 10.254.254.1 diff --git a/tests/topotests/msdp_topo2/r1/zebra.conf b/tests/topotests/msdp_topo2/r1/zebra.conf new file mode 100644 index 00000000..3219fad3 --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +! +interface r1-eth0 + ip address 192.168.1.1/24 +! +interface r1-eth1 + ip address 192.168.3.1/24 +! +interface r1-eth2 + ip address 192.168.6.1/24 +! +interface lo + ip address 10.254.254.1/32 +! diff --git a/tests/topotests/msdp_topo2/r2/bgpd.conf b/tests/topotests/msdp_topo2/r2/bgpd.conf new file mode 100644 index 00000000..b9f31689 --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as 65001 + neighbor 192.168.2.5 remote-as 65005 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r2/pimd.conf b/tests/topotests/msdp_topo2/r2/pimd.conf new file mode 100644 index 00000000..66e63026 --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.2 +! +interface r2-eth0 + ip pim +! +interface r2-eth1 + ip pim +! +ip msdp peer 192.168.1.1 source 192.168.1.2 +ip msdp peer 192.168.2.5 source 192.168.2.2 +ip pim rp 10.254.254.2 diff --git a/tests/topotests/msdp_topo2/r2/zebra.conf b/tests/topotests/msdp_topo2/r2/zebra.conf new file mode 100644 index 00000000..740b51a4 --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r2-eth0 + ip address 192.168.1.2/24 +! +interface r2-eth1 + ip address 192.168.2.2/24 +! +interface lo + ip address 10.254.254.2/32 +! diff --git a/tests/topotests/msdp_topo2/r3/bgpd.conf b/tests/topotests/msdp_topo2/r3/bgpd.conf new file mode 100644 index 00000000..ecd25b05 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.3.1 remote-as 65001 + neighbor 192.168.4.4 remote-as 65004 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r3/pimd.conf b/tests/topotests/msdp_topo2/r3/pimd.conf new file mode 100644 index 00000000..e8e53268 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.3 +! +interface r3-eth0 + ip pim +! +interface r3-eth1 + ip pim +! +ip msdp peer 192.168.3.1 source 192.168.3.3 +ip msdp peer 192.168.4.4 source 192.168.4.3 +ip pim rp 10.254.254.3 diff --git a/tests/topotests/msdp_topo2/r3/zebra.conf b/tests/topotests/msdp_topo2/r3/zebra.conf new file mode 100644 index 00000000..d1be65f6 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r3-eth0 + ip address 192.168.3.3/24 +! +interface r3-eth1 + ip address 192.168.4.3/24 +! +interface lo + ip address 10.254.254.3/32 +! diff --git a/tests/topotests/msdp_topo2/r4/bgpd.conf b/tests/topotests/msdp_topo2/r4/bgpd.conf new file mode 100644 index 00000000..430517bc --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65004 + no bgp ebgp-requires-policy + neighbor 192.168.4.3 remote-as 65003 + neighbor 192.168.5.5 remote-as 65005 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r4/pimd.conf b/tests/topotests/msdp_topo2/r4/pimd.conf new file mode 100644 index 00000000..32e3c613 --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.4 +! +interface r4-eth0 + ip pim +! +interface r4-eth1 + ip pim +! +ip msdp peer 192.168.4.3 source 192.168.4.4 +ip msdp peer 192.168.5.5 source 192.168.5.4 +ip pim rp 10.254.254.4 diff --git a/tests/topotests/msdp_topo2/r4/zebra.conf b/tests/topotests/msdp_topo2/r4/zebra.conf new file mode 100644 index 00000000..045d2e80 --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r4-eth0 + ip address 192.168.4.4/24 +! +interface r4-eth1 + ip address 192.168.5.4/24 +! +interface lo + ip address 10.254.254.4/32 +! diff --git a/tests/topotests/msdp_topo2/r5/bgpd.conf b/tests/topotests/msdp_topo2/r5/bgpd.conf new file mode 100644 index 00000000..053dd3d3 --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65005 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as 65002 + neighbor 192.168.5.4 remote-as 65004 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r5/pimd.conf b/tests/topotests/msdp_topo2/r5/pimd.conf new file mode 100644 index 00000000..e6cdd14c --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/pimd.conf @@ -0,0 +1,20 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.5 +! +interface r5-eth0 + ip pim +! +interface r5-eth1 + ip pim +! +interface r5-eth2 + ip pim + ip igmp +! +ip msdp peer 192.168.2.2 source 192.168.2.5 +ip msdp peer 192.168.5.4 source 192.168.5.5 +ip pim rp 10.254.254.5 diff --git a/tests/topotests/msdp_topo2/r5/zebra.conf b/tests/topotests/msdp_topo2/r5/zebra.conf new file mode 100644 index 00000000..195e0035 --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +! +interface r5-eth0 + ip address 192.168.2.5/24 +! +interface r5-eth1 + ip address 192.168.5.5/24 +! +interface r5-eth2 + ip address 192.168.7.5/24 +! +interface lo + ip address 10.254.254.5/32 +! diff --git a/tests/topotests/msdp_topo2/test_msdp_topo2.py b/tests/topotests/msdp_topo2/test_msdp_topo2.py new file mode 100755 index 00000000..def5368f --- /dev/null +++ b/tests/topotests/msdp_topo2/test_msdp_topo2.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_msdp_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2024 by +# Adriano Marto Reis +# + +""" +test_msdp_topo2.py: Test the FRR PIM MSDP peer. + + ────────────────────► + shortest path + ┌──┐ + ┌───────┤r2├───────┐ +sender │ s1 └──┘ s2 │ receiver + ┌──┐ ┌─┴┐ ┌─┴┐ ┌──┐ + │h1├────┤r1│ │r5├────┤h2│ + └──┘ s6 └─┬┘ └─┬┘ s7 └──┘ + │ ┌──┐ ┌──┐ │ + └───┤r3├────┤r4├───┘ + s3 └──┘ s4 └──┘ s5 +""" + +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 + +# Required to instantiate the topology builder class. +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +from lib.pim import McastTesterHelper + +pytestmark = [pytest.mark.bgpd, pytest.mark.pimd] + +app_helper = McastTesterHelper() + +MCAST_ADDR = "229.1.2.3" + +def build_topo(tgen): + "Build function" + + for routern in range(1, 6): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s6") + tgen.add_host("h1", "192.168.6.100/24", "via 192.168.6.1") + switch.add_link(tgen.gears["h1"]) + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s7") + tgen.add_host("h2", "192.168.7.100/24", "via 192.168.7.5") + switch.add_link(tgen.gears["h2"]) + switch.add_link(tgen.gears["r5"]) + + +def setup_module(mod): + "Sets up the pytest environment" + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ZEBRA, daemon_file) + + daemon_file = "{}/{}/bgpd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_BGP, daemon_file) + + daemon_file = "{}/{}/pimd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_PIM, daemon_file) + + tgen.start_router() + + app_helper.init(tgen) + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + app_helper.cleanup() + tgen.stop_topology() + + +def test_bgp_convergence(): + """ + Wait for BGP protocol convergence + All the loopback addresses (10.254.254.x) must be reachable from all + routers. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + routes = { + "r1": "10.254.254.1/32", + "r2": "10.254.254.2/32", + "r3": "10.254.254.3/32", + "r4": "10.254.254.4/32", + "r5": "10.254.254.5/32", + } + + for router1 in routes.keys(): + for router2, route in routes.items(): + if router1 != router2: + logger.info("waiting route {} in {}".format(route, router1)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router1], + "show ip route json", + {route: [{"protocol": "bgp"}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router1) + assert result is None, assertmsg + + +def test_msdp_peers(): + """ + Waits for the MSPD peer connections to be established. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + expected_msdp_peers = { + "r1": { + "192.168.1.2": { + "peer": "192.168.1.2", + "local": "192.168.1.1", + "state": "established", + }, + "192.168.3.3": { + "peer": "192.168.3.3", + "local": "192.168.3.1", + "state": "established", + }, + }, + "r2": { + "192.168.1.1": { + "peer": "192.168.1.1", + "local": "192.168.1.2", + "state": "established", + }, + "192.168.2.5": { + "peer": "192.168.2.5", + "local": "192.168.2.2", + "state": "established", + }, + }, + "r3": { + "192.168.3.1": { + "peer": "192.168.3.1", + "local": "192.168.3.3", + "state": "established", + }, + "192.168.4.4": { + "peer": "192.168.4.4", + "local": "192.168.4.3", + "state": "established", + }, + }, + "r4": { + "192.168.4.3": { + "peer": "192.168.4.3", + "local": "192.168.4.4", + "state": "established", + }, + "192.168.5.5": { + "peer": "192.168.5.5", + "local": "192.168.5.4", + "state": "established", + }, + }, + "r5": { + "192.168.2.2": { + "peer": "192.168.2.2", + "local": "192.168.2.5", + "state": "established", + }, + "192.168.5.4": { + "peer": "192.168.5.4", + "local": "192.168.5.5", + "state": "established", + }, + }, + } + + for router, peers in expected_msdp_peers.items(): + logger.info("Waiting for {} msdp peer data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip msdp peer json", + peers, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + +def test_msdp_sa(): + """ + Waits for the MSDP SA to be propagated. + The MSDP SA must be present on all routers. The MSDP SA must indicate + the original RP. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + app_helper.run("h1", ["--send=0.7", MCAST_ADDR, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDR, "h2-eth0"]) + + expected_sa_r1 = { + MCAST_ADDR: { + "192.168.6.100": { + "source": "192.168.6.100", + "group": MCAST_ADDR, + "rp": "-", + "local": "yes", + } + } + } + + expected_sa_r2_r3_r4_r5 = { + MCAST_ADDR: { + "192.168.6.100": { + "source": "192.168.6.100", + "group": MCAST_ADDR, + "rp": "10.254.254.1", + "local": "no", + } + } + } + + expected_sa = { + "r1": expected_sa_r1, + "r2": expected_sa_r2_r3_r4_r5, + "r3": expected_sa_r2_r3_r4_r5, + "r4": expected_sa_r2_r3_r4_r5, + "r5": expected_sa_r2_r3_r4_r5, + } + + for router, sa in expected_sa.items(): + logger.info("Waiting for {} msdp peer data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip msdp sa json", + sa, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + +def test_mroute(): + """ + Wait for the multicast routes. + The multicast routes must connect the shortest path between h1 and h2: + h1 ─► r1 ─► r2 ─► r5 ─► h2 + + The routers r3 and r4 must have no multicast routes, as they are not + included in the shortest path between h1 and h2. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + app_helper.run("h1", ["--send=0.7", MCAST_ADDR, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDR, "h2-eth0"]) + + expected_mroutes = { + "r1": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r1-eth2", + "oil": { + "r1-eth0": {"source": "192.168.6.100", "group": MCAST_ADDR}, + "r1-eth1": None, + }, + }, + }, + }, + "r2": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r2-eth0", + "oil": { + "r2-eth1": {"source": "192.168.6.100", "group": MCAST_ADDR}, + }, + }, + }, + }, + "r3": { + }, + "r4": { + }, + "r5": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r5-eth0", + "oil": { + "r5-eth1": None, + "r5-eth2": {"source": "192.168.6.100", "group": MCAST_ADDR}, + }, + }, + }, + }, + } + + for router, mroute in expected_mroutes.items(): + logger.info("Waiting for {} mroute data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip mroute json", + mroute, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "mroute convergence failure" + + +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/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py index 7eb58380..b8eb67a3 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py @@ -221,7 +221,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py index 8b174bf9..bab7fddf 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py @@ -175,7 +175,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py index 00d38fe6..5aa2ea65 100755 --- a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py +++ b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py @@ -20,10 +20,7 @@ Following tests are covered: import os import sys -import json import time -import datetime -from time import sleep import pytest # Save the Current Working Directory to find configuration files. @@ -43,14 +40,9 @@ from lib.common_config import ( write_test_footer, step, reset_config_on_routers, - shutdown_bringup_interface, apply_raw_config, add_interfaces_to_vlan, - kill_router_daemons, - start_router_daemons, - create_static_routes, check_router_status, - topo_daemons, required_linux_kernel_version, ) from lib.pim import ( @@ -59,9 +51,6 @@ from lib.pim import ( verify_mroutes, clear_mroute, clear_pim_interface_traffic, - verify_pim_config, - verify_upstream_iif, - verify_multicast_traffic, verify_multicast_flag_state, verify_igmp_groups, McastTesterHelper, 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 19870010..8d918260 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_topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py index f87a90d1..eefa96a3 100755 --- a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py +++ b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py @@ -64,7 +64,6 @@ from lib.common_config import ( reset_config_on_routers, shutdown_bringup_interface, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -214,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py b/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py index b62f7bbf..0af2efcc 100755 --- a/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py +++ b/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py @@ -62,7 +62,6 @@ from lib.common_config import ( start_router_daemons, stop_router, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -211,7 +210,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" 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 715aa1de..44a7db56 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 3bbcce13..982157a6 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 876befa1..6042ef4d 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 a3fb496d..0312c302 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 11ac5a01..537be377 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_sm_topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py index ae275467..9488ae02 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py @@ -57,7 +57,7 @@ sys.path.append(os.path.join(CWD, "../lib/")) # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import ( start_topology, write_test_header, @@ -68,7 +68,6 @@ from lib.common_config import ( apply_raw_config, check_router_status, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -354,7 +353,7 @@ def verify_pim_stats_increament(stats_before, stats_after): """ for router, stats_data in stats_before.items(): - for stats, value in stats_data.items(): + for stats, _ in stats_data.items(): if stats_before[router][stats] >= stats_after[router][stats]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py index 825281af..11f3cc42 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py @@ -55,7 +55,6 @@ from lib.common_config import ( apply_raw_config, create_static_routes, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -191,7 +190,7 @@ def reset_stats(stats): """ for router, state_data in stats.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): stats[router][state] = 0 logger.info( "[DUT: %s]: stats %s value has reset" " reset, Current value: %s", @@ -214,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py index c492d95d..38b9b2ec 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py @@ -87,7 +87,6 @@ TC_32 : Verify RP info and (*,G) mroute after deleting the RP and shut / no import os import sys import time -from time import sleep import datetime import pytest @@ -112,10 +111,7 @@ from lib.common_config import ( reset_config_on_routers, step, shutdown_bringup_interface, - kill_router_daemons, - start_router_daemons, create_static_routes, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -128,10 +124,7 @@ from lib.pim import ( verify_pim_rp_info, verify_pim_state, clear_pim_interface_traffic, - clear_igmp_interfaces, - clear_pim_interfaces, clear_mroute, - clear_mroute_verify, McastTesterHelper, ) diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py index 690c92f5..6f078a68 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py @@ -112,9 +112,6 @@ from lib.common_config import ( reset_config_on_routers, step, shutdown_bringup_interface, - kill_router_daemons, - start_router_daemons, - create_static_routes, ) from lib.pim import ( create_pim_config, @@ -123,9 +120,7 @@ from lib.pim import ( verify_join_state_and_timer, verify_mroutes, verify_pim_neighbors, - get_pim_interface_traffic, verify_pim_rp_info, - verify_pim_state, clear_pim_interface_traffic, clear_igmp_interfaces, clear_pim_interfaces, diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py index 8aa2e4ef..48c0a78f 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py @@ -123,14 +123,9 @@ from lib.pim import ( verify_join_state_and_timer, verify_mroutes, verify_pim_neighbors, - get_pim_interface_traffic, verify_pim_rp_info, - verify_pim_state, clear_pim_interface_traffic, - clear_igmp_interfaces, - clear_pim_interfaces, clear_mroute, - clear_mroute_verify, McastTesterHelper, ) diff --git a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py index 5728a4d0..bbd5501d 100644 --- a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py +++ b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py @@ -25,7 +25,6 @@ Following tests are covered to test multicast pim uplink: import os import sys -import json import time import pytest @@ -356,7 +355,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] > state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" @@ -1682,7 +1681,7 @@ def test_mroutes_updated_correctly_after_source_interface_shut_noshut_p1(request step("Shut and No shut source interface multiple time") - for i in range(0, 2): + for _ in range(0, 2): step("Shut and no shut the source interface from DUT") intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] shutdown_bringup_interface(tgen, "r1", intf_r1_i2, False) diff --git a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py index 1fb81c0d..893b8008 100644 --- a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py +++ b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py @@ -213,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] > state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" 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 00000000..dc9e1ac4 --- /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 00000000..d384baa4 --- /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 " 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 " 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 01a70915..d273a30e 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 e5f99317..3ce372cf 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 5747d5e1..e3b78239 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 a1a94bcd..99687c0a 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/nb_config/test_nb_config.py b/tests/topotests/nb_config/test_nb_config.py index 9099ef10..09d6407d 100644 --- a/tests/topotests/nb_config/test_nb_config.py +++ b/tests/topotests/nb_config/test_nb_config.py @@ -30,7 +30,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/nhrp_redundancy/host/frr.conf b/tests/topotests/nhrp_redundancy/host/frr.conf new file mode 100644 index 00000000..8bb7da0a --- /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/host/zebra.conf b/tests/topotests/nhrp_redundancy/host/zebra.conf deleted file mode 100644 index 8bb7da0a..00000000 --- a/tests/topotests/nhrp_redundancy/host/zebra.conf +++ /dev/null @@ -1,4 +0,0 @@ -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 00000000..98e848bc --- /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/nhc1/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhc1/nhrpd.conf deleted file mode 100644 index a0862f77..00000000 --- a/tests/topotests/nhrp_redundancy/nhc1/nhrpd.conf +++ /dev/null @@ -1,11 +0,0 @@ -!debug nhrp all -interface nhc1-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 nhc1-eth0 -exit diff --git a/tests/topotests/nhrp_redundancy/nhc1/zebra.conf b/tests/topotests/nhrp_redundancy/nhc1/zebra.conf deleted file mode 100644 index 07d91754..00000000 --- a/tests/topotests/nhrp_redundancy/nhc1/zebra.conf +++ /dev/null @@ -1,16 +0,0 @@ -ip forwarding -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 -! -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 \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/nhc2/frr.conf b/tests/topotests/nhrp_redundancy/nhc2/frr.conf new file mode 100644 index 00000000..818dd482 --- /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/nhc2/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhc2/nhrpd.conf deleted file mode 100644 index 16a6d87c..00000000 --- a/tests/topotests/nhrp_redundancy/nhc2/nhrpd.conf +++ /dev/null @@ -1,11 +0,0 @@ -!debug nhrp all -interface nhc2-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 nhc2-eth0 -exit diff --git a/tests/topotests/nhrp_redundancy/nhc2/zebra.conf b/tests/topotests/nhrp_redundancy/nhc2/zebra.conf deleted file mode 100644 index 30ea6d4d..00000000 --- a/tests/topotests/nhrp_redundancy/nhc2/zebra.conf +++ /dev/null @@ -1,16 +0,0 @@ -ip forwarding -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 -! -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/nhs1/frr.conf b/tests/topotests/nhrp_redundancy/nhs1/frr.conf new file mode 100644 index 00000000..583d0143 --- /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/nhs1/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhs1/nhrpd.conf deleted file mode 100644 index c0c8c28f..00000000 --- a/tests/topotests/nhrp_redundancy/nhs1/nhrpd.conf +++ /dev/null @@ -1,9 +0,0 @@ -!debug nhrp all -nhrp nflog-group 1 -interface nhs1-gre0 - ip nhrp holdtime 10 - ip nhrp network-id 42 - ip nhrp registration no-unique - ip nhrp redirect - tunnel source nhs1-eth0 -exit diff --git a/tests/topotests/nhrp_redundancy/nhs1/zebra.conf b/tests/topotests/nhrp_redundancy/nhs1/zebra.conf deleted file mode 100644 index 718e01b9..00000000 --- a/tests/topotests/nhrp_redundancy/nhs1/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -ip forwarding -interface nhs1-eth0 - ip address 192.168.1.1/24 -! -ip route 192.168.2.0/24 192.168.1.6 -interface nhs1-gre0 - ip address 172.16.1.1/32 - no link-detect - ipv6 nd suppress-ra -! -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/nhs2/frr.conf b/tests/topotests/nhrp_redundancy/nhs2/frr.conf new file mode 100644 index 00000000..a6e0a98e --- /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/nhs2/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhs2/nhrpd.conf deleted file mode 100644 index df86d279..00000000 --- a/tests/topotests/nhrp_redundancy/nhs2/nhrpd.conf +++ /dev/null @@ -1,9 +0,0 @@ -!debug nhrp all -nhrp nflog-group 1 -interface nhs2-gre0 - ip nhrp holdtime 10 - ip nhrp network-id 42 - ip nhrp registration no-unique - ip nhrp redirect - tunnel source nhs2-eth0 -exit diff --git a/tests/topotests/nhrp_redundancy/nhs2/zebra.conf b/tests/topotests/nhrp_redundancy/nhs2/zebra.conf deleted file mode 100644 index 6001bf21..00000000 --- a/tests/topotests/nhrp_redundancy/nhs2/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -ip forwarding -interface nhs2-eth0 - ip address 192.168.1.2/24 -! -ip route 192.168.2.0/24 192.168.1.6 -interface nhs2-gre0 - ip address 172.16.1.2/32 - no link-detect - ipv6 nd suppress-ra -! -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/nhs3/frr.conf b/tests/topotests/nhrp_redundancy/nhs3/frr.conf new file mode 100644 index 00000000..e965baf3 --- /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/nhs3/nhrpd.conf b/tests/topotests/nhrp_redundancy/nhs3/nhrpd.conf deleted file mode 100644 index e7c3504f..00000000 --- a/tests/topotests/nhrp_redundancy/nhs3/nhrpd.conf +++ /dev/null @@ -1,9 +0,0 @@ -!debug nhrp all -nhrp nflog-group 1 -interface nhs3-gre0 - ip nhrp holdtime 10 - ip nhrp network-id 42 - ip nhrp registration no-unique - ip nhrp redirect - tunnel source nhs3-eth0 -exit diff --git a/tests/topotests/nhrp_redundancy/nhs3/zebra.conf b/tests/topotests/nhrp_redundancy/nhs3/zebra.conf deleted file mode 100644 index 7c154388..00000000 --- a/tests/topotests/nhrp_redundancy/nhs3/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -ip forwarding -interface nhs3-eth0 - ip address 192.168.1.3/24 -! -ip route 192.168.2.0/24 192.168.1.6 -interface nhs3-gre0 - ip address 172.16.1.3/32 - no link-detect - ipv6 nd suppress-ra -! -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/router/frr.conf b/tests/topotests/nhrp_redundancy/router/frr.conf new file mode 100644 index 00000000..c0eb19ca --- /dev/null +++ b/tests/topotests/nhrp_redundancy/router/frr.conf @@ -0,0 +1,7 @@ +ip forwarding +interface router-eth0 + ip address 192.168.1.6/24 +! +interface router-eth1 + ip address 192.168.2.6/24 +exit diff --git a/tests/topotests/nhrp_redundancy/router/zebra.conf b/tests/topotests/nhrp_redundancy/router/zebra.conf deleted file mode 100644 index c0eb19ca..00000000 --- a/tests/topotests/nhrp_redundancy/router/zebra.conf +++ /dev/null @@ -1,7 +0,0 @@ -ip forwarding -interface router-eth0 - ip address 192.168.1.6/24 -! -interface router-eth1 - ip address 192.168.2.6/24 -exit diff --git a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py index 06777aaa..d4cf9859 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 -+------------+ | +-------+----+ +------+-----+ | -| | | | | | | | -| | +--------+ | | | | ++------------+ +------------+ +------------+ +| | | | | | +| | | | | | +| 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 +| +---------+ | | | | | ++------------+ | +------------+ +------------+ | + | | + 10.4.4.0/24 """ # Save the Current Working Directory to find configuration files. @@ -148,8 +148,8 @@ def _populate_iface(): def _verify_iptables(): tgen = get_topogen() # Verify iptables is installed. Required for shortcuts - rc, _, _ = tgen.net["nhs1"].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): @@ -167,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 ("nhs1", "nhs2", "nhs3", "nhc1", "nhc2"): - 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() diff --git a/tests/topotests/nhrp_topo/r1/nhrp_shortcut_present.json b/tests/topotests/nhrp_topo/r1/nhrp_shortcut_present.json new file mode 100644 index 00000000..96632d84 --- /dev/null +++ b/tests/topotests/nhrp_topo/r1/nhrp_shortcut_present.json @@ -0,0 +1,14 @@ +{ + "attr":{ + "entriesCount":1 + }, + "table":[ + { + "type":"dynamic", + "prefix":"192.168.4.0\/24", + "via":"10.255.255.4", + "identity":"" + } + ] +} + diff --git a/tests/topotests/nhrp_topo/r1/nhrpd.conf b/tests/topotests/nhrp_topo/r1/nhrpd.conf index e5224e4a..8ade77d0 100644 --- a/tests/topotests/nhrp_topo/r1/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r1/nhrpd.conf @@ -1,7 +1,8 @@ log stdout debugging ! debug nhrp all interface r1-gre0 - ip nhrp holdtime 500 + ip nhrp authentication secret + ip nhrp holdtime 10 ip nhrp shortcut ip nhrp network-id 42 ip nhrp nhs dynamic nbma 10.2.1.2 diff --git a/tests/topotests/nhrp_topo/r1/zebra.conf b/tests/topotests/nhrp_topo/r1/zebra.conf index b45670fc..c8a21633 100644 --- a/tests/topotests/nhrp_topo/r1/zebra.conf +++ b/tests/topotests/nhrp_topo/r1/zebra.conf @@ -10,3 +10,4 @@ exit interface r1-eth1 ip address 192.168.1.1/24 ! +ip route 0.0.0.0/0 10.255.255.2 diff --git a/tests/topotests/nhrp_topo/r2/nhrp4_cache.json b/tests/topotests/nhrp_topo/r2/nhrp4_cache.json index 34558e0c..ee122c59 100644 --- a/tests/topotests/nhrp_topo/r2/nhrp4_cache.json +++ b/tests/topotests/nhrp_topo/r2/nhrp4_cache.json @@ -1,8 +1,19 @@ { "attr":{ - "entriesCount":2 + "entriesCount":3 }, "table":[ + { + "interface":"r2-gre0", + "type":"dynamic", + "protocol":"10.255.255.4", + "nbma":"10.1.1.4", + "claimed_nbma":"10.1.1.4", + "used":false, + "timeout":true, + "auth":false, + "identity":"" + }, { "interface":"r2-gre0", "type":"local", diff --git a/tests/topotests/nhrp_topo/r2/nhrp_route4.json b/tests/topotests/nhrp_topo/r2/nhrp_route4.json index 7393cba8..876b24a9 100644 --- a/tests/topotests/nhrp_topo/r2/nhrp_route4.json +++ b/tests/topotests/nhrp_topo/r2/nhrp_route4.json @@ -12,7 +12,31 @@ "installed":true, "internalNextHopNum":1, "internalNextHopActiveNum":1, - "nexthops":[ + "nexthops": [ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-gre0", + "active":true + } + ] + } + ], + "10.255.255.4\/32": [ + { + "prefix":"10.255.255.4\/32", + "prefixLen":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, diff --git a/tests/topotests/nhrp_topo/r2/nhrpd.conf b/tests/topotests/nhrp_topo/r2/nhrpd.conf index f9185f9a..d8e59936 100644 --- a/tests/topotests/nhrp_topo/r2/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r2/nhrpd.conf @@ -2,7 +2,8 @@ log stdout debugging nhrp nflog-group 1 interface r2-gre0 - ip nhrp holdtime 500 + ip nhrp authentication secret + ip nhrp holdtime 10 ip nhrp redirect ip nhrp network-id 42 ip nhrp registration no-unique diff --git a/tests/topotests/nhrp_topo/r2/zebra.conf b/tests/topotests/nhrp_topo/r2/zebra.conf index 9f40d4d7..756cc6d8 100644 --- a/tests/topotests/nhrp_topo/r2/zebra.conf +++ b/tests/topotests/nhrp_topo/r2/zebra.conf @@ -1,3 +1,4 @@ +ip forwarding interface r2-eth0 ip address 10.2.1.2/24 ! @@ -10,3 +11,5 @@ interface r2-gre0 interface r2-eth1 ip address 192.168.2.2/24 ! +ip route 192.168.4.4/24 10.255.255.4 +ip route 192.168.1.1/24 10.255.255.1 diff --git a/tests/topotests/nhrp_topo/r4/nhrp4_cache.json b/tests/topotests/nhrp_topo/r4/nhrp4_cache.json new file mode 100644 index 00000000..19074e4e --- /dev/null +++ b/tests/topotests/nhrp_topo/r4/nhrp4_cache.json @@ -0,0 +1,30 @@ +{ + "attr":{ + "entriesCount":2 + }, + "table":[ + { + "interface":"r4-gre0", + "type":"local", + "protocol":"10.255.255.4", + "nbma":"10.1.1.4", + "claimed_nbma":"10.1.1.4", + "used":false, + "timeout":false, + "auth":false, + "identity":"-" + }, + { + "interface":"r4-gre0", + "type":"nhs", + "protocol":"10.255.255.2", + "nbma":"10.2.1.2", + "claimed_nbma":"10.2.1.2", + "used":false, + "timeout":true, + "auth":false, + "identity":"" + } + ] +} + diff --git a/tests/topotests/nhrp_topo/r4/nhrp_route4.json b/tests/topotests/nhrp_topo/r4/nhrp_route4.json new file mode 100644 index 00000000..01d627c9 --- /dev/null +++ b/tests/topotests/nhrp_topo/r4/nhrp_route4.json @@ -0,0 +1,26 @@ +{ + "10.255.255.2\/32": [ + { + "prefix": "10.255.255.2\/32", + "prefixLen": 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": "r4-gre0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/nhrp_topo/r4/nhrpd.conf b/tests/topotests/nhrp_topo/r4/nhrpd.conf new file mode 100644 index 00000000..df9700c2 --- /dev/null +++ b/tests/topotests/nhrp_topo/r4/nhrpd.conf @@ -0,0 +1,11 @@ +log stdout debugging +debug nhrp all +interface r4-gre0 + ip nhrp authentication secret + ip nhrp holdtime 10 + ip nhrp shortcut + ip nhrp network-id 42 + ip nhrp nhs dynamic nbma 10.2.1.2 + ip nhrp registration no-unique + tunnel source r4-eth0 +exit diff --git a/tests/topotests/nhrp_topo/r4/zebra.conf b/tests/topotests/nhrp_topo/r4/zebra.conf new file mode 100644 index 00000000..b517dbb0 --- /dev/null +++ b/tests/topotests/nhrp_topo/r4/zebra.conf @@ -0,0 +1,13 @@ +interface r4-eth0 + ip address 10.1.1.4/24 +! +ip route 10.2.1.0/24 10.1.1.3 +interface r4-gre0 + ip address 10.255.255.4/32 + no link-detect + ipv6 nd suppress-ra +exit +interface r4-eth1 + ip address 192.168.4.4/24 +! +ip route 0.0.0.0/0 10.255.255.2 diff --git a/tests/topotests/nhrp_topo/test_nhrp_topo.py b/tests/topotests/nhrp_topo/test_nhrp_topo.py index 284c58a8..90e793f2 100644 --- a/tests/topotests/nhrp_topo/test_nhrp_topo.py +++ b/tests/topotests/nhrp_topo/test_nhrp_topo.py @@ -28,23 +28,57 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version +from lib.common_config import required_linux_kernel_version, retry # Required to instantiate the topology builder class. pytestmark = [pytest.mark.nhrpd] +TOPOLOGY = """ + 192.168.2.0/24 + -----+----- + | + | + | + +----------+ + | | + | R2 | + | NHS | + +----------+ + | .2 + | + | + | + GRE P2MP Between + 10.2.1.0/24 + Between Spokes and Hub | + | + 10.255.255.x/32 +----+-----+ + | | + | R3 | + | | + +----+-----+ + |.3 + | + | + +----------+ | +---------+ + | | | | | | | + | |R1 | | | R4 | | +192.168.1.0/24 +-------------|NHC +---------+----------| NHC | ------+ 192.168.4.0/24 + | | |.1 .4| | | + | +----------+ 10.1.1.0/24 +---------+ | +""" def build_topo(tgen): "Build function" - # Create 3 routers. - for routern in range(1, 4): + # Create 4 routers. + for routern in range(1, 5): tgen.add_router("r{}".format(routern)) switch = tgen.add_switch("s1") switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) switch = tgen.add_switch("s2") switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) @@ -53,6 +87,9 @@ def build_topo(tgen): switch = tgen.add_switch("s4") switch.add_link(tgen.gears["r1"]) + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r4"]) + def _populate_iface(): tgen = get_topogen() @@ -62,6 +99,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", ] cmds_tot = [ @@ -84,10 +122,27 @@ def _populate_iface(): output = tgen.net["r1"].cmd(input) logger.info("output: " + output) + input = cmd.format("r4", "4") + logger.info("input: " + input) + output = tgen.net["r4"].cmd(input) + logger.info("output: " + output) + + +def _verify_iptables(): + tgen = get_topogen() + # Verify iptables is installed + # This is needed for creating shortcuts + for rname in ("r1", "r4"): + rc, _, _ = tgen.net[rname].cmd_status("iptables --version") + if rc == 127: + return False + return True + def setup_module(mod): "Sets up the pytest environment" + logger.info("NHRP Topology : \n {}".format(TOPOLOGY)) result = required_linux_kernel_version("5.0") if result is not True: pytest.skip("Kernel requirements are not met") @@ -103,7 +158,7 @@ def setup_module(mod): TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)), ) - if rname in ("r1", "r2"): + if rname in ("r1", "r2", "r4"): router.load_config( TopoRouter.RD_NHRP, os.path.join(CWD, "{}/nhrpd.conf".format(rname)) ) @@ -214,18 +269,68 @@ def test_protocols_convergence(): def test_nhrp_connection(): "Assert that the NHRP peers can find themselves." tgen = get_topogen() + pingrouter = tgen.gears["r1"] + hubrouter = tgen.gears["r2"] if tgen.routers_have_failure(): pytest.skip(tgen.errors) - pingrouter = tgen.gears["r1"] - logger.info("Check Ping IPv4 from R1 to R2 = 10.255.255.2)") - output = pingrouter.run("ping 10.255.255.2 -f -c 1000") - logger.info(output) - if "1000 packets transmitted, 1000 received" not in output: - assertmsg = "expected ping IPv4 from R1 to R2 should be ok" - assert 0, assertmsg - else: - logger.info("Check Ping IPv4 from R1 to R2 OK") + def ping_helper(): + output = pingrouter.run("ping 10.255.255.2 -f -c 100") + logger.info(output) + return output + + # force session to reinitialize + def relink_session(): + for r in ["r1", "r2", "r4"]: + tgen.gears[r].vtysh_cmd("clear ip nhrp cache") + tgen.net[r].cmd("ip l del {}-gre0".format(r)) + _populate_iface() + + @retry(retry_timeout=40, initial_wait=5) + def verify_same_password(): + output = ping_helper() + if "100 packets transmitted, 100 received" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 OK") + + @retry(retry_timeout=40, initial_wait=5) + def verify_mismatched_password(): + output = ping_helper() + if "Network is unreachable" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 - should be down" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 missing - OK") + + ### Passwords are the same + logger.info("Check Ping IPv4 from R1 to R2 = 10.255.255.2") + verify_same_password() + + ### Passwords are different + logger.info("Modify password and send ping again, should drop") + hubrouter.vtysh_cmd( + """ + configure + interface r2-gre0 + ip nhrp authentication secret12 + """ + ) + relink_session() + verify_mismatched_password() + + ### Passwords are the same - again + logger.info("Recover password and verify conectivity is back") + hubrouter.vtysh_cmd( + """ + configure + interface r2-gre0 + ip nhrp authentication secret + """ + ) + relink_session() + verify_same_password() def test_route_install(): @@ -260,6 +365,134 @@ def test_route_install(): assert result is None, assertmsg +# Initial wait of 30 second because that is +# what the default purge time is for nhrp - +# here we are testing that all of the expected +# retries are sent and logged before a +# shortcut is purged +@retry(retry_timeout=10, initial_wait=30) +def check_retry_debug_info(pingspoke=None): + tgen = get_topogen() + r1 = tgen.gears["r1"] + if pingspoke == None: + pingspoke = r1 + logger.info(f"Check retries are being sent from {pingspoke.name}") + output = pingspoke.cmd("grep -c 'Retrying Resolution Request' nhrpd.log") + # Making sure that we see all expected retries for a 30 second purge time + assertmsg = f"Did not see all expected retries on {pingspoke.name}" + assert output.strip() == "6", assertmsg + logger.info("Check retries are being sent OK") + + +# Helper function to ping between spokes and +# check for either complete or incomplete shortcut +# based on whichever one you are expecting - +# expect_succesful_shortcut inidcates whether +# you are expecting to find a complete shortcut +# (True) or incomplete shortcut (False) as a +# result of the ping +@retry(retry_timeout=10, initial_wait=10) +def create_shortcut(expect_successful_shortcut=True, pingspoke=None, peer_addr=None): + tgen = get_topogen() + r1 = tgen.gears["r1"] + if pingspoke == None: + pingspoke = r1 + if peer_addr == None: + peer_addr = "192.168.4.4" + # Pinging the other spoke in an attempt to create specified type of shortcut + output = pingspoke.cmd(f"ping -c 10 -i .5 {peer_addr}") + print(output) + output = pingspoke.vtysh_cmd("show ip nhrp shortcut") + if expect_successful_shortcut: + logger.info(f"Check shortcut creation from {pingspoke.name} to {peer_addr}") + else: + logger.info( + f"Check incomplete shortcut creation from {pingspoke.name} to {peer_addr}" + ) + + output = pingspoke.vtysh_cmd("show ip nhrp shortcut") + print(output) + if expect_successful_shortcut: + json_file = "{}/{}/nhrp_shortcut_present.json".format(CWD, pingspoke.name) + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, pingspoke, "show ip nhrp shortcut json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + + if result is not None: + assertmsg = ( + "Shortcut is not being made between spoke {} and peer {}".format( + pingspoke.name, peer_addr + ) + ) + assert 0, assertmsg + else: + logger.info("Shortcut creation between spokes OK") + else: + # Currentlly, 'show ip nhrp shortcut json' does not show incomplete shortcuts + # so an explicit check for for the 'incompete' keyword needed here + if "incomplete" not in output: + assertmsg = ( + "Incomplete shortcut between spoke {} and peer {} is not seen".format( + pingspoke.name, peer_addr + ) + ) + assert 0, assertmsg + else: + logger.info("Incomplete shortcut creation between spokes OK") + + +# This function tests the NHRP resolution request retries by dropping +# incoming packets (including the NHRP resolution request packets) +# from a receiving spoke in order to stop the NHRP resolution +# responses from ever being sent from that receiving spoke - and in turn +# resolution responses will not reach the sending spoke. +# This will trigger the NHRP resolution request retries which +# can be viewed through log messages. +def test_nhrp_retry_resolution(): + """ " + Verify resolution requests are retried when resolution responses + are not received by a spoke + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + # iptables used to create shortcuts + # and subsequent resolution request retries + if not _verify_iptables(): + pytest.skip("iptables is not installed") + + r1 = tgen.gears["r1"] + r4 = tgen.gears["r4"] + + logger.info("Testing retrying resolution request functionality") + # Make sure that shortcut creation between spokes work + create_shortcut(expect_successful_shortcut=True) + # Clearing shortcut information for spokes + r1.vtysh_cmd("clear ip nhrp shortcut") + r4.vtysh_cmd("clear ip nhrp shortcut") + + # Setting iptables rules to stop incoming packets on r4 + # This should stop resolution requests from reaching + # the receiving router (r4) and hence stop the + # creation of a complete shortcut + r4.cmd("iptables -A INPUT -i r4-eth0 -j DROP") + + # Make sure that nhrp debugging is enabled to read the retry logs + r1.vtysh_cmd( + """ + configure + debug nhrp all + """ + ) + create_shortcut(expect_successful_shortcut=False) + # Look for retry logging output for resolution request retries + check_retry_debug_info() + # Undo iptables rule + r4.cmd("iptables -D INPUT -i r4-eth0 -j DROP") + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py index 45e1bc8d..ba705e3d 100755 --- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py +++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py @@ -135,7 +135,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py b/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py index 8e7a7ea4..077a9e42 100644 --- a/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py +++ b/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py @@ -30,7 +30,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen def setup_module(mod): @@ -46,7 +46,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py index 142acf1e..73a90224 100644 --- a/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py +++ b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py @@ -153,7 +153,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -229,7 +229,7 @@ def test_ospfv3_routingTable(): # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py index 56497570..85075a79 100644 --- a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py @@ -153,7 +153,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -229,7 +229,7 @@ def test_ospfv3_routingTable(): # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command @@ -351,7 +351,7 @@ def test_ospfv3_routingTable_write_multiplier(): r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py index f9829909..ccf25a0f 100755 --- a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py +++ b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py @@ -186,7 +186,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -260,7 +260,7 @@ def test_ospfv3_routingTable(): # For debugging, uncomment the next line # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command @@ -391,7 +391,7 @@ def test_ospfv3_routingTable_write_multiplier(): r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py index 0531e81d..18b72772 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py @@ -147,7 +147,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -2893,7 +2893,7 @@ def test_ospf_type5_summary_tc51_p2(request): step("Configure and re configure all the commands 10 times in a loop.") - for itrate in range(0, 10): + for _ in range(0, 10): ospf_summ_r1 = { "r0": { "ospf": { diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py index 603aeadb..cdc5d126 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py @@ -139,7 +139,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py index 8dd10301..922c5a0e 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py @@ -109,7 +109,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py index e58f081f..dc237e95 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py @@ -118,7 +118,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index aba313db..21e76752 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -121,7 +121,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -193,7 +193,7 @@ def test_ospf_ecmp_tc16_p0(request): step("Verify that route in R2 in stalled with 8 next hops.") nh = [] - for item in range(1, 7): + for _ in range(1, 7): nh.append(topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0]) nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py index 62b82122..7c37af02 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py @@ -51,7 +51,6 @@ from lib.common_config import ( create_static_routes, step, topo_daemons, - shutdown_bringup_interface, check_router_status, start_topology, write_test_header, @@ -65,8 +64,6 @@ from lib.common_config import ( write_test_header, write_test_footer, reset_config_on_routers, - stop_router, - start_router, step, create_static_routes, kill_router_daemons, @@ -163,7 +160,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py index 4a40b3e9..9c531c03 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py @@ -119,7 +119,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py index a90d7dbd..6aec98c7 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py @@ -105,7 +105,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index c9f43cdf..eee51796 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -134,7 +134,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index d169245f..193f5c8c 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -130,7 +130,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -208,7 +208,7 @@ def test_ospf_redistribution_tc5_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r1" - for num in range(0, nretry): + for _ in range(0, nretry): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break @@ -332,7 +332,7 @@ def test_ospf_redistribution_tc6_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r1" - for num in range(0, nretry): + for _ in range(0, nretry): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py index 59afc7a8..33841b9a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py @@ -115,7 +115,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py index ade55321..2d163799 100644 --- a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py +++ b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py @@ -72,7 +72,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py index 79374281..3bed390b 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py @@ -29,7 +29,6 @@ from lib.common_config import ( write_test_footer, reset_config_on_routers, step, - create_interfaces_cfg, scapy_send_raw_packet, ) @@ -38,7 +37,6 @@ from lib.topojson import build_config_from_json from lib.ospf import ( verify_ospf_neighbor, - clear_ospf, verify_ospf_gr_helper, create_router_ospf, ) diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py index 3be28196..a9028673 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py @@ -29,7 +29,6 @@ from lib.common_config import ( write_test_footer, reset_config_on_routers, step, - create_interfaces_cfg, scapy_send_raw_packet, ) @@ -38,7 +37,6 @@ from lib.topojson import build_config_from_json from lib.ospf import ( verify_ospf_neighbor, - clear_ospf, verify_ospf_gr_helper, create_router_ospf, ) diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py index 73185d50..73b660e5 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -144,7 +144,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py index 590b0d5e..ea450773 100644 --- a/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py +++ b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py @@ -15,7 +15,6 @@ test_ospf_instance_redistribute """ import os -import re import sys import pytest import json diff --git a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py index ea962651..b97b86bf 100644 --- a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py +++ b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py @@ -11,14 +11,13 @@ import os import sys import json -from time import sleep from functools import partial import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger @@ -166,7 +165,7 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() 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 248375dc..131085a4 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 6e133524..45ee1071 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 d7d31434..f3724bbb 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 1495c889..0f8b12bd 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 b1701fe1..db4e268c 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 3723a8a8..48657085 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_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py index ee0a0f6c..10a0051a 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py @@ -16,7 +16,7 @@ import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger @@ -139,7 +139,7 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt index bf874ac7..68fd30d4 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 e5152053..f0bce905 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 3763ef80..098eceb2 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 f6eaba6e..a9300f8d 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 5eb92efd..f58beb81 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 26cc1966..cfedf8fc 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 4fc93b58..718445f0 100644 --- a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py +++ b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py @@ -104,13 +104,13 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() # Move interfaces out of vrf namespace and delete the namespace router_list = tgen.routers() - for rname, router in router_list.items(): + for rname, _ in router_list.items(): tgen.net[rname].reset_intf_netns(rname + "-eth0") tgen.net[rname].reset_intf_netns(rname + "-eth1") tgen.net[rname].delete_netns(rname + "-ospf-cust1") diff --git a/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py b/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py index d8cd1322..4a67fa33 100644 --- a/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py +++ b/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py @@ -106,7 +106,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf index cb4538c0..89f255bb 100644 --- a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all + hostname r1 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf index 0ca8aec3..42933098 100644 --- a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r2 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf index 41ea70d4..eada7845 100644 --- a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r3 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf index 21fa9c72..3146ea09 100644 --- a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r4 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py index 1f0f8795..455c737f 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py @@ -9,7 +9,6 @@ import os import sys -import json from time import sleep from functools import partial import pytest @@ -17,13 +16,10 @@ import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -112,13 +108,15 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() -def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): +def verify_p2mp_interface( + tgen, router, nbr_cnt, nbr_adj_cnt, delay_reflood, nbr_filter +): "Verify the P2MP Configuration and interface settings" topo_router = tgen.gears[router] @@ -140,22 +138,6 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): "interfaces": { "r1-eth0": { "ospfEnabled": True, - "interfaceIp": { - "10.1.0.1": { - "ipAddress": "10.1.0.1", - "ipAddressPrefixlen": 24, - "ospfIfType": "Broadcast", - "routerId": "1.1.1.1", - "networkType": "POINTOMULTIPOINT", - "cost": 10, - "state": "Point-To-Point", - "nbrCount": nbr_cnt, - "nbrAdjacentCount": nbr_adj_cnt, - "prefixSuppression": False, - "p2mpDelayReflood": False, - "nbrFilterPrefixList": nbr_filter, - } - }, "ipAddress": "10.1.0.1", "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", @@ -168,7 +150,7 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): "nbrCount": nbr_cnt, "nbrAdjacentCount": nbr_adj_cnt, "prefixSuppression": False, - "p2mpDelayReflood": False, + "p2mpDelayReflood": delay_reflood, "nbrFilterPrefixList": nbr_filter, } } @@ -201,17 +183,6 @@ def verify_non_p2mp_interface(tgen): "interfaces": { "r1-eth0": { "ospfEnabled": True, - "interfaceIp": { - "10.1.0.1": { - "ipAddress": "10.1.0.1", - "ipAddressPrefixlen": 24, - "ospfIfType": "Broadcast", - "routerId": "1.1.1.1", - "networkType": "BROADCAST", - "cost": 10, - "prefixSuppression": False, - } - }, "ipAddress": "10.1.0.1", "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", @@ -312,7 +283,7 @@ def test_p2mp_broadcast_interface(): pytest.skip("Skipped because of router(s) failure") step("Verify router r1 interface r1-eth0 p2mp configuration") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") step("Verify router r1 p2mp interface r1-eth0 neighbors") verify_p2mp_neighbor( @@ -337,7 +308,7 @@ def test_p2mp_broadcast_interface(): step("Verify router r1 interface r1-eth0 p2mp configuration application") r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf network point-to-multipoint") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") step("Verify restablishment of r1-eth0 p2mp neighbors") verify_p2mp_neighbor( @@ -356,14 +327,14 @@ def test_p2mp_broadcast_interface(): verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0") -def test_p2mp_broadcast_neighbor_filter(): +def p2mp_broadcast_neighbor_filter_common(delay_reflood): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip("Skipped because of router(s) failure") step("Verify router r1 interface r1-eth0 p2mp configuration") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Verify router r1 p2mp interface r1-eth0 neighbors") verify_p2mp_neighbor( @@ -394,7 +365,7 @@ def test_p2mp_broadcast_neighbor_filter(): assert neighbor_filter_cfg == " ip ospf neighbor-filter nbr-filter", assertmsg step("Verify non-existent neighbor-filter is not applied to r1 interfaces") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Add nbr-filter prefix-list configuration to r1") r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 200 permit any") @@ -402,7 +373,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and neighbors still adjacent" ) - verify_p2mp_interface(tgen, "r1", 3, 3, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "nbr-filter") step("Add nbr-filter prefix-list configuration to block r4") r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") @@ -410,7 +381,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and r4 is no longer adjacent" ) - verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") step("Verify route to r4 subnet is now through r2") @@ -422,7 +393,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and r2 is no longer adjacent" ) - verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") step("Verify route to r4 and r2 subnet are now through r3") @@ -438,24 +409,105 @@ def test_p2mp_broadcast_neighbor_filter(): assert rc, assertmsg step("Verify interface neighbor-filter is removed and neighbors present") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Add neighbor filter configuration and verify neighbors are filtered") r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") - verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") step("Remove nbr-filter prefix-list configuration to block r2 and verify neighbor") r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter seq 20") - verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") verify_p2mp_neighbor( tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" ) step("Delete nbr-filter prefix-list and verify neighbors are present") r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") + + +def test_p2mp_broadcast_neighbor_filter(): + p2mp_broadcast_neighbor_filter_common(False) + + +def test_p2mp_broadcast_neighbor_filter_delay_reflood(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + step("Modify router r1 interface r1-eth0 p2mp delay-reflood configuration") + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + "conf t\ninterface r1-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + verify_p2mp_interface(tgen, "r1", 3, 3, True, "N/A") + + step("Modify router r2 interface r2-eth0 p2mp delay-reflood configuration") + r2 = tgen.gears["r2"] + r2.vtysh_cmd( + "conf t\ninterface r2-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r3 interface r3-eth0 p2mp delay-reflood configuration") + r3 = tgen.gears["r3"] + r3.vtysh_cmd( + "conf t\ninterface r3-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r4 interface r4-eth0 p2mp delay-reflood configuration") + r4 = tgen.gears["r4"] + r4.vtysh_cmd( + "conf t\ninterface r4-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + p2mp_broadcast_neighbor_filter_common(True) + + step("Recreate a partial P2MP mesh with neighbor filters") + step("Add nbr-filter prefix-list configuration to block r4") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.3/32") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.4/32") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") + + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") + r2.vtysh_cmd("conf t\ninterface r2-eth0\nip ospf neighbor-filter nbr-filter") + + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r3.vtysh_cmd("conf t\ninterface r3-eth0\nip ospf neighbor-filter nbr-filter") + + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.2/32") + r4.vtysh_cmd("conf t\ninterface r4-eth0\nip ospf neighbor-filter nbr-filter") + + step( + "Add redistribution and spaced static routes to r1 to test delay flood retransmission" + ) + r1.vtysh_cmd("conf t\nrouter ospf\nredistribute static") + r1.vtysh_cmd("conf t\nip route 20.1.1.1/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.2/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.3/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.4/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.5/32 null0") + sleep(1) + + step( + "Verify the routes are installed on r1 with delay-reflood in P2MP partial mesh" + ) + verify_p2mp_route(tgen, "r4", "20.1.1.1/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.2/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.3/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.4/32", 32, "10.1.0.3", "r4-eth0") def test_memory_leak(): diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py index 175dca74..83137a89 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py @@ -10,7 +10,6 @@ import os import sys -import json from time import sleep from functools import partial import pytest @@ -18,13 +17,10 @@ import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -116,7 +112,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -144,22 +140,6 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, non_broadcast): "interfaces": { "r1-eth0": { "ospfEnabled": True, - "interfaceIp": { - "10.1.0.1": { - "ipAddress": "10.1.0.1", - "ipAddressPrefixlen": 24, - "ospfIfType": "Broadcast", - "routerId": "1.1.1.1", - "networkType": "POINTOMULTIPOINT", - "cost": 10, - "state": "Point-To-Point", - "nbrCount": nbr_cnt, - "nbrAdjacentCount": nbr_adj_cnt, - "prefixSuppression": False, - "p2mpDelayReflood": False, - "p2mpNonBroadcast": non_broadcast, - } - }, "ipAddress": "10.1.0.1", "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", diff --git a/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py b/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py index d5ea7ebc..f91cba8d 100644 --- a/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py +++ b/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py @@ -10,21 +10,16 @@ import os import sys -import json -from time import sleep from functools import partial import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -125,7 +120,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_single_switch/test_ospf_single_switch.py b/tests/topotests/ospf_single_switch/test_ospf_single_switch.py index e53b5f5b..0a8d8456 100644 --- a/tests/topotests/ospf_single_switch/test_ospf_single_switch.py +++ b/tests/topotests/ospf_single_switch/test_ospf_single_switch.py @@ -14,12 +14,11 @@ from functools import partial import pytest from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import verify_rib from lib.ospf import verify_ospf_rib -from _ast import Try pytestmark = pytest.mark.ospfd @@ -86,7 +85,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Tear-down the test environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py b/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py index 21ae1432..ec076bb3 100755 --- a/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py +++ b/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py @@ -164,7 +164,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py index 936b438e..bac585dd 100644 --- a/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py +++ b/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py @@ -136,7 +136,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py index 8b3fc580..7f9ad27e 100644 --- a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py @@ -24,7 +24,6 @@ import os import sys import json from functools import partial -import re import pytest # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py b/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py index f939f3f5..24667248 100644 --- a/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py +++ b/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py @@ -110,7 +110,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_topo1/test_ospf_topo1.py b/tests/topotests/ospf_topo1/test_ospf_topo1.py index a079f569..b9bdee3d 100644 --- a/tests/topotests/ospf_topo1/test_ospf_topo1.py +++ b/tests/topotests/ospf_topo1/test_ospf_topo1.py @@ -93,7 +93,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_topo2/test_ospf_topo2.py b/tests/topotests/ospf_topo2/test_ospf_topo2.py index 8be06e41..45ae338a 100644 --- a/tests/topotests/ospf_topo2/test_ospf_topo2.py +++ b/tests/topotests/ospf_topo2/test_ospf_topo2.py @@ -66,7 +66,7 @@ def tgen(request): router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py index d07f5dc5..712c4e1d 100644 --- a/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py +++ b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py @@ -89,7 +89,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py b/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py index c0dd85cb..a97b1145 100644 --- a/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py @@ -92,7 +92,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py index 626a9d31..89a34ff9 100644 --- a/tests/topotests/ospfapi/test_ospf_clientapi.py +++ b/tests/topotests/ospfapi/test_ospf_clientapi.py @@ -16,7 +16,6 @@ import signal import subprocess import sys import time -from datetime import datetime, timedelta from functools import partial import pytest @@ -35,8 +34,7 @@ from lib.topotest import interface_set_status, json_cmp # 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.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.ospfd] diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py index 49c25ab8..c431147e 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py @@ -29,7 +29,6 @@ from time import sleep from lib.common_config import ( start_topology, write_test_header, - kill_router_daemons, write_test_footer, reset_config_on_routers, stop_router, @@ -37,7 +36,6 @@ from lib.common_config import ( verify_rib, create_static_routes, step, - start_router_daemons, create_route_maps, shutdown_bringup_interface, create_prefix_lists, @@ -163,7 +161,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -2456,7 +2454,7 @@ def test_ospfv3_type5_summary_tc51_p2(request): step("Configure and re configure all the commands 10 times in a loop.") - for itrate in range(0, 10): + for _ in range(0, 10): ospf_summ_r1 = { "r0": { "ospf6": { diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py index 00c98ac9..5f88f6d8 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py @@ -14,9 +14,7 @@ import sys import time import pytest from time import sleep -from copy import deepcopy import json -from lib.topotest import frr_unicode pytestmark = pytest.mark.ospf6d @@ -39,11 +37,8 @@ from lib.common_config import ( shutdown_bringup_interface, ) from lib.topolog import logger -from lib.topojson import build_topo_from_json, build_config_from_json -from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface, clear_ospf -from ipaddress import IPv4Address - -# Global variables +from lib.topojson import build_config_from_json +from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface topo = None # Reading the data from JSON File for topology creation jsonFile = "{}/ospfv3_authentication.json".format(CWD) @@ -118,7 +113,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. * `mod`: module name diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py index 0c1e3fa4..45652a3e 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py @@ -122,7 +122,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -285,7 +285,7 @@ def test_ospfv3_ecmp_tc16_p0(request): step("Verify that route in R2 in stalled with 8 next hops.") nh = [] - for item in range(1, 7): + for _ in range(1, 7): nh.append(llip) llip = get_llip("r0", "r1") diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py index 7c677326..95f2493c 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py @@ -13,11 +13,6 @@ import os import sys import time import pytest -import json -from copy import deepcopy -from ipaddress import IPv4Address -from lib.topotest import frr_unicode -import ipaddress # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -37,9 +32,6 @@ from lib.common_config import ( verify_rib, create_static_routes, step, - create_route_maps, - shutdown_bringup_interface, - create_interfaces_cfg, get_frr_ipv6_linklocal, ) from lib.topolog import logger @@ -47,16 +39,11 @@ from lib.topojson import build_config_from_json from lib.ospf import ( verify_ospf6_neighbor, - config_ospf_interface, clear_ospf, verify_ospf6_rib, create_router_ospf, - verify_ospf6_interface, - verify_ospf6_database, - config_ospf6_interface, ) -from ipaddress import IPv6Address pytestmark = [pytest.mark.ospfd, pytest.mark.staticd] @@ -137,7 +124,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py index dc4ce888..cc96cd17 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py @@ -78,7 +78,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py index 5a6c377a..4ad725e3 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py @@ -13,15 +13,10 @@ import os import sys import time import pytest -from copy import deepcopy import ipaddress from lib.ospf import ( verify_ospf6_neighbor, - config_ospf6_interface, - clear_ospf, verify_ospf6_rib, - verify_ospf6_interface, - verify_ospf6_database, create_router_ospf, ) @@ -29,12 +24,6 @@ from lib.ospf import ( # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.bgp import ( - verify_bgp_convergence, - create_router_bgp, - clear_bgp_and_verify, - verify_bgp_rib, -) from lib.topolog import logger from lib.common_config import ( start_topology, @@ -44,12 +33,9 @@ from lib.common_config import ( verify_rib, create_static_routes, step, - create_route_maps, - shutdown_bringup_interface, create_interfaces_cfg, check_router_status, ) -from ipaddress import IPv4Address from lib.topolog import logger from lib.topojson import build_config_from_json diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py index 069806a3..ff88bade 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py @@ -136,7 +136,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py index 916f6555..06989db8 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py @@ -45,7 +45,6 @@ from lib.ospf import ( verify_ospf6_neighbor, clear_ospf, verify_ospf6_rib, - verify_ospf_database, create_router_ospf, config_ospf6_interface, verify_ospf6_interface, @@ -127,7 +126,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. 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 f0b139a5..00d4e8ff 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py @@ -36,7 +36,6 @@ from lib.common_config import ( step, create_interfaces_cfg, create_debug_log_config, - apply_raw_config, ) from lib.topolog import logger from lib.topojson import build_config_from_json @@ -121,7 +120,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -389,6 +388,11 @@ def test_ospfv3_hello_tc10_p0(request): step("Bring up the base config as per the topology") reset_config_on_routers(tgen) + ospf_covergence = verify_ospf6_neighbor(tgen) + assert ( + ospf_covergence is True + ), "Testcase {} [01]: Reset Failed \n Error: {}".format(tc_name, ospf_covergence) + step("modify hello timer from default value to some other value on r1") topo1 = { @@ -403,7 +407,9 @@ def test_ospfv3_hello_tc10_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 {} [02]: Failed \n Error: {}".format( + tc_name, result + ) step( "verify that new timer value is configured and applied using " @@ -423,7 +429,9 @@ def test_ospfv3_hello_tc10_p0(request): } } 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 {} [03]: Failed \n Error: {}".format( + tc_name, result + ) step("modify hello timer from default value to r1 hello timer on r2") @@ -439,7 +447,9 @@ def test_ospfv3_hello_tc10_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 {} [04]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -456,12 +466,14 @@ def test_ospfv3_hello_tc10_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 {} [05]: 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( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [06]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("reconfigure the default hello timer value to default on r1 and r2") @@ -478,7 +490,9 @@ def test_ospfv3_hello_tc10_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": { @@ -492,7 +506,9 @@ def test_ospfv3_hello_tc10_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 = { @@ -509,12 +525,14 @@ def test_ospfv3_hello_tc10_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 {} [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( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [10]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("reconfigure the default hello timer value to default on r1 and r2") @@ -531,7 +549,9 @@ def test_ospfv3_hello_tc10_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": { @@ -545,7 +565,9 @@ def test_ospfv3_hello_tc10_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 = { @@ -562,12 +584,14 @@ def test_ospfv3_hello_tc10_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( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [14]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("configure hello timer = 1 on r1 and r2") @@ -583,7 +607,9 @@ def test_ospfv3_hello_tc10_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 {} [15]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -597,7 +623,9 @@ def test_ospfv3_hello_tc10_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 new timer value is configured.") input_dict = { @@ -614,12 +642,14 @@ def test_ospfv3_hello_tc10_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 {} [17]: 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( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [18]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step(" Configure hello timer = 65535") @@ -635,7 +665,9 @@ def test_ospfv3_hello_tc10_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 {} [19]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -649,7 +681,9 @@ def test_ospfv3_hello_tc10_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 {} [20]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -666,7 +700,9 @@ def test_ospfv3_hello_tc10_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 {} [21]: Failed \n Error: {}".format( + tc_name, result + ) step(" Try configuring timer values outside range for example 65536") topo1 = { @@ -683,7 +719,7 @@ def test_ospfv3_hello_tc10_p0(request): result = create_interfaces_cfg(tgen, topo1) assert ( result is not True - ), "Testcase {} : Failed \n Create interface failed. Error: {}".format( + ), "Testcase {} [23]: Failed \n Create interface failed. Error: {}".format( tc_name, result ) @@ -702,13 +738,17 @@ def test_ospfv3_hello_tc10_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 {} [24]: 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": {"timerIntervalsConfigHello": 10}}}}} 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 {} [25]: Failed \n Error: {}".format( + tc_name, result + ) write_test_footer(tc_name) @@ -745,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 " @@ -754,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") @@ -763,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) @@ -805,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": { @@ -819,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 ) @@ -847,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": { @@ -861,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 = { @@ -869,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 ) @@ -892,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 ) @@ -911,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_acl/test_pim_acl.py b/tests/topotests/pim_acl/test_pim_acl.py index 6e5092da..d8eececf 100755 --- a/tests/topotests/pim_acl/test_pim_acl.py +++ b/tests/topotests/pim_acl/test_pim_acl.py @@ -169,7 +169,7 @@ def setup_module(module): tgen.start_router() -def teardown_module(module): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/pim_autorp/__init__.py b/tests/topotests/pim_autorp/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/tests/topotests/pim_autorp/r1/frr.conf b/tests/topotests/pim_autorp/r1/frr.conf new file mode 100644 index 00000000..2fddbc3a --- /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 00000000..fd3c0cad --- /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 00000000..ad618af2 --- /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/test_pim.py b/tests/topotests/pim_basic/test_pim.py index 85b49aac..ce1abe42 100644 --- a/tests/topotests/pim_basic/test_pim.py +++ b/tests/topotests/pim_basic/test_pim.py @@ -88,7 +88,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() 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 00000000..72d031e1 --- /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 00000000..08f721dd --- /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 00000000..8e58e8c6 --- /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 00000000..ed60fdd4 --- /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 00000000..b6804fa1 --- /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 00000000..e69de29b 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 00000000..899e9c06 --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r1/frr.conf @@ -0,0 +1,49 @@ +! +hostname r1 +password zebra +log file /tmp/r1-frr.log +! +!debug pim packet +!debug pim bsm +!debug pimv6 bsm +! +! +interface lo + ip address 10.0.0.1/32 + ipv6 address fd00:0:0:0::1/128 + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r1-eth0 + ip address 10.0.0.1/24 + ipv6 address fd00:0:0:0::1/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r1-eth1 + ip address 10.0.1.1/24 + ipv6 address fd00:0:0:1::1/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +router pim + bsr candidate-bsr priority 200 source address 10.0.0.1 +! +router pim6 + bsr candidate-bsr priority 200 source address fd00:0:0:0::1 +! +router ospf + ospf router-id 10.0.0.1 + network 10.0.0.0/16 area 0 +! +router ospf6 + ospf6 router-id 10.0.0.1 +! +ip forwarding +ipv6 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 00000000..85af461d --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r2/frr.conf @@ -0,0 +1,48 @@ +! +hostname r2 +password zebra +log file /tmp/r2-frr.log +! +!debug pim packet +!debug pim bsm +!debug pimv6 bsm +! +interface lo + ip address 10.0.0.2/32 + ipv6 address fd00:0:0:0::2/128 + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r2-eth0 + ip address 10.0.0.2/24 + ipv6 address fd00:0:0:0::2/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r2-eth1 + ip address 10.0.2.2/24 + ipv6 address fd00:0:0:2::2/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +router pim + bsr candidate-bsr priority 100 +! +router pim6 + bsr candidate-bsr priority 100 +! +router ospf + ospf router-id 10.0.0.2 + network 10.0.0.0/16 area 0 +! +router ospf6 + ospf6 router-id 10.0.0.2 +! +ip forwarding +ipv6 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 00000000..022c44ea --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r3/frr.conf @@ -0,0 +1,52 @@ +! +hostname r3 +password zebra +log file /tmp/r3-frr.log +! +!debug pim packet +!debug pim bsm +!debug pimv6 bsm +! +! +interface r3-eth0 + ip address 10.0.1.3/24 + ipv6 address fd00:0:0:1::3/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r3-eth1 + ip address 10.0.3.3/24 + ipv6 address fd00:0:0:3::3/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r3-eth2 + ip address 10.0.4.3/24 + ipv6 address fd00:0:0:4::3/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +router pim + bsr candidate-rp group 239.0.0.0/16 + bsr candidate-rp priority 10 source address 10.0.3.3 +! +router pim6 + bsr candidate-rp group ffbb::/64 + bsr candidate-rp priority 10 source address fd00:0:0:3::3 +! +router ospf + ospf router-id 10.0.1.3 + network 10.0.0.0/16 area 0 +! +router ospf6 + ospf6 router-id 10.0.1.3 +! +ip forwarding +ipv6 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 00000000..2d0a035f --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r4/frr.conf @@ -0,0 +1,66 @@ +! +hostname r4 +password zebra +log file /tmp/r4-frr.log +! +! +interface lo + ip address 10.0.3.4/32 + ipv6 address fd00:0:0:3::4/64 + ip pim + ipv6 pim +! +interface r4-eth0 + ip address 10.0.2.4/24 + ipv6 address fd00:0:0:2::4/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r4-eth1 + ip address 10.0.3.4/24 + ipv6 address fd00:0:0:3::4/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r4-eth2 + ip address 10.0.5.4/24 + ipv6 address fd00:0:0:5::4/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r4-eth3 + ip address 10.0.0.4/24 + ipv6 address fd00:0:0:0::4/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +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 +! +router pim6 + bsr candidate-rp group ffbb::/124 + bsr candidate-rp group ffbb::/64 + bsr candidate-rp group ffbb::/108 + bsr candidate-rp priority 20 +! +router ospf + ospf router-id 10.0.2.4 + network 10.0.0.0/16 area 0 +! +router ospf6 + ospf6 router-id 10.0.2.4 +! +ip forwarding +ipv6 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 00000000..552e51f4 --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r5/frr.conf @@ -0,0 +1,34 @@ +! +hostname r5 +password zebra +log file /tmp/r5-frr.log +! +! +interface r5-eth0 + ip address 10.0.4.5/24 + ipv6 address fd00:0:0:4::5/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r5-eth1 + ip address 10.0.6.5/24 + ipv6 address fd00:0:0:6::5/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +router pim6 +! +router ospf + ospf router-id 10.0.4.5 + network 10.0.0.0/16 area 0 +! +router ospf6 + ospf6 router-id 10.0.4.5 +! +ip forwarding +ipv6 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 00000000..20955a12 --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r6/frr.conf @@ -0,0 +1,42 @@ +! +hostname r6 +password zebra +log file /tmp/r6-frr.log +! +! +interface r6-eth0 + ip address 10.0.5.6/24 + ipv6 address fd00:0:0:5::6/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r6-eth1 + ip address 10.0.6.6/24 + ipv6 address fd00:0:0:6::6/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +interface r6-eth2 + ip address 10.0.3.6/24 + ipv6 address fd00:0:0:3::6/64 + ip igmp + ip pim + ipv6 pim + ipv6 ospf6 area 0 +! +router pim6 +! +router ospf + ospf router-id 10.0.5.6 + network 10.0.0.0/16 area 0 +! +router ospf6 + ospf6 router-id 10.0.5.6 +! +ip forwarding +ipv6 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 00000000..96a3241a --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/test_pim_cand_rp_bsr.py @@ -0,0 +1,506 @@ +#!/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, + pytest.mark.pim6d, + pytest.mark.ospfd, + pytest.mark.ospf6d, +] + + +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_pimv6_bsr_election_r1(request): + "Test PIMv6 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": "fd00::1", + "priority": 200, + "state": "ACCEPT_PREFERRED", + } + + test_func = partial( + topotest.router_json_cmp, r2, "show ipv6 pim bsr json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + + assertmsg = "r2: r1 was not elected, IPv6 bsr election mismatch" + assert result is None, assertmsg + + +def test_pimv6_bsr_cand_rp(request): + "Test PIMv6 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": "fd00:0:0:3::3", "priority": 10} + test_func = partial( + topotest.router_json_cmp, r3, "show ipv6 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_pimv6_bsr_rp_info(request): + "Test IPv6 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", + "ffbb::0/64", + None, + "fd00:0:0:3::3", + "BSR", + False, + "ipv6", + True, + retry_timeout=90, + ) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + result = verify_pim_rp_info( + tgen, + None, + "r5", + "ffbb::0/124", + None, + "fd00:0:0:3::4", + "BSR", + False, + "ipv6", + True, + retry_timeout=30, + ) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + result = verify_pim_rp_info( + tgen, + None, + "r5", + "ffbb::0/108", + None, + "fd00:0:0:3::4", + "BSR", + False, + "ipv6", + 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/pim_igmp_vrf/test_pim_vrf.py b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py index 01c496d7..d6d879d4 100755 --- a/tests/topotests/pim_igmp_vrf/test_pim_vrf.py +++ b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py @@ -92,7 +92,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.topotest import iproute2_is_vrf_capable -from lib.common_config import required_linux_kernel_version, retry +from lib.common_config import required_linux_kernel_version from lib.pim import McastTesterHelper @@ -205,7 +205,7 @@ def setup_module(module): ) -def teardown_module(module): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index db806fed..b234a842 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/rip_allow_ecmp/test_rip_allow_ecmp.py b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py index 7d958fd4..c07b1ffc 100644 --- a/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py +++ b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py @@ -20,7 +20,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripd] @@ -39,7 +39,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py b/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py index d03d5479..26680f54 100644 --- a/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py +++ b/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py @@ -20,7 +20,6 @@ import pytest from functools import partial from lib import topotest from lib.topogen import Topogen, TopoRouter -from lib.topolog import logger pytestmark = [ pytest.mark.bfdd, diff --git a/tests/topotests/rip_passive_interface/test_rip_passive_interface.py b/tests/topotests/rip_passive_interface/test_rip_passive_interface.py index c2b28c4a..ebc36d1f 100644 --- a/tests/topotests/rip_passive_interface/test_rip_passive_interface.py +++ b/tests/topotests/rip_passive_interface/test_rip_passive_interface.py @@ -21,7 +21,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripd] @@ -40,7 +40,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/rip_topo1/r1/show_ip_rip.ref b/tests/topotests/rip_topo1/r1/show_ip_rip.ref index a0b77c88..b49a042d 100644 --- a/tests/topotests/rip_topo1/r1/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r1/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r2/show_ip_rip.ref b/tests/topotests/rip_topo1/r2/show_ip_rip.ref index b61fb45e..d0e7e81b 100644 --- a/tests/topotests/rip_topo1/r2/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r2/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r3/show_ip_rip.ref b/tests/topotests/rip_topo1/r3/show_ip_rip.ref index 1df299b5..bb4afc76 100644 --- a/tests/topotests/rip_topo1/r3/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r3/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py b/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py index 08bb9999..060b558f 100644 --- a/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py +++ b/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py @@ -20,7 +20,7 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripngd] @@ -39,7 +39,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ripng_route_map/test_ripng_route_map.py b/tests/topotests/ripng_route_map/test_ripng_route_map.py index e1cc88e9..4fadb5fb 100644 --- a/tests/topotests/ripng_route_map/test_ripng_route_map.py +++ b/tests/topotests/ripng_route_map/test_ripng_route_map.py @@ -20,8 +20,7 @@ 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 +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.ripngd] @@ -39,7 +38,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref index 30d0f31e..8645979c 100644 --- a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref index fe5bcc8b..2c4db1ab 100644 --- a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref index 909ad663..2ba0aa6d 100644 --- a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/route_scale/scale_test_common.py b/tests/topotests/route_scale/scale_test_common.py index b3cba1cb..bb95c660 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 \ @@ -165,7 +186,7 @@ def route_install_helper(iter): # Table of defaults, used for timeout values and 'expected' objects scale_defaults = dict( - zip(scale_keys, [None, None, 10, 50, expected_installed, expected_removed]) + zip(scale_keys, [None, None, 10, 60, expected_installed, expected_removed]) ) # List of params for each step in the test; note extra time given @@ -176,13 +197,12 @@ 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; # use defaults where the step doesn't supply a value - scale_setups = [] s = scale_steps[iter] d = dict(zip(scale_keys, s)) diff --git a/tests/topotests/route_scale/test_route_scale1.py b/tests/topotests/route_scale/test_route_scale1.py index ccbdd515..68af979c 100644 --- a/tests/topotests/route_scale/test_route_scale1.py +++ b/tests/topotests/route_scale/test_route_scale1.py @@ -14,11 +14,8 @@ test_route_scale1.py: Testing route scale """ import os -import re import sys import pytest -import json -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -26,9 +23,6 @@ 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 scale_test_common import ( scale_build_common, diff --git a/tests/topotests/route_scale/test_route_scale2.py b/tests/topotests/route_scale/test_route_scale2.py index e244d4fb..4be8554a 100644 --- a/tests/topotests/route_scale/test_route_scale2.py +++ b/tests/topotests/route_scale/test_route_scale2.py @@ -14,11 +14,8 @@ test_route_scale2.py: Testing route scale """ import os -import re import sys import pytest -import json -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -26,9 +23,6 @@ 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 scale_test_common import ( scale_build_common, diff --git a/tests/topotests/simple_snmp_test/test_simple_snmp.py b/tests/topotests/simple_snmp_test/test_simple_snmp.py index ee02c7b5..0387e292 100755 --- a/tests/topotests/simple_snmp_test/test_simple_snmp.py +++ b/tests/topotests/simple_snmp_test/test_simple_snmp.py @@ -79,7 +79,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/srv6_encap_src_addr/r1/zebra.conf b/tests/topotests/srv6_encap_src_addr/r1/zebra.conf index c570756b..c245dd2d 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_encap_src_addr/test_srv6_encap_src_addr.py b/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py index b8bcab8d..854bc1cd 100755 --- a/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py +++ b/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py @@ -18,7 +18,6 @@ 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, "../")) @@ -56,7 +55,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/srv6_locator/test_srv6_locator.py b/tests/topotests/srv6_locator/test_srv6_locator.py index 3a27d9c2..bab67464 100755 --- a/tests/topotests/srv6_locator/test_srv6_locator.py +++ b/tests/topotests/srv6_locator/test_srv6_locator.py @@ -56,7 +56,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -81,12 +81,12 @@ def test_srv6(): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py index 92980d3b..d3df902a 100755 --- a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py +++ b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py @@ -52,7 +52,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -77,12 +77,12 @@ def test_srv6(): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py index 54187351..e0c05c51 100755 --- a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py +++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py @@ -49,7 +49,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -70,13 +70,13 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=3) + _, result = topotest.run_and_expect(func, None, count=5, wait=3) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=3) + _, result = topotest.run_and_expect(func, None, count=5, wait=3) assert result is None, "Failed" 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 00000000..34597966 --- /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 00000000..a35e2b1b --- /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 00000000..0dea0c57 --- /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 00000000..8ed99787 --- /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 00000000..b4594d1c --- /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 00000000..c4755f84 --- /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 00000000..a85d9701 --- /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 00000000..3a50cb01 --- /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 00000000..046bcb6a --- /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 00000000..93fb32fd --- /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 00000000..f6484355 --- /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 00000000..7913d6f3 --- /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 00000000..2ab6f2d2 --- /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 00000000..a88df73c --- /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 00000000..21414ffc --- /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 00000000..e0b65405 --- /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 00000000..ab6dfc9e --- /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 00000000..ebe85560 --- /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 00000000..e69de29b 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 00000000..80741856 --- /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 00000000..20c396af --- /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 00000000..29e1a311 --- /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 00000000..e69de29b 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 00000000..590d75af --- /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 00000000..cdbec3f2 --- /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 00000000..c4a5d750 --- /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 00000000..9c5901b9 --- /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 00000000..52bc589a --- /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 00000000..2aae3497 --- /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 00000000..de9e450c --- /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 00000000..ef7fb78e --- /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 00000000..b095f049 --- /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 00000000..1d4a9e9a --- /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 00000000..fc0f1d3b --- /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 00000000..f8a5d93f --- /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 00000000..5e46ddf7 --- /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 00000000..32737dfc --- /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 00000000..e237db2f --- /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 00000000..6ce5760e --- /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 00000000..c590fcfd --- /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 00000000..c6287058 --- /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 00000000..a284240d --- /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 00000000..73cf6b08 --- /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 00000000..b4c92146 --- /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 00000000..0f26fa5d --- /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 00000000..7b575f18 --- /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 00000000..cb052dbb --- /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 00000000..0ca7a76b --- /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 00000000..266db7c5 --- /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 00000000..26f895dd --- /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 00000000..65beaa59 --- /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 00000000..a7b3262f --- /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 00000000..ec55f24d --- /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 00000000..f40b0d35 --- /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 00000000..90110355 --- /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 00000000..c36fae79 --- /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 00000000..f8816db4 --- /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 00000000..e69de29b 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 00000000..5fc293b6 --- /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 00000000..d06354b8 --- /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 00000000..abcdedde --- /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 00000000..8300ca0b --- /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 00000000..fe0fa245 --- /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 00000000..87ff5a99 --- /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 00000000..95d7d441 --- /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 00000000..8ac64c55 --- /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 00000000..31f22d99 --- /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 +# + +""" +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/srv6_static_route/test_srv6_route.py b/tests/topotests/srv6_static_route/test_srv6_route.py index 7a4cd39f..f23e199d 100755 --- a/tests/topotests/srv6_static_route/test_srv6_route.py +++ b/tests/topotests/srv6_static_route/test_srv6_route.py @@ -55,7 +55,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -74,7 +74,7 @@ def test_srv6_static_route(): def check_srv6_static_route(router, expected_file): func = functools.partial(_check_srv6_static_route, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=15, wait=1) + _, result = topotest.run_and_expect(func, None, count=15, wait=1) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/static_routing_mpls/test_static_routing_mpls.py b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py index c1e249cc..a0f11c01 100644 --- a/tests/topotests/static_routing_mpls/test_static_routing_mpls.py +++ b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py @@ -14,11 +14,8 @@ test_static_routing_mpls.py: Testing MPLS configuration with mpls interface sett """ import os -import re import sys import pytest -import json -from functools import partial import functools # Save the Current Working Directory to find configuration files. @@ -113,7 +110,7 @@ def _check_mpls_state(router, interface, configured=True): test_func = functools.partial( _check_mpls_state_interface, router, interface, up=configured ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) return success diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py index e0135150..0d6b3e7b 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py @@ -150,7 +150,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py index 9d35b7dc..ff349f27 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py @@ -134,7 +134,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py index 3e03055a..c74d8d70 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py @@ -113,7 +113,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py index abae75e7..926a9909 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py @@ -110,7 +110,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py index 820a736a..933e5410 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py @@ -152,7 +152,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py index 1ad963f3..9fabd9d5 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py @@ -133,7 +133,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py index 0fc81aaf..f1b7606e 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py @@ -111,7 +111,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/static_simple/test_static_simple.py b/tests/topotests/static_simple/test_static_simple.py index f862d812..bb3580a1 100644 --- a/tests/topotests/static_simple/test_static_simple.py +++ b/tests/topotests/static_simple/test_static_simple.py @@ -13,11 +13,10 @@ import datetime import ipaddress import math import os -import sys import re import pytest -from lib.topogen import TopoRouter, Topogen, get_topogen +from lib.topogen import TopoRouter, Topogen from lib.topolog import logger from lib.common_config import retry, step @@ -80,7 +79,7 @@ def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): kernel = r1.run(f"ip -4 route show{vrfstr}") logger.debug("checking kernel routing table%s:\n%s", vrfstr, kernel) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if not add: assert str(net) not in kernel continue @@ -116,7 +115,6 @@ def do_config( else: super_prefix = "2001::/48" if do_ipv6 else "10.0.0.0/8" - matchtype = "" matchvia = "" if via == "blackhole": pass @@ -146,7 +144,7 @@ def do_config( if vrf: f.write("vrf {}\n".format(vrf)) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if add: f.write("ip route {} {}\n".format(net, via)) else: 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 00000000..e69de29b 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 00000000..9d28957d --- /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 00000000..3bb8cf8a --- /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 00000000..1522e903 --- /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 00000000..46d2c9a0 --- /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 00000000..add181dd --- /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 00000000..8b026698 --- /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 00000000..af0d1eb7 --- /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 00000000..060777e7 --- /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 00000000..db6a503b --- /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 00000000..a3f5ae54 --- /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 00000000..b309e15a --- /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 00000000..dc052da8 --- /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 00000000..7096ce08 --- /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 00000000..c1600496 --- /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 00000000..85910479 --- /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 00000000..1c73154e --- /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/zebra_fec_nexthop_resolution/r5/isisd.conf b/tests/topotests/zebra_fec_nexthop_resolution/r5/isisd.conf new file mode 100644 index 00000000..959d5be2 --- /dev/null +++ b/tests/topotests/zebra_fec_nexthop_resolution/r5/isisd.conf @@ -0,0 +1,26 @@ +! +interface lo + ip router isis 1 + isis hello-interval 1 + isis hello-multiplier 3 + isis passive +exit +! +interface r5-eth0 + 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.5555.00 + lsp-timers gen-interval 1 refresh-interval 900 max-lifetime 1200 + mpls-te on + 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 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 00000000..868129f8 --- /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 00000000..dd519e8d --- /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 00000000..60c4928f --- /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 00000000..5e16e3e4 --- /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 00000000..eeda9d9c --- /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 00000000..f8e56e12 --- /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 00000000..f5202254 --- /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 00000000..984ff3c1 --- /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 00000000..db03ce84 --- /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 00000000..22465cb4 --- /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/r1/ip_route_kernel_blackhole.json b/tests/topotests/zebra_multiple_connected/r1/ip_route_kernel_blackhole.json new file mode 100644 index 00000000..c8ea9303 --- /dev/null +++ b/tests/topotests/zebra_multiple_connected/r1/ip_route_kernel_blackhole.json @@ -0,0 +1,24 @@ +{ + "0.0.0.0/0":[ + { + "prefix":"0.0.0.0/0", + "prefixLen":0, + "protocol":"kernel", + "vrfName":"default", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "nexthops":[ + { + "fib":true, + "unreachable":true, + "blackhole":true, + "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 0b2937c1..eda8c887 100644 --- a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py +++ b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py @@ -15,11 +15,13 @@ test_zebra_multiple_connected.py: Testing multiple connected """ import os -import re 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__)) @@ -29,7 +31,6 @@ sys.path.append(os.path.join(CWD, "../")) # Import topogen and topotest helpers from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger # Required to instantiate the topology builder class. @@ -157,10 +158,71 @@ def test_zebra_noprefix_connected(): test_func = partial( topotest.router_output_cmp, router, "show ip route 192.168.44.0/24", expected ) - result, diff = topotest.run_and_expect(test_func, "", count=20, wait=1) + result, _ = topotest.run_and_expect(test_func, "", count=20, wait=1) 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(_) + + +def test_zebra_kernel_route_blackhole_add(): + "Test that a blackhole route is not affected by interface's link change" + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r1"] + router.run("ip route add blackhole default") + router.run("ip link set dev r1-eth1 down") + + kernel = "{}/{}/ip_route_kernel_blackhole.json".format(CWD, router.name) + expected = json.loads(open(kernel).read()) + + test_func = partial( + topotest.router_json_cmp, router, "show ip route 0.0.0.0/0 json", expected + ) + result, _ = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result, "Blackhole Route should have not been removed\n{}".format(_) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/zebra_netlink/test_zebra_netlink.py b/tests/topotests/zebra_netlink/test_zebra_netlink.py index d970c04e..3748f9c4 100644 --- a/tests/topotests/zebra_netlink/test_zebra_netlink.py +++ b/tests/topotests/zebra_netlink/test_zebra_netlink.py @@ -13,9 +13,7 @@ test_zebra_netlink.py: Test some basic interactions with kernel using Netlink """ # pylint: disable=C0413 import ipaddress -import json import sys -from functools import partial import pytest from lib import topotest @@ -42,7 +40,7 @@ def tgen(request): # Initialize all routers. router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_SHARP) diff --git a/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py index fbef0fef..16e45806 100644 --- a/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py +++ b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py @@ -16,7 +16,6 @@ import sys import pytest from lib.common_config import ( - start_topology, verify_rib, verify_ip_nht, step, @@ -24,7 +23,6 @@ from lib.common_config import ( ) # pylint: disable=C0413 -from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger diff --git a/tests/topotests/zebra_opaque/test_zebra_opaque.py b/tests/topotests/zebra_opaque/test_zebra_opaque.py index 25fbb978..4f49a69b 100644 --- a/tests/topotests/zebra_opaque/test_zebra_opaque.py +++ b/tests/topotests/zebra_opaque/test_zebra_opaque.py @@ -32,7 +32,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -49,7 +49,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -98,17 +98,17 @@ def test_zebra_opaque(): router = tgen.gears["r1"] test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see BGP community aliases "{}"'.format(router) router = tgen.gears["r3"] test_func = functools.partial(_ospf_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see OSPFv2 opaque attributes "{}"'.format(router) router = tgen.gears["r3"] test_func = functools.partial(_ospf6_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see OSPFv3 opaque attributes "{}"'.format(router) diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index 05036fa7..c0a79ed7 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -71,7 +71,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -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()) @@ -235,7 +235,7 @@ def test_route_map_usage(): return topotest.json_cmp(output, expected) test_func = partial(check_initial_routes_installed, r1) - success, result = topotest.run_and_expect(test_func, None, count=40, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=1) static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir) expected = open(static_rmapfile).read().rstrip() diff --git a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py index 4a4cf062..f94b7d4a 100755 --- a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py +++ b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py @@ -80,7 +80,7 @@ def test_zebra_seg6_routes(): expected = open_json_file(os.path.join(CWD, "{}/routes_setup.json".format("r1"))) test_func = partial(check_connected, r1, "2001::/64", expected) - success, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assert result is None, "Failed to fully setup connected routes needed" manifests = open_json_file(os.path.join(CWD, "{}/routes.json".format("r1"))) @@ -96,7 +96,7 @@ def test_zebra_seg6_routes(): ) logger.info("CHECK {} {} {}".format(dest, nh, sid)) test_func = partial(check, r1, dest, manifest["out"]) - success, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assert result is None, "Failed" diff --git a/tests/topotests/zebra_seg6local_route/r1/routes.json b/tests/topotests/zebra_seg6local_route/r1/routes.json index e3919225..7dcc6450 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 0dc87741..59c681df 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))) ) @@ -101,7 +101,7 @@ def test_zebra_seg6local_routes(): dest, manifest["out"], ) - success, result = topotest.run_and_expect(test_func, None, count=25, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=25, wait=1) assert result is None, "Failed" diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl index f52f1a16..2c773f7f 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -4668,6 +4668,7 @@ sub process { # check for new typedefs, only function parameters and sparse annotations # make sense. if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef.*\s(pim_[^\s]+|[^\s]+_pim)\s*;/ && $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && $line !~ /\b$typeTypedefs\b/ && @@ -5149,7 +5150,7 @@ sub process { # none after. May be left adjacent to another # unary operator, or a cast } elsif ($op eq '!' || $op eq '~' || - $opv eq '*U' || $opv eq '-U' || + $opv eq '*U' || $opv eq '-U' || $opv eq '+U' || $opv eq '&U' || $opv eq '&&U') { if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { if (ERROR("SPACING", diff --git a/tools/etc/logrotate.d/frr b/tools/etc/logrotate.d/frr index 735af653..2da55435 100644 --- a/tools/etc/logrotate.d/frr +++ b/tools/etc/logrotate.d/frr @@ -16,7 +16,7 @@ # between file and syslog, rsyslogd might still have file # open, as well as the daemons, so always signal the daemons. # It's safe, a NOP if (only) syslog is being used. - for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd sharpd \ + for i in babeld bgpd eigrpd isisd ldpd mgmtd nhrpd ospf6d ospfd sharpd \ pimd pim6d ripd ripngd zebra pathd pbrd staticd bfdd fabricd vrrpd; do if [ -e /var/run/frr/$i.pid ] ; then pids="$pids $(cat /var/run/frr/$i.pid)" diff --git a/tools/etc/rsyslog.d/45-frr.conf b/tools/etc/rsyslog.d/45-frr.conf index 75b20d76..ef37d66d 100644 --- a/tools/etc/rsyslog.d/45-frr.conf +++ b/tools/etc/rsyslog.d/45-frr.conf @@ -11,6 +11,7 @@ if $programname == 'babeld' or $programname == 'isisd' or $programname == 'fabricd' or $programname == 'ldpd' or + $programname == 'mgmtd' or $programname == 'nhrpd' or $programname == 'ospf6d' or $programname == 'ospfd' or @@ -33,6 +34,7 @@ if $programname == 'babeld' or $programname == 'isisd' or $programname == 'fabricd' or $programname == 'ldpd' or + $programname == 'mgmtd' or $programname == 'nhrpd' or $programname == 'ospf6d' or $programname == 'ospfd' or diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 461f0e8c..08a1f1e0 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -94,7 +94,7 @@ class Vtysh(object): output = self("configure") - if "VTY configuration is locked by other VTY" in output: + if "configuration is locked" in output.lower(): log.error("vtysh 'configure' returned\n%s\n" % (output)) return False @@ -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\S*)", line) + obj = re.match(sub_str + r" (?P\S*)", line) if obj: line = "%s %s" % (sub_str, obj.group("esi").lower()) break @@ -228,7 +228,7 @@ def get_normalized_interface_vrf(line): correctly and configurations are matched appropriately. """ - intf_vrf = re.search("interface (\S+) vrf (\S+)", line) + intf_vrf = re.search(r"interface (\S+) vrf (\S+)", line) if intf_vrf: old_line = "vrf %s" % intf_vrf.group(2) new_line = line.replace(old_line, "").strip() @@ -261,6 +261,8 @@ ctx_keywords = { "router ospf6": {}, "router eigrp ": {}, "router babel": {}, + "router pim": {}, + "router pim6": {}, "mpls ldp": {"address-family ": {"interface ": {}}}, "l2vpn ": {"member pseudowire ": {}}, "key chain ": {"key ": {}}, @@ -306,12 +308,65 @@ class Config(object): file_output = self.vtysh.mark_file(filename) + vrf_context = None + pim_vrfs = [] + for line in file_output.split("\n"): line = line.strip() # Compress duplicate whitespaces line = " ".join(line.split()) + # Detect when we are within a vrf context for converting legacy PIM commands + if vrf_context: + re_vrf = re.match("^(exit-vrf|exit|end)$", line) + if re_vrf: + vrf_context = None + else: + re_vrf = re.match("^vrf ([a-z]+)$", line) + if re_vrf: + vrf_context = re_vrf.group(1) + + # Detect legacy pim commands that need to move under the router pim context + re_pim = re.match( + "^ip(v6)? pim ((ecmp|join|keep|mlag|packets|register|rp|send|spt|ssm).*)$", + line, + ) + if re_pim and re_pim.group(2): + router_pim = "router pim" + if re_pim.group(1): + router_pim += "6" + if vrf_context: + router_pim += " vrf " + vrf_context + + if vrf_context: + pim_vrfs.append(router_pim) + pim_vrfs.append(re_pim.group(2)) + pim_vrfs.append("exit") + line = "# PIM VRF LINE MOVED TO ROUTER PIM" + else: + self.lines.append(router_pim) + self.lines.append(re_pim.group(2)) + line = "exit" + + re_pim = re.match("^ip(v6)? ((ssmpingd|msdp).*)$", line) + if re_pim and re_pim.group(2): + router_pim = "router pim" + if re_pim.group(1): + router_pim += "6" + if vrf_context: + router_pim += " vrf " + vrf_context + + if vrf_context: + pim_vrfs.append(router_pim) + pim_vrfs.append(re_pim.group(2)) + pim_vrfs.append("exit") + line = "# PIM VRF LINE MOVED TO ROUTER PIM" + else: + self.lines.append(router_pim) + self.lines.append(re_pim.group(2)) + line = "exit" + # Remove 'vrf ' from 'interface vrf ' if line.startswith("interface ") and "vrf" in line: line = get_normalized_interface_vrf(line) @@ -348,6 +403,9 @@ class Config(object): self.lines.append(line) + if len(pim_vrfs) > 0: + self.lines.append(pim_vrfs) + self.load_contexts() def load_from_show_running(self, daemon): @@ -813,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 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(), @@ -836,13 +894,13 @@ def bgp_delete_nbr_remote_as_line(lines_to_add): if ctx_keys[0] in pg_dict: for pg_key in pg_dict[ctx_keys[0]]: # Find 'neighbor remote-as' - pg_rmtas = "neighbor %s remote-as (\S+)" % pg_key + pg_rmtas = r"neighbor %s remote-as (\S+)" % pg_key re_pg_rmtas = re.search(pg_rmtas, line) if re_pg_rmtas: pg_dict[ctx_keys[0]][pg_key]["remoteas"] = True # Find 'neighbor [interface] peer-group ' - nb_pg = "neighbor (\S+) peer-group %s$" % pg_key + nb_pg = r"neighbor (\S+) peer-group %s$" % pg_key re_nbr_pg = re.search(nb_pg, line) if ( re_nbr_pg @@ -860,7 +918,7 @@ def bgp_delete_nbr_remote_as_line(lines_to_add): and line and line.startswith("neighbor ") ): - nbr_rmtas = "neighbor (\S+) remote-as.*" + nbr_rmtas = r"neighbor (\S+) remote-as.*" re_nbr_rmtas = re.search(nbr_rmtas, line) if re_nbr_rmtas and ctx_keys[0] in pg_dict: for pg in pg_dict[ctx_keys[0]]: @@ -889,8 +947,8 @@ def bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict): ): if ctx_keys[0] in del_nbr_dict: for nbr in del_nbr_dict[ctx_keys[0]]: - re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line) - nb_exp = "neighbor %s .*" % nbr + re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line) + nb_exp = r"neighbor %s .*" % nbr if not re_nbr_pg: re_nb = re.search(nb_exp, line) if re_nb: @@ -988,7 +1046,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): # neighbor uplink1 interface remote-as internal # # 'no neighbor peer [interface] remote-as <>' - nb_remoteas = "neighbor (\S+) .*remote-as (\S+)" + nb_remoteas = r"neighbor (\S+) .*remote-as (\S+)" re_nb_remoteas = re.search(nb_remoteas, line) if re_nb_remoteas: lines_to_del_to_app.append((ctx_keys, line)) @@ -996,7 +1054,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): # 'no neighbor peer [interface] peer-group <>' is in lines_to_del # copy the neighbor and look for all config removal lines associated # to neighbor and delete them from the lines_to_del - re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line) + re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line) if re_nbr_pg: if ctx_keys[0] not in del_nbr_dict: del_nbr_dict[ctx_keys[0]] = list() @@ -1008,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 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 @@ -1035,7 +1093,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): if ctx_keys[0] in del_dict: for pg_key in del_dict[ctx_keys[0]]: # 'neighbor [interface] peer-group ' - nb_pg = "neighbor (\S+) .*peer-group %s$" % pg_key + nb_pg = r"neighbor (\S+) .*peer-group %s$" % pg_key re_nbr_pg = re.search(nb_pg, line) if ( re_nbr_pg @@ -1053,7 +1111,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): if ctx_keys[0] in del_dict: for pg in del_dict[ctx_keys[0]]: for nbr in del_dict[ctx_keys[0]][pg]: - nb_exp = "neighbor %s .*" % nbr + nb_exp = r"neighbor %s .*" % nbr re_nb = re.search(nb_exp, line) # add peer configs to delete list. if re_nb and line not in lines_to_del_to_del: @@ -1082,32 +1140,37 @@ 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 "): - pim_msdp_peer = re.search("ip msdp peer (\S+) source (\S+)", line) + pim_msdp_peer = re.search(r"ip msdp peer (\S+) source (\S+)", line) if pim_msdp_peer: source_sub_str = "source %s" % pim_msdp_peer.group(2) new_line = line.replace(source_sub_str, "").strip() 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)) @@ -1186,10 +1249,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # # If so then chop the del line and the corresponding add lines re_swpx_int_peergroup = re.search( - "neighbor (\S+) interface peer-group (\S+)", line + r"neighbor (\S+) interface peer-group (\S+)", line ) re_swpx_int_v6only_peergroup = re.search( - "neighbor (\S+) interface v6only peer-group (\S+)", line + r"neighbor (\S+) interface v6only peer-group (\S+)", line ) if re_swpx_int_peergroup or re_swpx_int_v6only_peergroup: @@ -1246,7 +1309,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): if re_nbr_bfd_timers: nbr = re_nbr_bfd_timers.group(1) - bfd_nbr = "neighbor %s" % nbr + bfd_nbr = r"neighbor %s" % nbr bfd_search_string = bfd_nbr + r" bfd (\S+) (\S+) (\S+)" for ctx_keys, add_line in lines_to_add: @@ -1271,13 +1334,13 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # they actually match and if we are going from a very old style # command such that the neighbor command is under the `router # bgp ..` node that we need to handle that appropriately - re_nbr_rm = re.search("neighbor(.*)route-map(.*)(in|out)$", line) + re_nbr_rm = re.search(r"neighbor(.*)route-map(.*)(in|out)$", line) if re_nbr_rm: adjust_for_bgp_node = 0 neighbor_name = re_nbr_rm.group(1) rm_name_del = re_nbr_rm.group(2) dir = re_nbr_rm.group(3) - search = "neighbor%sroute-map(.*)%s" % (neighbor_name, dir) + search = r"neighbor%sroute-map(.*)%s" % (neighbor_name, dir) save_line = "EMPTY" for ctx_keys_al, add_line in lines_to_add: if ctx_keys_al[0].startswith("router bgp"): @@ -1330,10 +1393,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # # If so then chop the del line and the corresponding add lines re_swpx_int_remoteas = re.search( - "neighbor (\S+) interface remote-as (\S+)", line + r"neighbor (\S+) interface remote-as (\S+)", line ) re_swpx_int_v6only_remoteas = re.search( - "neighbor (\S+) interface v6only remote-as (\S+)", line + r"neighbor (\S+) interface v6only remote-as (\S+)", line ) if re_swpx_int_remoteas or re_swpx_int_v6only_remoteas: @@ -1373,7 +1436,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # unnecessary session resets. if "multipath-relax" in line: re_asrelax_new = re.search( - "^bgp\s+bestpath\s+as-path\s+multipath-relax$", line + r"^bgp\s+bestpath\s+as-path\s+multipath-relax$", line ) old_asrelax_cmd = "bgp bestpath as-path multipath-relax no-as-set" found_asrelax_old = line_exist(lines_to_add, ctx_keys, old_asrelax_cmd) @@ -1398,7 +1461,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # the new syntax. This causes an unnecessary 'no import-table' followed # by the same old 'ip import-table' which causes perturbations in # announced routes leading to traffic blackholes. Fix this issue. - re_importtbl = re.search("^ip\s+import-table\s+(\d+)$", ctx_keys[0]) + re_importtbl = re.search(r"^ip\s+import-table\s+(\d+)$", ctx_keys[0]) if re_importtbl: table_num = re_importtbl.group(1) for ctx in lines_to_add: @@ -1419,7 +1482,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # access-list FOO seq 5 permit 2.2.2.2/32 # ipv6 access-list BAR seq 5 permit 2:2:2::2/128 re_acl_pfxlst = re.search( - "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_acl_pfxlst: @@ -1452,7 +1515,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # bgp large-community-list standard llist seq 5 permit 65001:65001:1 # bgp extcommunity-list standard elist seq 5 permit soo 123:123 re_bgp_lists = re.search( - "^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_bgp_lists: @@ -1481,7 +1544,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # Examples: # bgp as-path access-list important_internet_bgp_as_numbers seq 30 permit _40841_" re_bgp_as_path = re.search( - "^(bgp )(as-path )(access-list )(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(bgp )(as-path )(access-list )(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_bgp_as_path: @@ -1511,7 +1574,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): and ctx_keys[2].startswith("vni") ): re_route_target = ( - re.search("^route-target import (.*)$", line) + re.search(r"^route-target import (.*)$", line) if line is not None else False ) @@ -1648,7 +1711,7 @@ def compare_context_objects(newconf, running): pcclist_to_del = [] candidates_to_add = [] delete_bgpd = False - area_stub_no_sum = "area (\S+) stub no-summary" + area_stub_no_sum = r"area (\S+) stub no-summary" deleted_keychains = [] # Find contexts that are in newconf but not in running @@ -1683,9 +1746,11 @@ def compare_context_objects(newconf, running): lines_to_del.append((running_ctx_keys, None)) # We cannot do 'no interface' or 'no vrf' in FRR, and so deal with it - elif running_ctx_keys[0].startswith("interface") or running_ctx_keys[ - 0 - ].startswith("vrf"): + elif ( + running_ctx_keys[0].startswith("interface") + or running_ctx_keys[0].startswith("vrf") + or running_ctx_keys[0].startswith("router pim") + ): for line in running_ctx.lines: lines_to_del.append((running_ctx_keys, line)) diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index a8798113..046dc9e9 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 251643c6..c2e7fd91 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 64ca0bd5..f2ed2332 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 a772b3b5..fd0edcfc 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 c1421ebb..c8b4c897 100644 --- a/vrrpd/vrrp_debug.h +++ b/vrrpd/vrrp_debug.h @@ -27,14 +27,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. * diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index 36494c7d..a2fb2bc3 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 fd6cbc8b..59794d92 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/.gitignore b/vtysh/.gitignore index a6c3d4ab..9cbd248f 100644 --- a/vtysh/.gitignore +++ b/vtysh/.gitignore @@ -1,5 +1,6 @@ vtysh vtysh_cmd.c +vtysh_cmd.*.c # does not exist anymore - remove 2023-10-04 or so extract.pl diff --git a/vtysh/subdir.am b/vtysh/subdir.am index 2eae16d6..d39987eb 100644 --- a/vtysh/subdir.am +++ b/vtysh/subdir.am @@ -17,9 +17,6 @@ vtysh_vtysh_SOURCES = \ vtysh/vtysh_user.c \ vtysh/vtysh_config.c \ # end -nodist_vtysh_vtysh_SOURCES = \ - vtysh/vtysh_cmd.c \ - # end noinst_HEADERS += \ vtysh/vtysh.h \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index b1c957d0..2d80feef 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1161,14 +1161,12 @@ static char **new_completion(const char *text, int start, int end) } /* Vty node structures. */ -#ifdef HAVE_BGPD static struct cmd_node bgp_node = { .name = "bgp", .node = BGP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_BGPD */ static struct cmd_node rip_node = { .name = "rip", @@ -1177,7 +1175,6 @@ static struct cmd_node rip_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_ISISD static struct cmd_node isis_node = { .name = "isis", .node = ISIS_NODE, @@ -1205,16 +1202,13 @@ static struct cmd_node isis_srv6_node_msd_node = { .parent_node = ISIS_SRV6_NODE, .prompt = "%s(config-router-srv6-node-msd)# ", }; -#endif /* HAVE_ISISD */ -#ifdef HAVE_FABRICD static struct cmd_node openfabric_node = { .name = "openfabric", .node = OPENFABRIC_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_FABRICD */ static struct cmd_node interface_node = { .name = "interface", @@ -1237,7 +1231,6 @@ static struct cmd_node segment_routing_node = { .prompt = "%s(config-sr)# ", }; -#if defined(HAVE_PATHD) static struct cmd_node sr_traffic_eng_node = { .name = "sr traffic-eng", .node = SR_TRAFFIC_ENG_NODE, @@ -1293,7 +1286,6 @@ static struct cmd_node pcep_pce_config_node = { .parent_node = PCEP_NODE, .prompt = "%s(pcep-sr-te-pcep-pce-config)# ", }; -#endif /* HAVE_PATHD */ static struct cmd_node vrf_node = { .name = "vrf", @@ -1344,14 +1336,33 @@ static struct cmd_node srv6_encap_node = { .prompt = "%s(config-srv6-encap)# " }; -#ifdef HAVE_PBRD +static struct cmd_node srv6_sid_formats_node = { + .name = "srv6-formats", + .node = SRV6_SID_FORMATS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-formats)# ", +}; + +static struct cmd_node srv6_sid_format_usid_f3216_node = { + .name = "srv6-format-usid-f3216", + .node = SRV6_SID_FORMAT_USID_F3216_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .name = "srv6-format-uncompressed-f4024", + .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + static struct cmd_node pbr_map_node = { .name = "pbr-map", .node = PBRMAP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-pbr-map)# ", }; -#endif /* HAVE_PBRD */ static struct cmd_node zebra_node = { .name = "zebra", @@ -1360,7 +1371,6 @@ static struct cmd_node zebra_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_BGPD static struct cmd_node bgp_vpnv4_node = { .name = "bgp vpnv4", .node = BGP_VPNV4_NODE, @@ -1456,7 +1466,6 @@ static struct cmd_node bgp_ipv6l_node = { .no_xpath = true, }; -#ifdef ENABLE_BGP_VNC static struct cmd_node bgp_vnc_defaults_node = { .name = "bgp vnc defaults", .node = BGP_VNC_DEFAULTS_NODE, @@ -1484,7 +1493,6 @@ static struct cmd_node bgp_vnc_l2_group_node = { .parent_node = BGP_NODE, .prompt = "%s(config-router-vnc-l2-group)# ", }; -#endif /* ENABLE_BGP_VNC */ static struct cmd_node bmp_node = { .name = "bmp", @@ -1499,34 +1507,27 @@ static struct cmd_node bgp_srv6_node = { .parent_node = BGP_NODE, .prompt = "%s(config-router-srv6)# ", }; -#endif /* HAVE_BGPD */ -#ifdef HAVE_OSPFD static struct cmd_node ospf_node = { .name = "ospf", .node = OSPF_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_OSPFD */ -#ifdef HAVE_EIGRPD static struct cmd_node eigrp_node = { .name = "eigrp", .node = EIGRP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_EIGRPD */ -#ifdef HAVE_BABELD static struct cmd_node babel_node = { .name = "babel", .node = BABEL_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_BABELD */ static struct cmd_node ripng_node = { .name = "ripng", @@ -1535,16 +1536,13 @@ static struct cmd_node ripng_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_OSPF6D static struct cmd_node ospf6_node = { .name = "ospf6", .node = OSPF6_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-ospf6)# ", }; -#endif /* HAVE_OSPF6D */ -#ifdef HAVE_LDPD static struct cmd_node ldp_node = { .name = "ldp", .node = LDP_NODE, @@ -1593,7 +1591,6 @@ static struct cmd_node ldp_pseudowire_node = { .parent_node = LDP_L2VPN_NODE, .prompt = "%s(config-l2vpn-pw)# ", }; -#endif /* HAVE_LDPD */ static struct cmd_node keychain_node = { .name = "keychain", @@ -1616,7 +1613,6 @@ struct cmd_node link_params_node = { .prompt = "%s(config-link-params)# ", }; -#ifdef HAVE_BGPD static struct cmd_node rpki_node = { .name = "rpki", .node = RPKI_NODE, @@ -1631,9 +1627,6 @@ static struct cmd_node rpki_vrf_node = { .prompt = "%s(config-vrf-rpki)# ", }; -#endif /* HAVE_BGPD */ - -#if HAVE_BFDD > 0 static struct cmd_node bfd_node = { .name = "bfd", .node = BFD_NODE, @@ -1654,7 +1647,20 @@ static struct cmd_node bfd_profile_node = { .parent_node = BFD_NODE, .prompt = "%s(config-bfd-profile)# ", }; -#endif /* HAVE_BFDD */ + +static struct cmd_node pim_node = { + .name = "pim", + .node = PIM_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim)# ", +}; + +static struct cmd_node pim6_node = { + .name = "pim6", + .node = PIM6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim6)# ", +}; /* Defined in lib/vty.c */ extern struct cmd_node vty_node; @@ -1715,6 +1721,31 @@ DEFUNSH(VTYSH_ZEBRA, srv6_encap, srv6_encap_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, srv6_sid_formats, srv6_sid_formats_cmd, "formats", + "Segment Routing SRv6 SID formats\n") +{ + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f3216_usid, srv6_sid_format_f3216_usid_cmd, + "format usid-f3216", + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + vty->node = SRV6_SID_FORMAT_USID_F3216_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f4024_uncompressed, srv6_sid_format_f4024_uncompressed_cmd, + "format uncompressed-f4024", + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + vty->node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_BGPD DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd, "router bgp [ASNUM [ VIEWVRFNAME] [as-notation ]]", @@ -2367,6 +2398,30 @@ DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd, } #endif /* HAVE_BFDD */ +#ifdef HAVE_PIMD +DEFUNSH(VTYSH_PIMD, router_pim, router_pim_cmd, + "router pim [vrf NAME]", + ROUTER_STR + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + vty->node = PIM_NODE; + return CMD_SUCCESS; +} +#endif /* HAVE_PIMD */ + +#ifdef HAVE_PIM6D +DEFUNSH(VTYSH_PIM6D, router_pim6, router_pim6_cmd, + "router pim6 [vrf NAME]", + ROUTER_STR + "Start PIMv6 configuration\n" + VRF_CMD_HELP_STR) +{ + vty->node = PIM6_NODE; + return CMD_SUCCESS; +} +#endif /* HAVE_PIM6D*/ + DEFUNSH(VTYSH_ALL, vtysh_line_vty, vtysh_line_vty_cmd, "line vty", "Configure a terminal line\n" "Virtual terminal\n") @@ -2515,6 +2570,23 @@ DEFUNSH(VTYSH_ZEBRA, exit_srv6_encap, exit_srv6_encap_cmd, "exit", return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_formats, exit_srv6_sid_formats_cmd, "exit", + "Exit from SRv6 SID formats configuration mode\n") +{ + if (vty->node == SRV6_SID_FORMATS_NODE) + vty->node = SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_format, exit_srv6_sid_format_cmd, + "exit", "Exit from SRv6 SID format configuration mode\n") +{ + if (vty->node == SRV6_SID_FORMAT_USID_F3216_NODE || + vty->node == SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE) + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_RIPD DEFUNSH(VTYSH_MGMTD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, "exit", "Exit current mode and down to previous mode\n") @@ -2763,6 +2835,34 @@ DEFUNSH(VTYSH_PATHD, vtysh_quit_pathd, vtysh_quit_pathd_cmd, "quit", } #endif /* HAVE_PATHD */ +#ifdef HAVE_PIMD +DEFUNSH(VTYSH_PIMD, vtysh_exit_pimd, vtysh_exit_pimd_cmd, "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit(vty); +} + +DEFUNSH(VTYSH_PIMD, vtysh_quit_pimd, vtysh_quit_pimd_cmd, "quit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_pimd(self, vty, argc, argv); +} +#endif /* HAVE_PIMD */ + +#ifdef HAVE_PIM6D +DEFUNSH(VTYSH_PIM6D, vtysh_exit_pim6d, vtysh_exit_pim6d_cmd, "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit(vty); +} + +DEFUNSH(VTYSH_PIM6D, vtysh_quit_pim6d, vtysh_quit_pim6d_cmd, "quit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_pim6d(self, vty, argc, argv); +} +#endif /* HAVE_PIM6D */ + DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit", "Exit current mode and down to previous mode\n") { @@ -2925,9 +3025,6 @@ static int show_one_daemon(struct vty *vty, struct cmd_token **argv, int argc, return ret; } -#if CONFDATE > 20240707 - CPP_NOTICE("Remove `show thread ...` commands") -#endif DEFUN (vtysh_show_event_timer, vtysh_show_event_timer_cmd, "show event timers", @@ -4542,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", @@ -4591,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; @@ -4824,15 +4938,87 @@ void vtysh_init_vty(void) cmd_init(0); cmd_variable_handler_register(vtysh_var_handler); + install_node(&bgp_node); + install_node(&babel_node); + install_node(&bgp_vpnv4_node); + install_node(&bgp_vpnv6_node); + install_node(&bgp_flowspecv4_node); + install_node(&bgp_flowspecv6_node); + install_node(&bgp_ipv4_node); + install_node(&bgp_ipv4m_node); + install_node(&bgp_ipv4l_node); + install_node(&bgp_ipv6_node); + install_node(&bgp_ipv6m_node); + install_node(&bgp_ipv6l_node); + install_node(&bgp_vrf_policy_node); + install_node(&bgp_vnc_defaults_node); + install_node(&bgp_vnc_nve_group_node); + install_node(&bgp_vnc_l2_group_node); + install_node(&bgp_evpn_node); + install_node(&bgp_evpn_vni_node); + install_node(&rpki_node); + install_node(&bmp_node); + install_node(&bgp_srv6_node); + install_node(&rip_node); + install_node(&ripng_node); + install_node(&ospf_node); + install_node(&ospf6_node); + install_node(&ldp_node); + install_node(&ldp_ipv4_node); + install_node(&ldp_ipv6_node); + install_node(&ldp_ipv4_iface_node); + install_node(&ldp_ipv6_iface_node); + install_node(&ldp_l2vpn_node); + install_node(&ldp_pseudowire_node); + install_node(&eigrp_node); + install_node(&isis_node); + install_node(&isis_flex_algo_node); + install_node(&isis_srv6_node); + install_node(&isis_srv6_node_msd_node); + install_node(&openfabric_node); + install_node(&pbr_map_node); + install_node(&bfd_node); + install_node(&bfd_peer_node); + install_node(&bfd_profile_node); + install_node(&segment_routing_node); + install_node(&sr_traffic_eng_node); + install_node(&srte_segment_list_node); + install_node(&srte_policy_node); + install_node(&srte_candidate_dyn_node); + install_node(&pcep_node); + install_node(&pcep_pcc_node); + install_node(&pcep_pce_node); + install_node(&pcep_pce_config_node); + install_node(&keychain_node); + install_node(&keychain_key_node); + install_node(&nh_group_node); + install_node(&zebra_node); + install_node(&interface_node); + install_node(&pim_node); + install_node(&pim6_node); + install_node(&link_params_node); + install_node(&pw_node); + install_node(&vrf_node); + install_node(&rpki_vrf_node); + install_node(&rmap_node); + install_node(&vty_node); + install_node(&srv6_node); + install_node(&srv6_locs_node); + install_node(&srv6_loc_node); + install_node(&srv6_encap_node); + install_node(&srv6_sid_formats_node); + install_node(&srv6_sid_format_usid_f3216_node); + install_node(&srv6_sid_format_uncompressed_f4024_node); + + vtysh_init_cmd(); + /* bgpd */ #ifdef HAVE_BGPD - install_node(&bgp_node); install_element(CONFIG_NODE, &router_bgp_cmd); install_element(BGP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_NODE, &vtysh_end_all_cmd); - install_node(&bgp_vpnv4_node); install_element(BGP_NODE, &address_family_ipv4_vpn_cmd); #ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv4_cmd); @@ -4842,7 +5028,6 @@ void vtysh_init_vty(void) install_element(BGP_VPNV4_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV4_NODE, &exit_address_family_cmd); - install_node(&bgp_vpnv6_node); install_element(BGP_NODE, &address_family_ipv6_vpn_cmd); #ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv6_cmd); @@ -4852,56 +5037,48 @@ void vtysh_init_vty(void) install_element(BGP_VPNV6_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV6_NODE, &exit_address_family_cmd); - install_node(&bgp_flowspecv4_node); install_element(BGP_NODE, &address_family_flowspecv4_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_end_all_cmd); install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); - install_node(&bgp_flowspecv6_node); install_element(BGP_NODE, &address_family_flowspecv6_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_end_all_cmd); install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4_node); install_element(BGP_NODE, &address_family_ipv4_cmd); install_element(BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4m_node); install_element(BGP_NODE, &address_family_ipv4_multicast_cmd); install_element(BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4M_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4M_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4l_node); install_element(BGP_NODE, &address_family_ipv4_labeled_unicast_cmd); install_element(BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4L_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4L_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6_node); install_element(BGP_NODE, &address_family_ipv6_cmd); install_element(BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6m_node); install_element(BGP_NODE, &address_family_ipv6_multicast_cmd); install_element(BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV6M_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6M_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6l_node); install_element(BGP_NODE, &address_family_ipv6_labeled_unicast_cmd); install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd); @@ -4909,28 +5086,24 @@ void vtysh_init_vty(void) install_element(BGP_IPV6L_NODE, &exit_address_family_cmd); #if defined(ENABLE_BGP_VNC) - install_node(&bgp_vrf_policy_node); install_element(BGP_NODE, &vnc_vrf_policy_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd); install_element(BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); - install_node(&bgp_vnc_defaults_node); install_element(BGP_NODE, &vnc_defaults_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd); - install_node(&bgp_vnc_nve_group_node); install_element(BGP_NODE, &vnc_nve_group_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd); - install_node(&bgp_vnc_l2_group_node); install_element(BGP_NODE, &vnc_l2_group_cmd); install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_quit_bgpd_cmd); @@ -4938,33 +5111,28 @@ void vtysh_init_vty(void) install_element(BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd); #endif - install_node(&bgp_evpn_node); install_element(BGP_NODE, &address_family_evpn_cmd); install_element(BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_EVPN_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_NODE, &exit_address_family_cmd); - install_node(&bgp_evpn_vni_node); install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd); - install_node(&rpki_node); install_element(CONFIG_NODE, &rpki_cmd); install_element(RPKI_NODE, &rpki_exit_cmd); install_element(RPKI_NODE, &rpki_quit_cmd); install_element(RPKI_NODE, &vtysh_end_all_cmd); - install_node(&bmp_node); install_element(BGP_NODE, &bmp_targets_cmd); install_element(BMP_NODE, &bmp_exit_cmd); install_element(BMP_NODE, &bmp_quit_cmd); install_element(BMP_NODE, &vtysh_end_all_cmd); - install_node(&bgp_srv6_node); install_element(BGP_NODE, &bgp_srv6_cmd); install_element(BGP_SRV6_NODE, &exit_bgp_srv6_cmd); install_element(BGP_SRV6_NODE, &quit_bgp_srv6_cmd); @@ -4972,7 +5140,6 @@ void vtysh_init_vty(void) #endif /* HAVE_BGPD */ /* ripd */ - install_node(&rip_node); #ifdef HAVE_RIPD install_element(CONFIG_NODE, &router_rip_cmd); install_element(RIP_NODE, &vtysh_exit_ripd_cmd); @@ -4981,7 +5148,6 @@ void vtysh_init_vty(void) #endif /* HAVE_RIPD */ /* ripngd */ - install_node(&ripng_node); #ifdef HAVE_RIPNGD install_element(CONFIG_NODE, &router_ripng_cmd); install_element(RIPNG_NODE, &vtysh_exit_ripngd_cmd); @@ -4991,7 +5157,6 @@ void vtysh_init_vty(void) /* ospfd */ #ifdef HAVE_OSPFD - install_node(&ospf_node); install_element(CONFIG_NODE, &router_ospf_cmd); install_element(OSPF_NODE, &vtysh_exit_ospfd_cmd); install_element(OSPF_NODE, &vtysh_quit_ospfd_cmd); @@ -5000,7 +5165,6 @@ void vtysh_init_vty(void) /* ospf6d */ #ifdef HAVE_OSPF6D - install_node(&ospf6_node); install_element(CONFIG_NODE, &router_ospf6_cmd); install_element(OSPF6_NODE, &vtysh_exit_ospf6d_cmd); install_element(OSPF6_NODE, &vtysh_quit_ospf6d_cmd); @@ -5009,45 +5173,38 @@ void vtysh_init_vty(void) /* ldpd */ #if defined(HAVE_LDPD) - install_node(&ldp_node); install_element(CONFIG_NODE, &ldp_mpls_ldp_cmd); install_element(LDP_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv4_node); install_element(LDP_NODE, &ldp_address_family_ipv4_cmd); install_element(LDP_IPV4_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV4_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV4_NODE, &ldp_exit_address_family_cmd); install_element(LDP_IPV4_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv6_node); install_element(LDP_NODE, &ldp_address_family_ipv6_cmd); install_element(LDP_IPV6_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV6_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd); install_element(LDP_IPV6_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv4_iface_node); install_element(LDP_IPV4_NODE, &ldp_interface_ifname_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv6_iface_node); install_element(LDP_IPV6_NODE, &ldp_interface_ifname_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_end_all_cmd); - install_node(&ldp_l2vpn_node); install_element(CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd); install_element(LDP_L2VPN_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_L2VPN_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_L2VPN_NODE, &vtysh_end_all_cmd); - install_node(&ldp_pseudowire_node); install_element(LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd); install_element(LDP_PSEUDOWIRE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_PSEUDOWIRE_NODE, &vtysh_quit_ldpd_cmd); @@ -5056,7 +5213,6 @@ void vtysh_init_vty(void) /* eigrpd */ #ifdef HAVE_EIGRPD - install_node(&eigrp_node); install_element(CONFIG_NODE, &router_eigrp_cmd); install_element(EIGRP_NODE, &vtysh_exit_eigrpd_cmd); install_element(EIGRP_NODE, &vtysh_quit_eigrpd_cmd); @@ -5065,7 +5221,6 @@ void vtysh_init_vty(void) /* babeld */ #ifdef HAVE_BABELD - install_node(&babel_node); install_element(CONFIG_NODE, &router_babel_cmd); install_element(BABEL_NODE, &vtysh_exit_babeld_cmd); install_element(BABEL_NODE, &vtysh_quit_babeld_cmd); @@ -5074,25 +5229,21 @@ void vtysh_init_vty(void) /* isisd */ #ifdef HAVE_ISISD - install_node(&isis_node); install_element(CONFIG_NODE, &router_isis_cmd); install_element(ISIS_NODE, &vtysh_exit_isisd_cmd); install_element(ISIS_NODE, &vtysh_quit_isisd_cmd); install_element(ISIS_NODE, &vtysh_end_all_cmd); - install_node(&isis_flex_algo_node); install_element(ISIS_NODE, &isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_exit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_quit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_end_all_cmd); - install_node(&isis_srv6_node); install_element(ISIS_NODE, &isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &isis_srv6_node_msd_cmd); install_element(ISIS_SRV6_NODE, &vtysh_exit_isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &vtysh_quit_isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &vtysh_end_all_cmd); - install_node(&isis_srv6_node_msd_node); install_element(ISIS_SRV6_NODE_MSD_NODE, &vtysh_exit_isis_srv6_node_msd_cmd); install_element(ISIS_SRV6_NODE_MSD_NODE, @@ -5102,7 +5253,6 @@ void vtysh_init_vty(void) /* fabricd */ #ifdef HAVE_FABRICD - install_node(&openfabric_node); install_element(CONFIG_NODE, &router_openfabric_cmd); install_element(OPENFABRIC_NODE, &vtysh_exit_fabricd_cmd); install_element(OPENFABRIC_NODE, &vtysh_quit_fabricd_cmd); @@ -5111,7 +5261,6 @@ void vtysh_init_vty(void) /* pbrd */ #ifdef HAVE_PBRD - install_node(&pbr_map_node); install_element(CONFIG_NODE, &vtysh_pbr_map_cmd); install_element(CONFIG_NODE, &vtysh_no_pbr_map_cmd); install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd); @@ -5121,37 +5270,28 @@ void vtysh_init_vty(void) /* bfdd */ #if HAVE_BFDD > 0 - install_node(&bfd_node); install_element(CONFIG_NODE, &bfd_enter_cmd); install_element(BFD_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_NODE, &vtysh_end_all_cmd); - install_node(&bfd_peer_node); install_element(BFD_NODE, &bfd_peer_enter_cmd); install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_end_all_cmd); - install_node(&bfd_profile_node); install_element(BFD_NODE, &bfd_profile_enter_cmd); install_element(BFD_PROFILE_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_PROFILE_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd); #endif /* HAVE_BFDD */ - install_node(&segment_routing_node); install_element(CONFIG_NODE, &segment_routing_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd); #if defined(HAVE_PATHD) - install_node(&sr_traffic_eng_node); - install_node(&srte_segment_list_node); - install_node(&srte_policy_node); - install_node(&srte_candidate_dyn_node); - install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd); install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd); install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd); @@ -5172,11 +5312,6 @@ void vtysh_init_vty(void) install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd); install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_path_cmd); - install_node(&pcep_node); - install_node(&pcep_pcc_node); - install_node(&pcep_pce_node); - install_node(&pcep_pce_config_node); - install_element(PCEP_NODE, &vtysh_exit_pathd_cmd); install_element(PCEP_NODE, &vtysh_quit_pathd_cmd); install_element(PCEP_PCC_NODE, &vtysh_exit_pathd_cmd); @@ -5199,14 +5334,12 @@ void vtysh_init_vty(void) #endif /* HAVE_PATHD */ /* keychain */ - install_node(&keychain_node); install_element(CONFIG_NODE, &key_chain_cmd); install_element(KEYCHAIN_NODE, &key_chain_cmd); install_element(KEYCHAIN_NODE, &vtysh_exit_keys_cmd); install_element(KEYCHAIN_NODE, &vtysh_quit_keys_cmd); install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd); - install_node(&keychain_key_node); install_element(KEYCHAIN_NODE, &key_cmd); install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd); install_element(KEYCHAIN_KEY_NODE, &vtysh_exit_keys_cmd); @@ -5214,7 +5347,6 @@ void vtysh_init_vty(void) install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd); /* nexthop-group */ - install_node(&nh_group_node); install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd); install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd); install_element(NH_GROUP_NODE, &vtysh_end_all_cmd); @@ -5222,15 +5354,27 @@ void vtysh_init_vty(void) install_element(NH_GROUP_NODE, &vtysh_quit_nexthop_group_cmd); /* zebra and all */ - install_node(&zebra_node); - - install_node(&interface_node); install_element(CONFIG_NODE, &vtysh_interface_cmd); install_element(INTERFACE_NODE, &vtysh_end_all_cmd); install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd); install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd); - install_node(&link_params_node); + /* pimd */ +#ifdef HAVE_PIMD + install_element(CONFIG_NODE, &router_pim_cmd); + install_element(PIM_NODE, &vtysh_exit_pimd_cmd); + install_element(PIM_NODE, &vtysh_quit_pimd_cmd); + install_element(PIM_NODE, &vtysh_end_all_cmd); +#endif /* HAVE_PIMD */ + + /* pim6d */ +#ifdef HAVE_PIM6D + install_element(CONFIG_NODE, &router_pim6_cmd); + install_element(PIM6_NODE, &vtysh_exit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_quit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_end_all_cmd); +#endif /* HAVE_PIM6D */ + install_element(INTERFACE_NODE, &vtysh_link_params_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); @@ -5238,13 +5382,11 @@ void vtysh_init_vty(void) install_element(LINK_PARAMS_NODE, &vtysh_exit_link_params_cmd); install_element(LINK_PARAMS_NODE, &vtysh_quit_link_params_cmd); - install_node(&pw_node); install_element(CONFIG_NODE, &vtysh_pseudowire_cmd); install_element(PW_NODE, &vtysh_end_all_cmd); install_element(PW_NODE, &vtysh_exit_pseudowire_cmd); install_element(PW_NODE, &vtysh_quit_pseudowire_cmd); - install_node(&vrf_node); install_element(CONFIG_NODE, &vtysh_vrf_cmd); install_element(VRF_NODE, &exit_vrf_config_cmd); install_element(VRF_NODE, &vtysh_end_all_cmd); @@ -5252,7 +5394,6 @@ void vtysh_init_vty(void) install_element(VRF_NODE, &vtysh_quit_vrf_cmd); #ifdef HAVE_BGPD - install_node(&rpki_vrf_node); install_element(VRF_NODE, &rpki_cmd); install_element(RPKI_VRF_NODE, &rpki_exit_cmd); install_element(RPKI_VRF_NODE, &rpki_quit_cmd); @@ -5262,13 +5403,11 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &vtysh_affinity_map_cmd); install_element(CONFIG_NODE, &vtysh_no_affinity_map_cmd); - install_node(&rmap_node); install_element(CONFIG_NODE, &vtysh_route_map_cmd); install_element(RMAP_NODE, &vtysh_exit_rmap_cmd); install_element(RMAP_NODE, &vtysh_quit_rmap_cmd); install_element(RMAP_NODE, &vtysh_end_all_cmd); - install_node(&vty_node); install_element(CONFIG_NODE, &vtysh_line_vty_cmd); install_element(VTY_NODE, &vtysh_exit_line_vty_cmd); install_element(VTY_NODE, &vtysh_quit_line_vty_cmd); @@ -5301,26 +5440,38 @@ void vtysh_init_vty(void) install_element(ENABLE_NODE, &vtysh_end_all_cmd); /* SRv6 Data-plane */ - install_node(&srv6_node); install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); + install_element(SRV6_NODE, &srv6_sid_formats_cmd); install_element(SRV6_NODE, &exit_srv6_config_cmd); install_element(SRV6_NODE, &vtysh_end_all_cmd); install_element(SRV6_NODE, &srv6_encap_cmd); - install_node(&srv6_locs_node); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &exit_srv6_locs_config_cmd); install_element(SRV6_LOCS_NODE, &vtysh_end_all_cmd); - install_node(&srv6_loc_node); install_element(SRV6_LOC_NODE, &exit_srv6_loc_config_cmd); install_element(SRV6_LOC_NODE, &vtysh_end_all_cmd); - install_node(&srv6_encap_node); install_element(SRV6_ENCAP_NODE, &exit_srv6_encap_cmd); install_element(SRV6_ENCAP_NODE, &vtysh_end_all_cmd); + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_f4024_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, &exit_srv6_sid_formats_cmd); + install_element(SRV6_SID_FORMATS_NODE, &vtysh_end_all_cmd); + + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, &vtysh_end_all_cmd); + + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &vtysh_end_all_cmd); + install_element(ENABLE_NODE, &vtysh_show_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index b1d57aa3..3c532b99 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 c207e4d4..6536e1b3 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 @@ -497,6 +487,11 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(BFD_NODE, line); else if (strncmp(line, "rpki", strlen("rpki")) == 0) config = config_get(RPKI_NODE, line); + else if (strncmp(line, "router pim", strlen("router pim")) == 0) + config = config_get(PIM_NODE, line); + else if (strncmp(line, "router pim6", strlen("router pim6")) == + 0) + config = config_get(PIM6_NODE, line); else { if (strncmp(line, "log", strlen("log")) == 0 || strncmp(line, "hostname", strlen("hostname")) == 0 || @@ -532,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/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 464d82cf..64198132 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -489,7 +489,6 @@ int main(int argc, char **argv, char **env) /* Make vty structure and register commands. */ vtysh_init_vty(); - vtysh_init_cmd(); vtysh_user_init(); vtysh_config_init(); diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang index ffba42b5..02ed9214 100644 --- a/yang/frr-bfdd.yang +++ b/yang/frr-bfdd.yang @@ -16,9 +16,6 @@ module frr-bfdd { import frr-vrf { prefix frr-vrf; } - import frr-route-types { - prefix frr-route-types; - } organization "FRRouting"; contact diff --git a/yang/frr-bgp-common.yang b/yang/frr-bgp-common.yang index 2b1babdd..9d215973 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 abfb14c2..44058ab0 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-eigrpd.yang b/yang/frr-eigrpd.yang index f672dd55..d3d9db2f 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -75,7 +75,7 @@ module frr-eigrpd { typedef autonomous-system { description "Administrative domain identification for a network"; type uint16 { - range 1..65535; + range "1..65535"; } } diff --git a/yang/frr-gmp.yang b/yang/frr-gmp.yang index c8a05a2b..5636010d 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-isisd.yang b/yang/frr-isisd.yang index d1a08fa9..a3e073f6 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -685,7 +685,7 @@ module frr-isisd { type uint32 { range "0..16777215"; } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide' or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style)"; + must ". < 64 or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style) or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style != 'narrow'"; default "10"; description "Default level-1 metric for this IS-IS circuit."; @@ -695,7 +695,7 @@ module frr-isisd { type uint32 { range "0..16777215"; } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide' or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style)"; + must ". < 64 or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style) or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style != 'narrow'"; default "10"; description "Default level-2 metric for this IS-IS circuit."; @@ -1922,7 +1922,7 @@ module frr-isisd { if set to disable, ISISEXPLICITNULLFlag will override the value of ISISPHPFlag"; leaf algo { - type uint32 { + type uint8 { range "128..255"; } description diff --git a/yang/frr-pim-candidate.yang b/yang/frr-pim-candidate.yang new file mode 100644 index 00000000..09d0a063 --- /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: + FRR Development List: "; + + 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 4cc21413..dbd5513e 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-pim.yang b/yang/frr-pim.yang index 732a38a9..6a6c5218 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -5,6 +5,10 @@ module frr-pim { prefix frr-pim; + import frr-filter { + prefix frr-filter; + } + import frr-interface { prefix frr-interface; } @@ -118,6 +122,37 @@ module frr-pim { } } + grouping msdp-authentication { + description + "MSDP authentication options."; + + leaf authentication-type { + type enumeration { + enum None { + value 0; + description + "No authentication."; + } + enum MD5 { + value 1; + description + "Use MD5 digest."; + } + } + default None; + description + "Authentication method."; + } + + leaf authentication-key { + when "../authentication-type = 'MD5'"; + mandatory true; + type string; + description + "Authentication key."; + } + } + grouping global-pim-config-attributes { description "A grouping defining per address family pim global attributes"; @@ -267,6 +302,20 @@ module frr-pim { description "MSDP source IP address."; } + + leaf sa-filter-in { + type frr-filter:access-list-name; + description + "Access list name used to filter the incoming SAs exchanged."; + } + + leaf sa-filter-out { + type frr-filter:access-list-name; + description + "Access list name used to filter the outgoing SAs exchanged."; + } + + uses msdp-authentication; } container mlag { diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index 26d56acc..c875a6ec 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -360,16 +360,16 @@ module frr-route-map { case set-min-metric { when "derived-from-or-self(../action, 'set-min-metric')"; - choice minimun-metric-value { + choice minimum-metric-value { description - "Mimimum metric to set or use"; + "Minimum metric to set or use"; case min-metric { leaf min-metric { type uint32 { range "0..4294967295"; } description - "Use the following mimumn metric value"; + "Use the following minimum metric value"; } } } diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index 79c524a4..f97a4cc1 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -626,6 +626,7 @@ module frr-zebra { leaf table-id { type uint32; + default "254"; description "Routing Table id (default id - 254)."; } @@ -2855,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 9c7a6af7..ed64b78a 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: - // 2 octects + // 2 octets // 6 octets type union { diff --git a/yang/subdir.am b/yang/subdir.am index 71aa0408..786bd0bc 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 404f892f..ce26c14c 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -176,6 +176,40 @@ static void connected_update(struct interface *ifp, struct connected *ifc) connected_announce(ifp, ifc); } +/* + * This function goes through and handles the deletion of a kernel route that happened + * to be the exact same as the connected route, so that the connected route wins. + * This can happen during processing if we happen to receive events in a slightly + * unexpected order. This is similiar to code in the other direction where if we + * have a kernel route don't install it if it perfectly matches a connected route. + */ +static void connected_remove_kernel_for_connected(afi_t afi, safi_t safi, struct zebra_vrf *zvrf, + struct prefix *p, struct nexthop *nh) +{ + struct route_node *rn; + struct route_entry *re; + rib_dest_t *dest; + struct route_table *table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf->vrf->vrf_id); + + rn = route_node_match(table, p); + if (!rn) + return; + + if (!prefix_same(&rn->p, p)) + return; + + dest = rib_dest_from_rnode(rn); + if (!dest || !dest->selected_fib) + return; + + re = dest->selected_fib; + if (re->type != ZEBRA_ROUTE_KERNEL) + return; + + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_KERNEL, 0, 0, p, NULL, nh, 0, + zvrf->table_id, 0, 0, false); +} + /* Called from if_up(). */ void connected_up(struct interface *ifp, struct connected *ifc) { @@ -185,6 +219,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; @@ -283,10 +318,13 @@ void connected_up(struct interface *ifp, struct connected *ifc) } if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + connected_remove_kernel_for_connected(afi, SAFI_UNICAST, zvrf, &p, &nh); + rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, false); + connected_remove_kernel_for_connected(afi, SAFI_MULTICAST, zvrf, &p, &nh); rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, false); diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 9ad92d62..c12a569f 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -36,13 +36,11 @@ #include "zebra/zebra_dplane.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_router.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_evpn.h" #include "zebra/zebra_evpn_mac.h" #include "zebra/kernel_netlink.h" #include "zebra/rt_netlink.h" -#include "zebra/debug.h" #include "fpm/fpm.h" #include "zebra/dplane_fpm_nl_clippy.c" @@ -136,8 +134,6 @@ struct fpm_nl_ctx { /* Amount of data plane context processed. */ _Atomic uint32_t dplane_contexts; - /* Amount of data plane contexts enqueued. */ - _Atomic uint32_t ctxqueue_len; /* Peak amount of data plane contexts enqueued. */ _Atomic uint32_t ctxqueue_len_peak; @@ -385,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); } @@ -399,6 +395,12 @@ DEFUN(fpm_show_counters, fpm_show_counters_cmd, FPM_STR "FPM statistic counters\n") { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + vty_out(vty, "%30s\n%30s\n", "FPM counters", "============"); #define SHOW_COUNTER(label, counter) \ @@ -412,8 +414,7 @@ DEFUN(fpm_show_counters, fpm_show_counters_cmd, SHOW_COUNTER("Connection errors", gfnc->counters.connection_errors); SHOW_COUNTER("Data plane items processed", gfnc->counters.dplane_contexts); - SHOW_COUNTER("Data plane items enqueued", - gfnc->counters.ctxqueue_len); + SHOW_COUNTER("Data plane items enqueued", curr_queue_len); SHOW_COUNTER("Data plane items queue peak", gfnc->counters.ctxqueue_len_peak); SHOW_COUNTER("Buffer full hits", gfnc->counters.buffer_full); @@ -432,6 +433,12 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, "FPM statistic counters\n" JSON_STR) { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + struct json_object *jo; jo = json_object_new_object(); @@ -445,8 +452,7 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, gfnc->counters.connection_errors); json_object_int_add(jo, "data-plane-contexts", gfnc->counters.dplane_contexts); - json_object_int_add(jo, "data-plane-contexts-queue", - gfnc->counters.ctxqueue_len); + json_object_int_add(jo, "data-plane-contexts-queue", curr_queue_len); json_object_int_add(jo, "data-plane-contexts-queue-peak", gfnc->counters.ctxqueue_len_peak); json_object_int_add(jo, "buffer-full-hits", gfnc->counters.buffer_full); @@ -1330,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) @@ -1495,8 +1501,6 @@ static void fpm_process_queue(struct event *t) /* Account the processed entries. */ processed_contexts++; - atomic_fetch_sub_explicit(&fnc->counters.ctxqueue_len, 1, - memory_order_relaxed); dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); dplane_provider_enqueue_out_ctx(fnc->prov, ctx); @@ -1670,10 +1674,29 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) struct zebra_dplane_ctx *ctx; struct fpm_nl_ctx *fnc; int counter, limit; - uint64_t cur_queue, peak_queue = 0, stored_peak_queue; + uint64_t cur_queue = 0, peak_queue = 0, stored_peak_queue; 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) @@ -1684,25 +1707,27 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) * anyway. */ if (fnc->socket != -1 && fnc->connecting == false) { + enum dplane_op_e op = dplane_ctx_get_op(ctx); + /* - * Update the number of queued contexts *before* - * enqueueing, to ensure counter consistency. + * Just skip multicast routes and let them flow through */ - atomic_fetch_add_explicit(&fnc->counters.ctxqueue_len, - 1, memory_order_relaxed); + if ((op == DPLANE_OP_ROUTE_DELETE || op == DPLANE_OP_ROUTE_INSTALL || + op == DPLANE_OP_ROUTE_UPDATE) && + dplane_ctx_get_safi(ctx) == SAFI_MULTICAST) + goto skip; frr_with_mutex (&fnc->ctxqueue_mutex) { dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx); + cur_queue = + dplane_ctx_queue_count(&fnc->ctxqueue); } - cur_queue = atomic_load_explicit( - &fnc->counters.ctxqueue_len, - memory_order_relaxed); if (peak_queue < cur_queue) peak_queue = cur_queue; continue; } - +skip: dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); dplane_provider_enqueue_out_ctx(prov, ctx); } @@ -1714,9 +1739,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) atomic_store_explicit(&fnc->counters.ctxqueue_len_peak, peak_queue, memory_order_relaxed); - if (atomic_load_explicit(&fnc->counters.ctxqueue_len, - memory_order_relaxed) - > 0) + if (cur_queue > 0) event_add_event(fnc->fthread->master, fpm_process_queue, fnc, 0, &fnc->t_dequeue); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index d0aa2167..688a7f6e 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 32335198..8beae125 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 9b31906a..dc1f71cb 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 9db95989..28cbb041 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 b3adc448..d1460047 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -32,7 +32,6 @@ #include "zebra/zebra_ptm.h" #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_evpn_mh.h" @@ -1059,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 d2f1db67..84aabc42 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 e37bba0c..9db4e578 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 d50e7de2..5cfbe7a8 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/main.c b/zebra/main.c index ea1e1cbd..4d9b7c3b 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -65,8 +65,6 @@ struct mgmt_be_client *mgmt_be_client; /* Route retain mode flag. */ int retain_mode = 0; -int graceful_restart; - /* Receive buffer size for kernel control sockets */ #define RCVBUFSIZE_MIN 4194304 #ifdef HAVE_NETLINK @@ -88,7 +86,6 @@ const struct option longopts[] = { { "socket", required_argument, NULL, 'z' }, { "ecmp", required_argument, NULL, 'e' }, { "retain", no_argument, NULL, 'r' }, - { "graceful_restart", required_argument, NULL, 'K' }, { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, { "v6-with-v4-nexthops", no_argument, NULL, OPTION_V6_WITH_V4_NEXTHOP }, #ifdef HAVE_NETLINK @@ -96,7 +93,7 @@ const struct option longopts[] = { { "nl-bufsize", required_argument, NULL, 's' }, { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - {"routing-table", optional_argument, NULL, 'R'}, + { "routing-table", optional_argument, NULL, 'R' }, { 0 } }; @@ -241,7 +238,7 @@ void zebra_finalize(struct event *dummy) zebra_ns_notify_close(); /* Final shutdown of ns resources */ - ns_walk_func(zebra_ns_final_shutdown, NULL, NULL); + ns_walk_func(zebra_ns_kernel_shutdown, NULL, NULL); zebra_rib_terminate(); zebra_router_terminate(); @@ -254,6 +251,8 @@ void zebra_finalize(struct event *dummy) label_manager_terminate(); + ns_walk_func(zebra_ns_final_shutdown, NULL, NULL); + ns_terminate(); frr_fini(); exit(0); @@ -326,7 +325,6 @@ int main(int argc, char **argv) bool v6_with_v4_nexthop = false; bool notify_on_ack = true; - graceful_restart = 0; vrf_configure_backend(VRF_BACKEND_VRF_LITE); frr_preinit(&zebra_di, argc, argv); @@ -342,9 +340,8 @@ int main(int argc, char **argv) " -z, --socket Set path of zebra socket\n" " -e, --ecmp Specify ECMP to use.\n" " -r, --retain When program terminates, retain added route by zebra.\n" - " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" - " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops" + " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops\n" #ifdef HAVE_NETLINK " -s, --nl-bufsize Set netlink receive buffer size\n" " -n, --vrfwnetns Use NetNS as VRF backend\n" @@ -352,8 +349,7 @@ int main(int argc, char **argv) #else " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ - " -R, --routing-table Set kernel routing table\n" - ); + " -R, --routing-table Set kernel routing table\n"); while (1) { int opt = frr_getopt(argc, argv, NULL); @@ -397,9 +393,6 @@ int main(int argc, char **argv) case 'r': retain_mode = 1; break; - case 'K': - graceful_restart = atoi(optarg); - break; case 's': rcvbufsize = atoi(optarg); if (rcvbufsize < RCVBUFSIZE_MIN) @@ -488,11 +481,25 @@ int main(int argc, char **argv) * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, - * we have to have route_read() called before. + * we have to have route_read() called before. + * If FRR is gracefully restarting, we either wait for clients + * (e.g., BGP) to signal GR is complete else we wait for specified + * duration. */ zrouter.startup_time = monotime(NULL); - event_add_timer(zrouter.master, rib_sweep_route, NULL, graceful_restart, - &zrouter.sweeper); + zrouter.rib_sweep_time = 0; + zrouter.graceful_restart = zebra_di.graceful_restart; + if (!zrouter.graceful_restart) + event_add_timer(zrouter.master, rib_sweep_route, NULL, 0, NULL); + else { + int gr_cleanup_time; + + gr_cleanup_time = zebra_di.gr_cleanup_time + ? zebra_di.gr_cleanup_time + : ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME; + event_add_timer(zrouter.master, rib_sweep_route, NULL, + gr_cleanup_time, &zrouter.t_rib_sweep); + } /* Needed for BSD routing socket. */ pid = getpid(); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 11c13303..2de0917a 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 a721f4ba..5fedb073 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 * @@ -622,17 +622,22 @@ static inline struct nexthop_group *rib_get_fib_backup_nhg( } extern void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + 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 01b527ea..ab07ef8d 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; @@ -591,12 +591,9 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, return nh; } -static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, - struct nexthop_group *ng, - struct rtmsg *rtm, - struct rtnexthop *rtnh, - struct rtattr **tb, - void *prefsrc, vrf_id_t vrf_id) +static uint16_t parse_multipath_nexthops_unicast(ns_id_t ns_id, struct nexthop_group *ng, + struct rtmsg *rtm, struct rtnexthop *rtnh, + struct rtattr **tb, void *prefsrc, vrf_id_t vrf_id) { void *gate = NULL; struct interface *ifp = NULL; @@ -721,7 +718,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, rtnh = RTNH_NEXT(rtnh); } - uint8_t nhop_num = nexthop_group_nexthop_num(ng); + uint16_t nhop_num = nexthop_group_nexthop_num(ng); return nhop_num; } @@ -799,8 +796,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); @@ -1002,7 +997,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); if (!nhe_id) { - uint8_t nhop_num; + uint16_t nhop_num; /* Use temporary list of nexthops; parse * message payload's nexthops. @@ -1040,7 +1035,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, zlog_err( "%s: %pFX multipath RTM_NEWROUTE has a invalid nexthop group from the kernel", __func__, &p); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } } else { if (ctx) { @@ -1690,7 +1685,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: @@ -2646,11 +2641,9 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) /* Char length to debug ID with */ #define ID_LENGTH 10 -static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, - uint32_t id, - const struct nh_grp *z_grp, - const uint8_t count, bool resilient, - const struct nhg_resilience *nhgr) +static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, uint32_t id, + const struct nh_grp *z_grp, const uint16_t count, + bool resilient, const struct nhg_resilience *nhgr) { struct nexthop_grp grp[count]; /* Need space for max group size, "/", and null term */ @@ -2981,7 +2974,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: @@ -3185,6 +3178,9 @@ netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) } else return FRR_NETLINK_ERROR; + if (dplane_ctx_get_safi(ctx) == SAFI_MULTICAST) + return FRR_NETLINK_SUCCESS; + if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) return FRR_NETLINK_SUCCESS; @@ -3210,7 +3206,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; @@ -3287,7 +3283,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, struct nh_grp *z_grp, int z_grp_size, struct nhg_resilience *nhgr) { - uint8_t count = 0; + uint16_t count = 0; /* linux/nexthop.h group struct */ struct nexthop_grp *n_grp = NULL; @@ -3357,10 +3353,10 @@ 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; + uint16_t grp_count = 0; struct rtattr *tb[NHA_MAX + 1] = {}; frrtrace(3, frr_zebra, netlink_nexthop_change, h, ns_id, startup); diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 0bfcd518..4444eda9 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -317,12 +317,12 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) frr_with_privs(&zserv_privs) { if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) { - if (!RSYSTEM_ROUTE(type)) + if (!RSYSTEM_ROUTE(type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST) kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), dplane_ctx_get_ng(ctx), dplane_ctx_get_metric(ctx)); } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) { - if (!RSYSTEM_ROUTE(type)) + if (!RSYSTEM_ROUTE(type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST) kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), dplane_ctx_get_ng(ctx), dplane_ctx_get_metric(ctx)); @@ -330,12 +330,12 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) /* Must do delete and add separately - * no update available */ - if (!RSYSTEM_ROUTE(old_type)) + if (!RSYSTEM_ROUTE(old_type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST) kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), dplane_ctx_get_old_ng(ctx), dplane_ctx_get_old_metric(ctx)); - if (!RSYSTEM_ROUTE(type)) + if (!RSYSTEM_ROUTE(type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST) kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), dplane_ctx_get_ng(ctx), dplane_ctx_get_metric(ctx)); diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 470391de..8f671351 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 19667e66..3c4db009 100644 --- a/zebra/tc_netlink.c +++ b/zebra/tc_netlink.c @@ -660,27 +660,6 @@ netlink_put_tc_filter_update_msg(struct nl_batch *bth, return ret; } -/* - * 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 */ @@ -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 5e95e6c1..300c53b6 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 d585ef99..7dae75ba 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -517,7 +517,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct zapi_nexthop *api_nh; struct nexthop *nexthop; const struct prefix *p, *src_p; - uint8_t count = 0; + uint16_t count = 0; afi_t afi; size_t stream_size = MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route)); @@ -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; } @@ -999,6 +1001,48 @@ void zsend_neighbor_notify(int cmd, struct interface *ifp, } } +void zsend_srv6_sid_notify(struct zserv *client, const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, const char *locator_name, + enum zapi_srv6_sid_notify note) + +{ + struct stream *s; + uint16_t cmd = ZEBRA_SRV6_SID_NOTIFY; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: notifying %s ctx %s sid %pI6 note %s (proto=%u, instance=%u, sessionId=%u)", + __func__, zserv_command_string(cmd), + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value, + zapi_srv6_sid_notify2str(note), client->proto, + client->instance, client->session_id); + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, cmd, VRF_DEFAULT); + /* Notification type (e.g. ZAPI_SRV6_SID_ALLOCATED, ZAPI_SRV6_SID_FAIL_ALLOC, ...) */ + stream_put(s, ¬e, sizeof(note)); + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + /* SRv6 SID value (i.e. IPv6 address) */ + stream_put(s, sid_value, sizeof(struct in6_addr)); + /* SRv6 SID function */ + stream_putl(s, func); + /* SRv6 wide SID function */ + stream_putl(s, wide_func); + /* SRv6 locator name optional */ + if (locator_name) { + stream_putw(s, strlen(locator_name)); + stream_put(s, locator_name, strlen(locator_name)); + } else + stream_putw(s, 0); + + stream_putw_at(s, 0, stream_get_endp(s)); + + zserv_send_message(client, s); +} + /* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, @@ -1136,9 +1180,25 @@ static int zsend_table_manager_connect_response(struct zserv *client, int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct srv6_locator locator = {}; + struct srv6_sid_format *format = loc->sid_format; + + /* + * Copy the locator and fill locator block/node/func/arg length from the format + * before sending the locator to the zclient + */ + srv6_locator_copy(&locator, loc); + if (format) { + locator.block_bits_length = format->block_len; + locator.node_bits_length = format->node_len; + locator.function_bits_length = format->function_len; + locator.argument_bits_length = format->argument_len; + if (format->type == SRV6_SID_FORMAT_TYPE_USID) + SET_FLAG(locator.flags, SRV6_LOCATOR_USID); + } zclient_create_header(s, ZEBRA_SRV6_LOCATOR_ADD, VRF_DEFAULT); - zapi_srv6_locator_encode(s, loc); + zapi_srv6_locator_encode(s, &locator); stream_putw_at(s, 0, stream_get_endp(s)); return zserv_send_message(client, s); @@ -2071,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. */ @@ -2090,7 +2150,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, &api.prefix, zebra_route_string(client->proto)); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2115,7 +2175,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2134,8 +2194,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) @@ -2147,8 +2206,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, api.safi); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2177,8 +2235,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) */ if (ret == -1) { client->error_cnt++; - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } /* At this point, these allocations are not needed: 're' has been @@ -2206,9 +2263,10 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) } } -void zapi_re_opaque_free(struct re_opaque *opaque) +void zapi_re_opaque_free(struct route_entry *re) { - XFREE(MTYPE_RE_OPAQUE, opaque); + XFREE(MTYPE_RE_OPAQUE, re->opaque); + re->opaque = NULL; } static void zread_route_del(ZAPI_HANDLER_ARGS) @@ -2356,6 +2414,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) stream_putl(s, zrouter.multipath_num); stream_putc(s, zebra_mlag_get_role()); stream_putc(s, zrouter.v6_with_v4_nexthop); + stream_putc(s, zrouter.graceful_restart); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } @@ -2418,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 */ @@ -2990,6 +3033,96 @@ stream_failure: return; } +/** + * Handle SRv6 SID request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct in6_addr *sid_value_ptr = NULL; + char locator[SRV6_LOCNAME_SIZE] = { 0 }; + uint16_t len; + struct zebra_srv6_sid *sid = NULL; + uint8_t flags; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + STREAM_GETC(s, flags); + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) { + STREAM_GET(&sid_value, s, sizeof(struct in6_addr)); + sid_value_ptr = &sid_value; + } + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) { + STREAM_GETW(s, len); + STREAM_GET(locator, s, len); + } + + /* Call hook to get a SID using wrapper */ + srv6_manager_get_sid_call(&sid, client, &ctx, sid_value_ptr, locator); + +stream_failure: + return; +} + +/** + * Handle SRv6 SID release request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_release_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + + /* Call hook to release a SID using wrapper */ + srv6_manager_release_sid_call(client, &ctx); + +stream_failure: + return; +} + +/** + * Handle SRv6 locator get request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_locator(struct zserv *client, + struct stream *msg) +{ + struct stream *s = msg; + uint16_t len; + char locator_name[SRV6_LOCNAME_SIZE] = { 0 }; + struct srv6_locator *locator = NULL; + + /* Get data */ + STREAM_GETW(s, len); + STREAM_GET(locator_name, s, len); + + /* Call hook to get the locator info using wrapper */ + srv6_manager_get_locator_call(&locator, client, locator_name); + +stream_failure: + return; +} + static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) { switch (hdr->command) { @@ -3001,6 +3134,15 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) zread_srv6_manager_release_locator_chunk(client, msg, zvrf_id(zvrf)); break; + case ZEBRA_SRV6_MANAGER_GET_SRV6_SID: + zread_srv6_manager_get_srv6_sid(client, msg); + break; + case ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID: + zread_srv6_manager_release_srv6_sid(client, msg); + break; + case ZEBRA_SRV6_MANAGER_GET_LOCATOR: + zread_srv6_manager_get_locator(client, msg); + break; default: zlog_err("%s: unknown SRv6 Manager command", __func__); break; @@ -3897,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, @@ -3949,6 +4090,9 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_SRV6_SID] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_LOCATOR] = zread_srv6_manager_request, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover, [ZEBRA_NHG_ADD] = zread_nhg_add, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 43f734d2..a59ccc83 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -94,6 +94,11 @@ extern int zsend_sr_policy_notify_status(uint32_t color, extern void zsend_neighbor_notify(int cmd, struct interface *ifp, struct ipaddr *ipaddr, int ndm_state, union sockunion *link_layer_ipv4, int ip_len); +extern void zsend_srv6_sid_notify(struct zserv *client, + const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, const char *locator_name, + enum zapi_srv6_sid_notify note); extern int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client); @@ -101,7 +106,7 @@ extern int zsend_client_close_notify(struct zserv *client, int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, uint32_t id, enum zapi_nhg_notify_owner note); -extern void zapi_re_opaque_free(struct re_opaque *opaque); +extern void zapi_re_opaque_free(struct route_entry *re); extern int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc); @@ -110,6 +115,9 @@ extern int zsend_zebra_srv6_locator_delete(struct zserv *client, extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct srv6_locator *loc); +extern int zsend_srv6_manager_get_locator_response(struct zserv *client, + struct srv6_locator *locator); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_cli.c b/zebra/zebra_cli.c index 3e03d747..6ee0fdbb 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]", @@ -2851,6 +2882,10 @@ const struct frr_yang_module_info frr_zebra_cli_info = { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range", .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 39448764..00e990e8 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -86,7 +86,7 @@ struct dplane_nexthop_info { struct nexthop_group ng; struct nh_grp nh_grp[MULTIPATH_NUM]; - uint8_t nh_grp_count; + uint16_t nh_grp_count; }; /* @@ -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; @@ -969,6 +967,11 @@ struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_list_head *q) return ctx; } +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q) +{ + return dplane_ctx_list_count(q); +} + /* * Accessors for information from the context object */ @@ -2313,7 +2316,7 @@ dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx) return ctx->u.rinfo.nhe.nh_grp; } -uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx) +uint16_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); return ctx->u.rinfo.nhe.nh_grp_count; @@ -4309,6 +4312,10 @@ dplane_route_update_internal(struct route_node *rn, NEXTHOP_FLAG_RECURSIVE)) continue; + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_DUPLICATE)) + continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) SET_FLAG(nexthop->flags, @@ -4494,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, @@ -5994,6 +6014,14 @@ int dplane_show_helper(struct vty *vty, bool detailed) vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n", incoming); vty_out(vty, "Route update errors: %"PRIu64"\n", errs); + + incoming = atomic_load_explicit(&zdplane_info.dg_nexthops_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_nexthop_errors, + memory_order_relaxed); + vty_out(vty, "Nexthop updates: %" PRIu64 "\n", incoming); + vty_out(vty, "Nexthop update errors: %" PRIu64 "\n", errs); + vty_out(vty, "Other errors : %"PRIu64"\n", other_errs); vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit); vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued); @@ -6099,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; } @@ -6269,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); @@ -6300,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; @@ -6328,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) @@ -6353,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; } @@ -7301,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 */ @@ -7328,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, @@ -7358,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. @@ -7392,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) @@ -7420,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) @@ -7447,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_dplane.h b/zebra/zebra_dplane.h index 060b1c8b..a3318bf5 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -323,6 +323,8 @@ struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_list_head *q); /* Init a list of contexts */ void dplane_ctx_q_init(struct dplane_ctx_list_head *q); +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q); + /* * Accessors for information from the context object */ @@ -595,7 +597,7 @@ const struct nexthop_group * dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx); const struct nh_grp * dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx); -uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx); +uint16_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx); /* Accessors for LSP information */ diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 09b369e2..dcfa37d2 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -787,6 +787,18 @@ static struct log_ref ferr_zebra_err[] = { .suggestion = "Wait for Zebra to reattempt update.", }, + { + .code = EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + .title = "SRv6 manager unable to assign SID", + .description = "Zebra's SRv6 manager was unable to assign a SID to client.", + .suggestion = "Ensure that Zebra has a sufficient SID range available.", + }, + { + .code = EC_ZEBRA_SM_DAEMON_MISMATCH, + .title = "Daemon mismatch when releasing SRV6 SIDs", + .description = "Zebra noticed a mismatch between a SRv6 SID and a protocol daemon number or instance when releasing unused SRv6 SIDs.", + .suggestion = "Ignore this error.", + }, { .code = END_FERR, } diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 3ac654bd..84632e1a 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -124,6 +124,8 @@ enum zebra_log_refs { EC_ZEBRA_GRE_SET_UPDATE, EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK, EC_ZEBRA_INTF_UPDATE_FAILURE, + EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + EC_ZEBRA_SM_DAEMON_MISMATCH, }; void zebra_error_init(void); diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index ebb5a422..a733b591 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 bfc060db..0d535913 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 cee66cc0..07391b7a 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -103,6 +103,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client) info->stale_client_ptr = client; TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info); + info->client_ptr = client; return info; } @@ -290,6 +291,7 @@ struct zebra_gr_afi_clean { afi_t afi; uint8_t proto; uint8_t instance; + time_t restart_time; struct event *t_gac; }; @@ -420,7 +422,7 @@ void zread_client_capabilities(ZAPI_HANDLER_ARGS) * Schedule for after anything already in the meta Q */ rib_add_gr_run(api.afi, api.vrf_id, client->proto, - client->instance); + client->instance, client->restart_time); zebra_gr_process_client_stale_routes(client, info); break; case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: @@ -455,7 +457,11 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) struct zserv *client; struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - client = (struct zserv *)info->stale_client_ptr; + info->t_stale_removal = NULL; + if (zrouter.graceful_restart) + client = (struct zserv *)info->client_ptr; + else + client = (struct zserv *)info->stale_client_ptr; cnt = zebra_gr_delete_stale_routes(info); @@ -486,16 +492,24 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) * * Returns true when a node is deleted else false */ -static bool zebra_gr_process_route_entry(struct zserv *client, - struct route_node *rn, - struct route_entry *re) +static bool zebra_gr_process_route_entry(struct route_node *rn, + struct route_entry *re, + time_t compare_time, uint8_t proto) { + struct nexthop *nexthop; + char buf[PREFIX2STR_BUFFER]; + /* If the route is not refreshed after restart, delete the entry */ - if (re->uptime < client->restart_time) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("%s: Client %s stale route %pFX is deleted", - __func__, zebra_route_string(client->proto), - &rn->p); + if (re->uptime < compare_time) { + if (IS_ZEBRA_DEBUG_RIB) { + prefix2str(&rn->p, buf, sizeof(buf)); + zlog_debug("%s: Client %s stale route %s is deleted", + __func__, zebra_route_string(proto), buf); + } + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + rib_delnode(rn, re); return true; @@ -532,8 +546,9 @@ static void zebra_gr_delete_stale_route_table_afi(struct event *event) if (re->type == gac->proto && re->instance == gac->instance && - zebra_gr_process_route_entry( - gac->info->stale_client_ptr, rn, re)) + zebra_gr_process_route_entry(rn, re, + gac->restart_time, + gac->proto)) n++; /* If the max route count is reached @@ -567,28 +582,42 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, uint8_t proto; uint16_t instance; struct zserv *s_client; + struct zserv *client; + time_t restart_time; - s_client = info->stale_client_ptr; - if (s_client == NULL) { - LOG_GR("%s: Stale client %s(%u) not present", __func__, - zvrf->vrf->name, zvrf->vrf->vrf_id); + if ((info == NULL) || (zvrf == NULL)) return -1; - } - proto = s_client->proto; - instance = s_client->instance; + if (zrouter.graceful_restart) { + client = info->client_ptr; + if (client == NULL) { + LOG_GR("%s: client not present", __func__); + return -1; + } + proto = client->proto; + instance = client->instance; + restart_time = zrouter.startup_time; + } else { + s_client = info->stale_client_ptr; + if (s_client == NULL) { + LOG_GR("%s: Stale client not present", __func__); + return -1; + } + proto = s_client->proto; + instance = s_client->instance; + restart_time = s_client->restart_time; + } LOG_GR("%s: Client %s %s(%u) stale routes are being deleted", __func__, zebra_route_string(proto), zvrf->vrf->name, zvrf->vrf->vrf_id); /* Process routes for all AFI */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { - /* * Schedule for immediately after anything in the * meta-Q */ - rib_add_gr_run(afi, info->vrf_id, proto, instance); + rib_add_gr_run(afi, info->vrf_id, proto, instance, restart_time); } return 0; } @@ -641,12 +670,13 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, /* * Route update completed for all AFI, SAFI - * Cancel the stale timer, routes are already being processed + * Also perform the cleanup if FRR itself is gracefully restarting. */ - if (info->t_stale_removal) { + info->route_sync_done_time = monotime(NULL); + if (info->t_stale_removal || zrouter.graceful_restart) { struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - LOG_GR("%s: Client %s canceled stale delete timer vrf %s(%d)", + LOG_GR("%s: Client %s route update complete for all AFI/SAFI in vrf %s(%d)", __func__, zebra_route_string(client->proto), VRF_LOGNAME(vrf), info->vrf_id); EVENT_OFF(info->t_stale_removal); @@ -654,7 +684,7 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, } void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance) + uint8_t instance, time_t restart_time) { struct zserv *client = zserv_find_client(proto, instance); struct client_gr_info *info = NULL; @@ -676,6 +706,7 @@ void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, gac->afi = afi; gac->proto = proto; gac->instance = instance; + gac->restart_time = restart_time; event_add_event(zrouter.master, zebra_gr_delete_stale_route_table_afi, gac, 0, &gac->t_gac); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index d1c9cd54..9549af5f 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; } @@ -447,6 +478,30 @@ static int fec_send(struct zebra_fec *fec, struct zserv *client) return zserv_send_message(client, s); } +/* + * 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 dd6f9601..27f5bdbc 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); /* @@ -256,6 +256,12 @@ void mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf, 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. * diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index eee93230..0a7ed5db 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -883,6 +883,13 @@ const struct frr_yang_module_info frr_zebra_info = { .modify = lib_vrf_zebra_netns_table_range_end_modify, } }, + { + .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 = { diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index b40ed682..785291bc 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 ae6232a1..09c0091e 100644 --- a/zebra/zebra_nb_config.c +++ b/zebra/zebra_nb_config.c @@ -3780,6 +3780,59 @@ int lib_vrf_zebra_netns_table_range_end_modify(struct nb_cb_modify_args *args) return NB_OK; } +/* + * 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 */ diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 6235ecad..1519246c 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; } @@ -612,9 +625,8 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) return nhe1->id == nhe2->id; } -static int zebra_nhg_process_grp(struct nexthop_group *nhg, - struct nhg_connected_tree_head *depends, - struct nh_grp *grp, uint8_t count, +static int zebra_nhg_process_grp(struct nexthop_group *nhg, struct nhg_connected_tree_head *depends, + struct nh_grp *grp, uint16_t count, struct nhg_resilience *resilience) { nhg_connected_tree_init(depends); @@ -969,7 +981,7 @@ static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx) return &ctx->u.nh; } -static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx) +static uint16_t nhg_ctx_get_count(const struct nhg_ctx *ctx) { return ctx->count; } @@ -1015,9 +1027,8 @@ done: XFREE(MTYPE_NHG_CTX, *ctx); } -static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, - struct nh_grp *grp, vrf_id_t vrf_id, - afi_t afi, int type, uint8_t count, +static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, struct nh_grp *grp, + vrf_id_t vrf_id, afi_t afi, int type, uint16_t count, struct nhg_resilience *resilience) { struct nhg_ctx *ctx = NULL; @@ -1088,11 +1099,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 +1169,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 +1189,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); } @@ -1186,7 +1202,7 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) struct nhg_hash_entry *nhe = NULL; uint32_t id = nhg_ctx_get_id(ctx); - uint8_t count = nhg_ctx_get_count(ctx); + uint16_t count = nhg_ctx_get_count(ctx); vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx); int type = nhg_ctx_get_type(ctx); afi_t afi = nhg_ctx_get_afi(ctx); @@ -1338,9 +1354,9 @@ int nhg_ctx_process(struct nhg_ctx *ctx) } /* Kernel-side, you either get a single new nexthop or a array of ID's */ -int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, - uint8_t count, vrf_id_t vrf_id, afi_t afi, int type, - int startup, struct nhg_resilience *nhgr) +int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, uint16_t count, + vrf_id_t vrf_id, afi_t afi, int type, int startup, + struct nhg_resilience *nhgr) { struct nhg_ctx *ctx = NULL; @@ -1417,6 +1433,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. */ @@ -1782,6 +1803,12 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); resolved_hop->vrf_id = nexthop->vrf_id; + + /* Using weighted ECMP, we should respect the weight and use + * the same value for non-recursive next-hop. + */ + resolved_hop->weight = nexthop->weight; + switch (newhop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -2645,13 +2672,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) @@ -2903,6 +2923,154 @@ static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg) return curr_active; } +/* + * 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, @@ -2910,7 +3078,8 @@ static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg) * * 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; @@ -2966,6 +3135,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)", @@ -3004,14 +3178,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, - struct nhg_hash_entry *nhe, - int max_num) +static uint16_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp, uint16_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; - uint8_t i = curr_index; + struct nexthop *nexthop; + uint16_t i = curr_index; frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { bool duplicate = false; @@ -3037,8 +3211,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) @@ -3079,8 +3256,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++; } } @@ -3100,14 +3306,13 @@ done: } /* Convert a nhe into a group array */ -uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, - int max_num) +uint16_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; @@ -3120,9 +3325,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) && @@ -3146,9 +3358,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; } } @@ -3474,7 +3683,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) { /* @@ -3710,7 +3919,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, @@ -3723,6 +3933,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 3bb697aa..0f90627a 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 */ @@ -212,7 +231,7 @@ struct nhg_ctx { int type; /* If its a group array, how many? */ - uint8_t count; + uint16_t count; /* Its either a single nexthop or an array of ID's */ union { @@ -298,10 +317,8 @@ extern int nhg_ctx_process(struct nhg_ctx *ctx); void nhg_ctx_free(struct nhg_ctx **ctx); /* Find via kernel nh creation */ -extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, - struct nh_grp *grp, uint8_t count, - vrf_id_t vrf_id, afi_t afi, int type, - int startup, +extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, + uint16_t count, vrf_id_t vrf_id, afi_t afi, int type, int startup, struct nhg_resilience *resilience); /* Del via kernel */ extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id); @@ -360,11 +377,10 @@ extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); extern void zebra_nhg_check_valid(struct nhg_hash_entry *nhe); /* Convert nhe depends to a grp context that can be passed around safely */ -extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, - int size); +extern uint16_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 +401,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_ns.c b/zebra/zebra_ns.c index 803d8f00..ffd749fc 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -175,6 +175,22 @@ int zebra_ns_early_shutdown(struct ns *ns, return NS_WALK_CONTINUE; } +/* During zebra shutdown, do kernel cleanup + * netlink sockets, .. + */ +int zebra_ns_kernel_shutdown(struct ns *ns, void *param_in __attribute__((unused)), + void **param_out __attribute__((unused))) +{ + struct zebra_ns *zns = ns->info; + + if (zns == NULL) + return NS_WALK_CONTINUE; + + kernel_terminate(zns, true); + + return NS_WALK_CONTINUE; +} + /* During zebra shutdown, do final cleanup * after all dataplane work is complete. */ @@ -185,9 +201,7 @@ int zebra_ns_final_shutdown(struct ns *ns, struct zebra_ns *zns = ns->info; if (zns == NULL) - return 0; - - kernel_terminate(zns, true); + return NS_WALK_CONTINUE; zebra_ns_delete(ns); diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 8d988c3f..d5fd5869 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -70,6 +70,8 @@ int zebra_ns_early_shutdown(struct ns *ns, int zebra_ns_final_shutdown(struct ns *ns, void *param_in __attribute__((unused)), void **param_out __attribute__((unused))); +int zebra_ns_kernel_shutdown(struct ns *ns, void *param_in __attribute__((unused)), + void **param_out __attribute__((unused))); void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index deed3b6a..6adc0b1b 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -147,7 +147,6 @@ void zebra_pw_update(struct zebra_pw *pw) { if (zebra_pw_check_reachability(pw) < 0) { zebra_pw_uninstall(pw); - zebra_pw_install_failure(pw, PW_NOT_FORWARDING); /* wait for NHT and try again later */ } else { /* @@ -167,12 +166,17 @@ static void zebra_pw_install(struct zebra_pw *pw) hook_call(pw_install, pw); if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) { + /* + * Realistically this is never going to fail passing + * the pw data down to the dplane. The failure modes + * look like impossible events but we still return + * on them.... but I don't see a real clean way to remove this + * at all. So let's just leave the retry mechanism for + * the moment. + */ zebra_pw_install_failure(pw, PW_NOT_FORWARDING); return; } - - if (pw->status != PW_FORWARDING) - zebra_pw_update_status(pw, PW_FORWARDING); } static void zebra_pw_uninstall(struct zebra_pw *pw) @@ -188,9 +192,30 @@ static void zebra_pw_uninstall(struct zebra_pw *pw) /* ignore any possible error */ hook_call(pw_uninstall, pw); dplane_pw_uninstall(pw); +} + +void zebra_pw_handle_dplane_results(struct zebra_dplane_ctx *ctx) +{ + struct zebra_pw *pw; + struct zebra_vrf *vrf; + enum dplane_op_e op; + + op = dplane_ctx_get_op(ctx); + + vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); + pw = zebra_pw_find(vrf, dplane_ctx_get_ifname(ctx)); + + if (!pw) + return; - if (zebra_pw_enabled(pw)) - zebra_pw_update_status(pw, PW_NOT_FORWARDING); + if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { + zebra_pw_install_failure(pw, dplane_ctx_get_pw_status(ctx)); + } else { + if (op == DPLANE_OP_PW_INSTALL && pw->status != PW_FORWARDING) + zebra_pw_update_status(pw, PW_FORWARDING); + else if (op == DPLANE_OP_PW_UNINSTALL && zebra_pw_enabled(pw)) + zebra_pw_update_status(pw, PW_NOT_FORWARDING); + } } /* diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index 431d663f..e037a550 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -64,6 +64,7 @@ void zebra_pw_init_vrf(struct zebra_vrf *); void zebra_pw_exit_vrf(struct zebra_vrf *); void zebra_pw_terminate(void); void zebra_pw_vty_init(void); +void zebra_pw_handle_dplane_results(struct zebra_dplane_ctx *ctx); #ifdef __cplusplus } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5b95d866..752f8282 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)) @@ -668,7 +637,6 @@ int zebra_rib_labeled_unicast(struct route_entry *re) void rib_install_kernel(struct route_node *rn, struct route_entry *re, struct route_entry *old) { - struct nexthop *nexthop; struct rib_table_info *info = srcdest_rnode_table_info(rn); struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(re->vrf_id); const struct prefix *p, *src_p; @@ -678,17 +646,10 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, srcdest_rnode_prefixes(rn, &p, &src_p); - if (info->safi != SAFI_UNICAST) { - for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - return; - } - - /* * 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 @@ -751,17 +712,8 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, /* Uninstall the route from kernel. */ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) { - struct nexthop *nexthop; - struct rib_table_info *info = srcdest_rnode_table_info(rn); struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(re->vrf_id); - if (info->safi != SAFI_UNICAST) { - UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - return; - } - /* * Make sure we update the FPM any time we send new information to * the dataplane. @@ -1235,8 +1187,15 @@ static void rib_process(struct route_node *rn) struct zebra_vrf *zvrf = NULL; struct vrf *vrf; struct route_entry *proto_re_changed = NULL; - vrf_id_t vrf_id = VRF_UNKNOWN; + safi_t safi = SAFI_UNICAST; + + if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_DETAILED) { + struct rib_table_info *info = srcdest_rnode_table_info(rn); + + assert(info); + safi = info->safi; + } assert(rn); @@ -1262,9 +1221,8 @@ static void rib_process(struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB_DETAILED) { struct route_entry *re = re_list_first(&dest->routes); - zlog_debug("%s(%u:%u):%pRN: Processing rn %p", - VRF_LOGNAME(vrf), vrf_id, re->table, rn, - rn); + zlog_debug("%s(%u:%u:%u):%pRN: Processing rn %p", VRF_LOGNAME(vrf), vrf_id, + re->table, safi, rn, rn); } old_fib = dest->selected_fib; @@ -1274,15 +1232,12 @@ static void rib_process(struct route_node *rn) char flags_buf[128]; char status_buf[128]; - zlog_debug( - "%s(%u:%u):%pRN: Examine re %p (%s) status: %sflags: %sdist %d metric %d", - VRF_LOGNAME(vrf), vrf_id, re->table, rn, re, - zebra_route_string(re->type), - _dump_re_status(re, status_buf, - sizeof(status_buf)), - zclient_dump_route_flags(re->flags, flags_buf, - sizeof(flags_buf)), - re->distance, re->metric); + zlog_debug("%s(%u:%u:%u):%pRN: Examine re %p (%s) status: %sflags: %sdist %d metric %d", + VRF_LOGNAME(vrf), vrf_id, re->table, safi, rn, re, + zebra_route_string(re->type), + _dump_re_status(re, status_buf, sizeof(status_buf)), + zclient_dump_route_flags(re->flags, flags_buf, sizeof(flags_buf)), + re->distance, re->metric); } /* Currently selected re. */ @@ -1305,7 +1260,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; @@ -1408,11 +1363,10 @@ static void rib_process(struct route_node *rn) : old_fib ? old_fib : new_fib ? new_fib : NULL; - zlog_debug( - "%s(%u:%u):%pRN: After processing: old_selected %p new_selected %p old_fib %p new_fib %p", - VRF_LOGNAME(vrf), vrf_id, entry ? entry->table : 0, rn, - (void *)old_selected, (void *)new_selected, - (void *)old_fib, (void *)new_fib); + zlog_debug("%s(%u:%u:%u):%pRN: After processing: old_selected %p new_selected %p old_fib %p new_fib %p", + VRF_LOGNAME(vrf), vrf_id, entry ? entry->table : 0, safi, rn, + (void *)old_selected, (void *)new_selected, (void *)old_fib, + (void *)new_fib); } /* Buffer ROUTE_ENTRY_CHANGED here, because it will get cleared if @@ -1619,6 +1573,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; @@ -1659,6 +1617,9 @@ static bool rib_update_nhg_from_ctx(struct nexthop_group *re_nhg, if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + continue; + /* Check for a FIB nexthop corresponding to the RIB nexthop */ if (!nexthop_same(ctx_nexthop, nexthop)) { /* If the FIB doesn't know about the nexthop, @@ -2693,8 +2654,7 @@ static void early_route_memory_free(struct zebra_early_route *ere) if (ere->re_nhe) zebra_nhg_free(ere->re_nhe); - zapi_re_opaque_free(ere->re->opaque); - XFREE(MTYPE_RE, ere->re); + zebra_rib_route_entry_free(ere->re); XFREE(MTYPE_WQ_WRAPPER, ere); } @@ -2861,10 +2821,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( @@ -3159,6 +3120,7 @@ struct meta_q_gr_run { vrf_id_t vrf_id; uint8_t proto; uint8_t instance; + time_t restart_time; }; static void process_subq_gr_run(struct listnode *lnode) @@ -3166,7 +3128,7 @@ static void process_subq_gr_run(struct listnode *lnode) struct meta_q_gr_run *gr_run = listgetdata(lnode); zebra_gr_process_client(gr_run->afi, gr_run->vrf_id, gr_run->proto, - gr_run->instance); + gr_run->instance, gr_run->restart_time); XFREE(MTYPE_WQ_WRAPPER, gr_run); } @@ -3833,7 +3795,8 @@ static void rib_meta_queue_free(struct meta_queue *mq, struct list *l, } static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, - struct zebra_vrf *zvrf) + const struct zebra_vrf *zvrf, + uint8_t proto, uint8_t instance) { struct zebra_early_route *ere; struct listnode *node, *nnode; @@ -3842,6 +3805,10 @@ static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, if (zvrf && ere->re->vrf_id != zvrf->vrf->vrf_id) continue; + if (proto != ZEBRA_ROUTE_ALL && + (proto != ere->re->type && instance != ere->re->instance)) + continue; + early_route_memory_free(ere); node->data = NULL; list_delete_node(l, node); @@ -3880,7 +3847,8 @@ void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf) evpn_meta_queue_free(mq, mq->subq[i], zvrf); break; case META_QUEUE_EARLY_ROUTE: - early_route_meta_queue_free(mq, mq->subq[i], zvrf); + early_route_meta_queue_free(mq, mq->subq[i], zvrf, + ZEBRA_ROUTE_ALL, 0); break; case META_QUEUE_EARLY_LABEL: early_label_meta_queue_free(mq, mq->subq[i], zvrf); @@ -4060,9 +4028,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) rib_re_nhg_free(re); - zapi_re_opaque_free(re->opaque); - - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } void rib_delnode(struct route_node *rn, struct route_entry *re) @@ -4098,9 +4064,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]; @@ -4154,35 +4119,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 @@ -4211,32 +4173,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) @@ -4257,16 +4220,20 @@ 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; } -int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) +int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance, + time_t restart_time) { struct meta_q_gr_run *gr_run; @@ -4276,6 +4243,7 @@ int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) gr_run->proto = proto; gr_run->vrf_id = vrf_id; gr_run->instance = instance; + gr_run->restart_time = restart_time; return mq_add_handler(gr_run, rib_meta_queue_gr_run_add); } @@ -4307,6 +4275,7 @@ struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, void zebra_rib_route_entry_free(struct route_entry *re) { + zapi_re_opaque_free(re); XFREE(MTYPE_RE, re); } @@ -4360,31 +4329,67 @@ 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 */ if (ret < 0) - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return ret; } 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) { @@ -4448,6 +4453,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; @@ -4464,15 +4472,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)) || nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { + 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; } @@ -4512,20 +4561,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; @@ -4533,7 +4586,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; @@ -4694,6 +4747,10 @@ void rib_sweep_route(struct event *t) struct vrf *vrf; struct zebra_vrf *zvrf; + zrouter.rib_sweep_time = monotime(NULL); + /* TODO: Change to debug */ + zlog_info("Sweeping the RIB for stale routes..."); + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { if ((zvrf = vrf->info) == NULL) continue; @@ -4742,6 +4799,10 @@ unsigned long rib_score_proto(uint8_t proto, unsigned short instance) if (!zvrf) continue; + early_route_meta_queue_free(zrouter.mq, + zrouter.mq->subq[META_QUEUE_EARLY_ROUTE], + zvrf, proto, instance); + cnt += rib_score_proto_table(proto, instance, zvrf->table[AFI_IP][SAFI_UNICAST]) + rib_score_proto_table( @@ -4774,29 +4835,6 @@ void rib_close_table(struct route_table *table) } } -/* - * Handler for async dataplane results after a pseudowire installation - */ -static void handle_pw_result(struct zebra_dplane_ctx *ctx) -{ - struct zebra_pw *pw; - struct zebra_vrf *vrf; - - /* The pseudowire code assumes success - we act on an error - * result for installation attempts here. - */ - if (dplane_ctx_get_op(ctx) != DPLANE_OP_PW_INSTALL) - return; - - if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { - vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); - pw = zebra_pw_find(vrf, dplane_ctx_get_ifname(ctx)); - if (pw) - zebra_pw_install_failure(pw, - dplane_ctx_get_pw_status(ctx)); - } -} - /* * Handle results from the dataplane system. Dequeue update context * structs, dispatch to appropriate internal handlers. @@ -4903,7 +4941,7 @@ static void rib_process_dplane_results(struct event *thread) case DPLANE_OP_PW_INSTALL: case DPLANE_OP_PW_UNINSTALL: - handle_pw_result(ctx); + zebra_pw_handle_dplane_results(ctx); break; case DPLANE_OP_SYS_ROUTE_ADD: @@ -5001,6 +5039,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 bff82588..7c25fb3e 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -220,10 +220,9 @@ void zebra_free_rnh(struct rnh *rnh) if (rern) { rib_dest_t *dest; - route_unlock_node(rern); - dest = rib_dest_from_rnode(rern); rnh_list_del(&dest->nht, rnh); + route_unlock_node(rern); } } free_state(rnh->vrf_id, rnh->state, rnh->node); @@ -826,7 +825,7 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, /* free RE and nexthops */ zebra_nhg_free(re->nhe); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } static void copy_state(struct rnh *rnh, const struct route_entry *re, @@ -1344,13 +1343,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_routemap.c b/zebra/zebra_routemap.c index c1ec5067..46afbcec 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -650,9 +650,8 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix, plist = prefix_list_lookup(afi, (char *)rule); if (plist == NULL) { if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "%s: Prefix List %s specified does not exist defaulting to NO_MATCH", - __func__, (char *)rule); + zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH", + __func__, (char *)rule, afi2str(afi)); return RMAP_NOMATCH; } diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 3fd4e6eb..4022c1a2 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -238,7 +238,7 @@ void zebra_router_terminate(void) { struct zebra_router_table *zrt, *tmp; - EVENT_OFF(zrouter.sweeper); + EVENT_OFF(zrouter.t_rib_sweep); RB_FOREACH_SAFE (zrt, zebra_router_table_head, &zrouter.tables, tmp) zebra_router_free_table(zrt); @@ -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_router.h b/zebra/zebra_router.h index 30417074..c86c6be1 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -191,10 +191,16 @@ struct zebra_router { enum multicast_mode ipv4_multicast_mode; /* - * Time for when we sweep the rib from old routes + * zebra start time and time of sweeping RIB of old routes */ time_t startup_time; - struct event *sweeper; + time_t rib_sweep_time; + + /* FRR fast/graceful restart info */ + bool graceful_restart; + int gr_cleanup_time; +#define ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME 500 + struct event *t_rib_sweep; /* * The hash of nexthop groups associated with this router diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 1c6d5815..4b4f5232 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.c b/zebra/zebra_srv6.c index bb872ef9..082d4609 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -18,11 +18,6 @@ #include "zebra/zebra_srv6.h" #include "zebra/zebra_errors.h" #include "zebra/ge_netlink.h" -#include -#include -#include -#include -#include #include #include @@ -33,6 +28,16 @@ DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager"); DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_BLOCK, "SRv6 SID block"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_FUNC, "SRv6 SID function"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_USID_WLIB, + "SRv6 uSID Wide LIB information"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID, "SRv6 SID"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_CTX, "SRv6 SID context"); + +/* Prototypes */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func); /* define hooks for the basic API, so that it can be specialized or served * externally @@ -55,6 +60,18 @@ DEFINE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DEFINE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DEFINE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); +DEFINE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); + /* define wrappers to be called in zapi_msg.c (as hooks must be called in * source file where they were defined) */ @@ -85,11 +102,502 @@ int srv6_manager_client_disconnect_cb(struct zserv *client) return 0; } + +void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + hook_call(srv6_manager_get_sid, sid, client, ctx, sid_value, + locator_name); +} + +void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + hook_call(srv6_manager_release_sid, client, ctx); +} + +void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + hook_call(srv6_manager_get_locator, locator, client, locator_name); +} + static int zebra_srv6_cleanup(struct zserv *client) { + /* Client has disconnected, let's release all the SIDs allocated by it. */ + release_daemon_srv6_sids(client); return 0; } +/* --- Zebra SRv6 SID context management functions -------------------------- */ + +struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void) +{ + struct zebra_srv6_sid_ctx *ctx = NULL; + + ctx = XCALLOC(MTYPE_ZEBRA_SRV6_SID_CTX, + sizeof(struct zebra_srv6_sid_ctx)); + + return ctx; +} + +void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_CTX, ctx); +} + +/** + * Free an SRv6 SID context. + * + * @param val SRv6 SID context to be freed + */ +void delete_zebra_srv6_sid_ctx(void *val) +{ + zebra_srv6_sid_ctx_free((struct zebra_srv6_sid_ctx *)val); +} + +/* --- Zebra SRv6 SID format management functions --------------------------- */ + +void srv6_sid_format_register(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + /* Ensure that the format is registered only once */ + assert(!srv6_sid_format_lookup(format->name)); + + listnode_add(srv6->sid_formats, format); +} + +void srv6_sid_format_unregister(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + listnode_delete(srv6->sid_formats, format); +} + +struct srv6_sid_format *srv6_sid_format_lookup(const char *name) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_sid_format *format; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) + if (!strncmp(name, format->name, sizeof(format->name))) + return format; + + return NULL; +} + +/* + * Called to change the SID format of a locator. + * + * After switching the locator to a different format, the SIDs allocated + * from the locator may no longer be valid; we need to notify the + * interested zclient that the locator has changed, so that the + * zclients can withdraw/uninstall the old SIDs, allocate/advertise/program + * the new SIDs. + */ +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block_old, *block_new; + struct prefix_ipv6 block_pfx_new; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (!locator) + return; + + locator->sid_format = format; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, old=%s new=%s", + __func__, locator->name, + locator->sid_format ? ((struct srv6_sid_format *) + locator->sid_format) + ->name + : NULL, + format ? format->name : NULL); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_DEL notification to zclients", + __func__, locator->name); + + /* Release the current parent block */ + block_old = locator->sid_block; + if (block_old) { + block_old->refcnt--; + if (block_old->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block_old); + zebra_srv6_sid_block_free(block_old); + } + } + locator->sid_block = NULL; + + block_pfx_new = locator->prefix; + if (format) + block_pfx_new.prefixlen = format->block_len; + else + block_pfx_new.prefixlen = locator->block_bits_length; + apply_mask(&block_pfx_new); + + /* Allocate the new parent block */ + block_new = zebra_srv6_sid_block_lookup(&block_pfx_new); + if (!block_new) { + block_new = zebra_srv6_sid_block_alloc(format, &block_pfx_new); + listnode_add(srv6->sid_blocks, block_new); + } + + block_new->refcnt++; + locator->sid_block = block_new; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_ADD notification to zclients", + __func__, locator->name); + + /* Notify zclients about the updated locator */ + zebra_srv6_locator_add(locator); +} + +/* + * Called when a SID format is modified by the user. + * + * After modifying a SID format, the SIDs that are using that format may no + * longer be valid. + * This function walks through the list of locators that are using the SID format + * and notifies the zclients that the locator has changed, so that the zclients + * can withdraw/uninstall the old SIDs, allocate/program/advertise the new SIDs. + */ +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *locator; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SID format %s has changed. Notifying zclients.", + __func__, format->name); + + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + if (locator->sid_format == format) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s has changed because its format (%s) has been modified. Notifying zclients.", + __func__, locator->name, + format->name); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + /* Notify zclients about the updated locator */ + zebra_notify_srv6_locator_add(locator); + } + } +} + +/* + * Helper function to create the SRv6 compressed format `usid-f3216`. + */ +static struct srv6_sid_format *create_srv6_sid_format_usid_f3216(void) +{ + struct srv6_sid_format *format = NULL; + + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_USID_F3216_NAME); + + format->type = SRV6_SID_FORMAT_TYPE_USID; + + /* Define block/node/function length */ + format->block_len = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + return format; +} + +/* + * Helper function to create the SRv6 uncompressed format. + */ +static struct srv6_sid_format *create_srv6_sid_format_uncompressed(void) +{ + struct srv6_sid_format *format = NULL; + + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + + format->type = SRV6_SID_FORMAT_TYPE_UNCOMPRESSED; + + /* Define block/node/function length */ + format->block_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.uncompressed.explicit_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + return format; +} + +/* --- Zebra SRv6 SID function management functions ---------------------------- */ + +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func) +{ + uint32_t *sid_func_ptr; + + sid_func_ptr = XCALLOC(MTYPE_ZEBRA_SRV6_SID_FUNC, sizeof(uint32_t)); + *sid_func_ptr = func; + + return sid_func_ptr; +} + +void zebra_srv6_sid_func_free(uint32_t *func) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_FUNC, func); +} + +/** + * Free an SRv6 SID function. + * + * @param val SRv6 SID function to be freed + */ +void delete_zebra_srv6_sid_func(void *val) +{ + zebra_srv6_sid_func_free((uint32_t *)val); +} + +/* --- Zebra SRv6 SID block management functions ---------------------------- */ + +static struct zebra_srv6_sid_block *zebra_srv6_sid_block_alloc_internal(void) +{ + struct zebra_srv6_sid_block *block = NULL; + + block = XCALLOC(MTYPE_ZEBRA_SRV6_SID_BLOCK, + sizeof(struct zebra_srv6_sid_block)); + + return block; +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, + struct prefix_ipv6 *prefix) +{ + struct zebra_srv6_sid_block *block; + + block = zebra_srv6_sid_block_alloc_internal(); + block->sid_format = format; + block->prefix = *prefix; + + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Init uSID LIB */ + block->u.usid.lib.func_allocated = list_new(); + block->u.usid.lib.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.func_released = list_new(); + block->u.usid.lib.func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.first_available_func = + format->config.usid.lib_start; + + /* Init uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + block->u.usid.wide_lib = + XCALLOC(MTYPE_ZEBRA_SRV6_USID_WLIB, + (wlib_end - wlib_start + 1) * + sizeof(struct wide_lib)); + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + block->u.usid.wide_lib[func].func_allocated = + list_new(); + block->u.usid.wide_lib[func].func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func_released = + list_new(); + block->u.usid.wide_lib[func].func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func = func; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + } else { + /* We should never arrive here */ + assert(0); + } + } else { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = 1; + } + + return block; +} + +void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block) +{ + if (block->sid_format) { + if (block->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Free uSID LIB */ + list_delete(&block->u.usid.lib.func_allocated); + list_delete(&block->u.usid.lib.func_released); + + /* Free uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + list_delete(&block->u.usid.wide_lib[func] + .func_allocated); + list_delete(&block->u.usid.wide_lib[func] + .func_released); + } + XFREE(MTYPE_ZEBRA_SRV6_USID_WLIB, + block->u.usid.wide_lib); + } else if (block->sid_format->type == + SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } + + XFREE(MTYPE_ZEBRA_SRV6_SID_BLOCK, block); +} + +/** + * Free an SRv6 SID block. + * + * @param val SRv6 SID block to be freed + */ +void delete_zebra_srv6_sid_block(void *val) +{ + zebra_srv6_sid_block_free((struct zebra_srv6_sid_block *)val); +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, block)) + if (prefix_match(prefix, &block->prefix)) + return block; + + return NULL; +} + +/* --- Zebra SRv6 SID management functions ---------------------------------- */ + +/** + * Alloc and fill an SRv6 SID. + * + * @param ctx Context associated with the SID to be created + * @param sid_value IPv6 address associated with the SID to be created + * @param locator Parent locator of the SID to be created + * @param sid_block Block from which the SID value has been allocated + * @param sid_func Function part of the SID to be created + * @param alloc_mode Allocation mode of the Function (dynamic vs explicit) + * @return The requested SID + */ +struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode) +{ + struct zebra_srv6_sid *sid; + + if (!ctx || !sid_value) + return NULL; + + sid = XCALLOC(MTYPE_ZEBRA_SRV6_SID, sizeof(struct zebra_srv6_sid)); + sid->ctx = ctx; + sid->value = *sid_value; + sid->locator = locator; + sid->block = sid_block; + sid->func = sid_func; + sid->alloc_mode = alloc_mode; + sid->client_list = list_new(); + + return sid; +} + +void zebra_srv6_sid_free(struct zebra_srv6_sid *sid) +{ + list_delete(&sid->client_list); + XFREE(MTYPE_ZEBRA_SRV6_SID, sid); +} + +/** + * Free an SRv6 SID. + * + * @param val SRv6 SID to be freed + */ +void delete_zebra_srv6_sid(void *val) +{ + zebra_srv6_sid_free((struct zebra_srv6_sid *)val); +} + void zebra_srv6_locator_add(struct srv6_locator *locator) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -121,7 +629,6 @@ void zebra_srv6_locator_add(struct srv6_locator *locator) void zebra_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct zserv *client; @@ -136,18 +643,8 @@ void zebra_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn( - "%s: Not found zclient(proto=%u, instance=%u).", - __func__, c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } listnode_delete(srv6->locators, locator); srv6_locator_free(locator); @@ -190,7 +687,6 @@ void zebra_notify_srv6_locator_add(struct srv6_locator *locator) void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zserv *client; /* @@ -204,17 +700,8 @@ void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn("Not found zclient(proto=%u, instance=%u).", - c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } } struct zebra_srv6 srv6; @@ -222,10 +709,32 @@ struct zebra_srv6 srv6; struct zebra_srv6 *zebra_srv6_get_default(void) { static bool first_execution = true; + struct srv6_sid_format *format_usidf3216; + struct srv6_sid_format *format_uncompressed; if (first_execution) { first_execution = false; srv6.locators = list_new(); + + /* Initialize list of SID formats */ + srv6.sid_formats = list_new(); + srv6.sid_formats->del = delete_srv6_sid_format; + + /* Create SID format `usid-f3216` */ + format_usidf3216 = create_srv6_sid_format_usid_f3216(); + srv6_sid_format_register(format_usidf3216); + + /* Create SID format `uncompressed` */ + format_uncompressed = create_srv6_sid_format_uncompressed(); + srv6_sid_format_register(format_uncompressed); + + /* Init list to store SRv6 SIDs */ + srv6.sids = list_new(); + srv6.sids->del = delete_zebra_srv6_sid_ctx; + + /* Init list to store SRv6 SID blocks */ + srv6.sid_blocks = list_new(); + srv6.sid_blocks->del = delete_zebra_srv6_sid_block; } return &srv6; } @@ -427,30 +936,1522 @@ void zebra_srv6_encap_src_addr_unset(void) memset(&srv6->encap_src_addr, 0, sizeof(struct in6_addr)); } -void zebra_srv6_terminate(void) +/* --- SRv6 SID Allocation/Release functions -------------------------------- */ + +/** + * Return the SRv6 SID obtained composing the locator and function. + * + * @param sid_value SRv6 SID address returned + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_compose(struct in6_addr *sid_value, + struct srv6_locator *locator, + uint32_t sid_func) { - struct srv6_locator *locator; + uint8_t offset, func_len; + struct srv6_sid_format *format; - if (!srv6.locators) - return; + if (!sid_value || !locator) + return false; - while (listcount(srv6.locators)) { - locator = listnode_head(srv6.locators); + format = locator->sid_format; + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = locator->block_bits_length + locator->node_bits_length; + func_len = locator->function_bits_length; + } + + *sid_value = locator->prefix.prefix; + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; - listnode_delete(srv6.locators, locator); - srv6_locator_free(locator); + sid_value->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); + if (sid_func >> (func_len - 1 - idx) & 0x1) + sid_value->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); } - list_delete(&srv6.locators); + return true; } -void zebra_srv6_init(void) +/** + * Return the parent locator and function of an SRv6 SID. + * + * @param sid_value SRv6 SID address to be decomposed + * @param sid_block Parent block of the SRv6 SID + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @param sid_wide_func Wide function of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_decompose(struct in6_addr *sid_value, + struct zebra_srv6_sid_block **sid_block, + struct srv6_locator **locator, + uint32_t *sid_func, uint32_t *sid_wide_func) { - hook_register(zserv_client_close, zebra_srv6_cleanup); - hook_register(srv6_manager_get_chunk, - zebra_srv6_manager_get_locator_chunk); - hook_register(srv6_manager_release_chunk, - zebra_srv6_manager_release_locator_chunk); + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *l; + struct zebra_srv6_sid_block *b; + struct srv6_sid_format *format; + struct listnode *node; + struct prefix_ipv6 tmp_prefix; + uint8_t offset, func_len; + + if (!sid_value || !sid_func) + return false; + + *sid_func = 0; + *sid_wide_func = 0; + + /* + * Build a temporary prefix_ipv6 object representing the SRv6 SID. + * This temporary prefix object is used below by the prefix_match + * function to check if the SID belongs to a specific locator. + */ + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = *sid_value; + + /* + * Lookup the parent locator of the SID and return the locator and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, l)) { + /* + * Check if the locator prefix includes the temporary prefix + * representing the SID. + */ + if (prefix_match((struct prefix *)&l->prefix, + (struct prefix *)&tmp_prefix)) { + format = l->sid_format; + + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = l->block_bits_length + + l->node_bits_length; + func_len = l->function_bits_length; + } + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((func_len - 1 - idx) / 8) * 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = l->sid_format; + + offset = format->block_len + + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / + 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * + 8); + } + } + } + + *locator = l; + *sid_block = l->sid_block; + + return true; + } + } + + /* + * If we arrive here, the SID does not belong to any locator. + * Then, let's try to find the parent block from which the SID + * has been allocated. + */ + + /* + * Lookup the parent block of the SID and return the block and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, b)) { + /* + * Check if the block prefix includes the temporary prefix + * representing the SID + */ + if (prefix_match((struct prefix *)&b->prefix, + (struct prefix *)&tmp_prefix)) { + format = b->sid_format; + + if (!format) + continue; + + offset = format->block_len + format->node_len; + func_len = format->function_len; + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << ((func_len - 1 - idx) / 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = b->sid_format; + + offset = format->block_len + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * 8); + } + } + + *sid_block = b; + + return true; + } + } + + return false; +} + +/** + * Allocate an explicit SID function (i.e. specific SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function to be allocated + * @param sid_wide_func SID wide function to be allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t wlib_end = format->config.usid.wlib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function has to be allocated from the ELIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = + zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.usid.lib.func_allocated, + sid_func_ptr); + block->u.usid.lib.num_func_allocated++; + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function has to be allocated from the EWLIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, + sid_wide_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + if (sid_wide_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_wide_func_ptr = zebra_srv6_sid_func_alloc( + sid_wide_func); + listnode_add(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + block->u.usid.wide_lib[sid_func] + .num_func_allocated++; + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_err("%s: invalid SM request arguments: SID function %u out of explicit range (%u - %u)", + __func__, sid_func, explicit_start, + explicit_end); + return false; + } + + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, + sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return true; +} + +/** + * Allocate a dynamic SID function (i.e. any available SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t *sid_func) +{ + struct srv6_sid_format *format; + uint32_t *sid_func_ptr = NULL; + + if (!block || !sid_func) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate dynamic SID function from block %pFX", + __func__, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + /* Format is uSID and behavior => allocate SID function from LIB range */ + + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.usid.lib.first_available_func > dlib_end) { + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted", + __func__); + return false; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.usid.lib.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.usid.lib.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.usid.lib.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = + block->u.usid.lib.first_available_func; + block->u.usid.lib.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.usid.lib.num_func_allocated++; + + if (block->u.usid.lib.first_available_func > dlib_end) + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted and next SID request will fail", + __func__); + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + /* Format is uncompressed => allocate SID function from Dynamic range */ + + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.uncompressed.first_available_func > + dynamic_end) { + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted", + __func__); + return NULL; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed + .first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + + if (block->u.uncompressed.first_available_func > + dynamic_end) + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted and next SID request will fail", + __func__); + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed.first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated dynamic SID function %u from block %pFX", + __func__, *sid_func, &block->prefix); + + return true; +} + +/** + * Get an explicit SID (i.e., a specific SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value specific SRv6 SID value (i.e. IPv6 address) to be + * allocated explicitly + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_explicit(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx = NULL; + struct listnode *node; + uint32_t sid_func = 0, sid_func_wide = 0; + struct srv6_locator *locator = NULL; + struct zebra_srv6_sid_block *block = NULL; + char buf[256]; + + if (!ctx || !sid_value) + return -1; + + /* Check if we already have a SID associated with the provided context */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + /* + * If the context is already associated with a SID that has the same SID value, then + * return the existing SID + */ + if (sid_same(&s->sid->value, sid_value)) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SRv6 SID %pI6 ctx %s", + __func__, &s->sid->value, + srv6_sid_ctx2str(buf, + sizeof(buf), + ctx)); + *sid = s->sid; + return 0; + } + + /* + * It is not allowed to allocate an explicit SID for a given context if the context + * is already associated with an explicit SID + */ + if (s->sid->alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { + zlog_err("%s: cannot alloc SID %pI6 for ctx %s: ctx already associated with SID %pI6", + __func__, sid_value, + srv6_sid_ctx2str(buf, sizeof(buf), + &s->ctx), + &s->sid->value); + return -1; + } + + zctx = s; + break; + } + } + + /* Get parent locator and function of the provided SID */ + if (!zebra_srv6_sid_decompose(sid_value, &block, &locator, &sid_func, + &sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: parent block/locator not found for SID %pI6", + __func__, sid_value); + return -1; + } + + if (ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + zlog_err("%s: invalid SM request arguments: explicit SID allocation not allowed for End/uN behavior", + __func__); + return -1; + } + + /* Allocate an explicit SID function for the SID */ + if (!alloc_srv6_sid_func_explicit(block, sid_func, sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + if (!zctx) { + /* If we don't have a zebra SID context for this context, allocate a new one */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + } else { + /* + * If we already have a SID associated with this context, we need to + * deallocate the current SID function before allocating the new one + */ + if (zctx->sid) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: ctx %s already associated with a dynamic SID %pI6, releasing dynamic SID", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &zctx->sid->value); + + release_srv6_sid_func_dynamic(block, zctx->sid->func); + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + } + } + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_EXPLICIT); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get a dynamic SID (i.e., any available SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param locator SRv6 locator from which the SID has to be allocated + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_dynamic(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct srv6_locator *locator) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct srv6_sid_format *format; + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node; + struct in6_addr sid_value; + uint32_t sid_func = 0; + char buf[256]; + + if (!ctx || !locator) + return -1; + + block = locator->sid_block; + format = locator->sid_format; + + /* + * If we already have a SID for the provided context, we return the existing + * SID instead of allocating a new one. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (locator && s->sid && s->sid->locator) { + if (strncmp(s->sid->locator->name, locator->name, + SRV6_LOCNAME_SIZE)) { + continue; + } + } + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SID %s %pI6", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &s->sid->value); + *sid = s->sid; + return 0; + } + } + + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID && + ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else if (!format && ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else { + /* Allocate a dynamic SID function for the SID */ + if (!alloc_srv6_sid_func_dynamic(block, &sid_func)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + /* Compose the SID as the locator followed by the SID function */ + zebra_srv6_sid_compose(&sid_value, locator, sid_func); + } + + /* Allocate a zebra SID context to store SID context information */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, &sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_DYNAMIC); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID ctx %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), &sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated new dynamic SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get an SRv6 SID for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * If the sid_value parameter is non-NULL, it allocates the requested SID value + * if it is available (explicit SID allocation). + * If the sid_value parameter is NULL, it allocates any available SID value + * (dynamic SID allocation). + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value SRv6 SID value to be allocated (for explicit SID allocation) + * @param locator_name Parent SRv6 locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name) +{ + int ret = -1; + struct srv6_locator *locator; + char buf[256]; + + enum srv6_sid_alloc_mode alloc_mode = + (sid_value) ? SRV6_SID_ALLOC_MODE_EXPLICIT + : SRV6_SID_ALLOC_MODE_DYNAMIC; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: received SRv6 SID alloc request: SID ctx %s (%pI6), mode=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value, srv6_sid_alloc_mode2str(alloc_mode)); + + if (alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { + /* + * Explicit SID allocation: allocate a specific SID value + */ + + if (!sid_value) { + zlog_err("%s: invalid SM request arguments: missing SRv6 SID value, necessary for explicit allocation", + __func__); + return -1; + } + + ret = get_srv6_sid_explicit(sid, ctx, sid_value); + } else { + /* + * Dynamic SID allocation: allocate any available SID value + */ + + if (!locator_name) { + zlog_err("%s: invalid SM request arguments: missing SRv6 locator, necessary for dynamic allocation", + __func__); + return -1; + } + + locator = zebra_srv6_locator_lookup(locator_name); + if (!locator) { + zlog_err("%s: invalid SM request arguments: SRv6 locator '%s' does not exist", + __func__, locator_name); + return -1; + } + + ret = get_srv6_sid_dynamic(sid, ctx, locator); + } + + return ret; +} + +/** + * Release an explicit SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static bool release_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = format->config.usid.wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function comes from the ELIB range */ + + /* Lookup SID function in the functions allocated list of ELIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the ELIB range */ + listnode_delete(block->u.usid.lib.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function comes from the EWLIB range */ + + /* Lookup SID function in the functions allocated list of EWLIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, sid_wide_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_wide_func_ptr) { + zlog_warn("%s: failed to release wide SID function %u, function is not allocated", + __func__, sid_wide_func); + return -1; + } + + /* Release the SID function from the EWLIB range */ + listnode_delete(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + zebra_srv6_sid_func_free(sid_wide_func_ptr); + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_warn("%s: function %u is outside explicit alloc range [%u/%u]", + __func__, sid_func, explicit_start, + explicit_end); + return -1; + } + + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Release a dynamic SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func) +{ + struct srv6_sid_format *format; + struct listnode *node, *nnode; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t dlib_start = format->config.usid.lib_start; + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic LIB (DLIB) range */ + if (!(sid_func >= dlib_start && sid_func <= dlib_end)) { + zlog_warn("%s: function %u is outside Dynamic LIB range [%u/%u]", + __func__, sid_func, dlib_start, dlib_end); + return -1; + } + + if (sid_func == block->u.usid.lib.first_available_func - 1) { + /* + * The SID function to be released precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.usid.lib.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.usid.lib + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.usid.lib.first_available_func - + 1) { + listnode_delete(block->u.usid + .lib + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.usid.lib + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The SID function to be released does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.usid.lib.func_released, + sid_func_ptr); + } + } else if (format && format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t dynamic_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + /* The Dynamic range ends where the Explicit range begins */ + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic range */ + if (!(sid_func >= dynamic_start && sid_func <= dynamic_end)) { + zlog_warn("%s: function %u is outside dynamic range [%u/%u]", + __func__, sid_func, dynamic_start, + dynamic_end); + return -1; + } + + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } else if (!format) { + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Core function, release the SRv6 SID associated with a given context. + * + * @param client The client for which the SID has to be released + * @param ctx Context associated with the SRv6 SID to be released + * @return 0 on success, -1 otherwise + */ +int release_srv6_sid(struct zserv *client, struct zebra_srv6_sid_ctx *zctx) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + char buf[256]; + + if (!zctx || !zctx->sid) + return -1; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* Ensures the SID is in use by the client */ + if (!listnode_lookup(zctx->sid->client_list, client)) { + flog_err(EC_ZEBRA_SM_DAEMON_MISMATCH, "%s: Daemon mismatch!!", + __func__); + return -1; + } + + /* Remove the client from the list of clients using the SID */ + listnode_delete(zctx->sid->client_list, client); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* + * If the SID is not used by any other client, then deallocate it + * and remove it from the SRv6 database. + */ + if (listcount(zctx->sid->client_list) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SRv6 SID %pI6 associated with ctx %s is no longer in use, removing it from SRv6 database", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), + &zctx->ctx)); + + if (!(zctx->sid->block->sid_format && + zctx->sid->block->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) && + !(!zctx->sid->block->sid_format && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END)) { + if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_EXPLICIT) + /* Release SRv6 SID function */ + release_srv6_sid_func_explicit(zctx->sid->block, + zctx->sid->func, + zctx->sid->wide_func); + else if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_DYNAMIC) + /* Release SRv6 SID function */ + release_srv6_sid_func_dynamic(zctx->sid->block, + zctx->sid->func); + else + /* We should never arrive here */ + assert(0); + } + + /* Free the SID */ + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + + /* Remove the SID context from the list and free memory */ + listnode_delete(srv6->sids, zctx); + zebra_srv6_sid_ctx_free(zctx); + } + + return 0; +} + +/** + * Handle a get SRv6 Locator request received from a client. + * + * It looks up the requested locator and send it to the client. + * + * @param locator SRv6 locator returned by this function + * @param client The client that sent the Get SRv6 Locator request + * @param locator_name Name of the locator to look up + * + * @return 0 on success + */ +static int srv6_manager_get_srv6_locator_internal(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + *locator = zebra_srv6_locator_lookup(locator_name); + if (!*locator) + return -1; + + return zsend_zebra_srv6_locator_add(client, *locator); +} + +/** + * Handle a get SID request received from a client. + * + * It gets a SID for a given context. If there is no SID associated with the context yet, + * we allocate one and return it to the client. Otherwise, we return the existing SID. + * + * - When the `sid_value` parameter is non-NULL, SRv6 Manager assigns the requested SID value + * if it is available (explicit SID allocation). + * - When the `sid_value` parameter is NULL, SRv6 Manager assigns any available SID value + * (dynamic SID allocation). + * + * Finally, notify the client whether the SID allocation was successful or failed. + * + * @param sid SID returned by this function + * @param client The client that requested the SID + * @param ctx Context for which the SID was requested + * @param sid_value SID value (i.e., IPv6 address) that has to be assigned to the SID + * (for explicit SID allocation) + * @param locator_name Locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 on success, -1 otherwise + */ +static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + int ret = -1; + struct listnode *node; + struct zserv *c; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: getting SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value ? sid_value : &in6addr_any, locator_name); + + ret = get_srv6_sid(sid, ctx, sid_value, locator_name); + if (ret < 0) { + zlog_warn("%s: not got SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value ? sid_value : &in6addr_any, locator_name); + + /* Notify client about SID alloc failure */ + zsend_srv6_sid_notify(client, ctx, sid_value, 0, 0, NULL, + ZAPI_SRV6_SID_FAIL_ALLOC); + } else if (ret == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got existing SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notify client", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + + zsend_srv6_sid_notify(client, ctx, &(*sid)->value, (*sid)->func, + (*sid)->wide_func, + (*sid)->locator ? (*sid)->locator->name + : NULL, + ZAPI_SRV6_SID_ALLOCATED); + } else { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got new SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notifying all clients", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + + for (ALL_LIST_ELEMENTS_RO((*sid)->client_list, node, c)) + zsend_srv6_sid_notify(c, ctx, &(*sid)->value, + (*sid)->func, (*sid)->wide_func, + (*sid)->locator + ? (*sid)->locator->name + : NULL, + ZAPI_SRV6_SID_ALLOCATED); + } + + return ret; +} + +/** + * Release SRv6 SIDs from a client. + * + * Called on client disconnection or reconnection. + * + * @param client The client to release SIDs from + * @return Number of SIDs released + */ +int release_daemon_srv6_sids(struct zserv *client) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + int count = 0; + int ret; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SIDs for client proto %s, instance %d, session %u", + __func__, zebra_route_string(client->proto), + client->instance, client->session_id); + + /* Iterate over the SIDs and release SIDs used by the client daemon */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!listnode_lookup(ctx->sid->client_list, client)) + continue; + + ret = release_srv6_sid(client, ctx); + if (ret == 0) + count++; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released %d SRv6 SIDs", __func__, count); + + return count; +} + +/** + * Release SRv6 SIDs from a client. + * + * @param client The client zapi session + * @param ctx Context associated with the SRv6 SID + * @return 0 on success, -1 on failure + */ +static int srv6_manager_release_sid_internal(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + int ret = -1; + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node, *nnode; + char buf[256]; + const char *locator_name = NULL; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID associated with ctx %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* Lookup Zebra SID context and release it */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, zctx)) + if (memcmp(&zctx->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (zctx->sid && zctx->sid->locator) + locator_name = + (const char *)zctx->sid->locator->name; + ret = release_srv6_sid(client, zctx); + break; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: no SID associated with ctx %s", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + if (ret == 0) + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, + ZAPI_SRV6_SID_RELEASED); + else + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, + ZAPI_SRV6_SID_FAIL_RELEASE); + + return ret; +} + +void zebra_srv6_terminate(void) +{ + struct srv6_locator *locator; + struct srv6_sid_format *format; + struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *sid_ctx; + + if (srv6.locators) { + while (listcount(srv6.locators)) { + locator = listnode_head(srv6.locators); + + listnode_delete(srv6.locators, locator); + srv6_locator_free(locator); + } + + list_delete(&srv6.locators); + } + + /* Free SRv6 SIDs */ + if (srv6.sids) { + while (listcount(srv6.sids)) { + sid_ctx = listnode_head(srv6.sids); + + listnode_delete(srv6.sids, sid_ctx); + zebra_srv6_sid_ctx_free(sid_ctx); + } + + list_delete(&srv6.sids); + } + + /* Free SRv6 SID blocks */ + if (srv6.sid_blocks) { + while (listcount(srv6.sid_blocks)) { + block = listnode_head(srv6.sid_blocks); + + listnode_delete(srv6.sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + + list_delete(&srv6.sid_blocks); + } + + /* Free SRv6 SID formats */ + if (srv6.sid_formats) { + while (listcount(srv6.sid_formats)) { + format = listnode_head(srv6.sid_formats); + + srv6_sid_format_unregister(format); + srv6_sid_format_free(format); + } + + list_delete(&srv6.sid_formats); + } +} + +void zebra_srv6_init(void) +{ + hook_register(zserv_client_close, zebra_srv6_cleanup); + hook_register(srv6_manager_get_chunk, + zebra_srv6_manager_get_locator_chunk); + hook_register(srv6_manager_release_chunk, + zebra_srv6_manager_release_locator_chunk); + + hook_register(srv6_manager_get_sid, srv6_manager_get_sid_internal); + hook_register(srv6_manager_release_sid, + srv6_manager_release_sid_internal); + hook_register(srv6_manager_get_locator, + srv6_manager_get_srv6_locator_internal); } bool zebra_srv6_is_enable(void) diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 21936c33..1599fd7a 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -16,12 +16,197 @@ #include #include +/* Default config for SRv6 SID `usid-f3216` format */ +#define SRV6_SID_FORMAT_USID_F3216_NAME "usid-f3216" +#define SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN 32 +#define SRV6_SID_FORMAT_USID_F3216_NODE_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_USID_F3216_LIB_START 0xE000 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_START 0xFE00 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_END 0xFEFF +#define SRV6_SID_FORMAT_USID_F3216_WLIB_START 0xFFF0 +#define SRV6_SID_FORMAT_USID_F3216_WLIB_END 0xFFF7 +#define SRV6_SID_FORMAT_USID_F3216_EWLIB_START 0xFFF7 + +/* Default config for SRv6 SID `uncompressed` format */ +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME "uncompressed-f4024" +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN 40 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN 24 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START 0xFF00 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN 0x40 + +/* uSID Wide LIB */ +struct wide_lib { + uint32_t func; + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; +}; + +/* + * SRv6 SID block. + * + * A SID block is an IPv6 prefix from which SRv6 SIDs are allocated. + * Example: + * SID block = fc00:0::/32 + * SID 1 = fc00:0:1:e000:: + * SID 2 = fc00:0:1:fe00:: + * ... + */ +struct zebra_srv6_sid_block { + /* Prefix of this block, e.g. fc00:0::/32 */ + struct prefix_ipv6 prefix; + + /* Reference counter */ + unsigned long refcnt; + + /* + * Pointer to the SID format that defines the structure of the SIDs + * allocated from this block + */ + struct srv6_sid_format *sid_format; + + /* + * Run-time information/state of this SID block. + * + * This includes stuff like how many SID functions have been allocated + * from this block, which functions are still available to be allocated + * and so on... + */ + union { + /* Information/state for compressed uSID format */ + struct { + /* uSID Local ID Block (LIB) */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } lib; + + /* uSID Wide LIB */ + struct wide_lib *wide_lib; + } usid; + + /* Information/state for uncompressed SID format */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } uncompressed; + } u; +}; + +/** + * The function part of an SRv6 SID can be allocated in one + * of the following ways: + * - dynamic: allocate any available function + * - explicit: allocate a specific function + */ +enum srv6_sid_alloc_mode { + SRV6_SID_ALLOC_MODE_UNSPEC = 0, + /* Dynamic SID allocation */ + SRV6_SID_ALLOC_MODE_DYNAMIC = 1, + /* Explicit SID allocation */ + SRV6_SID_ALLOC_MODE_EXPLICIT = 2, + SRV6_SID_ALLOC_MODE_MAX = 3, +}; + +/** + * Convert SID allocation mode to string. + * + * @param alloc_mode SID allocation mode + * @return String representing the allocation mode + */ +static inline const char * +srv6_sid_alloc_mode2str(enum srv6_sid_alloc_mode alloc_mode) +{ + switch (alloc_mode) { + case SRV6_SID_ALLOC_MODE_EXPLICIT: + return "explicit"; + case SRV6_SID_ALLOC_MODE_DYNAMIC: + return "dynamic"; + case SRV6_SID_ALLOC_MODE_UNSPEC: + return "unspec"; + case SRV6_SID_ALLOC_MODE_MAX: + default: + return "unknown"; + } +} + +/* SRv6 SID instance. */ +struct zebra_srv6_sid { + /* + * SID context associated with the SID. + * Defines behavior and attributes of the SID. + */ + struct zebra_srv6_sid_ctx *ctx; + + /* SID value (e.g. fc00:0:1:e000::) */ + struct in6_addr value; + + /* Pointer to the SRv6 locator from which the SID has been allocated */ + struct srv6_locator *locator; + + /* Pointer to the SRv6 block from which the SID has been allocated */ + struct zebra_srv6_sid_block *block; + + /* + * Function part of the SID + * Example: + * SID = fc00:0:1:e000:: => func = e000 + */ + uint32_t func; + + /* SID wide function. */ + uint32_t wide_func; + + /* SID allocation mode: dynamic or explicit */ + enum srv6_sid_alloc_mode alloc_mode; + + /* List of clients that are using the SID */ + struct list *client_list; +}; + +/* + * Zebra SRv6 SID context. + * A context defines a behavior and (optionally) some behavior-specific + * attributes. Client daemons (bgp, isis, ...) ask SRv6 Manager to allocate + * a SID for a particular context. SRv6 Manager is responsible for allocating + * a SID from a given SID block and associating with the context. + * + * Example: + * bgp asks to associate a SID to the context {behavior=End.DT46 vrf=Vrf10}. + * SRv6 Manager allocate SID fc00:0:1:e000:: for that context. + */ +struct zebra_srv6_sid_ctx { + /* SRv6 SID context information. */ + struct srv6_sid_ctx ctx; + + /* SID associated with the context. */ + struct zebra_srv6_sid *sid; +}; + /* SRv6 instance structure. */ struct zebra_srv6 { struct list *locators; /* Source address for SRv6 encapsulation */ struct in6_addr encap_src_addr; + + /* SRv6 SID formats */ + struct list *sid_formats; + + /* SRv6 SIDs */ + struct list *sids; + + /* SRv6 SID blocks */ + struct list *sid_blocks; }; /* declare hooks for the basic API, so that it can be specialized or served @@ -46,6 +231,17 @@ DECLARE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DECLARE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DECLARE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); +DECLARE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); extern void zebra_srv6_locator_add(struct srv6_locator *locator); extern void zebra_srv6_locator_delete(struct srv6_locator *locator); @@ -74,4 +270,55 @@ extern int release_daemon_srv6_locator_chunks(struct zserv *client); extern void zebra_srv6_encap_src_addr_set(struct in6_addr *src_addr); extern void zebra_srv6_encap_src_addr_unset(void); +void srv6_sid_format_register(struct srv6_sid_format *format); +void srv6_sid_format_unregister(struct srv6_sid_format *format); +struct srv6_sid_format *srv6_sid_format_lookup(const char *name); +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format); +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format); + +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func); +void zebra_srv6_sid_func_free(uint32_t *func); +void delete_zebra_srv6_sid_func(void *val); + +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, + struct prefix_ipv6 *prefix); +extern void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block); +extern void delete_zebra_srv6_sid_block(void *val); +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix); + +extern struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode); +extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid); +extern void delete_zebra_srv6_sid(void *val); + +extern void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx); + +extern void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name); + +extern int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name); +extern int release_srv6_sid(struct zserv *client, + struct zebra_srv6_sid_ctx *zctx); +extern int release_daemon_srv6_sids(struct zserv *client); +extern int srv6_manager_get_sid_response(struct zebra_srv6_sid *sid, + struct zserv *client); + +extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void); +extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx); +extern void delete_zebra_srv6_sid_ctx(void *val); + #endif /* _ZEBRA_SRV6_H */ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index d5cd30e6..5a805241 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -68,6 +68,27 @@ static struct cmd_node srv6_encap_node = { .prompt = "%s(config-srv6-encap)# " }; +static struct cmd_node srv6_sid_formats_node = { + .name = "srv6-formats", + .node = SRV6_SID_FORMATS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-formats)# ", +}; + +static struct cmd_node srv6_sid_format_usid_f3216_node = { + .name = "srv6-format-usid-f3216", + .node = SRV6_SID_FORMAT_USID_F3216_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .name = "srv6-format-uncompressed-f4024", + .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + DEFPY (show_srv6_manager, show_srv6_manager_cmd, "show segment-routing srv6 manager [json]", @@ -198,15 +219,32 @@ DEFUN (show_srv6_locator_detail, prefix2str(&locator->prefix, str, sizeof(str)); vty_out(vty, "Name: %s\n", locator->name); vty_out(vty, "Prefix: %s\n", str); - vty_out(vty, "Block-Bit-Len: %u\n", locator->block_bits_length); - vty_out(vty, "Node-Bit-Len: %u\n", locator->node_bits_length); - vty_out(vty, "Function-Bit-Len: %u\n", - locator->function_bits_length); - vty_out(vty, "Argument-Bit-Len: %u\n", - locator->argument_bits_length); + if (locator->sid_format) { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->sid_format->block_len); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->sid_format->node_len); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->sid_format->function_len); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->sid_format->argument_len); + + if (locator->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID) + vty_out(vty, "Behavior: uSID\n"); + } else { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->block_bits_length); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->node_bits_length); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->function_bits_length); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->argument_bits_length); - if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) - vty_out(vty, "Behavior: uSID\n"); + if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + vty_out(vty, "Behavior: uSID\n"); + } vty_out(vty, "Chunks:\n"); for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, @@ -248,9 +286,30 @@ DEFUN (no_srv6, struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct srv6_locator *locator; struct listnode *node, *nnode; + struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *ctx; + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) { + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } - for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) zebra_srv6_locator_delete(locator); + } return CMD_SUCCESS; } @@ -297,12 +356,37 @@ DEFUN (no_srv6_locator, "Segment Routing SRv6 locator\n" "Specify locator-name\n") { + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg); if (!locator) { vty_out(vty, "%% Can't find SRv6 locator\n"); return CMD_WARNING_CONFIG_FAILED; } + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } + zebra_srv6_locator_delete(locator); return CMD_SUCCESS; } @@ -323,14 +407,37 @@ DEFPY (locator_prefix, VTY_DECLVAR_CONTEXT(srv6_locator, locator); struct srv6_locator_chunk *chunk = NULL; struct listnode *node = NULL; + uint8_t expected_prefixlen; + struct srv6_sid_format *format; locator->prefix = *prefix; func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH; + expected_prefixlen = prefix->prefixlen; + format = locator->sid_format; + if (format) { + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format->name, + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + } + + if (prefix->prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + prefix->prefixlen, format->name); + return CMD_WARNING_CONFIG_FAILED; + } + /* Resolve optional arguments */ if (block_bit_len == 0 && node_bit_len == 0) { - block_bit_len = - prefix->prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH; + block_bit_len = prefix->prefixlen - + ZEBRA_SRV6_LOCATOR_NODE_LENGTH; node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH; } else if (block_bit_len == 0) { block_bit_len = prefix->prefixlen - node_bit_len; @@ -401,7 +508,8 @@ DEFPY (locator_prefix, } } - zebra_srv6_locator_add(locator); + zebra_srv6_locator_format_set(locator, locator->sid_format); + return CMD_SUCCESS; } @@ -422,8 +530,9 @@ DEFPY (locator_behavior, /* SRv6 locator uSID flag already set, nothing to do */ return CMD_SUCCESS; - /* Remove old locator from zclients */ - zebra_notify_srv6_locator_delete(locator); + if (!locator->sid_format) + /* Remove old locator from zclients */ + zebra_notify_srv6_locator_delete(locator); /* Set/Unset the SRV6_LOCATOR_USID */ if (no) @@ -431,8 +540,75 @@ DEFPY (locator_behavior, else SET_FLAG(locator->flags, SRV6_LOCATOR_USID); - /* Notify the new locator to zclients */ - zebra_notify_srv6_locator_add(locator); + if (!locator->sid_format) + /* Notify the new locator to zclients */ + zebra_srv6_locator_add(locator); + + return CMD_SUCCESS; +} + +DEFPY(locator_sid_format, + locator_sid_format_cmd, + "format $format", + "Configure SRv6 SID format\n" + "Specify usid-f3216 format\n" + "Specify uncompressed-f4024 format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + struct srv6_sid_format *sid_format = NULL; + uint8_t expected_prefixlen; + + expected_prefixlen = locator->prefix.prefixlen; + if (strmatch(format, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + + if (IPV6_ADDR_SAME(&locator->prefix, &in6addr_any)) { + vty_out(vty, + "%% Unexpected configuration sequence: the prefix of the locator is required before configuring the format. Please configure the prefix first and then configure the format.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (locator->prefix.prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + locator->prefix.prefixlen, format); + return CMD_WARNING_CONFIG_FAILED; + } + + sid_format = srv6_sid_format_lookup(format); + if (!sid_format) { + vty_out(vty, "%% Cannot find SRv6 SID format '%s'\n", format); + return CMD_WARNING_CONFIG_FAILED; + } + + if (sid_format == locator->sid_format) + /* Format has not changed, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, sid_format); + + return CMD_SUCCESS; +} + +DEFPY (no_locator_sid_format, + no_locator_sid_format_cmd, + "no format [WORD]", + NO_STR + "Configure SRv6 SID format\n" + "Specify SRv6 SID format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + + if (!locator->sid_format) + /* SID format already unset, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, NULL); return CMD_SUCCESS; } @@ -469,11 +645,312 @@ DEFPY (no_srv6_src_addr, return CMD_SUCCESS; } +DEFUN_NOSH(srv6_sid_formats, + srv6_sid_formats_cmd, + "formats", + "Segment Routing SRv6 SID formats\n") +{ + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f3216_usid, + srv6_sid_format_f3216_usid_cmd, + "format usid-f3216", + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_USID_F3216_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f3216_usid, + no_srv6_sid_format_f3216_usid_cmd, + "no format usid-f3216", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f4024_uncompressed, + srv6_sid_format_uncompressed_cmd, + "format uncompressed-f4024", + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f4024_uncompressed, + no_srv6_sid_format_f4024_uncompressed_cmd, + "no format uncompressed-f4024", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + format->config.uncompressed.explicit_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib, + srv6_sid_format_usid_lib_cmd, + "local-id-block start (0-4294967295)$start", + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.lib_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib, + no_srv6_sid_format_usid_lib_cmd, + "no local-id-block [start (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.lib_start = + SRV6_SID_FORMAT_USID_F3216_LIB_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib_explicit, + srv6_sid_format_usid_lib_explicit_cmd, + "local-id-block explicit start (0-4294967295)$start end (0-4294967295)$end", + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.elib_start = start; + format->config.usid.elib_end = end; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib_explicit, + no_srv6_sid_format_usid_lib_explicit_cmd, + "no local-id-block explicit [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.elib_start = + SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = + SRV6_SID_FORMAT_USID_F3216_ELIB_END; + } else { + assert(0); + } + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wlib, + srv6_sid_format_usid_wlib_cmd, + "wide-local-id-block start (0-4294967295)$start end (0-4294967295)$end", + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.wlib_start = start; + format->config.usid.wlib_end = end; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wlib, + no_srv6_sid_format_usid_wlib_cmd, + "no wide-local-id-block [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.wlib_start = + SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = + SRV6_SID_FORMAT_USID_F3216_WLIB_END; + } else { + assert(0); + } + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wide_lib_explicit, + srv6_sid_format_usid_wide_lib_explicit_cmd, + "wide-local-id-block explicit start (0-4294967295)$start", + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.ewlib_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wide_lib_explicit, + no_srv6_sid_format_usid_wide_lib_explicit_cmd, + "no wide-local-id-block explicit [start (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_explicit, + srv6_sid_format_explicit_cmd, + "explicit start (0-4294967295)$start", + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.uncompressed.explicit_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_explicit, + no_srv6_sid_format_explicit_cmd, + "no explicit [start (0-4294967295)$start]", + NO_STR + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + static int zebra_sr_config(struct vty *vty) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct listnode *node; struct srv6_locator *locator; + struct srv6_sid_format *format; char str[256]; bool display_source_srv6 = false; @@ -492,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, @@ -515,6 +992,54 @@ static int zebra_sr_config(struct vty *vty) vty_out(vty, "\n"); if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) vty_out(vty, " behavior usid\n"); + if (locator->sid_format) { + format = locator->sid_format; + vty_out(vty, " format %s\n", format->name); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); + vty_out(vty, " formats\n"); + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) { + if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + vty_out(vty, " format %s\n", format->name); + if (format->config.uncompressed.explicit_start != + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START) + vty_out(vty, " explicit start %u\n", + format->config.uncompressed + .explicit_start); + } + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + vty_out(vty, " format %s\n", format->name); + if (format->config.usid.lib_start != + SRV6_SID_FORMAT_USID_F3216_LIB_START) + vty_out(vty, + " local-id-block start %u\n", + format->config.usid.lib_start); + if (format->config.usid.elib_start != + SRV6_SID_FORMAT_USID_F3216_ELIB_START || + format->config.usid.elib_end != + SRV6_SID_FORMAT_USID_F3216_ELIB_END) + vty_out(vty, + " local-id-block explicit start %u end %u\n", + format->config.usid.elib_start, + format->config.usid.elib_end); + if (format->config.usid.wlib_start != + SRV6_SID_FORMAT_USID_F3216_WLIB_START || + format->config.usid.wlib_end != + SRV6_SID_FORMAT_USID_F3216_WLIB_END) + vty_out(vty, + " wide-local-id-block start %u end %u\n", + format->config.usid.wlib_start, + format->config.usid.wlib_end); + if (format->config.usid.ewlib_start != + SRV6_SID_FORMAT_USID_F3216_EWLIB_START) + vty_out(vty, + " wide-local-id-block explicit start %u\n", + format->config.usid.ewlib_start); + } vty_out(vty, " exit\n"); vty_out(vty, " !\n"); } @@ -538,11 +1063,17 @@ void zebra_srv6_vty_init(void) install_node(&srv6_locs_node); install_node(&srv6_loc_node); install_node(&srv6_encap_node); + install_node(&srv6_sid_formats_node); + install_node(&srv6_sid_format_usid_f3216_node); + install_node(&srv6_sid_format_uncompressed_f4024_node); install_default(SEGMENT_ROUTING_NODE); install_default(SRV6_NODE); install_default(SRV6_LOCS_NODE); install_default(SRV6_LOC_NODE); install_default(SRV6_ENCAP_NODE); + install_default(SRV6_SID_FORMATS_NODE); + install_default(SRV6_SID_FORMAT_USID_F3216_NODE); + install_default(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE); /* Command for change node */ install_element(CONFIG_NODE, &segment_routing_cmd); @@ -550,14 +1081,44 @@ void zebra_srv6_vty_init(void) install_element(SEGMENT_ROUTING_NODE, &no_srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); install_element(SRV6_NODE, &srv6_encap_cmd); + install_element(SRV6_NODE, &srv6_sid_formats_cmd); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd); + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f4024_uncompressed_cmd); /* Command for configuration */ install_element(SRV6_LOC_NODE, &locator_prefix_cmd); install_element(SRV6_LOC_NODE, &locator_behavior_cmd); + install_element(SRV6_LOC_NODE, &locator_sid_format_cmd); + install_element(SRV6_LOC_NODE, &no_locator_sid_format_cmd); install_element(SRV6_ENCAP_NODE, &srv6_src_addr_cmd); install_element(SRV6_ENCAP_NODE, &no_srv6_src_addr_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &srv6_sid_format_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &no_srv6_sid_format_explicit_cmd); /* Command for operation */ install_element(VIEW_NODE, &show_srv6_locator_cmd); diff --git a/zebra/zebra_trace.h b/zebra/zebra_trace.h index 17528c4b..64515624 100644 --- a/zebra/zebra_trace.h +++ b/zebra/zebra_trace.h @@ -68,20 +68,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, diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 5cbfab1d..f97138c8 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 ae82d201..303146c2 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"); } @@ -3794,6 +3802,10 @@ static int config_write_protocol(struct vty *vty) if (!zebra_nhg_recursive_use_backups()) vty_out(vty, "no zebra nexthop resolve-via-backup\n"); +#ifdef HAVE_SCRIPTING + frrscript_names_config_write(vty); +#endif + if (rnh_get_hide_backups()) vty_out(vty, "ip nht hide-backup-events\n"); @@ -3825,6 +3837,20 @@ DEFUN (show_zebra, struct vrf *vrf; struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); char *out; + char timebuf[MONOTIME_STRLEN]; + + time_to_string(zrouter.startup_time, timebuf); + vty_out(vty, "Zebra started%s at time %s", + zrouter.graceful_restart ? " gracefully" : "", timebuf); + + if (zrouter.t_rib_sweep) + vty_out(vty, + "Zebra RIB sweep timer running, remaining time %lds\n", + event_timer_remain_second(zrouter.t_rib_sweep)); + else { + time_to_string(zrouter.rib_sweep_time, timebuf); + vty_out(vty, "Zebra RIB sweep happened at %s", timebuf); + } ttable_rowseps(table, 0, BOTTOM, true, '-'); ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get()); @@ -3895,7 +3921,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, @@ -4129,12 +4155,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) { @@ -4311,14 +4331,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", @@ -4331,7 +4343,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/zebra_vxlan.c b/zebra/zebra_vxlan.c index b8c11e18..f1ae42e3 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1356,6 +1356,18 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, { struct zebra_mac *zrmac = NULL; struct ipaddr *vtep = NULL; + struct ipaddr ipv4_vtep; + + /* vtep_ip may be v4 or v6-mapped-v4. But zrmac->fwd_info + * can only contain v4 version. So convert if needed + */ + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep_ip->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4); zrmac = zl3vni_rmac_lookup(zl3vni, rmac); if (!zrmac) { @@ -1369,7 +1381,7 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, return -1; } memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1383,14 +1395,14 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); } else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &vtep_ip->ipaddr_v4)) { + &(ipv4_vtep.ipaddr_v4))) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "L3VNI %u Remote VTEP change(%pI4 -> %pIA) for RMAC %pEA", zl3vni->vni, &zrmac->fwd_info.r_vtep_ip, vtep_ip, rmac); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1410,36 +1422,29 @@ static void zl3vni_remote_rmac_del(struct zebra_l3vni *zl3vni, struct zebra_mac *zrmac, struct ipaddr *vtep_ip) { - struct ipaddr ipv4_vtep; - if (!zl3vni_nh_lookup(zl3vni, vtep_ip)) { - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &ipv4_vtep.ipaddr_v4); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - /* remove nh from rmac's list */ - l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, &ipv4_vtep); - /* delete nh is same as current selected, fall back to - * one present in the list - */ - if (IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &ipv4_vtep.ipaddr_v4) && - listcount(zrmac->nh_list)) { + l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, vtep_ip); + /* If there are remaining entries, use IPv4 from one */ + if (listcount(zrmac->nh_list)) { struct ipaddr *vtep; + struct ipaddr ipv4_vtep; vtep = listgetdata(listhead(zrmac->nh_list)); - zrmac->fwd_info.r_vtep_ip = vtep->ipaddr_v4; + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), + &vtep->ipaddr_v4); + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", - zl3vni->vni, &ipv4_vtep, - &zrmac->fwd_info.r_vtep_ip, - &zrmac->macaddr); + zlog_debug("L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", + zl3vni->vni, vtep_ip, + &zrmac->fwd_info.r_vtep_ip, + &zrmac->macaddr); /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); @@ -2531,7 +2536,6 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, const struct prefix *host_prefix) { struct zebra_l3vni *zl3vni = NULL; - struct ipaddr ipv4_vtep; zl3vni = zl3vni_from_vrf(vrf_id); if (!zl3vni || !is_l3vni_oper_up(zl3vni)) @@ -2547,24 +2551,10 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, svd_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); /* - * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 - * address. Rmac is programmed against the ipv4 vtep because we only - * support ipv4 tunnels in the h/w right now - */ - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &(ipv4_vtep.ipaddr_v4)); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - - /* - * add the rmac - remote rmac to be installed is against the ipv4 + * add the rmac - remote rmac to be installed is against the * nexthop address */ - zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep); + zl3vni_remote_rmac_add(zl3vni, rmac, vtep_ip); } /* handle evpn vrf route delete */ diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c index f4b859b8..17ab05c1 100644 --- a/zebra/zebra_vxlan_if.c +++ b/zebra/zebra_vxlan_if.c @@ -208,13 +208,13 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); return 0; } - if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_MAC_CHANGE) && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zebra_vxlan_process_l3vni_oper_up(zl3vni); @@ -224,7 +224,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, /* access-vlan change - process oper down, associate with new * svi_if and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->svi_if = NULL; @@ -242,7 +242,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * local-ip change - process oper down, associate with new * local-ip and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_LOCAL_IP_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->local_vtep_ip = vxl->vtep_ip; @@ -262,7 +262,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, zl3vni_bridge_if_set(zl3vni, br_if, true /* set */); /* if we have a valid new master, process l3-vni oper up */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) { if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); } @@ -285,7 +285,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { /* Delete from client, remove all remote VTEPs */ /* Also, free up all MACs and neighbors. */ @@ -298,7 +298,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, } /* Handle other changes. */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { /* Remove all existing local neigh and MACs for this VNI * (including from BGP) */ @@ -341,9 +341,10 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, return 0; /* Inform BGP, if there is a change of interest. */ - if (chgflags & - (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE | - ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE)) + if (CHECK_FLAG(chgflags, (ZEBRA_VXLIF_MASTER_CHANGE | + ZEBRA_VXLIF_LOCAL_IP_CHANGE | + ZEBRA_VXLIF_MCAST_GRP_CHANGE | + ZEBRA_VXLIF_VLAN_CHANGE))) zebra_evpn_send_add_to_client(zevpn); /* If there is a valid new master or a VLAN mapping change, @@ -351,9 +352,9 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * Also, reinstall any remote MACs and neighbors * for this VNI (based on new VLAN). */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) zebra_evpn_read_mac_neigh(zevpn, ifp); - else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + else if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { struct neigh_walk_ctx n_wctx; zebra_evpn_read_mac_neigh(zevpn, ifp); diff --git a/zebra/zserv.c b/zebra/zserv.c index 27668534..07e39966 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); @@ -1031,6 +1035,7 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen) /* Display client info details */ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) { + struct client_gr_info *info; char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; time_t connect_time, last_read_time, last_write_time; @@ -1125,6 +1130,45 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) vty_out(vty, "ES-EVI %-12u%-12u%-12u\n", client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt); vty_out(vty, "Errors: %u\n", client->error_cnt); + + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + afi_t afi; + bool route_sync_done = true; + char timebuf[MONOTIME_STRLEN]; + + vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); + vty_out(vty, "Capabilities : "); + switch (info->capabilities) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + vty_out(vty, "Graceful Restart\n"); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + case ZEBRA_CLIENT_GR_DISABLE: + case ZEBRA_CLIENT_RIB_STALE_TIME: + vty_out(vty, "None\n"); + break; + } + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + if (info->af_enabled[afi]) { + if (info->route_sync[afi]) + vty_out(vty, + "AFI %d enabled, route sync DONE\n", + afi); + else { + vty_out(vty, + "AFI %d enabled, route sync NOT DONE\n", + afi); + route_sync_done = false; + } + } + } + if (route_sync_done) { + time_to_string(info->route_sync_done_time, timebuf); + vty_out(vty, "Route sync finished at %s", timebuf); + } + } + vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n", client->ibuf_fifo->count, client->ibuf_fifo->max_count, client->obuf_fifo->count, client->obuf_fifo->max_count); diff --git a/zebra/zserv.h b/zebra/zserv.h index 57d67306..87d2b4ad 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -64,6 +64,8 @@ struct client_gr_info { /* Book keeping */ void *stale_client_ptr; struct event *t_stale_removal; + void *client_ptr; + time_t route_sync_done_time; TAILQ_ENTRY(client_gr_info) gr_info; }; -- cgit v1.2.3