summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/labeler.yml2
-rw-r--r--.github/workflows/base-branch-label.yml1
-rw-r--r--.github/workflows/conflicts.yml1
-rw-r--r--.github/workflows/docker-daily-master.yml52
-rw-r--r--.github/workflows/docker-stable.yml53
-rw-r--r--.github/workflows/labeler.yml20
-rw-r--r--.github/workflows/mergifyio_backport.yml22
-rw-r--r--.github/workflows/size-label.yml26
-rw-r--r--.github/workflows/stale.yml1
-rw-r--r--bfdd/bfd_packet.c2
-rw-r--r--bgpd/bgp_addpath.c26
-rw-r--r--bgpd/bgp_aspath.c27
-rw-r--r--bgpd/bgp_aspath.h1
-rw-r--r--bgpd/bgp_attr.c256
-rw-r--r--bgpd/bgp_attr.h40
-rw-r--r--bgpd/bgp_debug.c174
-rw-r--r--bgpd/bgp_ecommunity.c9
-rw-r--r--bgpd/bgp_evpn.c1
-rw-r--r--bgpd/bgp_evpn_mh.c52
-rw-r--r--bgpd/bgp_evpn_vty.c18
-rw-r--r--bgpd/bgp_flowspec_vty.c12
-rw-r--r--bgpd/bgp_fsm.c282
-rw-r--r--bgpd/bgp_fsm.h3
-rw-r--r--bgpd/bgp_keepalives.c16
-rw-r--r--bgpd/bgp_mpath.c22
-rw-r--r--bgpd/bgp_mplsvpn.c96
-rw-r--r--bgpd/bgp_mplsvpn_snmp.c8
-rw-r--r--bgpd/bgp_network.c6
-rw-r--r--bgpd/bgp_nexthop.c26
-rw-r--r--bgpd/bgp_nht.c139
-rw-r--r--bgpd/bgp_open.c18
-rw-r--r--bgpd/bgp_packet.c15
-rw-r--r--bgpd/bgp_pbr.c5
-rw-r--r--bgpd/bgp_route.c275
-rw-r--r--bgpd/bgp_route.h13
-rw-r--r--bgpd/bgp_routemap.c27
-rw-r--r--bgpd/bgp_snmp.c858
-rw-r--r--bgpd/bgp_snmp.h32
-rw-r--r--bgpd/bgp_snmp_bgp4.c814
-rw-r--r--bgpd/bgp_snmp_bgp4.h90
-rw-r--r--bgpd/bgp_snmp_bgp4v2.c1419
-rw-r--r--bgpd/bgp_snmp_bgp4v2.h100
-rw-r--r--bgpd/bgp_trace.h65
-rw-r--r--bgpd/bgp_updgrp.c317
-rw-r--r--bgpd/bgp_updgrp.h8
-rw-r--r--bgpd/bgp_updgrp_adv.c25
-rw-r--r--bgpd/bgp_updgrp_packet.c40
-rw-r--r--bgpd/bgp_vty.c374
-rw-r--r--bgpd/bgp_vty.h16
-rw-r--r--bgpd/bgp_zebra.c136
-rw-r--r--bgpd/bgpd.c111
-rw-r--r--bgpd/bgpd.h7
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c12
-rw-r--r--bgpd/rfapi/rfapi.c8
-rw-r--r--bgpd/rfapi/rfapi_import.c3
-rw-r--r--bgpd/rfapi/rfapi_vty.c52
-rw-r--r--bgpd/subdir.am5
-rw-r--r--configure.ac21
-rw-r--r--debian/changelog6
-rwxr-xr-xdebian/rules6
-rw-r--r--doc/accords/README.md32
-rw-r--r--doc/accords/cli-colors44
-rw-r--r--doc/accords/frr-service-is-watchfrr16
-rw-r--r--doc/accords/integrated-config-wins10
-rw-r--r--doc/developer/building-frr-for-freebsd13.rst122
-rw-r--r--doc/developer/building.rst3
-rw-r--r--doc/developer/fpm.rst16
-rw-r--r--doc/developer/frr-release-procedure.rst3
-rw-r--r--doc/developer/packaging-debian.rst2
-rw-r--r--doc/developer/packaging-redhat.rst1
-rw-r--r--doc/developer/subdir.am1
-rw-r--r--doc/developer/workflow.rst41
-rw-r--r--doc/user/basic.rst4
-rw-r--r--doc/user/bgp.rst42
-rw-r--r--doc/user/evpn.rst504
-rw-r--r--doc/user/index.rst1
-rw-r--r--doc/user/ospfd.rst9
-rw-r--r--doc/user/setup.rst10
-rw-r--r--doc/user/snmp.rst61
-rw-r--r--doc/user/subdir.am1
-rw-r--r--doc/user/vrrp.rst23
-rw-r--r--doc/user/zebra.rst20
-rw-r--r--docker/alpine/Dockerfile6
-rw-r--r--include/subdir.am1
-rw-r--r--isisd/isis_spf.c2
-rw-r--r--ldpd/ldpe.c2
-rw-r--r--lib/agentx.c19
-rw-r--r--lib/compiler.h39
-rw-r--r--lib/if.c26
-rw-r--r--lib/if.h1
-rw-r--r--lib/lib_vty.c12
-rw-r--r--lib/libospf.h1
-rw-r--r--lib/link_state.c2
-rw-r--r--lib/linklist.c31
-rw-r--r--lib/linklist.h31
-rw-r--r--lib/log.c25
-rw-r--r--lib/prefix.h16
-rw-r--r--lib/privs.c39
-rw-r--r--lib/smux.h15
-rw-r--r--lib/srv6.c9
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/tc.c88
-rw-r--r--lib/tc.h151
-rw-r--r--lib/vrf.c1
-rw-r--r--lib/vty.c3
-rw-r--r--lib/workqueue.c7
-rw-r--r--lib/workqueue.h5
-rw-r--r--lib/zclient.c91
-rw-r--r--lib/zclient.h6
-rw-r--r--lib/zlog_targets.c4
-rw-r--r--m4/ax_lua.m42
-rw-r--r--ospf6d/ospf6_abr.c2
-rw-r--r--ospf6d/ospf6_asbr.c31
-rw-r--r--ospf6d/ospf6_asbr.h2
-rw-r--r--ospf6d/ospf6_interface.c6
-rw-r--r--ospf6d/ospf6_lsa.c4
-rw-r--r--ospf6d/ospf6_message.c3
-rw-r--r--ospf6d/ospf6_neighbor.c65
-rw-r--r--ospf6d/ospf6_nssa.c48
-rw-r--r--ospf6d/ospf6_route.c41
-rw-r--r--ospf6d/ospf6_route.h12
-rw-r--r--ospf6d/ospf6_top.c8
-rw-r--r--ospfclient/ospf_apiclient.c4
-rw-r--r--ospfclient/subdir.am1
-rw-r--r--ospfd/ospf_api.h2
-rw-r--r--ospfd/ospf_apiserver.c31
-rw-r--r--ospfd/ospf_apiserver.h4
-rw-r--r--ospfd/ospf_ism.c12
-rw-r--r--ospfd/ospf_lsa.c13
-rw-r--r--ospfd/ospf_network.c11
-rw-r--r--ospfd/ospf_packet.c4
-rw-r--r--ospfd/ospf_snmp.c6
-rw-r--r--ospfd/ospf_spf.c75
-rw-r--r--ospfd/ospf_vty.c120
-rw-r--r--ospfd/ospfd.c25
-rw-r--r--ospfd/subdir.am8
-rw-r--r--pathd/path_pcep_config.c3
-rw-r--r--pimd/pim_cmd_common.c81
-rw-r--r--pimd/pim_ifchannel.c5
-rw-r--r--pimd/pim_join.c34
-rw-r--r--pimd/pim_msdp_packet.c44
-rw-r--r--pimd/pim_oil.c4
-rw-r--r--pimd/pim_register.c3
-rw-r--r--pimd/pim_ssm.c3
-rw-r--r--pimd/pim_upstream.c2
-rw-r--r--pimd/pim_util.c4
-rw-r--r--redhat/frr.spec.in17
-rw-r--r--sharpd/sharp_vty.c61
-rw-r--r--sharpd/sharp_zebra.c122
-rw-r--r--sharpd/sharp_zebra.h5
-rw-r--r--staticd/static_nb_config.c2
-rw-r--r--staticd/static_vty.c652
-rw-r--r--staticd/static_zebra.c1
-rw-r--r--tests/lib/test_heavy_wq.c6
-rw-r--r--tests/topotests/bfd_topo1/test_bfd_topo1.py2
-rw-r--r--tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py22
-rw-r--r--tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py54
-rw-r--r--tests/topotests/bgp_comm_list_match/__init__.py0
-rw-r--r--tests/topotests/bgp_comm_list_match/r1/bgpd.conf23
-rw-r--r--tests/topotests/bgp_comm_list_match/r1/zebra.conf11
-rw-r--r--tests/topotests/bgp_comm_list_match/r2/bgpd.conf21
-rw-r--r--tests/topotests/bgp_comm_list_match/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py119
-rw-r--r--tests/topotests/bgp_confed1/__init__.py0
-rw-r--r--tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json63
-rw-r--r--tests/topotests/bgp_confed1/r1/bgp_summary.json13
-rw-r--r--tests/topotests/bgp_confed1/r1/bgpd.conf13
-rw-r--r--tests/topotests/bgp_confed1/r1/isisd.conf0
-rw-r--r--tests/topotests/bgp_confed1/r1/zebra.conf6
-rw-r--r--tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json63
-rw-r--r--tests/topotests/bgp_confed1/r2/bgp_summary.json18
-rw-r--r--tests/topotests/bgp_confed1/r2/bgpd.conf18
-rw-r--r--tests/topotests/bgp_confed1/r2/isisd.conf8
-rw-r--r--tests/topotests/bgp_confed1/r2/zebra.conf9
-rw-r--r--tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json77
-rw-r--r--tests/topotests/bgp_confed1/r3/bgp_summary.json18
-rw-r--r--tests/topotests/bgp_confed1/r3/bgpd.conf17
-rw-r--r--tests/topotests/bgp_confed1/r3/isisd.conf8
-rw-r--r--tests/topotests/bgp_confed1/r3/zebra.conf10
-rw-r--r--tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json77
-rw-r--r--tests/topotests/bgp_confed1/r4/bgp_summary.json13
-rw-r--r--tests/topotests/bgp_confed1/r4/bgpd.conf14
-rw-r--r--tests/topotests/bgp_confed1/r4/isisd.conf0
-rw-r--r--tests/topotests/bgp_confed1/r4/zebra.conf6
-rw-r--r--tests/topotests/bgp_confed1/test_bgp_confed1.py129
-rw-r--r--tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py18
-rw-r--r--tests/topotests/bgp_features/test_bgp_features.py12
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py14
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf48
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/staticd.conf6
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf11
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py21
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py50
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py131
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/__init__.py0
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r1/bgpd.conf14
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r1/zebra.conf7
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r2/bgpd.conf14
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r2/zebra.conf7
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r3/bgpd.conf35
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r3/zebra.conf13
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r4/bgpd.conf10
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r4/zebra.conf4
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r5/bgpd.conf14
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/r5/zebra.conf7
-rw-r--r--tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py179
-rw-r--r--tests/topotests/bgp_labeled_unicast_default_originate/__init__.py0
-rw-r--r--tests/topotests/bgp_labeled_unicast_default_originate/r1/bgpd.conf21
-rw-r--r--tests/topotests/bgp_labeled_unicast_default_originate/r1/zebra.conf4
-rw-r--r--tests/topotests/bgp_labeled_unicast_default_originate/r2/bgpd.conf11
-rw-r--r--tests/topotests/bgp_labeled_unicast_default_originate/r2/zebra.conf4
-rw-r--r--tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py122
-rw-r--r--tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py63
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf17
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf1
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf13
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py40
-rw-r--r--tests/topotests/bgp_path_selection/__init__.py0
-rw-r--r--tests/topotests/bgp_path_selection/r1/bgpd.conf28
-rw-r--r--tests/topotests/bgp_path_selection/r1/ldpd.conf26
-rw-r--r--tests/topotests/bgp_path_selection/r1/staticd.conf2
-rw-r--r--tests/topotests/bgp_path_selection/r1/zebra.conf11
-rw-r--r--tests/topotests/bgp_path_selection/r2/bgpd.conf25
-rw-r--r--tests/topotests/bgp_path_selection/r2/ldpd.conf26
-rw-r--r--tests/topotests/bgp_path_selection/r2/staticd.conf0
-rw-r--r--tests/topotests/bgp_path_selection/r2/zebra.conf7
-rw-r--r--tests/topotests/bgp_path_selection/r3/bgpd.conf25
-rw-r--r--tests/topotests/bgp_path_selection/r3/ldpd.conf24
-rw-r--r--tests/topotests/bgp_path_selection/r3/staticd.conf0
-rw-r--r--tests/topotests/bgp_path_selection/r3/zebra.conf7
-rw-r--r--tests/topotests/bgp_path_selection/test_bgp_path_selection.py233
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/__init__.py0
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf8
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf7
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf8
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf7
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf5
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf4
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py120
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf31
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf5
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf23
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf17
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf5
-rwxr-xr-xtests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py248
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf0
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf9
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf41
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json31
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json25
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json22
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json27
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf27
-rwxr-xr-xtests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py128
-rwxr-xr-xtests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf2
-rwxr-xr-xtests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py34
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py46
-rw-r--r--tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py7
-rw-r--r--tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py4
-rw-r--r--tests/topotests/bgp_unnumbered/__init__.py0
-rw-r--r--tests/topotests/bgp_unnumbered/r1/bgpd.conf9
-rw-r--r--tests/topotests/bgp_unnumbered/r1/zebra.conf10
-rw-r--r--tests/topotests/bgp_unnumbered/r2/bgpd.conf9
-rw-r--r--tests/topotests/bgp_unnumbered/r2/zebra.conf12
-rw-r--r--tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py132
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/__init__.py0
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/cpe1/bgpd.conf9
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/cpe1/zebra.conf9
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/cpe2/bgpd.conf6
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/cpe2/zebra.conf6
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/pe1/bgpd.conf38
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/pe1/ldpd.conf10
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/pe1/ospf6d.conf12
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/pe1/zebra.conf14
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/pe2/bgpd.conf29
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/pe2/ldpd.conf10
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/pe2/ospf6d.conf12
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/pe2/zebra.conf14
-rw-r--r--tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py138
-rw-r--r--tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py20
-rw-r--r--tests/topotests/bgp_vrf_leaking_5549_routes/ce1/bgpd.conf23
-rw-r--r--tests/topotests/bgp_vrf_leaking_5549_routes/ce1/zebra.conf13
-rw-r--r--tests/topotests/bgp_vrf_leaking_5549_routes/pe1/bgpd.conf41
-rw-r--r--tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/default_ipv4_vpn.json32
-rw-r--r--tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json32
-rw-r--r--tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json34
-rw-r--r--tests/topotests/bgp_vrf_leaking_5549_routes/pe1/zebra.conf10
-rwxr-xr-xtests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py121
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf6
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf6
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py234
-rw-r--r--tests/topotests/config_timing/test_config_timing.py11
-rw-r--r--tests/topotests/cspf_topo1/test_cspf_topo1.py2
-rw-r--r--tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py267
-rw-r--r--tests/topotests/isis_lfa_topo1/rt1/bfdd.conf2
-rw-r--r--tests/topotests/isis_lfa_topo1/rt2/bfdd.conf2
-rwxr-xr-xtests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py134
-rwxr-xr-xtests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py14
-rw-r--r--tests/topotests/lib/bgprib.py193
-rw-r--r--tests/topotests/lib/common_config.py68
-rw-r--r--tests/topotests/lib/snmptest.py7
-rw-r--r--tests/topotests/lib/topotest.py20
-rwxr-xr-xtests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py35
-rwxr-xr-xtests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py7
-rw-r--r--tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py6
-rw-r--r--tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py6
-rwxr-xr-xtests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py9
-rwxr-xr-xtests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_static_routes_topo1.py5
-rwxr-xr-xtests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_transit_router_topo3.py5
-rwxr-xr-xtests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py5
-rwxr-xr-xtests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py5
-rwxr-xr-xtests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py5
-rwxr-xr-xtests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py5
-rwxr-xr-xtests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py5
-rwxr-xr-xtests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py8
-rwxr-xr-xtests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py6
-rw-r--r--tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py64
-rwxr-xr-xtests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py4
-rw-r--r--tests/topotests/ospf6_topo2/test_ospf6_topo2.py2
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_rte_calc.json2
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_authentication.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_chaos.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_lan.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_nssa.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_single_area.py6
-rw-r--r--tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py6
-rw-r--r--tests/topotests/ospf_gr_helper/ospf_gr_helper.json10
-rw-r--r--tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py6
-rw-r--r--tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py6
-rw-r--r--tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py6
-rwxr-xr-xtests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py4
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt2
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt2
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt4
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py6
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py59
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py6
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py6
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py6
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py124
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py6
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py6
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py6
-rw-r--r--tests/topotests/pim_basic/test_pim.py2
-rw-r--r--tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py4
-rwxr-xr-xtests/topotests/srv6_locator/test_srv6_locator.py4
-rwxr-xr-xtests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py6
-rw-r--r--tests/topotests/srv6_locator_usid/r1/zebra.conf2
-rwxr-xr-xtests/topotests/srv6_locator_usid/test_srv6_locator_usid.py20
-rwxr-xr-xtests/topotests/tc_basic/test_tc_basic.py133
-rw-r--r--tools/etc/frr/daemons5
-rwxr-xr-xtools/frr-reload.py1
-rwxr-xr-xtools/frrcommon.sh.in16
-rw-r--r--vrrpd/vrrp.c19
-rw-r--r--vrrpd/vrrp.h10
-rw-r--r--vrrpd/vrrp_northbound.c27
-rw-r--r--vrrpd/vrrp_packet.c33
-rw-r--r--vrrpd/vrrp_packet.h10
-rw-r--r--vrrpd/vrrp_vty.c40
-rw-r--r--vrrpd/vrrp_vty.h3
-rw-r--r--vtysh/vtysh.c34
-rw-r--r--vtysh/vtysh_config.c6
-rw-r--r--vtysh/vtysh_main.c9
-rw-r--r--yang/frr-vrrpd.yang7
-rw-r--r--zebra/connected.c72
-rw-r--r--zebra/debug.c21
-rw-r--r--zebra/debug.h9
-rw-r--r--zebra/dplane_fpm_nl.c148
-rw-r--r--zebra/if_netlink.c8
-rw-r--r--zebra/interface.c16
-rw-r--r--zebra/interface.h3
-rw-r--r--zebra/irdp_interface.c4
-rw-r--r--zebra/kernel_netlink.c43
-rw-r--r--zebra/kernel_socket.c11
-rw-r--r--zebra/main.c6
-rw-r--r--zebra/rt_netlink.c36
-rw-r--r--zebra/rt_netlink.h4
-rw-r--r--zebra/rtadv.c29
-rw-r--r--zebra/rtadv.h7
-rw-r--r--zebra/rtread_netlink.c7
-rw-r--r--zebra/rtread_sysctl.c5
-rw-r--r--zebra/subdir.am2
-rw-r--r--zebra/tc_netlink.c735
-rw-r--r--zebra/tc_netlink.h50
-rw-r--r--zebra/tc_socket.c26
-rw-r--r--zebra/zapi_msg.c174
-rw-r--r--zebra/zebra_dplane.c656
-rw-r--r--zebra/zebra_dplane.h89
-rw-r--r--zebra/zebra_fpm_netlink.c13
-rw-r--r--zebra/zebra_gr.c19
-rw-r--r--zebra/zebra_mpls.c1
-rw-r--r--zebra/zebra_nhg.c11
-rw-r--r--zebra/zebra_ns.c6
-rw-r--r--zebra/zebra_pbr.c27
-rw-r--r--zebra/zebra_pbr.h3
-rw-r--r--zebra/zebra_rib.c137
-rw-r--r--zebra/zebra_rnh.c185
-rw-r--r--zebra/zebra_rnh.h3
-rw-r--r--zebra/zebra_routemap.c146
-rw-r--r--zebra/zebra_routemap.h2
-rw-r--r--zebra/zebra_router.c26
-rw-r--r--zebra/zebra_router.h12
-rw-r--r--zebra/zebra_script.c11
-rw-r--r--zebra/zebra_srv6_vty.c14
-rw-r--r--zebra/zebra_tc.c444
-rw-r--r--zebra/zebra_tc.h79
-rw-r--r--zebra/zebra_trace.h43
-rw-r--r--zebra/zebra_vrf.c1
-rw-r--r--zebra/zebra_vty.c427
-rw-r--r--zebra/zserv.c14
-rw-r--r--zebra/zserv.h7
426 files changed, 14938 insertions, 4071 deletions
diff --git a/.github/labeler.yml b/.github/labeler.yml
deleted file mode 100644
index af29289d33..0000000000
--- a/.github/labeler.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-backport:
- - '(Mergifyio backport )'
diff --git a/.github/workflows/base-branch-label.yml b/.github/workflows/base-branch-label.yml
index 01da280911..5c5d8290b7 100644
--- a/.github/workflows/base-branch-label.yml
+++ b/.github/workflows/base-branch-label.yml
@@ -8,6 +8,7 @@ on:
jobs:
label:
+ if: github.repository == 'frrouting/frr'
runs-on: ubuntu-latest
permissions:
contents: read
diff --git a/.github/workflows/conflicts.yml b/.github/workflows/conflicts.yml
index 18a8c0d15d..3f51e7f4de 100644
--- a/.github/workflows/conflicts.yml
+++ b/.github/workflows/conflicts.yml
@@ -7,6 +7,7 @@ on:
jobs:
conflicts:
+ if: github.repository == 'frrouting/frr'
runs-on: ubuntu-latest
permissions:
contents: read
diff --git a/.github/workflows/docker-daily-master.yml b/.github/workflows/docker-daily-master.yml
new file mode 100644
index 0000000000..5b521a870d
--- /dev/null
+++ b/.github/workflows/docker-daily-master.yml
@@ -0,0 +1,52 @@
+name: Build daily 'master' images for Docker
+
+on:
+ schedule:
+ - cron: '59 23 * * *'
+
+concurrency:
+ group: ${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ docker_daily_master:
+ if: github.repository == 'frrouting/frr'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - name: Custom variables
+ id: vars
+ run: |
+ # To package a specific git commit, the date of the commit gets
+ # appended to the latest release, e.g. 1.0.0_git20180204.
+ # This is the requirement by APKBUILD (abuild).
+ # More details: https://wiki.alpinelinux.org/wiki/APKBUILD_Reference.
+ echo ::set-output name=date::$(date +'%Y%m%d')
+
+ - name: Checkout
+ uses: actions/checkout@v3
+ with:
+ ref: master
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Build and push
+ uses: docker/build-push-action@v3
+ with:
+ context: .
+ file: ./docker/alpine/Dockerfile
+ push: true
+ tags: ${{ secrets.DOCKERHUB_USERNAME }}/frr:master
+ build-args: PKGVER=${{ steps.vars.outputs.date }}
+ platforms: linux/amd64,linux/arm64,linux/arm/v7
diff --git a/.github/workflows/docker-stable.yml b/.github/workflows/docker-stable.yml
new file mode 100644
index 0000000000..1e069a722e
--- /dev/null
+++ b/.github/workflows/docker-stable.yml
@@ -0,0 +1,53 @@
+name: Build stable branch images for Docker
+
+on:
+ push:
+ branches:
+ - 'stable/**'
+
+concurrency:
+ group: ${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ docker_daily_master:
+ if: github.repository == 'frrouting/frr'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - name: Custom variables
+ id: vars
+ run: |
+ # To package a specific git commit, the date of the commit gets
+ # appended to the latest release, e.g. 1.0.0_git20180204.
+ # This is the requirement by APKBUILD (abuild).
+ # More details: https://wiki.alpinelinux.org/wiki/APKBUILD_Reference.
+ echo ::set-output name=date::$(date +'%Y%m%d')
+ # Get the real version specified in configure.ac file.
+ echo ::set-output name=frr_version::$(grep AC_INIT configure.ac | cut -d '[' -f3 | cut -d ']' -f 1)
+
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Build and push
+ uses: docker/build-push-action@v3
+ with:
+ context: .
+ file: ./docker/alpine/Dockerfile
+ push: true
+ tags: ${{ secrets.DOCKERHUB_USERNAME }}/frr:v${{ steps.vars.outputs.frr_version }}
+ build-args: PKGVER=${{ steps.vars.outputs.date }}
+ platforms: linux/amd64,linux/arm64,linux/arm/v7
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
deleted file mode 100644
index 9b01cd1b90..0000000000
--- a/.github/workflows/labeler.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-name: Labeler
-
-on:
- pull_request_target:
- types:
- - opened
- - reopened
-
-jobs:
- labeler:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- pull-requests: write
- steps:
- - uses: github/issue-labeler@v2.5
- with:
- repo-token: "${{ secrets.GITHUB_TOKEN }}"
- configuration-path: .github/labeler.yml
- enable-versioned-regex: 0
diff --git a/.github/workflows/mergifyio_backport.yml b/.github/workflows/mergifyio_backport.yml
new file mode 100644
index 0000000000..455dcbeb8e
--- /dev/null
+++ b/.github/workflows/mergifyio_backport.yml
@@ -0,0 +1,22 @@
+name: Mergifyio backport
+
+on: [issue_comment]
+
+jobs:
+ mergifyio_backport:
+ if: github.repository == 'frrouting/frr'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+
+ - uses: actions-ecosystem/action-regex-match@v2
+ id: regex-match
+ with:
+ text: ${{ github.event.comment.body }}
+ regex: '[Mm]ergifyio backport '
+
+ - uses: actions-ecosystem/action-add-labels@v1
+ if: ${{ steps.regex-match.outputs.match != '' }}
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ labels: backport
diff --git a/.github/workflows/size-label.yml b/.github/workflows/size-label.yml
new file mode 100644
index 0000000000..1ce07864ae
--- /dev/null
+++ b/.github/workflows/size-label.yml
@@ -0,0 +1,26 @@
+name: Add PRs size label
+
+on: pull_request_target
+
+jobs:
+ size-label:
+ if: github.repository == 'frrouting/frr'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: write
+ steps:
+ - name: size-label
+ uses: "pascalgn/size-label-action@v0.4.2"
+ env:
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+ with:
+ sizes: >
+ {
+ "0": "XS",
+ "20": "S",
+ "50": "M",
+ "200": "L",
+ "800": "XL",
+ "2000": "XXL"
+ }
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 45095b3dd3..cd1365ba51 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -10,6 +10,7 @@ permissions:
jobs:
stale:
+ if: github.repository == 'frrouting/frr'
permissions:
issues: write
pull-requests: write
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 382f78a0f6..6397aa5747 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -1397,8 +1397,6 @@ int bp_peer_socket(const struct bfd_session *bs)
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr));
- if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
- sin.sin_addr.s_addr = INADDR_ANY;
pcount = 0;
do {
diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c
index d822f6e330..461e60dbfc 100644
--- a/bgpd/bgp_addpath.c
+++ b/bgpd/bgp_addpath.c
@@ -111,6 +111,9 @@ void bgp_addpath_free_info_data(struct bgp_addpath_info_data *d,
uint32_t bgp_addpath_id_for_peer(struct peer *peer, afi_t afi, safi_t safi,
struct bgp_addpath_info_data *d)
{
+ if (safi == SAFI_LABELED_UNICAST)
+ safi = SAFI_UNICAST;
+
if (peer->addpath_type[afi][safi] < BGP_ADDPATH_MAX)
return d->addpath_tx_id[peer->addpath_type[afi][safi]];
else
@@ -182,6 +185,9 @@ static void bgp_addpath_flush_type_rn(struct bgp *bgp, afi_t afi, safi_t safi,
{
struct bgp_path_info *pi;
+ if (safi == SAFI_LABELED_UNICAST)
+ safi = SAFI_UNICAST;
+
idalloc_drain_pool(
bgp->tx_addpath.id_allocators[afi][safi][addpath_type],
&(dest->tx_addpath.free_ids[addpath_type]));
@@ -210,6 +216,9 @@ static void bgp_addpath_flush_type(struct bgp *bgp, afi_t afi, safi_t safi,
{
struct bgp_dest *dest, *ndest;
+ if (safi == SAFI_LABELED_UNICAST)
+ safi = SAFI_UNICAST;
+
for (dest = bgp_table_top(bgp->rib[afi][safi]); dest;
dest = bgp_route_next(dest)) {
if (safi == SAFI_MPLS_VPN) {
@@ -251,6 +260,7 @@ static void bgp_addpath_populate_path(struct id_alloc *allocator,
* and afi/safi combination. Since we won't waste the time computing addpath IDs
* for unused strategies, the first time a peer is configured to use a strategy,
* we have to backfill the data.
+ * In labeled-unicast, addpath allocations SHOULD be done in unicast SAFI.
*/
static void bgp_addpath_populate_type(struct bgp *bgp, afi_t afi, safi_t safi,
enum bgp_addpath_strat addpath_type)
@@ -259,6 +269,9 @@ static void bgp_addpath_populate_type(struct bgp *bgp, afi_t afi, safi_t safi,
char buf[200];
struct id_alloc *allocator;
+ if (safi == SAFI_LABELED_UNICAST)
+ safi = SAFI_UNICAST;
+
snprintf(buf, sizeof(buf), "Addpath ID Allocator %s:%d/%d",
bgp_addpath_names(addpath_type)->config_name, (int)afi,
(int)safi);
@@ -357,11 +370,15 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
enum bgp_addpath_strat addpath_type)
{
struct bgp *bgp = peer->bgp;
- enum bgp_addpath_strat old_type = peer->addpath_type[afi][safi];
+ enum bgp_addpath_strat old_type;
struct listnode *node, *nnode;
struct peer *tmp_peer;
struct peer_group *group;
+ if (safi == SAFI_LABELED_UNICAST)
+ safi = SAFI_UNICAST;
+
+ old_type = peer->addpath_type[afi][safi];
if (addpath_type == old_type)
return;
@@ -389,9 +406,9 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
}
}
- zlog_info("Resetting peer %s%s due to change in addpath config",
+ zlog_info("Resetting peer %s%pBP due to change in addpath config",
CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "",
- peer->host);
+ peer);
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
group = peer->group;
@@ -431,6 +448,9 @@ void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *bn, afi_t afi,
struct bgp_path_info *pi;
struct id_alloc_pool **pool_ptr;
+ if (safi == SAFI_LABELED_UNICAST)
+ safi = SAFI_UNICAST;
+
for (i = 0; i < BGP_ADDPATH_MAX; i++) {
struct id_alloc *alloc =
bgp->tx_addpath.id_allocators[afi][safi][i];
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 06f6073781..85f09ccf0b 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -1187,6 +1187,33 @@ int aspath_loop_check(struct aspath *aspath, as_t asno)
return count;
}
+/* AS path loop check. If aspath contains asno
+ * that is a confed id then return >= 1.
+ */
+int aspath_loop_check_confed(struct aspath *aspath, as_t asno)
+{
+ struct assegment *seg;
+ int count = 0;
+
+ if (aspath == NULL || aspath->segments == NULL)
+ return 0;
+
+ seg = aspath->segments;
+
+ while (seg) {
+ unsigned int i;
+
+ for (i = 0; i < seg->length; i++)
+ if (seg->type != AS_CONFED_SEQUENCE &&
+ seg->type != AS_CONFED_SET && seg->as[i] == asno)
+ count++;
+
+ seg = seg->next;
+ }
+ return count;
+}
+
+
/* When all of AS path is private AS return 1. */
bool aspath_private_as_check(struct aspath *aspath)
{
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 0b58e1adc4..97bc7c0aca 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -111,6 +111,7 @@ extern unsigned int aspath_key_make(const void *p);
extern unsigned int aspath_get_first_as(struct aspath *aspath);
extern unsigned int aspath_get_last_as(struct aspath *aspath);
extern int aspath_loop_check(struct aspath *aspath, as_t asno);
+extern int aspath_loop_check_confed(struct aspath *aspath, as_t asno);
extern bool aspath_private_as_check(struct aspath *aspath);
extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
as_t target_asn,
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index b8010364a7..3d93e8a1ac 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -825,55 +825,56 @@ bool attrhash_cmp(const void *p1, const void *p2)
&& 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->label_index == attr2->label_index
- && attr1->mp_nexthop_len == attr2->mp_nexthop_len
- && bgp_attr_get_ecommunity(attr1)
- == bgp_attr_get_ecommunity(attr2)
- && bgp_attr_get_ipv6_ecommunity(attr1)
- == 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_aigp_metric(attr1)
- == bgp_attr_get_aigp_metric(attr2)
- && attr1->rmap_table_id == attr2->rmap_table_id
- && (attr1->encap_tunneltype == attr2->encap_tunneltype)
- && encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
+ 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->label_index == attr2->label_index &&
+ attr1->mp_nexthop_len == attr2->mp_nexthop_len &&
+ bgp_attr_get_ecommunity(attr1) ==
+ bgp_attr_get_ecommunity(attr2) &&
+ bgp_attr_get_ipv6_ecommunity(attr1) ==
+ 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_aigp_metric(attr1) ==
+ bgp_attr_get_aigp_metric(attr2) &&
+ attr1->rmap_table_id == attr2->rmap_table_id &&
+ (attr1->encap_tunneltype == attr2->encap_tunneltype) &&
+ encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
#ifdef ENABLE_BGP_VNC
&& encap_same(bgp_attr_get_vnc_subtlvs(attr1),
bgp_attr_get_vnc_subtlvs(attr2))
#endif
&& IPV6_ADDR_SAME(&attr1->mp_nexthop_global,
- &attr2->mp_nexthop_global)
- && IPV6_ADDR_SAME(&attr1->mp_nexthop_local,
- &attr2->mp_nexthop_local)
- && IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in,
- &attr2->mp_nexthop_global_in)
- && IPV4_ADDR_SAME(&attr1->originator_id,
- &attr2->originator_id)
- && overlay_index_same(attr1, attr2)
- && !memcmp(&attr1->esi, &attr2->esi, sizeof(esi_t))
- && attr1->es_flags == attr2->es_flags
- && attr1->mm_sync_seqnum == attr2->mm_sync_seqnum
- && attr1->df_pref == attr2->df_pref
- && attr1->df_alg == attr2->df_alg
- && attr1->nh_ifindex == attr2->nh_ifindex
- && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
- && attr1->distance == attr2->distance
- && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
- && 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)
+ &attr2->mp_nexthop_global) &&
+ IPV6_ADDR_SAME(&attr1->mp_nexthop_local,
+ &attr2->mp_nexthop_local) &&
+ IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in,
+ &attr2->mp_nexthop_global_in) &&
+ IPV4_ADDR_SAME(&attr1->originator_id,
+ &attr2->originator_id) &&
+ overlay_index_same(attr1, attr2) &&
+ !memcmp(&attr1->esi, &attr2->esi, sizeof(esi_t)) &&
+ attr1->es_flags == attr2->es_flags &&
+ attr1->mm_sync_seqnum == attr2->mm_sync_seqnum &&
+ attr1->df_pref == attr2->df_pref &&
+ attr1->df_alg == attr2->df_alg &&
+ attr1->nh_ifindex == attr2->nh_ifindex &&
+ attr1->nh_flag == attr2->nh_flag &&
+ attr1->nh_lla_ifindex == attr2->nh_lla_ifindex &&
+ attr1->distance == attr2->distance &&
+ srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn) &&
+ 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)
return true;
}
@@ -904,20 +905,20 @@ static void attrhash_finish(void)
static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty)
{
struct attr *attr = bucket->data;
- char sid_str[BUFSIZ];
+ struct in6_addr *sid = NULL;
- vty_out(vty, "attr[%ld] nexthop %pI4\n", attr->refcnt, &attr->nexthop);
-
- sid_str[0] = '\0';
if (attr->srv6_l3vpn)
- inet_ntop(AF_INET6, &attr->srv6_l3vpn->sid, sid_str, BUFSIZ);
+ sid = &attr->srv6_l3vpn->sid;
else if (attr->srv6_vpn)
- inet_ntop(AF_INET6, &attr->srv6_vpn->sid, sid_str, BUFSIZ);
+ sid = &attr->srv6_vpn->sid;
+
+ vty_out(vty, "attr[%ld] nexthop %pI4\n", attr->refcnt, &attr->nexthop);
vty_out(vty,
- "\tflags: %" PRIu64" distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %s\n",
+ "\tflags: %" PRIu64
+ " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n",
attr->flag, attr->distance, attr->med, attr->local_pref,
- attr->origin, attr->weight, attr->label, sid_str);
+ attr->origin, attr->weight, attr->label, sid);
}
void attr_show_all(struct vty *vty)
@@ -1746,12 +1747,9 @@ enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer,
if (ipv4_martian(&attr->nexthop) && !bgp->allow_martian) {
uint8_t data[7]; /* type(2) + length(1) + nhop(4) */
- char buf[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, &attr->nexthop.s_addr, buf,
- INET_ADDRSTRLEN);
- flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s",
- buf);
+ flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %pI4",
+ &attr->nexthop);
data[0] = BGP_ATTR_FLAG_TRANS;
data[1] = BGP_ATTR_NEXT_HOP;
data[2] = BGP_ATTR_NHLEN_IPV4;
@@ -2257,6 +2255,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_WITHDRAW;
}
attr->nh_ifindex = peer->nexthop.ifp->ifindex;
+ if (if_is_operative(peer->nexthop.ifp))
+ SET_FLAG(attr->nh_flag,
+ BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(attr->nh_flag,
+ BGP_ATTR_NH_IF_OPERSTATE);
}
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
@@ -2274,6 +2278,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_WITHDRAW;
}
attr->nh_ifindex = peer->nexthop.ifp->ifindex;
+ if (if_is_operative(peer->nexthop.ifp))
+ SET_FLAG(attr->nh_flag,
+ BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(attr->nh_flag,
+ BGP_ATTR_NH_IF_OPERSTATE);
}
if (attr->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
@@ -2709,6 +2719,18 @@ bgp_attr_srv6_service_data(struct bgp_attr_parser_args *args)
}
if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE) {
+ if (STREAM_READABLE(peer->curr) <
+ BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %zu remaining in UPDATE)",
+ BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH,
+ STREAM_READABLE(peer->curr));
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
loc_block_len = stream_getc(peer->curr);
loc_node_len = stream_getc(peer->curr);
func_len = stream_getc(peer->curr);
@@ -2758,7 +2780,6 @@ bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
uint16_t length, endpoint_behavior;
size_t headersz = sizeof(type) + sizeof(length);
enum bgp_attr_parse_ret err;
- char buf[BUFSIZ];
if (STREAM_READABLE(peer->curr) < headersz) {
flog_err(
@@ -2782,6 +2803,17 @@ bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
}
if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO) {
+ if (STREAM_READABLE(peer->curr) <
+ BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %d for attribute data, have %zu remaining in UPDATE)",
+ BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH,
+ STREAM_READABLE(peer->curr));
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
stream_getc(peer->curr);
stream_get(&ipv6_sid, peer->curr, sizeof(ipv6_sid));
sid_flags = stream_getc(peer->curr);
@@ -2789,12 +2821,11 @@ bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
stream_getc(peer->curr);
/* Log SRv6 Service Sub-TLV */
- if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
- inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
zlog_debug(
- "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
- __func__, buf, sid_flags, endpoint_behavior);
- }
+ "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x",
+ __func__, &ipv6_sid, sid_flags,
+ endpoint_behavior);
/* Configure from Info */
if (attr->srv6_l3vpn) {
@@ -2855,7 +2886,6 @@ bgp_attr_psid_sub(uint8_t type, uint16_t length,
uint32_t srgb_range;
int srgb_count;
uint8_t sid_type, sid_flags;
- char buf[BUFSIZ];
if (type == BGP_PREFIX_SID_LABEL_INDEX) {
if (STREAM_READABLE(peer->curr) < length
@@ -2986,12 +3016,10 @@ bgp_attr_psid_sub(uint8_t type, uint16_t length,
sizeof(ipv6_sid)); /* sid_value */
/* Log VPN-SID Sub-TLV */
- if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
- inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
zlog_debug(
- "%s: vpn-sid: sid %s, sid-type 0x%02x sid-flags 0x%02x",
- __func__, buf, sid_type, sid_flags);
- }
+ "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x",
+ __func__, &ipv6_sid, sid_type, sid_flags);
/* Configure from Info */
if (attr->srv6_vpn) {
@@ -3861,7 +3889,10 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
stream_putc(s, attr->mp_nexthop_len);
stream_put_ipv4(s, attr->nexthop.s_addr);
}
- default:
+ break;
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
+ assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
break;
}
break;
@@ -3912,17 +3943,24 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
break;
case SAFI_FLOWSPEC:
stream_putc(s, 0); /* no nexthop for flowspec */
- default:
+ break;
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
+ assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
break;
}
break;
- default:
+ case AFI_L2VPN:
if (safi != SAFI_FLOWSPEC)
flog_err(
EC_BGP_ATTR_NH_SEND_LEN,
"Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
peer->host, afi, safi, attr->mp_nexthop_len);
break;
+ case AFI_UNSPEC:
+ case AFI_MAX:
+ assert(!"DEV ESCAPE: AFI_UNSPEC or AFI_MAX should not be used here");
+ break;
}
/* SNPA */
@@ -3936,7 +3974,12 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
uint32_t num_labels, bool addpath_capable,
uint32_t addpath_tx_id, struct attr *attr)
{
- if (safi == SAFI_MPLS_VPN) {
+ switch (safi) {
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
+ assert(!"Dev escape usage of SAFI_UNSPEC or MAX");
+ break;
+ case SAFI_MPLS_VPN:
if (addpath_capable)
stream_putl(s, addpath_tx_id);
/* Label, RD, Prefix write. */
@@ -3944,33 +3987,74 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
stream_put(s, label, BGP_LABEL_BYTES);
stream_put(s, prd->val, 8);
stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
- } else if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
- /* EVPN prefix - contents depend on type */
- bgp_evpn_encode_prefix(s, p, prd, label, num_labels, attr,
- addpath_capable, addpath_tx_id);
- } else if (safi == SAFI_LABELED_UNICAST) {
+ break;
+ case SAFI_EVPN:
+ if (afi == AFI_L2VPN)
+ /* EVPN prefix - contents depend on type */
+ bgp_evpn_encode_prefix(s, p, prd, label, num_labels,
+ attr, addpath_capable,
+ addpath_tx_id);
+ else
+ assert(!"Add encoding bits here for other AFI's");
+ break;
+ case SAFI_LABELED_UNICAST:
/* Prefix write with label. */
stream_put_labeled_prefix(s, p, label, addpath_capable,
addpath_tx_id);
- } else if (safi == SAFI_FLOWSPEC) {
+ break;
+ case SAFI_FLOWSPEC:
stream_putc(s, p->u.prefix_flowspec.prefixlen);
stream_put(s, (const void *)p->u.prefix_flowspec.ptr,
p->u.prefix_flowspec.prefixlen);
- } else
+ break;
+
+ case SAFI_UNICAST:
+ case SAFI_MULTICAST:
stream_put_prefix_addpath(s, p, addpath_capable, addpath_tx_id);
+ break;
+ case SAFI_ENCAP:
+ assert(!"Please add proper encoding of SAFI_ENCAP");
+ break;
+ }
}
size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
const struct prefix *p)
{
int size = PSIZE(p->prefixlen);
- if (safi == SAFI_MPLS_VPN)
+
+ switch (safi) {
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
+ assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE");
+ break;
+ case SAFI_UNICAST:
+ case SAFI_MULTICAST:
+ break;
+ case SAFI_MPLS_VPN:
size += 88;
- else if (safi == SAFI_LABELED_UNICAST)
+ break;
+ case SAFI_ENCAP:
+ /* This has to be wrong, but I don't know what to put here */
+ assert(!"Do we try to use this?");
+ break;
+ case SAFI_LABELED_UNICAST:
size += BGP_LABEL_BYTES;
- else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
- size += 232; // TODO: Maximum possible for type-2, type-3 and
- // type-5
+ break;
+ case SAFI_EVPN:
+ /*
+ * TODO: Maximum possible for type-2, type-3 and type-5
+ */
+ if (afi == AFI_L2VPN)
+ size += 232;
+ else
+ assert(!"Attempting to figure size for SAFI_EVPN and !AFI_L2VPN and FRR will not have the proper values");
+ break;
+ case SAFI_FLOWSPEC:
+ size = ((struct prefix_fs *)p)->prefix.prefixlen;
+ break;
+ }
+
return size;
}
@@ -4611,7 +4695,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
/* AIGP */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
+ if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
(CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
peer->sort != BGP_PEER_EBGP)) {
/* At the moment only AIGP Metric TLV exists for AIGP
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index bc82d0c6ed..f8beb5fba9 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -170,6 +170,12 @@ struct attr {
uint32_t med;
uint32_t local_pref;
ifindex_t nh_ifindex;
+ uint8_t nh_flag;
+
+#define BGP_ATTR_NH_VALID 0x01
+#define BGP_ATTR_NH_IF_OPERSTATE 0x02
+#define BGP_ATTR_NH_MP_PREFER_GLOBAL 0x04 /* MP Nexthop preference */
+#define BGP_ATTR_NH_REFRESH 0x08
/* Path origin attribute */
uint8_t origin;
@@ -220,9 +226,6 @@ struct attr {
/* MP Nexthop length */
uint8_t mp_nexthop_len;
- /* MP Nexthop preference */
- uint8_t mp_nexthop_prefer_global;
-
/* Static MAC for EVPN */
uint8_t sticky;
@@ -344,6 +347,8 @@ struct attr {
#define BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED (1 << 6)
#define BATTR_RMAP_LINK_BW_SET (1 << 7)
#define BATTR_RMAP_L3VPN_ACCEPT_GRE (1 << 8)
+#define BATTR_RMAP_VPNV4_NHOP_CHANGED (1 << 9)
+#define BATTR_RMAP_VPNV6_GLOBAL_NHOP_CHANGED (1 << 10)
/* Router Reflector related structure. */
struct cluster_list {
@@ -473,20 +478,23 @@ extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
extern enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer,
struct attr *attr);
-static inline int bgp_rmap_nhop_changed(uint32_t out_rmap_flags,
- uint32_t in_rmap_flags)
+static inline bool bgp_rmap_nhop_changed(uint32_t out_rmap_flags,
+ uint32_t in_rmap_flags)
{
- return ((CHECK_FLAG(out_rmap_flags, BATTR_RMAP_NEXTHOP_PEER_ADDRESS)
- || CHECK_FLAG(out_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED)
- || CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV4_NHOP_CHANGED)
- || CHECK_FLAG(out_rmap_flags,
- BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED)
- || CHECK_FLAG(out_rmap_flags,
- BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED)
- || CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV6_LL_NHOP_CHANGED)
- || CHECK_FLAG(in_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED))
- ? 1
- : 0);
+ return ((CHECK_FLAG(out_rmap_flags, BATTR_RMAP_NEXTHOP_PEER_ADDRESS) ||
+ CHECK_FLAG(out_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED) ||
+ CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV4_NHOP_CHANGED) ||
+ CHECK_FLAG(out_rmap_flags, BATTR_RMAP_VPNV4_NHOP_CHANGED) ||
+ CHECK_FLAG(out_rmap_flags,
+ BATTR_RMAP_VPNV6_GLOBAL_NHOP_CHANGED) ||
+ CHECK_FLAG(out_rmap_flags,
+ BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED) ||
+ CHECK_FLAG(out_rmap_flags,
+ BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED) ||
+ CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV6_LL_NHOP_CHANGED) ||
+ CHECK_FLAG(in_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED))
+ ? true
+ : false);
}
static inline uint32_t mac_mobility_seqnum(struct attr *attr)
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 92a22d71b3..9e540b63cb 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -51,6 +51,8 @@
#include "bgpd/bgp_flowspec.h"
#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_debug_clippy.c"
+
unsigned long conf_bgp_debug_as4;
unsigned long conf_bgp_debug_neighbor_events;
unsigned long conf_bgp_debug_events;
@@ -324,7 +326,7 @@ static void bgp_debug_list_add_entry(struct list *list, const char *host,
}
static bool bgp_debug_list_remove_entry(struct list *list, const char *host,
- struct prefix *p)
+ const struct prefix *p)
{
struct bgp_debug_filter *filter;
struct listnode *node, *nnode;
@@ -378,8 +380,6 @@ bool bgp_debug_peer_updout_enabled(char *host)
/* Dump attribute. */
bool bgp_dump_attr(struct attr *attr, char *buf, size_t size)
{
- char addrbuf[BUFSIZ];
-
if (!attr)
return false;
@@ -395,15 +395,12 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size)
/* Add MP case. */
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL
|| attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
- snprintf(buf + strlen(buf), size - strlen(buf),
- ", mp_nexthop %s",
- inet_ntop(AF_INET6, &attr->mp_nexthop_global, addrbuf,
- BUFSIZ));
+ snprintfrr(buf + strlen(buf), size - strlen(buf),
+ ", mp_nexthop %pI6", &attr->mp_nexthop_global);
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
- snprintf(buf + strlen(buf), size - strlen(buf), "(%s)",
- inet_ntop(AF_INET6, &attr->mp_nexthop_local, addrbuf,
- BUFSIZ));
+ snprintfrr(buf + strlen(buf), size - strlen(buf), "(%pI6)",
+ &attr->mp_nexthop_local);
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4)
snprintfrr(buf, size, "nexthop %pI4", &attr->nexthop);
@@ -635,17 +632,14 @@ static void bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc,
}
static int bgp_debug_parse_evpn_prefix(struct vty *vty, struct cmd_token **argv,
- int argc, struct prefix **argv_pp)
+ int argc, struct prefix *argv_p)
{
- struct prefix *argv_p;
struct ethaddr mac = {};
struct ipaddr ip = {};
int evpn_type = 0;
int mac_idx = 0;
int ip_idx = 0;
- argv_p = *argv_pp;
-
if (bgp_evpn_cli_parse_type(&evpn_type, argv, argc) < 0)
return CMD_WARNING;
@@ -1028,49 +1022,42 @@ DEFUN (no_debug_bgp_keepalive_peer,
}
/* debug bgp bestpath */
-DEFUN (debug_bgp_bestpath_prefix,
+DEFPY (debug_bgp_bestpath_prefix,
debug_bgp_bestpath_prefix_cmd,
- "debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>",
+ "debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>$prefix",
DEBUG_STR
BGP_STR
"BGP bestpath\n"
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- struct prefix *argv_p;
- int idx_ipv4_ipv6_prefixlen = 3;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
-
if (!bgp_debug_bestpath_prefixes)
bgp_debug_bestpath_prefixes = list_new();
if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL,
- argv_p)) {
+ prefix)) {
vty_out(vty,
"BGP bestpath debugging is already enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
- bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, argv_p);
+ bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix);
if (vty->node == CONFIG_NODE) {
DEBUG_ON(bestpath, BESTPATH);
} else {
TERM_DEBUG_ON(bestpath, BESTPATH);
vty_out(vty, "BGP bestpath debugging is on for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
}
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_bestpath_prefix,
+DEFPY (no_debug_bgp_bestpath_prefix,
no_debug_bgp_bestpath_prefix_cmd,
- "no debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>",
+ "no debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>$prefix",
NO_STR
DEBUG_STR
BGP_STR
@@ -1078,18 +1065,12 @@ DEFUN (no_debug_bgp_bestpath_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 4;
- struct prefix *argv_p;
- int found_prefix = 0;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
+ bool found_prefix = false;
if (bgp_debug_bestpath_prefixes
&& !list_isempty(bgp_debug_bestpath_prefixes)) {
found_prefix = bgp_debug_list_remove_entry(
- bgp_debug_bestpath_prefixes, NULL, argv_p);
+ bgp_debug_bestpath_prefixes, NULL, prefix);
if (list_isempty(bgp_debug_bestpath_prefixes)) {
if (vty->node == CONFIG_NODE) {
@@ -1104,10 +1085,10 @@ DEFUN (no_debug_bgp_bestpath_prefix,
if (found_prefix)
vty_out(vty, "BGP bestpath debugging is off for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
else
vty_out(vty, "BGP bestpath debugging was not enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
@@ -1415,8 +1396,6 @@ DEFUN (no_debug_bgp_update_direct_peer,
return CMD_SUCCESS;
}
-#include "bgpd/bgp_debug_clippy.c"
-
DEFPY (debug_bgp_update_prefix_afi_safi,
debug_bgp_update_prefix_afi_safi_cmd,
"debug bgp updates prefix l2vpn$afi evpn$safi type <<macip|2> mac <X:X:X:X:X:X|X:X:X:X:X:X/M> [ip <A.B.C.D|X:X::X:X>]|<multicast|3> ip <A.B.C.D|X:X::X:X>|<prefix|5> ip <A.B.C.D/M|X:X::X:X/M>>",
@@ -1444,39 +1423,33 @@ DEFPY (debug_bgp_update_prefix_afi_safi,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- struct prefix *argv_p;
+ struct prefix argv_p;
int ret = CMD_SUCCESS;
- argv_p = prefix_new();
-
ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p);
- if (ret != CMD_SUCCESS) {
- prefix_free(&argv_p);
+ if (ret != CMD_SUCCESS)
return ret;
- }
if (!bgp_debug_update_prefixes)
bgp_debug_update_prefixes = list_new();
- if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p)) {
+ if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL,
+ &argv_p)) {
vty_out(vty,
"BGP updates debugging is already enabled for %pFX\n",
- argv_p);
- prefix_free(&argv_p);
+ &argv_p);
return CMD_SUCCESS;
}
- bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p);
+ bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p);
if (vty->node == CONFIG_NODE) {
DEBUG_ON(update, UPDATE_PREFIX);
} else {
TERM_DEBUG_ON(update, UPDATE_PREFIX);
- vty_out(vty, "BGP updates debugging is on for %pFX\n", argv_p);
+ vty_out(vty, "BGP updates debugging is on for %pFX\n", &argv_p);
}
- prefix_free(&argv_p);
-
return CMD_SUCCESS;
}
@@ -1508,22 +1481,18 @@ DEFPY (no_debug_bgp_update_prefix_afi_safi,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- struct prefix *argv_p;
+ struct prefix argv_p;
bool found_prefix = false;
int ret = CMD_SUCCESS;
- argv_p = prefix_new();
-
ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p);
- if (ret != CMD_SUCCESS) {
- prefix_free(&argv_p);
+ if (ret != CMD_SUCCESS)
return ret;
- }
if (bgp_debug_update_prefixes
&& !list_isempty(bgp_debug_update_prefixes)) {
found_prefix = bgp_debug_list_remove_entry(
- bgp_debug_update_prefixes, NULL, argv_p);
+ bgp_debug_update_prefixes, NULL, &argv_p);
if (list_isempty(bgp_debug_update_prefixes)) {
if (vty->node == CONFIG_NODE) {
@@ -1537,20 +1506,19 @@ DEFPY (no_debug_bgp_update_prefix_afi_safi,
}
if (found_prefix)
- vty_out(vty, "BGP updates debugging is off for %pFX\n", argv_p);
+ vty_out(vty, "BGP updates debugging is off for %pFX\n",
+ &argv_p);
else
vty_out(vty, "BGP updates debugging was not enabled for %pFX\n",
- argv_p);
-
- prefix_free(&argv_p);
+ &argv_p);
return ret;
}
-DEFUN (debug_bgp_update_prefix,
+DEFPY (debug_bgp_update_prefix,
debug_bgp_update_prefix_cmd,
- "debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>",
+ "debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>$prefix",
DEBUG_STR
BGP_STR
"BGP updates\n"
@@ -1558,39 +1526,32 @@ DEFUN (debug_bgp_update_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 4;
- struct prefix *argv_p;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
-
if (!bgp_debug_update_prefixes)
bgp_debug_update_prefixes = list_new();
- if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p)) {
+ if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix)) {
vty_out(vty,
"BGP updates debugging is already enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
- bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p);
+ bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix);
if (vty->node == CONFIG_NODE) {
DEBUG_ON(update, UPDATE_PREFIX);
} else {
TERM_DEBUG_ON(update, UPDATE_PREFIX);
vty_out(vty, "BGP updates debugging is on for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
}
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_update_prefix,
+DEFPY (no_debug_bgp_update_prefix,
no_debug_bgp_update_prefix_cmd,
- "no debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>",
+ "no debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>$prefix",
NO_STR
DEBUG_STR
BGP_STR
@@ -1599,18 +1560,12 @@ DEFUN (no_debug_bgp_update_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 5;
- struct prefix *argv_p;
- int found_prefix = 0;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
+ bool found_prefix = false;
if (bgp_debug_update_prefixes
&& !list_isempty(bgp_debug_update_prefixes)) {
found_prefix = bgp_debug_list_remove_entry(
- bgp_debug_update_prefixes, NULL, argv_p);
+ bgp_debug_update_prefixes, NULL, prefix);
if (list_isempty(bgp_debug_update_prefixes)) {
if (vty->node == CONFIG_NODE) {
@@ -1625,10 +1580,10 @@ DEFUN (no_debug_bgp_update_prefix,
if (found_prefix)
vty_out(vty, "BGP updates debugging is off for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
else
vty_out(vty, "BGP updates debugging was not enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
@@ -1698,9 +1653,9 @@ DEFUN (debug_bgp_graceful_restart,
}
-DEFUN (debug_bgp_zebra_prefix,
+DEFPY (debug_bgp_zebra_prefix,
debug_bgp_zebra_prefix_cmd,
- "debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
+ "debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>$prefix",
DEBUG_STR
BGP_STR
"BGP Zebra messages\n"
@@ -1708,30 +1663,22 @@ DEFUN (debug_bgp_zebra_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 4;
- struct prefix *argv_p;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
-
if (!bgp_debug_zebra_prefixes)
bgp_debug_zebra_prefixes = list_new();
- if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, argv_p)) {
+ if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix)) {
vty_out(vty, "BGP zebra debugging is already enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
- bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, argv_p);
+ bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix);
if (vty->node == CONFIG_NODE)
DEBUG_ON(zebra, ZEBRA);
else {
TERM_DEBUG_ON(zebra, ZEBRA);
- vty_out(vty, "BGP zebra debugging is on for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ vty_out(vty, "BGP zebra debugging is on for %s\n", prefix_str);
}
return CMD_SUCCESS;
@@ -1773,9 +1720,9 @@ DEFUN (no_debug_bgp_graceful_restart,
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_zebra_prefix,
+DEFPY (no_debug_bgp_zebra_prefix,
no_debug_bgp_zebra_prefix_cmd,
- "no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
+ "no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>$prefix",
NO_STR
DEBUG_STR
BGP_STR
@@ -1784,18 +1731,12 @@ DEFUN (no_debug_bgp_zebra_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 5;
- struct prefix *argv_p;
- int found_prefix = 0;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
+ bool found_prefix = false;
if (bgp_debug_zebra_prefixes
&& !list_isempty(bgp_debug_zebra_prefixes)) {
found_prefix = bgp_debug_list_remove_entry(
- bgp_debug_zebra_prefixes, NULL, argv_p);
+ bgp_debug_zebra_prefixes, NULL, prefix);
if (list_isempty(bgp_debug_zebra_prefixes)) {
if (vty->node == CONFIG_NODE)
@@ -1808,11 +1749,10 @@ DEFUN (no_debug_bgp_zebra_prefix,
}
if (found_prefix)
- vty_out(vty, "BGP zebra debugging is off for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ vty_out(vty, "BGP zebra debugging is off for %s\n", prefix_str);
else
vty_out(vty, "BGP zebra debugging was not enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 589d9af1e5..62fba1f58e 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -988,13 +988,8 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
type == ECOMMUNITY_ENCODE_IP) {
struct in_addr *ipv4 =
(struct in_addr *)pnt;
- char ipv4str[INET_ADDRSTRLEN];
-
- inet_ntop(AF_INET, ipv4,
- ipv4str,
- INET_ADDRSTRLEN);
- snprintf(encbuf, sizeof(encbuf),
- "NH:%s:%d", ipv4str, pnt[5]);
+ snprintfrr(encbuf, sizeof(encbuf),
+ "NH:%pI4:%d", ipv4, pnt[5]);
} else if (sub_type ==
ECOMMUNITY_LINK_BANDWIDTH &&
type == ECOMMUNITY_ENCODE_AS) {
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index eab70bfdaf..7a8a91b00b 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -6912,6 +6912,7 @@ static void bgp_evpn_remote_ip_hash_del(struct bgpevpn *vpn,
if (ip->macip_path_list->count == 0) {
bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
hash_release(vpn->remote_ip_hash, ip);
+ list_delete(&ip->macip_path_list);
XFREE(MTYPE_EVPN_REMOTE_IP, ip);
}
}
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index 2a5c5d7ec4..7b1c7cf471 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -1692,7 +1692,7 @@ bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf *es_vrf,
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("update paths linked to es %s on es-vrf %s %s",
- es->esi_str, es_vrf->bgp_vrf->name, reason);
+ es->esi_str, es_vrf->bgp_vrf->name_pretty, reason);
for (ALL_LIST_ELEMENTS_RO(es->macip_global_path_list, node, es_info)) {
pi = es_info->pi;
@@ -2435,7 +2435,7 @@ static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es,
struct listnode *node;
struct bgp_evpn_es_vtep *es_vtep;
bool first = true;
- char ip_buf[INET6_ADDRSTRLEN];
+ char ip_buf[INET_ADDRSTRLEN];
vtep_str[0] = '\0';
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -3230,7 +3230,7 @@ static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
json_object *json_types;
json_object_string_add(json, "esi", es->esi_str);
- json_object_string_add(json, "vrf", bgp_vrf->name);
+ json_object_string_add(json, "vrf", bgp_vrf->name_pretty);
if (es_vrf->flags & (BGP_EVPNES_VRF_NHG_ACTIVE)) {
json_types = json_object_new_array();
@@ -3250,7 +3250,7 @@ static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
strlcat(flags_str, "A", sizeof(flags_str));
vty_out(vty, "%-30s %-15s %-5s %-8u %-8u %u\n", es->esi_str,
- bgp_vrf->name, flags_str, es_vrf->nhg_id,
+ bgp_vrf->name_pretty, flags_str, es_vrf->nhg_id,
es_vrf->v6_nhg_id, es_vrf->ref_cnt);
}
}
@@ -3903,7 +3903,7 @@ static char *bgp_evpn_es_evi_vteps_str(char *vtep_str,
struct listnode *node;
struct bgp_evpn_es_evi_vtep *evi_vtep;
bool first = true;
- char ip_buf[INET6_ADDRSTRLEN];
+ char ip_buf[INET_ADDRSTRLEN];
vtep_str[0] = '\0';
for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
@@ -4425,10 +4425,11 @@ static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add)
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) {
if (add)
zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra",
- nh->bgp_vrf->name, nh->nh_str, &nh->rmac);
+ nh->bgp_vrf->name_pretty, nh->nh_str,
+ &nh->rmac);
else if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug("evpn vrf %s nh %s del to zebra",
- nh->bgp_vrf->name, nh->nh_str);
+ nh->bgp_vrf->name_pretty, nh->nh_str);
}
frrtrace(2, frr_bgp, evpn_mh_nh_rmac_zsend, add, nh);
@@ -4497,8 +4498,8 @@ static struct bgp_evpn_nh *bgp_evpn_nh_add(struct bgp *bgp_vrf,
}
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh %s rmac %pEA add", n->bgp_vrf->name,
- n->nh_str, &n->rmac);
+ zlog_debug("evpn vrf %s nh %s rmac %pEA add",
+ n->bgp_vrf->name_pretty, n->nh_str, &n->rmac);
bgp_evpn_nh_zebra_update(n, true);
return n;
}
@@ -4513,8 +4514,8 @@ static void bgp_evpn_nh_del(struct bgp_evpn_nh *n)
return;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh %s del to zebra", bgp_vrf->name,
- n->nh_str);
+ zlog_debug("evpn vrf %s nh %s del to zebra",
+ bgp_vrf->name_pretty, n->nh_str);
bgp_evpn_nh_zebra_update(n, false);
list_delete(&n->pi_list);
@@ -4556,7 +4557,7 @@ static bool bgp_evpn_nh_cmp(const void *p1, const void *p2)
void bgp_evpn_nh_init(struct bgp *bgp_vrf)
{
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh init", bgp_vrf->name);
+ zlog_debug("evpn vrf %s nh init", bgp_vrf->name_pretty);
bgp_vrf->evpn_nh_table = hash_create(
bgp_evpn_nh_hash_keymake, bgp_evpn_nh_cmp, "BGP EVPN NH table");
}
@@ -4568,7 +4569,7 @@ static void bgp_evpn_nh_flush_entry(struct bgp_evpn_nh *nh)
struct bgp_path_evpn_nh_info *nh_info;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh %s flush", nh->bgp_vrf->name,
+ zlog_debug("evpn vrf %s nh %s flush", nh->bgp_vrf->name_pretty,
nh->nh_str);
/* force flush paths */
@@ -4586,7 +4587,7 @@ static void bgp_evpn_nh_flush_cb(struct hash_bucket *bucket, void *ctxt)
void bgp_evpn_nh_finish(struct bgp *bgp_vrf)
{
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh finish", bgp_vrf->name);
+ zlog_debug("evpn vrf %s nh finish", bgp_vrf->name_pretty);
hash_iterate(
bgp_vrf->evpn_nh_table,
(void (*)(struct hash_bucket *, void *))bgp_evpn_nh_flush_cb,
@@ -4612,7 +4613,7 @@ static void bgp_evpn_nh_update_ref_pi(struct bgp_evpn_nh *nh)
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug("evpn vrf %s nh %s ref_pi update",
- nh->bgp_vrf->name, nh->nh_str);
+ nh->bgp_vrf->name_pretty, nh->nh_str);
nh->ref_pi = pi;
/* If we have a new pi copy rmac from it and update
* zebra if the new rmac is different
@@ -4632,8 +4633,8 @@ static void bgp_evpn_nh_clear_ref_pi(struct bgp_evpn_nh *nh,
return;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh %s ref_pi clear", nh->bgp_vrf->name,
- nh->nh_str);
+ zlog_debug("evpn vrf %s nh %s ref_pi clear",
+ nh->bgp_vrf->name_pretty, nh->nh_str);
nh->ref_pi = NULL;
/* try to find another ref_pi */
bgp_evpn_nh_update_ref_pi(nh);
@@ -4692,7 +4693,7 @@ static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info)
pi->net ? prefix2str(&pi->net->p, prefix_buf,
sizeof(prefix_buf))
: "",
- nh->bgp_vrf->name, nh->nh_str);
+ nh->bgp_vrf->name_pretty, nh->nh_str);
list_delete_node(nh->pi_list, &nh_info->nh_listnode);
@@ -4724,7 +4725,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi)
if (!bgp_vrf->evpn_nh_table) {
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("path %pFX linked to vrf %s failed",
- &pi->net->p, bgp_vrf->name);
+ &pi->net->p, bgp_vrf->name_pretty);
return;
}
@@ -4772,7 +4773,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi)
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("path %pFX linked to nh %s %s", &pi->net->p,
- nh->bgp_vrf->name, nh->nh_str);
+ nh->bgp_vrf->name_pretty, nh->nh_str);
/* link mac-ip path to the new nh */
nh_info->nh = nh;
@@ -4786,7 +4787,8 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi)
if (!nh->ref_pi)
zlog_debug(
"path %pFX linked to nh %s %s with no valid pi",
- &pi->net->p, nh->bgp_vrf->name, nh->nh_str);
+ &pi->net->p, nh->bgp_vrf->name_pretty,
+ nh->nh_str);
}
}
@@ -4826,15 +4828,15 @@ static void bgp_evpn_nh_show_entry(struct bgp_evpn_nh *nh, struct vty *vty,
else
prefix_buf[0] = '\0';
if (json) {
- json_object_string_add(json, "vrf", nh->bgp_vrf->name);
+ json_object_string_add(json, "vrf", nh->bgp_vrf->name_pretty);
json_object_string_add(json, "ip", nh->nh_str);
json_object_string_add(json, "rmac", mac_buf);
json_object_string_add(json, "basePath", prefix_buf);
json_object_int_add(json, "pathCount", listcount(nh->pi_list));
} else {
- vty_out(vty, "%-15s %-15s %-17s %-10d %s\n", nh->bgp_vrf->name,
- nh->nh_str, mac_buf, listcount(nh->pi_list),
- prefix_buf);
+ vty_out(vty, "%-15s %-15s %-17s %-10d %s\n",
+ nh->bgp_vrf->name_pretty, nh->nh_str, mac_buf,
+ listcount(nh->pi_list), prefix_buf);
}
/* add ES to the json array */
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 88c1329f48..c3f648b720 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -372,7 +372,6 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
json_object *json)
{
- char buf1[INET6_ADDRSTRLEN];
char *ecom_str;
struct listnode *node, *nnode;
struct vrf_route_target *l3rt;
@@ -419,9 +418,8 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
vty_out(vty, " Advertise-svi-macip : %s\n", "n/a");
vty_out(vty, " Advertise-pip: %s\n",
bgp_vrf->evpn_info->advertise_pip ? "Yes" : "No");
- vty_out(vty, " System-IP: %s\n",
- inet_ntop(AF_INET, &bgp_vrf->evpn_info->pip_ip,
- buf1, INET_ADDRSTRLEN));
+ vty_out(vty, " System-IP: %pI4\n",
+ &bgp_vrf->evpn_info->pip_ip);
vty_out(vty, " System-MAC: %s\n",
prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac,
buf2, sizeof(buf2)));
@@ -2537,6 +2535,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
safi_t safi;
json_object *json_paths = NULL;
struct ethaddr empty_mac = {};
+ struct ipaddr empty_ip = {};
const struct prefix_evpn *evp;
afi = AFI_L2VPN;
@@ -2550,7 +2549,8 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
return;
}
- build_evpn_type2_prefix(&p, mac ? mac : &empty_mac, ip);
+ build_evpn_type2_prefix(&p, mac ? mac : &empty_mac,
+ ip ? ip : &empty_ip);
/* See if route exists. Look for both non-sticky and sticky. */
dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
@@ -7071,8 +7071,6 @@ static int vni_cmp(const void **a, const void **b)
void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi)
{
- char buf2[INET6_ADDRSTRLEN];
-
if (bgp->advertise_all_vni)
vty_out(vty, " advertise-all-vni\n");
@@ -7217,10 +7215,8 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp->evpn_info->advertise_pip) {
if (bgp->evpn_info->pip_ip_static.s_addr
!= INADDR_ANY) {
- vty_out(vty, " advertise-pip ip %s",
- inet_ntop(AF_INET,
- &bgp->evpn_info->pip_ip_static,
- buf2, INET_ADDRSTRLEN));
+ vty_out(vty, " advertise-pip ip %pI4",
+ &bgp->evpn_info->pip_ip_static);
if (!is_zero_mac(&(
bgp->evpn_info->pip_rmac_static))) {
char buf[ETHER_ADDR_STRLEN];
diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c
index 02dcdfcaa3..626e980346 100644
--- a/bgpd/bgp_flowspec_vty.c
+++ b/bgpd/bgp_flowspec_vty.c
@@ -338,18 +338,14 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
local_buff[0] = '\0';
if (p->u.prefix_flowspec.family == AF_INET
&& attr->nexthop.s_addr != INADDR_ANY)
- inet_ntop(AF_INET,
- &attr->nexthop.s_addr,
- local_buff,
- INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET, &attr->nexthop.s_addr,
+ local_buff, sizeof(local_buff));
else if (p->u.prefix_flowspec.family == AF_INET6 &&
attr->mp_nexthop_len != 0 &&
attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV4 &&
attr->mp_nexthop_len != BGP_ATTR_NHLEN_VPNV4)
- inet_ntop(AF_INET6,
- &attr->mp_nexthop_global,
- local_buff,
- INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, &attr->mp_nexthop_global,
+ local_buff, sizeof(local_buff));
if (local_buff[0] != '\0')
vty_out(vty, "\tNLRI NH %s\n",
local_buff);
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index fcb7275c34..923586f633 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -61,6 +61,13 @@
DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer));
DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer));
+enum bgp_fsm_state_progress {
+ BGP_FSM_FAILURE_AND_DELETE = -2,
+ BGP_FSM_FAILURE = -1,
+ BGP_FSM_SUCCESS = 0,
+ BGP_FSM_SUCCESS_STATE_TRANSFER = 1,
+};
+
/* Definition of display strings corresponding to FSM events. This should be
* kept consistent with the events defined in bgpd.h
*/
@@ -99,7 +106,7 @@ static void bgp_holdtime_timer(struct thread *);
static void bgp_delayopen_timer(struct thread *);
/* BGP FSM functions. */
-static int bgp_start(struct peer *);
+static enum bgp_fsm_state_progress bgp_start(struct peer *);
/* Register peer with NHT */
int bgp_peer_reg_with_nht(struct peer *peer)
@@ -1238,7 +1245,7 @@ static void bgp_update_delay_process_status_change(struct peer *peer)
/* Called after event occurred, this function change status and reset
read/write and timer thread. */
-void bgp_fsm_change_status(struct peer *peer, int status)
+void bgp_fsm_change_status(struct peer *peer, enum bgp_fsm_status status)
{
struct bgp *bgp;
uint32_t peer_count;
@@ -1293,7 +1300,8 @@ void bgp_fsm_change_status(struct peer *peer, int status)
* Clearing
* (or Deleted).
*/
- if (!work_queue_is_scheduled(peer->clear_node_queue))
+ if (!work_queue_is_scheduled(peer->clear_node_queue) &&
+ status != Deleted)
BGP_EVENT_ADD(peer, Clearing_Completed);
}
@@ -1341,11 +1349,11 @@ void bgp_fsm_change_status(struct peer *peer, int status)
}
/* Flush the event queue and ensure the peer is shut down */
-static int bgp_clearing_completed(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_clearing_completed(struct peer *peer)
{
- int rc = bgp_stop(peer);
+ enum bgp_fsm_state_progress rc = bgp_stop(peer);
- if (rc >= 0)
+ if (rc >= BGP_FSM_SUCCESS)
BGP_EVENT_FLUSH(peer);
return rc;
@@ -1353,12 +1361,12 @@ static int bgp_clearing_completed(struct peer *peer)
/* Administrative BGP peer stop event. */
/* May be called multiple times for the same peer */
-int bgp_stop(struct peer *peer)
+enum bgp_fsm_state_progress bgp_stop(struct peer *peer)
{
afi_t afi;
safi_t safi;
char orf_name[BUFSIZ];
- int ret = 0;
+ enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS;
struct bgp *bgp = peer->bgp;
struct graceful_restart_info *gr_info = NULL;
@@ -1375,7 +1383,7 @@ int bgp_stop(struct peer *peer)
zlog_debug("%s (dynamic neighbor) deleted (%s)",
peer->host, __func__);
peer_delete(peer);
- return -1;
+ return BGP_FSM_FAILURE_AND_DELETE;
}
/* Can't do this in Clearing; events are used for state transitions */
@@ -1584,7 +1592,7 @@ int bgp_stop(struct peer *peer)
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)
&& !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
peer_delete(peer);
- ret = -1;
+ ret = BGP_FSM_FAILURE_AND_DELETE;
} else {
bgp_peer_conf_if_to_su_update(peer);
}
@@ -1592,7 +1600,7 @@ int bgp_stop(struct peer *peer)
}
/* BGP peer is stoped by the error. */
-static int bgp_stop_with_error(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_stop_with_error(struct peer *peer)
{
/* Double start timer. */
peer->v_start *= 2;
@@ -1606,16 +1614,16 @@ static int bgp_stop_with_error(struct peer *peer)
zlog_debug("%s (dynamic neighbor) deleted (%s)",
peer->host, __func__);
peer_delete(peer);
- return -1;
+ return BGP_FSM_FAILURE;
}
- return (bgp_stop(peer));
+ return bgp_stop(peer);
}
/* something went wrong, send notify and tear down */
-static int bgp_stop_with_notify(struct peer *peer, uint8_t code,
- uint8_t sub_code)
+static enum bgp_fsm_state_progress
+bgp_stop_with_notify(struct peer *peer, uint8_t code, uint8_t sub_code)
{
/* Send notify to remote peer */
bgp_notify_send(peer, code, sub_code);
@@ -1625,13 +1633,13 @@ static int bgp_stop_with_notify(struct peer *peer, uint8_t code,
zlog_debug("%s (dynamic neighbor) deleted (%s)",
peer->host, __func__);
peer_delete(peer);
- return -1;
+ return BGP_FSM_FAILURE;
}
/* Clear start timer value to default. */
peer->v_start = BGP_INIT_START_TIMER;
- return (bgp_stop(peer));
+ return bgp_stop(peer);
}
/**
@@ -1696,13 +1704,12 @@ static void bgp_connect_check(struct thread *thread)
/* TCP connection open. Next we send open message to remote peer. And
add read thread for reading open message. */
-static int bgp_connect_success(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_connect_success(struct peer *peer)
{
if (peer->fd < 0) {
flog_err(EC_BGP_CONNECT, "%s peer's fd is negative value %d",
__func__, peer->fd);
- bgp_stop(peer);
- return -1;
+ return bgp_stop(peer);
}
if (bgp_getsockname(peer) < 0) {
@@ -1712,7 +1719,7 @@ static int bgp_connect_success(struct peer *peer)
bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
bgp_fsm_error_subcode(peer->status));
bgp_writes_on(peer);
- return -1;
+ return BGP_FSM_FAILURE;
}
/*
@@ -1734,19 +1741,19 @@ static int bgp_connect_success(struct peer *peer)
/* Send an open message */
bgp_open_send(peer);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* TCP connection open with RFC 4271 optional session attribute DelayOpen flag
* set.
*/
-static int bgp_connect_success_w_delayopen(struct peer *peer)
+static enum bgp_fsm_state_progress
+bgp_connect_success_w_delayopen(struct peer *peer)
{
if (peer->fd < 0) {
flog_err(EC_BGP_CONNECT, "%s: peer's fd is negative value %d",
__func__, peer->fd);
- bgp_stop(peer);
- return -1;
+ return bgp_stop(peer);
}
if (bgp_getsockname(peer) < 0) {
@@ -1756,7 +1763,7 @@ static int bgp_connect_success_w_delayopen(struct peer *peer)
bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
bgp_fsm_error_subcode(peer->status));
bgp_writes_on(peer);
- return -1;
+ return BGP_FSM_FAILURE;
}
/*
@@ -1787,18 +1794,18 @@ static int bgp_connect_success_w_delayopen(struct peer *peer)
zlog_debug("%s [FSM] BGP OPEN message delayed for %d seconds",
peer->host, peer->delayopen);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* TCP connect fail */
-static int bgp_connect_fail(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_connect_fail(struct peer *peer)
{
if (peer_dynamic_neighbor_no_nsf(peer)) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s (dynamic neighbor) deleted (%s)",
peer->host, __func__);
peer_delete(peer);
- return -1;
+ return BGP_FSM_FAILURE_AND_DELETE;
}
/*
@@ -1807,13 +1814,13 @@ static int bgp_connect_fail(struct peer *peer)
*/
bgp_nht_interface_events(peer);
- return (bgp_stop(peer));
+ return bgp_stop(peer);
}
/* This function is the first starting point of all BGP connection. It
* try to connect to remote peer with non-blocking IO.
*/
-int bgp_start(struct peer *peer)
+enum bgp_fsm_state_progress bgp_start(struct peer *peer)
{
int status;
@@ -1825,7 +1832,7 @@ int bgp_start(struct peer *peer)
"%s [FSM] Unable to get neighbor's IP address, waiting...",
peer->host);
peer->last_reset = PEER_DOWN_NBR_ADDR;
- return -1;
+ return BGP_FSM_FAILURE;
}
if (BGP_PEER_START_SUPPRESSED(peer)) {
@@ -1841,7 +1848,7 @@ int bgp_start(struct peer *peer)
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
else if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
peer->last_reset = PEER_DOWN_PFX_COUNT;
- return -1;
+ return BGP_FSM_FAILURE;
}
/* Scrub some information that might be left over from a previous,
@@ -1867,7 +1874,7 @@ int bgp_start(struct peer *peer)
/* If the peer is passive mode, force to move to Active mode. */
if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) {
BGP_EVENT_ADD(peer, TCP_connection_open_failed);
- return 0;
+ return BGP_FSM_SUCCESS;
}
if (peer->bgp->vrf_id == VRF_UNKNOWN) {
@@ -1877,7 +1884,7 @@ int bgp_start(struct peer *peer)
"%s [FSM] In a VRF that is not initialised yet",
peer->host);
peer->last_reset = PEER_DOWN_VRF_UNINIT;
- return -1;
+ return BGP_FSM_FAILURE;
}
/* Register peer for NHT. If next hop is already resolved, proceed
@@ -1891,7 +1898,7 @@ int bgp_start(struct peer *peer)
peer->host);
peer->last_reset = PEER_DOWN_WAITING_NHT;
BGP_EVENT_ADD(peer, TCP_connection_open_failed);
- return 0;
+ return BGP_FSM_SUCCESS;
}
}
@@ -1926,7 +1933,7 @@ int bgp_start(struct peer *peer)
flog_err(EC_BGP_FSM,
"%s peer's fd is negative value %d", __func__,
peer->fd);
- return -1;
+ return BGP_FSM_FAILURE;
}
/*
* - when the socket becomes ready, poll() will signify POLLOUT
@@ -1943,24 +1950,26 @@ int bgp_start(struct peer *peer)
&peer->t_connect_check_w);
break;
}
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* Connect retry timer is expired when the peer status is Connect. */
-static int bgp_reconnect(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_reconnect(struct peer *peer)
{
- if (bgp_stop(peer) < 0)
- return -1;
+ enum bgp_fsm_state_progress ret;
+
+ ret = bgp_stop(peer);
+ if (ret < BGP_FSM_SUCCESS)
+ return ret;
/* Send graceful restart capabilty */
BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
peer->bgp->peer);
- bgp_start(peer);
- return 0;
+ return bgp_start(peer);
}
-static int bgp_fsm_open(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_open(struct peer *peer)
{
/* If DelayOpen is active, we may still need to send an open message */
if ((peer->status == Connect) || (peer->status == Active))
@@ -1969,12 +1978,12 @@ static int bgp_fsm_open(struct peer *peer)
/* Send keepalive and make keepalive timer */
bgp_keepalive_send(peer);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* FSM error, unexpected event. This is error of BGP connection. So cut the
peer and change to Idle status. */
-static int bgp_fsm_event_error(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_event_error(struct peer *peer)
{
flog_err(EC_BGP_FSM, "%s [FSM] unexpected packet received in state %s",
peer->host, lookup_msg(bgp_status_msg, peer->status, NULL));
@@ -1985,7 +1994,7 @@ static int bgp_fsm_event_error(struct peer *peer)
/* Hold timer expire. This is error of BGP connection. So cut the
peer and change to Idle status. */
-static int bgp_fsm_holdtime_expire(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_holdtime_expire(struct peer *peer)
{
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s [FSM] Hold timer expire", peer->host);
@@ -2003,7 +2012,8 @@ static int bgp_fsm_holdtime_expire(struct peer *peer)
}
/* RFC 4271 DelayOpenTimer_Expires event */
-static int bgp_fsm_delayopen_timer_expire(struct peer *peer)
+static enum bgp_fsm_state_progress
+bgp_fsm_delayopen_timer_expire(struct peer *peer)
{
/* Stop the DelayOpenTimer */
THREAD_OFF(peer->t_delayopen);
@@ -2014,7 +2024,7 @@ static int bgp_fsm_delayopen_timer_expire(struct peer *peer)
/* Set the HoldTimer to a large value (4 minutes) */
peer->v_holdtime = 245;
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* Start the selection deferral timer thread for the specified AFI, SAFI */
@@ -2095,25 +2105,28 @@ static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi)
* Convert peer from stub to full fledged peer, set some timers, and generate
* initial updates.
*/
-static int bgp_establish(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_establish(struct peer *peer)
{
afi_t afi;
safi_t safi;
int nsf_af_count = 0;
- int ret = 0;
+ enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS;
struct peer *other;
int status;
other = peer->doppelganger;
+ hash_release(peer->bgp->peerhash, peer);
+ if (other)
+ hash_release(peer->bgp->peerhash, other);
+
peer = peer_xfer_conn(peer);
if (!peer) {
flog_err(EC_BGP_CONNECT, "%%Neighbor failed in xfer_conn");
- return -1;
+ return BGP_FSM_FAILURE;
}
if (other == peer)
- ret = 1; /* bgp_establish specific code when xfer_conn
- happens. */
+ ret = BGP_FSM_SUCCESS_STATE_TRANSFER;
/* Reset capability open status flag. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
@@ -2309,7 +2322,6 @@ static int bgp_establish(struct peer *peer)
* the doppelgangers su and this peer's su are the same
* so the hash_release is the same for either.
*/
- hash_release(peer->bgp->peerhash, peer);
(void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
/* Start BFD peer if not already running. */
@@ -2320,21 +2332,21 @@ static int bgp_establish(struct peer *peer)
}
/* Keepalive packet is received. */
-static int bgp_fsm_keepalive(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_keepalive(struct peer *peer)
{
THREAD_OFF(peer->t_holdtime);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* Update packet is received. */
-static int bgp_fsm_update(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_update(struct peer *peer)
{
THREAD_OFF(peer->t_holdtime);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* This is empty event. */
-static int bgp_ignore(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_ignore(struct peer *peer)
{
flog_err(
EC_BGP_FSM,
@@ -2343,11 +2355,11 @@ static int bgp_ignore(struct peer *peer)
lookup_msg(bgp_status_msg, peer->status, NULL),
bgp_event_str[peer->last_event],
bgp_event_str[peer->last_major_event], peer->fd);
- return 0;
+ return BGP_FSM_SUCCESS;
}
/* This is to handle unexpected events.. */
-static int bgp_fsm_exeption(struct peer *peer)
+static enum bgp_fsm_state_progress bgp_fsm_exception(struct peer *peer)
{
flog_err(
EC_BGP_FSM,
@@ -2356,7 +2368,7 @@ static int bgp_fsm_exeption(struct peer *peer)
lookup_msg(bgp_status_msg, peer->status, NULL),
bgp_event_str[peer->last_event],
bgp_event_str[peer->last_major_event], peer->fd);
- return (bgp_stop(peer));
+ return bgp_stop(peer);
}
void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops)
@@ -2397,7 +2409,7 @@ void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops)
/* Finite State Machine structure */
static const struct {
- int (*func)(struct peer *);
+ enum bgp_fsm_state_progress (*func)(struct peer *);
enum bgp_fsm_status next_state;
} FSM[BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] = {
{
@@ -2428,19 +2440,19 @@ static const struct {
{bgp_connect_success, OpenSent}, /* TCP_connection_open */
{bgp_connect_success_w_delayopen,
Connect}, /* TCP_connection_open_w_delay */
- {bgp_stop, Idle}, /* TCP_connection_closed */
+ {bgp_stop, Idle}, /* TCP_connection_closed */
{bgp_connect_fail, Active}, /* TCP_connection_open_failed */
{bgp_connect_fail, Idle}, /* TCP_fatal_error */
{bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */
- {bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */
- {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
+ {bgp_fsm_exception, Idle}, /* Hold_Timer_expired */
+ {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */
{bgp_fsm_delayopen_timer_expire,
OpenSent}, /* DelayOpen_timer_expired */
{bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
- {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
- {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_exception, Idle}, /* Receive_KEEPALIVE_message */
+ {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */
+ {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* Active, */
@@ -2448,97 +2460,97 @@ static const struct {
{bgp_stop, Idle}, /* BGP_Stop */
{bgp_connect_success, OpenSent}, /* TCP_connection_open */
{bgp_connect_success_w_delayopen,
- Active}, /* TCP_connection_open_w_delay */
- {bgp_stop, Idle}, /* TCP_connection_closed */
- {bgp_ignore, Active}, /* TCP_connection_open_failed */
- {bgp_fsm_exeption, Idle}, /* TCP_fatal_error */
- {bgp_start, Connect}, /* ConnectRetry_timer_expired */
- {bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */
- {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
+ Active}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Idle}, /* TCP_connection_closed */
+ {bgp_ignore, Active}, /* TCP_connection_open_failed */
+ {bgp_fsm_exception, Idle}, /* TCP_fatal_error */
+ {bgp_start, Connect}, /* ConnectRetry_timer_expired */
+ {bgp_fsm_exception, Idle}, /* Hold_Timer_expired */
+ {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */
{bgp_fsm_delayopen_timer_expire,
OpenSent}, /* DelayOpen_timer_expired */
{bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
- {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_exception, Idle}, /* Receive_KEEPALIVE_message */
+ {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */
+ {bgp_fsm_exception, Idle}, /* Receive_NOTIFICATION_message */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* OpenSent, */
- {bgp_ignore, OpenSent}, /* BGP_Start */
- {bgp_stop, Idle}, /* BGP_Stop */
- {bgp_stop, Active}, /* TCP_connection_open */
- {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
- {bgp_stop, Active}, /* TCP_connection_closed */
- {bgp_stop, Active}, /* TCP_connection_open_failed */
- {bgp_stop, Active}, /* TCP_fatal_error */
- {bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */
+ {bgp_ignore, OpenSent}, /* BGP_Start */
+ {bgp_stop, Idle}, /* BGP_Stop */
+ {bgp_stop, Active}, /* TCP_connection_open */
+ {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Active}, /* TCP_connection_closed */
+ {bgp_stop, Active}, /* TCP_connection_open_failed */
+ {bgp_stop, Active}, /* TCP_fatal_error */
+ {bgp_fsm_exception, Idle}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
- {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
- {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
+ {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */
+ {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */
{bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
{bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */
{bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */
{bgp_fsm_event_error, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* OpenConfirm, */
{bgp_ignore, OpenConfirm}, /* BGP_Start */
- {bgp_stop, Idle}, /* BGP_Stop */
- {bgp_stop, Idle}, /* TCP_connection_open */
- {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
- {bgp_stop, Idle}, /* TCP_connection_closed */
- {bgp_stop, Idle}, /* TCP_connection_open_failed */
- {bgp_stop, Idle}, /* TCP_fatal_error */
- {bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */
+ {bgp_stop, Idle}, /* BGP_Stop */
+ {bgp_stop, Idle}, /* TCP_connection_open */
+ {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Idle}, /* TCP_connection_closed */
+ {bgp_stop, Idle}, /* TCP_connection_open_failed */
+ {bgp_stop, Idle}, /* TCP_fatal_error */
+ {bgp_fsm_exception, Idle}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
{bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */
- {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
- {bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */
+ {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */
+ {bgp_fsm_exception, Idle}, /* Receive_OPEN_message */
{bgp_establish, Established}, /* Receive_KEEPALIVE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
+ {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */
{bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* Established, */
{bgp_ignore, Established}, /* BGP_Start */
- {bgp_stop, Clearing}, /* BGP_Stop */
- {bgp_stop, Clearing}, /* TCP_connection_open */
- {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
- {bgp_stop, Clearing}, /* TCP_connection_closed */
- {bgp_stop, Clearing}, /* TCP_connection_open_failed */
- {bgp_stop, Clearing}, /* TCP_fatal_error */
- {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
+ {bgp_stop, Clearing}, /* BGP_Stop */
+ {bgp_stop, Clearing}, /* TCP_connection_open */
+ {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Clearing}, /* TCP_connection_closed */
+ {bgp_stop, Clearing}, /* TCP_connection_open_failed */
+ {bgp_stop, Clearing}, /* TCP_fatal_error */
+ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */
{bgp_ignore, Established}, /* KeepAlive_timer_expired */
- {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
- {bgp_stop, Clearing}, /* Receive_OPEN_message */
+ {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */
+ {bgp_stop, Clearing}, /* Receive_OPEN_message */
{bgp_fsm_keepalive,
Established}, /* Receive_KEEPALIVE_message */
{bgp_fsm_update, Established}, /* Receive_UPDATE_message */
{bgp_stop_with_error,
- Clearing}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ Clearing}, /* Receive_NOTIFICATION_message */
+ {bgp_fsm_exception, Idle}, /* Clearing_Completed */
},
{
/* Clearing, */
{bgp_ignore, Clearing}, /* BGP_Start */
- {bgp_stop, Clearing}, /* BGP_Stop */
- {bgp_stop, Clearing}, /* TCP_connection_open */
- {bgp_stop, Clearing}, /* TCP_connection_open_w_delay */
- {bgp_stop, Clearing}, /* TCP_connection_closed */
- {bgp_stop, Clearing}, /* TCP_connection_open_failed */
- {bgp_stop, Clearing}, /* TCP_fatal_error */
- {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
- {bgp_stop, Clearing}, /* Hold_Timer_expired */
- {bgp_stop, Clearing}, /* KeepAlive_timer_expired */
- {bgp_stop, Clearing}, /* DelayOpen_timer_expired */
- {bgp_stop, Clearing}, /* Receive_OPEN_message */
- {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */
- {bgp_stop, Clearing}, /* Receive_UPDATE_message */
- {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */
+ {bgp_stop, Clearing}, /* BGP_Stop */
+ {bgp_stop, Clearing}, /* TCP_connection_open */
+ {bgp_stop, Clearing}, /* TCP_connection_open_w_delay */
+ {bgp_stop, Clearing}, /* TCP_connection_closed */
+ {bgp_stop, Clearing}, /* TCP_connection_open_failed */
+ {bgp_stop, Clearing}, /* TCP_fatal_error */
+ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
+ {bgp_stop, Clearing}, /* Hold_Timer_expired */
+ {bgp_stop, Clearing}, /* KeepAlive_timer_expired */
+ {bgp_stop, Clearing}, /* DelayOpen_timer_expired */
+ {bgp_stop, Clearing}, /* Receive_OPEN_message */
+ {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */
+ {bgp_stop, Clearing}, /* Receive_UPDATE_message */
+ {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */
{bgp_clearing_completed, Idle}, /* Clearing_Completed */
},
{
@@ -2571,13 +2583,15 @@ void bgp_event(struct thread *thread)
peer = THREAD_ARG(thread);
event = THREAD_VAL(thread);
+ peer_lock(peer);
bgp_event_update(peer, event);
+ peer_unlock(peer);
}
int bgp_event_update(struct peer *peer, enum bgp_fsm_events event)
{
enum bgp_fsm_status next;
- int ret = 0;
+ enum bgp_fsm_state_progress ret = 0;
struct peer *other;
int passive_conn = 0;
int dyn_nbr;
@@ -2606,8 +2620,9 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event)
if (FSM[peer->status - 1][event - 1].func)
ret = (*(FSM[peer->status - 1][event - 1].func))(peer);
- if (ret >= 0) {
- if (ret == 1 && next == Established) {
+ if (ret >= BGP_FSM_SUCCESS) {
+ if (ret == BGP_FSM_SUCCESS_STATE_TRANSFER &&
+ next == Established) {
/* The case when doppelganger swap accurred in
bgp_establish.
Update the peer pointer accordingly */
@@ -2641,7 +2656,8 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event)
* we need to indicate that the peer was stopped in the return
* code.
*/
- if (!dyn_nbr && !passive_conn && peer->bgp) {
+ if (!dyn_nbr && !passive_conn && peer->bgp &&
+ ret != BGP_FSM_FAILURE_AND_DELETE) {
flog_err(
EC_BGP_FSM,
"%s [FSM] Failure handling event %s in state %s, prior events %s, %s, fd %d",
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index 368c2c5001..6418e15b9a 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -125,7 +125,8 @@ extern int bgp_event_update(struct peer *, enum bgp_fsm_events event);
extern int bgp_stop(struct peer *peer);
extern void bgp_timer_set(struct peer *);
extern void bgp_routeadv_timer(struct thread *);
-extern void bgp_fsm_change_status(struct peer *peer, int status);
+extern void bgp_fsm_change_status(struct peer *peer,
+ enum bgp_fsm_status status);
extern const char *const peer_down_str[];
extern void bgp_update_delay_end(struct bgp *);
extern void bgp_maxmed_update(struct bgp *);
diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c
index b39a7daa1d..0e83157ecd 100644
--- a/bgpd/bgp_keepalives.c
+++ b/bgpd/bgp_keepalives.c
@@ -36,6 +36,10 @@
#include "bgpd/bgp_keepalives.h"
/* clang-format on */
+DEFINE_MTYPE_STATIC(BGPD, BGP_PKAT, "Peer KeepAlive Timer");
+DEFINE_MTYPE_STATIC(BGPD, BGP_COND, "BGP Peer pthread Conditional");
+DEFINE_MTYPE_STATIC(BGPD, BGP_MUTEX, "BGP Peer pthread Mutex");
+
/*
* Peer KeepAlive Timer.
* Associates a peer with the time of its last keepalive.
@@ -54,7 +58,7 @@ static struct hash *peerhash;
static struct pkat *pkat_new(struct peer *peer)
{
- struct pkat *pkat = XMALLOC(MTYPE_TMP, sizeof(struct pkat));
+ struct pkat *pkat = XMALLOC(MTYPE_BGP_PKAT, sizeof(struct pkat));
pkat->peer = peer;
monotime(&pkat->last);
return pkat;
@@ -62,7 +66,7 @@ static struct pkat *pkat_new(struct peer *peer)
static void pkat_del(void *pkat)
{
- XFREE(MTYPE_TMP, pkat);
+ XFREE(MTYPE_BGP_PKAT, pkat);
}
@@ -158,8 +162,8 @@ static void bgp_keepalives_finish(void *arg)
pthread_mutex_destroy(peerhash_mtx);
pthread_cond_destroy(peerhash_cond);
- XFREE(MTYPE_TMP, peerhash_mtx);
- XFREE(MTYPE_TMP, peerhash_cond);
+ XFREE(MTYPE_BGP_MUTEX, peerhash_mtx);
+ XFREE(MTYPE_BGP_COND, peerhash_cond);
}
/*
@@ -184,8 +188,8 @@ void *bgp_keepalives_start(void *arg)
*/
rcu_read_unlock();
- peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t));
- peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t));
+ peerhash_mtx = XCALLOC(MTYPE_BGP_MUTEX, sizeof(pthread_mutex_t));
+ peerhash_cond = XCALLOC(MTYPE_BGP_COND, sizeof(pthread_cond_t));
/* initialize mutex */
pthread_mutex_init(peerhash_mtx, NULL);
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 64af8a5411..84c847d796 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -142,15 +142,21 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
&bpi2->attr->mp_nexthop_global);
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- addr1 = (bpi1->attr->mp_nexthop_prefer_global)
+ addr1 = (CHECK_FLAG(
+ bpi1->attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
? bpi1->attr->mp_nexthop_global
: bpi1->attr->mp_nexthop_local;
- addr2 = (bpi2->attr->mp_nexthop_prefer_global)
+ addr2 = (CHECK_FLAG(
+ bpi2->attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
? bpi2->attr->mp_nexthop_global
: bpi2->attr->mp_nexthop_local;
- if (!bpi1->attr->mp_nexthop_prefer_global
- && !bpi2->attr->mp_nexthop_prefer_global)
+ if (!CHECK_FLAG(bpi1->attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL) &&
+ !CHECK_FLAG(bpi2->attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
compare = !bgp_interface_same(
bpi1->peer->ifp,
bpi2->peer->ifp);
@@ -278,8 +284,10 @@ void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo)
static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void)
{
struct bgp_path_info_mpath *new_mpath;
+
new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
sizeof(struct bgp_path_info_mpath));
+
return new_mpath;
}
@@ -313,8 +321,6 @@ bgp_path_info_mpath_get(struct bgp_path_info *path)
if (!path->mpath) {
mpath = bgp_path_info_mpath_new();
- if (!mpath)
- return NULL;
path->mpath = mpath;
mpath->mp_info = path;
}
@@ -567,7 +573,7 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
if (debug)
zlog_debug(
- "%pRN(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw u%" PRIu64,
+ "%pRN(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64,
bgp_dest_to_rnode(dest), bgp->name_pretty,
new_best ? new_best->peer->host : "NONE",
mp_list ? listcount(mp_list) : 0, old_mpath_count,
@@ -750,7 +756,7 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
if (debug)
zlog_debug(
- "%pRN(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw u%" PRIu64,
+ "%pRN(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64,
bgp_dest_to_rnode(dest), bgp->name_pretty,
mpath_count, mpath_changed ? "YES" : "NO",
all_paths_lb, cum_bw);
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 18cb90763c..9b86c9b4b1 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -888,7 +888,7 @@ void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
srv6_locator_chunk_free(&bgp_vrf->vpn_policy[afi].tovpn_sid_locator);
if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
- sid_unregister(bgp_vrf, bgp_vrf->vpn_policy[afi].tovpn_sid);
+ sid_unregister(bgp_vpn, bgp_vrf->vpn_policy[afi].tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->vpn_policy[afi].tovpn_sid);
}
bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label = 0;
@@ -915,7 +915,7 @@ void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator);
if (bgp_vrf->tovpn_sid) {
- sid_unregister(bgp_vrf, bgp_vrf->tovpn_sid);
+ sid_unregister(bgp_vpn, bgp_vrf->tovpn_sid);
XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
}
bgp_vrf->tovpn_sid_transpose_label = 0;
@@ -1060,9 +1060,11 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
{
struct bgp_path_info *bpi_ultimate;
struct bgp *bgp_nexthop;
+ struct bgp_table *table;
bool nh_valid;
bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi);
+ table = bgp_dest_table(bpi_ultimate->net);
if (bpi->extra && bpi->extra->bgp_orig)
bgp_nexthop = bpi->extra->bgp_orig;
@@ -1070,13 +1072,25 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
bgp_nexthop = bgp_orig;
/*
- * No nexthop tracking for redistributed routes or for
+ * No nexthop tracking for redistributed routes,
+ * for static (i.e. coming from the bgp network statement or for
* EVPN-imported routes that get leaked.
*/
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
is_pi_family_evpn(bpi_ultimate))
nh_valid = 1;
- else
+ else if (bpi_ultimate->type == ZEBRA_ROUTE_BGP &&
+ bpi_ultimate->sub_type == BGP_ROUTE_STATIC && table &&
+ (table->safi == SAFI_UNICAST ||
+ table->safi == SAFI_LABELED_UNICAST)) {
+ /* Routes from network statement */
+ if (CHECK_FLAG(bgp_nexthop->flags, BGP_FLAG_IMPORT_CHECK))
+ nh_valid = bgp_find_or_add_nexthop(
+ to_bgp, bgp_nexthop, afi, safi, bpi_ultimate,
+ NULL, 0, p);
+ else
+ nh_valid = 1;
+ } else
/*
* TBD do we need to do anything about the
* 'connected' parameter?
@@ -1266,6 +1280,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
if (debug)
zlog_debug("%s: ->%s: %pBD Found route, changed attr",
__func__, to_bgp->name_pretty, bn);
+ UNSET_FLAG(bpi->attr->nh_flag, BGP_ATTR_NH_REFRESH);
return bpi;
}
@@ -1505,7 +1520,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
} else {
if (!CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
- if (afi == AFI_IP) {
+ if (afi == AFI_IP &&
+ !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) {
/*
* For ipv4, copy to multiprotocol
* nexthop field
@@ -1863,11 +1879,31 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
uint32_t num_labels = 0;
int nexthop_self_flag = 1;
struct bgp_path_info *bpi_ultimate = NULL;
+ struct bgp_path_info *bpi;
int origin_local = 0;
struct bgp *src_vrf;
+ struct interface *ifp;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
+ /*
+ * For VRF-2-VRF route-leaking,
+ * the source will be the originating VRF.
+ *
+ * If ACCEPT_OWN mechanism is enabled, then we SHOULD(?)
+ * get the source VRF (BGP) by looking at the RD.
+ */
+ struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi);
+
+ if (path_vpn->extra && path_vpn->extra->bgp_orig)
+ src_vrf = path_vpn->extra->bgp_orig;
+ else if (src_bgp)
+ src_vrf = src_bgp;
+ else
+ src_vrf = from_bgp;
+
+ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);
+
if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
@@ -1927,6 +1963,18 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
community_strip_accept_own(&static_attr);
+ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) {
+ if (bpi->extra && bpi->extra->parent == path_vpn)
+ break;
+ }
+
+ if (bpi &&
+ leak_update_nexthop_valid(to_bgp, bn, &static_attr, afi, safi,
+ path_vpn, bpi, src_vrf, p, debug))
+ SET_FLAG(static_attr.nh_flag, BGP_ATTR_NH_VALID);
+ else
+ UNSET_FLAG(static_attr.nh_flag, BGP_ATTR_NH_VALID);
+
/*
* Nexthop: stash and clear
*
@@ -1969,6 +2017,22 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
break;
}
+ if (static_attr.nexthop.s_addr == INADDR_ANY &&
+ IN6_IS_ADDR_UNSPECIFIED(&static_attr.mp_nexthop_global)) {
+ ifp = if_get_vrf_loopback(src_vrf->vrf_id);
+ if (ifp)
+ static_attr.nh_ifindex = ifp->ifindex;
+ } else if (static_attr.nh_ifindex)
+ ifp = if_lookup_by_index(static_attr.nh_ifindex,
+ src_vrf->vrf_id);
+ else
+ ifp = NULL;
+
+ if (ifp && if_is_operative(ifp))
+ SET_FLAG(static_attr.nh_flag, BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(static_attr.nh_flag, BGP_ATTR_NH_IF_OPERSTATE);
+
/*
* route map handling
*/
@@ -2050,22 +2114,6 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
zlog_debug("%s: pfx %pBD: num_labels %d", __func__,
path_vpn->net, num_labels);
- /*
- * For VRF-2-VRF route-leaking,
- * the source will be the originating VRF.
- *
- * If ACCEPT_OWN mechanism is enabled, then we SHOULD(?)
- * get the source VRF (BGP) by looking at the RD.
- */
- struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi);
-
- if (path_vpn->extra && path_vpn->extra->bgp_orig)
- src_vrf = path_vpn->extra->bgp_orig;
- else if (src_bgp)
- src_vrf = src_bgp;
- else
- src_vrf = from_bgp;
-
leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels,
num_labels, src_vrf, &nexthop_orig, nexthop_self_flag,
debug);
@@ -2820,6 +2868,10 @@ int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd,
{
struct bgp *bgp;
struct bgp_table *table;
+ uint16_t show_flags = 0;
+
+ if (use_json)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
bgp = bgp_get_default();
if (bgp == NULL) {
@@ -2831,7 +2883,7 @@ int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd,
}
table = bgp->rib[afi][SAFI_MPLS_VPN];
return bgp_show_table_rd(vty, bgp, SAFI_MPLS_VPN, table, prd, type,
- output_arg, use_json);
+ output_arg, show_flags);
}
DEFUN (show_bgp_ip_vpn_all_rd,
diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c
index 7a2f618ce6..8d5daa49c8 100644
--- a/bgpd/bgp_mplsvpn_snmp.c
+++ b/bgpd/bgp_mplsvpn_snmp.c
@@ -1529,7 +1529,7 @@ static uint8_t *mplsL3vpnRteTable(struct variable *v, oid name[],
char vrf_name[VRF_NAMSIZ];
struct bgp *l3vpn_bgp;
struct bgp_dest *dest;
- struct bgp_path_info *pi;
+ struct bgp_path_info *pi, *bpi_ultimate;
const struct prefix *p;
uint16_t policy = 0;
@@ -1545,6 +1545,8 @@ static uint8_t *mplsL3vpnRteTable(struct variable *v, oid name[],
if (!pi)
return NULL;
+ bpi_ultimate = bgp_get_imported_bpi_ultimate(pi);
+
p = bgp_dest_get_prefix(dest);
if (!p)
@@ -1661,8 +1663,8 @@ static uint8_t *mplsL3vpnRteTable(struct variable *v, oid name[],
case MPLSL3VPNVRFRTEINETCIDRNEXTHOPAS:
return SNMP_INTEGER(pi->peer ? pi->peer->as : 0);
case MPLSL3VPNVRFRTEINETCIDRMETRIC1:
- if (pi->extra)
- return SNMP_INTEGER(pi->extra->igpmetric);
+ if (bpi_ultimate->extra)
+ return SNMP_INTEGER(bpi_ultimate->extra->igpmetric);
else
return SNMP_INTEGER(0);
case MPLSL3VPNVRFRTEINETCIDRMETRIC2:
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index b43f8c8664..7186a50711 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -553,9 +553,7 @@ static void bgp_accept(struct thread *thread)
peer1->host);
peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as,
- peer1->as, peer1->as_type, NULL);
- hash_release(peer->bgp->peerhash, peer);
- (void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
+ peer1->as, peer1->as_type, NULL, false);
peer_xfer_config(peer, peer1);
bgp_peer_gr_flags_update(peer);
@@ -572,8 +570,6 @@ static void bgp_accept(struct thread *thread)
}
}
- UNSET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
-
peer->doppelganger = peer1;
peer1->doppelganger = peer;
peer->fd = bgp_sock;
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 075350cd2b..6bbdbdc1a9 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -500,11 +500,8 @@ static void bgp_connected_cleanup(struct route_table *table,
if (!bc)
return;
- bc->refcnt--;
- if (bc->refcnt == 0) {
- XFREE(MTYPE_BGP_CONN, bc);
- bgp_dest_set_bgp_connected_ref_info(bn, NULL);
- }
+ XFREE(MTYPE_BGP_CONN, bc);
+ bgp_dest_set_bgp_connected_ref_info(bn, NULL);
}
bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
@@ -768,28 +765,22 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
struct bgp_nexthop_cache *bnc)
{
- char buf[PREFIX2STR_BUFFER];
struct nexthop *nexthop;
for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) {
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV6:
- vty_out(vty, " gate %s\n",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
- sizeof(buf)));
+ vty_out(vty, " gate %pI6\n", &nexthop->gate.ipv6);
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " gate %s, if %s\n",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
- sizeof(buf)),
+ vty_out(vty, " gate %pI6, if %s\n",
+ &nexthop->gate.ipv6,
ifindex2ifname(bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_IPV4:
- vty_out(vty, " gate %s\n",
- inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
- sizeof(buf)));
+ vty_out(vty, " gate %pI4\n", &nexthop->gate.ipv4);
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out(vty, " if %s\n",
@@ -798,9 +789,8 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " gate %s, if %s\n",
- inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
- sizeof(buf)),
+ vty_out(vty, " gate %pI4, if %s\n",
+ &nexthop->gate.ipv4,
ifindex2ifname(bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bgp->vrf_id));
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index fd1aa6ab47..b6b0c584d7 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -46,6 +46,7 @@
#include "bgpd/bgp_flowspec_util.h"
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_rd.h"
+#include "bgpd/bgp_mplsvpn.h"
extern struct zclient *zclient;
@@ -212,6 +213,37 @@ void bgp_replace_nexthop_by_peer(struct peer *from, struct peer *to)
bnct->nht_info = to;
}
+/*
+ * Returns the bnc whose bnc->nht_info matches the LL peer by
+ * looping through the IPv6 nexthop table
+ */
+static struct bgp_nexthop_cache *
+bgp_find_ipv6_nexthop_matching_peer(struct peer *peer)
+{
+ struct bgp_nexthop_cache *bnc;
+
+ frr_each (bgp_nexthop_cache, &peer->bgp->nexthop_cache_table[AFI_IP6],
+ bnc) {
+ if (bnc->nht_info == peer) {
+ if (BGP_DEBUG(nht, NHT)) {
+ zlog_debug(
+ "Found bnc: %pFX(%u)(%u)(%p) for peer: %s(%s) %p",
+ &bnc->prefix, bnc->ifindex,
+ bnc->srte_color, bnc, peer->host,
+ peer->bgp->name_pretty, peer);
+ }
+ return bnc;
+ }
+ }
+
+ if (BGP_DEBUG(nht, NHT))
+ zlog_debug(
+ "Could not find bnc for peer %s(%s) %p in v6 nexthop table",
+ peer->host, peer->bgp->name_pretty, peer);
+
+ return NULL;
+}
+
void bgp_unlink_nexthop_by_peer(struct peer *peer)
{
struct prefix p;
@@ -219,15 +251,30 @@ void bgp_unlink_nexthop_by_peer(struct peer *peer)
afi_t afi = family2afi(peer->su.sa.sa_family);
ifindex_t ifindex = 0;
- if (!sockunion2hostprefix(&peer->su, &p))
- return;
- /*
- * Gather the ifindex for if up/down events to be
- * tagged into this fun
- */
- if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
- ifindex = peer->su.sin6.sin6_scope_id;
- bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0, ifindex);
+ if (!sockunion2hostprefix(&peer->su, &p)) {
+ /*
+ * In scenarios where unnumbered BGP session is brought
+ * down by shutting down the interface before unconfiguring
+ * the BGP neighbor, neighbor information in peer->su.sa
+ * will be cleared when the interface is shutdown. So
+ * during the deletion of unnumbered bgp peer, above check
+ * will return true. Therefore, in this case,BGP needs to
+ * find the bnc whose bnc->nht_info matches the
+ * peer being deleted and free it.
+ */
+ bnc = bgp_find_ipv6_nexthop_matching_peer(peer);
+ } else {
+ /*
+ * Gather the ifindex for if up/down events to be
+ * tagged into this fun
+ */
+ if (afi == AFI_IP6 &&
+ IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
+ ifindex = peer->su.sin6.sin6_scope_id;
+ bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0,
+ ifindex);
+ }
+
if (!bnc)
return;
@@ -248,6 +295,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
{
struct bgp_nexthop_cache_head *tree = NULL;
struct bgp_nexthop_cache *bnc;
+ struct bgp_path_info *bpi_ultimate;
struct prefix p;
uint32_t srte_color = 0;
int is_bgp_static_route = 0;
@@ -341,7 +389,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
if (pi && is_route_parent_evpn(pi))
bnc->is_evpn_gwip_nexthop = true;
- if (is_bgp_static_route) {
+ if (is_bgp_static_route && !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)) {
SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
/* If we're toggling the type, re-register */
@@ -376,8 +424,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
- } else if (peer && !connected
- && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) {
+ } else if (peer && !connected &&
+ CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) {
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
@@ -404,10 +452,12 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
/* updates NHT pi list reference */
path_nh_map(pi, bnc, true);
+ bpi_ultimate = bgp_get_imported_bpi_ultimate(pi);
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
- (bgp_path_info_extra_get(pi))->igpmetric = bnc->metric;
- else if (pi->extra)
- pi->extra->igpmetric = 0;
+ (bgp_path_info_extra_get(bpi_ultimate))->igpmetric =
+ bnc->metric;
+ else if (bpi_ultimate->extra)
+ bpi_ultimate->extra->igpmetric = 0;
} else if (peer) {
/*
* Let's not accidentally save the peer data for a peer
@@ -443,6 +493,15 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
if (!peer)
return;
+ /*
+ * In case the below check evaluates true and if
+ * the bnc has not been freed at this point, then
+ * we might have to do something similar to what's
+ * done in bgp_unlink_nexthop_by_peer(). Since
+ * bgp_unlink_nexthop_by_peer() loops through the
+ * nodes of V6 nexthop cache to find the bnc, it is
+ * currently not being called here.
+ */
if (!sockunion2hostprefix(&peer->su, &p))
return;
/*
@@ -776,10 +835,13 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
{
struct bgp_nexthop_cache_head *tree = NULL;
struct bgp_nexthop_cache *bnc_nhc, *bnc_import;
+ struct bgp_path_info *pi;
+ struct bgp_dest *dest;
struct bgp *bgp;
struct prefix match;
struct zapi_route nhr;
afi_t afi;
+ safi_t safi;
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp) {
@@ -800,25 +862,37 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
tree = &bgp->nexthop_cache_table[afi];
bnc_nhc = bnc_find(tree, &match, nhr.srte_color, 0);
- if (!bnc_nhc) {
- if (BGP_DEBUG(nht, NHT))
- zlog_debug(
- "parse nexthop update(%pFX(%u)(%s)): bnc info not found for nexthop cache",
- &nhr.prefix, nhr.srte_color, bgp->name_pretty);
- } else
+ if (bnc_nhc)
bgp_process_nexthop_update(bnc_nhc, &nhr, false);
+ else if (BGP_DEBUG(nht, NHT))
+ zlog_debug(
+ "parse nexthop update(%pFX(%u)(%s)): bnc info not found for nexthop cache",
+ &nhr.prefix, nhr.srte_color, bgp->name_pretty);
tree = &bgp->import_check_table[afi];
bnc_import = bnc_find(tree, &match, nhr.srte_color, 0);
- if (!bnc_import) {
- if (BGP_DEBUG(nht, NHT))
- zlog_debug(
- "parse nexthop update(%pFX(%u)(%s)): bnc info not found for import check",
- &nhr.prefix, nhr.srte_color, bgp->name_pretty);
- } else
+ if (bnc_import) {
bgp_process_nexthop_update(bnc_import, &nhr, true);
+ safi = nhr.safi;
+ if (bgp->rib[afi][safi]) {
+ dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
+ &match, NULL);
+
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi;
+ pi = pi->next)
+ if (pi->peer == bgp->peer_self &&
+ pi->type == ZEBRA_ROUTE_BGP &&
+ pi->sub_type == BGP_ROUTE_STATIC)
+ vpn_leak_from_vrf_update(
+ bgp_get_default(), bgp, pi);
+ }
+ } else if (BGP_DEBUG(nht, NHT))
+ zlog_debug(
+ "parse nexthop update(%pFX(%u)(%s)): bnc info not found for import check",
+ &nhr.prefix, nhr.srte_color, bgp->name_pretty);
+
/*
* HACK: if any BGP route is dependant on an SR-policy that doesn't
* exist, zebra will never send NH updates relative to that policy. In
@@ -931,7 +1005,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
*/
else if (pi->attr->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
- if (pi->attr->mp_nexthop_prefer_global)
+ if (CHECK_FLAG(pi->attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
p->u.prefix6 =
pi->attr->mp_nexthop_global;
else
@@ -1068,6 +1143,7 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
{
struct bgp_dest *dest;
struct bgp_path_info *path;
+ struct bgp_path_info *bpi_ultimate;
int afi;
struct peer *peer = (struct peer *)bnc->nht_info;
struct bgp_table *table;
@@ -1167,11 +1243,12 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
/* Copy the metric to the path. Will be used for bestpath
* computation */
+ bpi_ultimate = bgp_get_imported_bpi_ultimate(path);
if (bgp_isvalid_nexthop(bnc) && bnc->metric)
- (bgp_path_info_extra_get(path))->igpmetric =
+ (bgp_path_info_extra_get(bpi_ultimate))->igpmetric =
bnc->metric;
- else if (path->extra)
- path->extra->igpmetric = 0;
+ else if (bpi_ultimate->extra)
+ bpi_ultimate->extra->igpmetric = 0;
if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED)
|| CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index c8cb6b77e2..79c54dd32d 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -1658,7 +1658,7 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
as_t local_as;
uint8_t afi_safi_count = 0;
- int adv_addpath_tx = 0;
+ bool adv_addpath_tx = false;
/* Non-Ext OP Len. */
cp = stream_get_endp(s);
@@ -1797,7 +1797,17 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
* will use it is
* configured */
if (peer->addpath_type[afi][safi] != BGP_ADDPATH_NONE)
- adv_addpath_tx = 1;
+ adv_addpath_tx = true;
+
+ /* If we have enabled labeled unicast, we MUST check
+ * against unicast SAFI because addpath IDs are
+ * allocated under unicast SAFI, the same as the RIB
+ * is managed in unicast SAFI.
+ */
+ if (safi == SAFI_LABELED_UNICAST)
+ if (peer->addpath_type[afi][SAFI_UNICAST] !=
+ BGP_ADDPATH_NONE)
+ adv_addpath_tx = true;
}
}
@@ -1838,6 +1848,10 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
SET_FLAG(flags, BGP_ADDPATH_TX);
SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_TX_ADV);
+ if (safi == SAFI_LABELED_UNICAST)
+ SET_FLAG(
+ peer->af_cap[afi][SAFI_UNICAST],
+ PEER_CAP_ADDPATH_AF_TX_ADV);
} else {
UNSET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_TX_ADV);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index f3ca3bba0a..5d4cf2a6aa 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -979,10 +979,11 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code,
peer->notify.code = bgp_notify.code;
peer->notify.subcode = bgp_notify.subcode;
+ peer->notify.length = bgp_notify.length;
if (bgp_notify.length && data) {
- bgp_notify.data =
- XMALLOC(MTYPE_TMP, bgp_notify.length * 3);
+ bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION,
+ bgp_notify.length * 3);
for (i = 0; i < bgp_notify.length; i++)
if (first) {
snprintf(c, sizeof(c), " %02x",
@@ -1002,7 +1003,15 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code,
bgp_notify_print(peer, &bgp_notify, "sending", hard_reset);
if (bgp_notify.data) {
- XFREE(MTYPE_TMP, bgp_notify.data);
+ if (data) {
+ XFREE(MTYPE_BGP_NOTIFICATION,
+ peer->notify.data);
+ peer->notify.data = XCALLOC(
+ MTYPE_BGP_NOTIFICATION, datalen);
+ memcpy(peer->notify.data, data, datalen);
+ }
+
+ XFREE(MTYPE_BGP_NOTIFICATION, bgp_notify.data);
bgp_notify.length = 0;
}
}
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index b71e19ab33..807c4cd5a4 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -1636,9 +1636,8 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
ptr_ip = &api->actions[i].u.zr.redirect_ip_v4;
else
ptr_ip = &api->actions[i].u.zr.redirect_ip_v6;
- if (inet_ntop(afi2family(api->afi),
- ptr_ip, local_buff,
- INET6_ADDRSTRLEN) != NULL) {
+ if (inet_ntop(afi2family(api->afi), ptr_ip, local_buff,
+ sizeof(local_buff)) != NULL) {
delta = snprintf(ptr, len,
"@redirect ip nh %s", local_buff);
len -= delta;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 2ca9502545..e478abc44a 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -277,8 +277,10 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi)
}
/* Free bgp route information. */
-static void bgp_path_info_free(struct bgp_path_info *path)
+void bgp_path_info_free_with_caller(const char *name,
+ struct bgp_path_info *path)
{
+ frrtrace(2, frr_bgp, bgp_path_info_free, path, name);
bgp_attr_unintern(&path->attr);
bgp_unlink_nexthop(path);
@@ -389,8 +391,10 @@ static int bgp_dest_set_defer_flag(struct bgp_dest *dest, bool delete)
return -1;
}
-void bgp_path_info_add(struct bgp_dest *dest, struct bgp_path_info *pi)
+void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest,
+ struct bgp_path_info *pi)
{
+ frrtrace(2, frr_bgp, bgp_path_info_add, dest, pi, name);
struct bgp_path_info *top;
top = bgp_dest_get_bgp_path_info(dest);
@@ -2086,11 +2090,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
/* If this is not the bestpath then check to see if there is an enabled
* addpath
* feature that requires us to advertise it */
- if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
- if (!bgp_addpath_tx_path(peer->addpath_type[afi][safi], pi)) {
+ if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
+ if (!bgp_addpath_capable(pi, peer, afi, safi))
return false;
- }
- }
/* Aggregate-address suppress check. */
if (bgp_path_suppressed(pi) && !UNSUPPRESS_MAP_NAME(filter))
@@ -2197,7 +2199,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
/* If we're a CONFED we need to loop check the CONFED ID too */
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
- if (aspath_loop_check(piattr->aspath, bgp->confed_id)) {
+ if (aspath_loop_check_confed(piattr->aspath, bgp->confed_id)) {
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
zlog_debug(
"%pBP [Update:SEND] suppress announcement to peer AS %u is AS path.",
@@ -2583,8 +2585,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
zlog_debug(
- "%s: BGP_PATH_ANNC_NH_SELF, family=%s",
- __func__, family2str(family));
+ "%s: %pFX BGP_PATH_ANNC_NH_SELF, family=%s",
+ __func__, p, family2str(family));
subgroup_announce_reset_nhop(family, attr);
nh_reset = true;
}
@@ -4014,7 +4016,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
struct attr new_attr;
struct attr *attr_new;
struct bgp_path_info *pi;
- struct bgp_path_info *new;
+ struct bgp_path_info *new = NULL;
struct bgp_path_info_extra *extra;
const char *reason;
char pfx_buf[BGP_PRD_PATH_STRLEN];
@@ -4114,16 +4116,23 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
/* AS path loop check. */
if (do_loop_check) {
- if (aspath_loop_check(attr->aspath, bgp->as) > allowas_in ||
- (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) &&
- (aspath_loop_check(attr->aspath, bgp->confed_id) >
- allowas_in))) {
+ if (aspath_loop_check(attr->aspath, bgp->as) >
+ peer->allowas_in[afi][safi]) {
peer->stat_pfx_aspath_loop++;
reason = "as-path contains our own AS;";
goto filtered;
}
}
+ /* If we're a CONFED we need to loop check the CONFED ID too */
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) && do_loop_check)
+ if (aspath_loop_check_confed(attr->aspath, bgp->confed_id) >
+ peer->allowas_in[afi][safi]) {
+ peer->stat_pfx_aspath_loop++;
+ reason = "as-path contains our own confed AS;";
+ goto filtered;
+ }
+
/* Route reflector originator ID check. If ACCEPT_OWN mechanism is
* enabled, then take care of that too.
*/
@@ -4237,9 +4246,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
new_attr.local_pref = BGP_GSHUT_LOCAL_PREF;
- /* If graceful-shutdown is configured then add the GSHUT
- * community to all paths received from eBGP peers */
- } else if (bgp_in_graceful_shutdown(peer->bgp))
+ /* If graceful-shutdown is configured globally or
+ * per neighbor, then add the GSHUT community to
+ * all paths received from eBGP peers. */
+ } else if (bgp_in_graceful_shutdown(peer->bgp) ||
+ CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_SHUTDOWN))
bgp_attr_add_gshut_community(&new_attr);
}
@@ -4279,14 +4290,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
&& (!CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED)))
SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING);
- /* If maximum prefix count is configured and current prefix
- * count exeed it.
- */
- if (bgp_maximum_prefix_overflow(peer, afi, safi, 0)) {
- bgp_attr_flush(&new_attr);
- return -1;
- }
-
/* If neighbor soo is configured, tag all incoming routes with
* this SoO tag and then filter out advertisements in
* subgroup_announce_check() if it matches the configured SoO
@@ -4789,14 +4792,9 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
else {
- if (BGP_DEBUG(nht, NHT)) {
- char buf1[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET,
- (const void *)&attr_new->nexthop,
- buf1, INET6_ADDRSTRLEN);
- zlog_debug("%s(%s): NH unresolved", __func__,
- buf1);
- }
+ if (BGP_DEBUG(nht, NHT))
+ zlog_debug("%s(%pI4): NH unresolved", __func__,
+ &attr_new->nexthop);
bgp_path_info_unset_flag(dest, new, BGP_PATH_VALID);
}
} else {
@@ -4806,6 +4804,15 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
}
+ /* If maximum prefix count is configured and current prefix
+ * count exeed it.
+ */
+ if (bgp_maximum_prefix_overflow(peer, afi, safi, 0)) {
+ reason = "maximum-prefix overflow";
+ bgp_attr_flush(&new_attr);
+ goto filtered;
+ }
+
/* Addpath ID */
new->addpath_rx_id = addpath_id;
@@ -4877,6 +4884,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
/* This BGP update is filtered. Log the reason then update BGP
entry. */
filtered:
+ if (new) {
+ bgp_unlink_nexthop(new);
+ bgp_path_info_delete(dest, new);
+ bgp_path_info_extra_free(&new->extra);
+ XFREE(MTYPE_BGP_ROUTE, new);
+ }
+
hook_call(bgp_process, bgp, afi, safi, dest, peer, true);
if (bgp_debug_update(peer, p, NULL, 1)) {
@@ -6296,7 +6310,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
char buf1[INET6_ADDRSTRLEN];
inet_ntop(p->family,
&p->u.prefix, buf1,
- INET6_ADDRSTRLEN);
+ sizeof(buf1));
zlog_debug(
"%s(%s): Route not in table, not advertising",
__func__, buf1);
@@ -6346,8 +6360,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
else {
if (BGP_DEBUG(nht, NHT)) {
char buf1[INET6_ADDRSTRLEN];
+
inet_ntop(p->family, &p->u.prefix, buf1,
- INET6_ADDRSTRLEN);
+ sizeof(buf1));
zlog_debug(
"%s(%s): Route not in table, not advertising",
__func__, buf1);
@@ -8668,6 +8683,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
afi_t afi;
route_map_result_t ret;
struct bgp_redist *red;
+ struct interface *ifp;
/* Make default attribute. */
bgp_attr_default_set(&attr, bgp, BGP_ORIGIN_INCOMPLETE);
@@ -8717,6 +8733,11 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
}
attr.nh_type = nhtype;
attr.nh_ifindex = ifindex;
+ ifp = if_lookup_by_index(ifindex, bgp->vrf_id);
+ if (ifp && if_is_operative(ifp))
+ SET_FLAG(attr.nh_flag, BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(attr.nh_flag, BGP_ATTR_NH_IF_OPERSTATE);
attr.med = metric;
attr.distance = distance;
@@ -8900,7 +8921,11 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type,
bgp_aggregate_decrement(bgp, bgp_dest_get_prefix(dest),
pi, afi, SAFI_UNICAST);
bgp_path_info_delete(dest, pi);
- bgp_process(bgp, dest, afi, SAFI_UNICAST);
+ if (!CHECK_FLAG(bgp->flags,
+ BGP_FLAG_DELETE_IN_PROGRESS))
+ bgp_process(bgp, dest, afi, SAFI_UNICAST);
+ else
+ bgp_path_info_reap(dest, pi);
}
}
}
@@ -8910,7 +8935,7 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p,
struct vty *vty, json_object *json, bool wide)
{
int len = 0;
- char buf[BUFSIZ];
+ char buf[INET6_ADDRSTRLEN];
if (p->family == AF_INET) {
if (!json) {
@@ -8919,7 +8944,7 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p,
json_object_string_add(json, "prefix",
inet_ntop(p->family,
&p->u.prefix, buf,
- BUFSIZ));
+ sizeof(buf)));
json_object_int_add(json, "prefixLen", p->prefixlen);
json_object_string_addf(json, "network", "%pFX", p);
json_object_int_add(json, "version", dest->version);
@@ -8941,9 +8966,9 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p,
len = vty_out(vty, "%pFX", p);
else {
json_object_string_add(json, "prefix",
- inet_ntop(p->family,
- &p->u.prefix, buf,
- BUFSIZ));
+ inet_ntop(p->family,
+ &p->u.prefix, buf,
+ sizeof(buf)));
json_object_int_add(json, "prefixLen", p->prefixlen);
json_object_string_addf(json, "network", "%pFX", p);
json_object_int_add(json, "version", dest->version);
@@ -9212,20 +9237,17 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
* attr->mp_nexthop_global_in
*/
if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)) {
- char buf[BUFSIZ];
char nexthop[128];
int af = NEXTHOP_FAMILY(attr->mp_nexthop_len);
switch (af) {
case AF_INET:
- snprintf(nexthop, sizeof(nexthop), "%s",
- inet_ntop(af, &attr->mp_nexthop_global_in, buf,
- BUFSIZ));
+ snprintfrr(nexthop, sizeof(nexthop), "%pI4",
+ &attr->mp_nexthop_global_in);
break;
case AF_INET6:
- snprintf(nexthop, sizeof(nexthop), "%s",
- inet_ntop(af, &attr->mp_nexthop_global, buf,
- BUFSIZ));
+ snprintfrr(nexthop, sizeof(nexthop), "%pI6",
+ &attr->mp_nexthop_global);
break;
default:
snprintf(nexthop, sizeof(nexthop), "?");
@@ -9402,9 +9424,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
"link-local");
if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global,
- &attr->mp_nexthop_local)
- != 0)
- && !attr->mp_nexthop_prefer_global)
+ &attr->mp_nexthop_local) !=
+ 0) &&
+ !CHECK_FLAG(attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
json_object_boolean_true_add(
json_nexthop_ll, "used");
else
@@ -9416,10 +9439,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
} else {
/* Display LL if LL/Global both in table unless
* prefer-global is set */
- if (((attr->mp_nexthop_len
- == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
- && !attr->mp_nexthop_prefer_global)
- || (path->peer->conf_if)) {
+ if (((attr->mp_nexthop_len ==
+ BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) &&
+ !CHECK_FLAG(attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)) ||
+ (path->peer->conf_if)) {
if (path->peer->conf_if) {
len = vty_out(vty, "%s",
path->peer->conf_if);
@@ -9615,7 +9639,7 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest,
json_status = json_object_new_object();
json_net = json_object_new_object();
} else {
- vty_out(vty, "*");
+ vty_out(vty, " *");
vty_out(vty, ">");
vty_out(vty, " ");
}
@@ -9679,8 +9703,14 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest,
attr->aspath->str);
/* Print origin */
+#if CONFDATE > 20231208
+CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs")
+#endif
json_object_string_add(json_net, "bgpOriginCode",
bgp_origin_str[attr->origin]);
+ json_object_string_add(
+ json_net, "origin",
+ bgp_origin_long_str[attr->origin]);
} else {
if (p->family == AF_INET &&
(safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP ||
@@ -9696,13 +9726,8 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest,
vty_out(vty, "%-16pI4", &attr->nexthop);
} else if (p->family == AF_INET6 ||
BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr)) {
- char buf[BUFSIZ];
-
- len = vty_out(
- vty, "%s",
- inet_ntop(AF_INET6,
- &attr->mp_nexthop_global, buf,
- BUFSIZ));
+ len = vty_out(vty, "%pI6",
+ &attr->mp_nexthop_global);
len = wide ? (41 - len) : (16 - len);
if (len < 1)
vty_out(vty, "\n%*s", 36, " ");
@@ -9736,8 +9761,20 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest,
}
}
if (use_json) {
+ struct bgp_path_info *bpi = bgp_dest_get_bgp_path_info(dest);
+
+#if CONFDATE > 20231208
+CPP_NOTICE("Drop `bgpStatusCodes` from JSON outputs")
+#endif
json_object_boolean_true_add(json_status, "*");
json_object_boolean_true_add(json_status, ">");
+ json_object_boolean_true_add(json_net, "valid");
+ json_object_boolean_true_add(json_net, "best");
+
+ if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_MULTIPATH)) {
+ json_object_boolean_true_add(json_status, "=");
+ json_object_boolean_true_add(json_net, "multipath");
+ }
json_object_object_add(json_net, "appliedStatusSymbols",
json_status);
json_object_object_addf(json_ar, json_net, "%pFX", p);
@@ -10216,7 +10253,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object *json_paths)
{
char buf[INET6_ADDRSTRLEN];
- char buf1[BUFSIZ];
char tag_buf[30];
struct attr *attr = path->attr;
time_t tbuf;
@@ -10249,6 +10285,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
uint32_t exp = 0;
mpls_label_t label = MPLS_INVALID_LABEL;
tag_buf[0] = '\0';
+ struct bgp_path_info *bpi_ultimate =
+ bgp_get_imported_bpi_ultimate(path);
if (json_paths) {
json_path = json_object_new_object();
@@ -10489,7 +10527,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
}
/* Display the IGP cost or 'inaccessible' */
- if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) {
+ if (!CHECK_FLAG(bpi_ultimate->flags, BGP_PATH_VALID)) {
bool import = CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK);
if (json_paths) {
@@ -10502,14 +10540,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
import ? ", import-check enabled" : "");
}
} else {
- if (path->extra && path->extra->igpmetric) {
+ if (bpi_ultimate->extra && bpi_ultimate->extra->igpmetric) {
if (json_paths)
- json_object_int_add(json_nexthop_global,
- "metric",
- path->extra->igpmetric);
+ json_object_int_add(
+ json_nexthop_global, "metric",
+ bpi_ultimate->extra->igpmetric);
else
vty_out(vty, " (metric %u)",
- path->extra->igpmetric);
+ bpi_ultimate->extra->igpmetric);
}
/* IGP cost is 0, display this only for json */
@@ -10596,10 +10634,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
vty_out(vty, " (%pI4)", &attr->originator_id);
else
- vty_out(vty, " (%s)",
- inet_ntop(AF_INET,
- &path->peer->remote_id, buf1,
- sizeof(buf1)));
+ vty_out(vty, " (%pI4)", &path->peer->remote_id);
}
}
@@ -10670,7 +10705,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object_boolean_true_add(json_nexthop_ll,
"accessible");
- if (!attr->mp_nexthop_prefer_global)
+ if (!CHECK_FLAG(attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
json_object_boolean_true_add(json_nexthop_ll,
"used");
else
@@ -10680,7 +10716,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, " (%s) %s\n",
inet_ntop(AF_INET6, &attr->mp_nexthop_local,
buf, INET6_ADDRSTRLEN),
- attr->mp_nexthop_prefer_global
+ CHECK_FLAG(attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)
? "(prefer-global)"
: "(used)");
}
@@ -11012,11 +11049,12 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
/* Remote SID */
if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) {
- inet_ntop(AF_INET6, &path->extra->sid[0].sid, buf, sizeof(buf));
if (json_paths)
- json_object_string_add(json_path, "remoteSid", buf);
+ json_object_string_addf(json_path, "remoteSid", "%pI6",
+ &path->extra->sid[0].sid);
else
- vty_out(vty, " Remote SID: %s\n", buf);
+ vty_out(vty, " Remote SID: %pI6\n",
+ &path->extra->sid[0].sid);
}
/* Label Index */
@@ -11228,6 +11266,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
bool wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
bool all = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
+ bool detail_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON_DETAIL);
+ bool detail_routes = CHECK_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL);
if (output_cum && *output_cum != 0)
header = false;
@@ -11261,8 +11301,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
}
/* Check for 'json detail', where we need header output once per dest */
- if (use_json && CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL) &&
- type != bgp_show_type_dampend_paths &&
+ if (use_json && detail_json && type != bgp_show_type_dampend_paths &&
type != bgp_show_type_damp_neighbor &&
type != bgp_show_type_flap_statistics &&
type != bgp_show_type_flap_neighbor)
@@ -11525,17 +11564,19 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
vty_out(vty, "Default local pref %u, ",
bgp->default_local_pref);
vty_out(vty, "local AS %u\n", bgp->as);
- vty_out(vty, BGP_SHOW_SCODE_HEADER);
- vty_out(vty, BGP_SHOW_NCODE_HEADER);
- vty_out(vty, BGP_SHOW_OCODE_HEADER);
- vty_out(vty, BGP_SHOW_RPKI_HEADER);
+ if (!detail_routes) {
+ vty_out(vty, BGP_SHOW_SCODE_HEADER);
+ vty_out(vty, BGP_SHOW_NCODE_HEADER);
+ vty_out(vty, BGP_SHOW_OCODE_HEADER);
+ vty_out(vty, BGP_SHOW_RPKI_HEADER);
+ }
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
vty_out(vty, BGP_SHOW_DAMP_HEADER);
else if (type == bgp_show_type_flap_statistics
|| type == bgp_show_type_flap_neighbor)
vty_out(vty, BGP_SHOW_FLAP_HEADER);
- else
+ else if (!detail_routes)
vty_out(vty, (wide ? BGP_SHOW_HEADER_WIDE
: BGP_SHOW_HEADER));
header = false;
@@ -11578,16 +11619,30 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
AFI_IP, safi, use_json,
json_paths);
else {
- if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL))
+ if (detail_routes || detail_json) {
+ const struct prefix_rd *prd = NULL;
+
+ if (dest->pdest)
+ prd = bgp_rd_from_dest(
+ dest->pdest, safi);
+
+ if (!use_json)
+ route_vty_out_detail_header(
+ vty, bgp, dest,
+ bgp_dest_get_prefix(
+ dest),
+ prd, table->afi, safi,
+ NULL);
+
route_vty_out_detail(
- vty, bgp, dest,
- bgp_dest_get_prefix(dest), pi,
+ vty, bgp, dest, dest_p, pi,
family2afi(dest_p->family),
safi, RPKI_NOT_BEING_USED,
json_paths);
- else
+ } else {
route_vty_out(vty, dest_p, pi, display,
safi, json_paths, wide);
+ }
}
display++;
}
@@ -11669,7 +11724,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
struct bgp_table *table, struct prefix_rd *prd_match,
- enum bgp_show_type type, void *output_arg, bool use_json)
+ enum bgp_show_type type, void *output_arg,
+ uint16_t show_flags)
{
struct bgp_dest *dest, *next;
unsigned long output_cum = 0;
@@ -11677,13 +11733,10 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
unsigned long json_header_depth = 0;
struct bgp_table *itable;
bool show_msg;
- uint16_t show_flags = 0;
+ bool use_json = !!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
show_msg = (!use_json && type == bgp_show_type_normal);
- if (use_json)
- SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
-
for (dest = bgp_table_top(table); dest; dest = next) {
const struct prefix *dest_p = bgp_dest_get_prefix(dest);
@@ -11714,6 +11767,9 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
vty_out(vty,
"\nDisplayed %ld routes and %ld total paths\n",
output_cum, total_cum);
+ } else {
+ if (use_json && output_cum == 0)
+ vty_out(vty, "{}\n");
}
return CMD_SUCCESS;
}
@@ -11746,7 +11802,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
/* use MPLS and ENCAP specific shows until they are merged */
if (safi == SAFI_MPLS_VPN) {
return bgp_show_table_rd(vty, bgp, safi, table, NULL, type,
- output_arg, use_json);
+ output_arg, show_flags);
}
if (safi == SAFI_FLOWSPEC && type == bgp_show_type_detail) {
@@ -12628,7 +12684,8 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes\
|optimal-route-reflection [WORD$orr_group_name]\
- ] [json$uj [detail$detail] | wide$wide]",
+ |detail-routes$detail_routes\
+ ] [json$uj [detail$detail_json] | wide$wide]",
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
"Display the entries for all address families\n"
@@ -12678,6 +12735,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
"Display route and more specific routes\n"
"Display Optimal Route Reflection RR Clients\n"
"ORR Group name\n"
+ "Display detailed version of all routes\n"
JSON_STR
"Display detailed version of JSON output\n"
"Increase table width for longer prefixes\n")
@@ -12701,8 +12759,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
}
- if (detail)
- SET_FLAG(show_flags, BGP_SHOW_OPT_DETAIL);
+ if (detail_json)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON_DETAIL);
+
+ if (detail_routes)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL);
/* [<ipv4|ipv6> [all]] */
if (all) {
@@ -14068,6 +14129,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
vty_out(vty, "Originating default network %s\n\n",
(afi == AFI_IP) ? "0.0.0.0/0" : "::/0");
}
+ (*output_count)++;
*header1 = 0;
}
@@ -14240,7 +14302,9 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
json_ar = json_object_new_object();
json_scode = json_object_new_object();
json_ocode = json_object_new_object();
-
+#if CONFDATE > 20231208
+CPP_NOTICE("Drop `bgpStatusCodes` from JSON outputs")
+#endif
json_object_string_add(json_scode, "suppressed", "s");
json_object_string_add(json_scode, "damped", "d");
json_object_string_add(json_scode, "history", "h");
@@ -14252,6 +14316,9 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
json_object_string_add(json_scode, "stale", "S");
json_object_string_add(json_scode, "removed", "R");
+#if CONFDATE > 20231208
+CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs")
+#endif
json_object_string_add(json_ocode, "igp", "i");
json_object_string_add(json_ocode, "egp", "e");
json_object_string_add(json_ocode, "incomplete", "?");
@@ -14673,7 +14740,7 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed,
struct bgp *bgp = NULL;
int idx = 0;
bool uj = use_json(argc, argv);
- uint16_t show_flags = BGP_SHOW_OPT_DETAIL;
+ uint16_t show_flags = BGP_SHOW_OPT_ROUTES_DETAIL;
if (uj) {
argc--;
@@ -15514,13 +15581,15 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
/* "network" configuration display. */
if (p->u.prefix_evpn.route_type == 5) {
char local_buf[PREFIX_STRLEN];
+
uint8_t family = is_evpn_prefix_ipaddr_v4((
struct prefix_evpn *)p)
? AF_INET
: AF_INET6;
inet_ntop(family,
- &p->u.prefix_evpn.prefix_addr.ip.ip.addr,
- local_buf, PREFIX_STRLEN);
+ &p->u.prefix_evpn.prefix_addr.ip.ip
+ .addr,
+ local_buf, sizeof(local_buf));
snprintf(buf, sizeof(buf), "%s/%u", local_buf,
p->u.prefix_evpn.prefix_addr
.ip_prefix_length);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 3fa58c0dfb..e16e077029 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -663,8 +663,9 @@ DECLARE_HOOK(bgp_process,
#define BGP_SHOW_OPT_AFI_IP6 (1 << 4)
#define BGP_SHOW_OPT_ESTABLISHED (1 << 5)
#define BGP_SHOW_OPT_FAILED (1 << 6)
-#define BGP_SHOW_OPT_DETAIL (1 << 7)
+#define BGP_SHOW_OPT_JSON_DETAIL (1 << 7)
#define BGP_SHOW_OPT_TERSE (1 << 8)
+#define BGP_SHOW_OPT_ROUTES_DETAIL (1 << 9)
/* Prototypes. */
extern void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi,
@@ -865,7 +866,7 @@ extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
struct bgp_table *table, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg,
- bool use_json);
+ uint16_t show_flags);
extern void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi);
extern bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
uint8_t type, uint8_t stype,
@@ -882,4 +883,12 @@ bgp_path_selection_reason2str(enum bgp_path_selection_reason reason);
extern bool bgp_addpath_encode_rx(struct peer *peer, afi_t afi, safi_t safi);
extern const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
safi_t safi);
+extern void bgp_path_info_free_with_caller(const char *caller,
+ struct bgp_path_info *path);
+extern void bgp_path_info_add_with_caller(const char *caller,
+ struct bgp_dest *dest,
+ struct bgp_path_info *pi);
+#define bgp_path_info_add(A, B) \
+ bgp_path_info_add_with_caller(__func__, (A), (B))
+#define bgp_path_info_free(B) bgp_path_info_free_with_caller(__func__, (B))
#endif /* _QUAGGA_BGP_ROUTE_H */
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index b736e6c38a..f779b34371 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -3531,11 +3531,11 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
|| CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) {
/* Set next hop preference to global */
- path->attr->mp_nexthop_prefer_global = true;
+ SET_FLAG(path->attr->nh_flag, BGP_ATTR_NH_MP_PREFER_GLOBAL);
SET_FLAG(path->attr->rmap_change_flags,
BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
} else {
- path->attr->mp_nexthop_prefer_global = false;
+ UNSET_FLAG(path->attr->nh_flag, BGP_ATTR_NH_MP_PREFER_GLOBAL);
SET_FLAG(path->attr->rmap_change_flags,
BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
}
@@ -3725,6 +3725,8 @@ route_set_vpnv4_nexthop(void *rule, const struct prefix *prefix, void *object)
path->attr->mp_nexthop_global_in = *address;
path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+ SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_VPNV4_NHOP_CHANGED);
+
return RMAP_OKAY;
}
@@ -3762,6 +3764,9 @@ route_set_vpnv6_nexthop(void *rule, const struct prefix *prefix, void *object)
sizeof(struct in6_addr));
path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL;
+ SET_FLAG(path->attr->rmap_change_flags,
+ BATTR_RMAP_VPNV6_GLOBAL_NHOP_CHANGED);
+
return RMAP_OKAY;
}
@@ -4140,7 +4145,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
safi2str(safi),
inet_ntop(bn_p->family,
&bn_p->u.prefix, buf,
- INET6_ADDRSTRLEN));
+ sizeof(buf)));
bgp_static_update(bgp, bn_p, bgp_static, afi,
safi);
}
@@ -4192,7 +4197,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
safi2str(safi),
inet_ntop(bn_p->family,
&bn_p->u.prefix, buf,
- INET6_ADDRSTRLEN));
+ sizeof(buf)));
bgp_aggregate_route(bgp, bn_p, afi, safi,
aggregate);
}
@@ -6847,9 +6852,9 @@ DEFUN_YANG (no_set_vpn_nexthop,
}
#endif /* KEEP_OLD_VPN_COMMANDS */
-DEFUN_YANG (set_ipx_vpn_nexthop,
+DEFPY_YANG (set_ipx_vpn_nexthop,
set_ipx_vpn_nexthop_cmd,
- "set <ipv4|ipv6> vpn next-hop <A.B.C.D|X:X::X:X>",
+ "set <ipv4|ipv6> vpn next-hop <A.B.C.D$addrv4|X:X::X:X$addrv6>",
SET_STR
"IPv4 information\n"
"IPv6 information\n"
@@ -6865,6 +6870,11 @@ DEFUN_YANG (set_ipx_vpn_nexthop,
if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
if (afi == AFI_IP) {
+ if (addrv6_str) {
+ vty_out(vty, "%% IPv4 next-hop expected\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
const char *xpath =
"./set-action[action='frr-bgp-route-map:ipv4-vpn-address']";
@@ -6874,6 +6884,11 @@ DEFUN_YANG (set_ipx_vpn_nexthop,
"%s/rmap-set-action/frr-bgp-route-map:ipv4-address",
xpath);
} else {
+ if (addrv4_str) {
+ vty_out(vty, "%% IPv6 next-hop expected\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
const char *xpath =
"./set-action[action='frr-bgp-route-map:ipv6-vpn-address']";
diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c
index 6bc313464a..b202ec2e17 100644
--- a/bgpd/bgp_snmp.c
+++ b/bgpd/bgp_snmp.c
@@ -40,864 +40,16 @@
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_snmp.h"
+#include "bgpd/bgp_snmp_bgp4.h"
+#include "bgpd/bgp_snmp_bgp4v2.h"
#include "bgpd/bgp_mplsvpn_snmp.h"
-/* BGP4-MIB described in RFC1657. */
-#define BGP4MIB 1,3,6,1,2,1,15
-
-/* BGP TRAP. */
-#define BGPESTABLISHED 1
-#define BGPBACKWARDTRANSITION 2
-
-/* BGP MIB bgpVersion. */
-#define BGPVERSION 0
-
-/* BGP MIB bgpLocalAs. */
-#define BGPLOCALAS 0
-
-/* BGP MIB bgpPeerTable. */
-#define BGPPEERIDENTIFIER 1
-#define BGPPEERSTATE 2
-#define BGPPEERADMINSTATUS 3
-#define BGPPEERNEGOTIATEDVERSION 4
-#define BGPPEERLOCALADDR 5
-#define BGPPEERLOCALPORT 6
-#define BGPPEERREMOTEADDR 7
-#define BGPPEERREMOTEPORT 8
-#define BGPPEERREMOTEAS 9
-#define BGPPEERINUPDATES 10
-#define BGPPEEROUTUPDATES 11
-#define BGPPEERINTOTALMESSAGES 12
-#define BGPPEEROUTTOTALMESSAGES 13
-#define BGPPEERLASTERROR 14
-#define BGPPEERFSMESTABLISHEDTRANSITIONS 15
-#define BGPPEERFSMESTABLISHEDTIME 16
-#define BGPPEERCONNECTRETRYINTERVAL 17
-#define BGPPEERHOLDTIME 18
-#define BGPPEERKEEPALIVE 19
-#define BGPPEERHOLDTIMECONFIGURED 20
-#define BGPPEERKEEPALIVECONFIGURED 21
-#define BGPPEERMINROUTEADVERTISEMENTINTERVAL 22
-#define BGPPEERINUPDATEELAPSEDTIME 23
-
-/* BGP MIB bgpIdentifier. */
-#define BGPIDENTIFIER 0
-
-/* BGP MIB bgpRcvdPathAttrTable */
-#define BGPPATHATTRPEER 1
-#define BGPPATHATTRDESTNETWORK 2
-#define BGPPATHATTRORIGIN 3
-#define BGPPATHATTRASPATH 4
-#define BGPPATHATTRNEXTHOP 5
-#define BGPPATHATTRINTERASMETRIC 6
-
-/* BGP MIB bgp4PathAttrTable. */
-#define BGP4PATHATTRPEER 1
-#define BGP4PATHATTRIPADDRPREFIXLEN 2
-#define BGP4PATHATTRIPADDRPREFIX 3
-#define BGP4PATHATTRORIGIN 4
-#define BGP4PATHATTRASPATHSEGMENT 5
-#define BGP4PATHATTRNEXTHOP 6
-#define BGP4PATHATTRMULTIEXITDISC 7
-#define BGP4PATHATTRLOCALPREF 8
-#define BGP4PATHATTRATOMICAGGREGATE 9
-#define BGP4PATHATTRAGGREGATORAS 10
-#define BGP4PATHATTRAGGREGATORADDR 11
-#define BGP4PATHATTRCALCLOCALPREF 12
-#define BGP4PATHATTRBEST 13
-#define BGP4PATHATTRUNKNOWN 14
-
-/* SNMP value hack. */
-#define INTEGER ASN_INTEGER
-#define INTEGER32 ASN_INTEGER
-#define COUNTER32 ASN_COUNTER
-#define OCTET_STRING ASN_OCTET_STR
-#define IPADDRESS ASN_IPADDRESS
-#define GAUGE32 ASN_UNSIGNED
-
-/* Declare static local variables for convenience. */
-SNMP_LOCAL_VARIABLES
-
-/* BGP-MIB instances. */
-static oid bgp_oid[] = {BGP4MIB};
-static oid bgp_trap_oid[] = {BGP4MIB, 0};
-
-/* IP address 0.0.0.0. */
-static struct in_addr bgp_empty_addr = {.s_addr = 0};
-
-/* Hook functions. */
-static uint8_t *bgpVersion(struct variable *, oid[], size_t *, int, size_t *,
- WriteMethod **);
-static uint8_t *bgpLocalAs(struct variable *, oid[], size_t *, int, size_t *,
- WriteMethod **);
-static uint8_t *bgpPeerTable(struct variable *, oid[], size_t *, int, size_t *,
- WriteMethod **);
-static uint8_t *bgpRcvdPathAttrTable(struct variable *, oid[], size_t *, int,
- size_t *, WriteMethod **);
-static uint8_t *bgpIdentifier(struct variable *, oid[], size_t *, int, size_t *,
- WriteMethod **);
-static uint8_t *bgp4PathAttrTable(struct variable *, oid[], size_t *, int,
- size_t *, WriteMethod **);
-/* static uint8_t *bgpTraps (); */
-
-static struct variable bgp_variables[] = {
- /* BGP version. */
- {BGPVERSION, OCTET_STRING, RONLY, bgpVersion, 1, {1}},
- /* BGP local AS. */
- {BGPLOCALAS, INTEGER, RONLY, bgpLocalAs, 1, {2}},
- /* BGP peer table. */
- {BGPPEERIDENTIFIER, IPADDRESS, RONLY, bgpPeerTable, 3, {3, 1, 1}},
- {BGPPEERSTATE, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 2}},
- {BGPPEERADMINSTATUS, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 3}},
- {BGPPEERNEGOTIATEDVERSION,
- INTEGER32,
- RONLY,
- bgpPeerTable,
- 3,
- {3, 1, 4}},
- {BGPPEERLOCALADDR, IPADDRESS, RONLY, bgpPeerTable, 3, {3, 1, 5}},
- {BGPPEERLOCALPORT, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 6}},
- {BGPPEERREMOTEADDR, IPADDRESS, RONLY, bgpPeerTable, 3, {3, 1, 7}},
- {BGPPEERREMOTEPORT, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 8}},
- {BGPPEERREMOTEAS, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 9}},
- {BGPPEERINUPDATES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 10}},
- {BGPPEEROUTUPDATES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 11}},
- {BGPPEERINTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 12}},
- {BGPPEEROUTTOTALMESSAGES,
- COUNTER32,
- RONLY,
- bgpPeerTable,
- 3,
- {3, 1, 13}},
- {BGPPEERLASTERROR, OCTET_STRING, RONLY, bgpPeerTable, 3, {3, 1, 14}},
- {BGPPEERFSMESTABLISHEDTRANSITIONS,
- COUNTER32,
- RONLY,
- bgpPeerTable,
- 3,
- {3, 1, 15}},
- {BGPPEERFSMESTABLISHEDTIME,
- GAUGE32,
- RONLY,
- bgpPeerTable,
- 3,
- {3, 1, 16}},
- {BGPPEERCONNECTRETRYINTERVAL,
- INTEGER,
- RWRITE,
- bgpPeerTable,
- 3,
- {3, 1, 17}},
- {BGPPEERHOLDTIME, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 18}},
- {BGPPEERKEEPALIVE, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 19}},
- {BGPPEERHOLDTIMECONFIGURED,
- INTEGER,
- RWRITE,
- bgpPeerTable,
- 3,
- {3, 1, 20}},
- {BGPPEERKEEPALIVECONFIGURED,
- INTEGER,
- RWRITE,
- bgpPeerTable,
- 3,
- {3, 1, 21}},
- {BGPPEERMINROUTEADVERTISEMENTINTERVAL,
- INTEGER,
- RWRITE,
- bgpPeerTable,
- 3,
- {3, 1, 23}},
- {BGPPEERINUPDATEELAPSEDTIME,
- GAUGE32,
- RONLY,
- bgpPeerTable,
- 3,
- {3, 1, 24}},
- /* BGP identifier. */
- {BGPIDENTIFIER, IPADDRESS, RONLY, bgpIdentifier, 1, {4}},
- /* BGP received path attribute table. */
- {BGPPATHATTRPEER, IPADDRESS, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 1}},
- {BGPPATHATTRDESTNETWORK,
- IPADDRESS,
- RONLY,
- bgpRcvdPathAttrTable,
- 3,
- {5, 1, 2}},
- {BGPPATHATTRORIGIN, INTEGER, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 3}},
- {BGPPATHATTRASPATH,
- OCTET_STRING,
- RONLY,
- bgpRcvdPathAttrTable,
- 3,
- {5, 1, 4}},
- {BGPPATHATTRNEXTHOP,
- IPADDRESS,
- RONLY,
- bgpRcvdPathAttrTable,
- 3,
- {5, 1, 5}},
- {BGPPATHATTRINTERASMETRIC,
- INTEGER32,
- RONLY,
- bgpRcvdPathAttrTable,
- 3,
- {5, 1, 6}},
- /* BGP-4 received path attribute table. */
- {BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 1}},
- {BGP4PATHATTRIPADDRPREFIXLEN,
- INTEGER,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 2}},
- {BGP4PATHATTRIPADDRPREFIX,
- IPADDRESS,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 3}},
- {BGP4PATHATTRORIGIN, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 4}},
- {BGP4PATHATTRASPATHSEGMENT,
- OCTET_STRING,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 5}},
- {BGP4PATHATTRNEXTHOP,
- IPADDRESS,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 6}},
- {BGP4PATHATTRMULTIEXITDISC,
- INTEGER,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 7}},
- {BGP4PATHATTRLOCALPREF,
- INTEGER,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 8}},
- {BGP4PATHATTRATOMICAGGREGATE,
- INTEGER,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 9}},
- {BGP4PATHATTRAGGREGATORAS,
- INTEGER,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 10}},
- {BGP4PATHATTRAGGREGATORADDR,
- IPADDRESS,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 11}},
- {BGP4PATHATTRCALCLOCALPREF,
- INTEGER,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 12}},
- {BGP4PATHATTRBEST, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 13}},
- {BGP4PATHATTRUNKNOWN,
- OCTET_STRING,
- RONLY,
- bgp4PathAttrTable,
- 3,
- {6, 1, 14}},
-};
-
-
-static uint8_t *bgpVersion(struct variable *v, oid name[], size_t *length,
- int exact, size_t *var_len,
- WriteMethod **write_method)
-{
- static uint8_t version;
-
- if (smux_header_generic(v, name, length, exact, var_len, write_method)
- == MATCH_FAILED)
- return NULL;
-
- /* Return BGP version. Zebra bgpd only support version 4. */
- version = (0x80 >> (BGP_VERSION_4 - 1));
-
- /* Return octet string length 1. */
- *var_len = 1;
- return &version;
-}
-
-static uint8_t *bgpLocalAs(struct variable *v, oid name[], size_t *length,
- int exact, size_t *var_len,
- WriteMethod **write_method)
-{
- struct bgp *bgp;
-
- if (smux_header_generic(v, name, length, exact, var_len, write_method)
- == MATCH_FAILED)
- return NULL;
-
- /* Get BGP structure. */
- bgp = bgp_get_default();
- if (!bgp)
- return NULL;
-
- return SNMP_INTEGER(bgp->as);
-}
-
-static struct peer *peer_lookup_addr_ipv4(struct in_addr *src)
-{
- struct bgp *bgp;
- struct peer *peer;
- struct listnode *node;
- struct listnode *bgpnode;
-
- for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) {
- for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
- if (sockunion_family(&peer->su) != AF_INET)
- continue;
-
- if (sockunion2ip(&peer->su) == src->s_addr)
- return peer;
- }
- }
-
- return NULL;
-}
-
-static struct peer *bgp_peer_lookup_next(struct in_addr *src)
-{
- struct bgp *bgp;
- struct peer *peer;
- struct peer *next_peer = NULL;
- struct listnode *node;
- struct listnode *bgpnode;
-
- for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) {
- for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
- if (sockunion_family(&peer->su) != AF_INET)
- continue;
- if (ntohl(sockunion2ip(&peer->su)) <= ntohl(src->s_addr))
- continue;
-
- if (!next_peer
- || ntohl(sockunion2ip(&next_peer->su))
- > ntohl(sockunion2ip(&peer->su))) {
- next_peer = peer;
- }
- }
- }
-
- if (next_peer) {
- src->s_addr = sockunion2ip(&next_peer->su);
- return next_peer;
- }
-
- return NULL;
-}
-
-/* 1.3.6.1.2.1.15.3.1.x = 10 */
-#define PEERTAB_NAMELEN 10
-
-static struct peer *bgpPeerTable_lookup(struct variable *v, oid name[],
- size_t *length, struct in_addr *addr,
- int exact)
-{
- struct peer *peer = NULL;
- size_t namelen = v ? v->namelen : PEERTAB_NAMELEN;
- int len;
-
- if (exact) {
- /* Check the length. */
- if (*length - namelen != sizeof(struct in_addr))
- return NULL;
-
- oid2in_addr(name + namelen, IN_ADDR_SIZE, addr);
-
- peer = peer_lookup_addr_ipv4(addr);
- return peer;
- } else {
- len = *length - namelen;
- if (len > 4)
- len = 4;
-
- oid2in_addr(name + namelen, len, addr);
-
- peer = bgp_peer_lookup_next(addr);
-
- if (peer == NULL)
- return NULL;
-
- oid_copy_in_addr(name + namelen, addr);
- *length = sizeof(struct in_addr) + namelen;
-
- return peer;
- }
- return NULL;
-}
-
-/* BGP write methods. */
-static int write_bgpPeerTable(int action, uint8_t *var_val,
- uint8_t var_val_type, size_t var_val_len,
- uint8_t *statP, oid *name, size_t length)
-{
- struct in_addr addr;
- struct peer *peer;
- long intval;
-
- if (var_val_type != ASN_INTEGER) {
- return SNMP_ERR_WRONGTYPE;
- }
- if (var_val_len != sizeof(long)) {
- return SNMP_ERR_WRONGLENGTH;
- }
-
- intval = *(long *)var_val;
-
- memset(&addr, 0, sizeof(addr));
-
- peer = bgpPeerTable_lookup(NULL, name, &length, &addr, 1);
- if (!peer)
- return SNMP_ERR_NOSUCHNAME;
-
- if (action != SNMP_MSG_INTERNAL_SET_COMMIT)
- return SNMP_ERR_NOERROR;
-
- zlog_info("%s: SNMP write .%ld = %ld", peer->host,
- (long)name[PEERTAB_NAMELEN - 1], intval);
-
- switch (name[PEERTAB_NAMELEN - 1]) {
- case BGPPEERADMINSTATUS:
-#define BGP_PeerAdmin_stop 1
-#define BGP_PeerAdmin_start 2
- /* When the peer is established, */
- if (intval == BGP_PeerAdmin_stop)
- BGP_EVENT_ADD(peer, BGP_Stop);
- else if (intval == BGP_PeerAdmin_start)
- ; /* Do nothing. */
- else
- return SNMP_ERR_NOSUCHNAME;
- break;
- case BGPPEERCONNECTRETRYINTERVAL:
- peer_flag_set(peer, PEER_FLAG_TIMER_CONNECT);
- peer->connect = intval;
- peer->v_connect = intval;
- break;
- case BGPPEERHOLDTIMECONFIGURED:
- peer_flag_set(peer, PEER_FLAG_TIMER);
- peer->holdtime = intval;
- peer->v_holdtime = intval;
- break;
- case BGPPEERKEEPALIVECONFIGURED:
- peer_flag_set(peer, PEER_FLAG_TIMER);
- peer->keepalive = intval;
- peer->v_keepalive = intval;
- break;
- case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
- peer->v_routeadv = intval;
- break;
- }
- return SNMP_ERR_NOERROR;
-}
-
-static uint8_t *bgpPeerTable(struct variable *v, oid name[], size_t *length,
- int exact, size_t *var_len,
- WriteMethod **write_method)
-{
- static struct in_addr addr;
- struct peer *peer;
- uint32_t ui, uo;
-
- if (smux_header_table(v, name, length, exact, var_len, write_method)
- == MATCH_FAILED)
- return NULL;
- memset(&addr, 0, sizeof(addr));
-
- peer = bgpPeerTable_lookup(v, name, length, &addr, exact);
- if (!peer)
- return NULL;
-
- switch (v->magic) {
- case BGPPEERIDENTIFIER:
- return SNMP_IPADDRESS(peer->remote_id);
- case BGPPEERSTATE:
- return SNMP_INTEGER(peer->status);
- case BGPPEERADMINSTATUS:
- *write_method = write_bgpPeerTable;
-#define BGP_PeerAdmin_stop 1
-#define BGP_PeerAdmin_start 2
- if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
- return SNMP_INTEGER(BGP_PeerAdmin_stop);
- else
- return SNMP_INTEGER(BGP_PeerAdmin_start);
- case BGPPEERNEGOTIATEDVERSION:
- return SNMP_INTEGER(BGP_VERSION_4);
- case BGPPEERLOCALADDR:
- if (peer->su_local)
- return SNMP_IPADDRESS(peer->su_local->sin.sin_addr);
- else
- return SNMP_IPADDRESS(bgp_empty_addr);
- case BGPPEERLOCALPORT:
- if (peer->su_local)
- return SNMP_INTEGER(
- ntohs(peer->su_local->sin.sin_port));
- else
- return SNMP_INTEGER(0);
- case BGPPEERREMOTEADDR:
- if (peer->su_remote)
- return SNMP_IPADDRESS(peer->su_remote->sin.sin_addr);
- else
- return SNMP_IPADDRESS(bgp_empty_addr);
- case BGPPEERREMOTEPORT:
- if (peer->su_remote)
- return SNMP_INTEGER(
- ntohs(peer->su_remote->sin.sin_port));
- else
- return SNMP_INTEGER(0);
- case BGPPEERREMOTEAS:
- return SNMP_INTEGER(peer->as);
- case BGPPEERINUPDATES:
- ui = atomic_load_explicit(&peer->update_in,
- memory_order_relaxed);
- return SNMP_INTEGER(ui);
- case BGPPEEROUTUPDATES:
- uo = atomic_load_explicit(&peer->update_out,
- memory_order_relaxed);
- return SNMP_INTEGER(uo);
- case BGPPEERINTOTALMESSAGES:
- return SNMP_INTEGER(PEER_TOTAL_RX(peer));
- case BGPPEEROUTTOTALMESSAGES:
- return SNMP_INTEGER(PEER_TOTAL_TX(peer));
- case BGPPEERLASTERROR: {
- static uint8_t lasterror[2];
- lasterror[0] = peer->notify.code;
- lasterror[1] = peer->notify.subcode;
- *var_len = 2;
- return (uint8_t *)&lasterror;
- }
- case BGPPEERFSMESTABLISHEDTRANSITIONS:
- return SNMP_INTEGER(peer->established);
- case BGPPEERFSMESTABLISHEDTIME:
- if (peer->uptime == 0)
- return SNMP_INTEGER(0);
- else
- return SNMP_INTEGER(monotime(NULL) - peer->uptime);
- case BGPPEERCONNECTRETRYINTERVAL:
- *write_method = write_bgpPeerTable;
- return SNMP_INTEGER(peer->v_connect);
- case BGPPEERHOLDTIME:
- return SNMP_INTEGER(peer->v_holdtime);
- case BGPPEERKEEPALIVE:
- return SNMP_INTEGER(peer->v_keepalive);
- case BGPPEERHOLDTIMECONFIGURED:
- *write_method = write_bgpPeerTable;
- if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
- return SNMP_INTEGER(peer->holdtime);
- else
- return SNMP_INTEGER(peer->v_holdtime);
- case BGPPEERKEEPALIVECONFIGURED:
- *write_method = write_bgpPeerTable;
- if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
- return SNMP_INTEGER(peer->keepalive);
- else
- return SNMP_INTEGER(peer->v_keepalive);
- case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
- *write_method = write_bgpPeerTable;
- return SNMP_INTEGER(peer->v_routeadv);
- case BGPPEERINUPDATEELAPSEDTIME:
- if (peer->update_time == 0)
- return SNMP_INTEGER(0);
- else
- return SNMP_INTEGER(monotime(NULL) - peer->update_time);
- default:
- return NULL;
- }
- return NULL;
-}
-
-static uint8_t *bgpIdentifier(struct variable *v, oid name[], size_t *length,
- int exact, size_t *var_len,
- WriteMethod **write_method)
-{
- struct bgp *bgp;
-
- if (smux_header_generic(v, name, length, exact, var_len, write_method)
- == MATCH_FAILED)
- return NULL;
-
- bgp = bgp_get_default();
- if (!bgp)
- return NULL;
-
- return SNMP_IPADDRESS(bgp->router_id);
-}
-
-static uint8_t *bgpRcvdPathAttrTable(struct variable *v, oid name[],
- size_t *length, int exact, size_t *var_len,
- WriteMethod **write_method)
-{
- /* Received Path Attribute Table. This table contains, one entry
- per path to a network, path attributes received from all peers
- running BGP version 3 or less. This table is obsolete, having
- been replaced in functionality with the bgp4PathAttrTable. */
- return NULL;
-}
-
-static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[],
- size_t *length, struct bgp *bgp,
- struct prefix_ipv4 *addr,
- int exact)
-{
- oid *offset;
- int offsetlen;
- struct bgp_path_info *path;
- struct bgp_path_info *min;
- struct bgp_dest *dest;
- union sockunion su;
- unsigned int len;
- struct in_addr paddr;
-
- sockunion_init(&su);
-
-#define BGP_PATHATTR_ENTRY_OFFSET (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE)
-
- if (exact) {
- if (*length - v->namelen != BGP_PATHATTR_ENTRY_OFFSET)
- return NULL;
-
- /* Set OID offset for prefix. */
- offset = name + v->namelen;
- oid2in_addr(offset, IN_ADDR_SIZE, &addr->prefix);
- offset += IN_ADDR_SIZE;
-
- /* Prefix length. */
- addr->prefixlen = *offset;
- offset++;
-
- /* Peer address. */
- su.sin.sin_family = AF_INET;
- oid2in_addr(offset, IN_ADDR_SIZE, &su.sin.sin_addr);
-
- /* Lookup node. */
- dest = bgp_node_lookup(bgp->rib[AFI_IP][SAFI_UNICAST],
- (struct prefix *)addr);
- if (dest) {
- for (path = bgp_dest_get_bgp_path_info(dest); path;
- path = path->next)
- if (sockunion_same(&path->peer->su, &su))
- return path;
-
- bgp_dest_unlock_node(dest);
- }
- } else {
- offset = name + v->namelen;
- offsetlen = *length - v->namelen;
- len = offsetlen;
-
- if (offsetlen == 0)
- dest = bgp_table_top(bgp->rib[AFI_IP][SAFI_UNICAST]);
- else {
- if (len > IN_ADDR_SIZE)
- len = IN_ADDR_SIZE;
-
- oid2in_addr(offset, len, &addr->prefix);
-
- offset += IN_ADDR_SIZE;
- offsetlen -= IN_ADDR_SIZE;
-
- if (offsetlen > 0)
- addr->prefixlen = *offset;
- else
- addr->prefixlen = len * 8;
-
- dest = bgp_node_get(bgp->rib[AFI_IP][SAFI_UNICAST],
- (struct prefix *)addr);
-
- offset++;
- offsetlen--;
- }
-
- if (offsetlen > 0) {
- len = offsetlen;
- if (len > IN_ADDR_SIZE)
- len = IN_ADDR_SIZE;
-
- oid2in_addr(offset, len, &paddr);
- } else
- paddr.s_addr = INADDR_ANY;
-
- if (!dest)
- return NULL;
-
- do {
- min = NULL;
-
- for (path = bgp_dest_get_bgp_path_info(dest); path;
- path = path->next) {
- if (path->peer->su.sin.sin_family == AF_INET
- && ntohl(paddr.s_addr)
- < ntohl(path->peer->su.sin
- .sin_addr
- .s_addr)) {
- if (min) {
- if (ntohl(path->peer->su.sin
- .sin_addr
- .s_addr)
- < ntohl(min->peer->su.sin
- .sin_addr
- .s_addr))
- min = path;
- } else
- min = path;
- }
- }
-
- if (min) {
- const struct prefix *rn_p =
- bgp_dest_get_prefix(dest);
-
- *length =
- v->namelen + BGP_PATHATTR_ENTRY_OFFSET;
-
- offset = name + v->namelen;
- oid_copy_in_addr(offset, &rn_p->u.prefix4);
- offset += IN_ADDR_SIZE;
- *offset = rn_p->prefixlen;
- offset++;
- oid_copy_in_addr(offset,
- &min->peer->su.sin.sin_addr);
- addr->prefix = rn_p->u.prefix4;
- addr->prefixlen = rn_p->prefixlen;
-
- bgp_dest_unlock_node(dest);
-
- return min;
- }
-
- paddr.s_addr = INADDR_ANY;
- } while ((dest = bgp_route_next(dest)) != NULL);
- }
- return NULL;
-}
-
-static uint8_t *bgp4PathAttrTable(struct variable *v, oid name[],
- size_t *length, int exact, size_t *var_len,
- WriteMethod **write_method)
-{
- struct bgp *bgp;
- struct bgp_path_info *path;
- struct prefix_ipv4 addr;
-
- bgp = bgp_get_default();
- if (!bgp)
- return NULL;
-
- if (smux_header_table(v, name, length, exact, var_len, write_method)
- == MATCH_FAILED)
- return NULL;
- memset(&addr, 0, sizeof(addr));
-
- path = bgp4PathAttrLookup(v, name, length, bgp, &addr, exact);
- if (!path)
- return NULL;
-
- switch (v->magic) {
- case BGP4PATHATTRPEER: /* 1 */
- return SNMP_IPADDRESS(path->peer->su.sin.sin_addr);
- case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */
- return SNMP_INTEGER(addr.prefixlen);
- case BGP4PATHATTRIPADDRPREFIX: /* 3 */
- return SNMP_IPADDRESS(addr.prefix);
- case BGP4PATHATTRORIGIN: /* 4 */
- return SNMP_INTEGER(path->attr->origin);
- case BGP4PATHATTRASPATHSEGMENT: /* 5 */
- return aspath_snmp_pathseg(path->attr->aspath, var_len);
- case BGP4PATHATTRNEXTHOP: /* 6 */
- return SNMP_IPADDRESS(path->attr->nexthop);
- case BGP4PATHATTRMULTIEXITDISC: /* 7 */
- return SNMP_INTEGER(path->attr->med);
- case BGP4PATHATTRLOCALPREF: /* 8 */
- return SNMP_INTEGER(path->attr->local_pref);
- case BGP4PATHATTRATOMICAGGREGATE: /* 9 */
- return SNMP_INTEGER(1);
- case BGP4PATHATTRAGGREGATORAS: /* 10 */
- return SNMP_INTEGER(path->attr->aggregator_as);
- case BGP4PATHATTRAGGREGATORADDR: /* 11 */
- return SNMP_IPADDRESS(path->attr->aggregator_addr);
- case BGP4PATHATTRCALCLOCALPREF: /* 12 */
- return SNMP_INTEGER(-1);
- case BGP4PATHATTRBEST: /* 13 */
-#define BGP4_PathAttrBest_false 1
-#define BGP4_PathAttrBest_true 2
- if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
- return SNMP_INTEGER(BGP4_PathAttrBest_true);
- else
- return SNMP_INTEGER(BGP4_PathAttrBest_false);
- case BGP4PATHATTRUNKNOWN: /* 14 */
- *var_len = 0;
- return NULL;
- }
- return NULL;
-}
-
-/* BGP Traps. */
-static struct trap_object bgpTrapList[] = {{3, {3, 1, BGPPEERREMOTEADDR} },
- {3, {3, 1, BGPPEERLASTERROR} },
- {3, {3, 1, BGPPEERSTATE} } };
-
-static int bgpTrapEstablished(struct peer *peer)
-{
- int ret;
- struct in_addr addr;
- oid index[sizeof(oid) * IN_ADDR_SIZE];
-
- /* Check if this peer just went to Established */
- if ((peer->ostatus != OpenConfirm) || !(peer_established(peer)))
- return 0;
-
- ret = inet_aton(peer->host, &addr);
- if (ret == 0)
- return 0;
-
- oid_copy_in_addr(index, &addr);
-
- smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid,
- array_size(bgp_trap_oid), bgp_oid,
- sizeof(bgp_oid) / sizeof(oid), index, IN_ADDR_SIZE,
- bgpTrapList, array_size(bgpTrapList), BGPESTABLISHED);
- return 0;
-}
-
-static int bgpTrapBackwardTransition(struct peer *peer)
-{
- int ret;
- struct in_addr addr;
- oid index[sizeof(oid) * IN_ADDR_SIZE];
-
- ret = inet_aton(peer->host, &addr);
- if (ret == 0)
- return 0;
-
- oid_copy_in_addr(index, &addr);
-
- smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid,
- array_size(bgp_trap_oid), bgp_oid,
- sizeof(bgp_oid) / sizeof(oid), index, IN_ADDR_SIZE,
- bgpTrapList, array_size(bgpTrapList), BGPBACKWARDTRANSITION);
- return 0;
-}
-
static int bgp_snmp_init(struct thread_master *tm)
{
smux_init(tm);
- REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid);
+ bgp_snmp_bgp4_init(tm);
+ bgp_snmp_bgp4v2_init(tm);
bgp_mpls_l3vpn_module_init();
return 0;
}
diff --git a/bgpd/bgp_snmp.h b/bgpd/bgp_snmp.h
new file mode 100644
index 0000000000..a89e82b6c6
--- /dev/null
+++ b/bgpd/bgp_snmp.h
@@ -0,0 +1,32 @@
+/* Common header file for BGP SNMP implementation.
+ *
+ * Copyright (C) 2022 Donatas Abraitis <donatas@opensourcerouting.org>
+ *
+ * This file is part of FRRouting (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_BGP_SNMP_H_
+#define _FRR_BGP_SNMP_H_
+
+/* SNMP value hack. */
+#define INTEGER ASN_INTEGER
+#define INTEGER32 ASN_INTEGER
+#define COUNTER32 ASN_COUNTER
+#define OCTET_STRING ASN_OCTET_STR
+#define IPADDRESS ASN_IPADDRESS
+#define GAUGE32 ASN_UNSIGNED
+
+#endif /* _FRR_BGP_SNMP_H_ */
diff --git a/bgpd/bgp_snmp_bgp4.c b/bgpd/bgp_snmp_bgp4.c
new file mode 100644
index 0000000000..bb8b7f4b19
--- /dev/null
+++ b/bgpd/bgp_snmp_bgp4.c
@@ -0,0 +1,814 @@
+/* BGP4 SNMP support
+ * Copyright (C) 1999, 2000 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "thread.h"
+#include "smux.h"
+#include "filter.h"
+#include "hook.h"
+#include "libfrr.h"
+#include "lib/version.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_snmp.h"
+#include "bgpd/bgp_snmp_bgp4.h"
+#include "bgpd/bgp_mplsvpn_snmp.h"
+
+/* Declare static local variables for convenience. */
+SNMP_LOCAL_VARIABLES
+
+/* BGP-MIB instances. */
+static oid bgp_oid[] = {BGP4MIB};
+static oid bgp_trap_oid[] = {BGP4MIB, 0};
+
+/* IP address 0.0.0.0. */
+static struct in_addr bgp_empty_addr = {.s_addr = 0};
+
+static uint8_t *bgpVersion(struct variable *v, oid name[], size_t *length,
+ int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ static uint8_t version;
+
+ if (smux_header_generic(v, name, length, exact, var_len,
+ write_method) == MATCH_FAILED)
+ return NULL;
+
+ /* Return BGP version. Zebra bgpd only support version 4. */
+ version = (0x80 >> (BGP_VERSION_4 - 1));
+
+ /* Return octet string length 1. */
+ *var_len = 1;
+ return &version;
+}
+
+static uint8_t *bgpLocalAs(struct variable *v, oid name[], size_t *length,
+ int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct bgp *bgp;
+
+ if (smux_header_generic(v, name, length, exact, var_len,
+ write_method) == MATCH_FAILED)
+ return NULL;
+
+ /* Get BGP structure. */
+ bgp = bgp_get_default();
+ if (!bgp)
+ return NULL;
+
+ return SNMP_INTEGER(bgp->as);
+}
+
+static struct peer *peer_lookup_addr_ipv4(struct in_addr *src)
+{
+ struct bgp *bgp;
+ struct peer *peer;
+ struct listnode *node;
+ struct listnode *bgpnode;
+
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) {
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
+ if (sockunion_family(&peer->su) != AF_INET)
+ continue;
+
+ if (sockunion2ip(&peer->su) == src->s_addr)
+ return peer;
+ }
+ }
+
+ return NULL;
+}
+
+static struct peer *bgp_peer_lookup_next(struct in_addr *src)
+{
+ struct bgp *bgp;
+ struct peer *peer;
+ struct peer *next_peer = NULL;
+ struct listnode *node;
+ struct listnode *bgpnode;
+
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) {
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
+ if (sockunion_family(&peer->su) != AF_INET)
+ continue;
+ if (ntohl(sockunion2ip(&peer->su)) <=
+ ntohl(src->s_addr))
+ continue;
+
+ if (!next_peer ||
+ ntohl(sockunion2ip(&next_peer->su)) >
+ ntohl(sockunion2ip(&peer->su))) {
+ next_peer = peer;
+ }
+ }
+ }
+
+ if (next_peer) {
+ src->s_addr = sockunion2ip(&next_peer->su);
+ return next_peer;
+ }
+
+ return NULL;
+}
+
+/* 1.3.6.1.2.1.15.3.1.x = 10 */
+#define PEERTAB_NAMELEN 10
+
+static struct peer *bgpPeerTable_lookup(struct variable *v, oid name[],
+ size_t *length, struct in_addr *addr,
+ int exact)
+{
+ struct peer *peer = NULL;
+ size_t namelen = v ? v->namelen : PEERTAB_NAMELEN;
+ int len;
+
+ if (exact) {
+ /* Check the length. */
+ if (*length - namelen != sizeof(struct in_addr))
+ return NULL;
+
+ oid2in_addr(name + namelen, IN_ADDR_SIZE, addr);
+
+ peer = peer_lookup_addr_ipv4(addr);
+ return peer;
+ } else {
+ len = *length - namelen;
+ if (len > 4)
+ len = 4;
+
+ oid2in_addr(name + namelen, len, addr);
+
+ peer = bgp_peer_lookup_next(addr);
+
+ if (peer == NULL)
+ return NULL;
+
+ oid_copy_in_addr(name + namelen, addr);
+ *length = sizeof(struct in_addr) + namelen;
+
+ return peer;
+ }
+ return NULL;
+}
+
+/* BGP write methods. */
+static int write_bgpPeerTable(int action, uint8_t *var_val,
+ uint8_t var_val_type, size_t var_val_len,
+ uint8_t *statP, oid *name, size_t length)
+{
+ struct in_addr addr;
+ struct peer *peer;
+ long intval;
+
+ if (var_val_type != ASN_INTEGER) {
+ return SNMP_ERR_WRONGTYPE;
+ }
+ if (var_val_len != sizeof(long)) {
+ return SNMP_ERR_WRONGLENGTH;
+ }
+
+ intval = *(long *)var_val;
+
+ memset(&addr, 0, sizeof(addr));
+
+ peer = bgpPeerTable_lookup(NULL, name, &length, &addr, 1);
+ if (!peer)
+ return SNMP_ERR_NOSUCHNAME;
+
+ if (action != SNMP_MSG_INTERNAL_SET_COMMIT)
+ return SNMP_ERR_NOERROR;
+
+ zlog_info("%s: SNMP write .%ld = %ld", peer->host,
+ (long)name[PEERTAB_NAMELEN - 1], intval);
+
+ switch (name[PEERTAB_NAMELEN - 1]) {
+ case BGPPEERADMINSTATUS:
+#define BGP_PeerAdmin_stop 1
+#define BGP_PeerAdmin_start 2
+ /* When the peer is established, */
+ if (intval == BGP_PeerAdmin_stop)
+ BGP_EVENT_ADD(peer, BGP_Stop);
+ else if (intval == BGP_PeerAdmin_start)
+ ; /* Do nothing. */
+ else
+ return SNMP_ERR_NOSUCHNAME;
+ break;
+ case BGPPEERCONNECTRETRYINTERVAL:
+ peer_flag_set(peer, PEER_FLAG_TIMER_CONNECT);
+ peer->connect = intval;
+ peer->v_connect = intval;
+ break;
+ case BGPPEERHOLDTIMECONFIGURED:
+ peer_flag_set(peer, PEER_FLAG_TIMER);
+ peer->holdtime = intval;
+ peer->v_holdtime = intval;
+ break;
+ case BGPPEERKEEPALIVECONFIGURED:
+ peer_flag_set(peer, PEER_FLAG_TIMER);
+ peer->keepalive = intval;
+ peer->v_keepalive = intval;
+ break;
+ case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
+ peer->v_routeadv = intval;
+ break;
+ }
+ return SNMP_ERR_NOERROR;
+}
+
+static uint8_t *bgpPeerTable(struct variable *v, oid name[], size_t *length,
+ int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ static struct in_addr addr;
+ struct peer *peer;
+ uint32_t ui, uo;
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method) ==
+ MATCH_FAILED)
+ return NULL;
+ memset(&addr, 0, sizeof(addr));
+
+ peer = bgpPeerTable_lookup(v, name, length, &addr, exact);
+ if (!peer)
+ return NULL;
+
+ switch (v->magic) {
+ case BGPPEERIDENTIFIER:
+ return SNMP_IPADDRESS(peer->remote_id);
+ case BGPPEERSTATE:
+ return SNMP_INTEGER(peer->status);
+ case BGPPEERADMINSTATUS:
+ *write_method = write_bgpPeerTable;
+#define BGP_PeerAdmin_stop 1
+#define BGP_PeerAdmin_start 2
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
+ return SNMP_INTEGER(BGP_PeerAdmin_stop);
+ else
+ return SNMP_INTEGER(BGP_PeerAdmin_start);
+ case BGPPEERNEGOTIATEDVERSION:
+ return SNMP_INTEGER(BGP_VERSION_4);
+ case BGPPEERLOCALADDR:
+ if (peer->su_local)
+ return SNMP_IPADDRESS(peer->su_local->sin.sin_addr);
+ else
+ return SNMP_IPADDRESS(bgp_empty_addr);
+ case BGPPEERLOCALPORT:
+ if (peer->su_local)
+ return SNMP_INTEGER(
+ ntohs(peer->su_local->sin.sin_port));
+ else
+ return SNMP_INTEGER(0);
+ case BGPPEERREMOTEADDR:
+ if (peer->su_remote)
+ return SNMP_IPADDRESS(peer->su_remote->sin.sin_addr);
+ else
+ return SNMP_IPADDRESS(bgp_empty_addr);
+ case BGPPEERREMOTEPORT:
+ if (peer->su_remote)
+ return SNMP_INTEGER(
+ ntohs(peer->su_remote->sin.sin_port));
+ else
+ return SNMP_INTEGER(0);
+ case BGPPEERREMOTEAS:
+ return SNMP_INTEGER(peer->as);
+ case BGPPEERINUPDATES:
+ ui = atomic_load_explicit(&peer->update_in,
+ memory_order_relaxed);
+ return SNMP_INTEGER(ui);
+ case BGPPEEROUTUPDATES:
+ uo = atomic_load_explicit(&peer->update_out,
+ memory_order_relaxed);
+ return SNMP_INTEGER(uo);
+ case BGPPEERINTOTALMESSAGES:
+ return SNMP_INTEGER(PEER_TOTAL_RX(peer));
+ case BGPPEEROUTTOTALMESSAGES:
+ return SNMP_INTEGER(PEER_TOTAL_TX(peer));
+ case BGPPEERLASTERROR: {
+ static uint8_t lasterror[2];
+ lasterror[0] = peer->notify.code;
+ lasterror[1] = peer->notify.subcode;
+ *var_len = 2;
+ return (uint8_t *)&lasterror;
+ }
+ case BGPPEERFSMESTABLISHEDTRANSITIONS:
+ return SNMP_INTEGER(peer->established);
+ case BGPPEERFSMESTABLISHEDTIME:
+ if (peer->uptime == 0)
+ return SNMP_INTEGER(0);
+ else
+ return SNMP_INTEGER(monotime(NULL) - peer->uptime);
+ case BGPPEERCONNECTRETRYINTERVAL:
+ *write_method = write_bgpPeerTable;
+ return SNMP_INTEGER(peer->v_connect);
+ case BGPPEERHOLDTIME:
+ return SNMP_INTEGER(peer->v_holdtime);
+ case BGPPEERKEEPALIVE:
+ return SNMP_INTEGER(peer->v_keepalive);
+ case BGPPEERHOLDTIMECONFIGURED:
+ *write_method = write_bgpPeerTable;
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
+ return SNMP_INTEGER(peer->holdtime);
+ else
+ return SNMP_INTEGER(peer->v_holdtime);
+ case BGPPEERKEEPALIVECONFIGURED:
+ *write_method = write_bgpPeerTable;
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
+ return SNMP_INTEGER(peer->keepalive);
+ else
+ return SNMP_INTEGER(peer->v_keepalive);
+ case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
+ *write_method = write_bgpPeerTable;
+ return SNMP_INTEGER(peer->v_routeadv);
+ case BGPPEERINUPDATEELAPSEDTIME:
+ if (peer->update_time == 0)
+ return SNMP_INTEGER(0);
+ else
+ return SNMP_INTEGER(monotime(NULL) - peer->update_time);
+ default:
+ return NULL;
+ }
+ return NULL;
+}
+
+static uint8_t *bgpIdentifier(struct variable *v, oid name[], size_t *length,
+ int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct bgp *bgp;
+
+ if (smux_header_generic(v, name, length, exact, var_len,
+ write_method) == MATCH_FAILED)
+ return NULL;
+
+ bgp = bgp_get_default();
+ if (!bgp)
+ return NULL;
+
+ return SNMP_IPADDRESS(bgp->router_id);
+}
+
+static uint8_t *bgpRcvdPathAttrTable(struct variable *v, oid name[],
+ size_t *length, int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ /* Received Path Attribute Table. This table contains, one entry
+ per path to a network, path attributes received from all peers
+ running BGP version 3 or less. This table is obsolete, having
+ been replaced in functionality with the bgp4PathAttrTable. */
+ return NULL;
+}
+
+static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[],
+ size_t *length, struct bgp *bgp,
+ struct prefix_ipv4 *addr,
+ int exact)
+{
+ oid *offset;
+ int offsetlen;
+ struct bgp_path_info *path;
+ struct bgp_path_info *min;
+ struct bgp_dest *dest;
+ union sockunion su;
+ unsigned int len;
+ struct in_addr paddr;
+
+ sockunion_init(&su);
+
+#define BGP_PATHATTR_ENTRY_OFFSET (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE)
+
+ if (exact) {
+ if (*length - v->namelen != BGP_PATHATTR_ENTRY_OFFSET)
+ return NULL;
+
+ /* Set OID offset for prefix. */
+ offset = name + v->namelen;
+ oid2in_addr(offset, IN_ADDR_SIZE, &addr->prefix);
+ offset += IN_ADDR_SIZE;
+
+ /* Prefix length. */
+ addr->prefixlen = *offset;
+ offset++;
+
+ /* Peer address. */
+ su.sin.sin_family = AF_INET;
+ oid2in_addr(offset, IN_ADDR_SIZE, &su.sin.sin_addr);
+
+ /* Lookup node. */
+ dest = bgp_node_lookup(bgp->rib[AFI_IP][SAFI_UNICAST],
+ (struct prefix *)addr);
+ if (dest) {
+ for (path = bgp_dest_get_bgp_path_info(dest); path;
+ path = path->next)
+ if (sockunion_same(&path->peer->su, &su))
+ return path;
+
+ bgp_dest_unlock_node(dest);
+ }
+ } else {
+ offset = name + v->namelen;
+ offsetlen = *length - v->namelen;
+ len = offsetlen;
+
+ if (offsetlen == 0)
+ dest = bgp_table_top(bgp->rib[AFI_IP][SAFI_UNICAST]);
+ else {
+ if (len > IN_ADDR_SIZE)
+ len = IN_ADDR_SIZE;
+
+ oid2in_addr(offset, len, &addr->prefix);
+
+ offset += IN_ADDR_SIZE;
+ offsetlen -= IN_ADDR_SIZE;
+
+ if (offsetlen > 0)
+ addr->prefixlen = *offset;
+ else
+ addr->prefixlen = len * 8;
+
+ dest = bgp_node_get(bgp->rib[AFI_IP][SAFI_UNICAST],
+ (struct prefix *)addr);
+
+ offset++;
+ offsetlen--;
+ }
+
+ if (offsetlen > 0) {
+ len = offsetlen;
+ if (len > IN_ADDR_SIZE)
+ len = IN_ADDR_SIZE;
+
+ oid2in_addr(offset, len, &paddr);
+ } else
+ paddr.s_addr = INADDR_ANY;
+
+ if (!dest)
+ return NULL;
+
+ do {
+ min = NULL;
+
+ for (path = bgp_dest_get_bgp_path_info(dest); path;
+ path = path->next) {
+ if (path->peer->su.sin.sin_family == AF_INET &&
+ ntohl(paddr.s_addr) <
+ ntohl(path->peer->su.sin.sin_addr
+ .s_addr)) {
+ if (min) {
+ if (ntohl(path->peer->su.sin
+ .sin_addr
+ .s_addr) <
+ ntohl(min->peer->su.sin
+ .sin_addr
+ .s_addr))
+ min = path;
+ } else
+ min = path;
+ }
+ }
+
+ if (min) {
+ const struct prefix *rn_p =
+ bgp_dest_get_prefix(dest);
+
+ *length =
+ v->namelen + BGP_PATHATTR_ENTRY_OFFSET;
+
+ offset = name + v->namelen;
+ oid_copy_in_addr(offset, &rn_p->u.prefix4);
+ offset += IN_ADDR_SIZE;
+ *offset = rn_p->prefixlen;
+ offset++;
+ oid_copy_in_addr(offset,
+ &min->peer->su.sin.sin_addr);
+ addr->prefix = rn_p->u.prefix4;
+ addr->prefixlen = rn_p->prefixlen;
+
+ bgp_dest_unlock_node(dest);
+
+ return min;
+ }
+
+ paddr.s_addr = INADDR_ANY;
+ } while ((dest = bgp_route_next(dest)) != NULL);
+ }
+ return NULL;
+}
+
+static uint8_t *bgp4PathAttrTable(struct variable *v, oid name[],
+ size_t *length, int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct bgp *bgp;
+ struct bgp_path_info *path;
+ struct prefix_ipv4 addr;
+
+ bgp = bgp_get_default();
+ if (!bgp)
+ return NULL;
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method) ==
+ MATCH_FAILED)
+ return NULL;
+ memset(&addr, 0, sizeof(addr));
+
+ path = bgp4PathAttrLookup(v, name, length, bgp, &addr, exact);
+ if (!path)
+ return NULL;
+
+ switch (v->magic) {
+ case BGP4PATHATTRPEER: /* 1 */
+ return SNMP_IPADDRESS(path->peer->su.sin.sin_addr);
+ case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */
+ return SNMP_INTEGER(addr.prefixlen);
+ case BGP4PATHATTRIPADDRPREFIX: /* 3 */
+ return SNMP_IPADDRESS(addr.prefix);
+ case BGP4PATHATTRORIGIN: /* 4 */
+ return SNMP_INTEGER(path->attr->origin);
+ case BGP4PATHATTRASPATHSEGMENT: /* 5 */
+ return aspath_snmp_pathseg(path->attr->aspath, var_len);
+ case BGP4PATHATTRNEXTHOP: /* 6 */
+ return SNMP_IPADDRESS(path->attr->nexthop);
+ case BGP4PATHATTRMULTIEXITDISC: /* 7 */
+ return SNMP_INTEGER(path->attr->med);
+ case BGP4PATHATTRLOCALPREF: /* 8 */
+ return SNMP_INTEGER(path->attr->local_pref);
+ case BGP4PATHATTRATOMICAGGREGATE: /* 9 */
+ return SNMP_INTEGER(1);
+ case BGP4PATHATTRAGGREGATORAS: /* 10 */
+ return SNMP_INTEGER(path->attr->aggregator_as);
+ case BGP4PATHATTRAGGREGATORADDR: /* 11 */
+ return SNMP_IPADDRESS(path->attr->aggregator_addr);
+ case BGP4PATHATTRCALCLOCALPREF: /* 12 */
+ return SNMP_INTEGER(-1);
+ case BGP4PATHATTRBEST: /* 13 */
+#define BGP4_PathAttrBest_false 1
+#define BGP4_PathAttrBest_true 2
+ if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
+ return SNMP_INTEGER(BGP4_PathAttrBest_true);
+ else
+ return SNMP_INTEGER(BGP4_PathAttrBest_false);
+ case BGP4PATHATTRUNKNOWN: /* 14 */
+ *var_len = 0;
+ return NULL;
+ }
+ return NULL;
+}
+
+/* BGP Traps. */
+static struct trap_object bgpTrapList[] = {{3, {3, 1, BGPPEERREMOTEADDR}},
+ {3, {3, 1, BGPPEERLASTERROR}},
+ {3, {3, 1, BGPPEERSTATE}}};
+
+static struct variable bgp_variables[] = {
+ /* BGP version. */
+ {BGPVERSION, OCTET_STRING, RONLY, bgpVersion, 1, {1}},
+ /* BGP local AS. */
+ {BGPLOCALAS, INTEGER, RONLY, bgpLocalAs, 1, {2}},
+ /* BGP peer table. */
+ {BGPPEERIDENTIFIER, IPADDRESS, RONLY, bgpPeerTable, 3, {3, 1, 1}},
+ {BGPPEERSTATE, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 2}},
+ {BGPPEERADMINSTATUS, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 3}},
+ {BGPPEERNEGOTIATEDVERSION,
+ INTEGER32,
+ RONLY,
+ bgpPeerTable,
+ 3,
+ {3, 1, 4}},
+ {BGPPEERLOCALADDR, IPADDRESS, RONLY, bgpPeerTable, 3, {3, 1, 5}},
+ {BGPPEERLOCALPORT, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 6}},
+ {BGPPEERREMOTEADDR, IPADDRESS, RONLY, bgpPeerTable, 3, {3, 1, 7}},
+ {BGPPEERREMOTEPORT, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 8}},
+ {BGPPEERREMOTEAS, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 9}},
+ {BGPPEERINUPDATES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 10}},
+ {BGPPEEROUTUPDATES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 11}},
+ {BGPPEERINTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 12}},
+ {BGPPEEROUTTOTALMESSAGES,
+ COUNTER32,
+ RONLY,
+ bgpPeerTable,
+ 3,
+ {3, 1, 13}},
+ {BGPPEERLASTERROR, OCTET_STRING, RONLY, bgpPeerTable, 3, {3, 1, 14}},
+ {BGPPEERFSMESTABLISHEDTRANSITIONS,
+ COUNTER32,
+ RONLY,
+ bgpPeerTable,
+ 3,
+ {3, 1, 15}},
+ {BGPPEERFSMESTABLISHEDTIME,
+ GAUGE32,
+ RONLY,
+ bgpPeerTable,
+ 3,
+ {3, 1, 16}},
+ {BGPPEERCONNECTRETRYINTERVAL,
+ INTEGER,
+ RWRITE,
+ bgpPeerTable,
+ 3,
+ {3, 1, 17}},
+ {BGPPEERHOLDTIME, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 18}},
+ {BGPPEERKEEPALIVE, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 19}},
+ {BGPPEERHOLDTIMECONFIGURED,
+ INTEGER,
+ RWRITE,
+ bgpPeerTable,
+ 3,
+ {3, 1, 20}},
+ {BGPPEERKEEPALIVECONFIGURED,
+ INTEGER,
+ RWRITE,
+ bgpPeerTable,
+ 3,
+ {3, 1, 21}},
+ {BGPPEERMINROUTEADVERTISEMENTINTERVAL,
+ INTEGER,
+ RWRITE,
+ bgpPeerTable,
+ 3,
+ {3, 1, 23}},
+ {BGPPEERINUPDATEELAPSEDTIME,
+ GAUGE32,
+ RONLY,
+ bgpPeerTable,
+ 3,
+ {3, 1, 24}},
+ /* BGP identifier. */
+ {BGPIDENTIFIER, IPADDRESS, RONLY, bgpIdentifier, 1, {4}},
+ /* BGP received path attribute table. */
+ {BGPPATHATTRPEER, IPADDRESS, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 1}},
+ {BGPPATHATTRDESTNETWORK,
+ IPADDRESS,
+ RONLY,
+ bgpRcvdPathAttrTable,
+ 3,
+ {5, 1, 2}},
+ {BGPPATHATTRORIGIN, INTEGER, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 3}},
+ {BGPPATHATTRASPATH,
+ OCTET_STRING,
+ RONLY,
+ bgpRcvdPathAttrTable,
+ 3,
+ {5, 1, 4}},
+ {BGPPATHATTRNEXTHOP,
+ IPADDRESS,
+ RONLY,
+ bgpRcvdPathAttrTable,
+ 3,
+ {5, 1, 5}},
+ {BGPPATHATTRINTERASMETRIC,
+ INTEGER32,
+ RONLY,
+ bgpRcvdPathAttrTable,
+ 3,
+ {5, 1, 6}},
+ /* BGP-4 received path attribute table. */
+ {BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 1}},
+ {BGP4PATHATTRIPADDRPREFIXLEN,
+ INTEGER,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 2}},
+ {BGP4PATHATTRIPADDRPREFIX,
+ IPADDRESS,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 3}},
+ {BGP4PATHATTRORIGIN, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 4}},
+ {BGP4PATHATTRASPATHSEGMENT,
+ OCTET_STRING,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 5}},
+ {BGP4PATHATTRNEXTHOP,
+ IPADDRESS,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 6}},
+ {BGP4PATHATTRMULTIEXITDISC,
+ INTEGER,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 7}},
+ {BGP4PATHATTRLOCALPREF,
+ INTEGER,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 8}},
+ {BGP4PATHATTRATOMICAGGREGATE,
+ INTEGER,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 9}},
+ {BGP4PATHATTRAGGREGATORAS,
+ INTEGER,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 10}},
+ {BGP4PATHATTRAGGREGATORADDR,
+ IPADDRESS,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 11}},
+ {BGP4PATHATTRCALCLOCALPREF,
+ INTEGER,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 12}},
+ {BGP4PATHATTRBEST, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 13}},
+ {BGP4PATHATTRUNKNOWN,
+ OCTET_STRING,
+ RONLY,
+ bgp4PathAttrTable,
+ 3,
+ {6, 1, 14}},
+};
+
+int bgpTrapEstablished(struct peer *peer)
+{
+ int ret;
+ struct in_addr addr;
+ oid index[sizeof(oid) * IN_ADDR_SIZE];
+
+ /* Check if this peer just went to Established */
+ if ((peer->ostatus != OpenConfirm) || !(peer_established(peer)))
+ return 0;
+
+ ret = inet_aton(peer->host, &addr);
+ if (ret == 0)
+ return 0;
+
+ oid_copy_in_addr(index, &addr);
+
+ smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid,
+ array_size(bgp_trap_oid), bgp_oid,
+ sizeof(bgp_oid) / sizeof(oid), index, IN_ADDR_SIZE,
+ bgpTrapList, array_size(bgpTrapList), BGPESTABLISHED);
+ return 0;
+}
+
+int bgpTrapBackwardTransition(struct peer *peer)
+{
+ int ret;
+ struct in_addr addr;
+ oid index[sizeof(oid) * IN_ADDR_SIZE];
+
+ ret = inet_aton(peer->host, &addr);
+ if (ret == 0)
+ return 0;
+
+ oid_copy_in_addr(index, &addr);
+
+ smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid,
+ array_size(bgp_trap_oid), bgp_oid,
+ sizeof(bgp_oid) / sizeof(oid), index, IN_ADDR_SIZE,
+ bgpTrapList, array_size(bgpTrapList), BGPBACKWARDTRANSITION);
+ return 0;
+}
+
+int bgp_snmp_bgp4_init(struct thread_master *tm)
+{
+ REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid);
+ return 0;
+}
diff --git a/bgpd/bgp_snmp_bgp4.h b/bgpd/bgp_snmp_bgp4.h
new file mode 100644
index 0000000000..ac51191660
--- /dev/null
+++ b/bgpd/bgp_snmp_bgp4.h
@@ -0,0 +1,90 @@
+/* BGP4-MIB SNMP support
+ *
+ * Using: http://www.circitor.fr/Mibs/Html/B/BGP4-MIB.php
+ *
+ * Copyright (C) 2022 Donatas Abraitis <donatas@opensourcerouting.org>
+ *
+ * This file is part of FRRouting (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_BGP_SNMP_BGP4_H_
+#define _FRR_BGP_SNMP_BGP4_H_
+
+#define BGPVERSION 0
+#define BGPLOCALAS 0
+#define BGPIDENTIFIER 0
+
+/* bgp */
+#define BGP4MIB 1, 3, 6, 1, 2, 1, 15
+
+/* bgpTraps */
+#define BGPESTABLISHED 1
+#define BGPBACKWARDTRANSITION 2
+
+/* bgpPeerTable */
+#define BGPPEERIDENTIFIER 1
+#define BGPPEERSTATE 2
+#define BGPPEERADMINSTATUS 3
+#define BGPPEERNEGOTIATEDVERSION 4
+#define BGPPEERLOCALADDR 5
+#define BGPPEERLOCALPORT 6
+#define BGPPEERREMOTEADDR 7
+#define BGPPEERREMOTEPORT 8
+#define BGPPEERREMOTEAS 9
+#define BGPPEERINUPDATES 10
+#define BGPPEEROUTUPDATES 11
+#define BGPPEERINTOTALMESSAGES 12
+#define BGPPEEROUTTOTALMESSAGES 13
+#define BGPPEERLASTERROR 14
+#define BGPPEERFSMESTABLISHEDTRANSITIONS 15
+#define BGPPEERFSMESTABLISHEDTIME 16
+#define BGPPEERCONNECTRETRYINTERVAL 17
+#define BGPPEERHOLDTIME 18
+#define BGPPEERKEEPALIVE 19
+#define BGPPEERHOLDTIMECONFIGURED 20
+#define BGPPEERKEEPALIVECONFIGURED 21
+#define BGPPEERMINROUTEADVERTISEMENTINTERVAL 22
+#define BGPPEERINUPDATEELAPSEDTIME 23
+
+/* bgpPathAttrEntry */
+#define BGPPATHATTRPEER 1
+#define BGPPATHATTRDESTNETWORK 2
+#define BGPPATHATTRORIGIN 3
+#define BGPPATHATTRASPATH 4
+#define BGPPATHATTRNEXTHOP 5
+#define BGPPATHATTRINTERASMETRIC 6
+
+/* bgp4PathAttrEntry */
+#define BGP4PATHATTRPEER 1
+#define BGP4PATHATTRIPADDRPREFIXLEN 2
+#define BGP4PATHATTRIPADDRPREFIX 3
+#define BGP4PATHATTRORIGIN 4
+#define BGP4PATHATTRASPATHSEGMENT 5
+#define BGP4PATHATTRNEXTHOP 6
+#define BGP4PATHATTRMULTIEXITDISC 7
+#define BGP4PATHATTRLOCALPREF 8
+#define BGP4PATHATTRATOMICAGGREGATE 9
+#define BGP4PATHATTRAGGREGATORAS 10
+#define BGP4PATHATTRAGGREGATORADDR 11
+#define BGP4PATHATTRCALCLOCALPREF 12
+#define BGP4PATHATTRBEST 13
+#define BGP4PATHATTRUNKNOWN 14
+
+extern int bgpTrapEstablished(struct peer *peer);
+extern int bgpTrapBackwardTransition(struct peer *peer);
+extern int bgp_snmp_bgp4_init(struct thread_master *tm);
+
+#endif /* _FRR_BGP_SNMP_BGP4_H_ */
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c
new file mode 100644
index 0000000000..fe0c33251e
--- /dev/null
+++ b/bgpd/bgp_snmp_bgp4v2.c
@@ -0,0 +1,1419 @@
+/* BGP4V2-MIB SNMP support
+ *
+ * Copyright (C) 2022 Donatas Abraitis <donatas@opensourcerouting.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "thread.h"
+#include "smux.h"
+#include "filter.h"
+#include "hook.h"
+#include "libfrr.h"
+#include "lib/version.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_snmp.h"
+#include "bgpd/bgp_snmp_bgp4v2.h"
+
+SNMP_LOCAL_VARIABLES
+
+static oid bgpv2_oid[] = {BGP4V2MIB};
+static struct in_addr bgp_empty_addr = {};
+
+static struct peer *peer_lookup_all_vrf(struct ipaddr *addr)
+{
+ struct bgp *bgp;
+ struct peer *peer;
+ struct listnode *node;
+ struct listnode *bgpnode;
+
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) {
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
+ switch (sockunion_family(&peer->su)) {
+ case AF_INET:
+ if (IPV4_ADDR_SAME(&peer->su.sin.sin_addr,
+ &addr->ip._v4_addr))
+ return peer;
+ break;
+ case AF_INET6:
+ if (IPV6_ADDR_SAME(&peer->su.sin6.sin6_addr,
+ &addr->ip._v6_addr))
+ return peer;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static struct peer *peer_lookup_all_vrf_next(struct ipaddr *addr, oid *offset,
+ sa_family_t family)
+{
+ struct bgp *bgp;
+ struct peer *peer;
+ struct peer *next_peer = NULL;
+ struct listnode *node;
+ struct listnode *bgpnode;
+
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) {
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
+ sa_family_t peer_family = sockunion_family(&peer->su);
+
+ if (peer_family != family)
+ continue;
+
+ switch (sockunion_family(&peer->su)) {
+ case AF_INET:
+ oid2in_addr(offset, IN_ADDR_SIZE,
+ &addr->ip._v4_addr);
+ if (IPV4_ADDR_CMP(&peer->su.sin.sin_addr,
+ &addr->ip._v4_addr) < 0 ||
+ IPV4_ADDR_SAME(&peer->su.sin.sin_addr,
+ &addr->ip._v4_addr))
+ continue;
+
+ if (!next_peer ||
+ IPV4_ADDR_CMP(&next_peer->su.sin.sin_addr,
+ &peer->su.sin.sin_addr) > 0)
+ next_peer = peer;
+
+ break;
+ case AF_INET6:
+ oid2in6_addr(offset, &addr->ip._v6_addr);
+ if (IPV6_ADDR_CMP(&peer->su.sin6.sin6_addr,
+ &addr->ip._v6_addr) < 0 ||
+ IPV6_ADDR_SAME(&peer->su.sin6.sin6_addr,
+ &addr->ip._v6_addr))
+ continue;
+
+ if (!next_peer ||
+ IPV6_ADDR_CMP(&next_peer->su.sin6.sin6_addr,
+ &peer->su.sin6.sin6_addr) > 0)
+ next_peer = peer;
+
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (next_peer)
+ return next_peer;
+
+ return NULL;
+}
+
+static struct peer *bgpv2PeerTable_lookup(struct variable *v, oid name[],
+ size_t *length, int exact,
+ struct ipaddr *addr)
+{
+ struct peer *peer = NULL;
+ size_t namelen = v ? v->namelen : BGP4V2_PEER_ENTRY_OFFSET;
+ oid *offset = name + namelen;
+ sa_family_t family = name[namelen - 1] == 4 ? AF_INET : AF_INET6;
+ int afi_len = IN_ADDR_SIZE;
+ size_t offsetlen = *length - namelen;
+
+ if (family == AF_INET6)
+ afi_len = IN6_ADDR_SIZE;
+
+ /* Somehow with net-snmp 5.7.3, every OID item in an array
+ * is uninitialized and has a max random value, let's zero it.
+ * With 5.8, 5.9, it works fine even without this hack.
+ */
+ if (!offsetlen) {
+ for (int i = 0; i < afi_len; i++)
+ *(offset + i) = 0;
+ }
+
+ if (exact) {
+ if (family == AF_INET) {
+ oid2in_addr(offset, afi_len, &addr->ip._v4_addr);
+ peer = peer_lookup_all_vrf(addr);
+ return peer;
+ } else if (family == AF_INET6) {
+ oid2in6_addr(offset, &addr->ip._v6_addr);
+ return peer_lookup_all_vrf(addr);
+ }
+ } else {
+ peer = peer_lookup_all_vrf_next(addr, offset, family);
+ if (peer == NULL)
+ return NULL;
+
+ switch (sockunion_family(&peer->su)) {
+ case AF_INET:
+ oid_copy_in_addr(offset, &peer->su.sin.sin_addr);
+ *length = afi_len + namelen;
+ return peer;
+ case AF_INET6:
+ oid_copy_in6_addr(offset, &peer->su.sin6.sin6_addr);
+ *length = afi_len + namelen;
+ return peer;
+ default:
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static uint8_t *bgpv2PeerTable(struct variable *v, oid name[], size_t *length,
+ int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct peer *peer;
+ struct ipaddr addr = {};
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method) ==
+ MATCH_FAILED)
+ return NULL;
+
+ peer = bgpv2PeerTable_lookup(v, name, length, exact, &addr);
+ if (!peer)
+ return NULL;
+
+ switch (v->magic) {
+ case BGP4V2_PEER_INSTANCE:
+ return SNMP_INTEGER(peer->bgp->vrf_id);
+ case BGP4V2_PEER_LOCAL_ADDR_TYPE:
+ if (peer->su_local)
+ return SNMP_INTEGER(peer->su_local->sa.sa_family ==
+ AF_INET
+ ? AFI_IP
+ : AFI_IP6);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LOCAL_ADDR:
+ if (peer->su_local)
+ if (peer->su_local->sa.sa_family == AF_INET)
+ return SNMP_IPADDRESS(
+ peer->su_local->sin.sin_addr);
+ else
+ return SNMP_IP6ADDRESS(
+ peer->su_local->sin6.sin6_addr);
+ else
+ return SNMP_IPADDRESS(bgp_empty_addr);
+ case BGP4V2_PEER_REMOTE_ADDR_TYPE:
+ if (peer->su_remote)
+ return SNMP_INTEGER(peer->su_remote->sa.sa_family ==
+ AF_INET
+ ? AFI_IP
+ : AFI_IP6);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_REMOTE_ADDR:
+ if (peer->su_remote)
+ if (peer->su_remote->sa.sa_family == AF_INET)
+ return SNMP_IPADDRESS(
+ peer->su_remote->sin.sin_addr);
+ else
+ return SNMP_IP6ADDRESS(
+ peer->su_remote->sin6.sin6_addr);
+ else
+ return SNMP_IPADDRESS(bgp_empty_addr);
+ case BGP4V2_PEER_LOCAL_PORT:
+ if (peer->su_local)
+ if (peer->su_local->sa.sa_family == AF_INET)
+ return SNMP_INTEGER(
+ ntohs(peer->su_local->sin.sin_port));
+ else
+ return SNMP_INTEGER(
+ ntohs(peer->su_local->sin6.sin6_port));
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LOCAL_AS:
+ return SNMP_INTEGER(peer->local_as);
+ case BGP4V2_PEER_LOCAL_IDENTIFIER:
+ return SNMP_IPADDRESS(peer->local_id);
+ case BGP4V2_PEER_REMOTE_PORT:
+ if (peer->su_remote)
+ if (peer->su_remote->sa.sa_family == AF_INET)
+ return SNMP_INTEGER(
+ ntohs(peer->su_remote->sin.sin_port));
+ else
+ return SNMP_INTEGER(
+ ntohs(peer->su_remote->sin6.sin6_port));
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_REMOTE_AS:
+ return SNMP_INTEGER(peer->as);
+ case BGP4V2_PEER_REMOTE_IDENTIFIER:
+ return SNMP_IPADDRESS(peer->remote_id);
+ case BGP4V2_PEER_ADMIN_STATUS:
+#define BGP_PEER_ADMIN_STATUS_HALTED 1
+#define BGP_PEER_ADMIN_STATUS_RUNNING 2
+ if (BGP_PEER_START_SUPPRESSED(peer))
+ return SNMP_INTEGER(BGP_PEER_ADMIN_STATUS_HALTED);
+ else
+ return SNMP_INTEGER(BGP_PEER_ADMIN_STATUS_RUNNING);
+ case BGP4V2_PEER_STATE:
+ return SNMP_INTEGER(peer->status);
+ case BGP4V2_PEER_DESCRIPTION:
+ if (peer->desc)
+ return SNMP_STRING(peer->desc);
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *bgpv2PeerErrorsTable(struct variable *v, oid name[],
+ size_t *length, int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct peer *peer;
+ struct ipaddr addr = {};
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method) ==
+ MATCH_FAILED)
+ return NULL;
+
+ peer = bgpv2PeerTable_lookup(v, name, length, exact, &addr);
+ if (!peer)
+ return NULL;
+
+ switch (v->magic) {
+ case BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->notify.code);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->notify.subcode);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->resettime);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) {
+ struct bgp_notify notify = peer->notify;
+ char msg_buf[255];
+ const char *msg_str = NULL;
+
+ if (notify.code == BGP_NOTIFY_CEASE &&
+ (notify.subcode ==
+ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN ||
+ notify.subcode == BGP_NOTIFY_CEASE_ADMIN_RESET)) {
+ msg_str = bgp_notify_admin_message(
+ msg_buf, sizeof(msg_buf),
+ (uint8_t *)notify.data, notify.length);
+ return SNMP_STRING(msg_str);
+ }
+ }
+ return SNMP_STRING("");
+ case BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_STRING(peer->notify.data);
+ else
+ return SNMP_STRING("");
+ case BGP4V2_PEER_LAST_ERROR_CODE_SENT:
+ if (peer->last_reset != PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->notify.code);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT:
+ if (peer->last_reset != PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->notify.subcode);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_SENT_TIME:
+ if (peer->last_reset != PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->resettime);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_SENT_TEXT:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_SEND ||
+ peer->last_reset == PEER_DOWN_RTT_SHUTDOWN ||
+ peer->last_reset == PEER_DOWN_USER_SHUTDOWN) {
+ struct bgp_notify notify = peer->notify;
+ char msg_buf[255];
+ const char *msg_str = NULL;
+
+ if (notify.code == BGP_NOTIFY_CEASE &&
+ (notify.subcode ==
+ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN ||
+ notify.subcode == BGP_NOTIFY_CEASE_ADMIN_RESET)) {
+ msg_str = bgp_notify_admin_message(
+ msg_buf, sizeof(msg_buf),
+ (uint8_t *)notify.data, notify.length);
+ return SNMP_STRING(msg_str);
+ }
+ }
+ return SNMP_STRING("");
+ case BGP4V2_PEER_LAST_ERROR_SENT_DATA:
+ if ((peer->last_reset == PEER_DOWN_NOTIFY_SEND ||
+ peer->last_reset == PEER_DOWN_RTT_SHUTDOWN ||
+ peer->last_reset == PEER_DOWN_USER_SHUTDOWN) &&
+ peer->notify.data)
+ return SNMP_STRING(peer->notify.data);
+ else
+ return SNMP_STRING("");
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *bgpv2PeerEventTimesTable(struct variable *v, oid name[],
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct peer *peer;
+ struct ipaddr addr = {};
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method) ==
+ MATCH_FAILED)
+ return NULL;
+
+ peer = bgpv2PeerTable_lookup(v, name, length, exact, &addr);
+ if (!peer)
+ return NULL;
+
+ switch (v->magic) {
+ case BGP4V2_PEER_FSM_ESTABLISHED_TIME:
+ if (!peer->uptime)
+ return SNMP_INTEGER(0);
+ else
+ return SNMP_INTEGER(monotime(NULL) - peer->uptime);
+ case BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME:
+ if (!peer->update_time)
+ return SNMP_INTEGER(0);
+ else
+ return SNMP_INTEGER(monotime(NULL) - peer->update_time);
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static struct bgp_path_info *
+bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
+ struct bgp *bgp, struct prefix *addr, int exact)
+{
+ oid *offset;
+ int offsetlen;
+ struct bgp_path_info *path, *min;
+ struct bgp_dest *dest;
+ union sockunion su;
+ unsigned int len;
+ struct ipaddr paddr = {};
+ size_t namelen = v ? v->namelen : BGP4V2_NLRI_ENTRY_OFFSET;
+ sa_family_t family = name[namelen - 1] == 4 ? AF_INET : AF_INET6;
+ afi_t afi = AFI_IP;
+ size_t afi_len = IN_ADDR_SIZE;
+
+ if (family == AF_INET6) {
+ afi = AFI_IP6;
+ afi_len = IN6_ADDR_SIZE;
+ }
+
+#define BGP_NLRI_ENTRY_OFFSET (afi_len + 1 + afi_len)
+
+ sockunion_init(&su);
+
+ if (exact) {
+ if (*length - namelen != BGP_NLRI_ENTRY_OFFSET)
+ return NULL;
+
+ /* Set OID offset for prefix */
+ offset = name + namelen;
+ if (family == AF_INET)
+ oid2in_addr(offset, afi_len, &addr->u.prefix4);
+ else
+ oid2in6_addr(offset, &addr->u.prefix6);
+ offset += afi_len;
+
+ /* Prefix length */
+ addr->prefixlen = *offset;
+ addr->family = family;
+ offset++;
+
+ /* Peer address */
+ su.sin.sin_family = family;
+ if (family == AF_INET)
+ oid2in_addr(offset, afi_len, &su.sin.sin_addr);
+ else
+ oid2in6_addr(offset, &su.sin6.sin6_addr);
+
+ /* Lookup node */
+ dest = bgp_node_lookup(bgp->rib[afi][SAFI_UNICAST], addr);
+ if (dest) {
+ for (path = bgp_dest_get_bgp_path_info(dest); path;
+ path = path->next)
+ if (sockunion_same(&path->peer->su, &su))
+ return path;
+
+ bgp_dest_unlock_node(dest);
+ }
+
+ return NULL;
+ }
+
+ offset = name + namelen;
+ offsetlen = *length - namelen;
+ len = offsetlen;
+
+ if (offsetlen == 0) {
+ dest = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]);
+ } else {
+ if (len > afi_len)
+ len = afi_len;
+
+ if (family == AF_INET)
+ oid2in_addr(offset, len, &addr->u.prefix4);
+ else
+ oid2in6_addr(offset, &addr->u.prefix6);
+
+ offset += afi_len;
+ offsetlen -= afi_len;
+
+ if (offsetlen > 0)
+ addr->prefixlen = *offset;
+ else
+ addr->prefixlen = len * 8;
+
+ addr->family = family;
+
+ dest = bgp_node_get(bgp->rib[afi][SAFI_UNICAST], addr);
+
+ offset++;
+ offsetlen--;
+ }
+
+ if (offsetlen > 0) {
+ len = offsetlen;
+ if (len > afi_len)
+ len = afi_len;
+
+ if (family == AF_INET)
+ oid2in_addr(offset, len, &paddr.ip._v4_addr);
+ else
+ oid2in6_addr(offset, &paddr.ip._v6_addr);
+ } else {
+ if (family == AF_INET)
+ memset(&paddr.ip._v4_addr, 0, afi_len);
+ else
+ memset(&paddr.ip._v6_addr, 0, afi_len);
+ }
+
+ if (!dest)
+ return NULL;
+
+ do {
+ min = NULL;
+
+ for (path = bgp_dest_get_bgp_path_info(dest); path;
+ path = path->next) {
+ sa_family_t path_family =
+ sockunion_family(&path->peer->su);
+
+ if (path_family == AF_INET &&
+ IPV4_ADDR_CMP(&paddr.ip._v4_addr,
+ &path->peer->su.sin.sin_addr) < 0) {
+ if (!min ||
+ (min &&
+ IPV4_ADDR_CMP(
+ &path->peer->su.sin.sin_addr,
+ &min->peer->su.sin.sin_addr) < 0))
+ min = path;
+ } else if (path_family == AF_INET6 &&
+ IPV6_ADDR_CMP(
+ &paddr.ip._v6_addr,
+ &path->peer->su.sin6.sin6_addr) <
+ 0) {
+ if (!min ||
+ (min &&
+ IPV6_ADDR_CMP(
+ &path->peer->su.sin6.sin6_addr,
+ &min->peer->su.sin6.sin6_addr) <
+ 0))
+ min = path;
+ }
+ }
+
+ if (min) {
+ const struct prefix *rn_p = bgp_dest_get_prefix(dest);
+
+ *length = namelen + BGP_NLRI_ENTRY_OFFSET;
+
+ offset = name + namelen;
+
+ /* Encode prefix into OID */
+ if (family == AF_INET)
+ oid_copy_in_addr(offset, &rn_p->u.prefix4);
+ else
+ oid_copy_in6_addr(offset, &rn_p->u.prefix6);
+
+ offset += afi_len;
+ *offset = rn_p->prefixlen;
+ offset++;
+
+ /* Encode peer's IP into OID */
+ if (family == AF_INET) {
+ oid_copy_in_addr(offset,
+ &min->peer->su.sin.sin_addr);
+ addr->u.prefix4 = rn_p->u.prefix4;
+ } else {
+ oid_copy_in6_addr(
+ offset, &min->peer->su.sin6.sin6_addr);
+ addr->u.prefix6 = rn_p->u.prefix6;
+ }
+
+ addr->prefixlen = rn_p->prefixlen;
+ addr->family = rn_p->family;
+
+ bgp_dest_unlock_node(dest);
+
+ return min;
+ }
+
+ if (family == AF_INET)
+ memset(&paddr.ip._v4_addr, 0, afi_len);
+ else
+ memset(&paddr.ip._v6_addr, 0, afi_len);
+ } while ((dest = bgp_route_next(dest)));
+
+ return NULL;
+}
+
+static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
+ size_t *length, int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct bgp *bgp;
+ struct bgp_path_info *path;
+ struct peer_af *paf = NULL;
+ struct prefix addr = {};
+ const struct prefix *prefix = NULL;
+ enum bgp_af_index index;
+
+ bgp = bgp_get_default();
+ if (!bgp)
+ return NULL;
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method) ==
+ MATCH_FAILED)
+ return NULL;
+
+ path = bgp4v2PathAttrLookup(v, name, length, bgp, &addr, exact);
+ if (!path)
+ return NULL;
+
+ prefix = bgp_dest_get_prefix(path->net);
+
+ AF_FOREACH (index) {
+ paf = path->peer->peer_af_array[index];
+ if (paf)
+ break;
+ }
+
+ switch (v->magic) {
+ case BGP4V2_NLRI_INDEX:
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_AFI:
+ if (paf)
+ return SNMP_INTEGER(paf->afi);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_SAFI:
+ if (paf)
+ return SNMP_INTEGER(paf->safi);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_PREFIX_TYPE:
+ if (paf)
+ return SNMP_INTEGER(paf->afi);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_PREFIX:
+ if (prefix->family == AF_INET6)
+ return SNMP_IP6ADDRESS(prefix->u.prefix6);
+ else
+ return SNMP_IPADDRESS(prefix->u.prefix4);
+ case BGP4V2_NLRI_PREFIX_LEN:
+ return SNMP_INTEGER(prefix->prefixlen);
+ case BGP4V2_NLRI_BEST:
+ if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
+ return SNMP_INTEGER(1);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_CALC_LOCAL_PREF:
+ if (CHECK_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))
+ return SNMP_INTEGER(path->attr->local_pref);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_ORIGIN:
+ switch (path->attr->origin) {
+ case BGP_ORIGIN_IGP:
+ return SNMP_INTEGER(1);
+ case BGP_ORIGIN_EGP:
+ return SNMP_INTEGER(2);
+ case BGP_ORIGIN_INCOMPLETE:
+ return SNMP_INTEGER(3);
+ default:
+ return SNMP_INTEGER(0);
+ }
+ case BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE:
+ switch (path->attr->mp_nexthop_len) {
+ case BGP_ATTR_NHLEN_IPV4:
+ return SNMP_INTEGER(1);
+ case BGP_ATTR_NHLEN_IPV6_GLOBAL:
+ return SNMP_INTEGER(2);
+ case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
+ if (CHECK_FLAG(path->attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
+ return SNMP_INTEGER(2);
+ else
+ return SNMP_INTEGER(4);
+ default:
+ return SNMP_INTEGER(1);
+ }
+ case BGP4V2_NLRI_NEXT_HOP_ADDR:
+ switch (path->attr->mp_nexthop_len) {
+ case BGP_ATTR_NHLEN_IPV4:
+ return SNMP_IPADDRESS(path->attr->mp_nexthop_global_in);
+ case BGP_ATTR_NHLEN_IPV6_GLOBAL:
+ return SNMP_IP6ADDRESS(path->attr->mp_nexthop_global);
+ case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
+ if (CHECK_FLAG(path->attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
+ return SNMP_IP6ADDRESS(
+ path->attr->mp_nexthop_global);
+ else
+ return SNMP_IP6ADDRESS(
+ path->attr->mp_nexthop_local);
+ default:
+ return SNMP_IPADDRESS(path->attr->nexthop);
+ }
+ break;
+ case BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE:
+ case BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR:
+ /* Not properly defined in specification what should be here. */
+ break;
+ case BGP4V2_NLRI_LOCAL_PREF_PRESENT:
+ if (CHECK_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))
+ return SNMP_INTEGER(1);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_LOCAL_PREF:
+ if (CHECK_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))
+ return SNMP_INTEGER(path->attr->local_pref);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_MED_PRESENT:
+ if (CHECK_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)))
+ return SNMP_INTEGER(1);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_MED:
+ if (CHECK_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)))
+ return SNMP_INTEGER(path->attr->med);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_ATOMIC_AGGREGATE:
+ if (CHECK_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)))
+ return SNMP_INTEGER(1);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_AGGREGATOR_PRESENT:
+ if (CHECK_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)))
+ return SNMP_INTEGER(1);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_AGGREGATOR_AS:
+ if (CHECK_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)))
+ return SNMP_INTEGER(path->attr->aggregator_as);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_NLRI_AGGREGATOR_ADDR:
+ if (CHECK_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)))
+ return SNMP_IPADDRESS(path->attr->aggregator_addr);
+ else
+ return SNMP_IPADDRESS(bgp_empty_addr);
+ case BGP4V2_NLRI_AS_PATH_CALC_LENGTH:
+ return SNMP_INTEGER(path->attr->aspath->segments->length);
+ case BGP4V2_NLRI_AS_PATH:
+ return aspath_snmp_pathseg(path->attr->aspath, var_len);
+ case BGP4V2_NLRI_PATH_ATTR_UNKNOWN:
+ *var_len = 0;
+ return NULL;
+ }
+ return NULL;
+}
+
+static struct variable bgpv2_variables[] = {
+ /* bgp4V2PeerEntry */
+ {BGP4V2_PEER_INSTANCE,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_INSTANCE, 1, 4}},
+ {BGP4V2_PEER_INSTANCE,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_INSTANCE, 2, 16}},
+ {BGP4V2_PEER_LOCAL_ADDR_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR_TYPE, 1, 4}},
+ {BGP4V2_PEER_LOCAL_ADDR_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR_TYPE, 2, 16}},
+ {BGP4V2_PEER_LOCAL_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR, 1, 4}},
+ {BGP4V2_PEER_LOCAL_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_ADDR, 2, 16}},
+ {BGP4V2_PEER_REMOTE_ADDR_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR_TYPE, 1, 4}},
+ {BGP4V2_PEER_REMOTE_ADDR_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR_TYPE, 2, 16}},
+ {BGP4V2_PEER_REMOTE_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR, 1, 4}},
+ {BGP4V2_PEER_REMOTE_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_ADDR, 2, 16}},
+ {BGP4V2_PEER_LOCAL_PORT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 4}},
+ {BGP4V2_PEER_LOCAL_PORT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 2, 16}},
+ {BGP4V2_PEER_LOCAL_AS,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_AS, 1, 4}},
+ {BGP4V2_PEER_LOCAL_AS,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_AS, 2, 16}},
+ {BGP4V2_PEER_LOCAL_IDENTIFIER,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_IDENTIFIER, 1, 4}},
+ {BGP4V2_PEER_LOCAL_IDENTIFIER,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_LOCAL_IDENTIFIER, 2, 16}},
+ {BGP4V2_PEER_REMOTE_PORT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 4}},
+ {BGP4V2_PEER_REMOTE_PORT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 2, 16}},
+ {BGP4V2_PEER_REMOTE_AS,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_AS, 1, 4}},
+ {BGP4V2_PEER_REMOTE_AS,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_AS, 2, 16}},
+ {BGP4V2_PEER_REMOTE_IDENTIFIER,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_IDENTIFIER, 1, 4}},
+ {BGP4V2_PEER_REMOTE_IDENTIFIER,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_REMOTE_IDENTIFIER, 2, 16}},
+ {BGP4V2_PEER_ADMIN_STATUS,
+ ASN_INTEGER,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_ADMIN_STATUS, 1, 4}},
+ {BGP4V2_PEER_ADMIN_STATUS,
+ ASN_INTEGER,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_ADMIN_STATUS, 2, 16}},
+ {BGP4V2_PEER_STATE,
+ ASN_INTEGER,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_STATE, 1, 4}},
+ {BGP4V2_PEER_STATE,
+ ASN_INTEGER,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_STATE, 2, 16}},
+ {BGP4V2_PEER_DESCRIPTION,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_DESCRIPTION, 1, 4}},
+ {BGP4V2_PEER_DESCRIPTION,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerTable,
+ 6,
+ {1, 2, 1, BGP4V2_PEER_DESCRIPTION, 2, 16}},
+ /* bgp4V2PeerErrorsEntry */
+ {BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_CODE_SENT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_CODE_SENT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_TEXT,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_TEXT,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_DATA,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_DATA,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 2, 16}},
+ /* bgp4V2PeerEventTimesEntry */
+ {BGP4V2_PEER_FSM_ESTABLISHED_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerEventTimesTable,
+ 6,
+ {1, 4, 1, BGP4V2_PEER_FSM_ESTABLISHED_TIME, 1, 4}},
+ {BGP4V2_PEER_FSM_ESTABLISHED_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerEventTimesTable,
+ 6,
+ {1, 4, 1, BGP4V2_PEER_FSM_ESTABLISHED_TIME, 2, 16}},
+ {BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerEventTimesTable,
+ 6,
+ {1, 4, 1, BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME, 1, 4}},
+ {BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerEventTimesTable,
+ 6,
+ {1, 4, 1, BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME, 2, 16}},
+ /* bgp4V2NlriTable */
+ {BGP4V2_NLRI_INDEX,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_INDEX, 1, 4}},
+ {BGP4V2_NLRI_INDEX,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_INDEX, 2, 16}},
+ {BGP4V2_NLRI_AFI,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AFI, 1, 4}},
+ {BGP4V2_NLRI_AFI,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AFI, 2, 16}},
+ {BGP4V2_NLRI_SAFI,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_SAFI, 1, 4}},
+ {BGP4V2_NLRI_SAFI,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_SAFI, 2, 16}},
+ {BGP4V2_NLRI_PREFIX_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_PREFIX_TYPE, 1, 4}},
+ {BGP4V2_NLRI_PREFIX_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_PREFIX_TYPE, 2, 16}},
+ {BGP4V2_NLRI_PREFIX,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_PREFIX, 1, 4}},
+ {BGP4V2_NLRI_PREFIX,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_PREFIX, 2, 16}},
+ {BGP4V2_NLRI_PREFIX_LEN,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_PREFIX_LEN, 1, 4}},
+ {BGP4V2_NLRI_PREFIX_LEN,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_PREFIX_LEN, 2, 16}},
+ {BGP4V2_NLRI_BEST,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_BEST, 1, 4}},
+ {BGP4V2_NLRI_BEST,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_BEST, 2, 16}},
+ {BGP4V2_NLRI_CALC_LOCAL_PREF,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_CALC_LOCAL_PREF, 1, 4}},
+ {BGP4V2_NLRI_CALC_LOCAL_PREF,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_CALC_LOCAL_PREF, 2, 16}},
+ {BGP4V2_NLRI_ORIGIN,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_ORIGIN, 1, 4}},
+ {BGP4V2_NLRI_ORIGIN,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_ORIGIN, 2, 16}},
+ {BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE, 1, 4}},
+ {BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE, 2, 16}},
+ {BGP4V2_NLRI_NEXT_HOP_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR, 1, 4}},
+ {BGP4V2_NLRI_NEXT_HOP_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_NEXT_HOP_ADDR, 2, 16}},
+ {BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE, 1, 4}},
+ {BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE, 2, 16}},
+ {BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR, 1, 4}},
+ {BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR, 2, 16}},
+ {BGP4V2_NLRI_LOCAL_PREF_PRESENT,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF_PRESENT, 1, 4}},
+ {BGP4V2_NLRI_LOCAL_PREF_PRESENT,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF_PRESENT, 2, 16}},
+ {BGP4V2_NLRI_LOCAL_PREF,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF, 1, 4}},
+ {BGP4V2_NLRI_LOCAL_PREF,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_LOCAL_PREF, 2, 16}},
+ {BGP4V2_NLRI_MED_PRESENT,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_MED_PRESENT, 1, 4}},
+ {BGP4V2_NLRI_MED_PRESENT,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_MED_PRESENT, 2, 16}},
+ {BGP4V2_NLRI_MED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_MED, 1, 4}},
+ {BGP4V2_NLRI_MED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_MED, 2, 16}},
+ {BGP4V2_NLRI_ATOMIC_AGGREGATE,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_ATOMIC_AGGREGATE, 1, 4}},
+ {BGP4V2_NLRI_ATOMIC_AGGREGATE,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_ATOMIC_AGGREGATE, 2, 16}},
+ {BGP4V2_NLRI_AGGREGATOR_PRESENT,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_PRESENT, 1, 4}},
+ {BGP4V2_NLRI_AGGREGATOR_PRESENT,
+ ASN_INTEGER,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_PRESENT, 2, 16}},
+ {BGP4V2_NLRI_AGGREGATOR_AS,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_AS, 1, 4}},
+ {BGP4V2_NLRI_AGGREGATOR_AS,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_AS, 2, 16}},
+ {BGP4V2_NLRI_AGGREGATOR_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_ADDR, 1, 4}},
+ {BGP4V2_NLRI_AGGREGATOR_ADDR,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AGGREGATOR_ADDR, 2, 16}},
+ {BGP4V2_NLRI_AS_PATH_CALC_LENGTH,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AS_PATH_CALC_LENGTH, 1, 4}},
+ {BGP4V2_NLRI_AS_PATH_CALC_LENGTH,
+ ASN_UNSIGNED,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AS_PATH_CALC_LENGTH, 2, 16}},
+ {BGP4V2_NLRI_AS_PATH_STRING,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AS_PATH_STRING, 1, 4}},
+ {BGP4V2_NLRI_AS_PATH_STRING,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AS_PATH_STRING, 2, 16}},
+ {BGP4V2_NLRI_AS_PATH,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AS_PATH, 1, 4}},
+ {BGP4V2_NLRI_AS_PATH,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_AS_PATH, 2, 16}},
+ {BGP4V2_NLRI_PATH_ATTR_UNKNOWN,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_PATH_ATTR_UNKNOWN, 1, 4}},
+ {BGP4V2_NLRI_PATH_ATTR_UNKNOWN,
+ ASN_OCTET_STR,
+ RONLY,
+ bgp4v2PathAttrTable,
+ 6,
+ {1, 9, 1, BGP4V2_NLRI_PATH_ATTR_UNKNOWN, 2, 16}},
+};
+
+int bgp_snmp_bgp4v2_init(struct thread_master *tm)
+{
+ REGISTER_MIB("mibII/bgpv2", bgpv2_variables, variable, bgpv2_oid);
+ return 0;
+}
diff --git a/bgpd/bgp_snmp_bgp4v2.h b/bgpd/bgp_snmp_bgp4v2.h
new file mode 100644
index 0000000000..8b474c3887
--- /dev/null
+++ b/bgpd/bgp_snmp_bgp4v2.h
@@ -0,0 +1,100 @@
+/* BGP4V2-MIB SNMP support
+ *
+ * Using: http://www.circitor.fr/Mibs/Html/B/BGP4V2-MIB.php
+ *
+ * Copyright (C) 2022 Donatas Abraitis <donatas@opensourcerouting.org>
+ *
+ * This file is part of FRRouting (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_BGP_SNMP_BGP4V2_H_
+#define _FRR_BGP_SNMP_BGP4V2_H_
+
+/* bgp4V2 */
+#define BGP4V2MIB 1, 3, 6, 1, 3, 5, 1
+
+/* bgp4V2PeerEntry:
+ * offset 1.3.6.1.3.5.1.1.2.1.x.(1|2).(4|16) = 13
+ */
+#define BGP4V2_PEER_ENTRY_OFFSET 13
+#define BGP4V2_PEER_INSTANCE 1
+#define BGP4V2_PEER_LOCAL_ADDR_TYPE 2
+#define BGP4V2_PEER_LOCAL_ADDR 3
+#define BGP4V2_PEER_REMOTE_ADDR_TYPE 4
+#define BGP4V2_PEER_REMOTE_ADDR 5
+#define BGP4V2_PEER_LOCAL_PORT 6
+#define BGP4V2_PEER_LOCAL_AS 7
+#define BGP4V2_PEER_LOCAL_IDENTIFIER 8
+#define BGP4V2_PEER_REMOTE_PORT 9
+#define BGP4V2_PEER_REMOTE_AS 10
+#define BGP4V2_PEER_REMOTE_IDENTIFIER 11
+#define BGP4V2_PEER_ADMIN_STATUS 12
+#define BGP4V2_PEER_STATE 13
+#define BGP4V2_PEER_DESCRIPTION 14
+
+/* bgp4V2PeerErrorsEntry */
+#define BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED 1
+#define BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED 2
+#define BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME 3
+#define BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT 4
+#define BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA 5
+#define BGP4V2_PEER_LAST_ERROR_CODE_SENT 6
+#define BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT 7
+#define BGP4V2_PEER_LAST_ERROR_SENT_TIME 8
+#define BGP4V2_PEER_LAST_ERROR_SENT_TEXT 9
+#define BGP4V2_PEER_LAST_ERROR_SENT_DATA 10
+
+/* bgp4V2PeerEventTimesEntry */
+#define BGP4V2_PEER_FSM_ESTABLISHED_TIME 1
+#define BGP4V2_PEER_PEER_IN_UPDATES_ELAPSED_TIME 2
+
+/* bgp4V2NlriEntry
+ * offset 1.3.6.1.3.5.1.1.9.1.x.(1|2).(4|16) = 13
+ */
+#define BGP4V2_NLRI_ENTRY_OFFSET 13
+#define BGP4V2_NLRI_INDEX 1
+#define BGP4V2_NLRI_AFI 2
+#define BGP4V2_NLRI_SAFI 3
+#define BGP4V2_NLRI_PREFIX_TYPE 4
+#define BGP4V2_NLRI_PREFIX 5
+#define BGP4V2_NLRI_PREFIX_LEN 6
+#define BGP4V2_NLRI_BEST 7
+#define BGP4V2_NLRI_CALC_LOCAL_PREF 8
+#define BGP4V2_NLRI_ORIGIN 9
+#define BGP4V2_NLRI_NEXT_HOP_ADDR_TYPE 10
+#define BGP4V2_NLRI_NEXT_HOP_ADDR 11
+#define BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR_TYPE 12
+#define BGP4V2_NLRI_LINK_LOCAL_NEXT_HOP_ADDR 13
+#define BGP4V2_NLRI_LOCAL_PREF_PRESENT 14
+#define BGP4V2_NLRI_LOCAL_PREF 15
+#define BGP4V2_NLRI_MED_PRESENT 16
+#define BGP4V2_NLRI_MED 17
+#define BGP4V2_NLRI_ATOMIC_AGGREGATE 18
+#define BGP4V2_NLRI_AGGREGATOR_PRESENT 19
+#define BGP4V2_NLRI_AGGREGATOR_AS 20
+#define BGP4V2_NLRI_AGGREGATOR_ADDR 21
+#define BGP4V2_NLRI_AS_PATH_CALC_LENGTH 22
+#define BGP4V2_NLRI_AS_PATH_STRING 23
+#define BGP4V2_NLRI_AS_PATH 24
+#define BGP4V2_NLRI_PATH_ATTR_UNKNOWN 25
+
+/* bgp4V2Notifications */
+#define BGP4V2_ESTABLISHED_NOTIFICATION 1
+#define BGP4V2_BACKWARD_TRANSITION_NOTIFICATION 2
+
+extern int bgp_snmp_bgp4v2_init(struct thread_master *tm);
+
+#endif /* _FRR_BGP_SNMP_BGP4V2_H_ */
diff --git a/bgpd/bgp_trace.h b/bgpd/bgp_trace.h
index 14149b5139..7cc8f24e06 100644
--- a/bgpd/bgp_trace.h
+++ b/bgpd/bgp_trace.h
@@ -247,6 +247,71 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_LOGLEVEL(frr_bgp, bgp_dest_unlock, TRACE_INFO)
+/*
+ * peer_lock/peer_unlock
+ */
+TRACEPOINT_EVENT(
+ frr_bgp,
+ bgp_peer_lock,
+ TP_ARGS(struct peer *, peer,
+ const char *, name),
+ TP_FIELDS(
+ ctf_string(caller, name)
+ ctf_string(peer, PEER_HOSTNAME(peer))
+ ctf_integer(unsigned int, count, peer->lock)
+ )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, bgp_peer_lock, TRACE_INFO)
+
+TRACEPOINT_EVENT(
+ frr_bgp,
+ bgp_peer_unlock,
+ TP_ARGS(struct peer *, peer,
+ const char *, name),
+ TP_FIELDS(
+ ctf_string(caller, name)
+ ctf_string(peer, PEER_HOSTNAME(peer))
+ ctf_integer(unsigned int, count, peer->lock)
+ )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, bgp_peer_unlock, TRACE_INFO)
+
+/*
+ * bgp_path_info_add/bgp_path_info_free
+ */
+TRACEPOINT_EVENT(
+ frr_bgp,
+ bgp_path_info_add,
+ TP_ARGS(struct bgp_dest *, dest,
+ struct bgp_path_info *, bpi,
+ const char *, name),
+ TP_FIELDS(
+ ctf_string(caller, name)
+ ctf_string(prefix, bgp_dest_get_prefix_str(dest))
+ ctf_string(peer, PEER_HOSTNAME(bpi->peer))
+ ctf_integer(unsigned int, dest_lock,
+ bgp_dest_get_lock_count(dest))
+ ctf_integer(unsigned int, peer_lock, bpi->peer->lock)
+ )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, bgp_path_info_add, TRACE_INFO)
+
+TRACEPOINT_EVENT(
+ frr_bgp,
+ bgp_path_info_free,
+ TP_ARGS(struct bgp_path_info *, bpi,
+ const char *, name),
+ TP_FIELDS(
+ ctf_string(caller, name)
+ ctf_string(prefix, bgp_dest_get_prefix_str(bpi->net))
+ ctf_string(peer, PEER_HOSTNAME(bpi->peer))
+ ctf_integer(unsigned int, dest_lock,
+ bgp_dest_get_lock_count(bpi->net))
+ ctf_integer(unsigned int, peer_lock, bpi->peer->lock)
+ )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, bgp_path_info_free, TRACE_INFO)
+
TRACEPOINT_EVENT(
frr_bgp,
evpn_mac_ip_zsend,
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index 9d550fd19b..afd2107b48 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -677,6 +677,15 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
struct bgp_filter *filter;
struct peer *peer = UPDGRP_PEER(updgrp);
int match = 0;
+ json_object *json_updgrp = NULL;
+ json_object *json_subgrps = NULL;
+ json_object *json_subgrp = NULL;
+ json_object *json_time = NULL;
+ json_object *json_subgrp_time = NULL;
+ json_object *json_subgrp_event = NULL;
+ json_object *json_peers = NULL;
+ json_object *json_pkt_info = NULL;
+ time_t epoch_tbuf, tbuf;
if (!ctx)
return CMD_SUCCESS;
@@ -703,79 +712,233 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
vty = ctx->vty;
- vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id);
- vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime));
+ if (ctx->uj) {
+ json_updgrp = json_object_new_object();
+ /* Display json o/p */
+ tbuf = monotime(NULL);
+ tbuf -= updgrp->uptime;
+ epoch_tbuf = time(NULL) - tbuf;
+ json_time = json_object_new_object();
+ json_object_int_add(json_time, "epoch", epoch_tbuf);
+ json_object_string_add(json_time, "epochString",
+ ctime(&epoch_tbuf));
+ json_object_object_add(json_updgrp, "groupCreateTime",
+ json_time);
+ json_object_string_add(json_updgrp, "afi",
+ afi2str(updgrp->afi));
+ json_object_string_add(json_updgrp, "safi",
+ safi2str(updgrp->safi));
+ } else {
+ vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id);
+ vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime));
+ }
+
filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi];
- if (filter->map[RMAP_OUT].name)
- vty_out(vty, " Outgoing route map: %s\n",
- filter->map[RMAP_OUT].name);
- vty_out(vty, " MRAI value (seconds): %d\n", updgrp->conf->v_routeadv);
- if (updgrp->conf->change_local_as)
- vty_out(vty, " Local AS %u%s%s\n",
- updgrp->conf->change_local_as,
- CHECK_FLAG(updgrp->conf->flags,
- PEER_FLAG_LOCAL_AS_NO_PREPEND)
- ? " no-prepend"
- : "",
- CHECK_FLAG(updgrp->conf->flags,
- PEER_FLAG_LOCAL_AS_REPLACE_AS)
- ? " replace-as"
- : "");
+ if (filter->map[RMAP_OUT].name) {
+ if (ctx->uj)
+ json_object_string_add(json_updgrp, "outRouteMap",
+ filter->map[RMAP_OUT].name);
+ else
+ vty_out(vty, " Outgoing route map: %s\n",
+ filter->map[RMAP_OUT].name);
+ }
+ if (ctx->uj)
+ json_object_int_add(json_updgrp, "minRouteAdvInt",
+ updgrp->conf->v_routeadv);
+ else
+ vty_out(vty, " MRAI value (seconds): %d\n",
+ updgrp->conf->v_routeadv);
+
+ if (updgrp->conf->change_local_as) {
+ if (ctx->uj) {
+ json_object_int_add(json_updgrp, "localAs",
+ updgrp->conf->change_local_as);
+ json_object_boolean_add(
+ json_updgrp, "noPrepend",
+ CHECK_FLAG(updgrp->conf->flags,
+ PEER_FLAG_LOCAL_AS_NO_PREPEND));
+ json_object_boolean_add(
+ json_updgrp, "replaceLocalAs",
+ CHECK_FLAG(updgrp->conf->flags,
+ PEER_FLAG_LOCAL_AS_REPLACE_AS));
+ } else {
+ vty_out(vty, " Local AS %u%s%s\n",
+ updgrp->conf->change_local_as,
+ CHECK_FLAG(updgrp->conf->flags,
+ PEER_FLAG_LOCAL_AS_NO_PREPEND)
+ ? " no-prepend"
+ : "",
+ CHECK_FLAG(updgrp->conf->flags,
+ PEER_FLAG_LOCAL_AS_REPLACE_AS)
+ ? " replace-as"
+ : "");
+ }
+ }
+ if (ctx->uj)
+ json_subgrps = json_object_new_array();
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
continue;
- vty_out(vty, "\n");
- vty_out(vty, " Update-subgroup %" PRIu64 ":\n", subgrp->id);
- vty_out(vty, " Created: %s",
- timestamp_string(subgrp->uptime));
+ if (ctx->uj) {
+ json_subgrp = json_object_new_object();
+ json_object_int_add(json_subgrp, "subGroupId",
+ subgrp->id);
+ tbuf = monotime(NULL);
+ tbuf -= subgrp->uptime;
+ epoch_tbuf = time(NULL) - tbuf;
+ json_subgrp_time = json_object_new_object();
+ json_object_int_add(json_subgrp_time, "epoch",
+ epoch_tbuf);
+ json_object_string_add(json_subgrp_time, "epochString",
+ ctime(&epoch_tbuf));
+ json_object_object_add(json_subgrp, "groupCreateTime",
+ json_subgrp_time);
+ } else {
+ vty_out(vty, "\n");
+ vty_out(vty, " Update-subgroup %" PRIu64 ":\n",
+ subgrp->id);
+ vty_out(vty, " Created: %s",
+ timestamp_string(subgrp->uptime));
+ }
if (subgrp->split_from.update_group_id
|| subgrp->split_from.subgroup_id) {
- vty_out(vty, " Split from group id: %" PRIu64 "\n",
- subgrp->split_from.update_group_id);
- vty_out(vty,
- " Split from subgroup id: %" PRIu64 "\n",
- subgrp->split_from.subgroup_id);
+ if (ctx->uj) {
+ json_object_int_add(
+ json_subgrp, "splitGroupId",
+ subgrp->split_from.update_group_id);
+ json_object_int_add(
+ json_subgrp, "splitSubGroupId",
+ subgrp->split_from.subgroup_id);
+ } else {
+ vty_out(vty,
+ " Split from group id: %" PRIu64
+ "\n",
+ subgrp->split_from.update_group_id);
+ vty_out(vty,
+ " Split from subgroup id: %" PRIu64
+ "\n",
+ subgrp->split_from.subgroup_id);
+ }
}
- vty_out(vty, " Join events: %u\n", subgrp->join_events);
- vty_out(vty, " Prune events: %u\n", subgrp->prune_events);
- vty_out(vty, " Merge events: %u\n", subgrp->merge_events);
- vty_out(vty, " Split events: %u\n", subgrp->split_events);
- vty_out(vty, " Update group switch events: %u\n",
- subgrp->updgrp_switch_events);
- vty_out(vty, " Peer refreshes combined: %u\n",
- subgrp->peer_refreshes_combined);
- vty_out(vty, " Merge checks triggered: %u\n",
- subgrp->merge_checks_triggered);
- vty_out(vty, " Coalesce Time: %u%s\n",
- (UPDGRP_INST(subgrp->update_group))->coalesce_time,
- subgrp->t_coalesce ? "(Running)" : "");
- vty_out(vty, " Version: %" PRIu64 "\n", subgrp->version);
- vty_out(vty, " Packet queue length: %d\n",
- bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
- vty_out(vty, " Total packets enqueued: %u\n",
- subgroup_total_packets_enqueued(subgrp));
- vty_out(vty, " Packet queue high watermark: %d\n",
- bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
- vty_out(vty, " Adj-out list count: %u\n", subgrp->adj_count);
- vty_out(vty, " Advertise list: %s\n",
- advertise_list_is_empty(subgrp) ? "empty"
- : "not empty");
- vty_out(vty, " Flags: %s\n",
- CHECK_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH)
- ? "R"
- : "");
- if (peer)
- vty_out(vty, " Max packet size: %d\n",
- peer->max_packet_size);
+ if (ctx->uj) {
+ json_subgrp_event = json_object_new_object();
+ json_object_int_add(json_subgrp_event, "joinEvents",
+ subgrp->join_events);
+ json_object_int_add(json_subgrp_event, "pruneEvents",
+ subgrp->prune_events);
+ json_object_int_add(json_subgrp_event, "mergeEvents",
+ subgrp->merge_events);
+ json_object_int_add(json_subgrp_event, "splitEvents",
+ subgrp->split_events);
+ json_object_int_add(json_subgrp_event, "switchEvents",
+ subgrp->updgrp_switch_events);
+ json_object_int_add(json_subgrp_event,
+ "peerRefreshEvents",
+ subgrp->peer_refreshes_combined);
+ json_object_int_add(json_subgrp_event,
+ "mergeCheckEvents",
+ subgrp->merge_checks_triggered);
+ json_object_object_add(json_subgrp, "statistics",
+ json_subgrp_event);
+ json_object_int_add(json_subgrp, "coalesceTime",
+ (UPDGRP_INST(subgrp->update_group))
+ ->coalesce_time);
+ json_object_int_add(json_subgrp, "version",
+ subgrp->version);
+ json_pkt_info = json_object_new_object();
+ json_object_int_add(
+ json_pkt_info, "qeueueLen",
+ bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
+ json_object_int_add(
+ json_pkt_info, "queuedTotal",
+ subgroup_total_packets_enqueued(subgrp));
+ json_object_int_add(
+ json_pkt_info, "queueHwmLen",
+ bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
+ json_object_int_add(
+ json_pkt_info, "totalEnqueued",
+ subgroup_total_packets_enqueued(subgrp));
+ json_object_object_add(json_subgrp, "packetQueueInfo",
+ json_pkt_info);
+ json_object_int_add(json_subgrp, "adjListCount",
+ subgrp->adj_count);
+ json_object_boolean_add(
+ json_subgrp, "needsRefresh",
+ CHECK_FLAG(subgrp->flags,
+ SUBGRP_FLAG_NEEDS_REFRESH));
+ } else {
+ vty_out(vty, " Join events: %u\n",
+ subgrp->join_events);
+ vty_out(vty, " Prune events: %u\n",
+ subgrp->prune_events);
+ vty_out(vty, " Merge events: %u\n",
+ subgrp->merge_events);
+ vty_out(vty, " Split events: %u\n",
+ subgrp->split_events);
+ vty_out(vty, " Update group switch events: %u\n",
+ subgrp->updgrp_switch_events);
+ vty_out(vty, " Peer refreshes combined: %u\n",
+ subgrp->peer_refreshes_combined);
+ vty_out(vty, " Merge checks triggered: %u\n",
+ subgrp->merge_checks_triggered);
+ vty_out(vty, " Coalesce Time: %u%s\n",
+ (UPDGRP_INST(subgrp->update_group))
+ ->coalesce_time,
+ subgrp->t_coalesce ? "(Running)" : "");
+ vty_out(vty, " Version: %" PRIu64 "\n",
+ subgrp->version);
+ vty_out(vty, " Packet queue length: %d\n",
+ bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
+ vty_out(vty, " Total packets enqueued: %u\n",
+ subgroup_total_packets_enqueued(subgrp));
+ vty_out(vty, " Packet queue high watermark: %d\n",
+ bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
+ vty_out(vty, " Adj-out list count: %u\n",
+ subgrp->adj_count);
+ vty_out(vty, " Advertise list: %s\n",
+ advertise_list_is_empty(subgrp) ? "empty"
+ : "not empty");
+ vty_out(vty, " Flags: %s\n",
+ CHECK_FLAG(subgrp->flags,
+ SUBGRP_FLAG_NEEDS_REFRESH)
+ ? "R"
+ : "");
+ if (peer)
+ vty_out(vty, " Max packet size: %d\n",
+ peer->max_packet_size);
+ }
if (subgrp->peer_count > 0) {
- vty_out(vty, " Peers:\n");
- SUBGRP_FOREACH_PEER (subgrp, paf)
- vty_out(vty, " - %s\n", paf->peer->host);
+ if (ctx->uj) {
+ json_peers = json_object_new_array();
+ SUBGRP_FOREACH_PEER (subgrp, paf) {
+ json_object *peer =
+ json_object_new_string(
+ paf->peer->host);
+ json_object_array_add(json_peers, peer);
+ }
+ json_object_object_add(json_subgrp, "peers",
+ json_peers);
+ } else {
+ vty_out(vty, " Peers:\n");
+ SUBGRP_FOREACH_PEER (subgrp, paf)
+ vty_out(vty, " - %s\n",
+ paf->peer->host);
+ }
}
+
+ if (ctx->uj)
+ json_object_array_add(json_subgrps, json_subgrp);
+ }
+
+ if (ctx->uj) {
+ json_object_object_add(json_updgrp, "subGroup", json_subgrps);
+ json_object_object_addf(ctx->json_updategrps, json_updgrp,
+ "%" PRIu64, updgrp->id);
}
+
return UPDWALK_CONTINUE;
}
@@ -1708,14 +1871,34 @@ void update_bgp_group_free(struct bgp *bgp)
}
void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty,
- uint64_t subgrp_id)
+ uint64_t subgrp_id, bool uj)
{
struct updwalk_context ctx;
+ json_object *json_vrf_obj = NULL;
+
memset(&ctx, 0, sizeof(ctx));
ctx.vty = vty;
ctx.subgrp_id = subgrp_id;
+ ctx.uj = uj;
+
+ if (uj) {
+ ctx.json_updategrps = json_object_new_object();
+ json_vrf_obj = json_object_new_object();
+ }
update_group_af_walk(bgp, afi, safi, update_group_show_walkcb, &ctx);
+
+ if (uj) {
+ const char *vname;
+
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ vname = VRF_DEFAULT_NAME;
+ else
+ vname = bgp->name;
+ json_object_object_add(json_vrf_obj, vname,
+ ctx.json_updategrps);
+ vty_json(vty, json_vrf_obj);
+ }
}
/*
@@ -2048,10 +2231,18 @@ bool bgp_addpath_encode_tx(struct peer *peer, afi_t afi, safi_t safi)
PEER_CAP_ADDPATH_AF_RX_RCV));
}
+bool bgp_addpath_capable(struct bgp_path_info *bpi, struct peer *peer,
+ afi_t afi, safi_t safi)
+{
+ return (bgp_addpath_tx_path(peer->addpath_type[afi][safi], bpi) ||
+ (safi == SAFI_LABELED_UNICAST &&
+ bgp_addpath_tx_path(peer->addpath_type[afi][SAFI_UNICAST],
+ bpi)));
+}
+
bool bgp_check_selected(struct bgp_path_info *bpi, struct peer *peer,
bool addpath_capable, afi_t afi, safi_t safi)
{
return (CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) ||
- (addpath_capable &&
- bgp_addpath_tx_path(peer->addpath_type[afi][safi], bpi)));
+ (addpath_capable && bgp_addpath_capable(bpi, peer, afi, safi)));
}
diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h
index 56289d399d..e27c1e7b67 100644
--- a/bgpd/bgp_updgrp.h
+++ b/bgpd/bgp_updgrp.h
@@ -88,6 +88,8 @@ typedef struct {
#define BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED (1 << 4)
#define BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED (1 << 5)
#define BPKT_ATTRVEC_FLAGS_RMAP_IPV6_LNH_CHANGED (1 << 6)
+#define BPKT_ATTRVEC_FLAGS_RMAP_VPNV4_NH_CHANGED (1 << 7)
+#define BPKT_ATTRVEC_FLAGS_RMAP_VPNV6_GNH_CHANGED (1 << 8)
typedef struct bpacket_attr_vec_arr {
bpacket_attr_vec entries[BGP_ATTR_VEC_MAX];
@@ -302,6 +304,8 @@ struct updwalk_context {
updgrp_walkcb cb;
void *context;
uint8_t flags;
+ bool uj;
+ json_object *json_updategrps;
#define UPDWALK_FLAGS_ADVQUEUE (1 << 0)
#define UPDWALK_FLAGS_ADVERTISED (1 << 1)
@@ -363,7 +367,7 @@ extern void update_bgp_group_init(struct bgp *);
extern void udpate_bgp_group_free(struct bgp *);
extern void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi,
- struct vty *vty, uint64_t subgrp_id);
+ struct vty *vty, uint64_t subgrp_id, bool uj);
extern void update_group_show_stats(struct bgp *bgp, struct vty *vty);
extern void update_group_adjust_peer(struct peer_af *paf);
extern int update_group_adjust_soloness(struct peer *peer, int set);
@@ -472,6 +476,8 @@ extern void update_bgp_group_free(struct bgp *bgp);
extern bool bgp_addpath_encode_tx(struct peer *peer, afi_t afi, safi_t safi);
extern bool bgp_check_selected(struct bgp_path_info *bpi, struct peer *peer,
bool addpath_capable, afi_t afi, safi_t safi);
+extern bool bgp_addpath_capable(struct bgp_path_info *bpi, struct peer *peer,
+ afi_t afi, safi_t safi);
/*
* Inline functions
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 72e70ebf9f..cbd5d05922 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -655,6 +655,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
struct peer *peer;
afi_t afi;
safi_t safi;
+ safi_t safi_rib;
bool addpath_capable;
struct bgp *bgp;
bool advertise;
@@ -666,10 +667,12 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
if (safi == SAFI_LABELED_UNICAST)
- safi = SAFI_UNICAST;
+ safi_rib = SAFI_UNICAST;
+ else
+ safi_rib = safi;
if (!table)
- table = peer->bgp->rib[afi][safi];
+ table = peer->bgp->rib[afi][safi_rib];
if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP && safi != SAFI_EVPN
&& CHECK_FLAG(peer->af_flags[afi][safi],
@@ -688,7 +691,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
for (ri = bgp_dest_get_bgp_path_info(dest); ri; ri = ri->next) {
if (!bgp_check_selected(ri, peer, addpath_capable, afi,
- safi))
+ safi_rib))
continue;
if (subgroup_announce_check(dest, ri, subgrp, dest_p,
@@ -703,7 +706,8 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
bgp_adj_out_unset_subgroup(
dest, subgrp, 1,
bgp_addpath_id_for_peer(
- peer, afi, safi,
+ peer, afi,
+ safi_rib,
&ri->tx_addpath));
}
} else {
@@ -722,7 +726,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
bgp_adj_out_unset_subgroup(
dest, subgrp, 1,
bgp_addpath_id_for_peer(
- peer, afi, safi,
+ peer, afi, safi_rib,
&ri->tx_addpath));
}
}
@@ -799,6 +803,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
route_map_result_t new_ret = RMAP_DENYMATCH;
afi_t afi;
safi_t safi;
+ safi_t safi_rib;
int pref = 65536;
int new_pref = 0;
@@ -812,6 +817,11 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
if (!(afi == AFI_IP || afi == AFI_IP6))
return;
+ if (safi == SAFI_LABELED_UNICAST)
+ safi_rib = SAFI_UNICAST;
+ else
+ safi_rib = safi;
+
bgp = peer->bgp;
from = bgp->peer_self;
@@ -845,7 +855,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
* the default route. We announce the default
* route only if route-map has a match.
*/
- for (dest = bgp_table_top(bgp->rib[afi][safi]); dest;
+ for (dest = bgp_table_top(bgp->rib[afi][safi_rib]); dest;
dest = bgp_route_next(dest)) {
if (!bgp_dest_has_bgp_path_info_data(dest))
continue;
@@ -903,7 +913,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
memset(&p, 0, sizeof(p));
p.family = afi2family(afi);
p.prefixlen = 0;
- dest = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi, &p, NULL);
+ dest = bgp_afi_node_lookup(bgp->rib[afi][safi_rib], afi, safi_rib, &p,
+ NULL);
if (withdraw) {
/* Withdraw the default route advertised using default
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 9de97cf060..346a3e7806 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -379,10 +379,11 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
route_map_sets_nh =
(CHECK_FLAG(vec->flags,
- BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED)
- || CHECK_FLAG(
- vec->flags,
- BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS));
+ BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED) ||
+ CHECK_FLAG(vec->flags,
+ BPKT_ATTRVEC_FLAGS_RMAP_VPNV4_NH_CHANGED) ||
+ CHECK_FLAG(vec->flags,
+ BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS));
switch (nhlen) {
case BGP_ATTR_NHLEN_IPV4:
@@ -468,10 +469,12 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
route_map_sets_nh =
(CHECK_FLAG(vec->flags,
- BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED)
- || CHECK_FLAG(
+ BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED) ||
+ CHECK_FLAG(
vec->flags,
- BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS));
+ BPKT_ATTRVEC_FLAGS_RMAP_VPNV6_GNH_CHANGED) ||
+ CHECK_FLAG(vec->flags,
+ BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS));
/*
* The logic here is rather similar to that for IPv4, the
@@ -1069,6 +1072,9 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
safi_t safi;
struct bpacket_attr_vec_arr vecarr;
bool addpath_capable = false;
+ uint8_t default_originate_label[4] = {0x80, 0x00, 0x00};
+ mpls_label_t *label = NULL;
+ uint32_t num_labels = 0;
if (DISABLE_BGP_ANNOUNCE)
return;
@@ -1082,6 +1088,11 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
bpacket_attr_vec_arr_reset(&vecarr);
addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
+ if (safi == SAFI_LABELED_UNICAST) {
+ label = (mpls_label_t *)default_originate_label;
+ num_labels = 1;
+ }
+
memset(&p, 0, sizeof(p));
p.family = afi2family(afi);
p.prefixlen = 0;
@@ -1124,9 +1135,9 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
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, NULL,
- 0, addpath_capable, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE,
- NULL);
+ NULL, peer, s, attr, &vecarr, &p, afi, safi, from, NULL, label,
+ num_labels, addpath_capable,
+ BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL);
/* Set Total Path Attribute Length. */
stream_putw_at(s, pos, total_attr_len);
@@ -1276,6 +1287,15 @@ bpacket_vec_arr_inherit_attr_flags(struct bpacket_attr_vec_arr *vecarr,
SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED);
+ if (CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_VPNV4_NHOP_CHANGED))
+ SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
+ BPKT_ATTRVEC_FLAGS_RMAP_VPNV4_NH_CHANGED);
+
+ if (CHECK_FLAG(attr->rmap_change_flags,
+ BATTR_RMAP_VPNV6_GLOBAL_NHOP_CHANGED))
+ SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
+ BPKT_ATTRVEC_FLAGS_RMAP_VPNV6_GNH_CHANGED);
+
if (CHECK_FLAG(attr->rmap_change_flags,
BATTR_RMAP_IPV6_LL_NHOP_CHANGED))
SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 53fdce3a35..8ea9c1996b 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -158,9 +158,7 @@ static struct peer_group *listen_range_exists(struct bgp *bgp,
struct prefix *range, int exact);
static void bgp_show_global_graceful_restart_mode_vty(struct vty *vty,
- struct bgp *bgp,
- bool use_json,
- json_object *json);
+ struct bgp *bgp);
static int bgp_show_neighbor_graceful_restart_afi_all(struct vty *vty,
enum show_type type,
@@ -1308,6 +1306,49 @@ void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi)
bgp_clear(NULL, bgp, afi, safi, clear_all, BGP_CLEAR_SOFT_IN, NULL);
}
+static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
+ uint64_t flag, int set)
+{
+ int ret;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, ip_str);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /*
+ * If 'neighbor <interface>', then this is for directly connected peers,
+ * we should not accept disable-connected-check.
+ */
+ if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
+ vty_out(vty,
+ "%s is directly connected peer, cannot accept disable-connected-check\n",
+ ip_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (!set && flag == PEER_FLAG_SHUTDOWN)
+ peer_tx_shutdown_message_unset(peer);
+
+ if (set)
+ ret = peer_flag_set(peer, flag);
+ else
+ ret = peer_flag_unset(peer, flag);
+
+ return bgp_vty_return(vty, ret);
+}
+
+static int peer_flag_set_vty(struct vty *vty, const char *ip_str, uint64_t flag)
+{
+ return peer_flag_modify_vty(vty, ip_str, flag, 1);
+}
+
+static int peer_flag_unset_vty(struct vty *vty, const char *ip_str,
+ uint64_t flag)
+{
+ return peer_flag_modify_vty(vty, ip_str, flag, 0);
+}
+
#include "bgpd/bgp_vty_clippy.c"
DEFUN_HIDDEN (bgp_local_mac,
@@ -1917,13 +1958,6 @@ DEFUN (bgp_confederation_peers,
for (i = idx_asn; i < argc; i++) {
as = strtoul(argv[i]->arg, NULL, 10);
-
- if (bgp->as == as) {
- vty_out(vty,
- "%% Local member-AS not allowed in confed peer list\n");
- continue;
- }
-
bgp_confederation_peers_add(bgp, as);
}
return CMD_SUCCESS;
@@ -3326,6 +3360,42 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable,
return bgp_vty_return(vty, ret);
}
+DEFPY (neighbor_graceful_shutdown,
+ neighbor_graceful_shutdown_cmd,
+ "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor graceful-shutdown",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Graceful shutdown\n")
+{
+ afi_t afi;
+ safi_t safi;
+ struct peer *peer;
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int ret;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (no)
+ ret = peer_flag_unset_vty(vty, neighbor,
+ PEER_FLAG_GRACEFUL_SHUTDOWN);
+ else
+ ret = peer_flag_set_vty(vty, neighbor,
+ PEER_FLAG_GRACEFUL_SHUTDOWN);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ bgp_clear(vty, bgp, afi, safi, clear_peer, BGP_CLEAR_SOFT_IN,
+ neighbor);
+ }
+
+ return ret;
+}
+
DEFUN_HIDDEN (bgp_graceful_restart_disable_eor,
bgp_graceful_restart_disable_eor_cmd,
"bgp graceful-restart disable-eor",
@@ -4606,7 +4676,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type);
} else {
peer = peer_create(NULL, conf_if, bgp, bgp->as, as, as_type,
- NULL);
+ NULL, true);
if (!peer) {
vty_out(vty, "%% BGP failed to create peer\n");
@@ -5251,51 +5321,6 @@ ALIAS_HIDDEN(no_neighbor_set_peer_group, no_neighbor_set_peer_group_hidden_cmd,
"Member of the peer-group\n"
"Peer-group name\n")
-static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
- uint64_t flag, int set)
-{
- int ret;
- struct peer *peer;
-
- peer = peer_and_group_lookup_vty(vty, ip_str);
- if (!peer)
- return CMD_WARNING_CONFIG_FAILED;
-
- /*
- * If 'neighbor <interface>', then this is for directly connected peers,
- * we should not accept disable-connected-check.
- */
- if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
- vty_out(vty,
- "%s is directly connected peer, cannot accept disable-connected-check\n",
- ip_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (!set && flag == PEER_FLAG_SHUTDOWN) {
- peer_tx_shutdown_message_unset(peer);
- UNSET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN);
- }
-
- if (set)
- ret = peer_flag_set(peer, flag);
- else
- ret = peer_flag_unset(peer, flag);
-
- return bgp_vty_return(vty, ret);
-}
-
-static int peer_flag_set_vty(struct vty *vty, const char *ip_str, uint64_t flag)
-{
- return peer_flag_modify_vty(vty, ip_str, flag, 1);
-}
-
-static int peer_flag_unset_vty(struct vty *vty, const char *ip_str,
- uint64_t flag)
-{
- return peer_flag_modify_vty(vty, ip_str, flag, 0);
-}
-
/* neighbor passive. */
DEFUN (neighbor_passive,
neighbor_passive_cmd,
@@ -9884,7 +9909,6 @@ DEFPY (show_bgp_srv6,
struct listnode *node;
struct srv6_locator_chunk *chunk;
struct bgp_srv6_function *func;
- char buf[256];
bgp = bgp_get_default();
if (!bgp)
@@ -9903,8 +9927,7 @@ DEFPY (show_bgp_srv6,
vty_out(vty, "functions:\n");
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) {
- inet_ntop(AF_INET6, &func->sid, buf, sizeof(buf));
- vty_out(vty, "- sid: %s\n", buf);
+ vty_out(vty, "- sid: %pI6\n", &func->sid);
vty_out(vty, " locator: %s\n", func->locator_name);
}
@@ -11831,7 +11854,6 @@ static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
static void bgp_show_neighnor_graceful_restart_flags(struct vty *vty,
struct peer *p,
- bool use_json,
json_object *json)
{
bool rbit = false;
@@ -11844,7 +11866,7 @@ static void bgp_show_neighnor_graceful_restart_flags(struct vty *vty,
nbit = CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV);
}
- if (use_json) {
+ if (json) {
json_object_boolean_add(json, "rBit", rbit);
json_object_boolean_add(json, "nBit", nbit);
} else {
@@ -11855,12 +11877,11 @@ static void bgp_show_neighnor_graceful_restart_flags(struct vty *vty,
static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty,
struct peer *peer,
- bool use_json,
json_object *json)
{
const char *mode = "NotApplicable";
- if (!use_json)
+ if (!json)
vty_out(vty, "\n Remote GR Mode: ");
if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
@@ -11883,20 +11904,19 @@ static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty,
}
}
- if (use_json) {
+ if (json)
json_object_string_add(json, "remoteGrMode", mode);
- } else
+ else
vty_out(vty, mode, "\n");
}
static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
struct peer *p,
- bool use_json,
json_object *json)
{
const char *mode = "Invalid";
- if (!use_json)
+ if (!json)
vty_out(vty, " Local GR Mode: ");
if (bgp_peer_gr_mode_get(p) == PEER_HELPER)
@@ -11916,15 +11936,14 @@ static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
mode = "Invalid*";
}
- if (use_json) {
+ if (json)
json_object_string_add(json, "localGrMode", mode);
- } else {
+ else
vty_out(vty, mode, "\n");
- }
}
static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
- struct vty *vty, struct peer *peer, bool use_json, json_object *json)
+ struct vty *vty, struct peer *peer, json_object *json)
{
afi_t afi;
safi_t safi;
@@ -11941,7 +11960,7 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))
continue;
- if (use_json) {
+ if (json) {
json_afi_safi = json_object_new_object();
json_endofrib_status = json_object_new_object();
json_timer = json_object_new_object();
@@ -11952,7 +11971,7 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
else
eor_flag = false;
- if (!use_json) {
+ if (!json) {
vty_out(vty, " %s:\n",
get_afi_safi_str(afi, safi, false));
@@ -11963,25 +11982,25 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
CHECK_FLAG(peer->af_cap[afi][safi],
PEER_CAP_RESTART_AF_PRESERVE_RCV)) {
- if (use_json) {
+ if (json) {
json_object_boolean_true_add(json_afi_safi,
"fBit");
} else
vty_out(vty, "True\n");
} else {
- if (use_json)
+ if (json)
json_object_boolean_false_add(json_afi_safi,
"fBit");
else
vty_out(vty, "False\n");
}
- if (!use_json)
+ if (!json)
vty_out(vty, " End-of-RIB sent: ");
if (CHECK_FLAG(peer->af_sflags[afi][safi],
PEER_STATUS_EOR_SEND)) {
- if (use_json) {
+ if (json) {
json_object_boolean_true_add(
json_endofrib_status, "endOfRibSend");
@@ -11994,7 +12013,7 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
PRINT_EOR(eor_flag);
}
} else {
- if (use_json) {
+ if (json) {
json_object_boolean_false_add(
json_endofrib_status, "endOfRibSend");
json_object_boolean_false_add(
@@ -12008,25 +12027,25 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
}
}
- if (!use_json)
+ if (!json)
vty_out(vty, " End-of-RIB received: ");
if (CHECK_FLAG(peer->af_sflags[afi][safi],
PEER_STATUS_EOR_RECEIVED)) {
- if (use_json)
+ if (json)
json_object_boolean_true_add(
json_endofrib_status, "endOfRibRecv");
else
vty_out(vty, "Yes\n");
} else {
- if (use_json)
+ if (json)
json_object_boolean_false_add(
json_endofrib_status, "endOfRibRecv");
else
vty_out(vty, "No\n");
}
- if (use_json) {
+ if (json) {
json_object_int_add(json_timer, "stalePathTimer",
peer->bgp->stalepath_time);
@@ -12086,7 +12105,7 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
peer->bgp->gr_info[afi][safi]
.t_select_deferral));
}
- if (use_json) {
+ if (json) {
json_object_object_add(json_afi_safi, "endOfRibStatus",
json_endofrib_status);
json_object_object_add(json_afi_safi, "timers",
@@ -12100,10 +12119,9 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
static void bgp_show_neighbor_graceful_restart_time(struct vty *vty,
struct peer *p,
- bool use_json,
json_object *json)
{
- if (use_json) {
+ if (json) {
json_object *json_timer = NULL;
json_timer = json_object_new_object();
@@ -12139,7 +12157,7 @@ static void bgp_show_neighbor_graceful_restart_time(struct vty *vty,
}
static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p,
- bool use_json, json_object *json)
+ json_object *json)
{
char dn_flag[2] = {0};
/* '*' + v6 address of neighbor */
@@ -12149,7 +12167,7 @@ static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p,
dn_flag[0] = '*';
if (p->conf_if) {
- if (use_json)
+ if (json)
json_object_string_addf(json, "neighborAddr", "%pSU",
&p->su);
else
@@ -12159,7 +12177,7 @@ static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p,
snprintf(neighborAddr, sizeof(neighborAddr), "%s%s", dn_flag,
p->host);
- if (use_json)
+ if (json)
json_object_string_add(json, "neighborAddr",
neighborAddr);
else
@@ -12167,7 +12185,7 @@ static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p,
}
/* more gr info in new format */
- BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json);
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, json);
}
static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
@@ -12850,7 +12868,6 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object *json)
{
struct bgp *bgp;
- char buf1[PREFIX2STR_BUFFER];
char timebuf[BGP_UPTIME_LEN];
char dn_flag[2];
afi_t afi;
@@ -12979,9 +12996,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
if (p->hostname) {
if (use_json) {
- if (p->hostname)
- json_object_string_add(json_neigh, "hostname",
- p->hostname);
+ json_object_string_add(json_neigh, "hostname",
+ p->hostname);
if (p->domainname)
json_object_string_add(json_neigh, "domainname",
@@ -12993,6 +13009,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
else
vty_out(vty, "Hostname: %s\n", p->hostname);
}
+ } else {
+ if (use_json)
+ json_object_string_add(json_neigh, "hostname",
+ "Unknown");
}
/* Peer-group */
@@ -13174,11 +13194,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
/* BGP Version. */
vty_out(vty, " BGP version 4");
- vty_out(vty, ", remote router ID %s",
- inet_ntop(AF_INET, &p->remote_id, buf1, sizeof(buf1)));
- vty_out(vty, ", local router ID %s\n",
- inet_ntop(AF_INET, &bgp->router_id, buf1,
- sizeof(buf1)));
+ vty_out(vty, ", remote router ID %pI4", &p->remote_id);
+ vty_out(vty, ", local router ID %pI4\n", &bgp->router_id);
/* Confederation */
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
@@ -14153,7 +14170,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
thread_timer_remain_second(p->t_gr_stale) *
1000);
/* more gr info in new format */
- BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json_grace);
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, json_grace);
json_object_object_add(json_neigh, "gracefulRestartInfo",
json_grace);
} else {
@@ -14199,7 +14216,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
thread_timer_remain_second(p->t_gr_stale));
/* more gr info in new format */
- BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, NULL);
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, NULL);
}
if (use_json) {
@@ -14548,19 +14565,26 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
"bgpConnection",
"nonSharedNetwork");
} else {
- vty_out(vty, "Nexthop: %s\n",
- inet_ntop(AF_INET, &p->nexthop.v4, buf1,
- sizeof(buf1)));
- vty_out(vty, "Nexthop global: %s\n",
- inet_ntop(AF_INET6, &p->nexthop.v6_global, buf1,
- sizeof(buf1)));
- vty_out(vty, "Nexthop local: %s\n",
- inet_ntop(AF_INET6, &p->nexthop.v6_local, buf1,
- sizeof(buf1)));
+ vty_out(vty, "Nexthop: %pI4\n", &p->nexthop.v4);
+ vty_out(vty, "Nexthop global: %pI6\n",
+ &p->nexthop.v6_global);
+ vty_out(vty, "Nexthop local: %pI6\n",
+ &p->nexthop.v6_local);
vty_out(vty, "BGP connection: %s\n",
p->shared_network ? "shared network"
: "non shared network");
}
+ } else {
+ if (use_json) {
+ json_object_string_add(json_neigh, "nexthop",
+ "Unknown");
+ json_object_string_add(json_neigh, "nexthopGlobal",
+ "Unknown");
+ json_object_string_add(json_neigh, "nexthopLocal",
+ "Unknown");
+ json_object_string_add(json_neigh, "bgpConnection",
+ "Unknown");
+ }
}
/* Timer information. */
@@ -14665,20 +14689,14 @@ static int bgp_show_neighbor_graceful_restart(struct vty *vty, struct bgp *bgp,
enum show_type type,
union sockunion *su,
const char *conf_if, afi_t afi,
- bool use_json)
+ json_object *json)
{
struct listnode *node, *nnode;
struct peer *peer;
- int find = 0;
+ bool found = false;
safi_t safi = SAFI_UNICAST;
- json_object *json = NULL;
json_object *json_neighbor = NULL;
- if (use_json) {
- json = json_object_new_object();
- json_neighbor = json_object_new_object();
- }
-
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
@@ -14687,15 +14705,15 @@ static int bgp_show_neighbor_graceful_restart(struct vty *vty, struct bgp *bgp,
if ((peer->afc[afi][safi]) == 0)
continue;
+ if (json)
+ json_neighbor = json_object_new_object();
+
if (type == show_all) {
- bgp_show_peer_gr_status(vty, peer, use_json,
- json_neighbor);
+ bgp_show_peer_gr_status(vty, peer, json_neighbor);
- if (use_json) {
+ if (json)
json_object_object_add(json, peer->host,
json_neighbor);
- json_neighbor = NULL;
- }
} else if (type == show_peer) {
if (conf_if) {
@@ -14703,43 +14721,39 @@ static int bgp_show_neighbor_graceful_restart(struct vty *vty, struct bgp *bgp,
&& !strcmp(peer->conf_if, conf_if))
|| (peer->hostname
&& !strcmp(peer->hostname, conf_if))) {
- find = 1;
+ found = true;
bgp_show_peer_gr_status(vty, peer,
- use_json,
json_neighbor);
}
} else {
if (sockunion_same(&peer->su, su)) {
- find = 1;
+ found = true;
bgp_show_peer_gr_status(vty, peer,
- use_json,
json_neighbor);
}
}
- if (use_json && find)
- json_object_object_add(json, peer->host,
- json_neighbor);
+ if (json) {
+ if (found)
+ json_object_object_add(json, peer->host,
+ json_neighbor);
+ else
+ json_object_free(json_neighbor);
+ }
}
- if (find) {
- json_neighbor = NULL;
+ if (found)
break;
- }
}
- if (type == show_peer && !find) {
- if (use_json)
+ if (type == show_peer && !found) {
+ if (json)
json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
else
vty_out(vty, "%% No such neighbor\n");
}
- if (use_json) {
- if (json_neighbor)
- json_object_free(json_neighbor);
- vty_json(vty, json);
- } else {
+
+ if (!json)
vty_out(vty, "\n");
- }
return CMD_SUCCESS;
}
@@ -14852,7 +14866,7 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
static void bgp_show_neighbor_graceful_restart_vty(struct vty *vty,
enum show_type type,
const char *ip_str,
- afi_t afi, bool use_json)
+ afi_t afi, json_object *json)
{
int ret;
@@ -14864,21 +14878,20 @@ static void bgp_show_neighbor_graceful_restart_vty(struct vty *vty,
if (!bgp)
return;
- if (!use_json)
- bgp_show_global_graceful_restart_mode_vty(vty, bgp, use_json,
- NULL);
+ if (!json)
+ bgp_show_global_graceful_restart_mode_vty(vty, bgp);
if (ip_str) {
ret = str2sockunion(ip_str, &su);
if (ret < 0)
- bgp_show_neighbor_graceful_restart(
- vty, bgp, type, NULL, ip_str, afi, use_json);
+ bgp_show_neighbor_graceful_restart(vty, bgp, type, NULL,
+ ip_str, afi, json);
else
bgp_show_neighbor_graceful_restart(vty, bgp, type, &su,
- NULL, afi, use_json);
+ NULL, afi, json);
} else
bgp_show_neighbor_graceful_restart(vty, bgp, type, NULL, NULL,
- afi, use_json);
+ afi, json);
}
static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
@@ -15198,9 +15211,7 @@ DEFUN (show_ip_bgp_lcommunity_info,
/* Graceful Restart */
static void bgp_show_global_graceful_restart_mode_vty(struct vty *vty,
- struct bgp *bgp,
- bool use_json,
- json_object *json)
+ struct bgp *bgp)
{
@@ -15235,22 +15246,32 @@ static int bgp_show_neighbor_graceful_restart_afi_all(struct vty *vty,
const char *ip_str,
afi_t afi, bool use_json)
{
+ json_object *json = NULL;
+
+ if (use_json)
+ json = json_object_new_object();
+
if ((afi == AFI_MAX) && (ip_str == NULL)) {
afi = AFI_IP;
while ((afi != AFI_L2VPN) && (afi < AFI_MAX)) {
bgp_show_neighbor_graceful_restart_vty(
- vty, type, ip_str, afi, use_json);
+ vty, type, ip_str, afi, json);
afi++;
}
} else if (afi != AFI_MAX) {
bgp_show_neighbor_graceful_restart_vty(vty, type, ip_str, afi,
- use_json);
+ json);
} else {
+ if (json)
+ json_object_free(json);
return CMD_ERR_INCOMPLETE;
}
+ if (json)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}
/* Graceful Restart */
@@ -15531,28 +15552,30 @@ DEFUN (show_ip_bgp_route_leak,
}
static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
- safi_t safi)
+ safi_t safi, bool uj)
{
struct listnode *node, *nnode;
struct bgp *bgp;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
- vty_out(vty, "\nInstance %s:\n",
- (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
- ? VRF_DEFAULT_NAME
- : bgp->name);
- update_group_show(bgp, afi, safi, vty, 0);
+ if (!uj)
+ vty_out(vty, "\nInstance %s:\n",
+ (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ ? VRF_DEFAULT_NAME
+ : bgp->name);
+
+ update_group_show(bgp, afi, safi, vty, 0, uj);
}
}
static int bgp_show_update_groups(struct vty *vty, const char *name, int afi,
- int safi, uint64_t subgrp_id)
+ int safi, uint64_t subgrp_id, bool uj)
{
struct bgp *bgp;
if (name) {
if (strmatch(name, "all")) {
- bgp_show_all_instances_updgrps_vty(vty, afi, safi);
+ bgp_show_all_instances_updgrps_vty(vty, afi, safi, uj);
return CMD_SUCCESS;
} else {
bgp = bgp_lookup_by_name(name);
@@ -15562,13 +15585,13 @@ static int bgp_show_update_groups(struct vty *vty, const char *name, int afi,
}
if (bgp)
- update_group_show(bgp, afi, safi, vty, subgrp_id);
+ update_group_show(bgp, afi, safi, vty, subgrp_id, uj);
return CMD_SUCCESS;
}
DEFUN (show_ip_bgp_updgrps,
show_ip_bgp_updgrps_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] update-groups [SUBGROUP-ID]",
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] update-groups [SUBGROUP-ID] [json]",
SHOW_STR
IP_STR
BGP_STR
@@ -15576,7 +15599,8 @@ DEFUN (show_ip_bgp_updgrps,
BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
"Detailed info about dynamic update groups\n"
- "Specific subgroup to display detailed info for\n")
+ "Specific subgroup to display detailed info for\n"
+ JSON_STR)
{
char *vrf = NULL;
afi_t afi = AFI_IP6;
@@ -15585,6 +15609,8 @@ DEFUN (show_ip_bgp_updgrps,
int idx = 0;
+ bool uj = use_json(argc, argv);
+
/* show [ip] bgp */
if (argv_find(argv, argc, "ip", &idx))
afi = AFI_IP;
@@ -15606,19 +15632,22 @@ DEFUN (show_ip_bgp_updgrps,
if (argv[idx]->type == VARIABLE_TKN)
subgrp_id = strtoull(argv[idx]->arg, NULL, 10);
- return (bgp_show_update_groups(vty, vrf, afi, safi, subgrp_id));
+ return (bgp_show_update_groups(vty, vrf, afi, safi, subgrp_id, uj));
}
DEFUN (show_bgp_instance_all_ipv6_updgrps,
show_bgp_instance_all_ipv6_updgrps_cmd,
- "show [ip] bgp <view|vrf> all update-groups",
+ "show [ip] bgp <view|vrf> all update-groups [json]",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_ALL_HELP_STR
- "Detailed info about dynamic update groups\n")
+ "Detailed info about dynamic update groups\n"
+ JSON_STR)
{
- bgp_show_all_instances_updgrps_vty(vty, AFI_IP6, SAFI_UNICAST);
+ bool uj = use_json(argc, argv);
+
+ bgp_show_all_instances_updgrps_vty(vty, AFI_IP6, SAFI_UNICAST, uj);
return CMD_SUCCESS;
}
@@ -15635,7 +15664,7 @@ DEFUN (show_bgp_l2vpn_evpn_updgrps,
char *vrf = NULL;
uint64_t subgrp_id = 0;
- bgp_show_update_groups(vty, vrf, AFI_L2VPN, SAFI_EVPN, subgrp_id);
+ bgp_show_update_groups(vty, vrf, AFI_L2VPN, SAFI_EVPN, subgrp_id, 0);
return CMD_SUCCESS;
}
@@ -17212,6 +17241,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
if (peergroup_flag_check(peer, PEER_FLAG_AIGP))
vty_out(vty, " neighbor %s aigp\n", addr);
+ /* graceful-shutdown */
+ if (peergroup_flag_check(peer, PEER_FLAG_GRACEFUL_SHUTDOWN))
+ vty_out(vty, " neighbor %s graceful-shutdown\n", addr);
+
/* role */
if (peergroup_flag_check(peer, PEER_FLAG_ROLE) &&
peer->local_role != ROLE_UNDEFINED)
@@ -18658,6 +18691,9 @@ void bgp_vty_init(void)
/* "neighbor aigp" commands. */
install_element(BGP_NODE, &neighbor_aigp_cmd);
+ /* "neighbor graceful-shutdown" command */
+ install_element(BGP_NODE, &neighbor_graceful_shutdown_cmd);
+
/* bgp disable-ebgp-connected-nh-check */
install_element(BGP_NODE, &bgp_disable_connected_route_check_cmd);
install_element(BGP_NODE, &no_bgp_disable_connected_route_check_cmd);
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 9526b50fb9..019789dff8 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -56,18 +56,14 @@ struct bgp;
"V AS LocalAS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc\n"
#define BGP_SHOW_SUMMARY_HEADER_FAILED "EstdCnt DropCnt ResetTime Reason\n"
-#define BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json) \
+#define BGP_SHOW_PEER_GR_CAPABILITY(vty, p, json) \
do { \
- bgp_show_neighbor_graceful_restart_local_mode(vty, p, \
- use_json, json); \
- bgp_show_neighbor_graceful_restart_remote_mode( \
- vty, p, use_json, json); \
- bgp_show_neighnor_graceful_restart_flags(vty, p, use_json, \
- json); \
- bgp_show_neighbor_graceful_restart_time(vty, p, use_json, \
- json); \
+ bgp_show_neighbor_graceful_restart_local_mode(vty, p, json); \
+ bgp_show_neighbor_graceful_restart_remote_mode(vty, p, json); \
+ bgp_show_neighnor_graceful_restart_flags(vty, p, json); \
+ bgp_show_neighbor_graceful_restart_time(vty, p, json); \
bgp_show_neighbor_graceful_restart_capability_per_afi_safi( \
- vty, p, use_json, json); \
+ vty, p, json); \
} while (0)
#define VTY_BGP_GR_DEFINE_LOOP_VARIABLE \
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 2badc25cd8..f6e7b444c6 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -234,6 +234,7 @@ static int bgp_ifp_up(struct interface *ifp)
struct connected *c;
struct nbr_connected *nc;
struct listnode *node, *nnode;
+ struct bgp *bgp_default = bgp_get_default();
struct bgp *bgp;
bgp = ifp->vrf->info;
@@ -256,6 +257,14 @@ static int bgp_ifp_up(struct interface *ifp)
hook_call(bgp_vrf_status_changed, bgp, ifp);
bgp_nht_ifp_up(ifp);
+ if (bgp_default && if_is_loopback(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);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6);
+ vpn_leak_postchange_all();
+ }
+
return 0;
}
@@ -264,6 +273,7 @@ static int bgp_ifp_down(struct interface *ifp)
struct connected *c;
struct nbr_connected *nc;
struct listnode *node, *nnode;
+ struct bgp *bgp_default = bgp_get_default();
struct bgp *bgp;
struct peer *peer;
@@ -303,6 +313,14 @@ static int bgp_ifp_down(struct interface *ifp)
hook_call(bgp_vrf_status_changed, bgp, ifp);
bgp_nht_ifp_down(ifp);
+ if (bgp_default && if_is_loopback(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);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6);
+ vpn_leak_postchange_all();
+ }
+
return 0;
}
@@ -390,10 +408,16 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
{
struct listnode *node, *nnode;
+ struct bgp_path_info *pi;
+ struct bgp_table *table;
+ struct bgp_dest *dest;
struct connected *ifc;
struct peer *peer;
- struct bgp *bgp;
+ struct bgp *bgp, *from_bgp, *bgp_default;
+ struct listnode *next;
struct prefix *addr;
+ afi_t afi;
+ safi_t safi;
bgp = bgp_lookup_by_vrf_id(vrf_id);
@@ -421,9 +445,6 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
* we do not want the peering to bounce.
*/
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- afi_t afi;
- safi_t safi;
-
if (addr->family == AF_INET)
continue;
@@ -439,6 +460,44 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
}
}
+ bgp_default = bgp_get_default();
+ afi = family2afi(addr->family);
+ safi = SAFI_UNICAST;
+
+ /* When the last IPv4 address was deleted, Linux removes all routes
+ * using the interface so that bgpd needs to re-send them.
+ */
+ if (bgp_default && afi == AFI_IP) {
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, from_bgp)) {
+ table = from_bgp->rib[afi][safi];
+ if (!table)
+ continue;
+
+ for (dest = bgp_table_top(table); dest;
+ dest = bgp_route_next(dest)) {
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi;
+ pi = pi->next) {
+ if (pi->type == ZEBRA_ROUTE_BGP &&
+ pi->attr &&
+ pi->attr->nh_ifindex ==
+ ifc->ifp->ifindex) {
+ SET_FLAG(pi->attr->nh_flag,
+ BGP_ATTR_NH_REFRESH);
+ }
+ }
+ }
+
+ if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
+ bgp_default, from_bgp);
+
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
+ bgp_default, from_bgp);
+ }
+ }
+
connected_free(&ifc);
return 0;
@@ -1007,7 +1066,8 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex)
|| path->attr->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
/* Check if route-map is set to prefer global over link-local */
- if (path->attr->mp_nexthop_prefer_global) {
+ if (CHECK_FLAG(path->attr->nh_flag,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)) {
nexthop = &path->attr->mp_nexthop_global;
if (IN6_IS_ADDR_LINKLOCAL(nexthop))
*ifindex = path->attr->nh_ifindex;
@@ -1307,6 +1367,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
uint8_t distance;
struct peer *peer;
struct bgp_path_info *mpinfo;
+ struct bgp_path_info *bpi_ultimate;
struct bgp *bgp_orig;
uint32_t metric;
struct attr local_attr;
@@ -1355,13 +1416,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
peer = info->peer;
- if (info->type == ZEBRA_ROUTE_BGP
- && info->sub_type == BGP_ROUTE_IMPORTED) {
-
- /* Obtain peer from parent */
- if (info->extra && info->extra->parent)
- peer = ((struct bgp_path_info *)(info->extra->parent))
- ->peer;
+ if (info->type == ZEBRA_ROUTE_BGP) {
+ bpi_ultimate = bgp_get_imported_bpi_ultimate(info);
+ peer = bpi_ultimate->peer;
}
tag = info->attr->tag;
@@ -1532,7 +1589,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api_nh->weight = nh_weight;
- if (mpinfo->extra && !sid_zero(&mpinfo->extra->sid[0].sid) &&
+ if (mpinfo->extra &&
+ bgp_is_valid_label(&mpinfo->extra->label[0]) &&
+ !sid_zero(&mpinfo->extra->sid[0].sid) &&
!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) {
sid_info = &mpinfo->extra->sid[0];
@@ -1540,12 +1599,16 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
sizeof(api_nh->seg6_segs));
if (sid_info->transposition_len != 0) {
- if (!bgp_is_valid_label(
- &mpinfo->extra->label[0]))
- continue;
-
mpls_lse_decode(mpinfo->extra->label[0], &label,
&ttl, &exp, &bos);
+
+ if (label < MPLS_LABEL_UNRESERVED_MIN) {
+ if (bgp_debug_zebra(&api.prefix))
+ zlog_debug(
+ "skip invalid SRv6 routes: transposition scheme is used, but label is too small");
+ continue;
+ }
+
transpose_sid(&api_nh->seg6_segs, label,
sid_info->transposition_offset,
sid_info->transposition_len);
@@ -1626,9 +1689,8 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
zlog_debug(
"Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI
" count %d nhg %d",
- valid_nh_count ? "add" : "delete", bgp->vrf_id,
- &api.prefix, api.metric, api.tag, api.nexthop_num,
- nhg_id);
+ is_add ? "add" : "delete", bgp->vrf_id, &api.prefix,
+ api.metric, api.tag, api.nexthop_num, nhg_id);
for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i];
@@ -3188,6 +3250,7 @@ extern struct zebra_privs_t bgpd_privs;
static int bgp_ifp_create(struct interface *ifp)
{
+ struct bgp *bgp_default = bgp_get_default();
struct bgp *bgp;
if (BGP_DEBUG(zebra, ZEBRA))
@@ -3202,6 +3265,17 @@ static int bgp_ifp_create(struct interface *ifp)
bgp_update_interface_nbrs(bgp, ifp, ifp);
hook_call(bgp_vrf_status_changed, bgp, ifp);
+
+ if (bgp_default &&
+ (if_is_loopback_exact(ifp) ||
+ (if_is_vrf(ifp) && ifp->vrf->vrf_id != VRF_DEFAULT))) {
+ 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);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6);
+ vpn_leak_postchange_all();
+ }
+
return 0;
}
@@ -3682,35 +3756,33 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
/* redirect IP */
if (afi == AFI_IP && nh->gate.ipv4.s_addr != INADDR_ANY) {
- char buff[PREFIX_STRLEN];
-
api_nh->vrf_id = nh->vrf_id;
api_nh->gate.ipv4 = nh->gate.ipv4;
api_nh->type = NEXTHOP_TYPE_IPV4;
- inet_ntop(AF_INET, &(nh->gate.ipv4), buff, INET_ADDRSTRLEN);
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("BGP: %s default route to %s table %d (redirect IP)",
- announce ? "adding" : "withdrawing",
- buff, table_id);
+ zlog_debug(
+ "BGP: %s default route to %pI4 table %d (redirect IP)",
+ announce ? "adding" : "withdrawing",
+ &nh->gate.ipv4, table_id);
+
zclient_route_send(announce ? ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE,
zclient, &api);
} else if (afi == AFI_IP6 &&
memcmp(&nh->gate.ipv6,
&in6addr_any, sizeof(struct in6_addr))) {
- char buff[PREFIX_STRLEN];
-
api_nh->vrf_id = nh->vrf_id;
memcpy(&api_nh->gate.ipv6, &nh->gate.ipv6,
sizeof(struct in6_addr));
api_nh->type = NEXTHOP_TYPE_IPV6;
- inet_ntop(AF_INET6, &(nh->gate.ipv6), buff, INET_ADDRSTRLEN);
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("BGP: %s default route to %s table %d (redirect IP)",
- announce ? "adding" : "withdrawing",
- buff, table_id);
+ zlog_debug(
+ "BGP: %s default route to %pI6 table %d (redirect IP)",
+ announce ? "adding" : "withdrawing",
+ &nh->gate.ipv6, table_id);
+
zclient_route_send(announce ? ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE,
zclient, &api);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 6ad1cf2c06..9b4aa38d7a 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -93,6 +93,7 @@
#include "bgpd/bgp_evpn_mh.h"
#include "bgpd/bgp_mac.h"
#include "bgpd/bgp_orr.h"
+#include "bgp_trace.h"
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
@@ -671,7 +672,7 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
struct peer *peer;
struct listnode *node, *nnode;
- if (bgp->as == as)
+ if (!bgp)
return;
if (bgp_confederation_peers_check(bgp, as))
@@ -687,8 +688,8 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (peer->as == as) {
- (void)peer_sort(peer);
peer->local_as = bgp->as;
+ (void)peer_sort(peer);
if (BGP_IS_VALID_STATE_FOR_NOTIF(
peer->status)) {
peer->last_reset =
@@ -738,8 +739,8 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (peer->as == as) {
- (void)peer_sort(peer);
peer->local_as = bgp->confed_id;
+ (void)peer_sort(peer);
if (BGP_IS_VALID_STATE_FOR_NOTIF(
peer->status)) {
peer->last_reset =
@@ -950,6 +951,7 @@ static bool peer_hash_same(const void *p1, const void *p2)
{
const struct peer *peer1 = p1;
const struct peer *peer2 = p2;
+
return (sockunion_same(&peer1->su, &peer2->su)
&& CHECK_FLAG(peer1->flags, PEER_FLAG_CONFIG_NODE)
== CHECK_FLAG(peer2->flags, PEER_FLAG_CONFIG_NODE));
@@ -1127,6 +1129,7 @@ static void peer_free(struct peer *peer)
bgp_timer_set(peer);
bgp_reads_off(peer);
bgp_writes_off(peer);
+ thread_cancel_event_ready(bm->master, peer);
FOREACH_AFI_SAFI (afi, safi)
THREAD_OFF(peer->t_revalidate_all[afi][safi]);
assert(!peer->t_write);
@@ -1192,6 +1195,7 @@ static void peer_free(struct peer *peer)
/* increase reference count on a struct peer */
struct peer *peer_lock_with_caller(const char *name, struct peer *peer)
{
+ frrtrace(2, frr_bgp, bgp_peer_lock, peer, name);
assert(peer && (peer->lock >= 0));
peer->lock++;
@@ -1204,6 +1208,7 @@ struct peer *peer_lock_with_caller(const char *name, struct peer *peer)
*/
struct peer *peer_unlock_with_caller(const char *name, struct peer *peer)
{
+ frrtrace(2, frr_bgp, bgp_peer_unlock, peer, name);
assert(peer && (peer->lock > 0));
peer->lock--;
@@ -1457,7 +1462,10 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
/* peer flags apply */
peer_dst->flags = peer_src->flags;
-
+ /*
+ * The doppelganger *must* not have a config node stored
+ */
+ UNSET_FLAG(peer_dst->flags, PEER_FLAG_CONFIG_NODE);
peer_dst->peer_gr_present_state = peer_src->peer_gr_present_state;
peer_dst->peer_gr_new_status_flag = peer_src->peer_gr_new_status_flag;
@@ -1613,15 +1621,18 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer)
struct interface *ifp;
int prev_family;
int peer_addr_updated = 0;
+ struct listnode *node;
+ union sockunion old_su;
+ /*
+ * This function is only ever needed when FRR an interface
+ * based peering, so this simple test will tell us if
+ * we are in an interface based configuration or not
+ */
if (!peer->conf_if)
return;
- /*
- * Our peer structure is stored in the bgp->peerhash
- * release it before we modify anything.
- */
- hash_release(peer->bgp->peerhash, peer);
+ old_su = peer->su;
prev_family = peer->su.sa.sa_family;
if ((ifp = if_lookup_by_name(peer->conf_if, peer->bgp->vrf_id))) {
@@ -1664,9 +1675,48 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer)
}
/*
- * Since our su changed we need to del/add peer to the peerhash
+ * If they are the same, nothing to do here, move along
*/
- (void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
+ if (!sockunion_same(&old_su, &peer->su)) {
+ union sockunion new_su = peer->su;
+ struct bgp *bgp = peer->bgp;
+
+ /*
+ * Our peer structure is stored in the bgp->peerhash
+ * release it before we modify anything in both the
+ * hash and the list. But *only* if the peer
+ * is in the bgp->peerhash as that on deletion
+ * we call bgp_stop which calls this function :(
+ * so on deletion let's remove from the list first
+ * and then do the deletion preventing this from
+ * being added back on the list below when we
+ * fail to remove it up here.
+ */
+
+ /*
+ * listnode_lookup just scans the list
+ * for the peer structure so it's safe
+ * to use without modifying the su
+ */
+ node = listnode_lookup(bgp->peer, peer);
+ if (node) {
+ /*
+ * Let's reset the peer->su release and
+ * reset it and put it back. We have to
+ * do this because hash_release will
+ * scan through looking for a matching
+ * su if needed.
+ */
+ peer->su = old_su;
+ hash_release(peer->bgp->peerhash, peer);
+ listnode_delete(peer->bgp->peer, peer);
+
+ peer->su = new_su;
+ (void)hash_get(peer->bgp->peerhash, peer,
+ hash_alloc_intern);
+ listnode_add_sort(peer->bgp->peer, peer);
+ }
+ }
}
void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, safi_t safi)
@@ -1715,7 +1765,8 @@ 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)
+ int as_type, struct peer_group *group,
+ bool config_node)
{
int active;
struct peer *peer;
@@ -1753,6 +1804,10 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
peer = peer_lock(peer); /* bgp peer list reference */
peer->group = group;
listnode_add_sort(bgp->peer, peer);
+
+ if (config_node)
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
+
(void)hash_get(bgp->peerhash, peer, hash_alloc_intern);
/* Adjust update-group coalesce timer heuristics for # peers. */
@@ -1780,8 +1835,6 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
/* Default configured keepalives count for shutdown rtt command */
peer->rtt_keepalive_conf = 1;
- SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
-
/* If 'bgp default <afi>-<safi>' is configured, then activate the
* neighbor for the corresponding address family. IPv4 Unicast is
* the only address family enabled by default without expliict
@@ -1816,6 +1869,7 @@ struct peer *peer_create_accept(struct bgp *bgp)
peer = peer_lock(peer); /* bgp peer list reference */
listnode_add_sort(bgp->peer, peer);
+ (void)hash_get(bgp->peerhash, peer, hash_alloc_intern);
return peer;
}
@@ -1987,7 +2041,8 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
else
local_as = bgp->as;
- peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL);
+ peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL,
+ true);
}
return 0;
@@ -2446,6 +2501,7 @@ int peer_delete(struct peer *peer)
bgp_keepalives_off(peer);
bgp_reads_off(peer);
bgp_writes_off(peer);
+ thread_cancel_event_ready(bm->master, peer);
FOREACH_AFI_SAFI (afi, safi)
THREAD_OFF(peer->t_revalidate_all[afi][safi]);
assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON));
@@ -2509,9 +2565,16 @@ int peer_delete(struct peer *peer)
/* Delete from all peer list. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
&& (pn = listnode_lookup(bgp->peer, peer))) {
- peer_unlock(peer); /* bgp peer list reference */
+ /*
+ * Removing from the list node first because
+ * peer_unlock *can* call peer_delete( I know,
+ * I know ). So let's remove it and in
+ * the su recalculate function we'll ensure
+ * it's in there or not.
+ */
list_delete_node(bgp->peer, pn);
hash_release(bgp->peerhash, peer);
+ peer_unlock(peer); /* bgp peer list reference */
}
/* Buffers. */
@@ -2649,6 +2712,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
{
uint32_t flags_tmp;
struct peer *conf;
+ bool config_node = !!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
conf = group->conf;
@@ -2676,6 +2740,9 @@ static void peer_group2peer_config_copy(struct peer_group *group,
SET_FLAG(peer->flags, flags_tmp);
SET_FLAG(peer->flags_invert, conf->flags_invert);
+ if (config_node)
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
+
/* peer timers apply */
if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TIMER)) {
PEER_ATTR_INHERIT(peer, group, holdtime);
@@ -3077,7 +3144,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
}
peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
- group->conf->as_type, group);
+ group->conf->as_type, group, true);
peer = peer_lock(peer); /* group->peer list reference */
listnode_add(group->peer, peer);
@@ -3099,8 +3166,6 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
peer_deactivate(peer, afi, safi);
}
- SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
-
/* Set up peer's events and timers. */
if (peer_active(peer))
bgp_timer_set(peer);
@@ -3723,8 +3788,10 @@ int bgp_delete(struct bgp *bgp)
for (ALL_LIST_ELEMENTS(bgp->group, node, next, group))
peer_group_delete(group);
- for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer))
+ while (listcount(bgp->peer)) {
+ peer = listnode_head(bgp->peer);
peer_delete(peer);
+ }
if (bgp->peer_self) {
peer_delete(bgp->peer_self);
@@ -3971,7 +4038,7 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp,
/* Create peer first; we've already checked group config is valid. */
peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
- group->conf->as_type, group);
+ group->conf->as_type, group, true);
if (!peer)
return NULL;
@@ -4000,7 +4067,6 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp,
/* Mark as dynamic, but also as a "config node" for other things to
* work. */
SET_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR);
- SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
return peer;
}
@@ -4289,6 +4355,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_ROLE, 0, peer_change_reset},
{PEER_FLAG_PORT, 0, peer_change_reset},
{PEER_FLAG_AIGP, 0, peer_change_none},
+ {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none},
{0, 0, 0}};
static const struct peer_flag_action peer_af_flag_action_list[] = {
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 8a0ec5ad2d..a75bfdf746 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1413,6 +1413,7 @@ struct peer {
#define PEER_FLAG_ROLE (1ULL << 32)
#define PEER_FLAG_PORT (1ULL << 33)
#define PEER_FLAG_AIGP (1ULL << 34)
+#define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35)
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
@@ -2176,8 +2177,10 @@ extern bool peer_active_nego(struct peer *);
extern bool peer_afc_received(struct peer *peer);
extern bool peer_afc_advertised(struct peer *peer);
extern void bgp_recalculate_all_bestpaths(struct bgp *bgp);
-extern struct peer *peer_create(union sockunion *, const char *, struct bgp *,
- as_t, as_t, int, struct peer_group *);
+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);
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,
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index eae9859ba1..b65d90e1b3 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -3847,6 +3847,13 @@ struct rfapi_cfg *bgp_rfapi_cfg_new(struct rfapi_rfp_cfg *cfg)
return h;
}
+static void bgp_rfapi_rfgn_list_delete(void *data)
+{
+ struct rfapi_rfg_name *rfgn = data;
+ free(rfgn->name);
+ rfgn_free(rfgn);
+}
+
void bgp_rfapi_cfg_destroy(struct bgp *bgp, struct rfapi_cfg *h)
{
afi_t afi;
@@ -3858,8 +3865,13 @@ void bgp_rfapi_cfg_destroy(struct bgp *bgp, struct rfapi_cfg *h)
if (h->l2_groups != NULL)
list_delete(&h->l2_groups);
list_delete(&h->nve_groups_sequential);
+
+ h->rfg_export_direct_bgp_l->del = bgp_rfapi_rfgn_list_delete;
list_delete(&h->rfg_export_direct_bgp_l);
+
+ h->rfg_export_zebra_l->del = bgp_rfapi_rfgn_list_delete;
list_delete(&h->rfg_export_zebra_l);
+
if (h->default_rt_export_list)
ecommunity_free(&h->default_rt_export_list);
if (h->default_rt_import_list)
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index a5d57748b7..80d0b3e269 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -1273,13 +1273,15 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp,
}
{ /* base code assumes have valid host pointer */
- char buf[BUFSIZ];
+ char buf[INET6_ADDRSTRLEN];
buf[0] = 0;
if (rfd->vn_addr.addr_family == AF_INET) {
- inet_ntop(AF_INET, &rfd->vn_addr.addr.v4, buf, BUFSIZ);
+ inet_ntop(AF_INET, &rfd->vn_addr.addr.v4, buf,
+ sizeof(buf));
} else if (rfd->vn_addr.addr_family == AF_INET6) {
- inet_ntop(AF_INET6, &rfd->vn_addr.addr.v6, buf, BUFSIZ);
+ inet_ntop(AF_INET6, &rfd->vn_addr.addr.v6, buf,
+ sizeof(buf));
}
rfd->peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, buf);
}
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 1dd623d3f3..2aae0bc616 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -2908,7 +2908,8 @@ static void rfapiBgpInfoFilteredImportEncap(
vnc_zlog_debug_verbose(
"%s: entry: %s: prefix %s/%d", __func__, action_str,
- inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen);
+ inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
+ p->prefixlen);
memset(&p_firstbpi_old, 0, sizeof(p_firstbpi_old));
memset(&p_firstbpi_new, 0, sizeof(p_firstbpi_new));
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 23f43fa7d3..719d898e3c 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -411,9 +411,10 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) {
char buf[BUFSIZ];
+
vty_out(vty, "UN=%s",
inet_ntop(pfx_un.family, pfx_un.u.val, buf,
- BUFSIZ));
+ sizeof(buf)));
}
}
@@ -432,11 +433,7 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
decode_label(&bpi->extra->label[0]));
if (bpi->extra->num_sids) {
- char buf[BUFSIZ];
-
- vty_out(vty, " sid=%s",
- inet_ntop(AF_INET6, &bpi->extra->sid[0].sid,
- buf, sizeof(buf)));
+ vty_out(vty, " sid=%pI6", &bpi->extra->sid[0].sid);
if (bpi->extra->sid[0].loc_block_len != 0) {
vty_out(vty, " sid_structure=[%d,%d,%d,%d]",
@@ -466,7 +463,6 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr)
const char *vty_newline;
struct transit *transit;
struct cluster_list *cluster;
- char buf[BUFSIZ];
struct ecommunity *ecomm;
struct community *comm;
@@ -478,8 +474,7 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr)
return;
/* IPv4 Nexthop */
- inet_ntop(AF_INET, &attr->nexthop, buf, BUFSIZ);
- fp(out, " nexthop=%s%s", buf, HVTYNL);
+ fp(out, " nexthop=%pI4%s", &attr->nexthop, HVTYNL);
fp(out, " aspath=%p, refcnt=%d%s", attr->aspath,
(attr->aspath ? attr->aspath->refcnt : 0), HVTYNL);
@@ -571,15 +566,12 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi)
/* Nexthop */
if (af == AF_INET) {
- r = snprintf(p, REMAIN, "%s",
- inet_ntop(AF_INET,
- &bpi->attr->mp_nexthop_global_in, buf,
- BUFSIZ));
+ r = snprintfrr(p, REMAIN, "%pI4",
+ &bpi->attr->mp_nexthop_global_in);
INCP;
} else if (af == AF_INET6) {
- r = snprintf(p, REMAIN, "%s",
- inet_ntop(AF_INET6, &bpi->attr->mp_nexthop_global,
- buf, BUFSIZ));
+ r = snprintfrr(p, REMAIN, "%pI6",
+ &bpi->attr->mp_nexthop_global);
INCP;
} else {
r = snprintf(p, REMAIN, "?");
@@ -590,9 +582,9 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi)
* VNC tunnel subtlv, if present, contains UN address
*/
if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) {
- r = snprintf(
- p, REMAIN, " un=%s",
- inet_ntop(pfx_un.family, pfx_un.u.val, buf, BUFSIZ));
+ r = snprintf(p, REMAIN, " un=%s",
+ inet_ntop(pfx_un.family, pfx_un.u.val, buf,
+ sizeof(buf)));
INCP;
}
@@ -719,7 +711,8 @@ char *rfapiMonitorVpn2Str(struct rfapi_monitor_vpn *m, char *buf, int size)
rc = snprintf(buf, size,
"m=%p, next=%p, rfd=%p(vn=%s un=%s), p=%s/%d, node=%p", m,
m->next, m->rfd, buf_vn, buf_un,
- inet_ntop(m->p.family, &m->p.u.prefix, buf_pfx, BUFSIZ),
+ inet_ntop(m->p.family, &m->p.u.prefix, buf_pfx,
+ sizeof(buf_pfx)),
m->p.prefixlen, m->node);
buf[size - 1] = 0;
if (rc >= size)
@@ -800,9 +793,9 @@ void rfapiShowImportTable(void *stream, const char *label, struct agg_table *rt,
const struct prefix *p = agg_node_get_prefix(rn);
if (p->family == AF_ETHERNET) {
- rfapiEthAddr2Str(&p->u.prefix_eth, buf, BUFSIZ);
+ rfapiEthAddr2Str(&p->u.prefix_eth, buf, sizeof(buf));
} else {
- inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ);
+ inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
}
fp(out, "%s/%d @%p #%d%s", buf, p->prefixlen, rn,
@@ -933,7 +926,7 @@ int rfapiShowVncQueries(void *stream, struct prefix *pfx_match)
buf_remain, BUFSIZ);
fp(out, " %-15s %-10s\n",
inet_ntop(m->p.family, &m->p.u.prefix,
- buf_pfx, BUFSIZ),
+ buf_pfx, sizeof(buf_pfx)),
buf_remain);
}
}
@@ -1052,9 +1045,10 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
* Prefix
*/
buf_pfx[0] = 0;
- snprintf(buf_pfx, sizeof(buf_pfx), "%s/%d",
- rfapi_ntop(p->family, &p->u.prefix, buf_ntop, BUFSIZ),
- p->prefixlen);
+ snprintf(
+ buf_pfx, sizeof(buf_pfx), "%s/%d",
+ rfapi_ntop(p->family, &p->u.prefix, buf_ntop, sizeof(buf_ntop)),
+ p->prefixlen);
buf_pfx[BUFSIZ - 1] = 0;
nlines++;
@@ -1065,7 +1059,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)) {
snprintf(buf_un, sizeof(buf_un), "%s",
inet_ntop(pfx_un.family, &pfx_un.u.prefix, buf_ntop,
- BUFSIZ));
+ sizeof(buf_ntop)));
}
bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type);
@@ -1079,7 +1073,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
*/
snprintf(buf_un, sizeof(buf_un), "%s",
inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop,
- BUFSIZ));
+ sizeof(buf_ntop)));
if (bpi->extra) {
uint32_t l = decode_label(&bpi->extra->label[0]);
snprintf(buf_vn, sizeof(buf_vn), "Label: %d", l);
@@ -1090,7 +1084,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
} else {
snprintf(buf_vn, sizeof(buf_vn), "%s",
inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop,
- BUFSIZ));
+ sizeof(buf_ntop)));
}
buf_vn[BUFSIZ - 1] = 0;
buf_un[BUFSIZ - 1] = 0;
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index 04fe1f1249..88f53da35e 100644
--- a/bgpd/subdir.am
+++ b/bgpd/subdir.am
@@ -151,6 +151,9 @@ noinst_HEADERS += \
bgpd/bgp_route.h \
bgpd/bgp_routemap_nb.h \
bgpd/bgp_script.h \
+ bgpd/bgp_snmp.h \
+ bgpd/bgp_snmp_bgp4.h \
+ bgpd/bgp_snmp_bgp4v2.h \
bgpd/bgp_table.h \
bgpd/bgp_updgrp.h \
bgpd/bgp_vpn.h \
@@ -189,7 +192,7 @@ bgpd_bgp_btoa_SOURCES = bgpd/bgp_btoa.c
bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBYANG_LIBS) $(LIBCAP) $(LIBM) $(UST_LIBS)
bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBYANG_LIBS) $(LIBCAP) $(LIBM) $(UST_LIBS)
-bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp.c bgpd/bgp_mplsvpn_snmp.c
+bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp_bgp4.c bgpd/bgp_snmp_bgp4v2.c bgpd/bgp_snmp.c bgpd/bgp_mplsvpn_snmp.c
bgpd_bgpd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
bgpd_bgpd_snmp_la_LDFLAGS = $(MODULE_LDFLAGS)
bgpd_bgpd_snmp_la_LIBADD = lib/libfrrsnmp.la
diff --git a/configure.ac b/configure.ac
index 97c8ca451b..2d9d4f66b1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -636,7 +636,7 @@ AC_ARG_ENABLE([isisd],
AC_ARG_ENABLE([pimd],
AS_HELP_STRING([--disable-pimd], [do not build pimd]))
AC_ARG_ENABLE([pim6d],
- AS_HELP_STRING([--enable-pim6d], [build pim6d]))
+ AS_HELP_STRING([--disable-pim6d], [do not build pim6d]))
AC_ARG_ENABLE([pbrd],
AS_HELP_STRING([--disable-pbrd], [do not build pbrd]))
AC_ARG_ENABLE([sharpd],
@@ -1765,7 +1765,7 @@ AS_IF([test "$enable_pimd" != "no"], [
AC_DEFINE([HAVE_PIMD], [1], [pimd])
])
-AS_IF([test "$enable_pim6d" = "yes"], [
+AS_IF([test "$enable_pim6d" != "no"], [
AC_DEFINE([HAVE_PIM6D], [1], [pim6d])
])
@@ -2078,7 +2078,7 @@ if test "$enable_rpki" = "yes"; then
fi
dnl ------------------------------------
-dnl pimd is not supported on OpenBSD and MacOS
+dnl pimd and pim6d not supported on OpenBSD and MacOS
dnl ------------------------------------
if test "$enable_pimd" != "no"; then
AC_MSG_CHECKING([for pimd OS support])
@@ -2097,6 +2097,19 @@ case "$host_os" in
esac
fi
+if test "$enable_pim6d" != "no"; then
+AC_MSG_CHECKING([for pim6d OS support])
+case "$host_os" in
+ linux*)
+ AC_MSG_RESULT([yes])
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ enable_pim6d="no"
+ ;;
+esac
+fi
+
dnl -------------------------------------
dnl VRRP is only supported on linux
dnl -------------------------------------
@@ -2730,7 +2743,7 @@ AM_CONDITIONAL([BABELD], [test "$enable_babeld" != "no"])
AM_CONDITIONAL([OSPF6D], [test "$enable_ospf6d" != "no"])
AM_CONDITIONAL([ISISD], [test "$enable_isisd" != "no"])
AM_CONDITIONAL([PIMD], [test "$enable_pimd" != "no"])
-AM_CONDITIONAL([PIM6D], [test "$enable_pim6d" = "yes"])
+AM_CONDITIONAL([PIM6D], [test "$enable_pim6d" != "no"])
AM_CONDITIONAL([PBRD], [test "$enable_pbrd" != "no"])
AM_CONDITIONAL([SHARPD], [test "$enable_sharpd" = "yes"])
AM_CONDITIONAL([STATICD], [test "$enable_staticd" != "no"])
diff --git a/debian/changelog b/debian/changelog
index ad43f13e33..e3b6634594 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -4,11 +4,11 @@ frr (8.5~dev-1) UNRELEASED; urgency=medium
-- Donatas Abraitis <donatas@opensourcerouting.org> Tue, 04 Oct 2022 16:00:00 +0500
-frr (8.4~dev-1) UNRELEASED; urgency=medium
+frr (8.4-0) unstable; urgency=medium
- * FRR Dev 8.4
+ * New upstream release FRR 8.4
- -- Jafar Al-Gharaibeh <jafar@atcorp.com> Wed, 20 Jul 2022 10:00:00 +0500
+ -- Jafar Al-Gharaibeh <jafar@atcorp.com> Tue, 01 Nov 2022 10:00:00 +0500
frr (8.3-0) unstable; urgency=medium
diff --git a/debian/rules b/debian/rules
index fdb458e6a8..6305603341 100755
--- a/debian/rules
+++ b/debian/rules
@@ -27,10 +27,10 @@ else
CONF_LUA=--enable-scripting
endif
-ifeq ($(filter pkg.frr.pim6d,$(DEB_BUILD_PROFILES)),)
- CONF_PIM6=--disable-pim6d
-else
+ifeq ($(filter pkg.frr.nopim6d,$(DEB_BUILD_PROFILES)),)
CONF_PIM6=--enable-pim6d
+else
+ CONF_PIM6=--disable-pim6d
endif
export PYTHON=python3
diff --git a/doc/accords/README.md b/doc/accords/README.md
new file mode 100644
index 0000000000..0461b0468b
--- /dev/null
+++ b/doc/accords/README.md
@@ -0,0 +1,32 @@
+FRR accords
+===========
+
+
+This directory contains some text documents with "accords" agreed upon by the
+FRR community. The idea here is that by passing text documents through the
+PR/review process, consensus for work items, design decisions, etc. can be
+established and documented. They can also be changed later by followup PRs if
+consensus shifts. This is intended to reduce friction, and provide more
+transparency for newcomers & less frequent contributors.
+
+Examples of things that could go here:
+
+- agreement on how to fix some deeper-seated existing shortcoming in FRR that
+ might take some time to fix, to get consensus before putting time into it.
+
+- larger design (especially system/package integration) decisions that are not
+ immediately tangible to the code.
+
+- scoping decisions, particularly negative (i.e. we decided at some point that
+ FRR is not the right place for something) - these are otherwise lost in some
+ ancient closed PR, and some new contributor might be unaware and waste time.
+
+Files in this directory are not formatted in any specific way and not rendered
+into documentation. They're intended to be read with your code editor of
+choice.
+
+To avoid misunderstandings, there is one "rule" about wording: the consensus
+actual is worded with "will", "going to", "is" - this reflects the idea that
+when the PR is merged, it *is* community consensus. Words like "should",
+"would" or "might" should be limited to context and reference that is provided
+as rationale for the consensus.
diff --git a/doc/accords/cli-colors b/doc/accords/cli-colors
new file mode 100644
index 0000000000..04bdfc7fae
--- /dev/null
+++ b/doc/accords/cli-colors
@@ -0,0 +1,44 @@
+Adding colors to FRR CLI output
+===============================
+
+
+There were multiple approaches/attempts to get colored output for the CLI into
+FRR, most recently End of 2022 in PR #12497. After some discussion, some items
+crystallized out:
+
+First, generally speaking, colors (or other rich output formatting) must be
+used sparingly. In particular, e.g. "every IP address" is not something to
+color. The output formatting needs to have an actual purpose to improve UX,
+not turn it into a christmas tree.
+
+In the long run, the CLI will hopefully become a YANG frontend. In that case,
+the CLI frontend component is a great place to apply all kinds of output/UI/UX
+features. However, this is a long way off.
+
+That said, an implementation in the current vtysh+daemon ecosystem is not out
+of the question, especially if the use of colors/formatting is limited to
+important places (which is desirable anyway - see general statement above.)
+We don't want to litter formatting all over every single vty_out call.
+
+A color option on a per-command/DEFUN level (i.e. the way `[json]` is done) was
+rejected. The decision to color output must take information from vtysh's
+environment into account, notably the TERM environment variable, the NO_COLOR
+environment variable, and whether stdout is a terminal or not. An explicit
+`--color` switch (or `terminal color` vtysh command, or other similar things)
+is needed too. To be clear, the switch must not be on individual commands, it
+needs to be on the vtysh session level.
+
+Lastly, the output pager needs to work with this.
+
+
+Suggested implementation
+------------------------
+
+(not part of the consensus / accord, only to record discussion)
+
+As far as discussion went, the most promising approach to actually implement
+this is to put some type of unconditional formatting tag into daemon's vty_out
+calls. This would be some escape-like sequence - an actual ANSI color code
+itself is not particularly readable or pretty, though that would work as well.
+vtysh would then, while passing through the output from the daemons, replace or
+remove these tags according to terminal/user settings.
diff --git a/doc/accords/frr-service-is-watchfrr b/doc/accords/frr-service-is-watchfrr
new file mode 100644
index 0000000000..2301c83b10
--- /dev/null
+++ b/doc/accords/frr-service-is-watchfrr
@@ -0,0 +1,16 @@
+The "FRR" service unit is watchfrr
+==================================
+
+
+"FRR" on the distribution/OS level is one service (generally called "frr").
+Exposing individual daemons (zebra, staticd, bgpd, ...) as service units does
+not match FRR's internal expectations.
+
+At some future point, watchfrr will add functionality to receive "router bgp",
+"router ospf" etc. commands (or their YANG variants) and automatically start
+the required daemons. In particular with multi-instance setups, this will
+simplify config (no more mucking around /etc/frr/daemons - if watchfrr
+understands which daemons are needed by a given config, the daemons file is
+pointless.)
+
+This to some degree assumes an "integrated-config world".
diff --git a/doc/accords/integrated-config-wins b/doc/accords/integrated-config-wins
new file mode 100644
index 0000000000..5a02b998e2
--- /dev/null
+++ b/doc/accords/integrated-config-wins
@@ -0,0 +1,10 @@
+Integrated config wins
+======================
+
+
+The use of split-configuration setups (zebra.conf, staticd.conf, bgpd.conf,
+etc.) in FRR is considered deprecated and will go away at some point.
+
+At this point there is no timeline yet on removing split-config support, and
+this needs to go through an extensive deprecation period with increasingly
+loud user warnings.
diff --git a/doc/developer/building-frr-for-freebsd13.rst b/doc/developer/building-frr-for-freebsd13.rst
new file mode 100644
index 0000000000..0bc8277930
--- /dev/null
+++ b/doc/developer/building-frr-for-freebsd13.rst
@@ -0,0 +1,122 @@
+FreeBSD 13
+==========
+
+FreeBSD 13 restrictions:
+------------------------
+
+- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
+ (4.5 or higher). LDP can be built, but may have limited use without
+ MPLS
+- PIM for IPv6 is not currently supported on ``FreeBSD``.
+
+Install required packages
+-------------------------
+
+Add packages: (Allow the install of the package management tool if this
+is first package install and asked)
+
+.. code-block:: shell
+
+ pkg install git autoconf automake libtool gmake json-c pkgconf \
+ bison py39-pytest c-ares py39-sphinx texinfo libunwind libyang2
+
+.. include:: building-libunwind-note.rst
+
+Get FRR, compile it and install it (from Git)
+---------------------------------------------
+
+**This assumes you want to build and install FRR from source and not using any
+packages**
+
+Add frr group and user
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: shell
+
+ pw groupadd frr -g 101
+ pw groupadd frrvty -g 102
+ pw adduser frr -g 101 -u 101 -G 102 -c "FRR suite" \
+ -d /usr/local/etc/frr -s /usr/sbin/nologin
+
+
+Download Source, configure and compile it
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+(You may prefer different options on configure statement. These are just
+an example)
+
+.. code-block:: shell
+
+ git clone https://github.com/frrouting/frr.git frr
+ cd frr
+ ./bootstrap.sh
+ export MAKE=gmake LDFLAGS=-L/usr/local/lib CPPFLAGS=-I/usr/local/include
+ ./configure \
+ --sysconfdir=/usr/local/etc/frr \
+ --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \
+ --localstatedir=/var/run/frr \
+ --prefix=/usr/local \
+ --enable-multipath=64 \
+ --enable-user=frr \
+ --enable-group=frr \
+ --enable-vty-group=frrvty \
+ --enable-configfile-mask=0640 \
+ --enable-logfile-mask=0640 \
+ --enable-fpm \
+ --with-pkg-git-version \
+ --with-pkg-extra-version=-MyOwnFRRVersion
+ gmake
+ gmake check
+ sudo gmake install
+
+Create empty FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: shell
+
+ sudo mkdir /usr/local/etc/frr
+
+For integrated config file:
+
+.. code-block:: shell
+
+ sudo touch /usr/local/etc/frr/frr.conf
+
+For individual config files:
+
+.. note:: Integrated config is preferred to individual config.
+
+.. code-block:: shell
+
+ sudo touch /usr/local/etc/frr/babeld.conf
+ sudo touch /usr/local/etc/frr/bfdd.conf
+ sudo touch /usr/local/etc/frr/bgpd.conf
+ sudo touch /usr/local/etc/frr/eigrpd.conf
+ sudo touch /usr/local/etc/frr/isisd.conf
+ sudo touch /usr/local/etc/frr/ldpd.conf
+ sudo touch /usr/local/etc/frr/nhrpd.conf
+ sudo touch /usr/local/etc/frr/ospf6d.conf
+ sudo touch /usr/local/etc/frr/ospfd.conf
+ sudo touch /usr/local/etc/frr/pbrd.conf
+ sudo touch /usr/local/etc/frr/pimd.conf
+ sudo touch /usr/local/etc/frr/ripd.conf
+ sudo touch /usr/local/etc/frr/ripngd.conf
+ sudo touch /usr/local/etc/frr/staticd.conf
+ sudo touch /usr/local/etc/frr/zebra.conf
+ sudo chown -R frr:frr /usr/local/etc/frr/
+ sudo touch /usr/local/etc/frr/vtysh.conf
+ sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
+ sudo chmod 640 /usr/local/etc/frr/*.conf
+
+Enable IP & IPv6 forwarding
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Add the following lines to the end of ``/etc/sysctl.conf``:
+
+::
+
+ # Routing: We need to forward packets
+ net.inet.ip.forwarding=1
+ net.inet6.ip6.forwarding=1
+
+**Reboot** or use ``sysctl`` to apply the same config to the running system.
diff --git a/doc/developer/building.rst b/doc/developer/building.rst
index c687ba8dc8..2d8cc209b0 100644
--- a/doc/developer/building.rst
+++ b/doc/developer/building.rst
@@ -16,9 +16,10 @@ Building FRR
building-frr-for-debian9
building-frr-for-fedora
building-frr-for-opensuse
+ building-frr-for-freebsd9
building-frr-for-freebsd10
building-frr-for-freebsd11
- building-frr-for-freebsd9
+ building-frr-for-freebsd13
building-frr-for-netbsd6
building-frr-for-netbsd7
building-frr-for-openbsd6
diff --git a/doc/developer/fpm.rst b/doc/developer/fpm.rst
index 9849869133..56d33671d2 100644
--- a/doc/developer/fpm.rst
+++ b/doc/developer/fpm.rst
@@ -101,3 +101,19 @@ Data
^^^^
The netlink or protobuf message payload.
+
+
+Route Status Notification from ASIC
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The dplane_fpm_nl has the ability to read route netlink messages
+from the underlying fpm implementation that can tell zebra
+whether or not the route has been Offloaded/Failed or Trapped.
+The end developer must send the data up the same socket that has
+been created to listen for FPM messages from Zebra. The data sent
+must have a Frame Header with Version set to 1, Message Type set to 1
+and an appropriate message Length. The message data must contain
+a RTM_NEWROUTE netlink message that sends the prefix and nexthops
+associated with the route. Finally rtm_flags must contain
+RTM_F_OFFLOAD, RTM_F_TRAP and or RTM_F_OFFLOAD_FAILED to signify
+what has happened to the route in the ASIC.
diff --git a/doc/developer/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst
index 4ef0ca8416..6ba44b9c49 100644
--- a/doc/developer/frr-release-procedure.rst
+++ b/doc/developer/frr-release-procedure.rst
@@ -235,6 +235,9 @@ Stage 3 - Publish
#. Deploy the updated ``frr-www`` on the frrouting.org web server and verify
that the announcement text is visible.
+#. Update readthedocs.org (Default Version) for https://docs.frrouting.org to
+ be the version of this latest release.
+
#. Send an email to ``announce@lists.frrouting.org``. The text of this email
should include text as appropriate from the GitHub release and a link to the
GitHub release, Debian repository, and RPM repository.
diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst
index 9aeb78c4fd..c2c3b7e7e1 100644
--- a/doc/developer/packaging-debian.rst
+++ b/doc/developer/packaging-debian.rst
@@ -66,7 +66,7 @@ buster.)
+----------------+-------------------+-----------------------------------------+
| pkg.frr.lua | pkg.frr.nolua | builds lua scripting extension |
+----------------+-------------------+-----------------------------------------+
- | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (work in progress) |
+ | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (default enabled) |
+----------------+-------------------+-----------------------------------------+
* 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 9e64b912f3..d88f449926 100644
--- a/doc/developer/packaging-redhat.rst
+++ b/doc/developer/packaging-redhat.rst
@@ -83,6 +83,7 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24.
%{!?with_watchfrr: %global with_watchfrr 1 }
%{!?with_bgp_vnc: %global with_bgp_vnc 0 }
%{!?with_pimd: %global with_pimd 1 }
+ %{!?with_pim6d: %global with_pim6d 1 }
%{!?with_rpki: %global with_rpki 0 }
8. Build the RPM::
diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am
index c8654d6725..9cf14a1966 100644
--- a/doc/developer/subdir.am
+++ b/doc/developer/subdir.am
@@ -14,6 +14,7 @@ dev_RSTFILES = \
doc/developer/building-frr-for-opensuse.rst \
doc/developer/building-frr-for-freebsd10.rst \
doc/developer/building-frr-for-freebsd11.rst \
+ doc/developer/building-frr-for-freebsd13.rst \
doc/developer/building-frr-for-freebsd9.rst \
doc/developer/building-frr-for-netbsd6.rst \
doc/developer/building-frr-for-netbsd7.rst \
diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst
index 688ce545fb..b0d320b5ea 100644
--- a/doc/developer/workflow.rst
+++ b/doc/developer/workflow.rst
@@ -139,6 +139,10 @@ March/July/November. Walking backwards from this date:
version. Once the release is done, whatever updates we make to changelog
files on the release branch need to be cherry-picked to the master branch.
+ Update essential dates in advance for reference table (below) when
+ the next freeze, dev/X.Y, RC, and release phases are scheduled. This should
+ go in the ``master`` branch.
+
- 2 weeks earlier, a ``frr-X.Y-rc`` release candidate is tagged.
.. code-block:: console
@@ -163,15 +167,29 @@ as early as possible, i.e. the first 2-week window.
For reference, the expected release schedule according to the above is:
+---------+------------+------------+------------+------------+------------+
-| Release | 2022-07-05 | 2022-11-01 | 2023-03-07 | 2023-07-04 | 2023-10-31 |
+| Release | 2023-03-07 | 2023-07-04 | 2023-10-31 | 2024-02-27 | 2024-06-25 |
+---------+------------+------------+------------+------------+------------+
-| RC | 2022-06-21 | 2022-10-18 | 2023-02-21 | 2023-06-20 | 2023-10-17 |
+| RC | 2023-02-21 | 2023-06-20 | 2023-10-17 | 2024-02-13 | 2024-06-11 |
+---------+------------+------------+------------+------------+------------+
-| dev/X.Y | 2022-06-07 | 2022-10-04 | 2023-02-07 | 2023-06-06 | 2023-10-03 |
+| dev/X.Y | 2023-02-07 | 2023-06-06 | 2023-10-03 | 2024-01-30 | 2024-05-28 |
+---------+------------+------------+------------+------------+------------+
-| freeze | 2022-05-24 | 2022-09-20 | 2023-01-24 | 2023-05-23 | 2023-09-19 |
+| freeze | 2023-01-24 | 2023-05-23 | 2023-09-19 | 2024-01-16 | 2024-05-14 |
+---------+------------+------------+------------+------------+------------+
+Here is the hint on how to get the dates easily:
+
+ .. code-block:: console
+
+ ~$ # Last freeze date was 2023-09-19
+ ~$ date +%F --date='2023-09-19 +119 days' # Next freeze date
+ 2024-01-16
+ ~$ date +%F --date='2024-01-16 +14 days' # Next dev/X.Y date
+ 2024-01-30
+ ~$ date +%F --date='2024-01-30 +14 days' # Next RC date
+ 2024-02-13
+ ~$ date +%F --date='2024-02-13 +14 days' # Next Release date
+ 2024-02-27
+
Each release is managed by one or more volunteer release managers from the FRR
community. These release managers are expected to handle the branch for a period
of one year. To spread and distribute this workload, this should be rotated for
@@ -290,6 +308,21 @@ your changes is usually not required and will be added based on your commit
messages by the maintainers. However, you are free to include an update to the
changelog with some better description.
+Accords: non-code community consensus
+=====================================
+
+The FRR repository has a place for "accords" - these are items of
+consideration for FRR that influence how we work as a community, but either
+haven't resulted in code *yet*, or may *never* result in code being written.
+They are placed in the ``doc/accords/`` directory.
+
+The general idea is to simply pass small blurbs of text through our normal PR
+procedures, giving them the same visibility, comment and review mechanisms as
+code PRs - and changing them later is another PR. Please refer to the README
+file in ``doc/accords/`` for further details. The file names of items in that
+directory are hopefully helpful in determining whether some of them might be
+relevant to your work.
+
Submitting Patches and Enhancements
===================================
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 7679a377eb..4a64d8f949 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -617,6 +617,10 @@ Terminal Mode Commands
usage is printed sequentially. You can specify the daemon's name to print
only its memory usage.
+.. clicmd:: show motd
+
+ Show current motd banner.
+
.. clicmd:: show history
Dump the vtysh cli history.
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 4a812a75e9..f751eb3a75 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1704,6 +1704,11 @@ Configuring Peers
Default: disabled.
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> graceful-shutdown
+
+ Mark all routes from this neighbor as less preferred by setting ``graceful-shutdown``
+ community, and local-preference to 0.
+
.. clicmd:: bgp fast-external-failover
This command causes bgp to take down ebgp peers immediately
@@ -2413,9 +2418,9 @@ in AS 7675, the announced routes' local preference value will be set to 80.
The following configuration is an example of BGP route filtering using
communities attribute. This configuration only permit BGP routes which has BGP
-communities value ``0:80`` or ``0:90``. The network operator can set special
-internal communities value at BGP border router, then limit the BGP route
-announcements into the internal network.
+communities value (``0:80`` and ``0:90``) or ``0:100``. The network operator can
+set special internal communities value at BGP border router, then limit the
+BGP route announcements into the internal network.
.. code-block:: frr
@@ -2426,6 +2431,7 @@ announcements into the internal network.
exit-address-family
!
bgp community-list 1 permit 0:80 0:90
+ bgp community-list 1 permit 0:100
!
route-map RMAP permit in
match community 1
@@ -2969,6 +2975,25 @@ sysctl configurations:
For more information, see ``man 7 arp``.
+.. _bgp-enabling-evpn:
+
+Enabling EVPN
+^^^^^^^^^^^^^
+
+EVPN should be enabled on the BGP instance corresponding to the VRF acting as
+the underlay for the VXLAN tunneling. In most circumstances this will be the
+default VRF. The command to enable EVPN for a BGP instance is
+``advertise-all-vni`` which lives under ``address-family l2vpn evpn``:
+
+.. code-block:: frr
+
+ router bgp 65001
+ !
+ address-family l2vpn evpn
+ advertise-all-vni
+
+A more comprehensive configuration example can be found in the :ref:`evpn` page.
+
.. _bgp-evpn-l3-route-targets:
EVPN L3 Route-Targets
@@ -4300,6 +4325,17 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
If ``json`` option is specified, output is displayed in JSON format.
+.. clicmd:: show [ip] bgp [afi] [safi] [all] detail-routes
+
+ Display the detailed version of all routes. The same format as using
+ ``show [ip] bgp [afi] [safi] PREFIX``, but for the whole BGP table.
+
+ If ``all`` option is specified, ``ip`` keyword is ignored and,
+ routes displayed for all AFIs and SAFIs.
+
+ If ``afi`` is specified, with ``all`` option, routes will be displayed for
+ each SAFI in the selected AFI.
+
.. _bgp-display-routes-by-community:
Displaying Routes by Community Attribute
diff --git a/doc/user/evpn.rst b/doc/user/evpn.rst
new file mode 100644
index 0000000000..c8052803cc
--- /dev/null
+++ b/doc/user/evpn.rst
@@ -0,0 +1,504 @@
+.. _evpn:
+
+****
+EVPN
+****
+
+:abbr:`EVPN` stands for Ethernet Virtual Private Network. This is an extension
+of BGP that enables the signaling of bridged (L2) and routed (L3) VPNs over a
+common network. EVPN is described in :rfc:`7432` and is updated by several
+additional RFCs and IETF drafts including :rfc:`9135` (Integrated Routing
+and Bridging in Ethernet VPN), :rfc:`9136` (IP Prefix Advertisement in Ethernet
+VPN), :rfc:`8584` (Framework for Ethernet VPN Designated Forwarder Election
+Extensibility), and :rfc:`8365` (A Network Virtualization Overlay Solution Using
+Ethernet VPN). FRR supports All-Active Layer-2 Multihoming for devices (MHD) via
+LACP Ethernet Segments as well as both Symmetric and Asymmetric IRB.
+FRR implements MAC-VRFs using a "VLAN-Based Service Interface" (:rfc:`7432`)
+and performs processing of Symmetric IRB routes following the
+"Interface-less IP-VRF-to-IP-VRF Model" (:rfc:`9136`).
+
+.. _evpn-concepts:
+
+EVPN Concepts
+=============
+BGP-EVPN is the control plane for the transport of Ethernet frames, regardless
+of whether those frames are bridged or routed. In the case of a VLAN-Based
+Service Interface with VXLAN encap, a single VNI is used to represent an EVPN
+Instance (EVI) and will have its own Route Distinguisher and set of
+Import/Export Route-Targets.
+
+A VNI is considered to be either Layer-2 (tied to a MAC-VRF) or Layer-3
+(tied to an IP-VRF), which indicates what kind of information is represented by
+the VRF. An IP-VRF represents a routing table (operating in much the same way as
+a VRF traditionally operates in L3VPN), while a MAC-VRF represents a bridging
+table i.e. MAC (fdb) and ARP/NDP entries.
+
+A MAC-VRF can be thought of as a VLAN with or without an SVI associated with it.
+An SVI is a Layer-3 interface bound to a bridging domain. In Linux an SVI can
+either be a traditional bridge or a VLAN subinterface of a VLAN-aware bridge.
+If there is an SVI for the VLAN, ARP/NDP entries can be bound to the MACs within
+the broadcast domain. Without an SVI, the VLAN operates in traditional L2
+fashion and MACs are the only type of host addresses known within the VLAN.
+
+In the same way that there can be a many-to-one relationship of SVIs to a VRF,
+there can also be a many-to-one relationship of MAC-VRFs (L2VNIs) to an IP-VRF
+(L3VNI). In FRR the L3VNI association for an L2VNI is determined by the
+presence of an SVI for the VLAN and the VRF membership of the SVI.
+If an L2VNI does not have an SVI or its SVI is not enslaved to a VRF, the L2VNI
+will be associated with the "default" VRF. If an L2VNI has an SVI whose master
+device is a VRF, then that L2VNI will be associated with its master VRF.
+
+.. _evpn-frr-configuration:
+
+FRR Configuration
+=================
+FRR learns about the system's Linux network interface configuration from the
+kernel via Netlink, however it does not manage network interfaces directly.
+The following sections will include examples of Linux interface configurations
+that are compatible with FRR's EVPN implementation. While there are multiple
+interface managers that can setup a proper kernel config (e.g. ifupdown2),
+these examples will use iproute2 to add/configure the interfaces.
+
+All of the examples will follow the same basic setup but use different, yet
+compatible, interface configurations.
+
+In this example we will setup the following:
+
+* An IP-VRF named vrf1, associated with L3VNI 100
+* An IP-VRF named vrf2, associated with L3VNI 200
+* An IP-VRF named vrf3, with no L3VNI associations
+* A MAC-VRF using VLAN 10, associated with L2VNI 110 and IP-VRF vrf1
+* A MAC-VRF using VLAN 20, associated with L2VNI 220 and IP-VRF vrf2
+* A MAC-VRF using VLAN 30, associated with L2VNI 330 and IP-VRF vrf3
+* A MAC-VRF using VLAN 40, associated with L2VNI 440 and IP-VRF default
+* A MAC-VRF using VLAN 50, associated with L2VNI 550 and operating L2-Only
+
+.. _evpn-sample-configuration:
+
+Sample Configuration
+--------------------
+This is a sample FRR configuration that implements the above EVPN environment.
+The first snippet will be the config in its entiretly, then each config element
+will be explained individually later in the document.
+
+The following snippet will result in a functional EVPN control plane if the
+corresponding Linux interface configuration is correct, compatible, and active:
+
+.. code-block:: frr
+
+ vrf vrf1
+ vni 100
+ exit-vrf
+ !
+ vrf vrf2
+ vni 200
+ exit-vrf
+ !
+ router bgp 4200000000
+ neighbor 192.168.122.12 remote-as internal
+ !
+ address-family ipv4 unicast
+ network 100.64.0.1/32
+ exit-address-family
+ !
+ address-family l2vpn evpn
+ neighbor 192.168.122.12 activate
+ advertise-all-vni
+ advertise-svi-ip
+ exit-address-family
+ exit
+ !
+ router bgp 4200000000 vrf vrf1
+ !
+ address-family ipv4 unicast
+ redistribute static
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ redistribute static
+ exit-address-family
+ !
+ address-family l2vpn evpn
+ advertise ipv4 unicast
+ advertise ipv6 unicast
+ exit-address-family
+ exit
+ !
+ router bgp 4200000000 vrf vrf2
+ !
+ address-family ipv4 unicast
+ redistribute static
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ redistribute static
+ exit-address-family
+ !
+ address-family l2vpn evpn
+ advertise ipv4 unicast
+ advertise ipv6 unicast
+ exit-address-family
+ exit
+
+A VRF will get its L3VNI association as a result of the ``vni`` command under
+the ``vrf`` stanza. Until this L3VNI association is made, zebra will discover
+the VNI from netlink but will consider it to be an L2VNI. The current L2 vs L3
+context of a VNI can be seen in the output of ``show evpn vni``.
+
+In this configuration we are telling zebra to consider VXLAN-ID 100 to be the
+L3VNI for vrf1 and VXLAN-ID 200 to be the L3VNI for vrf2.
+
+.. code-block:: frr
+
+ vrf vrf1
+ vni 100
+ exit-vrf
+ !
+ vrf vrf2
+ vni 200
+ exit-vrf
+
+The VTEP-IP (100.64.0.1) needs to be reachable by other VTEPs in the EVPN
+environment in order for VXLAN decapsulation to function. In this example we
+will advertise our local VTEP-IP using BGP (via the ``network`` statement), but
+static routes or other routing protocols like IS-IS or OSPF can also be used.
+
+In order to enable EVPN for a BGP instance, we must use the command
+``advertise-all-vni``. In this example we will be using the default VRF to
+carry the l2vpn evpn address-family, so we will enable EVPN for the default VRF.
+
+In this example, we plan to exchange EVPN routes with 192.168.122.12, so we
+will activate the l2vpn evpn address-family for this peer in order to allow
+EVPN NLRI to be advertised and received.
+
+The ``advertise-svi-ip`` command also belongs in the BGP instance where EVPN is
+enabled. This command tells FRR to originate "self" Type-2 routes for all the
+MAC/IP pairs associated with the local SVI interfaces.
+
+.. code-block:: frr
+
+ router bgp 4200000000
+ neighbor 192.168.122.12 remote-as internal
+ !
+ address-family ipv4 unicast
+ network 100.64.0.1/32
+ exit-address-family
+ !
+ address-family l2vpn evpn
+ neighbor 192.168.122.12 activate
+ advertise-all-vni
+ advertise-svi-ip
+ exit-address-family
+ exit
+
+IPv4 and IPv6 BGP Prefixes from an IP-VRF are not exported to EVPN as Type-5
+routes until the respective ``advertise <afi> unicast`` command has been
+configured in the BGP instance of the VRF in question. All routes in the BGP
+RIB (locally originated, learned from a peer, or leaked from another VRF) will
+be eligible to be exported to EVPN so long as they are valid and selected in
+the VRF's unicast table.
+
+In this example, the BGP instances for vrf1 and vrf2 will have their static
+routes redistributed into the BGP loc-rib for the ipv4 unicast and ipv6 unicast
+address-families via the ``redistribute static`` statements. These unicast
+prefixes will then be exported into EVPN as Type-5 routes as a result of the
+``advertise ipv4 unicast`` and ``advertise ipv6 unicast`` commands.
+
+.. code-block:: frr
+
+ router bgp 4200000000 vrf vrf1
+ !
+ address-family ipv4 unicast
+ redistribute static
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ redistribute static
+ exit-address-family
+ !
+ address-family l2vpn evpn
+ advertise ipv4 unicast
+ advertise ipv6 unicast
+ exit-address-family
+ exit
+ !
+ router bgp 4200000000 vrf vrf2
+ !
+ address-family ipv4 unicast
+ redistribute static
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ redistribute static
+ exit-address-family
+ !
+ address-family l2vpn evpn
+ advertise ipv4 unicast
+ advertise ipv6 unicast
+ exit-address-family
+ exit
+
+.. _evpn-linux-interface-configuration:
+
+Linux Interface Configuration
+=============================
+The Linux kernel offers several options for configuring netdevices for an
+EVPN-VXLAN environment. The following section will include samples of a few
+netdev configurations that are compatible with FRR which implement the
+environment described above.
+
+Some high-level config considerations:
+
+* The local VTEP-IP should always be set to a reachable IP on the lo device.
+* An L3VNI should always have an SVI (aka the L3-SVI).
+* An L3-SVI should not be assigned an IP address, link-local or otherwise.
+
+ * IPv6 address autoconfiguration can be disabled via ``addrgenmode none``.
+
+* An SVI for an L2VNI is only needed for routing (IRB) or ARP/ND suppression.
+
+ * ARP/ND suppression is a kernel function, it is not managed by FRR.
+ * ARP/ND suppression is enabled per bridge_slave via ``neigh_suppress``.
+ * ARP/ND suppression should only be enabled on vxlan interfaces.
+ * IPv4/IPv6 forwarding should be disabled on SVIs not used for routing (IRB).
+
+* Dynamic MAC/VTEP learning should be disabled on VXLAN interfaces used in EVPN.
+
+ * Dynamic MAC learning is a function of the kernel bridge driver, not FRR.
+ * Dynamic MAC learning is toggled per bridge_slave via ``learning {on|off}``.
+ * Dynamic VTEP learning is a function of the kernel vxlan driver, not FRR.
+ * Dynamic VTEP learning is toggled per vxlan interface via ``[no]learning``.
+
+* The VXLAN interfaces should not have a ``remote`` VTEP defined.
+
+ * Remote VTEPs are learned via EVPN, so static VTEPs are unnecessary.
+
+.. _evpn-traditional-bridge-traditional-vxlan-devices:
+
+Traditional Bridges and Traditional VXLAN Devices
+-------------------------------------------------
+In the traditional bridge model, we use a separate ``bridge`` interface per
+MAC-VRF which acts as the SVI for that broadcast domain. A bridge is considered
+"traditional" if ``vlan_filtering`` is set to ``0`` (disabled) which indicates
+the bridge only has one broadcast domain which does not consider VLAN tags.
+Similarly, only one VNI is carried by each "traditional" ``vxlan`` interface.
+So in this deployment model, each VXLAN-enabled broadcast domain will have one
+traditional vxlan interface enslaved to one traditional bridge.
+
+Bridges created for an L3VNI broadcast domain should only have one member: the
+L3VNI vxlan device. Bridges created for an L2VNI broadcast domain generally
+have multiple members: the L2VNI vxlan device, plus any host/network ports
+where the L2 domain will be carried.
+
+To carry the broadcast domains of multiple traditional bridges over the same
+host/network port, a tagged ``vlan`` sub-interface of the port must be created
+per broadcast domain. The vlan sub-interfaces would then be enslaved to the
+traditional bridge, ensuring that only packets tagged with the expected VID are
+associated with the expected broadcast domain.
+
+.. code-block:: shell
+
+ ###################
+ ## vxlan vtep-ip ##
+ ###################
+ ip addr add 100.64.0.1/32 dev lo
+
+ #############################
+ ## ip-vrf vrf1 / l3vni 100 ##
+ #############################
+ ip link add vrf1 type vrf table 1100
+ ip link set vrf1 up
+ ip link add br100 type bridge
+ ip link set br100 master vrf1 addrgenmode none
+ ip link set br100 addr aa:bb:cc:00:00:64
+ ip link add vni100 type vxlan local 100.64.0.1 dstport 4789 id 100 nolearning
+ ip link set vni100 master br100 addrgenmode none
+ ip link set vni100 type bridge_slave neigh_suppress on learning off
+ ip link set vni100 up
+ ip link set br100 up
+
+ #############################
+ ## ip-vrf vrf2 / l3vni 200 ##
+ #############################
+ ip link add vrf2 type vrf table 1200
+ ip link set vrf2 up
+ ip link add br200 type bridge
+ ip link set br200 master vrf2 addrgenmode none
+ ip link set br200 addr aa:bb:cc:00:00:c8
+ ip link add vni200 type vxlan local 100.64.0.1 dstport 4789 id 200 nolearning
+ ip link set vni200 master br200 addrgenmode none
+ ip link set vni200 type bridge_slave neigh_suppress on learning off
+ ip link set vni200 up
+ ip link set br200 up
+
+ #################
+ ## ip-vrf vrf3 ##
+ #################
+ ip link add vrf3 type vrf table 1300
+ ip link set vrf3 up
+
+ ###############
+ ## l2vni 110 ##
+ ###############
+ ip link add br10 type bridge
+ ip link set br10 master vrf1
+ ip link set br10 addr aa:bb:cc:00:00:6e
+ ip addr add 10.0.10.1/24 dev br10
+ ip addr add 2001:db8:0:10::1/64 dev br10
+ ip link add vni110 type vxlan local 100.64.0.1 dstport 4789 id 110 nolearning
+ ip link set vni110 master br10 addrgenmode none
+ ip link set vni110 type bridge_slave neigh_suppress on learning off
+ ip link set vni110 up
+ ip link set br10 up
+
+ ###############
+ ## l2vni 220 ##
+ ###############
+ ip link add br20 type bridge
+ ip link set br20 master vrf2
+ ip link set br20 addr aa:bb:cc:00:00:dc
+ ip addr add 10.0.20.1/24 dev br20
+ ip addr add 2001:db8:0:20::1/64 dev br20
+ ip link add vni220 type vxlan local 100.64.0.1 dstport 4789 id 220 nolearning
+ ip link set vni220 master br20 addrgenmode none
+ ip link set vni220 type bridge_slave neigh_suppress on learning off
+ ip link set vni220 up
+ ip link set br20 up
+
+ ###############
+ ## l2vni 330 ##
+ ###############
+ ip link add br30 type bridge
+ ip link set br30 master vrf3
+ ip link set br30 addr aa:bb:cc:00:01:4a
+ ip addr add 10.0.30.1/24 dev br30
+ ip addr add 2001:db8:0:30::1/64 dev br30
+ ip link add vni330 type vxlan local 100.64.0.1 dstport 4789 id 330 nolearning
+ ip link set vni330 master br30 addrgenmode none
+ ip link set vni330 type bridge_slave neigh_suppress on learning off
+ ip link set vni330 up
+ ip link set br30 up
+
+ ###############
+ ## l2vni 440 ##
+ ###############
+ ip link add br40 type bridge
+ ip link set br40 addr aa:bb:cc:00:01:b8
+ ip addr add 10.0.40.1/24 dev br40
+ ip addr add 2001:db8:0:40::1/64 dev br40
+ ip link add vni440 type vxlan local 100.64.0.1 dstport 4789 id 440 nolearning
+ ip link set vni440 master br40 addrgenmode none
+ ip link set vni440 type bridge_slave neigh_suppress on learning off
+ ip link set vni440 up
+ ip link set br40 up
+
+ ###############
+ ## l2vni 550 ##
+ ###############
+ ip link add br50 type bridge
+ ip link set br50 addrgenmode none
+ ip link set br50 addr aa:bb:cc:00:02:26
+ ip link add vni550 type vxlan local 100.64.0.1 dstport 4789 id 550 nolearning
+ ip link set vni550 master br50 addrgenmode none
+ ip link set vni550 type bridge_slave neigh_suppress on learning off
+ sysctl -w net.ipv4.conf.br50.forwarding=0
+ sysctl -w net.ipv6.conf.br50.forwarding=0
+ ip link set vni550 up
+ ip link set br50 up
+
+ ##################
+ ## create vlan subinterface of eth0 for each l2vni vlan and enslave each
+ ## subinterface to the corresponding bridge
+ ##################
+ ip link set eth0 up
+ for i in 10 20 30 40 50; do
+ ip link add link eth0 name eth0.$i type vlan id $i;
+ ip link set eth0.$i master br$i;
+ ip link set eth0.$i up;
+ done
+
+
+To begin with, it creates a ``vrf`` interface named "vrf1" that is bound to the
+kernel routing table with ID 1100. This will represent the IP-VRF "vrf1" which
+we will later allocate an L3VNI for.
+
+.. code-block:: shell
+
+ ip link add vrf1 type vrf table 1100
+
+This block creates a traditional ``bridge`` interface named "br100", binds it to
+the VRF named "vrf1", disables IPv6 address autoconfiguration, and statically
+defines the MAC address of "br100". This traditional bridge is used for the
+L3VNI broadcast domain mapping to VRF "vrf1", i.e. "br100" is vrf1's L3-SVI.
+
+.. code-block:: shell
+
+ ip link add br100 type bridge
+ ip link set br100 master vrf1 addrgenmode none
+ ip link set br100 addr aa:bb:cc:00:00:64
+
+Here a traditional ``vxlan`` interface is created with the name "vni100" which
+uses a VTEP-IP of 100.64.0.1, carries VNI 100, and has Dynamic VTEP learning
+disabled. IPv6 address autoconfiguration is disabled for "vni100", then the
+interface is enslaved to "br100", ARP/ND suppression is enabled, and Dynamic
+MAC Learning is disabled.
+
+.. code-block:: shell
+
+ ip link add vni100 type vxlan local 100.64.0.1 dstport 4789 id 100 nolearning
+ ip link set vni100 master br100 addrgenmode none
+ ip link set vni100 type bridge_slave neigh_suppress on learning off
+
+This completes the necessary configuration for a VRF and L3VNI.
+
+Here a traditional bridge named "br10" is created. We add "br10" to "vrf1" by
+setting "vrf1" as the ``master`` of "br10". It is not necessary to set the SVI
+MAC statically, but it is done here for consistency's sake. Since "br10" will
+be used for routing, IPv4 and IPv6 addresses are also added to the SVI.
+
+.. code-block:: shell
+
+ ip link add br10 type bridge
+ ip link set br10 master vrf1
+ ip link set br10 addr aa:bb:cc:00:00:6e
+ ip addr add 10.0.10.1/24 dev br10
+ ip addr add 2001:db8:0:10::1/64 dev br10
+
+If the SVI will not be used for routing, IP addresses should not be assigned to
+the SVI interface and IPv4/IPv6 "forwarding" should be disabled for the SVI via
+the appropriate sysctl nodes.
+
+.. code-block:: shell
+
+ sysctl -w net.ipv4.conf.<ifname>.forwarding=0
+ sysctl -w net.ipv6.conf.<ifname>.forwarding=0
+
+The following commands create a ``vxlan`` interface for VNI 100. Other than the
+VNI, The interface settings are the same for an L2VNI as they are for an L3VNI.
+
+.. code-block:: shell
+
+ ip link add vni110 type vxlan local 100.64.0.1 dstport 4789 id 110 nolearning
+ ip link set vni110 master br10 addrgenmode none
+ ip link set vni110 type bridge_slave neigh_suppress on learning off
+
+Finally, to limit a traditional bridge's broadcast domain to traffic matching
+specific VLAN-IDs, ``vlan`` subinterfaces of a host/network port need to be
+setup. This example shows the creation of a VLAN subinterface of "eth0"
+matching VID 10 with the name "eth0.10". By enslaving "eth0.10" to "br10"
+(instead of "eth0") we ensure that only Ethernet frames ingressing "eth0"
+tagged with VID 10 will be associated with the "br10" broadcast domain.
+
+.. code-block:: shell
+
+ ip link add link eth0 name eth0.10 type vlan id 10
+ ip link set eth0.10 master br10
+
+If you do not want to restrict the broadcast domain by VLAN-ID, you can skip
+the creation of the VLAN subinterfaces and directly enslave "eth0" to "br10".
+
+.. code-block:: shell
+
+ ip link set eth0 master br10
+
+This completes the necessary configuration for an L2VNI.
diff --git a/doc/user/index.rst b/doc/user/index.rst
index c8ad85c0c7..8b9b7e5af7 100644
--- a/doc/user/index.rst
+++ b/doc/user/index.rst
@@ -49,6 +49,7 @@ Protocols
fabricd
ldpd
eigrpd
+ evpn
isisd
nhrpd
ospfd
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 181a6b2f36..0dff2ea448 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -782,7 +782,7 @@ Showing Information
.. _show-ip-ospf:
-.. clicmd:: show ip ospf [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] [json]
Show information on a variety of general OSPF and area state and
configuration information.
@@ -831,6 +831,13 @@ Showing Information
Show the OSPF routing table, as determined by the most recent SPF
calculation.
+.. clicmd:: show ip ospf [vrf <NAME|all>] border-routers [json]
+
+ Show the list of ABR and ASBR border routers summary learnt via
+ OSPFv2 Type-3 (Summary LSA) and Type-4 (Summary ASBR LSA).
+ User can get that information as JSON format when ``json`` keyword
+ at the end of cli is presented.
+
.. clicmd:: show ip ospf (1-65535) route orr [NAME]
.. clicmd:: show ip ospf [vrf <NAME|all>] route orr [NAME]
diff --git a/doc/user/setup.rst b/doc/user/setup.rst
index dcc7607e48..372494fbce 100644
--- a/doc/user/setup.rst
+++ b/doc/user/setup.rst
@@ -116,6 +116,16 @@ allow this to happen.
::
+ FRR_NO_ROOT="yes"
+
+This option allows you to run FRR as a non-root user. Use this option
+only when you know what you are doing since most of the daemons
+in FRR will not be able to run under a regular user. This option
+is useful for example when you run FRR in a container with a designated
+user instead of root.
+
+::
+
zebra_options=" -s 90000000 --daemon -A 127.0.0.1"
bgpd_options=" --daemon -A 127.0.0.1"
...
diff --git a/doc/user/snmp.rst b/doc/user/snmp.rst
index b9058cc0d3..0bf3565b2e 100644
--- a/doc/user/snmp.rst
+++ b/doc/user/snmp.rst
@@ -115,6 +115,65 @@ Then, you can use the following command to check everything works as expected:
OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109
[...]
+An example below is how to query SNMP for BGP:
+
+ .. code-block:: shell
+
+ $ # BGP4-MIB (https://www.circitor.fr/Mibs/Mib/B/BGP4-MIB.mib)
+ $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.2.1.15
+
+ $ # BGP4V2-MIB (http://www.circitor.fr/Mibs/Mib/B/BGP4V2-MIB.mib)
+ $ # Information about the peers (bgp4V2PeerTable):
+ $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.3.5.1.1.2
+ ...
+ .1.3.6.1.3.5.1.1.2.1.1.1.4.192.168.10.124 = Gauge32: 0
+ .1.3.6.1.3.5.1.1.2.1.1.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 0
+ .1.3.6.1.3.5.1.1.2.1.2.1.4.192.168.10.124 = INTEGER: 1
+ .1.3.6.1.3.5.1.1.2.1.2.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2
+ .1.3.6.1.3.5.1.1.2.1.3.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 11
+ .1.3.6.1.3.5.1.1.2.1.3.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 01
+ .1.3.6.1.3.5.1.1.2.1.4.1.4.192.168.10.124 = INTEGER: 1
+ .1.3.6.1.3.5.1.1.2.1.4.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2
+ .1.3.6.1.3.5.1.1.2.1.5.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 7C
+ .1.3.6.1.3.5.1.1.2.1.5.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 02
+ .1.3.6.1.3.5.1.1.2.1.6.1.4.192.168.10.124 = Gauge32: 179
+ .1.3.6.1.3.5.1.1.2.1.6.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 179
+ .1.3.6.1.3.5.1.1.2.1.7.1.4.192.168.10.124 = Gauge32: 65002
+ .1.3.6.1.3.5.1.1.2.1.7.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65002
+ .1.3.6.1.3.5.1.1.2.1.8.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 11
+ .1.3.6.1.3.5.1.1.2.1.8.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C0 A8 0A 11
+ .1.3.6.1.3.5.1.1.2.1.9.1.4.192.168.10.124 = Gauge32: 41894
+ .1.3.6.1.3.5.1.1.2.1.9.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 39960
+ .1.3.6.1.3.5.1.1.2.1.10.1.4.192.168.10.124 = Gauge32: 65001
+ .1.3.6.1.3.5.1.1.2.1.10.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65001
+ .1.3.6.1.3.5.1.1.2.1.11.1.4.192.168.10.124 = Hex-STRING: C8 C8 C8 CA
+ .1.3.6.1.3.5.1.1.2.1.11.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C8 C8 C8 CA
+ .1.3.6.1.3.5.1.1.2.1.12.1.4.192.168.10.124 = INTEGER: 2
+ .1.3.6.1.3.5.1.1.2.1.12.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2
+ .1.3.6.1.3.5.1.1.2.1.13.1.4.192.168.10.124 = INTEGER: 6
+ .1.3.6.1.3.5.1.1.2.1.13.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 6
+
+ $ # Information about the BGP table (bgp4V2NlriTable):
+ $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.3.5.1.1.9
+ ...
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.10.0.2.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.10.10.100.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.1.32.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.2.32.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.3.32.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.0.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.1.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.10.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.0.64.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.10.0.2.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.10.10.100.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.1.32.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.2.32.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.3.32.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.0.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.1.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.10.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.0.64.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 02 01 FD E9
The AgentX protocol can be transported over a Unix socket or using TCP or UDP.
It usually defaults to a Unix socket and depends on how NetSNMP was built. If
@@ -132,5 +191,7 @@ Here is the syntax for using AgentX:
.. clicmd:: agentx
+ Once enabled, it can't be unconfigured. Only removing from the daemons file
+ the keyword ``agentx`` takes an effect.
.. include:: snmptrap.rst
diff --git a/doc/user/subdir.am b/doc/user/subdir.am
index 825938b31c..e07c9b6dc3 100644
--- a/doc/user/subdir.am
+++ b/doc/user/subdir.am
@@ -11,6 +11,7 @@ user_RSTFILES = \
doc/user/bugs.rst \
doc/user/conf.py \
doc/user/eigrpd.rst \
+ doc/user/evpn.rst \
doc/user/extlog.rst \
doc/user/fabricd.rst \
doc/user/filter.rst \
diff --git a/doc/user/vrrp.rst b/doc/user/vrrp.rst
index 44a56f2fca..ef3aebeafa 100644
--- a/doc/user/vrrp.rst
+++ b/doc/user/vrrp.rst
@@ -393,6 +393,11 @@ All interface configuration commands are documented below.
higher priority to take over Master status from the existing Master. Enabled
by default.
+.. clicmd:: vrrp (1-255) checksum-with-ipv4-pseudoheader
+
+ Specify whether VRRPv3 checksum should involve IPv4 pseudoheader. This
+ command should not affect VRRPv2 and IPv6. Enabled by default.
+
.. clicmd:: vrrp (1-255) priority (1-254)
Set the router priority. The router with the highest priority is elected as
@@ -448,7 +453,7 @@ Show commands, global defaults and debugging configuration commands.
zebra
Logs communications with Zebra.
-.. clicmd:: vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|shutdown>
+.. clicmd:: vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|checksum-with-ipv4-pseudoheader|shutdown>
Configure defaults for new VRRP routers. These values will not affect
already configured VRRP routers, but will be applied to newly configured
@@ -550,3 +555,19 @@ feature instead, explained `here
<https://www.virtuallyghetto.com/2018/04/native-mac-learning-in-vsphere-6-7-removes-the-need-for-promiscuous-mode-for-nested-esxi.html>`_.
Issue reference: https://github.com/FRRouting/frr/issues/5386
+
+
+My router cannot interoperate with branded routers / L3 switches
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+FRR includes a pseudoheader when calculating VRRPv3 checksums by default,
+regardless of whether it's IPv4 or IPv6.
+
+Some vendors have different interpretations of `VRRPv3 RFC 5798 #5.2.8
+<https://www.rfc-editor.org/rfc/rfc5798.html#section-5.2.8>`_. In such cases,
+their checksums are calculated with a pseudoheader only when it comes to IPv6.
+
+You need to disable ``checksum-with-ipv4-pseudoheader`` so that FRR computes and
+accepts such checksums.
+
+Issue reference: https://github.com/FRRouting/frr/issues/9951
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index db43266d68..c05a29af4e 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -68,7 +68,7 @@ Besides the common invocation options (:ref:`common-invocation-options`), the
option and we will use Route Replace Semantics instead of delete
than add.
-.. option:: --asic-offload [notify_on_offload|notify_on_ack]
+.. option:: --asic-offload=[notify_on_offload|notify_on_ack]
The linux kernel has the ability to use asic-offload ( see switchdev
development ). When the operator knows that FRR will be working in
@@ -76,11 +76,12 @@ Besides the common invocation options (:ref:`common-invocation-options`), the
code only supports asynchronous notification of the offload state.
In other words the initial ACK received for linux kernel installation
does not give zebra any data about what the state of the offload
- is. This option takes the optional paramegers notify_on_offload
+ is. This option takes the optional parameters notify_on_offload
or notify_on_ack. This signals to zebra to notify upper level
protocols about route installation/update on ack received from
the linux kernel or from offload notification.
+
.. option:: -s <SIZE>, --nl-bufsize <SIZE>
Allow zebra to modify the default receive buffer size to SIZE
@@ -296,7 +297,7 @@ the default route.
Allow IPv6 nexthop tracking to resolve via the default route. This parameter
is configured per-VRF, so the command is also available in the VRF subnode.
-.. clicmd:: show ip nht [vrf NAME] [A.B.C.D|X:X::X:X] [mrib]
+.. clicmd:: show ip nht [vrf NAME] [A.B.C.D|X:X::X:X] [mrib] [json]
Show nexthop tracking status for address resolution. If vrf is not specified
then display the default vrf. If ``all`` is specified show all vrf address
@@ -305,6 +306,17 @@ the default route.
indicates that the operator wants to see the multicast rib address resolution
table. An alternative form of the command is ``show ip import-check`` and this
form of the command is deprecated at this point in time.
+ User can get that information as JSON string when ``json`` key word
+ at the end of cli is presented.
+
+.. clicmd:: show ip nht route-map [vrf <NAME|all>] [json]
+
+ This command displays route-map attach point to nexthop tracking and
+ displays list of protocol with its applied route-map.
+ When zebra considers sending NHT resoultion, the nofification only
+ sent to appropriate client protocol only after applying route-map filter.
+ User can get that information as JSON format when ``json`` keyword
+ at the end of cli is presented.
PBR dataplane programming
=========================
@@ -1339,7 +1351,7 @@ zebra Terminal Mode Commands
total number of route nodes in the table. Which will be higher than
the actual number of routes that are held.
-.. clicmd:: show nexthop-group rib [ID] [vrf NAME] [singleton [ip|ip6]] [type]
+.. clicmd:: show nexthop-group rib [ID] [vrf NAME] [singleton [ip|ip6]] [type] [json]
Display nexthop groups created by zebra. The [vrf NAME] option
is only meaningful if you have started zebra with the --vrfwnetns
diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile
index 238a7fc409..afc6be2312 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.16 as alpine-builder
+FROM alpine:3.17 as alpine-builder
RUN apk add \
--update-cache \
abuild \
@@ -13,7 +13,7 @@ RUN apk add \
RUN adduser -D -G abuild builder && su builder -c 'abuild-keygen -a -n'
# This stage builds a dist tarball from the source
-FROM alpine:3.16 as source-builder
+FROM alpine:3.17 as source-builder
RUN mkdir -p /src/alpine
COPY alpine/APKBUILD.in /src/alpine
@@ -48,7 +48,7 @@ RUN cd /dist \
&& abuild -r -P /pkgs/apk
# This stage installs frr from the apk
-FROM alpine:3.16
+FROM alpine:3.17
RUN mkdir -p /pkgs/apk
COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/
RUN apk add \
diff --git a/include/subdir.am b/include/subdir.am
index f6328ef38e..4fa88a0afd 100644
--- a/include/subdir.am
+++ b/include/subdir.am
@@ -19,4 +19,5 @@ noinst_HEADERS += \
include/linux/seg6_local.h \
include/linux/mroute.h \
include/linux/mroute6.h \
+ include/linux/pkt_cls.h \
# end
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 0d1a5db0d6..89e751b4e6 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -1297,6 +1297,7 @@ static void spf_adj_get_reverse_metrics(struct isis_spftree *spftree)
if (lsp_adj == NULL || lsp_adj->hdr.rem_lifetime == 0) {
/* Delete one-way adjacency. */
listnode_delete(spftree->sadj_list, sadj);
+ isis_spf_adj_free(sadj);
continue;
}
@@ -1313,6 +1314,7 @@ static void spf_adj_get_reverse_metrics(struct isis_spftree *spftree)
if (args.reverse_metric == UINT32_MAX) {
/* Delete one-way adjacency. */
listnode_delete(spftree->sadj_list, sadj);
+ isis_spf_adj_free(sadj);
continue;
}
sadj->metric = args.reverse_metric;
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index 1b5c0e90fb..35d2bf21c9 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -208,7 +208,6 @@ ldpe_shutdown(void)
iev_main_sync->ibuf.fd = -1;
control_cleanup(ctl_sock_path);
- config_clear(leconf);
#ifdef __OpenBSD__
if (sysdep.no_pfkey == 0) {
@@ -231,6 +230,7 @@ ldpe_shutdown(void)
adj_del(adj, S_SHUTDOWN);
}
+ config_clear(leconf);
/* clean up */
if (iev_lde)
free(iev_lde);
diff --git a/lib/agentx.c b/lib/agentx.c
index 6c2923fcf8..5f62459805 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -32,13 +32,15 @@
#include "linklist.h"
#include "lib/version.h"
#include "lib_errors.h"
+#include "hook.h"
+#include "libfrr.h"
#include "xref.h"
XREF_SETUP();
DEFINE_HOOK(agentx_enabled, (), ());
-static int agentx_enabled = 0;
+static bool agentx_enabled = false;
static struct thread_master *agentx_tm;
static struct thread *timeout_thr = NULL;
@@ -226,7 +228,7 @@ DEFUN (agentx_enable,
init_snmp(FRR_SMUX_NAME);
events = list_new();
agentx_events_update();
- agentx_enabled = 1;
+ agentx_enabled = true;
hook_call(agentx_enabled);
}
@@ -245,7 +247,14 @@ DEFUN (no_agentx,
return CMD_WARNING_CONFIG_FAILED;
}
-int smux_enabled(void)
+static int smux_disable(void)
+{
+ agentx_enabled = false;
+
+ return 0;
+}
+
+bool smux_enabled(void)
{
return agentx_enabled;
}
@@ -264,6 +273,8 @@ void smux_init(struct thread_master *tm)
install_node(&agentx_node);
install_element(CONFIG_NODE, &agentx_enable_cmd);
install_element(CONFIG_NODE, &no_agentx_cmd);
+
+ hook_register(frr_early_fini, smux_disable);
}
void smux_agentx_enable(void)
@@ -272,7 +283,7 @@ void smux_agentx_enable(void)
init_snmp(FRR_SMUX_NAME);
events = list_new();
agentx_events_update();
- agentx_enabled = 1;
+ agentx_enabled = true;
}
}
diff --git a/lib/compiler.h b/lib/compiler.h
index bf443906eb..514f0cee6e 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -72,6 +72,16 @@ extern "C" {
#endif
#endif
+#ifdef __INTELLISENSE__
+/*
+ * Fix Visual Studio Code error: attribute "constructor" does not take
+ * arguments.
+ *
+ * Caused by the macro `DEFINE_MTYPE_ATTR` in `lib/memory.h`.
+ */
+#pragma diag_suppress 1094
+#endif /* __INTELISENSE__ */
+
#if __has_attribute(hot)
# define _OPTIMIZE_HOT __attribute__((hot))
#else
@@ -411,6 +421,35 @@ _Static_assert(sizeof(_uint64_t) == 8 && sizeof(_int64_t) == 8,
#endif /* !__cplusplus */
#endif /* !_FRR_ATTRIBUTE_PRINTFRR */
+/* helper to get type safety/avoid casts on calls
+ * (w/o this, functions accepting all prefix types need casts on the caller
+ * side, which strips type safety since the cast will accept any pointer
+ * type.)
+ */
+#ifndef __cplusplus
+#define prefixtype(uname, typename, fieldname) typename *fieldname;
+#define TRANSPARENT_UNION __attribute__((transparent_union))
+#else
+#define prefixtype(uname, typename, fieldname) \
+ typename *fieldname; \
+ uname(typename *x) \
+ { \
+ this->fieldname = x; \
+ }
+#define TRANSPARENT_UNION
+#endif
+
+#ifdef __INTELLISENSE__
+/*
+ * Fix Visual Studio Code error: argument of type "struct prefix *" is
+ * incompatible with parameter of type "union prefixptr".
+ *
+ * This is caused by all functions having the transparent unions in the
+ * prototype. Example: `prefixptr` and `prefixconstptr` from `lib/prefix.h`.
+ */
+#pragma diag_suppress 167
+#endif /* __INTELISENSE__ */
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/if.c b/lib/if.c
index 76568071ef..6766a04b37 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -38,6 +38,7 @@
#include "lib/if_clippy.c"
DEFINE_MTYPE_STATIC(LIB, IF, "Interface");
+DEFINE_MTYPE_STATIC(LIB, IFDESC, "Intf Desc");
DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected");
DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected");
DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label");
@@ -288,7 +289,7 @@ void if_delete(struct interface **ifp)
if_link_params_free(ptr);
- XFREE(MTYPE_TMP, ptr->desc);
+ XFREE(MTYPE_IFDESC, ptr->desc);
XFREE(MTYPE_IF, ptr);
*ifp = NULL;
@@ -563,9 +564,24 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
return count;
}
+/* Get the VRF loopback interface, i.e. the loopback on the default VRF
+ * or the VRF interface.
+ */
+struct interface *if_get_vrf_loopback(vrf_id_t vrf_id)
+{
+ struct interface *ifp = NULL;
+ struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+
+ FOR_ALL_INTERFACES (vrf, ifp)
+ if (if_is_loopback(ifp))
+ return ifp;
+
+ return NULL;
+}
/* Get interface by name if given name interface doesn't exist create
- one. */
+ * one.
+ */
struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id,
const char *vrf_name)
{
@@ -1612,9 +1628,9 @@ static int lib_interface_description_modify(struct nb_cb_modify_args *args)
return NB_OK;
ifp = nb_running_get_entry(args->dnode, NULL, true);
- XFREE(MTYPE_TMP, ifp->desc);
+ XFREE(MTYPE_IFDESC, ifp->desc);
description = yang_dnode_get_string(args->dnode, NULL);
- ifp->desc = XSTRDUP(MTYPE_TMP, description);
+ ifp->desc = XSTRDUP(MTYPE_IFDESC, description);
return NB_OK;
}
@@ -1627,7 +1643,7 @@ static int lib_interface_description_destroy(struct nb_cb_destroy_args *args)
return NB_OK;
ifp = nb_running_get_entry(args->dnode, NULL, true);
- XFREE(MTYPE_TMP, ifp->desc);
+ XFREE(MTYPE_IFDESC, ifp->desc);
return NB_OK;
}
diff --git a/lib/if.h b/lib/if.h
index 91dcd46247..a653246ccb 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -532,6 +532,7 @@ static inline bool if_address_is_local(const void *matchaddr, int family,
struct vrf;
extern struct interface *if_lookup_by_name_vrf(const char *name, struct vrf *vrf);
extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id);
+extern struct interface *if_get_vrf_loopback(vrf_id_t vrf_id);
extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id,
const char *vrf_name);
diff --git a/lib/lib_vty.c b/lib/lib_vty.c
index 85816c5123..46a0a68103 100644
--- a/lib/lib_vty.c
+++ b/lib/lib_vty.c
@@ -225,10 +225,8 @@ static struct call_back {
} callback;
-DEFUN_HIDDEN (start_config,
- start_config_cmd,
- "XFRR_start_configuration",
- "The Beginning of Configuration\n")
+DEFUN_NOSH(start_config, start_config_cmd, "XFRR_start_configuration",
+ "The Beginning of Configuration\n")
{
callback.readin_time = monotime(NULL);
@@ -240,10 +238,8 @@ DEFUN_HIDDEN (start_config,
return CMD_SUCCESS;
}
-DEFUN_HIDDEN (end_config,
- end_config_cmd,
- "XFRR_end_configuration",
- "The End of Configuration\n")
+DEFUN_NOSH(end_config, end_config_cmd, "XFRR_end_configuration",
+ "The End of Configuration\n")
{
time_t readin_time;
char readin_time_str[MONOTIME_STRLEN];
diff --git a/lib/libospf.h b/lib/libospf.h
index c8ada9d3c5..161c7635d8 100644
--- a/lib/libospf.h
+++ b/lib/libospf.h
@@ -52,6 +52,7 @@ extern "C" {
#define OSPF_DEFAULT_DESTINATION 0x00000000 /* 0.0.0.0 */
#define OSPF_INITIAL_SEQUENCE_NUMBER 0x80000001U
#define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffffU
+#define OSPF_INVALID_SEQUENCE_NUMBER 0x80000000U
/* OSPF Interface Types */
#define OSPF_IFTYPE_NONE 0
diff --git a/lib/link_state.c b/lib/link_state.c
index ab5a8515b5..1b79c79216 100644
--- a/lib/link_state.c
+++ b/lib/link_state.c
@@ -346,7 +346,7 @@ struct ls_prefix *ls_prefix_new(struct ls_node_id adv, struct prefix p)
if (adv.origin == UNKNOWN)
return NULL;
- new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes));
+ new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_prefix));
new->adv = adv;
new->pref = p;
diff --git a/lib/linklist.c b/lib/linklist.c
index d1b57084ef..d2a29b7ed1 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -28,6 +28,37 @@
DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List");
DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node");
+/* these *do not* cleanup list nodes and referenced data, as the functions
+ * do - these macros simply {de,at}tach a listnode from/to a list.
+ */
+
+/* List node attach macro. */
+#define LISTNODE_ATTACH(L, N) \
+ do { \
+ (N)->prev = (L)->tail; \
+ (N)->next = NULL; \
+ if ((L)->head == NULL) \
+ (L)->head = (N); \
+ else \
+ (L)->tail->next = (N); \
+ (L)->tail = (N); \
+ (L)->count++; \
+ } while (0)
+
+/* List node detach macro. */
+#define LISTNODE_DETACH(L, N) \
+ do { \
+ if ((N)->prev) \
+ (N)->prev->next = (N)->next; \
+ else \
+ (L)->head = (N)->next; \
+ if ((N)->next) \
+ (N)->next->prev = (N)->prev; \
+ else \
+ (L)->tail = (N)->prev; \
+ (L)->count--; \
+ } while (0)
+
struct list *list_new(void)
{
return XCALLOC(MTYPE_LINK_LIST, sizeof(struct list));
diff --git a/lib/linklist.h b/lib/linklist.h
index 1452145218..e7594728f1 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -349,37 +349,6 @@ extern struct list *list_dup(struct list *list);
(node) != NULL && ((data) = static_cast(data, listgetdata(node)), 1); \
(node) = listnextnode(node), ((data) = NULL)
-/* these *do not* cleanup list nodes and referenced data, as the functions
- * do - these macros simply {de,at}tach a listnode from/to a list.
- */
-
-/* List node attach macro. */
-#define LISTNODE_ATTACH(L, N) \
- do { \
- (N)->prev = (L)->tail; \
- (N)->next = NULL; \
- if ((L)->head == NULL) \
- (L)->head = (N); \
- else \
- (L)->tail->next = (N); \
- (L)->tail = (N); \
- (L)->count++; \
- } while (0)
-
-/* List node detach macro. */
-#define LISTNODE_DETACH(L, N) \
- do { \
- if ((N)->prev) \
- (N)->prev->next = (N)->next; \
- else \
- (L)->head = (N)->next; \
- if ((N)->next) \
- (N)->next->prev = (N)->prev; \
- else \
- (L)->tail = (N)->prev; \
- (L)->count--; \
- } while (0)
-
extern struct listnode *listnode_lookup_nocheck(struct list *list, void *data);
/*
diff --git a/lib/log.c b/lib/log.c
index 9548f26c1d..156982635d 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -337,6 +337,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_INTERFACE_UP),
DESC_ENTRY(ZEBRA_INTERFACE_DOWN),
DESC_ENTRY(ZEBRA_INTERFACE_SET_MASTER),
+ DESC_ENTRY(ZEBRA_INTERFACE_SET_PROTODOWN),
DESC_ENTRY(ZEBRA_ROUTE_ADD),
DESC_ENTRY(ZEBRA_ROUTE_DELETE),
DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_OWNER),
@@ -386,10 +387,10 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_FEC_REGISTER),
DESC_ENTRY(ZEBRA_FEC_UNREGISTER),
DESC_ENTRY(ZEBRA_FEC_UPDATE),
- DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP),
DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET),
+ DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
DESC_ENTRY(ZEBRA_LOCAL_ES_ADD),
DESC_ENTRY(ZEBRA_LOCAL_ES_DEL),
DESC_ENTRY(ZEBRA_REMOTE_ES_VTEP_ADD),
@@ -438,19 +439,23 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_MLAG_CLIENT_REGISTER),
DESC_ENTRY(ZEBRA_MLAG_CLIENT_UNREGISTER),
DESC_ENTRY(ZEBRA_MLAG_FORWARD_MSG),
+ DESC_ENTRY(ZEBRA_NHG_ADD),
+ DESC_ENTRY(ZEBRA_NHG_DEL),
+ DESC_ENTRY(ZEBRA_NHG_NOTIFY_OWNER),
+ DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_ADD),
+ DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL),
+ DESC_ENTRY(ZEBRA_SRV6_LOCATOR_ADD),
+ 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_ERROR),
DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES),
DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE),
DESC_ENTRY(ZEBRA_OPAQUE_REGISTER),
DESC_ENTRY(ZEBRA_OPAQUE_UNREGISTER),
DESC_ENTRY(ZEBRA_NEIGH_DISCOVER),
- DESC_ENTRY(ZEBRA_NHG_ADD),
- DESC_ENTRY(ZEBRA_NHG_DEL),
- DESC_ENTRY(ZEBRA_NHG_NOTIFY_OWNER),
DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST),
DESC_ENTRY(ZEBRA_CLIENT_CLOSE_NOTIFY),
- DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_ADD),
- DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL),
DESC_ENTRY(ZEBRA_NHRP_NEIGH_ADDED),
DESC_ENTRY(ZEBRA_NHRP_NEIGH_REMOVED),
DESC_ENTRY(ZEBRA_NHRP_NEIGH_GET),
@@ -461,7 +466,13 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_CONFIGURE_ARP),
DESC_ENTRY(ZEBRA_GRE_GET),
DESC_ENTRY(ZEBRA_GRE_UPDATE),
- DESC_ENTRY(ZEBRA_GRE_SOURCE_SET)};
+ DESC_ENTRY(ZEBRA_GRE_SOURCE_SET),
+ DESC_ENTRY(ZEBRA_TC_QDISC_INSTALL),
+ DESC_ENTRY(ZEBRA_TC_QDISC_UNINSTALL),
+ DESC_ENTRY(ZEBRA_TC_CLASS_ADD),
+ DESC_ENTRY(ZEBRA_TC_CLASS_DELETE),
+ DESC_ENTRY(ZEBRA_TC_FILTER_ADD),
+ DESC_ENTRY(ZEBRA_TC_FILTER_DELETE)};
#undef DESC_ENTRY
static const struct zebra_desc_table unknown = {0, "unknown", '?'};
diff --git a/lib/prefix.h b/lib/prefix.h
index c67656cfd1..7de8d7903e 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -301,22 +301,6 @@ struct prefix_sg {
struct in_addr grp;
};
-/* helper to get type safety/avoid casts on calls
- * (w/o this, functions accepting all prefix types need casts on the caller
- * side, which strips type safety since the cast will accept any pointer
- * type.)
- */
-#ifndef __cplusplus
-#define prefixtype(uname, typename, fieldname) \
- typename *fieldname;
-#define TRANSPARENT_UNION __attribute__((transparent_union))
-#else
-#define prefixtype(uname, typename, fieldname) \
- typename *fieldname; \
- uname(typename *x) { this->fieldname = x; }
-#define TRANSPARENT_UNION
-#endif
-
union prefixptr {
prefixtype(prefixptr, struct prefix, p)
prefixtype(prefixptr, struct prefix_ipv4, p4)
diff --git a/lib/privs.c b/lib/privs.c
index 71416beebe..08461d8d50 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -261,8 +261,34 @@ zebra_privs_current_t zprivs_state_caps(void)
return ZPRIVS_LOWERED;
}
+/** Release private cap state if allocated. */
+static void zprivs_state_free_caps(void)
+{
+ if (zprivs_state.syscaps_p) {
+ if (zprivs_state.syscaps_p->num)
+ XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p->caps);
+
+ XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p);
+ }
+
+ if (zprivs_state.syscaps_i) {
+ if (zprivs_state.syscaps_i->num)
+ XFREE(MTYPE_PRIVS, zprivs_state.syscaps_i->caps);
+
+ XFREE(MTYPE_PRIVS, zprivs_state.syscaps_i);
+ }
+
+ if (zprivs_state.caps) {
+ cap_free(zprivs_state.caps);
+ zprivs_state.caps = NULL;
+ }
+}
+
static void zprivs_caps_init(struct zebra_privs_t *zprivs)
{
+ /* Release allocated zcaps if this function was called before. */
+ zprivs_state_free_caps();
+
zprivs_state.syscaps_p = zcaps2sys(zprivs->caps_p, zprivs->cap_num_p);
zprivs_state.syscaps_i = zcaps2sys(zprivs->caps_i, zprivs->cap_num_i);
@@ -362,18 +388,7 @@ static void zprivs_caps_terminate(void)
exit(1);
}
- /* free up private state */
- if (zprivs_state.syscaps_p && zprivs_state.syscaps_p->num) {
- XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p->caps);
- XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p);
- }
-
- if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num) {
- XFREE(MTYPE_PRIVS, zprivs_state.syscaps_i->caps);
- XFREE(MTYPE_PRIVS, zprivs_state.syscaps_i);
- }
-
- cap_free(zprivs_state.caps);
+ zprivs_state_free_caps();
}
#else /* !HAVE_LCAPS */
#error "no Linux capabilities, dazed and confused..."
diff --git a/lib/smux.h b/lib/smux.h
index 74447341d8..1d73406a28 100644
--- a/lib/smux.h
+++ b/lib/smux.h
@@ -44,6 +44,7 @@ extern "C" {
#define SNMP_INVALID 2
#define IN_ADDR_SIZE sizeof(struct in_addr)
+#define IN6_ADDR_SIZE sizeof(struct in6_addr)
/* IANAipRouteProtocol */
#define IANAIPROUTEPROTOCOLOTHER 1
@@ -87,8 +88,9 @@ struct index_oid {
/* Declare SMUX return value. */
#define SNMP_LOCAL_VARIABLES \
static long snmp_int_val __attribute__((unused)); \
- static struct in_addr snmp_in_addr_val __attribute__((unused));
- static uint8_t snmp_octet_val __attribute__((unused));
+ static struct in_addr snmp_in_addr_val __attribute__((unused)); \
+ static uint8_t snmp_octet_val __attribute__((unused)); \
+ static char snmp_string_val[255] __attribute__((unused));
#define SNMP_INTEGER(V) \
(*var_len = sizeof(snmp_int_val), snmp_int_val = V, \
(uint8_t *)&snmp_int_val)
@@ -97,13 +99,20 @@ struct index_oid {
(*var_len = sizeof(snmp_octet_val), snmp_octet_val = V, \
(uint8_t *)&snmp_octet_val)
+#define SNMP_STRING(V) \
+ (*var_len = MIN(sizeof(snmp_string_val), strlen(V) + 1), \
+ strlcpy(snmp_string_val, V, *var_len), (uint8_t *)&snmp_string_val)
+
#define SNMP_IPADDRESS(V) \
(*var_len = sizeof(struct in_addr), snmp_in_addr_val = V, \
(uint8_t *)&snmp_in_addr_val)
#define SNMP_IP6ADDRESS(V) (*var_len = sizeof(struct in6_addr), (uint8_t *)&V)
-extern int smux_enabled(void);
+/*
+ * Check to see if snmp is enabled or not
+ */
+extern bool smux_enabled(void);
extern void smux_init(struct thread_master *tm);
extern void smux_agentx_enable(void);
diff --git a/lib/srv6.c b/lib/srv6.c
index 5cd82080f5..f4077a86d2 100644
--- a/lib/srv6.c
+++ b/lib/srv6.c
@@ -121,6 +121,13 @@ const char *seg6local_context2str(char *str, size_t size,
}
}
+static void srv6_locator_chunk_list_free(void *data)
+{
+ struct srv6_locator_chunk *chunk = data;
+
+ srv6_locator_chunk_free(&chunk);
+}
+
struct srv6_locator *srv6_locator_alloc(const char *name)
{
struct srv6_locator *locator = NULL;
@@ -128,7 +135,7 @@ struct srv6_locator *srv6_locator_alloc(const char *name)
locator = XCALLOC(MTYPE_SRV6_LOCATOR, sizeof(struct srv6_locator));
strlcpy(locator->name, name, sizeof(locator->name));
locator->chunks = list_new();
- locator->chunks->del = (void (*)(void *))srv6_locator_chunk_free;
+ locator->chunks->del = srv6_locator_chunk_list_free;
QOBJ_REG(locator, srv6_locator);
return locator;
diff --git a/lib/subdir.am b/lib/subdir.am
index ea6cb9339a..1a8c184823 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -123,6 +123,7 @@ lib_libfrr_la_SOURCES = \
lib/printf/glue.c \
lib/routing_nb.c \
lib/routing_nb_config.c \
+ lib/tc.c \
# end
nodist_lib_libfrr_la_SOURCES = \
@@ -275,6 +276,7 @@ pkginclude_HEADERS += \
lib/zlog_live.h \
lib/zlog_targets.h \
lib/pbr.h \
+ lib/tc.h \
lib/routing_nb.h \
\
lib/assert/assert.h \
diff --git a/lib/tc.c b/lib/tc.c
new file mode 100644
index 0000000000..1bc01ed3f6
--- /dev/null
+++ b/lib/tc.c
@@ -0,0 +1,88 @@
+/*
+ * Traffic Control (TC) main library
+ * Copyright (C) 2022 Shichu Yang
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "tc.h"
+
+int tc_getrate(const char *str, uint64_t *rate)
+{
+ char *endp;
+ uint64_t raw = strtoull(str, &endp, 10);
+
+ if (endp == str)
+ return -1;
+
+ /* if the string only contains a number, it must be valid rate (bps) */
+ bool valid = (*endp == '\0');
+
+ const char *p = endp;
+ bool bytes = false, binary_base = false;
+ int power = 0;
+
+ while (*p) {
+ if (strcmp(p, "Bps") == 0) {
+ bytes = true;
+ valid = true;
+ break;
+ } else if (strcmp(p, "bit") == 0) {
+ valid = true;
+ break;
+ }
+ switch (*p) {
+ case 'k':
+ case 'K':
+ power = 1;
+ break;
+ case 'm':
+ case 'M':
+ power = 2;
+ break;
+ case 'g':
+ case 'G':
+ power = 3;
+ break;
+ case 't':
+ case 'T':
+ power = 4;
+ break;
+ case 'i':
+ case 'I':
+ if (power != 0)
+ binary_base = true;
+ else
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ p++;
+ }
+
+ if (!valid)
+ return -1;
+
+ for (int i = 0; i < power; i++)
+ raw *= binary_base ? 1024ULL : 1000ULL;
+
+ if (bytes)
+ *rate = raw;
+ else
+ *rate = raw / 8ULL;
+
+ return 0;
+}
diff --git a/lib/tc.h b/lib/tc.h
new file mode 100644
index 0000000000..ec68e1f4cd
--- /dev/null
+++ b/lib/tc.h
@@ -0,0 +1,151 @@
+/*
+ * Traffic Control (TC) main header
+ * Copyright (C) 2022 Shichu Yang
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _TC_H
+#define _TC_H
+
+#include <zebra.h>
+#include "stream.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TC_STR "Traffic Control\n"
+
+/* qdisc definitions */
+
+/* qdisc kind (same as class kinds) */
+enum tc_qdisc_kind {
+ TC_QDISC_UNSPEC,
+ TC_QDISC_HTB,
+ TC_QDISC_NOQUEUE,
+};
+
+struct tc_qdisc_htb {
+ /* currently no members */
+};
+
+struct tc_qdisc {
+ ifindex_t ifindex;
+
+ enum tc_qdisc_kind kind;
+ union {
+ struct tc_qdisc_htb htb;
+ } u;
+};
+
+/* class definitions */
+
+/* since classes share the same kinds of qdisc, duplicates omitted */
+struct tc_class_htb {
+ uint64_t rate;
+ uint64_t ceil;
+};
+
+struct tc_class {
+ ifindex_t ifindex;
+ uint32_t handle;
+
+ enum tc_qdisc_kind kind;
+ union {
+ struct tc_class_htb htb;
+ } u;
+};
+
+/* filter definitions */
+
+/* filter kinds */
+enum tc_filter_kind {
+ TC_FILTER_UNSPEC,
+ TC_FILTER_BPF,
+ TC_FILTER_FLOW,
+ TC_FILTER_FLOWER,
+ TC_FILTER_U32,
+};
+
+struct tc_bpf {
+ /* TODO: fill in */
+};
+
+struct tc_flow {
+ /* TODO: fill in */
+};
+
+struct tc_flower {
+ uint32_t classid;
+
+#define TC_FLOWER_IP_PROTOCOL (1 << 0)
+#define TC_FLOWER_SRC_IP (1 << 1)
+#define TC_FLOWER_DST_IP (1 << 2)
+#define TC_FLOWER_SRC_PORT (1 << 3)
+#define TC_FLOWER_DST_PORT (1 << 4)
+#define TC_FLOWER_DSFIELD (1 << 5)
+
+ uint32_t filter_bm;
+
+ uint8_t ip_proto;
+
+ struct prefix src_ip;
+ struct prefix dst_ip;
+
+ uint16_t src_port_min;
+ uint16_t src_port_max;
+ uint16_t dst_port_min;
+ uint16_t dst_port_max;
+
+ uint8_t dsfield;
+ uint8_t dsfield_mask;
+};
+
+struct tc_u32 {
+ /* TODO: fill in */
+};
+
+struct tc_filter {
+ ifindex_t ifindex;
+ uint32_t handle;
+
+ uint32_t priority;
+ uint16_t protocol;
+
+ enum tc_filter_kind kind;
+
+ union {
+ struct tc_bpf bpf;
+ struct tc_flow flow;
+ struct tc_flower flower;
+ struct tc_u32 u32;
+ } u;
+};
+
+extern int tc_getrate(const char *str, uint64_t *rate);
+
+extern int zapi_tc_qdisc_encode(uint8_t cmd, struct stream *s,
+ struct tc_qdisc *qdisc);
+extern int zapi_tc_class_encode(uint8_t cmd, struct stream *s,
+ struct tc_class *class);
+extern int zapi_tc_filter_encode(uint8_t cmd, struct stream *s,
+ struct tc_filter *filter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TC_H */
diff --git a/lib/vrf.c b/lib/vrf.c
index 3a859895e8..5878c1734f 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -528,6 +528,7 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
static void vrf_terminate_single(struct vrf *vrf)
{
/* Clear configured flag and invoke delete. */
+ vrf_disable(vrf);
UNSET_FLAG(vrf->status, VRF_CONFIGURED);
if_terminate(vrf);
vrf_delete(vrf);
diff --git a/lib/vty.c b/lib/vty.c
index 5fe8d82473..352080e580 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -447,7 +447,8 @@ static int vty_command(struct vty *vty, char *buf)
/*
* Log non empty command lines
*/
- if (do_log_commands)
+ if (do_log_commands &&
+ strncmp(buf, "echo PING", strlen("echo PING")) != 0)
cp = buf;
if (cp != NULL) {
/* Skip white spaces. */
diff --git a/lib/workqueue.c b/lib/workqueue.c
index c703de90b3..a5338ba78b 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -272,9 +272,6 @@ void work_queue_run(struct thread *thread)
/* dont run items which are past their allowed retries */
if (item->ran > wq->spec.max_retries) {
- /* run error handler, if any */
- if (wq->spec.errorfunc)
- wq->spec.errorfunc(wq, item);
work_queue_item_remove(wq, item);
continue;
}
@@ -317,10 +314,6 @@ void work_queue_run(struct thread *thread)
case WQ_RETRY_NOW:
/* a RETRY_NOW that gets here has exceeded max_tries, same as
* ERROR */
- case WQ_ERROR: {
- if (wq->spec.errorfunc)
- wq->spec.errorfunc(wq, item);
- }
/* fallthru */
case WQ_SUCCESS:
default: {
diff --git a/lib/workqueue.h b/lib/workqueue.h
index 27fb1383eb..7866032fc0 100644
--- a/lib/workqueue.h
+++ b/lib/workqueue.h
@@ -41,7 +41,6 @@ DECLARE_MTYPE(WORK_QUEUE);
/* action value, for use by item processor and item error handlers */
typedef enum {
WQ_SUCCESS = 0,
- WQ_ERROR, /* Error, run error handler if provided */
WQ_RETRY_NOW, /* retry immediately */
WQ_RETRY_LATER, /* retry later, cease processing work queue */
WQ_REQUEUE, /* requeue item, continue processing work queue */
@@ -80,10 +79,6 @@ struct work_queue {
*/
wq_item_status (*workfunc)(struct work_queue *, void *);
- /* error handling function, optional */
- void (*errorfunc)(struct work_queue *,
- struct work_queue_item *);
-
/* callback to delete user specific item data */
void (*del_item_data)(struct work_queue *, void *);
diff --git a/lib/zclient.c b/lib/zclient.c
index fd6eb7db0d..07c7e5aea8 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -37,6 +37,7 @@
#include "mpls.h"
#include "sockopt.h"
#include "pbr.h"
+#include "tc.h"
#include "nexthop_group.h"
#include "lib_errors.h"
#include "srte.h"
@@ -1649,6 +1650,96 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
return 0;
}
+int zapi_tc_qdisc_encode(uint8_t cmd, struct stream *s, struct tc_qdisc *qdisc)
+{
+ stream_reset(s);
+ zclient_create_header(s, cmd, VRF_DEFAULT);
+
+
+ stream_putl(s, 1);
+
+ stream_putl(s, qdisc->ifindex);
+ stream_putl(s, qdisc->kind);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return 0;
+}
+
+int zapi_tc_class_encode(uint8_t cmd, struct stream *s, struct tc_class *class)
+{
+ stream_reset(s);
+ zclient_create_header(s, cmd, VRF_DEFAULT);
+
+ stream_putl(s, 1);
+
+ stream_putl(s, class->ifindex);
+ stream_putl(s, class->handle);
+ stream_putl(s, class->kind);
+
+ switch (class->kind) {
+ case TC_QDISC_HTB:
+ stream_putq(s, class->u.htb.rate);
+ stream_putq(s, class->u.htb.ceil);
+ break;
+ default:
+ /* not implemented */
+ break;
+ }
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return 0;
+}
+
+int zapi_tc_filter_encode(uint8_t cmd, struct stream *s,
+ struct tc_filter *filter)
+{
+ stream_reset(s);
+ zclient_create_header(s, cmd, VRF_DEFAULT);
+
+ stream_putl(s, 1);
+
+ stream_putl(s, filter->ifindex);
+ stream_putl(s, filter->handle);
+ stream_putl(s, filter->priority);
+ stream_putl(s, filter->protocol);
+ stream_putl(s, filter->kind);
+
+ switch (filter->kind) {
+ case TC_FILTER_FLOWER:
+ stream_putl(s, filter->u.flower.filter_bm);
+ if (filter->u.flower.filter_bm & TC_FLOWER_IP_PROTOCOL)
+ stream_putc(s, filter->u.flower.ip_proto);
+ if (filter->u.flower.filter_bm & TC_FLOWER_SRC_IP)
+ zapi_encode_prefix(s, &filter->u.flower.src_ip,
+ filter->u.flower.src_ip.family);
+ if (filter->u.flower.filter_bm & TC_FLOWER_SRC_PORT) {
+ stream_putw(s, filter->u.flower.src_port_min);
+ stream_putw(s, filter->u.flower.src_port_max);
+ }
+ if (filter->u.flower.filter_bm & TC_FLOWER_DST_IP)
+ zapi_encode_prefix(s, &filter->u.flower.dst_ip,
+ filter->u.flower.dst_ip.family);
+ if (filter->u.flower.filter_bm & TC_FLOWER_DST_PORT) {
+ stream_putw(s, filter->u.flower.dst_port_min);
+ stream_putw(s, filter->u.flower.dst_port_max);
+ }
+ if (filter->u.flower.filter_bm & TC_FLOWER_DSFIELD) {
+ stream_putc(s, filter->u.flower.dsfield);
+ stream_putc(s, filter->u.flower.dsfield_mask);
+ }
+ stream_putl(s, filter->u.flower.classid);
+ break;
+ default:
+ /* not implemented */
+ break;
+ }
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return 0;
+}
+
bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id,
enum zapi_nhg_notify_owner *note)
{
diff --git a/lib/zclient.h b/lib/zclient.h
index 731769abf7..584a42194d 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -243,6 +243,12 @@ typedef enum {
ZEBRA_GRE_GET,
ZEBRA_GRE_UPDATE,
ZEBRA_GRE_SOURCE_SET,
+ ZEBRA_TC_QDISC_INSTALL,
+ ZEBRA_TC_QDISC_UNINSTALL,
+ ZEBRA_TC_CLASS_ADD,
+ ZEBRA_TC_CLASS_DELETE,
+ ZEBRA_TC_FILTER_ADD,
+ ZEBRA_TC_FILTER_DELETE,
} zebra_message_types_t;
enum zebra_error_types {
diff --git a/lib/zlog_targets.c b/lib/zlog_targets.c
index 31bd8e16eb..f7ea48bf9d 100644
--- a/lib/zlog_targets.c
+++ b/lib/zlog_targets.c
@@ -257,6 +257,7 @@ bool zlog_file_set_filename(struct zlog_cfg_file *zcf, const char *filename)
return zlog_file_cycle(zcf);
}
assert(0);
+ return false;
}
bool zlog_file_set_fd(struct zlog_cfg_file *zcf, int fd)
@@ -271,6 +272,7 @@ bool zlog_file_set_fd(struct zlog_cfg_file *zcf, int fd)
return zlog_file_cycle(zcf);
}
assert(0);
+ return false;
}
struct rcu_close_rotate {
@@ -544,6 +546,7 @@ int zlog_syslog_get_facility(void)
return syslog_facility;
}
assert(0);
+ return 0;
}
void zlog_syslog_set_prio_min(int prio_min)
@@ -581,4 +584,5 @@ int zlog_syslog_get_prio_min(void)
return syslog_prio_min;
}
assert(0);
+ return 0;
}
diff --git a/m4/ax_lua.m4 b/m4/ax_lua.m4
index dde24eaf89..f4236cf08a 100644
--- a/m4/ax_lua.m4
+++ b/m4/ax_lua.m4
@@ -519,7 +519,7 @@ AC_DEFUN([AX_LUA_HEADERS],
[
ax_cv_lua_header_version=`echo LUA_VERSION | \
$CC -P -E $LUA_INCLUDE -imacros lua.h - | \
- $SED -e 's%"\s*"%%g' -e 's%^\s*%%' | \
+ $SED -e 's%"@<:@@<:@:space:@:>@@:>@*"%%g' -e 's%^@<:@@<:@:space:@:>@@:>@*%%' | \
tr -d '"\n' | \
$SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"`
])
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index e9c42bb80c..e007709f99 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -1322,7 +1322,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
ospf6_copy_nexthops(tmp_route->nh_list,
o_path->nh_list);
- if (ospf6_route_cmp_nexthops(tmp_route, route) != 0) {
+ if (!ospf6_route_cmp_nexthops(tmp_route, route)) {
/* adv. router exists in the list, update nhs */
list_delete_all_node(o_path->nh_list);
ospf6_copy_nexthops(o_path->nh_list,
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 07061b6f57..0fd6e15ed6 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -1585,7 +1585,11 @@ ospf6_asbr_summary_remove_lsa_and_route(struct ospf6 *ospf6,
zlog_debug(
"%s: Remove the blackhole route",
__func__);
+
ospf6_zebra_route_update_remove(aggr->route, ospf6);
+ if (aggr->route->route_option)
+ XFREE(MTYPE_OSPF6_EXTERNAL_INFO,
+ aggr->route->route_option);
ospf6_route_delete(aggr->route);
aggr->route = NULL;
}
@@ -2736,8 +2740,13 @@ ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6,
struct ospf6_external_aggr_rt *aggr)
{
struct ospf6_route *rt_aggr;
+ struct ospf6_route *old_rt = NULL;
struct ospf6_external_info *info;
+ /* Check if a route is already present. */
+ if (aggr->route)
+ old_rt = aggr->route;
+
/* Create summary route and save it. */
rt_aggr = ospf6_route_create(ospf6);
rt_aggr->type = OSPF6_DEST_TYPE_NETWORK;
@@ -2756,6 +2765,16 @@ ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6,
/* Add next-hop to Null interface. */
ospf6_add_route_nexthop_blackhole(rt_aggr);
+ /* Free the old route, if any. */
+ if (old_rt) {
+ ospf6_zebra_route_update_remove(old_rt, ospf6);
+
+ if (old_rt->route_option)
+ XFREE(MTYPE_OSPF6_EXTERNAL_INFO, old_rt->route_option);
+
+ ospf6_route_delete(old_rt);
+ }
+
ospf6_zebra_route_update_add(rt_aggr, ospf6);
}
@@ -3024,8 +3043,8 @@ static void ospf6_aggr_handle_external_info(void *data)
(void)ospf6_originate_type5_type7_lsas(rt, ospf6);
}
-static void
-ospf6_asbr_summary_config_delete(struct ospf6 *ospf6, struct route_node *rn)
+void ospf6_asbr_summary_config_delete(struct ospf6 *ospf6,
+ struct route_node *rn)
{
struct ospf6_external_aggr_rt *aggr = rn->info;
@@ -3167,14 +3186,6 @@ void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr)
hash_clean(aggr->match_extnl_hash,
ospf6_aggr_unlink_external_info);
- if (aggr->route) {
- if (aggr->route->route_option)
- XFREE(MTYPE_OSPF6_EXTERNAL_INFO,
- aggr->route->route_option);
-
- ospf6_route_delete(aggr->route);
- }
-
if (IS_OSPF6_DEBUG_AGGR)
zlog_debug("%s: Release the aggregator Address(%pFX)",
__func__,
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 0487bb14c3..0d2a98aeba 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -182,4 +182,6 @@ void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr);
void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6);
void ospf6_fill_aggr_route_details(struct ospf6 *ospf6,
struct ospf6_external_aggr_rt *aggr);
+void ospf6_asbr_summary_config_delete(struct ospf6 *ospf6,
+ struct route_node *rn);
#endif /* OSPF6_ASBR_H */
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index ed228f46ae..d3dd5501a4 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -303,6 +303,9 @@ void ospf6_interface_delete(struct ospf6_interface *oi)
/* disable from area list if possible */
ospf6_area_interface_delete(oi);
+ if (oi->at_data.auth_key)
+ XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, oi->at_data.auth_key);
+
/* Free BFD allocated data. */
XFREE(MTYPE_TMP, oi->bfd_config.profile);
@@ -1242,7 +1245,8 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
}
}
- json_auth = json_object_new_object();
+ if (use_json)
+ json_auth = json_object_new_object();
if (oi->at_data.flags != 0) {
if (use_json) {
if (CHECK_FLAG(oi->at_data.flags,
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index 2792820a54..55ac7c88a5 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -573,7 +573,7 @@ void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa,
json = json_object_new_object();
size_t header_str_sz = (2 * (end - start)) + 1;
- header_str = XMALLOC(MTYPE_TMP, header_str_sz);
+ header_str = XMALLOC(MTYPE_OSPF6_LSA_HEADER, header_str_sz);
inet_ntop(AF_INET, &lsa->header->id, id, sizeof(id));
inet_ntop(AF_INET, &lsa->header->adv_router, adv_router,
@@ -586,7 +586,7 @@ void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa,
json_object_string_add(json, "header", header_str);
json_object_array_add(json_array, json);
- XFREE(MTYPE_TMP, header_str);
+ XFREE(MTYPE_OSPF6_LSA_HEADER, header_str);
} else {
vty_out(vty, "\n%s:\n", lsa->name);
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 360a9db0d6..fb54ebab15 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -2015,6 +2015,9 @@ static void ospf6_auth_trailer_copy_keychain_key(struct ospf6_interface *oi)
* these values
*/
oi->at_data.hash_algo = key->hash_algo;
+ if (oi->at_data.auth_key)
+ XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY,
+ oi->at_data.auth_key);
oi->at_data.auth_key = XSTRDUP(
MTYPE_OSPF6_AUTH_MANUAL_KEY, key->string);
oi->at_data.key_id = key->index;
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 439b94c9af..a4ba1fb569 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -106,6 +106,23 @@ struct ospf6_neighbor *ospf6_area_neighbor_lookup(struct ospf6_area *area,
return NULL;
}
+static void ospf6_neighbor_clear_ls_lists(struct ospf6_neighbor *on)
+{
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsanext;
+
+ ospf6_lsdb_remove_all(on->summary_list);
+ if (on->last_ls_req) {
+ ospf6_lsa_unlock(on->last_ls_req);
+ on->last_ls_req = NULL;
+ }
+ ospf6_lsdb_remove_all(on->request_list);
+ for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
+ ospf6_decrement_retrans_count(lsa);
+ ospf6_lsdb_remove(lsa, on->retrans_list);
+ }
+}
+
/* create ospf6_neighbor */
struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
struct ospf6_interface *oi)
@@ -147,14 +164,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
void ospf6_neighbor_delete(struct ospf6_neighbor *on)
{
- struct ospf6_lsa *lsa, *lsanext;
-
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
ospf6_lsdb_remove_all(on->dbdesc_list);
ospf6_lsdb_remove_all(on->lsupdate_list);
@@ -339,12 +349,7 @@ void negotiation_done(struct thread *thread)
zlog_debug("Neighbor Event %s: *NegotiationDone*", on->name);
/* clear ls-list */
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
/* Interface scoped LSAs */
for (ALL_LSDB(on->ospf6_if->lsdb, lsa, lsanext)) {
@@ -464,7 +469,6 @@ void loading_done(struct thread *thread)
void adj_ok(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsanext;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -486,19 +490,13 @@ void adj_ok(struct thread *thread)
} else if (on->state >= OSPF6_NEIGHBOR_EXSTART && !need_adjacency(on)) {
ospf6_neighbor_state_change(OSPF6_NEIGHBOR_TWOWAY, on,
OSPF6_NEIGHBOR_EVENT_ADJ_OK);
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
}
}
void seqnumber_mismatch(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsanext;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -515,12 +513,7 @@ void seqnumber_mismatch(struct thread *thread)
SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
THREAD_OFF(on->thread_send_dbdesc);
on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
@@ -532,7 +525,6 @@ void seqnumber_mismatch(struct thread *thread)
void bad_lsreq(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsanext;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -549,12 +541,7 @@ void bad_lsreq(struct thread *thread)
SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
THREAD_OFF(on->thread_send_dbdesc);
on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
@@ -567,7 +554,6 @@ void bad_lsreq(struct thread *thread)
void oneway_received(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsanext;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -582,12 +568,7 @@ void oneway_received(struct thread *thread)
OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD);
thread_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
THREAD_OFF(on->thread_send_dbdesc);
THREAD_OFF(on->thread_send_lsreq);
diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c
index f35c9df4a5..2921046837 100644
--- a/ospf6d/ospf6_nssa.c
+++ b/ospf6d/ospf6_nssa.c
@@ -1090,7 +1090,25 @@ static void ospf6_check_and_originate_type7_lsa(struct ospf6_area *area)
ospf6_nssa_lsa_originate(aggr->route, area, true);
}
}
+}
+
+static void ospf6_ase_lsa_refresh(struct ospf6 *o)
+{
+ struct ospf6_lsa *old;
+ for (struct ospf6_route *route = ospf6_route_head(o->external_table);
+ route; route = ospf6_route_next(route)) {
+ old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+ route->path.origin.id, o->router_id,
+ o->lsdb);
+ if (old) {
+ THREAD_OFF(old->refresh);
+ thread_add_event(master, ospf6_lsa_refresh, old, 0,
+ &old->refresh);
+ } else {
+ ospf6_as_external_lsa_originate(route, o);
+ }
+ }
}
void ospf6_area_nssa_update(struct ospf6_area *area)
@@ -1134,6 +1152,36 @@ void ospf6_area_nssa_update(struct ospf6_area *area)
if (IS_OSPF6_DEBUG_NSSA)
zlog_debug("Normal area %s", area->name);
ospf6_nssa_flush_area(area);
+
+ /* Check if router is ABR */
+ if (ospf6_check_and_set_router_abr(area->ospf6)) {
+ if (IS_OSPF6_DEBUG_NSSA)
+ zlog_debug("Router is ABR area %s", area->name);
+ ospf6_schedule_abr_task(area->ospf6);
+ ospf6_ase_lsa_refresh(area->ospf6);
+ } else {
+ uint16_t type;
+ struct ospf6_lsa *lsa = NULL;
+
+ /*
+ * Refresh all type-5 LSAs so they get installed
+ * in the converted ares
+ */
+ if (IS_OSPF6_DEBUG_NSSA)
+ zlog_debug("Refresh type-5 LSAs, area %s",
+ area->name);
+
+ type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+ for (ALL_LSDB_TYPED_ADVRTR(area->ospf6->lsdb, type,
+ area->ospf6->router_id,
+ lsa)) {
+ if (IS_OSPF6_DEBUG_NSSA)
+ ospf6_lsa_header_print(lsa);
+ THREAD_OFF(lsa->refresh);
+ thread_add_event(master, ospf6_lsa_refresh, lsa,
+ 0, &lsa->refresh);
+ }
+ }
}
}
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index db94b85b1b..9603c91a9a 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -246,7 +246,10 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src)
}
}
-int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
+/*
+ * If the nexthops are the same return true
+ */
+bool ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
{
struct listnode *anode, *bnode;
struct ospf6_nexthop *anh, *bnh;
@@ -264,14 +267,14 @@ int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
/* Currnet List A element not found List B
* Non-Identical lists return */
if (identical == false)
- return 1;
+ return false;
}
- return 0;
+ return true;
} else
- return 1;
+ return false;
}
/* One of the routes doesn't exist ? */
- return (1);
+ return false;
}
int ospf6_num_nexthops(struct list *nh_list)
@@ -577,12 +580,7 @@ ospf6_route_lookup_identical(struct ospf6_route *route,
for (target = ospf6_route_lookup(&route->prefix, table); target;
target = target->next) {
- if (target->type == route->type
- && prefix_same(&target->prefix, &route->prefix)
- && target->path.type == route->path.type
- && target->path.cost == route->path.cost
- && target->path.u.cost_e2 == route->path.u.cost_e2
- && ospf6_route_cmp_nexthops(target, route) == 0)
+ if (ospf6_route_is_identical(target, route))
return target;
}
return NULL;
@@ -702,6 +700,27 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
}
if (old) {
+ /* if route does not actually change, return unchanged */
+ if (ospf6_route_is_identical(old, route)) {
+ if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
+ zlog_debug(
+ "%s %p: route add %p: needless update of %p old cost %u",
+ ospf6_route_table_name(table),
+ (void *)table, (void *)route,
+ (void *)old, old->path.cost);
+ else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
+ zlog_debug("%s: route add: needless update",
+ ospf6_route_table_name(table));
+
+ ospf6_route_delete(route);
+ SET_FLAG(old->flag, OSPF6_ROUTE_ADD);
+ ospf6_route_table_assert(table);
+
+ /* to free the lookup lock */
+ route_unlock_node(node);
+ return old;
+ }
+
if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
zlog_debug(
"%s %p: route add %p cost %u paths %u nh %u: update of %p cost %u paths %u nh %u",
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index bb5827a176..71a84a5c5d 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -297,6 +297,14 @@ extern const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX];
&& (ra)->path.origin.type == (rb)->path.origin.type \
&& (ra)->path.origin.id == (rb)->path.origin.id \
&& (ra)->path.origin.adv_router == (rb)->path.origin.adv_router)
+#define ospf6_route_is_identical(ra, rb) \
+ ((ra)->type == (rb)->type && \
+ prefix_same(&(ra)->prefix, &(rb)->prefix) && \
+ (ra)->path.type == (rb)->path.type && \
+ (ra)->path.cost == (rb)->path.cost && \
+ (ra)->path.u.cost_e2 == (rb)->path.u.cost_e2 && \
+ listcount(ra->paths) == listcount(rb->paths) && \
+ ospf6_route_cmp_nexthops(ra, rb))
#define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST))
@@ -322,8 +330,8 @@ extern void ospf6_add_nexthop(struct list *nh_list, int ifindex,
struct in6_addr *addr);
extern void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route);
extern int ospf6_num_nexthops(struct list *nh_list);
-extern int ospf6_route_cmp_nexthops(struct ospf6_route *a,
- struct ospf6_route *b);
+extern bool ospf6_route_cmp_nexthops(struct ospf6_route *a,
+ struct ospf6_route *b);
extern void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
struct zapi_nexthop nexthops[],
int entries, vrf_id_t vrf_id);
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index eb89a14cd3..db45fa5f5c 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -498,6 +498,7 @@ void ospf6_delete(struct ospf6 *o)
struct route_node *rn = NULL;
struct ospf6_area *oa;
struct vrf *vrf;
+ struct ospf6_external_aggr_rt *aggr;
QOBJ_UNREG(o);
@@ -536,8 +537,11 @@ void ospf6_delete(struct ospf6 *o)
}
for (rn = route_top(o->rt_aggr_tbl); rn; rn = route_next(rn))
- if (rn->info)
- ospf6_external_aggregator_free(rn->info);
+ if (rn->info) {
+ aggr = rn->info;
+ ospf6_asbr_summary_config_delete(o, rn);
+ ospf6_external_aggregator_free(aggr);
+ }
route_table_finish(o->rt_aggr_tbl);
XFREE(MTYPE_OSPF6_TOP, o->name);
diff --git a/ospfclient/ospf_apiclient.c b/ospfclient/ospf_apiclient.c
index 05c5e7789d..4982cd885e 100644
--- a/ospfclient/ospf_apiclient.c
+++ b/ospfclient/ospf_apiclient.c
@@ -54,10 +54,6 @@
#include "ospf_apiclient.h"
-/* *sigh* ... can't find a better way to hammer this into automake */
-#include "ospfd/ospf_dump_api.c"
-#include "ospfd/ospf_api.c"
-
XREF_SETUP();
DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient");
diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am
index b8c82c0bcf..289ddd009d 100644
--- a/ospfclient/subdir.am
+++ b/ospfclient/subdir.am
@@ -27,6 +27,7 @@ endif
ospfclient_ospfclient_LDADD = \
ospfclient/libfrrospfapiclient.la \
+ ospfd/libfrrospfclient.a \
$(LIBCAP) \
# end
diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h
index 6f569e962d..fd741c3c48 100644
--- a/ospfd/ospf_api.h
+++ b/ospfd/ospf_api.h
@@ -298,7 +298,7 @@ struct apimsg {
} u;
};
-#define OSPF_API_MAX_MSG_SIZE (sizeof(struct apimsg) + OSPF_MAX_LSA_SIZE)
+#define OSPF_API_MAX_MSG_SIZE (sizeof(struct apimsg) + OSPF_MAX_PACKET_SIZE)
/* -----------------------------------------------------------
* Prototypes for specific messages
diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c
index 0c2ee0c4f8..6fd1c82c24 100644
--- a/ospfd/ospf_apiserver.c
+++ b/ospfd/ospf_apiserver.c
@@ -56,10 +56,14 @@
#include "ospfd/ospf_ase.h"
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_errors.h"
+#include "ospfd/ospf_memory.h"
#include "ospfd/ospf_api.h"
#include "ospfd/ospf_apiserver.h"
+DEFINE_MTYPE_STATIC(OSPFD, APISERVER, "API Server");
+DEFINE_MTYPE_STATIC(OSPFD, APISERVER_MSGFILTER, "API Server Message Filter");
+
/* This is an implementation of an API to the OSPF daemon that allows
* external applications to access the OSPF daemon through socket
* connections. The application can use this API to inject its own
@@ -245,9 +249,9 @@ static int ospf_apiserver_del_lsa_hook(struct ospf_lsa *lsa)
struct ospf_apiserver *ospf_apiserver_new(int fd_sync, int fd_async)
{
struct ospf_apiserver *new =
- XMALLOC(MTYPE_OSPF_APISERVER, sizeof(struct ospf_apiserver));
+ XMALLOC(MTYPE_APISERVER, sizeof(struct ospf_apiserver));
- new->filter = XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER,
+ new->filter = XMALLOC(MTYPE_APISERVER_MSGFILTER,
sizeof(struct lsa_filter_type));
new->fd_sync = fd_sync;
@@ -360,7 +364,7 @@ void ospf_apiserver_free(struct ospf_apiserver *apiserv)
(void *)apiserv, apiserver_list->count);
/* And free instance. */
- XFREE(MTYPE_OSPF_APISERVER, apiserv);
+ XFREE(MTYPE_APISERVER, apiserv);
}
void ospf_apiserver_read(struct thread *thread)
@@ -862,8 +866,8 @@ int ospf_apiserver_register_opaque_type(struct ospf_apiserver *apiserv,
connection shuts down, we can flush all LSAs of this opaque
type. */
- regtype = XCALLOC(MTYPE_OSPF_APISERVER,
- sizeof(struct registered_opaque_type));
+ regtype =
+ XCALLOC(MTYPE_APISERVER, sizeof(struct registered_opaque_type));
regtype->lsa_type = lsa_type;
regtype->opaque_type = opaque_type;
@@ -1155,12 +1159,12 @@ int ospf_apiserver_handle_register_event(struct ospf_apiserver *apiserv,
seqnum = msg_get_seq(msg);
/* Free existing filter in apiserv. */
- XFREE(MTYPE_OSPF_APISERVER_MSGFILTER, apiserv->filter);
+ XFREE(MTYPE_APISERVER_MSGFILTER, apiserv->filter);
/* Alloc new space for filter. */
size = ntohs(msg->hdr.msglen);
if (size < OSPF_MAX_LSA_SIZE) {
- apiserv->filter = XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, size);
+ apiserv->filter = XMALLOC(MTYPE_APISERVER_MSGFILTER, size);
/* copy it over. */
memcpy(apiserv->filter, &rmsg->filter, size);
@@ -1365,8 +1369,7 @@ int ospf_apiserver_handle_sync_reachable(struct ospf_apiserver *apiserv,
goto out;
/* send all adds based on current reachable routers */
- a = abuf = XCALLOC(MTYPE_OSPF_APISERVER,
- sizeof(struct in_addr) * rt->count);
+ a = abuf = XCALLOC(MTYPE_APISERVER, sizeof(struct in_addr) * rt->count);
for (struct route_node *rn = route_top(rt); rn; rn = route_next(rn))
if (listhead((struct list *)rn->info))
*a++ = rn->p.u.prefix4;
@@ -1385,7 +1388,7 @@ int ospf_apiserver_handle_sync_reachable(struct ospf_apiserver *apiserv,
rc = ospf_apiserver_send_msg(apiserv, amsg);
msg_free(amsg);
}
- XFREE(MTYPE_OSPF_APISERVER, abuf);
+ XFREE(MTYPE_APISERVER, abuf);
out:
/* Send a reply back to client with return code */
@@ -2616,9 +2619,9 @@ void ospf_apiserver_notify_reachable(struct route_table *ort,
return;
}
if (nrt && nrt->count)
- a = abuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * nrt->count);
+ a = abuf = XCALLOC(MTYPE_APISERVER, insz * nrt->count);
if (ort && ort->count)
- d = dbuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * ort->count);
+ d = dbuf = XCALLOC(MTYPE_APISERVER, insz * ort->count);
/* walk both tables */
orn = ort ? route_top(ort) : NULL;
@@ -2683,9 +2686,9 @@ void ospf_apiserver_notify_reachable(struct route_table *ort,
msg_free(msg);
}
if (abuf)
- XFREE(MTYPE_OSPF_APISERVER, abuf);
+ XFREE(MTYPE_APISERVER, abuf);
if (dbuf)
- XFREE(MTYPE_OSPF_APISERVER, dbuf);
+ XFREE(MTYPE_APISERVER, dbuf);
}
diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h
index e28202e46f..0a6b7319a0 100644
--- a/ospfd/ospf_apiserver.h
+++ b/ospfd/ospf_apiserver.h
@@ -26,10 +26,6 @@
#include "ospf_api.h"
#include "ospf_lsdb.h"
-/* MTYPE definition is not reflected to "memory.h". */
-#define MTYPE_OSPF_APISERVER MTYPE_TMP
-#define MTYPE_OSPF_APISERVER_MSGFILTER MTYPE_TMP
-
/* List of opaque types that application registered */
struct registered_opaque_type {
uint8_t lsa_type;
diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c
index ab75ab9a1a..d4565b6651 100644
--- a/ospfd/ospf_ism.c
+++ b/ospfd/ospf_ism.c
@@ -223,8 +223,10 @@ int ospf_dr_election(struct ospf_interface *oi)
new_state = ospf_ism_state(oi);
- zlog_debug("DR-Election[1st]: Backup %pI4", &BDR(oi));
- zlog_debug("DR-Election[1st]: DR %pI4", &DR(oi));
+ if (IS_DEBUG_OSPF(ism, ISM_STATUS)) {
+ zlog_debug("DR-Election[1st]: Backup %pI4", &BDR(oi));
+ zlog_debug("DR-Election[1st]: DR %pI4", &DR(oi));
+ }
if (new_state != old_state
&& !(new_state == ISM_DROther && old_state < ISM_DROther)) {
@@ -233,8 +235,10 @@ int ospf_dr_election(struct ospf_interface *oi)
new_state = ospf_ism_state(oi);
- zlog_debug("DR-Election[2nd]: Backup %pI4", &BDR(oi));
- zlog_debug("DR-Election[2nd]: DR %pI4", &DR(oi));
+ if (IS_DEBUG_OSPF(ism, ISM_STATUS)) {
+ zlog_debug("DR-Election[2nd]: Backup %pI4", &BDR(oi));
+ zlog_debug("DR-Election[2nd]: DR %pI4", &DR(oi));
+ }
}
list_delete(&el_list);
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index a67b6c6c19..ad4a9fd142 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -428,8 +428,10 @@ struct ospf_neighbor *ospf_nbr_lookup_ptop(struct ospf_interface *oi)
/* PtoP link must have only 1 neighbor. */
if (ospf_nbr_count(oi, 0) > 1)
- flog_warn(EC_OSPF_PTP_NEIGHBOR,
- "Point-to-Point link has more than 1 neighobrs.");
+ flog_warn(
+ EC_OSPF_PTP_NEIGHBOR,
+ "Point-to-Point link on interface %s has more than 1 neighbor.",
+ oi->ifp->name);
return nbr;
}
@@ -3648,6 +3650,7 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
struct ospf_interface *oi;
struct ospf_lsa *lsa;
struct route_node *rn;
+ struct ospf_if_params *oip;
int need_to_flush_ase = 0;
ospf->inst_shutdown = 1;
@@ -3680,6 +3683,12 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
ospf_lsa_flush_area(oi->network_lsa_self, area);
ospf_lsa_unlock(&oi->network_lsa_self);
oi->network_lsa_self = NULL;
+
+ oip = ospf_lookup_if_params(
+ oi->ifp, oi->address->u.prefix4);
+ if (oip)
+ oip->network_lsa_seqnum = htonl(
+ OSPF_INVALID_SEQUENCE_NUMBER);
}
if (oi->type != OSPF_IFTYPE_VIRTUALLINK
diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c
index be06afe532..a8c9493ec8 100644
--- a/ospfd/ospf_network.c
+++ b/ospfd/ospf_network.c
@@ -104,11 +104,12 @@ int ospf_if_add_alldrouters(struct ospf *top, struct prefix *p,
"can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?",
top->fd, &p->u.prefix4, ifindex,
safe_strerror(errno));
- else
- zlog_debug(
- "interface %pI4 [%u] join AllDRouters Multicast group.",
- &p->u.prefix4, ifindex);
-
+ else {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "interface %pI4 [%u] join AllDRouters Multicast group.",
+ &p->u.prefix4, ifindex);
+ }
return ret;
}
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 8c87a568c0..0cb9d02725 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -1169,8 +1169,8 @@ static void ospf_db_desc_proc(struct stream *s, struct ospf_interface *oi,
if (IS_OPAQUE_LSA(lsah->type)
&& !CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
flog_warn(EC_OSPF_PACKET,
- "LSA[Type%d:%pI4]: Opaque capability mismatch?",
- lsah->type, &lsah->id);
+ "LSA[Type%d:%pI4] from %pI4: Opaque capability mismatch?",
+ lsah->type, &lsah->id, &lsah->adv_router);
OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch);
return;
}
diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c
index 9727c7039c..f1b876cfbe 100644
--- a/ospfd/ospf_snmp.c
+++ b/ospfd/ospf_snmp.c
@@ -50,6 +50,8 @@
#include "ospfd/ospf_route.h"
#include "ospfd/ospf_zebra.h"
+DEFINE_MTYPE_STATIC(OSPFD, SNMP, "OSPF SNMP");
+
/* OSPF2-MIB. */
#define OSPF2MIB 1,3,6,1,2,1,14
@@ -1321,12 +1323,12 @@ struct ospf_snmp_if {
static struct ospf_snmp_if *ospf_snmp_if_new(void)
{
- return XCALLOC(MTYPE_TMP, sizeof(struct ospf_snmp_if));
+ return XCALLOC(MTYPE_SNMP, sizeof(struct ospf_snmp_if));
}
static void ospf_snmp_if_free(struct ospf_snmp_if *osif)
{
- XFREE(MTYPE_TMP, osif);
+ XFREE(MTYPE_SNMP, osif);
}
static int ospf_snmp_if_delete(struct interface *ifp)
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 24ca4dcbf4..58fcbfa4a9 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -181,8 +181,10 @@ static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink,
return new;
}
-static void vertex_parent_free(void *p)
+static void vertex_parent_free(struct vertex_parent *p)
{
+ vertex_nexthop_free(p->local_nexthop);
+ vertex_nexthop_free(p->nexthop);
XFREE(MTYPE_OSPF_VERTEX_PARENT, p);
}
@@ -205,7 +207,7 @@ static struct vertex *ospf_vertex_new(struct ospf_area *area,
new->lsa = lsa->data;
new->children = list_new();
new->parents = list_new();
- new->parents->del = vertex_parent_free;
+ new->parents->del = (void (*)(void *))vertex_parent_free;
new->parents->cmp = vertex_parent_cmp;
new->lsa_p = lsa;
@@ -348,7 +350,7 @@ static struct vertex *ospf_spf_vertex_copy(struct vertex *vertex)
memcpy(copy, vertex, sizeof(struct vertex));
copy->parents = list_new();
- copy->parents->del = vertex_parent_free;
+ copy->parents->del = (void (*)(void *))vertex_parent_free;
copy->parents->cmp = vertex_parent_cmp;
copy->children = list_new();
@@ -685,11 +687,15 @@ static void ospf_spf_flush_parents(struct vertex *w)
/*
* Consider supplied next-hop for inclusion to the supplied list of
* equal-cost next-hops, adjust list as necessary.
+ *
+ * Returns vertex parent pointer if created otherwise `NULL` if it already
+ * exists.
*/
-static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
- struct vertex_nexthop *newhop,
- struct vertex_nexthop *newlhop,
- unsigned int distance)
+static struct vertex_parent *ospf_spf_add_parent(struct vertex *v,
+ struct vertex *w,
+ struct vertex_nexthop *newhop,
+ struct vertex_nexthop *newlhop,
+ unsigned int distance)
{
struct vertex_parent *vp, *wp;
struct listnode *node;
@@ -735,7 +741,8 @@ static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
zlog_debug(
"%s: ... nexthop already on parent list, skipping add",
__func__);
- return;
+
+ return NULL;
}
}
@@ -743,7 +750,7 @@ static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
newlhop);
listnode_add_sort(w->parents, vp);
- return;
+ return vp;
}
static int match_stub_prefix(struct lsa_header *lsa, struct in_addr v_link_addr,
@@ -981,8 +988,12 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
memcpy(lnh, nh,
sizeof(struct vertex_nexthop));
- ospf_spf_add_parent(v, w, nh, lnh,
- distance);
+ if (ospf_spf_add_parent(v, w, nh, lnh,
+ distance) ==
+ NULL) {
+ vertex_nexthop_free(nh);
+ vertex_nexthop_free(lnh);
+ }
return 1;
} else
zlog_info(
@@ -1021,8 +1032,13 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
memcpy(lnh, nh,
sizeof(struct vertex_nexthop));
- ospf_spf_add_parent(v, w, nh, lnh,
- distance);
+ if (ospf_spf_add_parent(v, w, nh, lnh,
+ distance) ==
+ NULL) {
+ vertex_nexthop_free(nh);
+ vertex_nexthop_free(lnh);
+ }
+
return 1;
} else
zlog_info(
@@ -1045,7 +1061,12 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
lnh = vertex_nexthop_new();
memcpy(lnh, nh, sizeof(struct vertex_nexthop));
- ospf_spf_add_parent(v, w, nh, lnh, distance);
+ if (ospf_spf_add_parent(v, w, nh, lnh, distance) ==
+ NULL) {
+ vertex_nexthop_free(nh);
+ vertex_nexthop_free(lnh);
+ }
+
return 1;
}
} /* end V is the root */
@@ -1088,8 +1109,12 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
sizeof(struct vertex_nexthop));
added = 1;
- ospf_spf_add_parent(v, w, nh, lnh,
- distance);
+ if (ospf_spf_add_parent(v, w, nh, lnh,
+ distance) ==
+ NULL) {
+ vertex_nexthop_free(nh);
+ vertex_nexthop_free(lnh);
+ }
}
/*
* Note lack of return is deliberate. See next
@@ -1150,7 +1175,13 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
lnh = NULL;
}
- ospf_spf_add_parent(v, w, vp->nexthop, lnh, distance);
+ nh = vertex_nexthop_new();
+ *nh = *vp->nexthop;
+
+ if (ospf_spf_add_parent(v, w, nh, lnh, distance) == NULL) {
+ vertex_nexthop_free(nh);
+ vertex_nexthop_free(lnh);
+ }
}
return added;
@@ -1925,9 +1956,10 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
rt_time = monotime_since(&start_time, NULL);
/* Free old all routers routing table */
- if (ospf->oall_rtrs)
- /* ospf_route_delete (ospf->old_rtrs); */
+ if (ospf->oall_rtrs) {
ospf_rtrs_free(ospf->oall_rtrs);
+ ospf->oall_rtrs = NULL;
+ }
/* Update all routers routing table */
ospf->oall_rtrs = ospf->all_rtrs;
@@ -1936,9 +1968,10 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs);
#endif
/* Free old ABR/ASBR routing table */
- if (ospf->old_rtrs)
- /* ospf_route_delete (ospf->old_rtrs); */
+ if (ospf->old_rtrs) {
ospf_rtrs_free(ospf->old_rtrs);
+ ospf->old_rtrs = NULL;
+ }
/* Update ABR/ASBR routing table */
ospf->old_rtrs = ospf->new_rtrs;
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 0bab045ef4..43b7de552a 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -6614,14 +6614,17 @@ static void show_lsa_detail_proc(struct vty *vty, struct route_table *rt,
route_lock_node(start);
for (rn = start; rn; rn = route_next_until(rn, start))
if ((lsa = rn->info)) {
- if (json) {
- json_lsa = json_object_new_object();
- json_object_array_add(json, json_lsa);
- }
+ if (show_function[lsa->data->type] != NULL) {
+ if (json) {
+ json_lsa =
+ json_object_new_object();
+ json_object_array_add(json,
+ json_lsa);
+ }
- if (show_function[lsa->data->type] != NULL)
show_function[lsa->data->type](
vty, lsa, json_lsa);
+ }
}
route_unlock_node(start);
}
@@ -6640,9 +6643,6 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type,
json_object *json_areas = NULL;
json_object *json_lsa_array = NULL;
- if (json)
- json_lsa_type = json_object_new_object();
-
switch (type) {
case OSPF_AS_EXTERNAL_LSA:
case OSPF_OPAQUE_AS_LSA:
@@ -6685,6 +6685,7 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type,
}
if (json) {
+ json_lsa_type = json_object_new_object();
json_object_object_add(json_lsa_type, "areas",
json_areas);
json_object_object_add(json,
@@ -7158,6 +7159,9 @@ DEFUN (show_ip_ospf_database_max,
vty_out(vty,
"%% OSPF is not enabled in vrf %s\n",
vrf_name);
+ if (uj)
+ json_object_free(json);
+
return CMD_SUCCESS;
}
ret = (show_ip_ospf_database_common(
@@ -7169,6 +7173,9 @@ DEFUN (show_ip_ospf_database_max,
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
if (ospf == NULL || !ospf->oi_running) {
vty_out(vty, "%% OSPF is not enabled in vrf default\n");
+ if (uj)
+ json_object_free(json);
+
return CMD_SUCCESS;
}
@@ -11209,15 +11216,37 @@ DEFUN (show_ip_ospf_instance_reachable_routers,
static int show_ip_ospf_border_routers_common(struct vty *vty,
struct ospf *ospf,
- uint8_t use_vrf)
+ uint8_t use_vrf,
+ json_object *json)
{
- if (ospf->instance)
- vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance);
+ json_object *json_vrf = NULL;
+ json_object *json_router = NULL;
- ospf_show_vrf_name(ospf, vty, NULL, use_vrf);
+ if (json) {
+ if (use_vrf)
+ json_vrf = json_object_new_object();
+ else
+ json_vrf = json;
+ json_router = json_object_new_object();
+ }
+
+ if (ospf->instance) {
+ if (!json)
+ vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance);
+ else
+ json_object_int_add(json_vrf, "ospfInstance",
+ ospf->instance);
+ }
+
+ ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf);
if (ospf->new_table == NULL) {
- vty_out(vty, "No OSPF routing information exist\n");
+ if (!json)
+ vty_out(vty, "No OSPF routing information exist\n");
+ else {
+ json_object_free(json_router);
+ json_object_free(json_vrf);
+ }
return CMD_SUCCESS;
}
@@ -11225,22 +11254,35 @@ static int show_ip_ospf_border_routers_common(struct vty *vty,
show_ip_ospf_route_network (vty, ospf->new_table); */
/* Show Router routes. */
- show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, NULL);
+ show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, json_router);
- vty_out(vty, "\n");
+ if (json) {
+ json_object_object_add(json_vrf, "routers", json_router);
+ if (use_vrf) {
+ if (ospf->vrf_id == VRF_DEFAULT)
+ json_object_object_add(json, "default",
+ json_vrf);
+ else
+ json_object_object_add(json, ospf->name,
+ json_vrf);
+ }
+ } else {
+ vty_out(vty, "\n");
+ }
return CMD_SUCCESS;
}
-DEFUN (show_ip_ospf_border_routers,
+DEFPY (show_ip_ospf_border_routers,
show_ip_ospf_border_routers_cmd,
- "show ip ospf [vrf <NAME|all>] border-routers",
+ "show ip ospf [vrf <NAME|all>] border-routers [json]",
SHOW_STR
IP_STR
"OSPF information\n"
VRF_CMD_HELP_STR
"All VRFs\n"
- "Show all the ABR's and ASBR's\n")
+ "Show all the ABR's and ASBR's\n"
+ JSON_STR)
{
struct ospf *ospf = NULL;
struct listnode *node = NULL;
@@ -11250,6 +11292,11 @@ DEFUN (show_ip_ospf_border_routers,
int inst = 0;
int idx_vrf = 0;
uint8_t use_vrf = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+
+ if (uj)
+ json = json_object_new_object();
OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
@@ -11265,32 +11312,47 @@ DEFUN (show_ip_ospf_border_routers,
ospf_output = true;
ret = show_ip_ospf_border_routers_common(
- vty, ospf, use_vrf);
+ vty, ospf, use_vrf, json);
}
- if (!ospf_output)
+ if (uj)
+ vty_json(vty, json);
+ else if (!ospf_output)
vty_out(vty, "%% OSPF is not enabled\n");
+
+ return ret;
} else {
ospf = ospf_lookup_by_inst_name(inst, vrf_name);
if (ospf == NULL || !ospf->oi_running) {
- vty_out(vty,
- "%% OSPF is not enabled in vrf %s\n",
- vrf_name);
+ if (uj)
+ vty_json(vty, json);
+ else
+ vty_out(vty,
+ "%% OSPF is not enabled in vrf %s\n",
+ vrf_name);
+
return CMD_SUCCESS;
}
-
- ret = show_ip_ospf_border_routers_common(vty, ospf,
- use_vrf);
}
} else {
/* Display default ospf (instance 0) info */
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
if (ospf == NULL || !ospf->oi_running) {
- vty_out(vty, "%% OSPF is not enabled in vrf default\n");
+ if (uj)
+ vty_json(vty, json);
+ else
+ vty_out(vty,
+ "%% OSPF is not enabled in vrf default\n");
+
return CMD_SUCCESS;
}
+ }
- ret = show_ip_ospf_border_routers_common(vty, ospf, use_vrf);
+ if (ospf) {
+ ret = show_ip_ospf_border_routers_common(vty, ospf, use_vrf,
+ json);
+ if (uj)
+ vty_json(vty, json);
}
return ret;
@@ -11317,7 +11379,7 @@ DEFUN (show_ip_ospf_instance_border_routers,
if (!ospf || !ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_border_routers_common(vty, ospf, 0);
+ return show_ip_ospf_border_routers_common(vty, ospf, 0, NULL);
}
static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf,
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 3f82d86921..a5d40ad176 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -89,6 +89,25 @@ static int ospf_network_match_iface(const struct connected *,
const struct prefix *);
static void ospf_finish_final(struct ospf *);
+/* API to clean refresh queues and LSAs */
+static void ospf_free_refresh_queue(struct ospf *ospf)
+{
+ for (int i = 0; i < OSPF_LSA_REFRESHER_SLOTS; i++) {
+ struct list *list = ospf->lsa_refresh_queue.qs[i];
+ struct listnode *node, *nnode;
+ struct ospf_lsa *lsa;
+
+ if (list) {
+ for (ALL_LIST_ELEMENTS(list, node, nnode, lsa)) {
+ listnode_delete(list, lsa);
+ lsa->refresh_list = -1;
+ ospf_lsa_unlock(&lsa);
+ }
+ list_delete(&list);
+ ospf->lsa_refresh_queue.qs[i] = NULL;
+ }
+ }
+}
#define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1
int p_spaces_compare_func(const struct p_space *a, const struct p_space *b)
@@ -833,6 +852,10 @@ static void ospf_finish_final(struct ospf *ospf)
ospf_route_delete(ospf, ospf->new_table);
ospf_route_table_free(ospf->new_table);
}
+ if (ospf->oall_rtrs)
+ ospf_rtrs_free(ospf->oall_rtrs);
+ if (ospf->all_rtrs)
+ ospf_rtrs_free(ospf->all_rtrs);
if (ospf->old_rtrs)
ospf_rtrs_free(ospf->old_rtrs);
if (ospf->new_rtrs)
@@ -895,6 +918,8 @@ static void ospf_finish_final(struct ospf *ospf)
route_table_finish(ospf->rt_aggr_tbl);
+ ospf_free_refresh_queue(ospf);
+
list_delete(&ospf->areas);
list_delete(&ospf->oi_write_q);
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
index b67f942883..e45f617dfa 100644
--- a/ospfd/subdir.am
+++ b/ospfd/subdir.am
@@ -4,6 +4,7 @@
if OSPFD
noinst_LIBRARIES += ospfd/libfrrospf.a
+noinst_LIBRARIES += ospfd/libfrrospfclient.a
sbin_PROGRAMS += ospfd/ospfd
vtysh_daemons += ospfd
if SNMP
@@ -12,6 +13,11 @@ endif
man8 += $(MANBUILD)/frr-ospfd.8
endif
+ospfd_libfrrospfclient_a_SOURCES = \
+ ospfd/ospf_api.c \
+ ospfd/ospf_dump_api.c \
+ #end
+
ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_abr.c \
ospfd/ospf_api.c \
@@ -104,7 +110,7 @@ noinst_HEADERS += \
ospfd/ospf_zebra.h \
# end
-ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM)
+ospfd_ospfd_LDADD = ospfd/libfrrospf.a ospfd/libfrrospfclient.a lib/libfrr.la $(LIBCAP) $(LIBM)
ospfd_ospfd_SOURCES = ospfd/ospf_main.c
ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c
diff --git a/pathd/path_pcep_config.c b/pathd/path_pcep_config.c
index 99b1c349a9..873b0ccd37 100644
--- a/pathd/path_pcep_config.c
+++ b/pathd/path_pcep_config.c
@@ -453,8 +453,7 @@ int path_pcep_config_update_path(struct path *path)
}
if (number_of_sid_clashed)
- SET_FLAG(segment->segment_list->flags,
- F_SEGMENT_LIST_SID_CONFLICT);
+ SET_FLAG(segment_list->flags, F_SEGMENT_LIST_SID_CONFLICT);
else
srte_apply_changes();
diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c
index b39f688cdb..28e4c488f3 100644
--- a/pimd/pim_cmd_common.c
+++ b/pimd/pim_cmd_common.c
@@ -2824,21 +2824,35 @@ static int pim_print_vty_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
struct nexthop *nh_node = NULL;
ifindex_t first_ifindex;
struct interface *ifp = NULL;
+ struct ttable *tt = NULL;
+ char *table = NULL;
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Address|Interface|Nexthop");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
first_ifindex = nh_node->ifindex;
ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
- vty_out(vty, "%-15pPA ", &pnc->rpf.rpf_addr);
- vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
#if PIM_IPV == 4
- vty_out(vty, "%pI4 ", &nh_node->gate.ipv4);
+ ttable_add_row(tt, "%pPA|%s|%pI4", &pnc->rpf.rpf_addr,
+ ifp ? ifp->name : "NULL", &nh_node->gate.ipv4);
#else
- vty_out(vty, "%pI6 ", &nh_node->gate.ipv6);
+ ttable_add_row(tt, "%pPA|%s|%pI6", &pnc->rpf.rpf_addr,
+ ifp ? ifp->name : "NULL", &nh_node->gate.ipv6);
#endif
- vty_out(vty, "\n");
}
+ /* Dump the generated table. */
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+
return CMD_SUCCESS;
}
@@ -2966,8 +2980,6 @@ void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj)
} else {
vty_out(vty, "Number of registered addresses: %lu\n",
pim->rpf_hash->count);
- vty_out(vty, "Address Interface Nexthop\n");
- vty_out(vty, "---------------------------------------------\n");
}
if (uj) {
@@ -5355,6 +5367,7 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
json_object *json = NULL;
json_object *json_group = NULL;
json_object *json_row = NULL;
+ struct ttable *tt = NULL;
if (uj) {
json = json_object_new_object();
@@ -5385,10 +5398,15 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
} else {
vty_out(vty, "Group Address %pFX\n", &bsgrp->group);
vty_out(vty, "--------------------------\n");
- vty_out(vty, "%-15s %-15s %-15s %-15s\n", "Rp Address",
- "priority", "Holdtime", "Hash");
-
- vty_out(vty, "(ACTIVE)\n");
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Rp Address|priority|Holdtime|Hash");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+
+ ttable_add_row(tt, "%s|%c|%c|%c", "(ACTIVE)", ' ', ' ',
+ ' ');
}
frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
@@ -5408,11 +5426,22 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
&bsm_rp->rp_address);
} else {
- vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ ttable_add_row(
+ tt, "%pPA|%u|%u|%u",
&bsm_rp->rp_address, bsm_rp->rp_prio,
bsm_rp->rp_holdtime, bsm_rp->hash);
}
}
+ /* Dump the generated table. */
+ if (tt) {
+ char *table = NULL;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ tt = NULL;
+ }
if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !uj)
vty_out(vty, "Active List is empty.\n");
@@ -5423,10 +5452,16 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
vty_out(vty, "(PENDING)\n");
vty_out(vty, "Pending RP count :%d\n",
bsgrp->pend_rp_cnt);
- if (bsgrp->pend_rp_cnt)
- vty_out(vty, "%-15s %-15s %-15s %-15s\n",
- "Rp Address", "priority", "Holdtime",
- "Hash");
+ if (bsgrp->pend_rp_cnt) {
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt,
+ "Rp Address|priority|Holdtime|Hash");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ }
}
frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
@@ -5445,11 +5480,21 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
"%pPA",
&bsm_rp->rp_address);
} else {
- vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ ttable_add_row(
+ tt, "%pPA|%u|%u|%u",
&bsm_rp->rp_address, bsm_rp->rp_prio,
bsm_rp->rp_holdtime, bsm_rp->hash);
}
}
+ /* Dump the generated table. */
+ if (tt) {
+ char *table = NULL;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
vty_out(vty, "Partial List is empty\n");
@@ -5610,7 +5655,7 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
/* unaligned, again */
- memcpy(&rp_addr, &bsm_rpinfo->rpaddr,
+ memcpy(&rp_addr, &bsm_rpinfo->rpaddr.addr,
sizeof(rp_addr));
buf += sizeof(struct bsmmsg_rpinfo);
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index ce252366ce..3310009c02 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -1217,8 +1217,9 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, pim_sgaddr *sg,
struct prefix g;
pim_addr_to_prefix(&g, up->sg.grp);
- if (prefix_list_apply(plist, &g)
- == PREFIX_DENY) {
+ if (prefix_list_apply_ext(plist, NULL, &g,
+ true) ==
+ PREFIX_DENY) {
pim_channel_add_oif(
up->channel_oil, pim->regiface,
PIM_OIF_FLAG_PROTO_GM,
diff --git a/pimd/pim_join.c b/pimd/pim_join.c
index 8c7ae80d2b..e028b6aa77 100644
--- a/pimd/pim_join.c
+++ b/pimd/pim_join.c
@@ -72,8 +72,21 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
* If the RPT and WC are set it's a (*,G)
* and the source is the RP
*/
- if ((source_flags & PIM_RPT_BIT_MASK)
- && (source_flags & PIM_WILDCARD_BIT_MASK)) {
+ if (CHECK_FLAG(source_flags, PIM_WILDCARD_BIT_MASK)) {
+ /* As per RFC 7761 Section 4.9.1:
+ * The RPT (or Rendezvous Point Tree) bit is a 1-bit value for
+ * use with PIM Join/Prune messages (see Section 4.9.5.1). If
+ * the WC bit is 1, the RPT bit MUST be 1.
+ */
+ if (!CHECK_FLAG(source_flags, PIM_RPT_BIT_MASK)) {
+ if (PIM_DEBUG_PIM_J_P)
+ zlog_debug(
+ "Discarding (*,G)=%pSG join since WC bit is set but RPT bit is unset",
+ sg);
+
+ return;
+ }
+
struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
pim_addr rpf_addr;
@@ -127,8 +140,21 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh,
++pim_ifp->pim_ifstat_prune_recv;
- if ((source_flags & PIM_RPT_BIT_MASK)
- && (source_flags & PIM_WILDCARD_BIT_MASK)) {
+ if (CHECK_FLAG(source_flags, PIM_WILDCARD_BIT_MASK)) {
+ /* As per RFC 7761 Section 4.9.1:
+ * The RPT (or Rendezvous Point Tree) bit is a 1-bit value for
+ * use with PIM Join/Prune messages (see Section 4.9.5.1). If
+ * the WC bit is 1, the RPT bit MUST be 1.
+ */
+ if (!CHECK_FLAG(source_flags, PIM_RPT_BIT_MASK)) {
+ if (PIM_DEBUG_PIM_J_P)
+ zlog_debug(
+ "Discarding (*,G)=%pSG prune since WC bit is set but RPT bit is unset",
+ sg);
+
+ return;
+ }
+
/*
* RFC 4601 Section 4.5.2:
* Received Prune(*,G) messages are processed even if the
diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c
index 1152dd6f67..5230f6a332 100644
--- a/pimd/pim_msdp_packet.c
+++ b/pimd/pim_msdp_packet.c
@@ -83,10 +83,18 @@ static void pim_msdp_pkt_sa_dump_one(struct stream *s)
static void pim_msdp_pkt_sa_dump(struct stream *s)
{
+ const size_t header_length = PIM_MSDP_SA_X_SIZE - PIM_MSDP_HEADER_SIZE;
+ size_t payload_length;
int entry_cnt;
int i;
struct in_addr rp; /* Last RP address associated with this SA */
+ if (header_length > STREAM_READABLE(s)) {
+ zlog_err("BUG MSDP SA bad header (readable %zu expected %zu)",
+ STREAM_READABLE(s), header_length);
+ return;
+ }
+
entry_cnt = stream_getc(s);
rp.s_addr = stream_get_ipv4(s);
@@ -96,6 +104,13 @@ static void pim_msdp_pkt_sa_dump(struct stream *s)
zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
}
+ payload_length = (size_t)entry_cnt * PIM_MSDP_SA_ONE_ENTRY_SIZE;
+ if (payload_length > STREAM_READABLE(s)) {
+ zlog_err("BUG MSDP SA bad length (readable %zu expected %zu)",
+ STREAM_READABLE(s), payload_length);
+ return;
+ }
+
/* dump SAs */
for (i = 0; i < entry_cnt; ++i) {
pim_msdp_pkt_sa_dump_one(s);
@@ -116,6 +131,11 @@ static void pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len,
return;
}
+ if (len < PIM_MSDP_HEADER_SIZE) {
+ zlog_err("invalid MSDP header length");
+ return;
+ }
+
switch (type) {
case PIM_MSDP_V4_SOURCE_ACTIVE:
pim_msdp_pkt_sa_dump(s);
@@ -711,6 +731,30 @@ void pim_msdp_read(struct thread *thread)
pim_msdp_pkt_rxed_with_fatal_error(mp);
return;
}
+
+ /*
+ * Handle messages with longer than expected TLV size: resize
+ * the stream to handle reading the whole message.
+ *
+ * RFC 3618 Section 12. 'Packet Formats':
+ * > ... If an implementation receives a TLV whose length
+ * > exceeds the maximum TLV length specified below, the TLV
+ * > SHOULD be accepted. Any additional data, including possible
+ * > next TLV's in the same message, SHOULD be ignored, and the
+ * > MSDP session should not be reset. ...
+ */
+ if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
+ /* Check if the current buffer is big enough. */
+ if (mp->ibuf->size < len) {
+ if (PIM_DEBUG_MSDP_PACKETS)
+ zlog_debug(
+ "MSDP peer %s sent TLV with unexpected large length (%d bytes)",
+ mp->key_str, len);
+
+ stream_resize_inplace(&mp->ibuf, len);
+ }
+ }
+
/* read complete TLV */
mp->packet_size = len;
}
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 3bfb31e0c6..dff1b4fed4 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -166,8 +166,8 @@ struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil,
const char *name)
{
if (PIM_DEBUG_MROUTE) {
- pim_sgaddr sg = {.src = *oil_mcastgrp(c_oil),
- .grp = *oil_origin(c_oil)};
+ pim_sgaddr sg = {.src = *oil_origin(c_oil),
+ .grp = *oil_mcastgrp(c_oil)};
zlog_debug(
"%s(%s): Del oil for %pSG, Ref Count: %d (Predecrement)",
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index a37759e0d2..b62c646c3d 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -628,7 +628,8 @@ int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
pim_addr_to_prefix(&src, sg.src);
- if (prefix_list_apply(plist, &src) == PREFIX_DENY) {
+ if (prefix_list_apply_ext(plist, NULL, &src, true) ==
+ PREFIX_DENY) {
pim_register_stop_send(ifp, &sg, dest_addr,
src_addr);
if (PIM_DEBUG_PIM_PACKETS)
diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c
index 1ff60f9b64..62246cc239 100644
--- a/pimd/pim_ssm.c
+++ b/pimd/pim_ssm.c
@@ -93,7 +93,8 @@ int pim_is_grp_ssm(struct pim_instance *pim, pim_addr group_addr)
if (!plist)
return 0;
- return (prefix_list_apply(plist, &group) == PREFIX_PERMIT);
+ return (prefix_list_apply_ext(plist, NULL, &group, true) ==
+ PREFIX_PERMIT);
}
int pim_ssm_range_set(struct pim_instance *pim, vrf_id_t vrf_id,
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 6b58fbb5cf..4ef0bfaa48 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -2153,7 +2153,7 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
continue;
}
pim_addr_to_prefix(&g, up->sg.grp);
- apply_new = prefix_list_apply(np, &g);
+ apply_new = prefix_list_apply_ext(np, NULL, &g, true);
if (apply_new == PREFIX_DENY)
pim_channel_add_oif(up->channel_oil, pim->regiface,
PIM_OIF_FLAG_PROTO_GM, __func__);
diff --git a/pimd/pim_util.c b/pimd/pim_util.c
index 150e1a01ea..273c332c95 100644
--- a/pimd/pim_util.c
+++ b/pimd/pim_util.c
@@ -150,7 +150,9 @@ bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp)
pim_addr_to_prefix(&grp_pfx, *grp);
pl = prefix_list_lookup(PIM_AFI, pim_ifp->boundary_oil_plist);
- return pl ? prefix_list_apply(pl, &grp_pfx) == PREFIX_DENY : false;
+ return pl ? prefix_list_apply_ext(pl, NULL, &grp_pfx, true) ==
+ PREFIX_DENY
+ : false;
}
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index afe75e1f26..a3f5f6b0cd 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -24,7 +24,7 @@
%{!?with_pam: %global with_pam 0 }
%{!?with_pbrd: %global with_pbrd 1 }
%{!?with_pimd: %global with_pimd 1 }
-%{!?with_pim6d: %global with_pim6d 0 }
+%{!?with_pim6d: %global with_pim6d 1 }
%{!?with_vrrpd: %global with_vrrpd 1 }
%{!?with_rtadv: %global with_rtadv 1 }
%{!?with_watchfrr: %global with_watchfrr 1 }
@@ -793,9 +793,18 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
%changelog
-* Wed Jul 20 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version}
-
-* Tue Oct 04 2022 Donatas Abraitis <donatas@opensourcerouting.org> - 8.4
+* Tue Nov 01 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+
+* Tue Nov 01 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.4
+- New BGP command (neighbor PEER soo) to configure SoO to prevent routing loops and suboptimal routing on dual-homed sites.
+- Command debug bgp allow-martian replaced to bgp allow-martian-nexthop because previously we allowed using martian next-hops when debug is turned on.
+- Implement BGP Prefix Origin Validation State Extended Community rfc8097
+- Implement Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages rfc9234
+- BMP L3VPN support
+- PIMv6 support
+- MLD support
+- New command to enable using reserved IPv4 ranges as normal addresses for BGP next-hops, interface addresses, etc.
+- For a full list of bug fixes, please refer to https://frrouting.org/release/
* Wed Jul 13 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.3
- General:
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index 164a0fd218..0cedd2bafc 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -32,6 +32,7 @@
#include "linklist.h"
#include "link_state.h"
#include "cspf.h"
+#include "tc.h"
#include "sharpd/sharp_globals.h"
#include "sharpd/sharp_zebra.h"
@@ -1339,6 +1340,64 @@ DEFPY (no_sharp_interface_protodown,
return CMD_SUCCESS;
}
+DEFPY (tc_filter_rate,
+ tc_filter_rate_cmd,
+ "sharp tc dev IFNAME$ifname \
+ source <A.B.C.D/M|X:X::X:X/M>$src \
+ destination <A.B.C.D/M|X:X::X:X/M>$dst \
+ ip-protocol <tcp|udp>$ip_proto \
+ src-port (1-65535)$src_port \
+ dst-port (1-65535)$dst_port \
+ rate RATE$ratestr",
+ SHARP_STR
+ "Traffic control\n"
+ "TC interface (for qdisc, class, filter)\n"
+ "TC interface name\n"
+ "TC filter source\n"
+ "TC filter source IPv4 prefix\n"
+ "TC filter source IPv6 prefix\n"
+ "TC filter destination\n"
+ "TC filter destination IPv4 prefix\n"
+ "TC filter destination IPv6 prefix\n"
+ "TC filter IP protocol\n"
+ "TC filter IP protocol TCP\n"
+ "TC filter IP protocol UDP\n"
+ "TC filter source port\n"
+ "TC filter source port\n"
+ "TC filter destination port\n"
+ "TC filter destination port\n"
+ "TC rate\n"
+ "TC rate number (bits/s) or rate string (suffixed with Bps or bit)\n")
+{
+ struct interface *ifp;
+ struct protoent *p;
+ uint64_t rate;
+
+ ifp = if_lookup_vrf_all(ifname);
+
+ if (!ifp) {
+ vty_out(vty, "%% Can't find interface %s\n", ifname);
+ return CMD_WARNING;
+ }
+
+ p = getprotobyname(ip_proto);
+ if (!p) {
+ vty_out(vty, "Unable to convert %s to proto id\n", ip_proto);
+ return CMD_WARNING;
+ }
+
+ if (tc_getrate(ratestr, &rate) != 0) {
+ vty_out(vty, "Unable to convert %s to rate\n", ratestr);
+ return CMD_WARNING;
+ }
+
+ if (sharp_zebra_send_tc_filter_rate(ifp, src, dst, p->p_proto, src_port,
+ dst_port, rate) != 0)
+ return CMD_WARNING;
+
+ return CMD_SUCCESS;
+}
+
void sharp_vty_init(void)
{
install_element(ENABLE_NODE, &install_routes_data_dump_cmd);
@@ -1374,5 +1433,7 @@ void sharp_vty_init(void)
install_element(ENABLE_NODE, &sharp_interface_protodown_cmd);
install_element(ENABLE_NODE, &no_sharp_interface_protodown_cmd);
+ install_element(ENABLE_NODE, &tc_filter_rate_cmd);
+
return;
}
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index 9d343576d6..bf5b98544e 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -31,6 +31,7 @@
#include "nexthop.h"
#include "nexthop_group.h"
#include "link_state.h"
+#include "tc.h"
#include "sharp_globals.h"
#include "sharp_nht.h"
@@ -302,8 +303,8 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance,
memcpy(api.opaque.data, opaque, api.opaque.length);
}
- if (zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api)
- == ZCLIENT_SEND_BUFFERED)
+ if (zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api) ==
+ ZCLIENT_SEND_BUFFERED)
return true;
else
return false;
@@ -326,8 +327,8 @@ static bool route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance)
api.instance = instance;
memcpy(&api.prefix, p, sizeof(*p));
- if (zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api)
- == ZCLIENT_SEND_BUFFERED)
+ if (zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api) ==
+ ZCLIENT_SEND_BUFFERED)
return true;
else
return false;
@@ -360,7 +361,7 @@ static void sharp_install_routes_restart(struct prefix *p, uint32_t count,
if (buffered) {
wb.p = *p;
- wb.count = i+1;
+ wb.count = i + 1;
wb.routes = routes;
wb.vrf_id = vrf_id;
wb.instance = instance;
@@ -447,17 +448,16 @@ static void handle_repeated(bool installed)
if (installed) {
sg.r.removed_routes = 0;
- sharp_remove_routes_helper(&p, sg.r.vrf_id,
- sg.r.inst, sg.r.total_routes);
+ sharp_remove_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
+ sg.r.total_routes);
}
if (!installed) {
sg.r.installed_routes = 0;
- sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
- sg.r.nhgid, &sg.r.nhop_group,
- &sg.r.backup_nhop_group,
- sg.r.total_routes, sg.r.flags,
- sg.r.opaque);
+ sharp_install_routes_helper(
+ &p, sg.r.vrf_id, sg.r.inst, sg.r.nhgid,
+ &sg.r.nhop_group, &sg.r.backup_nhop_group,
+ sg.r.total_routes, sg.r.flags, sg.r.opaque);
}
}
@@ -467,8 +467,7 @@ static void sharp_zclient_buffer_ready(void)
case SHARP_INSTALL_ROUTES_RESTART:
sharp_install_routes_restart(
&wb.p, wb.count, wb.vrf_id, wb.instance, wb.nhgid,
- wb.nhg, wb.backup_nhg, wb.routes, wb.flags,
- wb.opaque);
+ wb.nhg, wb.backup_nhg, wb.routes, wb.flags, wb.opaque);
return;
case SHARP_DELETE_ROUTES_RESTART:
sharp_remove_routes_restart(&wb.p, wb.count, wb.vrf_id,
@@ -484,8 +483,8 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS)
enum zapi_route_notify_owner note;
uint32_t table;
- if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, &note,
- NULL, NULL))
+ if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, &note, NULL,
+ NULL))
return -1;
switch (note) {
@@ -574,8 +573,8 @@ void nhg_add(uint32_t id, const struct nexthop_group *nhg,
}
if (api_nhg.nexthop_num == 0) {
- zlog_debug("%s: nhg %u not sent: no valid nexthops",
- __func__, id);
+ zlog_debug("%s: nhg %u not sent: no valid nexthops", __func__,
+ id);
is_valid = false;
goto done;
}
@@ -635,8 +634,7 @@ void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import,
command = ZEBRA_NEXTHOP_UNREGISTER;
if (zclient_send_rnh(zclient, command, p, SAFI_UNICAST, connected,
- false, vrf_id)
- == ZCLIENT_SEND_FAILURE)
+ false, vrf_id) == ZCLIENT_SEND_FAILURE)
zlog_warn("%s: Failure to send nexthop to zebra", __func__);
}
@@ -645,8 +643,7 @@ static int sharp_debug_nexthops(struct zapi_route *api)
int i;
if (api->nexthop_num == 0) {
- zlog_debug(
- " Not installed");
+ zlog_debug(" Not installed");
return 0;
}
@@ -711,8 +708,8 @@ static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS)
zlog_warn("%s: Decode of redistribute failed: %d", __func__,
ZEBRA_REDISTRIBUTE_ROUTE_ADD);
- zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd),
- &api.prefix, zebra_route_string(api.type));
+ zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd), &api.prefix,
+ zebra_route_string(api.type));
sharp_debug_nexthops(&api);
@@ -784,9 +781,9 @@ int sharp_zclient_delete(uint32_t session_id)
return 0;
}
-static const char *const type2txt[] = { "Generic", "Vertex", "Edge", "Subnet" };
-static const char *const status2txt[] = { "Unknown", "New", "Update",
- "Delete", "Sync", "Orphan"};
+static const char *const type2txt[] = {"Generic", "Vertex", "Edge", "Subnet"};
+static const char *const status2txt[] = {"Unknown", "New", "Update",
+ "Delete", "Sync", "Orphan"};
/* Handler for opaque messages */
static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS)
{
@@ -809,8 +806,7 @@ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS)
status2txt[lse->status],
type2txt[lse->type]);
lse->status = SYNC;
- }
- else
+ } else
zlog_debug(
"%s: Error to convert Stream into Link State",
__func__);
@@ -847,12 +843,11 @@ void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance,
instance, session_id,
buf, sizeof(buf));
if (ret == ZCLIENT_SEND_FAILURE) {
- zlog_debug("%s: send_opaque() failed => %d",
- __func__, ret);
+ zlog_debug("%s: send_opaque() failed => %d", __func__,
+ ret);
break;
}
}
-
}
/*
@@ -883,7 +878,6 @@ void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance,
stream_putw_at(s, 0, stream_get_endp(s));
(void)zclient_send_message(zclient);
-
}
/* Link State registration */
@@ -985,6 +979,64 @@ int sharp_zebra_send_interface_protodown(struct interface *ifp, bool down)
return 0;
}
+int sharp_zebra_send_tc_filter_rate(struct interface *ifp,
+ const struct prefix *source,
+ const struct prefix *destination,
+ uint8_t ip_proto, uint16_t src_port,
+ uint16_t dst_port, uint64_t rate)
+{
+#define SHARPD_TC_HANDLE 0x0001
+ struct stream *s;
+
+ s = zclient->obuf;
+
+ struct tc_qdisc q = {.ifindex = ifp->ifindex, .kind = TC_QDISC_HTB};
+
+ zapi_tc_qdisc_encode(ZEBRA_TC_QDISC_INSTALL, s, &q);
+ if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE)
+ return -1;
+
+ struct tc_class c = {.ifindex = ifp->ifindex,
+ .handle = SHARPD_TC_HANDLE & 0xffff,
+ .kind = TC_QDISC_HTB,
+ .u.htb.ceil = rate,
+ .u.htb.rate = rate};
+
+ zapi_tc_class_encode(ZEBRA_TC_CLASS_ADD, s, &c);
+ if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE)
+ return -1;
+
+ struct tc_filter f = {.ifindex = ifp->ifindex,
+ .handle = SHARPD_TC_HANDLE,
+ .priority = 0x1,
+ .kind = TC_FILTER_FLOWER,
+ .u.flower.filter_bm = 0};
+
+#ifdef ETH_P_IP
+ f.protocol = ETH_P_IP;
+#else
+ f.protocol = 0x0800;
+#endif
+
+ f.u.flower.filter_bm |= TC_FLOWER_IP_PROTOCOL;
+ f.u.flower.ip_proto = ip_proto;
+ f.u.flower.filter_bm |= TC_FLOWER_SRC_IP;
+ prefix_copy(&f.u.flower.src_ip, source);
+ f.u.flower.filter_bm |= TC_FLOWER_DST_IP;
+ prefix_copy(&f.u.flower.dst_ip, destination);
+ f.u.flower.filter_bm |= TC_FLOWER_SRC_PORT;
+ f.u.flower.src_port_min = f.u.flower.src_port_max = src_port;
+ f.u.flower.filter_bm |= TC_FLOWER_DST_PORT;
+ f.u.flower.dst_port_min = f.u.flower.dst_port_max = dst_port;
+ f.u.flower.classid = SHARPD_TC_HANDLE & 0xffff;
+
+ zapi_tc_filter_encode(ZEBRA_TC_FILTER_ADD, s, &f);
+ if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE)
+ return -1;
+
+ return 0;
+}
+
static zclient_handler *const sharp_handlers[] = {
[ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,
[ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete,
@@ -1002,8 +1054,8 @@ void sharp_zebra_init(void)
{
struct zclient_options opt = {.receive_notify = true};
- if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up,
- sharp_ifp_down, sharp_ifp_destroy);
+ if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, sharp_ifp_down,
+ sharp_ifp_destroy);
zclient = zclient_new(master, &opt, sharp_handlers,
array_size(sharp_handlers));
diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h
index d8ea679797..8de14ce5af 100644
--- a/sharpd/sharp_zebra.h
+++ b/sharpd/sharp_zebra.h
@@ -75,4 +75,9 @@ extern void sharp_install_seg6local_route_helper(struct prefix *p,
extern int sharp_zebra_send_interface_protodown(struct interface *ifp,
bool down);
+extern int sharp_zebra_send_tc_filter_rate(struct interface *ifp,
+ const struct prefix *source,
+ const struct prefix *destination,
+ uint8_t ip_proto, uint16_t src_port,
+ uint16_t dst_port, uint64_t rate);
#endif
diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c
index 5a7044e9f9..4a3d9e17a4 100644
--- a/staticd/static_nb_config.c
+++ b/staticd/static_nb_config.c
@@ -370,7 +370,7 @@ static int static_nexthop_color_destroy(struct nb_cb_destroy_args *args)
struct static_nexthop *nh;
uint32_t old_color;
- nh = nb_running_unset_entry(args->dnode);
+ nh = nb_running_get_entry(args->dnode, NULL, true);
old_color = nh->color;
nh->color = 0;
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index 94a3493477..efae3c53da 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -41,15 +41,33 @@
#define STATICD_STR "Static route daemon\n"
-static int static_route_leak(struct vty *vty, const char *svrf,
- const char *nh_svrf, afi_t afi, safi_t safi,
- const char *negate, const char *dest_str,
- const char *mask_str, const char *src_str,
- const char *gate_str, const char *ifname,
- const char *flag_str, const char *tag_str,
- const char *distance_str, const char *label_str,
- const char *table_str, bool onlink,
- const char *color_str)
+/** All possible route parameters available in CLI. */
+struct static_route_args {
+ /** "no" command? */
+ bool delete;
+ /** Is VRF obtained from XPath? */
+ bool xpath_vrf;
+
+ bool onlink;
+ afi_t afi;
+ safi_t safi;
+
+ const char *vrf;
+ const char *nexthop_vrf;
+ const char *prefix;
+ const char *prefix_mask;
+ const char *source;
+ const char *gateway;
+ const char *interface_name;
+ const char *flag;
+ const char *tag;
+ const char *distance;
+ const char *label;
+ const char *table;
+ const char *color;
+};
+
+static int static_route_nb_run(struct vty *vty, struct static_route_args *args)
{
int ret;
struct prefix p, src;
@@ -62,8 +80,8 @@ static int static_route_leak(struct vty *vty, const char *svrf,
char xpath_label[XPATH_MAXLEN];
char ab_xpath[XPATH_MAXLEN];
char buf_prefix[PREFIX_STRLEN];
- char buf_src_prefix[PREFIX_STRLEN];
- char buf_nh_type[PREFIX_STRLEN];
+ char buf_src_prefix[PREFIX_STRLEN] = {};
+ char buf_nh_type[PREFIX_STRLEN] = {};
char buf_tag[PREFIX_STRLEN];
uint8_t label_stack_id = 0;
const char *buf_gate_str;
@@ -71,37 +89,46 @@ static int static_route_leak(struct vty *vty, const char *svrf,
route_tag_t tag = 0;
uint32_t table_id = 0;
const struct lyd_node *dnode;
+ const struct lyd_node *vrf_dnode;
- memset(buf_src_prefix, 0, PREFIX_STRLEN);
- memset(buf_nh_type, 0, PREFIX_STRLEN);
+ if (args->xpath_vrf) {
+ vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ VTY_CURR_XPATH);
+ if (vrf_dnode == NULL) {
+ vty_out(vty,
+ "%% Failed to get vrf dnode in candidate db\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ args->vrf = yang_dnode_get_string(vrf_dnode, "./name");
+ } else {
+ if (args->vrf == NULL)
+ args->vrf = VRF_DEFAULT_NAME;
+ }
+ if (args->nexthop_vrf == NULL)
+ args->nexthop_vrf = args->vrf;
- ret = str2prefix(dest_str, &p);
- if (ret <= 0) {
- vty_out(vty, "%% Malformed address\n");
- return CMD_WARNING_CONFIG_FAILED;
+ if (args->interface_name &&
+ !strcasecmp(args->interface_name, "Null0")) {
+ args->flag = "Null0";
+ args->interface_name = NULL;
}
- switch (afi) {
+ assert(!!str2prefix(args->prefix, &p));
+
+ switch (args->afi) {
case AFI_IP:
/* Cisco like mask notation. */
- if (mask_str) {
- ret = inet_aton(mask_str, &mask);
- if (ret == 0) {
- vty_out(vty, "%% Malformed address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (args->prefix_mask) {
+ assert(inet_pton(AF_INET, args->prefix_mask, &mask) ==
+ 1);
p.prefixlen = ip_masklen(mask);
}
break;
case AFI_IP6:
/* srcdest routing */
- if (src_str) {
- ret = str2prefix(src_str, &src);
- if (ret <= 0 || src.family != AF_INET6) {
- vty_out(vty, "%% Malformed source address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
+ if (args->source)
+ assert(!!str2prefix(args->source, &src));
break;
default:
break;
@@ -109,62 +136,64 @@ static int static_route_leak(struct vty *vty, const char *svrf,
/* Apply mask for given prefix. */
apply_mask(&p);
-
prefix2str(&p, buf_prefix, sizeof(buf_prefix));
- if (src_str)
+ if (args->source)
prefix2str(&src, buf_src_prefix, sizeof(buf_src_prefix));
- if (gate_str)
- buf_gate_str = gate_str;
+ if (args->gateway)
+ buf_gate_str = args->gateway;
else
buf_gate_str = "";
- if (gate_str == NULL && ifname == NULL)
+ if (args->gateway == NULL && args->interface_name == NULL)
type = STATIC_BLACKHOLE;
- else if (gate_str && ifname) {
- if (afi == AFI_IP)
+ else if (args->gateway && args->interface_name) {
+ if (args->afi == AFI_IP)
type = STATIC_IPV4_GATEWAY_IFNAME;
else
type = STATIC_IPV6_GATEWAY_IFNAME;
- } else if (ifname)
+ } else if (args->interface_name)
type = STATIC_IFNAME;
else {
- if (afi == AFI_IP)
+ if (args->afi == AFI_IP)
type = STATIC_IPV4_GATEWAY;
else
type = STATIC_IPV6_GATEWAY;
}
/* Administrative distance. */
- if (distance_str)
- distance = atoi(distance_str);
+ if (args->distance)
+ distance = strtol(args->distance, NULL, 10);
/* tag */
- if (tag_str)
- tag = strtoul(tag_str, NULL, 10);
+ if (args->tag)
+ tag = strtoul(args->tag, NULL, 10);
/* TableID */
- if (table_str)
- table_id = atol(table_str);
+ if (args->table)
+ table_id = strtol(args->table, NULL, 10);
- static_get_nh_type(type, buf_nh_type, PREFIX_STRLEN);
- if (!negate) {
- if (src_str)
+ static_get_nh_type(type, buf_nh_type, sizeof(buf_nh_type));
+ if (!args->delete) {
+ if (args->source)
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- buf_src_prefix, table_id, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ buf_src_prefix, table_id, buf_nh_type,
+ args->nexthop_vrf, buf_gate_str,
+ args->interface_name);
else
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- table_id, buf_nh_type, nh_svrf, buf_gate_str,
- ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ table_id, buf_nh_type, args->nexthop_vrf,
+ buf_gate_str, args->interface_name);
/*
* If there's already the same nexthop but with a different
@@ -181,19 +210,21 @@ static int static_route_leak(struct vty *vty, const char *svrf,
}
/* route + path procesing */
- if (src_str)
+ if (args->source)
snprintf(xpath_prefix, sizeof(xpath_prefix),
FRR_S_ROUTE_SRC_INFO_KEY_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
buf_src_prefix, table_id, distance);
else
snprintf(xpath_prefix, sizeof(xpath_prefix),
FRR_STATIC_ROUTE_INFO_KEY_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
table_id, distance);
nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
@@ -208,8 +239,8 @@ static int static_route_leak(struct vty *vty, const char *svrf,
/* nexthop processing */
snprintf(ab_xpath, sizeof(ab_xpath),
- FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type,
+ args->nexthop_vrf, buf_gate_str, args->interface_name);
strlcpy(xpath_nexthop, xpath_prefix, sizeof(xpath_nexthop));
strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop));
nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_CREATE, NULL);
@@ -220,8 +251,8 @@ static int static_route_leak(struct vty *vty, const char *svrf,
sizeof(ab_xpath));
/* Route flags */
- if (flag_str) {
- switch (flag_str[0]) {
+ if (args->flag) {
+ switch (args->flag[0]) {
case 'r':
bh_type = "reject";
break;
@@ -248,7 +279,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_ONLINK_XPATH,
sizeof(ab_xpath));
- if (onlink)
+ if (args->onlink)
nb_cli_enqueue_change(vty, ab_xpath,
NB_OP_MODIFY, "true");
else
@@ -262,11 +293,12 @@ static int static_route_leak(struct vty *vty, const char *svrf,
strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_COLOR_XPATH,
sizeof(ab_xpath));
- if (color_str)
+ if (args->color)
nb_cli_enqueue_change(vty, ab_xpath,
- NB_OP_MODIFY, color_str);
+ NB_OP_MODIFY,
+ args->color);
}
- if (label_str) {
+ if (args->label) {
/* copy of label string (start) */
char *ostr;
/* pointer to next segment */
@@ -279,7 +311,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
NULL);
- ostr = XSTRDUP(MTYPE_TMP, label_str);
+ ostr = XSTRDUP(MTYPE_TMP, args->label);
while ((nump = strsep(&ostr, "/")) != NULL) {
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_STATIC_ROUTE_NHLB_KEY_XPATH,
@@ -302,22 +334,25 @@ static int static_route_leak(struct vty *vty, const char *svrf,
}
ret = nb_cli_apply_changes(vty, xpath_prefix);
} else {
- if (src_str)
+ if (args->source)
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- buf_src_prefix, table_id, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ buf_src_prefix, table_id, buf_nh_type,
+ args->nexthop_vrf, buf_gate_str,
+ args->interface_name);
else
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- table_id, buf_nh_type, nh_svrf, buf_gate_str,
- ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ table_id, buf_nh_type, args->nexthop_vrf,
+ buf_gate_str, args->interface_name);
dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
if (!dnode) {
@@ -336,22 +371,6 @@ static int static_route_leak(struct vty *vty, const char *svrf,
return ret;
}
-static int static_route(struct vty *vty, afi_t afi, safi_t safi,
- const char *negate, const char *dest_str,
- const char *mask_str, const char *src_str,
- const char *gate_str, const char *ifname,
- const char *flag_str, const char *tag_str,
- const char *distance_str, const char *vrf_name,
- const char *label_str, const char *table_str)
-{
- if (!vrf_name)
- vrf_name = VRF_DEFAULT_NAME;
-
- return static_route_leak(vty, vrf_name, vrf_name, afi, safi, negate,
- dest_str, mask_str, src_str, gate_str, ifname,
- flag_str, tag_str, distance_str, label_str,
- table_str, false, NULL);
-}
/* Static unicast routes for multicast RPF lookup. */
DEFPY_YANG (ip_mroute_dist,
@@ -365,9 +384,17 @@ DEFPY_YANG (ip_mroute_dist,
"Nexthop interface name\n"
"Distance\n")
{
- return static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str,
- NULL, NULL, gate_str, ifname, NULL, NULL,
- distance_str, NULL, NULL, NULL);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_MULTICAST,
+ .prefix = prefix_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .distance = distance_str,
+ };
+
+ return static_route_nb_run(vty, &args);
}
/* Static route configuration. */
@@ -398,9 +425,21 @@ DEFPY_YANG(ip_route_blackhole,
"Table to configure\n"
"The table number to configure\n")
{
- return static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
- mask_str, NULL, NULL, NULL, flag, tag_str,
- distance_str, vrf, label, table_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .vrf = vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_blackhole_vrf,
@@ -428,26 +467,28 @@ DEFPY_YANG(ip_route_blackhole_vrf,
"Table to configure\n"
"The table number to configure\n")
{
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .xpath_vrf = true,
+ };
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
/*
* Coverity is complaining that prefix could
* be dereferenced, but we know that prefix will
* valid. Add an assert to make it happy
*/
- assert(prefix);
- return static_route_leak(vty, vrfname, vrfname, AFI_IP, SAFI_UNICAST,
- no, prefix, mask_str, NULL, NULL, NULL, flag,
- tag_str, distance_str, label, table_str,
- false, NULL);
+ assert(args.prefix);
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_address_interface,
@@ -486,25 +527,25 @@ DEFPY_YANG(ip_route_address_interface,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_address_interface_vrf,
@@ -541,32 +582,25 @@ DEFPY_YANG(ip_route_address_interface_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route,
@@ -602,26 +636,24 @@ DEFPY_YANG(ip_route,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_vrf,
@@ -655,33 +687,24 @@ DEFPY_YANG(ip_route_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_blackhole,
@@ -711,9 +734,21 @@ DEFPY_YANG(ipv6_route_blackhole,
"Table to configure\n"
"The table number to configure\n")
{
- return static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
- NULL, from_str, NULL, NULL, flag, tag_str,
- distance_str, vrf, label, table_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .vrf = vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_blackhole_vrf,
@@ -741,28 +776,28 @@ DEFPY_YANG(ipv6_route_blackhole_vrf,
"Table to configure\n"
"The table number to configure\n")
{
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .xpath_vrf = true,
+ };
/*
* Coverity is complaining that prefix could
* be dereferenced, but we know that prefix will
* valid. Add an assert to make it happy
*/
- assert(prefix);
+ assert(args.prefix);
- return static_route_leak(vty, vrfname, vrfname, AFI_IP6, SAFI_UNICAST,
- no, prefix_str, NULL, from_str, NULL, NULL,
- flag, tag_str, distance_str, label, table_str,
- false, NULL);
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_address_interface,
@@ -801,26 +836,25 @@ DEFPY_YANG(ipv6_route_address_interface,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
- prefix_str, NULL, from_str, gate_str, ifname,
- flag, tag_str, distance_str, label, table_str,
- !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_address_interface_vrf,
@@ -857,32 +891,25 @@ DEFPY_YANG(ipv6_route_address_interface_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
- no, prefix_str, NULL, from_str, gate_str,
- ifname, flag, tag_str, distance_str, label,
- table_str, !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route,
@@ -918,25 +945,24 @@ DEFPY_YANG(ipv6_route,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
- prefix_str, NULL, from_str, gate_str, ifname,
- flag, tag_str, distance_str, label, table_str,
- false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_vrf,
@@ -970,32 +996,24 @@ DEFPY_YANG(ipv6_route_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
- no, prefix_str, NULL, from_str, gate_str,
- ifname, flag, tag_str, distance_str, label,
- table_str, false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
void static_cli_show(struct vty *vty, const struct lyd_node *dnode,
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index de07ad8ef3..cb36304473 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -313,6 +313,7 @@ static bool static_zebra_nht_get_prefix(const struct static_nexthop *nh,
}
assertf(0, "BUG: someone forgot to add nexthop type %u", nh->type);
+ return false;
}
void static_zebra_nht_register(struct static_nexthop *nh, bool reg)
diff --git a/tests/lib/test_heavy_wq.c b/tests/lib/test_heavy_wq.c
index 00aa7b80dd..be47ef4bbc 100644
--- a/tests/lib/test_heavy_wq.c
+++ b/tests/lib/test_heavy_wq.c
@@ -70,11 +70,6 @@ static void heavy_wq_add(struct vty *vty, const char *str, int i)
return;
}
-static void slow_func_err(struct work_queue *wq, struct work_queue_item *item)
-{
- printf("%s: running error function\n", __func__);
-}
-
static void slow_func_del(struct work_queue *wq, void *data)
{
struct heavy_wq_node *hn = data;
@@ -143,7 +138,6 @@ static int heavy_wq_init(void)
heavy_wq = work_queue_new(master, "heavy_work_queue");
heavy_wq->spec.workfunc = &slow_func;
- heavy_wq->spec.errorfunc = &slow_func_err;
heavy_wq->spec.del_item_data = &slow_func_del;
heavy_wq->spec.max_retries = 3;
heavy_wq->spec.hold = 1000;
diff --git a/tests/topotests/bfd_topo1/test_bfd_topo1.py b/tests/topotests/bfd_topo1/test_bfd_topo1.py
index c9020f16d3..955d54f30c 100644
--- a/tests/topotests/bfd_topo1/test_bfd_topo1.py
+++ b/tests/topotests/bfd_topo1/test_bfd_topo1.py
@@ -207,7 +207,7 @@ def test_bgp_fast_reconvergence():
test_func = partial(
topotest.router_json_cmp, router, "show ip bgp json", expected
)
- _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+ _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = "{}: bgp did not converge".format(router.name)
assert res is None, assertmsg
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 ec66c8caef..7ded0ce8b4 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
@@ -76,15 +76,6 @@ from lib.topojson import build_topo_from_json, build_config_from_json
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
-
-# Reading the data from JSON File for topology creation
-jsonFile = "{}/bgp_as_allow_in.json".format(CWD)
-try:
- with open(jsonFile, "r") as topoJson:
- topo = json.load(topoJson)
-except IOError:
- assert False, "Could not read file {}".format(jsonFile)
-
# Global variables
BGP_CONVERGENCE = False
ADDR_TYPES = check_address_types()
@@ -92,13 +83,6 @@ NETWORK = {"ipv4": "2.2.2.2/32", "ipv6": "22:22::2/128"}
NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
-def build_topo(tgen):
- """Build function"""
-
- # Building topology from json file
- build_topo_from_json(tgen, topo)
-
-
def setup_module(mod):
"""
Sets up the pytest environment
@@ -118,7 +102,11 @@ def setup_module(mod):
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
- tgen = Topogen(build_topo, mod.__name__)
+ json_file = "{}/bgp_as_allow_in.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+
# ... and here it calls Mininet initialization functions.
# Starting topology, create tmp files which are loaded to routers
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 4db4e37f7f..a2904e6e1e 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
@@ -34,11 +34,13 @@ 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]
@@ -81,30 +83,34 @@ def test_bgp_maximum_prefix_invalid():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- def _bgp_converge(router):
- while True:
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")
- )
- if output["192.168.255.1"]["bgpState"] == "Established":
- if (
- output["192.168.255.1"]["addressFamilyInfo"]["ipv4Unicast"][
- "acceptedPrefixCounter"
- ]
- == 2
- ):
- return True
-
- def _bgp_comm_list_delete(router):
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json")
- )
- if "333:333" in output["paths"][0]["community"]["list"]:
- return False
- return True
-
- if _bgp_converge("r2"):
- assert _bgp_comm_list_delete("r2") == True
+ 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,
+ }
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't converge initially"
+
+ def _bgp_comm_list_delete():
+ output = json.loads(r2.vtysh_cmd("show ip bgp 172.16.255.254/32 json"))
+ expected = {"paths": [{"community": {"list": ["333:333"]}}]}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_comm_list_delete)
+ _, result = topotest.run_and_expect(test_func, not None, count=60, wait=0.5)
+ assert result is not None, "333:333 community SHOULD be stripped from r1"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_comm_list_match/__init__.py b/tests/topotests/bgp_comm_list_match/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_comm_list_match/__init__.py
diff --git a/tests/topotests/bgp_comm_list_match/r1/bgpd.conf b/tests/topotests/bgp_comm_list_match/r1/bgpd.conf
new file mode 100644
index 0000000000..89c9f7728e
--- /dev/null
+++ b/tests/topotests/bgp_comm_list_match/r1/bgpd.conf
@@ -0,0 +1,23 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.0.2 remote-as external
+ neighbor 192.168.0.2 timers 1 3
+ neighbor 192.168.0.2 timers connect 1
+ address-family ipv4
+ redistribute connected
+ neighbor 192.168.0.2 route-map r2 out
+ exit-address-family
+!
+ip prefix-list p1 seq 5 permit 172.16.255.1/32
+ip prefix-list p3 seq 5 permit 172.16.255.3/32
+!
+route-map r2 permit 10
+ match ip address prefix-list p1
+ set community 65001:1 65001:2
+route-map r2 permit 20
+ match ip address prefix-list p3
+ set community 65001:3
+route-map r2 permit 30
+exit
+!
diff --git a/tests/topotests/bgp_comm_list_match/r1/zebra.conf b/tests/topotests/bgp_comm_list_match/r1/zebra.conf
new file mode 100644
index 0000000000..17d0ecceaf
--- /dev/null
+++ b/tests/topotests/bgp_comm_list_match/r1/zebra.conf
@@ -0,0 +1,11 @@
+!
+interface lo
+ ip address 172.16.255.1/32
+ ip address 172.16.255.2/32
+ ip address 172.16.255.3/32
+!
+interface r1-eth0
+ ip address 192.168.0.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_comm_list_match/r2/bgpd.conf b/tests/topotests/bgp_comm_list_match/r2/bgpd.conf
new file mode 100644
index 0000000000..35ad2d32e6
--- /dev/null
+++ b/tests/topotests/bgp_comm_list_match/r2/bgpd.conf
@@ -0,0 +1,21 @@
+!
+debug bgp updates
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.0.1 remote-as external
+ neighbor 192.168.0.1 timers 1 3
+ neighbor 192.168.0.1 timers connect 1
+ address-family ipv4
+ neighbor 192.168.0.1 route-map r1 in
+ neighbor 192.168.0.1 soft-reconfiguration inbound
+ exit-address-family
+!
+bgp community-list 1 seq 5 permit 65001:1 65001:2
+bgp community-list 1 seq 10 permit 65001:3
+!
+route-map r1 deny 10
+ match community 1
+route-map r1 permit 20
+exit
+!
diff --git a/tests/topotests/bgp_comm_list_match/r2/zebra.conf b/tests/topotests/bgp_comm_list_match/r2/zebra.conf
new file mode 100644
index 0000000000..a69c622352
--- /dev/null
+++ b/tests/topotests/bgp_comm_list_match/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.0.2/24
+!
+ip forwarding
+!
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
new file mode 100644
index 0000000000..1b8f73d233
--- /dev/null
+++ b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Check if BGP community-list works as OR if multiple community entries specified,
+like:
+
+bgp community-list 1 seq 5 permit 65001:1 65002:2
+bgp community-list 1 seq 10 permit 65001:3
+!
+route-map test deny 10
+ match community 1
+route-map test permit 20
+
+Here, we should deny routes in/out if the path has:
+(65001:1 AND 65001:2) OR 65001:3.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 3):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_comm_list_match():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r2"]
+
+ def _bgp_converge():
+ output = json.loads(
+ router.vtysh_cmd(
+ "show bgp ipv4 unicast neighbors 192.168.0.1 filtered-routes json"
+ )
+ )
+ expected = {
+ "receivedRoutes": {
+ "172.16.255.1/32": {
+ "path": "65001",
+ },
+ "172.16.255.3/32": {
+ "path": "65001",
+ },
+ }
+ }
+ 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=60, wait=0.5)
+ assert result is None, "Failed to filter BGP UPDATES with community-list on R2"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_confed1/__init__.py b/tests/topotests/bgp_confed1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_confed1/__init__.py
diff --git a/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json
new file mode 100644
index 0000000000..d3988eb0e7
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json
@@ -0,0 +1,63 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "routerId":"203.0.113.1",
+ "defaultLocPrf":100,
+ "localAS":100,
+ "routes":{"203.0.113.0/28":[
+ {
+ "network":"203.0.113.0\/28",
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.16/28":[
+ {
+ "network":"203.0.113.16\/28",
+ "peerId":"192.0.2.2",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.32/28":[
+ {
+ "network":"203.0.113.32\/28",
+ "peerId":"192.0.2.2",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.48/28":[
+ {
+ "network":"203.0.113.48\/28",
+ "peerId":"192.0.2.2",
+ "path":"300 400",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp_confed1/r1/bgp_summary.json b/tests/topotests/bgp_confed1/r1/bgp_summary.json
new file mode 100644
index 0000000000..f999021a20
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/bgp_summary.json
@@ -0,0 +1,13 @@
+{
+ "ipv4Unicast":{
+ "routerId":"203.0.113.1",
+ "as":100,
+ "peers":{
+ "192.0.2.2":{
+ "remoteAs": 300,
+ "state": "Established",
+ "peerState":"OK"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_confed1/r1/bgpd.conf b/tests/topotests/bgp_confed1/r1/bgpd.conf
new file mode 100644
index 0000000000..8413ef7fc3
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/bgpd.conf
@@ -0,0 +1,13 @@
+debug bgp neighbor-events
+debug bgp nht
+debug bgp updates in
+debug bgp updates out
+!
+router bgp 100
+ no bgp ebgp-requires-policy
+!
+ neighbor 192.0.2.2 remote-as 300
+ address-family ipv4 unicast
+ network 203.0.113.0/28
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_confed1/r1/isisd.conf b/tests/topotests/bgp_confed1/r1/isisd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/isisd.conf
diff --git a/tests/topotests/bgp_confed1/r1/zebra.conf b/tests/topotests/bgp_confed1/r1/zebra.conf
new file mode 100644
index 0000000000..5f76e74493
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r1/zebra.conf
@@ -0,0 +1,6 @@
+interface r1-eth0
+ ip address 192.0.2.1/28
+!
+interface lo
+ ip address 203.0.113.1/28
+!
diff --git a/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json
new file mode 100644
index 0000000000..b4a0946072
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json
@@ -0,0 +1,63 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "routerId":"203.0.113.17",
+ "defaultLocPrf":100,
+ "localAS":200,
+ "routes":{"203.0.113.0/28": [
+ {
+ "network":"203.0.113.0\/28",
+ "peerId":"192.0.2.1",
+ "path":"100",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.16/28":[
+ {
+ "network":"203.0.113.16\/28",
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.32/28":[
+ {
+ "network":"203.0.113.32\/28",
+ "peerId":"192.0.2.18",
+ "path":"(300)",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.18",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.48/28":[
+ {
+ "network":"203.0.113.48\/28",
+ "peerId":"192.0.2.18",
+ "path":"(300) 400",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.50",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp_confed1/r2/bgp_summary.json b/tests/topotests/bgp_confed1/r2/bgp_summary.json
new file mode 100644
index 0000000000..c2690a145a
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/bgp_summary.json
@@ -0,0 +1,18 @@
+{
+ "ipv4Unicast":{
+ "routerId":"203.0.113.17",
+ "as":200,
+ "peers":{
+ "192.0.2.1":{
+ "remoteAs":100,
+ "state":"Established",
+ "peerState":"OK"
+ },
+ "192.0.2.18":{
+ "remoteAs":300,
+ "state":"Established",
+ "peerState":"OK"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_confed1/r2/bgpd.conf b/tests/topotests/bgp_confed1/r2/bgpd.conf
new file mode 100644
index 0000000000..9f6a9852de
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/bgpd.conf
@@ -0,0 +1,18 @@
+debug bgp neighbor-events
+debug bgp nht
+debug bgp updates in
+debug bgp updates out
+!
+router bgp 200
+ no bgp ebgp-requires-policy
+ bgp confederation identifier 300
+ bgp confederation peers 300
+ neighbor 192.0.2.1 remote-as 100
+ neighbor 192.0.2.18 remote-as 300
+ !
+ address-family ipv4 unicast
+ network 203.0.113.16/28
+ neighbor 192.0.2.18 default-originate
+ exit-address-family
+!
+
diff --git a/tests/topotests/bgp_confed1/r2/isisd.conf b/tests/topotests/bgp_confed1/r2/isisd.conf
new file mode 100644
index 0000000000..135bb00a83
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/isisd.conf
@@ -0,0 +1,8 @@
+interface r2-eth1
+ ip router isis 1
+ isis circuit-type level-2-only
+
+router isis 1
+ is-type level-2-only
+ net 49.0001.0002.0002.0002.00
+ redistribute ipv4 connected level-2
diff --git a/tests/topotests/bgp_confed1/r2/zebra.conf b/tests/topotests/bgp_confed1/r2/zebra.conf
new file mode 100644
index 0000000000..85ebe9ee02
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r2/zebra.conf
@@ -0,0 +1,9 @@
+interface r2-eth0
+ ip address 192.0.2.2/28
+!
+interface r2-eth1
+ ip address 192.0.2.17/28
+!
+interface lo
+ ip address 203.0.113.17/28
+!
diff --git a/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json
new file mode 100644
index 0000000000..a263a9f4a7
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json
@@ -0,0 +1,77 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "routerId":"203.0.113.33",
+ "defaultLocPrf":100,
+ "localAS":300,
+ "routes":{"0.0.0.0/0":[
+ {
+ "network":"0.0.0.0\/0",
+ "peerId":"192.0.2.17",
+ "path":"(200)",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.17",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.0/28":[
+ {
+ "network":"203.0.113.0\/28",
+ "peerId":"192.0.2.17",
+ "path":"(200) 100",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.16/28":[
+ {
+ "network":"203.0.113.16\/28",
+ "peerId":"192.0.2.17",
+ "path":"(200)",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.17",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.32/28":[
+ {
+ "network":"203.0.113.32\/28",
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.48/28":[
+ {
+ "network":"203.0.113.48\/28",
+ "peerId":"192.0.2.50",
+ "path":"400",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.50",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp_confed1/r3/bgp_summary.json b/tests/topotests/bgp_confed1/r3/bgp_summary.json
new file mode 100644
index 0000000000..0cc0d53895
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/bgp_summary.json
@@ -0,0 +1,18 @@
+{
+ "ipv4Unicast":{
+ "routerId":"203.0.113.33",
+ "as":300,
+ "peers":{
+ "192.0.2.17":{
+ "remoteAs":200,
+ "state":"Established",
+ "peerState":"OK"
+ },
+ "192.0.2.50":{
+ "remoteAs":400,
+ "state":"Established",
+ "peerState":"OK"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_confed1/r3/bgpd.conf b/tests/topotests/bgp_confed1/r3/bgpd.conf
new file mode 100644
index 0000000000..3a018a42b3
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/bgpd.conf
@@ -0,0 +1,17 @@
+debug bgp neighbor-events
+debug bgp nht
+debug bgp updates in
+debug bgp updates out
+!
+router bgp 300
+ no bgp ebgp-requires-policy
+ bgp confederation identifier 300
+ bgp confederation peers 200
+ neighbor 192.0.2.17 remote-as 200
+ neighbor 192.0.2.50 remote-as 400
+!
+ address-family ipv4 unicast
+ network 203.0.113.32/28
+ exit-address-family
+!
+
diff --git a/tests/topotests/bgp_confed1/r3/isisd.conf b/tests/topotests/bgp_confed1/r3/isisd.conf
new file mode 100644
index 0000000000..a0b120019b
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/isisd.conf
@@ -0,0 +1,8 @@
+interface r3-eth1
+ ip router isis 1
+ isis circuit-type level-2-only
+
+router isis 1
+ is-type level-2-only
+ net 49.0001.0003.0003.0003.00
+ redistribute ipv4 connected level-2
diff --git a/tests/topotests/bgp_confed1/r3/zebra.conf b/tests/topotests/bgp_confed1/r3/zebra.conf
new file mode 100644
index 0000000000..555c8ed3cf
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r3/zebra.conf
@@ -0,0 +1,10 @@
+!
+interface r3-eth0
+ ip address 192.0.2.49/28
+!
+interface r3-eth1
+ ip address 192.0.2.18/28
+!
+interface lo
+ ip address 203.0.113.33/28
+!
diff --git a/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json
new file mode 100644
index 0000000000..8a1f0b6762
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json
@@ -0,0 +1,77 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "routerId":"203.0.113.49",
+ "defaultLocPrf":100,
+ "localAS":400,
+ "routes":{"0.0.0.0/0":[
+ {
+ "network":"0.0.0.0\/0",
+ "peerId":"192.0.2.49",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.49",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.0/28":[
+ {
+ "network":"203.0.113.0\/28",
+ "peerId":"192.0.2.49",
+ "path":"300 100",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.49",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.16/28":[
+ {
+ "network":"203.0.113.16\/28",
+ "peerId":"192.0.2.49",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.49",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.32/28":[
+ {
+ "network":"203.0.113.32\/28",
+ "peerId":"192.0.2.49",
+ "path":"300",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.0.2.49",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+],"203.0.113.48/28":[
+ {
+ "network":"203.0.113.48\/28",
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+] } }
diff --git a/tests/topotests/bgp_confed1/r4/bgp_summary.json b/tests/topotests/bgp_confed1/r4/bgp_summary.json
new file mode 100644
index 0000000000..11a0c45cc7
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/bgp_summary.json
@@ -0,0 +1,13 @@
+{
+ "ipv4Unicast":{
+ "routerId":"203.0.113.49",
+ "as":400,
+ "peers":{
+ "192.0.2.49":{
+ "remoteAs":300,
+ "state":"Established",
+ "peerState":"OK"
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_confed1/r4/bgpd.conf b/tests/topotests/bgp_confed1/r4/bgpd.conf
new file mode 100644
index 0000000000..134f221543
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/bgpd.conf
@@ -0,0 +1,14 @@
+debug bgp neighbor-events
+debug bgp nht
+debug bgp updates in
+debug bgp updates out
+!
+router bgp 400
+ no bgp ebgp-requires-policy
+ bgp disable-ebgp-connected-route-check
+!
+ neighbor 192.0.2.49 remote-as 300
+ address-family ipv4 unicast
+ network 203.0.113.48/28
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_confed1/r4/isisd.conf b/tests/topotests/bgp_confed1/r4/isisd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/isisd.conf
diff --git a/tests/topotests/bgp_confed1/r4/zebra.conf b/tests/topotests/bgp_confed1/r4/zebra.conf
new file mode 100644
index 0000000000..28c448eef8
--- /dev/null
+++ b/tests/topotests/bgp_confed1/r4/zebra.conf
@@ -0,0 +1,6 @@
+interface r4-eth0
+ ip address 192.0.2.50/28
+!
+interface lo
+ ip address 203.0.113.49/28
+!
diff --git a/tests/topotests/bgp_confed1/test_bgp_confed1.py b/tests/topotests/bgp_confed1/test_bgp_confed1.py
new file mode 100644
index 0000000000..7a35a10852
--- /dev/null
+++ b/tests/topotests/bgp_confed1/test_bgp_confed1.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_confed1.py
+#
+# 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 6WIND DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 6WIND BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_confed1.py: Test the FRR BGP confederations with AS member
+same as confederation Id, verify BGP prefixes and path distribution
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+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("s3")
+ 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"])
+
+def setup_module(mod):
+
+ 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))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_convergence():
+ "Assert that BGP is converging."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for bgp peers to go up")
+
+ for router in tgen.routers().values():
+ ref_file = "{}/{}/bgp_summary.json".format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip bgp summary json", expected
+ )
+ _, res = topotest.run_and_expect(test_func, None, count=125, wait=2.0)
+ assertmsg = "{}: bgp did not converge".format(router.name)
+ assert res is None, assertmsg
+
+
+def test_bgp_confed_ipv4_unicast():
+ "Assert that BGP is exchanging BGP route."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for bgp peers exchanging UPDATES")
+
+ for router in tgen.routers().values():
+ ref_file = "{}/{}/bgp_ipv4_unicast.json".format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show bgp ipv4 unicast json", expected
+ )
+ _, res = topotest.run_and_expect(test_func, None, count=40, wait=2.5)
+ assertmsg = "{}: BGP UPDATE exchange 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_ecmp_topo3/test_ibgp_ecmp_topo3.py b/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
index 9b6480c0d3..b7f6b7aca7 100644
--- a/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
+++ b/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
@@ -39,8 +39,7 @@ sys.path.append(os.path.join(CWD, "../../"))
# pylint: disable=C0413
# Import topogen and topotest helpers
-from lib.topogen import get_topogen
-from lib import topojson
+from lib.topogen import Topogen, get_topogen
from lib.common_config import (
write_test_header,
@@ -51,11 +50,12 @@ from lib.common_config import (
reset_config_on_routers,
shutdown_bringup_interface,
apply_raw_config,
+ start_topology,
)
from lib.topolog import logger
+from lib.topojson import build_config_from_json
from lib.bgp import create_router_bgp, verify_bgp_convergence
-
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
@@ -78,9 +78,19 @@ def setup_module(mod):
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
- tgen = topojson.setup_module_from_json(mod.__file__)
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/ibgp_ecmp_topo3.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
topo = tgen.json_topo
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py
index ab44ba3c83..0f501f7089 100644
--- a/tests/topotests/bgp_features/test_bgp_features.py
+++ b/tests/topotests/bgp_features/test_bgp_features.py
@@ -785,7 +785,7 @@ def test_bgp_delayopen_without():
test_func = functools.partial(
topotest.router_json_cmp, router, "show ip bgp summary json", expected
)
- _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+ _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = "BGP session on r{} did not shut down peer".format(router_num)
assert res is None, assertmsg
@@ -862,7 +862,7 @@ def test_bgp_delayopen_singular():
test_func = functools.partial(
topotest.router_json_cmp, router, "show ip bgp summary json", expected
)
- _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+ _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = "BGP session on r{} did not shut down peer".format(router_num)
assert res is None, assertmsg
@@ -880,7 +880,7 @@ def test_bgp_delayopen_singular():
test_func = functools.partial(
topotest.router_json_cmp, router, "show bgp neighbors json", expected
)
- _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+ _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = "BGP session on r1 failed to set DelayOpenTime for r4"
assert res is None, assertmsg
@@ -974,7 +974,7 @@ def test_bgp_delayopen_dual():
test_func = functools.partial(
topotest.router_json_cmp, router, "show ip bgp summary json", expected
)
- _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+ _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = "BGP session on r{} did not shut down peer".format(router_num)
assert res is None, assertmsg
@@ -1003,7 +1003,7 @@ def test_bgp_delayopen_dual():
test_func = functools.partial(
topotest.router_json_cmp, router, "show bgp neighbors json", expected
)
- _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+ _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = "BGP session on r{} failed to set DelayOpenTime".format(router_num)
assert res is None, assertmsg
@@ -1032,7 +1032,7 @@ def test_bgp_delayopen_dual():
test_func = functools.partial(
topotest.router_json_cmp, router, "show ip bgp summary json", expected
)
- _, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
+ _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = "BGP session on r{} did not enter Connect state with peer".format(
router_num
)
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf
index 46831bb711..375bbea9ff 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf
@@ -4,6 +4,8 @@ hostname ce1
!
interface lo
ip address 99.0.0.1/32
+ ip address 5.1.0.1/24
+ ip address 6.0.2.1/24
!
interface ce1-eth0
description to r1
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf
index fb4d8cc9c4..90dd3c55b4 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf
@@ -4,6 +4,8 @@ hostname ce2
!
interface lo
ip address 99.0.0.2/32
+ ip address 5.1.0.1/24
+ ip address 6.0.2.1/24
!
interface ce2-eth0
description to r3
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf
index e316de5690..cf7396eb12 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf
@@ -19,6 +19,7 @@ router bgp 5227
network 5.1.3.0/24 route-map rm-nh
network 6.0.1.0/24 route-map rm-nh
network 6.0.2.0/24 route-map rm-nh-same
+ network 6.0.3.0/24 route-map rm-nh-same
neighbor 192.168.1.1 activate
exit-address-family
!
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf
index 77a1163a4b..df6ac47b08 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf
@@ -4,6 +4,7 @@ hostname ce3
!
interface lo
ip address 99.0.0.3/32
+ ip address 6.0.3.1/24
!
interface ce3-eth0
description to r4
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf
index 60d9e93108..9a6ca08a0b 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf
@@ -19,6 +19,7 @@ router bgp 5228 vrf ce4-cust2
network 5.4.3.0/24 route-map rm-nh
network 6.0.1.0/24 route-map rm-nh
network 6.0.2.0/24 route-map rm-nh-same
+ network 6.0.3.0/24 route-map rm-nh-same
neighbor 192.168.2.1 activate
exit-address-family
!
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf
index e55c9e779a..0e3a736292 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf
@@ -4,6 +4,7 @@ hostname ce4
!
interface ce4-cust2
ip address 99.0.0.4/32
+ ip address 6.0.3.1/24
!
interface ce4-eth0
description to r4
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
index 5161d8471f..b2bf5f5f63 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
@@ -175,6 +175,20 @@ def ltemplatePreRouterStartHook():
"setup {0} vrf {0}-cust1, {0}-eth4. enabled mpls input.".format(rtr)
)
# configure cust2 VRFs & MPLS
+ rtrs = ["r1"]
+ cmds = [
+ "ip link add {0}-cust3 type vrf table 20",
+ "ip link set dev {0}-cust3 up",
+ "ip link add {0}-cust4 type vrf table 30",
+ "ip link set dev {0}-cust4 up",
+ "ip link add {0}-cust5 type vrf table 40",
+ "ip link set dev {0}-cust5 up",
+ ]
+ for rtr in rtrs:
+ for cmd in cmds:
+ cc.doCmd(tgen, rtr, cmd.format(rtr))
+ logger.info("setup {0} vrf {0}-cust3 and{0}-cust4.".format(rtr))
+ # configure cust2 VRFs & MPLS
rtrs = ["r4"]
cmds = [
"ip link add {0}-cust2 type vrf table 20",
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf
index 8d42cfc0d8..24e9f95372 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf
@@ -11,6 +11,7 @@ log file bgpd.log debugging
#debug bgp vpn leak-from-vrf
#debug bgp vpn label
#debug bgp updates out
+#debug bgp nht
router bgp 5226
bgp router-id 1.1.1.1
@@ -39,6 +40,11 @@ router bgp 5227 vrf r1-cust1
neighbor 192.168.1.2 timers 3 10
address-family ipv4 unicast
+ network 10.2.3.4/32
+ network 192.0.0.0/24
+
+ redistribute connected
+
neighbor 192.168.1.2 activate
neighbor 192.168.1.2 next-hop-self
@@ -51,5 +57,47 @@ router bgp 5227 vrf r1-cust1
exit-address-family
+router bgp 5228 vrf r1-cust3
+ bgp router-id 192.168.1.1
+
+ address-family ipv4 unicast
+ rd vpn export 10:13
+ rt vpn import 52:100
+
+ import vpn
+ export vpn
+ exit-address-family
+
+
+router bgp 5227 vrf r1-cust4
+ no bgp network import-check
+
+ bgp router-id 192.168.1.1
+
+ address-family ipv4 unicast
+ network 28.0.0.0/24
+
+ rd vpn export 10:14
+ rt vpn export 52:100
+
+ import vpn
+ export vpn
+ exit-address-family
+
+
+router bgp 5227 vrf r1-cust5
+ bgp router-id 192.168.1.1
+
+ address-family ipv4 unicast
+ redistribute connected
+
+ label vpn export 105
+ rd vpn export 10:15
+ rt vpn both 52:100
+
+ import vpn
+ export vpn
+ exit-address-family
+
!
end
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/staticd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/staticd.conf
new file mode 100644
index 0000000000..59430fdf99
--- /dev/null
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/staticd.conf
@@ -0,0 +1,6 @@
+hostname r1
+log file staticd.log
+!
+vrf r1-cust1
+ ip route 192.0.0.0/24 192.168.1.2
+exit-vrf
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf
index 221bc7a839..e81bc6b2ab 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf
@@ -4,6 +4,9 @@ hostname r1
password zebra
#debug zebra packet
+#debug zebra rib detailed
+#debug zebra dplane detailed
+#debug zebra nexthop detail
interface lo
ip address 1.1.1.1/32
@@ -18,6 +21,14 @@ interface r1-eth4
ip address 192.168.1.1/24
no link-detect
+interface r1-cust1
+ ip address 10.4.5.6/24
+ no link-detect
+
+interface r1-cust5
+ ip address 29.0.0.1/32
+ no link-detect
+
ip forwarding
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py
index 91a7adf997..89369241a8 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py
@@ -81,3 +81,24 @@ if ret != False and found != None:
"wait",
"CE3->CE4 (loopback) ping",
)
+ luCommand(
+ "r1",
+ "ip vrf exec r1-cust1 ping 6.0.3.1 -I 10.4.5.6 -c 1",
+ " 0. packet loss",
+ "wait",
+ "R1(r1-cust1)->CE3/4 (loopback) ping",
+ )
+ luCommand(
+ "r1",
+ "ip vrf exec r1-cust1 ping 6.0.3.1 -I 10.4.5.6 -c 1",
+ " 0. packet loss",
+ "pass",
+ "R1(r1-cust1)->CE3/4 (loopback) ping",
+ )
+ luCommand(
+ "r1",
+ "ip vrf exec r1-cust5 ping 6.0.3.1 -I 29.0.0.1 -c 1",
+ " 0. packet loss",
+ "pass",
+ "R1(r1-cust5)->CE3/4 ( (loopback) ping",
+ )
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
index 75158b127e..e9647898ab 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
@@ -72,3 +72,53 @@ luCommand(
"wait",
"CE4->PE4 ping",
)
+ret = luCommand(
+ "r1",
+ "ip vrf exec r1-cust5 ping 29.0.0.1 -I 29.0.0.1 -c 1",
+ " 0. packet loss",
+ "pass",
+ "Ping its own IP. Check https://bugzilla.kernel.org/show_bug.cgi?id=203483 if it fails",
+)
+luCommand(
+ "r1",
+ "ip vrf exec r1-cust5 ping 192.168.1.1 -I 29.0.0.1 -c 1",
+ " 0. packet loss",
+ "pass",
+ "R1(r1-cust5)->R1(r1-cust1 - r1-eth4) ping",
+)
+luCommand(
+ "r1",
+ "ip vrf exec r1-cust5 ping 192.168.1.2 -I 29.0.0.1 -c 1",
+ " 0. packet loss",
+ "wait",
+ "R1(r1-cust5)->CE1 ping",
+)
+luCommand(
+ "r1",
+ "ip vrf exec r1-cust5 ping 192.168.1.2 -I 29.0.0.1 -c 1",
+ " 0. packet loss",
+ "pass",
+ "R1(r1-cust5)->CE1 ping",
+)
+luCommand(
+ "r1",
+ "ip vrf exec r1-cust5 ping 99.0.0.1 -I 29.0.0.1 -c 1",
+ " 0. packet loss",
+ "pass",
+ "R1(r1-cust5)->CE1 (loopback) ping",
+)
+luCommand(
+ "r1",
+ "ip vrf exec r1-cust5 ping 5.1.0.1 -I 29.0.0.1 -c 1",
+ " 0. packet loss",
+ "wait",
+ "R1(r1-cust5)->CE1 (loopback) ping",
+ time=30,
+)
+luCommand(
+ "r1",
+ "ip vrf exec r1-cust5 ping 5.1.0.1 -I 29.0.0.1 -c 1",
+ " 0. packet loss",
+ "pass",
+ "R1(r1-cust5)->CE1 (loopback) ping",
+)
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
index 550ff93ea3..3242e3bd3a 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
@@ -54,15 +54,44 @@ bgpribRequireUnicastRoutes("ce4", "ipv4", "ce4-cust2", "Cust 4 routes in ce1", w
#
# r1 vtysh -c "show bgp vrf r1-cust1 ipv4"
#
-want_r1_cust1_routes = [
+want_r1_cust1_3_5_routes = [
{"p": "5.1.0.0/24", "n": "99.0.0.1"},
{"p": "5.1.1.0/24", "n": "99.0.0.1"},
{"p": "6.0.1.0/24", "n": "99.0.0.1"},
{"p": "6.0.2.0/24", "n": "99.0.0.1"},
+ {"p": "10.2.3.4/32", "n": "0.0.0.0", "bp": False},
+ {"p": "10.4.5.0/24", "n": "0.0.0.0", "bp": True},
+ {"p": "28.0.0.0/24", "n": "0.0.0.0", "bp": True},
+ {"p": "29.0.0.1/32", "n": "0.0.0.0", "bp": True},
{"p": "99.0.0.1/32", "n": "192.168.1.2"},
+ {"p": "192.0.0.0/24", "n": "0.0.0.0", "bp": True},
+ {"p": "192.168.1.0/24", "n": "0.0.0.0", "bp": True},
]
bgpribRequireUnicastRoutes(
- "r1", "ipv4", "r1-cust1", "Customer 1 routes in r1 vrf", want_r1_cust1_routes
+ "r1", "ipv4", "r1-cust1", "Customer 1 routes in r1 vrf", want_r1_cust1_3_5_routes
+)
+bgpribRequireUnicastRoutes(
+ "r1", "ipv4", "r1-cust3", "Customer 3 routes in r1 vrf", want_r1_cust1_3_5_routes
+)
+bgpribRequireUnicastRoutes(
+ "r1", "ipv4", "r1-cust5", "Customer 5 routes in r1 vrf", want_r1_cust1_3_5_routes
+)
+
+want_r1_cust4_routes = [
+ {"p": "5.1.0.0/24", "n": "99.0.0.1", "exist": False},
+ {"p": "5.1.1.0/24", "n": "99.0.0.1", "exist": False},
+ {"p": "6.0.1.0/24", "n": "99.0.0.1", "exist": False},
+ {"p": "6.0.2.0/24", "n": "99.0.0.1", "exist": False},
+ {"p": "10.2.3.4/32", "n": "0.0.0.0", "exist": False},
+ {"p": "10.4.5.0/24", "n": "0.0.0.0", "exist": False},
+ {"p": "28.0.0.0/24", "n": "0.0.0.0", "bp": True},
+ {"p": "29.0.0.1/32", "n": "0.0.0.0", "exist": False},
+ {"p": "99.0.0.1/32", "n": "192.168.1.2", "exist": False},
+ {"p": "192.0.0.0/24", "n": "0.0.0.0", "exist": False},
+ {"p": "192.168.1.0/24", "n": "0.0.0.0", "exist": False},
+]
+bgpribRequireUnicastRoutes(
+ "r1", "ipv4", "r1-cust4", "Customer 4 routes in r1 vrf", want_r1_cust4_routes
)
want_r3_cust1_routes = [
@@ -70,10 +99,20 @@ want_r3_cust1_routes = [
{"p": "5.1.1.0/24", "n": "99.0.0.2"},
{"p": "6.0.1.0/24", "n": "99.0.0.2"},
{"p": "6.0.2.0/24", "n": "99.0.0.2"},
+ {"p": "10.2.3.4/32", "n": "0.0.0.0", "exist": False},
+ {"p": "28.0.0.0/24", "n": "1.1.1.1", "bp": True},
+ {"p": "29.0.0.1/32", "n": "1.1.1.1", "bp": True},
{"p": "99.0.0.2/32", "n": "192.168.1.2"},
+ {"p": "192.0.0.0/24", "n": "1.1.1.1", "bp": True},
+ {"p": "192.168.1.0/24", "n": "1.1.1.1", "bp": True},
]
bgpribRequireUnicastRoutes(
- "r3", "ipv4", "r3-cust1", "Customer 1 routes in r3 vrf", want_r3_cust1_routes
+ "r3",
+ "ipv4",
+ "r3-cust1",
+ "Customer 1 routes in r3 vrf",
+ want_r3_cust1_routes,
+ retry=30,
)
want_r4_cust1_routes = [
@@ -81,10 +120,20 @@ want_r4_cust1_routes = [
{"p": "5.1.3.0/24", "n": "99.0.0.3"},
{"p": "6.0.1.0/24", "n": "99.0.0.3"},
{"p": "6.0.2.0/24", "n": "99.0.0.3"},
+ {"p": "10.2.3.4/32", "n": "0.0.0.0", "exist": False},
+ {"p": "28.0.0.0/24", "n": "1.1.1.1", "bp": True},
+ {"p": "29.0.0.1/32", "n": "1.1.1.1", "bp": True},
{"p": "99.0.0.3/32", "n": "192.168.1.2"},
+ {"p": "192.0.0.0/24", "n": "1.1.1.1", "bp": True},
+ {"p": "192.168.1.0/24", "n": "1.1.1.1", "bp": True},
]
bgpribRequireUnicastRoutes(
- "r4", "ipv4", "r4-cust1", "Customer 1 routes in r4 vrf", want_r4_cust1_routes
+ "r4",
+ "ipv4",
+ "r4-cust1",
+ "Customer 1 routes in r4 vrf",
+ want_r4_cust1_routes,
+ retry=30,
)
want_r4_cust2_routes = [
@@ -92,10 +141,20 @@ want_r4_cust2_routes = [
{"p": "5.4.3.0/24", "n": "99.0.0.4"},
{"p": "6.0.1.0/24", "n": "99.0.0.4"},
{"p": "6.0.2.0/24", "n": "99.0.0.4"},
+ {"p": "10.2.3.4/32", "n": "0.0.0.0", "exist": False},
+ {"p": "28.0.0.0/24", "n": "1.1.1.1", "bp": True},
+ {"p": "29.0.0.1/32", "n": "1.1.1.1", "bp": True},
{"p": "99.0.0.4/32", "n": "192.168.2.2"},
+ {"p": "192.0.0.0/24", "n": "1.1.1.1", "bp": True},
+ {"p": "192.168.1.0/24", "n": "1.1.1.1", "bp": True},
]
bgpribRequireUnicastRoutes(
- "r4", "ipv4", "r4-cust2", "Customer 2 routes in r4 vrf", want_r4_cust2_routes
+ "r4",
+ "ipv4",
+ "r4-cust2",
+ "Customer 2 routes in r4 vrf",
+ want_r4_cust2_routes,
+ retry=30,
)
########################################################################
@@ -339,7 +398,7 @@ luCommand(
luCommand(
"r1",
'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 6.0.1.0/24"',
- "3 available, best",
+ "4 available, best",
"wait",
"Ensure 6.0.1.0 shows up on r1",
10,
@@ -347,7 +406,7 @@ luCommand(
luCommand(
"r1",
'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 6.0.2.0/24"',
- "3 available, best",
+ "4 available, best",
"wait",
"Ensure 6.0.2.0 shows up on r1",
10,
@@ -396,9 +455,9 @@ want_r1_remote_cust1_routes = [
{"p": "6.0.1.0/24", "n": "3.3.3.3", "bp": False},
{"p": "6.0.1.0/24", "n": "4.4.4.4", "bp": False},
{"p": "6.0.1.0/24", "n": "99.0.0.1", "bp": True},
- {"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": True},
+ {"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": False},
{"p": "6.0.2.0/24", "n": "4.4.4.4", "bp": False},
- {"p": "6.0.2.0/24", "n": "99.0.0.1", "bp": False},
+ {"p": "6.0.2.0/24", "n": "99.0.0.1", "bp": True},
{"p": "99.0.0.1/32", "n": "192.168.1.2", "bp": True},
{"p": "99.0.0.2/32", "n": "3.3.3.3"},
{"p": "99.0.0.3/32", "n": "4.4.4.4"},
@@ -473,7 +532,7 @@ luCommand(
luCommand(
"r3",
'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 6.0.1.0/24"',
- "3 available, best",
+ "4 available, best",
"wait",
"Ensure 6.0.1.0 shows up on r3",
10,
@@ -481,7 +540,7 @@ luCommand(
luCommand(
"r3",
'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 6.0.2.0/24"',
- "3 available, best",
+ "4 available, best",
"wait",
"Ensure 6.0.2.0 shows up on r3",
10,
@@ -522,9 +581,9 @@ want_r3_remote_cust1_routes = [
{"p": "6.0.1.0/24", "n": "1.1.1.1", "bp": True},
{"p": "6.0.1.0/24", "n": "4.4.4.4", "bp": False},
{"p": "6.0.1.0/24", "n": "99.0.0.2", "bp": False},
- {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": True},
+ {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": False},
{"p": "6.0.2.0/24", "n": "4.4.4.4", "bp": False},
- {"p": "6.0.2.0/24", "n": "99.0.0.2", "bp": False},
+ {"p": "6.0.2.0/24", "n": "99.0.0.2", "bp": True},
{"p": "99.0.0.1/32", "n": "1.1.1.1", "bp": True},
{"p": "99.0.0.3/32", "n": "4.4.4.4", "bp": True},
{"p": "99.0.0.4/32", "n": "4.4.4.4", "bp": True},
@@ -611,9 +670,9 @@ want_r4_remote_cust1_routes = [
{"p": "6.0.1.0/24", "n": "3.3.3.3", "bp": False},
{"p": "6.0.1.0/24", "n": "99.0.0.3", "bp": False},
{"p": "6.0.1.0/24", "n": "99.0.0.4", "bp": False},
- {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": True},
+ {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": False},
{"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": False},
- {"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": False},
+ {"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": True},
{"p": "6.0.2.0/24", "n": "99.0.0.4", "bp": False},
{"p": "99.0.0.1/32", "n": "1.1.1.1", "bp": True},
{"p": "99.0.0.2/32", "n": "3.3.3.3", "bp": True},
@@ -638,9 +697,9 @@ want_r4_remote_cust2_routes = [
{"p": "6.0.1.0/24", "n": "3.3.3.3", "bp": False},
{"p": "6.0.1.0/24", "n": "99.0.0.3", "bp": False},
{"p": "6.0.1.0/24", "n": "99.0.0.4", "bp": False},
- {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": True},
+ {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": False},
{"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": False},
- {"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": False},
+ {"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": True},
{"p": "6.0.2.0/24", "n": "99.0.0.4", "bp": False},
{"p": "99.0.0.1/32", "n": "1.1.1.1", "bp": True},
{"p": "99.0.0.2/32", "n": "3.3.3.3", "bp": True},
@@ -667,7 +726,7 @@ bgpribRequireUnicastRoutes(
luCommand(
"ce1",
'vtysh -c "show bgp ipv4 uni"',
- "12 routes and 12",
+ "18 routes and 19",
"wait",
"Local and remote routes",
10,
@@ -689,7 +748,7 @@ bgpribRequireUnicastRoutes(
luCommand(
"ce2",
'vtysh -c "show bgp ipv4 uni"',
- "12 routes and 15",
+ "18 routes and 22",
"wait",
"Local and remote routes",
10,
@@ -721,7 +780,7 @@ luCommand("r4", 'vtysh -c "show ip route vrf r4-cust2"')
luCommand(
"ce3",
'vtysh -c "show bgp ipv4 uni"',
- "12 routes and 14",
+ "18 routes and 19",
"wait",
"Local and remote routes",
10,
@@ -733,7 +792,6 @@ want = [
{"p": "5.4.2.0/24", "n": "192.168.1.1", "bp": True},
{"p": "5.4.3.0/24", "n": "192.168.1.1", "bp": True},
{"p": "6.0.1.0/24", "n": "192.168.1.1", "bp": False},
- {"p": "6.0.2.0/24", "n": "192.168.1.1", "bp": False},
{"p": "6.0.1.0/24", "n": "99.0.0.3", "bp": True},
{"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": True},
]
@@ -744,7 +802,7 @@ bgpribRequireUnicastRoutes(
luCommand(
"ce4",
'vtysh -c "show bgp vrf ce4-cust2 ipv4 uni"',
- "12 routes and 14",
+ "18 routes and 21",
"wait",
"Local and remote routes",
10,
@@ -834,45 +892,36 @@ luCommand(
luCommand(
"ce1",
'vtysh -c "show bgp ipv4 uni 6.0.2.0"',
- "2 available, best .*192.168.1.1.* Local.* 99.0.0.1 from 0.0.0.0 .99.0.0.1"
- + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .Weight"
+ "1 available, best .*192.168.1.1.* Local.* 99.0.0.1 from 0.0.0.0 .99.0.0.1"
+ + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .First path received"
+ ".* Community: 0:67.* Extended Community: RT:89:123.* Large Community: 12:34:11",
"pass",
- "Redundant route 2 details",
+ "Route 2 details",
)
luCommand(
"ce2",
'vtysh -c "show bgp ipv4 uni 6.0.2.0"',
- "2 available, best .*192.168.1.1.* Local.* 99.0.0.2 from 0.0.0.0 .99.0.0.2"
- + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .Weight"
+ "1 available, best .*192.168.1.1.* Local.* 99.0.0.2 from 0.0.0.0 .99.0.0.2"
+ + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .First path received"
+ ".* Community: 0:67.* Extended Community: RT:89:123.* Large Community: 12:34:12",
"pass",
- "Redundant route 2 details",
+ "Route 2 details",
)
luCommand(
"ce3",
'vtysh -c "show bgp ipv4 uni 6.0.2.0"',
- "2 available, best .*192.168.1.1.* Local.* 99.0.0.3 from 0.0.0.0 .99.0.0.3"
- + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .Weight"
+ "1 available, best .*192.168.1.1.* Local.* 99.0.0.3 from 0.0.0.0 .99.0.0.3"
+ + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .First path received"
+ ".* Community: 0:67.* Extended Community: RT:89:123.* Large Community: 12:34:13",
"pass",
- "Redundant route 2 details",
-)
-luCommand(
- "ce3",
- 'vtysh -c "show bgp ipv4 uni 6.0.2.0"',
- "2 available, best .*192.168.1.1.* Local.* 192.168.1.1 from 192.168.1.1 .192.168.1.1"
- + ".* Origin IGP, metric 100, localpref 100, valid, internal"
- + ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:11",
- "pass",
- "Redundant route 2 details",
+ "Route 2 details",
)
luCommand(
"ce4",
'vtysh -c "show bgp vrf ce4-cust2 ipv4 6.0.2.0"',
"2 available, best .*192.168.2.1.* Local.* 192.168.2.1 from 192.168.2.1 .192.168.2.1"
+ ".* Origin IGP, metric 100, localpref 100, valid, internal"
- + ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:11",
+ + ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:13",
"pass",
"Redundant route 2 details",
)
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/__init__.py b/tests/topotests/bgp_labeled_unicast_addpath/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/__init__.py
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r1/bgpd.conf b/tests/topotests/bgp_labeled_unicast_addpath/r1/bgpd.conf
new file mode 100644
index 0000000000..ae3812ab96
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r1/bgpd.conf
@@ -0,0 +1,14 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 192.168.31.3 remote-as external
+ neighbor 192.168.31.3 timers 1 3
+ neighbor 192.168.31.3 timers connect 1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 192.168.31.3 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r1/zebra.conf b/tests/topotests/bgp_labeled_unicast_addpath/r1/zebra.conf
new file mode 100644
index 0000000000..fbaccdafdd
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r1/zebra.conf
@@ -0,0 +1,7 @@
+!
+interface lo
+ ip address 10.0.0.1/32
+!
+interface r1-eth0
+ ip address 192.168.31.1/24
+!
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r2/bgpd.conf b/tests/topotests/bgp_labeled_unicast_addpath/r2/bgpd.conf
new file mode 100644
index 0000000000..16dc1f3e4c
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r2/bgpd.conf
@@ -0,0 +1,14 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 192.168.32.3 remote-as external
+ neighbor 192.168.32.3 timers 1 3
+ neighbor 192.168.32.3 timers connect 1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 192.168.32.3 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r2/zebra.conf b/tests/topotests/bgp_labeled_unicast_addpath/r2/zebra.conf
new file mode 100644
index 0000000000..8118d56a1b
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r2/zebra.conf
@@ -0,0 +1,7 @@
+!
+interface lo
+ ip address 10.0.0.1/32
+!
+interface r2-eth0
+ ip address 192.168.32.2/24
+!
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r3/bgpd.conf b/tests/topotests/bgp_labeled_unicast_addpath/r3/bgpd.conf
new file mode 100644
index 0000000000..6dd8f7f67e
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r3/bgpd.conf
@@ -0,0 +1,35 @@
+!
+router bgp 65003
+ no bgp default ipv4-unicast
+ no bgp ebgp-requires-policy
+ no bgp suppress-duplicates
+ bgp bestpath as-path multipath-relax
+ neighbor 192.168.31.1 remote-as external
+ neighbor 192.168.31.1 timers 1 3
+ neighbor 192.168.31.1 timers connect 1
+ neighbor 192.168.32.2 remote-as external
+ neighbor 192.168.32.2 timers 1 3
+ neighbor 192.168.32.2 timers connect 1
+ neighbor 192.168.34.4 remote-as external
+ neighbor 192.168.34.4 timers 1 3
+ neighbor 192.168.34.4 timers connect 1
+ neighbor 192.168.35.5 remote-as external
+ neighbor 192.168.35.5 timers 1 3
+ neighbor 192.168.35.5 timers connect 1
+ neighbor 192.168.35.5 shutdown
+ address-family ipv4 labeled-unicast
+ neighbor 192.168.31.1 activate
+ neighbor 192.168.32.2 activate
+ neighbor 192.168.35.5 activate
+ neighbor 192.168.34.4 activate
+ neighbor 192.168.34.4 route-map r4 out
+ neighbor 192.168.34.4 addpath-tx-all-paths
+ exit-address-family
+ !
+!
+ip prefix-list r4 seq 5 permit 10.0.0.1/32
+!
+route-map r4 permit 10
+ match ip address prefix-list r4
+exit
+!
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r3/zebra.conf b/tests/topotests/bgp_labeled_unicast_addpath/r3/zebra.conf
new file mode 100644
index 0000000000..838413ac6f
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r3/zebra.conf
@@ -0,0 +1,13 @@
+!
+interface r3-eth0
+ ip address 192.168.31.3/24
+!
+interface r3-eth1
+ ip address 192.168.32.3/24
+!
+interface r3-eth2
+ ip address 192.168.34.3/24
+!
+interface r3-eth3
+ ip address 192.168.35.3/24
+!
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r4/bgpd.conf b/tests/topotests/bgp_labeled_unicast_addpath/r4/bgpd.conf
new file mode 100644
index 0000000000..e137156b74
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r4/bgpd.conf
@@ -0,0 +1,10 @@
+router bgp 65004
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 192.168.34.3 remote-as external
+ neighbor 192.168.34.3 timers 1 3
+ neighbor 192.168.34.3 timers connect 1
+ address-family ipv4 labeled-unicast
+ neighbor 192.168.34.3 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r4/zebra.conf b/tests/topotests/bgp_labeled_unicast_addpath/r4/zebra.conf
new file mode 100644
index 0000000000..2ec426a511
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r4/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r4-eth0
+ ip address 192.168.34.4/24
+!
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r5/bgpd.conf b/tests/topotests/bgp_labeled_unicast_addpath/r5/bgpd.conf
new file mode 100644
index 0000000000..5b38b5a0d2
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r5/bgpd.conf
@@ -0,0 +1,14 @@
+router bgp 65005
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 192.168.35.3 remote-as external
+ neighbor 192.168.35.3 timers 1 3
+ neighbor 192.168.35.3 timers connect 1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv4 labeled-unicast
+ neighbor 192.168.35.3 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_labeled_unicast_addpath/r5/zebra.conf b/tests/topotests/bgp_labeled_unicast_addpath/r5/zebra.conf
new file mode 100644
index 0000000000..6289e4ffc5
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/r5/zebra.conf
@@ -0,0 +1,7 @@
+!
+interface lo
+ ip address 10.0.0.1/32
+!
+interface r5-eth0
+ ip address 192.168.35.5/24
+!
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
new file mode 100644
index 0000000000..aae901eabe
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Check if labeled-unicast works correctly with addpath capability.
+Initially R3 MUST announce 10.0.0.1/32 multipath(2) from R1 + R2.
+Later, we enable R5 and 10.0.0.1/32 multipath(3) MUST be announced,
+R1 + R2 + R5.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 6):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r5"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_addpath_labeled_unicast():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r3 = tgen.gears["r3"]
+ r4 = tgen.gears["r4"]
+
+ def _bgp_check_advertised_routes(prefix_num):
+ output = json.loads(
+ r3.vtysh_cmd(
+ "show bgp ipv4 labeled-unicast neighbors 192.168.34.4 advertised-routes json"
+ )
+ )
+ expected = {
+ "advertisedRoutes": {
+ "10.0.0.1/32": {
+ "appliedStatusSymbols": {
+ "*": True,
+ ">": True,
+ "=": True,
+ }
+ }
+ },
+ "totalPrefixCounter": prefix_num,
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_advertised_routes, 2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "Failed to advertise labeled-unicast with addpath (multipath)"
+
+ def _bgp_check_received_routes():
+ output = json.loads(r4.vtysh_cmd("show bgp ipv4 labeled-unicast json"))
+ expected = {
+ "routes": {
+ "10.0.0.1/32": [
+ {
+ "valid": True,
+ "path": "65003 65001",
+ },
+ {
+ "valid": True,
+ "path": "65003 65002",
+ },
+ ]
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to receive labeled-unicast with addpath (multipath)"
+
+ step("Enable BGP session for R5")
+ r3.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65003
+ no neighbor 192.168.35.5 shutdown
+ """
+ )
+
+ test_func = functools.partial(_bgp_check_advertised_routes, 3)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "Failed to advertise labeled-unicast with addpath (multipath)"
+
+ step("Disable BGP session for R5")
+ r3.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65003
+ neighbor 192.168.35.5 shutdown
+ """
+ )
+
+ test_func = functools.partial(_bgp_check_advertised_routes, 2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "Failed to advertise labeled-unicast with addpath (multipath)"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/__init__.py b/tests/topotests/bgp_labeled_unicast_default_originate/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_default_originate/__init__.py
diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/r1/bgpd.conf b/tests/topotests/bgp_labeled_unicast_default_originate/r1/bgpd.conf
new file mode 100644
index 0000000000..75a4aa6ab3
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_default_originate/r1/bgpd.conf
@@ -0,0 +1,21 @@
+!
+router bgp 65001
+ no bgp default ipv4-unicast
+ no bgp ebgp-requires-policy
+ neighbor 192.168.12.2 remote-as external
+ neighbor 192.168.12.2 timers 1 3
+ neighbor 192.168.12.2 timers connect 1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ address-family ipv4 labeled-unicast
+ neighbor 192.168.12.2 activate
+ neighbor 192.168.12.2 default-originate route-map r2
+ exit-address-family
+ !
+!
+route-map r2 permit 10
+ set community 65001:65001
+ set metric 666
+exit
+!
diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/r1/zebra.conf b/tests/topotests/bgp_labeled_unicast_default_originate/r1/zebra.conf
new file mode 100644
index 0000000000..8eab7805df
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_default_originate/r1/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r1-eth0
+ ip address 192.168.12.1/24
+!
diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/r2/bgpd.conf b/tests/topotests/bgp_labeled_unicast_default_originate/r2/bgpd.conf
new file mode 100644
index 0000000000..c81ba9fe02
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_default_originate/r2/bgpd.conf
@@ -0,0 +1,11 @@
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 192.168.12.1 remote-as external
+ neighbor 192.168.12.1 timers 1 3
+ neighbor 192.168.12.1 timers connect 1
+ address-family ipv4 labeled-unicast
+ neighbor 192.168.12.1 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/r2/zebra.conf b/tests/topotests/bgp_labeled_unicast_default_originate/r2/zebra.conf
new file mode 100644
index 0000000000..d7dfd899cc
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_default_originate/r2/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r2-eth0
+ ip address 192.168.12.2/24
+!
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
new file mode 100644
index 0000000000..91a92d2dd1
--- /dev/null
+++ b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Check if labeled-unicast works correctly with default-originate.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 3):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_labeled_unicast_default_originate():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+
+ def _bgp_check_advertised_routes():
+ output = json.loads(
+ r1.vtysh_cmd(
+ "show bgp ipv4 labeled-unicast neighbors 192.168.12.2 advertised-routes json"
+ )
+ )
+ expected = {
+ "bgpOriginatingDefaultNetwork": "0.0.0.0/0",
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_advertised_routes)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to advertise default route for labeled-unicast"
+
+ def _bgp_check_received_routes():
+ output = json.loads(
+ r2.vtysh_cmd("show bgp ipv4 labeled-unicast 0.0.0.0/0 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "valid": True,
+ "metric": 666,
+ "community": {
+ "string": "65001:65001",
+ },
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to receive default route for labeled-unicast"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
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 bb2c43d1fc..2b4c4e816b 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
@@ -31,13 +31,14 @@ used together with `remove-private-AS`.
import os
import sys
import json
-import time
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]
@@ -84,29 +85,43 @@ def test_bgp_remove_private_as():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- def _bgp_converge(router):
- while True:
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")
- )
- if output["192.168.255.1"]["bgpState"] == "Established":
- time.sleep(1)
- return True
-
- def _bgp_as_path(router):
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json")
- )
- if output["prefix"] == "172.16.255.254/32":
- return output["paths"][0]["aspath"]["segments"][0]["list"]
-
- if _bgp_converge("r2"):
- assert len(_bgp_as_path("r2")) == 1
- assert 65000 not in _bgp_as_path("r2")
-
- if _bgp_converge("r4"):
- assert len(_bgp_as_path("r4")) == 2
- assert 3000 in _bgp_as_path("r4")
+ r2 = tgen.gears["r2"]
+ r4 = tgen.gears["r4"]
+
+ 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",
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't converge initially"
+
+ def _bgp_as_path(router, asn_path, asn_length):
+ output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.254/32 json"))
+ expected = {
+ "paths": [
+ {
+ "aspath": {
+ "string": asn_path,
+ "length": asn_length,
+ }
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_as_path, r2, "500", 1)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Private ASNs not stripped"
+
+ test_func = functools.partial(_bgp_as_path, r4, "500 3000", 2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Private ASNs not stripped"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
index 62110429cf..271a5bb1b1 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
@@ -1,6 +1,13 @@
router bgp 65000
- no bgp ebgp-requires-policy
- neighbor 192.168.255.2 remote-as 65001
- neighbor 192.168.255.2 timers 3 10
- address-family ipv4 unicast
- redistribute connected
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
+ address-family ipv4 unicast
+ redistribute connected
+ neighbor 192.168.255.2 prefix-list r2 out
+ exit-address-family
+ !
+!
+ip prefix-list r2 seq 5 permit 172.16.255.253/32
+ip prefix-list r2 seq 10 permit 172.16.255.254/32
+!
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf
index 0a283c06d5..68c5021636 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf
@@ -1,6 +1,7 @@
!
interface lo
ip address 172.16.255.254/32
+ ip address 172.16.255.253/32
!
interface r1-eth0
ip address 192.168.255.1/24
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
index 005425e850..cb30808f41 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
@@ -1,6 +1,9 @@
router bgp 65001
- no bgp ebgp-requires-policy
- neighbor 192.168.255.1 remote-as 65000
- neighbor 192.168.255.1 timers 3 10
- address-family ipv4
- neighbor 192.168.255.1 maximum-prefix 1
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
+ address-family ipv4
+ neighbor 192.168.255.1 maximum-prefix 1
+ exit-address-family
+ !
+!
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 5c34ebf919..ee68ecd7b6 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
@@ -36,11 +36,13 @@ 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]
@@ -83,29 +85,21 @@ def test_bgp_maximum_prefix_invalid():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- def _bgp_converge(router):
- while True:
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")
- )
- if output["192.168.255.1"]["connectionsEstablished"] > 0:
- return True
-
- def _bgp_parsing_nlri(router):
- cmd_max_exceeded = (
- 'grep "%MAXPFXEXCEED: No. of IPv4 Unicast prefix received" bgpd.log'
- )
- cmdt_error_parsing_nlri = 'grep "Error parsing NLRI" bgpd.log'
- output_max_exceeded = tgen.gears[router].run(cmd_max_exceeded)
- output_error_parsing_nlri = tgen.gears[router].run(cmdt_error_parsing_nlri)
-
- if len(output_max_exceeded) > 0:
- if len(output_error_parsing_nlri) > 0:
- return False
- return True
-
- if _bgp_converge("r2"):
- assert _bgp_parsing_nlri("r2") == True
+ r2 = tgen.gears["r2"]
+
+ def _bgp_parsing_nlri():
+ output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ expected = {
+ "192.168.255.1": {
+ "lastNotificationReason": "Cease/Maximum Number of Prefixes Reached",
+ "lastResetDueTo": "BGP Notification send",
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_parsing_nlri)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Didn't send NOTIFICATION when hitting maximum-prefix"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_path_selection/__init__.py b/tests/topotests/bgp_path_selection/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/__init__.py
diff --git a/tests/topotests/bgp_path_selection/r1/bgpd.conf b/tests/topotests/bgp_path_selection/r1/bgpd.conf
new file mode 100644
index 0000000000..08eb8675c2
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r1/bgpd.conf
@@ -0,0 +1,28 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.0.2.2 remote-as 65002
+ neighbor 192.0.2.2 timers 1 3
+ neighbor 192.0.2.2 timers connect 1
+ neighbor 192.0.2.2 ebgp-multihop 2
+ neighbor 192.0.2.3 remote-as 65002
+ neighbor 192.0.2.3 timers 1 3
+ neighbor 192.0.2.3 timers connect 1
+ neighbor 192.0.2.3 ebgp-multihop 2
+ address-family ipv4
+ redistribute connected
+ exit-address-family
+ address-family ipv4 vpn
+ neighbor 192.0.2.2 activate
+ neighbor 192.0.2.3 activate
+ exit-address-family
+!
+router bgp 65001 vrf vrf1
+ bgp router-id 192.0.2.1
+ address-family ipv4 unicast
+ label vpn export 101
+ rd vpn export 101:1
+ rt vpn both 52:100
+ import vpn
+ export vpn
+ exit-address-family
+! \ No newline at end of file
diff --git a/tests/topotests/bgp_path_selection/r1/ldpd.conf b/tests/topotests/bgp_path_selection/r1/ldpd.conf
new file mode 100644
index 0000000000..04ae06877a
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r1/ldpd.conf
@@ -0,0 +1,26 @@
+hostname r1
+log file ldpd.log
+password zebra
+!
+! debug mpls ldp zebra
+! debug mpls ldp event
+! debug mpls ldp errors
+! debug mpls ldp messages recv
+! debug mpls ldp messages sent
+! debug mpls ldp discovery hello recv
+! debug mpls ldp discovery hello sent
+!
+mpls ldp
+ router-id 192.0.2.1
+ !
+ address-family ipv4
+ discovery transport-address 192.0.2.1
+ !
+ interface r1-eth0
+ !
+ interface r1-eth1
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/bgp_path_selection/r1/staticd.conf b/tests/topotests/bgp_path_selection/r1/staticd.conf
new file mode 100644
index 0000000000..a37f60af10
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r1/staticd.conf
@@ -0,0 +1,2 @@
+ip route 192.0.2.2/32 192.168.1.2
+ip route 192.0.2.3/32 192.168.2.2 \ No newline at end of file
diff --git a/tests/topotests/bgp_path_selection/r1/zebra.conf b/tests/topotests/bgp_path_selection/r1/zebra.conf
new file mode 100644
index 0000000000..e860d6e524
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r1/zebra.conf
@@ -0,0 +1,11 @@
+!
+interface lo
+ ip address 192.0.2.1/32
+ ip address 172.16.255.1/32
+!
+interface r1-eth0
+ ip address 192.168.1.1/24
+!
+interface r1-eth1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/bgp_path_selection/r2/bgpd.conf b/tests/topotests/bgp_path_selection/r2/bgpd.conf
new file mode 100644
index 0000000000..cc878d83b9
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r2/bgpd.conf
@@ -0,0 +1,25 @@
+router bgp 65002
+ no bgp network import-check
+ network 192.0.2.8/32
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as 65001
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ neighbor 192.168.1.1 ebgp-multihop 2
+ neighbor 192.168.1.1 update-source 192.0.2.2
+ address-family ipv4 vpn
+ neighbor 192.168.1.1 activate
+ exit-address-family
+!
+router bgp 65002 vrf vrf1
+ bgp router-id 192.0.2.2
+ no bgp ebgp-requires-policy
+ address-family ipv4 unicast
+ redistribute connected
+ label vpn export 102
+ rd vpn export 102:1
+ rt vpn both 52:100
+ import vpn
+ export vpn
+ exit-address-family
+! \ No newline at end of file
diff --git a/tests/topotests/bgp_path_selection/r2/ldpd.conf b/tests/topotests/bgp_path_selection/r2/ldpd.conf
new file mode 100644
index 0000000000..67973ab6eb
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r2/ldpd.conf
@@ -0,0 +1,26 @@
+hostname r2
+log file ldpd.log
+password zebra
+!
+! debug mpls ldp zebra
+! debug mpls ldp event
+! debug mpls ldp errors
+! debug mpls ldp messages recv
+! debug mpls ldp messages sent
+! debug mpls ldp discovery hello recv
+! debug mpls ldp discovery hello sent
+!
+mpls ldp
+ router-id 192.0.2.2
+ !
+ address-family ipv4
+ discovery transport-address 192.0.2.2
+ !
+ interface r2-eth0
+ !
+ interface r2-eth1
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/bgp_path_selection/r2/staticd.conf b/tests/topotests/bgp_path_selection/r2/staticd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r2/staticd.conf
diff --git a/tests/topotests/bgp_path_selection/r2/zebra.conf b/tests/topotests/bgp_path_selection/r2/zebra.conf
new file mode 100644
index 0000000000..40dfa9854c
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r2/zebra.conf
@@ -0,0 +1,7 @@
+!
+int lo
+ ip address 192.0.2.2/32
+!
+interface r2-eth0
+ ip address 192.168.1.2/24
+!
diff --git a/tests/topotests/bgp_path_selection/r3/bgpd.conf b/tests/topotests/bgp_path_selection/r3/bgpd.conf
new file mode 100644
index 0000000000..ca8d27a2c5
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r3/bgpd.conf
@@ -0,0 +1,25 @@
+router bgp 65002
+ no bgp network import-check
+ network 192.0.2.8/32
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as 65001
+ neighbor 192.168.2.1 timers 1 3
+ neighbor 192.168.2.1 timers connect 1
+ neighbor 192.168.2.1 ebgp-multihop 2
+ neighbor 192.168.1.1 update-source 192.0.2.3
+ address-family ipv4 vpn
+ neighbor 192.168.2.1 activate
+ exit-address-family
+!
+router bgp 65002 vrf vrf1
+ bgp router-id 192.0.2.3
+ no bgp ebgp-requires-policy
+ address-family ipv4 unicast
+ redistribute connected
+ label vpn export 103
+ rd vpn export 102:1
+ rt vpn both 52:100
+ import vpn
+ export vpn
+ exit-address-family
+! \ No newline at end of file
diff --git a/tests/topotests/bgp_path_selection/r3/ldpd.conf b/tests/topotests/bgp_path_selection/r3/ldpd.conf
new file mode 100644
index 0000000000..b282b0832d
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r3/ldpd.conf
@@ -0,0 +1,24 @@
+hostname r3
+password zebra
+log file ldpd.log
+!
+! debug mpls ldp zebra
+! debug mpls ldp event
+! debug mpls ldp errors
+! debug mpls ldp messages recv
+! debug mpls ldp messages sent
+! debug mpls ldp discovery hello recv
+! debug mpls ldp discovery hello sent
+!
+mpls ldp
+ router-id 192.0.2.3
+ !
+ address-family ipv4
+ discovery transport-address 192.0.2.3
+ !
+ interface r3-eth0
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/bgp_path_selection/r3/staticd.conf b/tests/topotests/bgp_path_selection/r3/staticd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r3/staticd.conf
diff --git a/tests/topotests/bgp_path_selection/r3/zebra.conf b/tests/topotests/bgp_path_selection/r3/zebra.conf
new file mode 100644
index 0000000000..a0473b63ad
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/r3/zebra.conf
@@ -0,0 +1,7 @@
+!
+int lo
+ ip address 192.0.2.3/32
+!
+interface r3-eth0
+ ip address 192.168.2.2/24
+!
diff --git a/tests/topotests/bgp_path_selection/test_bgp_path_selection.py b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py
new file mode 100644
index 0000000000..50b71d8627
--- /dev/null
+++ b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Louis Scalbert <louis.scalbert@6wind.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 4):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for routern in range(1, 4):
+ tgen.gears["r{}".format(routern)].cmd("ip link add vrf1 type vrf table 10")
+ tgen.gears["r{}".format(routern)].cmd("ip link set vrf1 up")
+ tgen.gears["r{}".format(routern)].cmd("ip address add dev vrf1 {}.{}.{}.{}/32".format(routern, routern, routern,routern))
+ 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):
+ 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_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+ tgen.gears["r1"].cmd("ip route add 192.0.2.2 via 192.168.1.2 metric 20")
+ tgen.gears["r1"].cmd("ip route add 192.0.2.3 via 192.168.2.2 metric 20")
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+def test_bgp_path_selection_ecmp():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_check_path_selection_ecmp():
+ output = json.loads(
+ tgen.gears["r1"].vtysh_cmd("show bgp ipv4 unicast 192.0.2.8/32 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "valid": True,
+ "aspath": {"string": "65002"},
+ "multipath": True,
+ "nexthops": [{"ip": "192.0.2.2", "metric": 20}],
+ },
+ {
+ "valid": True,
+ "aspath": {"string": "65002"},
+ "multipath": True,
+ "nexthops": [{"ip": "192.0.2.3", "metric": 20}],
+ }
+ ]
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ step("Check if two ECMP paths are present")
+ test_func = functools.partial(_bgp_check_path_selection_ecmp)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP prefixes on R1"
+
+
+def test_bgp_path_selection_vpn_ecmp():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_check_path_selection_vpn_ecmp():
+ output = json.loads(
+ tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv4 unicast 192.0.2.8/32 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "valid": True,
+ "aspath": {"string": "65002"},
+ "multipath": True,
+ "nexthops": [{"ip": "192.0.2.2", "metric": 20}],
+ },
+ {
+ "valid": True,
+ "aspath": {"string": "65002"},
+ "multipath": True,
+ "nexthops": [{"ip": "192.0.2.3", "metric": 20}],
+ }
+ ]
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ step("Check if two ECMP paths are present")
+ test_func = functools.partial(_bgp_check_path_selection_vpn_ecmp)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP prefixes on R1"
+
+
+def test_bgp_path_selection_metric():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_check_path_selection_metric():
+ output = json.loads(
+ tgen.gears["r1"].vtysh_cmd("show bgp ipv4 unicast 192.0.2.8/32 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "valid": True,
+ "aspath": {"string": "65002"},
+ "nexthops": [{"ip": "192.0.2.2", "metric": 10}],
+ "bestpath":{ "selectionReason":"IGP Metric"},
+ },
+ {
+ "valid": True,
+ "aspath": {"string": "65002"},
+ "nexthops": [{"ip": "192.0.2.3", "metric": 20}],
+ }
+ ]
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ tgen.gears["r1"].cmd("ip route add 192.0.2.2 via 192.168.1.2 metric 10")
+ tgen.gears["r1"].cmd("ip route del 192.0.2.2 via 192.168.1.2 metric 20")
+
+ step("Check if IGP metric best path is selected")
+ test_func = functools.partial(_bgp_check_path_selection_metric)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP prefixes on R1"
+
+
+def test_bgp_path_selection_vpn_metric():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_check_path_selection_vpn_metric():
+ output = json.loads(
+ tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv4 unicast 192.0.2.8/32 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "valid": True,
+ "aspath": {"string": "65002"},
+ "nexthops": [{"ip": "192.0.2.2", "metric": 10}],
+ "bestpath":{ "selectionReason":"IGP Metric"},
+ },
+ {
+ "valid": True,
+ "aspath": {"string": "65002"},
+ "nexthops": [{"ip": "192.0.2.3", "metric": 20}],
+ }
+ ]
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ step("Check if IGP metric best path is selected")
+ test_func = functools.partial(_bgp_check_path_selection_vpn_metric)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP prefixes on R1"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/__init__.py b/tests/topotests/bgp_peer_graceful_shutdown/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/__init__.py
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf
new file mode 100644
index 0000000000..8e5909839a
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf
@@ -0,0 +1,8 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf
new file mode 100644
index 0000000000..376a19a808
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf
@@ -0,0 +1,7 @@
+!
+int lo
+ ip address 10.10.10.1/32
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf
new file mode 100644
index 0000000000..0ee1821003
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.2.2 remote-as internal
+ address-family ipv4 unicast
+ neighbor 192.168.2.2 next-hop-self
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf
new file mode 100644
index 0000000000..67ca02f10a
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf
@@ -0,0 +1,7 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+int r2-eth1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf
new file mode 100644
index 0000000000..5945a024b9
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf
@@ -0,0 +1,5 @@
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as internal
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf
new file mode 100644
index 0000000000..e5a37c98ca
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf
@@ -0,0 +1,4 @@
+!
+int r3-eth0
+ ip address 192.168.2.2/24
+!
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
new file mode 100644
index 0000000000..de62889a0e
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Check if routes from R1 has local-preference set to 0 and graceful-shutdown
+community.
+"""
+
+import os
+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
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2"), "s2": ("r2", "r3")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_orf():
+ 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 neighbor 192.168.2.2 advertised-routes json"
+ )
+ )
+ expected = {"advertisedRoutes": {"10.10.10.1/32": {"locPrf": 100}}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't converge at R2"
+
+ step("Mark routes from R1 as graceful-shutdown")
+ r2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ neighbor 192.168.1.1 graceful-shutdown
+ """
+ )
+
+ def _bgp_check_peer_graceful_shutdown():
+ output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.10.10.1/32 json"))
+ expected = {
+ "paths": [
+ {
+ "locPrf": 0,
+ "community": {"string": "graceful-shutdown"},
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_peer_graceful_shutdown)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "local-preference is not 0 and/or graceful-shutdown community missing"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf
new file mode 100644
index 0000000000..d82a21e1f9
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf
@@ -0,0 +1,31 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ no bgp default ipv4-unicast
+ neighbor 192.168.12.2 remote-as external
+ neighbor 192.168.12.2 timers 1 3
+ neighbor 192.168.12.2 timers connect 1
+ neighbor 2001:db8::12:2 remote-as external
+ neighbor 2001:db8::12:2 timers 1 3
+ neighbor 2001:db8::12:2 timers connect 1
+ !
+ address-family ipv4 unicast
+ network 10.0.0.0/31 route-map p1
+ network 10.0.0.2/32 route-map p2
+ neighbor 192.168.12.2 activate
+ exit-address-family
+ address-family ipv6 unicast
+ network 2001:db8::1/128 route-map p1
+ network 2001:db8:1::/56 route-map p2
+ neighbor 2001:db8::12:2 activate
+ exit-address-family
+!
+route-map p1 permit 10
+ set metric 1
+exit
+route-map p2 permit 10
+ set metric 2
+ set origin incomplete
+exit
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf
new file mode 100644
index 0000000000..0807e89d08
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf
@@ -0,0 +1,5 @@
+!
+interface r1-eth0
+ ip address 192.168.12.1/24
+ ipv6 address 2001:db8::12:1/64
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf
new file mode 100644
index 0000000000..3512e66cec
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf
@@ -0,0 +1,23 @@
+!
+debug bgp updates
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ no bgp default ipv4-unicast
+ neighbor 192.168.12.1 remote-as external
+ neighbor 192.168.12.1 timers 1 3
+ neighbor 192.168.12.1 timers connect 1
+ neighbor 2001:db8::12:1 remote-as external
+ neighbor 2001:db8::12:1 timers 1 3
+ neighbor 2001:db8::12:1 timers connect 1
+ !
+ address-family ipv4 unicast
+ neighbor 192.168.12.1 activate
+ exit-address-family
+ address-family ipv6 unicast
+ neighbor 2001:db8::12:1 activate
+ exit-address-family
+!
+agentx
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf
new file mode 100644
index 0000000000..032b93b676
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf
@@ -0,0 +1,17 @@
+agentAddress 127.0.0.1,[::1]
+
+group public_group v1 public
+group public_group v2c public
+access public_group "" any noauth prefix all all none
+
+rocommunity public default
+
+view all included .1
+
+iquerySecName frr
+rouser frr
+
+master agentx
+
+agentXSocket /etc/frr/agentx
+agentXPerms 777 755 root frr
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf
new file mode 100644
index 0000000000..db6d7005a0
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf
@@ -0,0 +1,5 @@
+!
+interface r2-eth0
+ ip address 192.168.12.2/24
+ ipv6 address 2001:db8::12:2/64
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py
new file mode 100755
index 0000000000..53ca10930b
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test some of the BGP4V2-MIB entries.
+"""
+
+import os
+import sys
+import json
+from time import sleep
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.snmptest import SnmpTester
+from lib import topotest
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.snmp]
+
+
+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"])
+
+
+def setup_module(mod):
+ snmpd = os.system("which snmpd")
+ if snmpd:
+ error_msg = "SNMP not installed - skipping"
+ pytest.skip(error_msg)
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ for rname, router in tgen.routers().items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, "{}/bgpd.conf".format(rname)),
+ "-M snmp",
+ )
+ router.load_config(
+ TopoRouter.RD_SNMP,
+ os.path.join(CWD, "{}/snmpd.conf".format(rname)),
+ "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX",
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_snmp_bgp4v2():
+ tgen = get_topogen()
+
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge_summary():
+ output = json.loads(r2.vtysh_cmd("show bgp summary json"))
+ expected = {
+ "ipv4Unicast": {
+ "peers": {
+ "192.168.12.1": {
+ "state": "Established",
+ "pfxRcd": 2,
+ }
+ }
+ },
+ "ipv6Unicast": {
+ "peers": {
+ "2001:db8::12:1": {
+ "state": "Established",
+ "pfxRcd": 2,
+ }
+ }
+ },
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge_summary)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see connections established"
+
+ def _bgp_converge_prefixes():
+ output = json.loads(r2.vtysh_cmd("show bgp all json"))
+ expected = {
+ "ipv4Unicast": {
+ "routes": {
+ "10.0.0.0/31": [
+ {
+ "metric": 1,
+ "origin": "IGP",
+ }
+ ],
+ "10.0.0.2/32": [
+ {
+ "metric": 2,
+ "origin": "incomplete",
+ }
+ ],
+ }
+ },
+ "ipv6Unicast": {
+ "routes": {
+ "2001:db8::1/128": [
+ {
+ "metric": 1,
+ "origin": "IGP",
+ }
+ ],
+ "2001:db8:1::/56": [
+ {
+ "metric": 2,
+ "origin": "incomplete",
+ }
+ ],
+ }
+ },
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge_prefixes)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see prefixes from R1"
+
+ snmp = SnmpTester(r2, "localhost", "public", "2c", "-Ln -On")
+
+ def _snmpwalk_remote_addr():
+ expected = {
+ "1.3.6.1.3.5.1.1.2.1.5.1.4.192.168.12.1": "C0 A8 0C 01",
+ "1.3.6.1.3.5.1.1.2.1.5.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "20 01 0D B8 00 00 00 00 00 00 00 00 00 12 00 01",
+ }
+
+ # bgp4V2PeerRemoteAddr
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.2.1.5")
+ return output == expected
+
+ _, result = topotest.run_and_expect(_snmpwalk_remote_addr, True, count=10, wait=1)
+ assertmsg = "Can't fetch SNMP for bgp4V2PeerRemoteAddr"
+ assert result, assertmsg
+
+ def _snmpwalk_peer_state():
+ expected = {
+ "1.3.6.1.3.5.1.1.2.1.13.1.4.192.168.12.1": "6",
+ "1.3.6.1.3.5.1.1.2.1.13.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "6",
+ }
+
+ # bgp4V2PeerState
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.2.1.13")
+ return output == expected
+
+ _, result = topotest.run_and_expect(_snmpwalk_peer_state, True, count=10, wait=1)
+ assertmsg = "Can't fetch SNMP for bgp4V2PeerState"
+ assert result, assertmsg
+
+ def _snmpwalk_peer_last_error_code_received():
+ expected = {
+ "1.3.6.1.3.5.1.1.3.1.1.1.4.192.168.12.1": "0",
+ "1.3.6.1.3.5.1.1.3.1.1.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "0",
+ }
+
+ # bgp4V2PeerLastErrorCodeReceived
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.3.1.1")
+ return output == expected
+
+ _, result = topotest.run_and_expect(
+ _snmpwalk_peer_last_error_code_received, True, count=10, wait=1
+ )
+ assertmsg = "Can't fetch SNMP for bgp4V2PeerLastErrorCodeReceived"
+ assert result, assertmsg
+
+ def _snmpwalk_origin():
+ expected = {
+ "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.0.31.192.168.12.1": "1",
+ "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.2.32.192.168.12.1": "3",
+ "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1",
+ "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "3",
+ }
+
+ # bgp4V2NlriOrigin
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.9")
+ return output == expected
+
+ _, result = topotest.run_and_expect(_snmpwalk_origin, True, count=10, wait=1)
+ assertmsg = "Can't fetch SNMP for bgp4V2NlriOrigin"
+ assert result, assertmsg
+
+ def _snmpwalk_med():
+ expected = {
+ "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.0.31.192.168.12.1": "1",
+ "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.2.32.192.168.12.1": "2",
+ "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1",
+ "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "2",
+ }
+
+ # bgp4V2NlriMed
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.17")
+ return output == expected
+
+ _, result = topotest.run_and_expect(_snmpwalk_med, True, count=10, wait=1)
+ assertmsg = "Can't fetch SNMP for bgp4V2NlriMed"
+ assert result, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf
new file mode 100644
index 0000000000..823a56d53f
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf
@@ -0,0 +1,9 @@
+log file zebra.log
+!
+hostname ce1
+!
+interface eth0
+ ip address 172.16.0.1/24
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf
new file mode 100644
index 0000000000..15779aa0d5
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf
@@ -0,0 +1,41 @@
+frr defaults traditional
+!
+hostname pe1
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+router bgp 65001
+ bgp router-id 192.0.2.1
+ !
+ segment-routing srv6
+ locator default
+ exit
+ !
+!
+router bgp 65001 vrf vrf10
+ bgp router-id 192.0.2.1
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ sid vpn export auto
+ rd vpn export 65001:10
+ rt vpn both 0:10
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
+router bgp 65001 vrf vrf20
+ bgp router-id 192.0.2.1
+ !
+ address-family ipv4 unicast
+ rd vpn export 65001:20
+ rt vpn both 0:10
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json
new file mode 100644
index 0000000000..dc86d7c978
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json
@@ -0,0 +1,31 @@
+{
+ "vrfName": "default",
+ "routerId": "192.0.2.1",
+ "localAS": 65001,
+ "routes": {
+ "routeDistinguishers": {
+ "65001:10": {
+ "172.16.0.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "172.16.0.0",
+ "prefixLen": 24,
+ "network": "172.16.0.0\/24",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "hostname": "pe1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json
new file mode 100644
index 0000000000..ce2d5c19c3
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json
@@ -0,0 +1,25 @@
+{
+ "vrfName": "vrf10",
+ "routerId": "192.0.2.1",
+ "localAS": 65001,
+ "routes": {
+ "172.16.0.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "172.16.0.0",
+ "prefixLen": 24,
+ "network": "172.16.0.0\/24",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "hostname": "pe1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json
new file mode 100644
index 0000000000..9f78447255
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json
@@ -0,0 +1,22 @@
+{
+ "172.16.0.0\/24": [
+ {
+ "prefix": "172.16.0.0\/24",
+ "prefixLen": 24,
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "installed": true,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "vrf": "vrf10",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json
new file mode 100644
index 0000000000..6a88d39a8c
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf20",
+ "routerId": "192.0.2.1",
+ "localAS": 65001,
+ "routes": {
+ "172.16.0.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "172.16.0.0",
+ "prefixLen": 24,
+ "network": "172.16.0.0\/24",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "hostname": "pe1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf
new file mode 100644
index 0000000000..52341fc4fc
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf
@@ -0,0 +1,27 @@
+log file zebra.log
+!
+hostname pe1
+!
+interface lo
+ ip address 10.0.0.1/32
+!
+interface eth0 vrf vrf10
+ ip address 172.16.0.254/24
+!
+line vty
+!
+segment-routing
+ srv6
+ locators
+ locator default
+ prefix 2001:db8:2::/64 block-len 40 node-len 24 func-bits 16
+ exit
+ !
+ exit
+ !
+ exit
+ !
+exit
+!
+end
+!
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
new file mode 100755
index 0000000000..16f8adb3c5
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2022, LINE Corporation
+# Authored by Ryoga Saito <ryoga.saito@linecorp.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+import os
+import re
+import sys
+import json
+import functools
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import required_linux_kernel_version
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ tgen.add_router("pe1")
+ tgen.add_router("ce1")
+
+ tgen.add_link(tgen.gears["pe1"], tgen.gears["ce1"], "eth0", "eth0")
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ for rname, router in tgen.routers().items():
+ router.load_config(TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)))
+ router.load_config(TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname)))
+
+ tgen.gears["pe1"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["pe1"].run("ip link set vrf10 up")
+ tgen.gears["pe1"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["pe1"].run("ip link set vrf20 up")
+ tgen.gears["pe1"].run("ip link set eth0 master vrf10")
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def open_json_file(path):
+ try:
+ with open(path, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(path)
+
+
+def check(name, command, checker):
+ tgen = get_topogen()
+ router = tgen.gears[name]
+
+ def _check():
+ try:
+ return checker(router.vtysh_cmd(command))
+ except:
+ return False
+
+ logger.info('[+] check {} "{}"'.format(name, command))
+ _, result = topotest.run_and_expect(_check, None, count=10, wait=0.5)
+ assert result is None, "Failed"
+
+
+def check_vrf10_bgp_rib(output):
+ expected = open_json_file("%s/pe1/results/vrf10_ipv4_unicast.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def check_default_bgp_vpn_rib(output):
+ expected = open_json_file("%s/pe1/results/default_ipv4_vpn.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def check_vrf20_bgp_rib(output):
+ expected = open_json_file("%s/pe1/results/vrf20_ipv4_unicast.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def check_vrf20_rib(output):
+ expected = open_json_file("%s/pe1/results/vrf20_ipv4.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def test_rib():
+ check("pe1", "show bgp vrf vrf10 ipv4 unicast json", check_vrf10_bgp_rib)
+ check("pe1", "show bgp ipv4 vpn json", check_default_bgp_vpn_rib)
+ check("pe1", "show bgp vrf vrf20 ipv4 unicast json", check_vrf20_bgp_rib)
+ check("pe1", "show ip route vrf vrf20 json", check_vrf20_rib)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
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 10d890effb..7c23d4c576 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
@@ -155,7 +155,7 @@ def check_ping(name, dest_addr, expect_connected):
if match not in output:
return "ping fail"
- match = "{} packet loss".format("0%" if expect_connected else "100%")
+ 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)
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf
index c06175193e..30a0f8fe78 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf
@@ -1,5 +1,7 @@
frr defaults traditional
!
+bgp send-extra-data zebra
+!
hostname r1
password zebra
!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf
index 05170572a4..7ca23002ac 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf
@@ -1,5 +1,7 @@
frr defaults traditional
!
+bgp send-extra-data zebra
+!
hostname r2
password zebra
!
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 af66a5a791..1209e9d6e3 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
@@ -69,10 +69,12 @@ def setup_module(mod):
tgen.start_topology()
for rname, router in tgen.routers().items():
router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
- router.load_config(TopoRouter.RD_ZEBRA,
- os.path.join(CWD, '{}/zebra.conf'.format(rname)))
- router.load_config(TopoRouter.RD_BGP,
- os.path.join(CWD, '{}/bgpd.conf'.format(rname)))
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
tgen.gears["r1"].run("sysctl net.vrf.strict_mode=1")
tgen.gears["r1"].run("ip link add vrf10 type vrf table 10")
@@ -114,7 +116,7 @@ def check_ping(name, dest_addr, expect_connected):
logger.info(output)
assert match in output, "ping fail"
- match = "{} packet loss".format("0%" if expect_connected else "100%")
+ 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)
@@ -131,7 +133,7 @@ def check_rib(name, cmd, expected_file):
expected = open_json_file("{}/{}".format(CWD, expected_file))
return topotest.json_cmp(output, expected)
- logger.info("[+] check {} \"{}\" {}".format(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)
@@ -154,16 +156,16 @@ def test_rib():
def test_ping():
- check_ping("ce1", "192.168.2.2", " 0% packet loss")
- check_ping("ce1", "192.168.3.2", " 0% packet loss")
- check_ping("ce1", "192.168.4.2", " 100% packet loss")
- check_ping("ce1", "192.168.5.2", " 100% packet loss")
- check_ping("ce1", "192.168.6.2", " 100% packet loss")
- check_ping("ce4", "192.168.1.2", " 100% packet loss")
- check_ping("ce4", "192.168.2.2", " 100% packet loss")
- check_ping("ce4", "192.168.3.2", " 100% packet loss")
- check_ping("ce4", "192.168.5.2", " 0% packet loss")
- check_ping("ce4", "192.168.6.2", " 0% packet loss")
+ check_ping("ce1", "192.168.2.2", True)
+ check_ping("ce1", "192.168.3.2", True)
+ check_ping("ce1", "192.168.4.2", False)
+ check_ping("ce1", "192.168.5.2", False)
+ check_ping("ce1", "192.168.6.2", False)
+ check_ping("ce4", "192.168.1.2", False)
+ check_ping("ce4", "192.168.2.2", False)
+ check_ping("ce4", "192.168.3.2", False)
+ check_ping("ce4", "192.168.5.2", True)
+ check_ping("ce4", "192.168.6.2", True)
if __name__ == "__main__":
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 e410bbbdeb..61ac7418a4 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
@@ -66,10 +66,12 @@ def setup_module(mod):
tgen.start_topology()
for rname, router in tgen.routers().items():
router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
- router.load_config(TopoRouter.RD_ZEBRA,
- os.path.join(CWD, '{}/zebra.conf'.format(rname)))
- router.load_config(TopoRouter.RD_BGP,
- os.path.join(CWD, '{}/bgpd.conf'.format(rname)))
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
tgen.gears["r1"].run("sysctl net.vrf.strict_mode=1")
tgen.gears["r1"].run("ip link add vrf10 type vrf table 10")
@@ -111,7 +113,7 @@ def check_ping4(name, dest_addr, expect_connected):
logger.info(output)
assert match in output, "ping fail"
- match = "{} packet loss".format("0%" if expect_connected else "100%")
+ 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)
@@ -144,7 +146,7 @@ def check_rib(name, cmd, expected_file):
expected = open_json_file("{}/{}".format(CWD, expected_file))
return topotest.json_cmp(output, expected)
- logger.info("[+] check {} \"{}\" {}".format(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)
@@ -214,10 +216,18 @@ def test_bgp_sid_vpn_export_disable():
no sid vpn per-vrf export
"""
)
- check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_disabled.json")
- check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_disabled.json")
- check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_disabled.json")
- check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_disabled.json")
+ check_rib(
+ "r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_disabled.json"
+ )
+ check_rib(
+ "r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_disabled.json"
+ )
+ check_rib(
+ "r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_disabled.json"
+ )
+ check_rib(
+ "r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_disabled.json"
+ )
check_ping4("ce1", "192.168.2.2", False)
check_ping6("ce1", "2001:2::2", False)
@@ -233,10 +243,18 @@ def test_bgp_sid_vpn_export_reenable():
sid vpn per-vrf export auto
"""
)
- check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_reenabled.json")
- check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_reenabled.json")
- check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_reenabled.json")
- check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_reenabled.json")
+ check_rib(
+ "r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_reenabled.json"
+ )
+ check_rib(
+ "r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_reenabled.json"
+ )
+ check_rib(
+ "r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_reenabled.json"
+ )
+ check_rib(
+ "r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_reenabled.json"
+ )
check_ping4("ce1", "192.168.2.2", True)
check_ping6("ce1", "2001:2::2", True)
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 96a294cae3..6d2b65a614 100644
--- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
+++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
@@ -106,7 +106,7 @@ def test_bgp_route():
"show ip route 50.0.0.0 json",
expected,
)
- _, result = topotest.run_and_expect(test_func, None, count=3, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assertmsg = '"r3" JSON output mismatches'
assert result is None, assertmsg
@@ -118,8 +118,9 @@ def test_bgp_route():
r3,
"show ip route 10.0.0.3 json",
expected,
- )
- _, result = topotest.run_and_expect(test_func, None, count=3, wait=0.5)
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+
def test_bgp_better_admin_won():
"A better Admin distance protocol may come along and knock us out"
diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py
index eed0b34371..acf89835e1 100644
--- a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py
+++ b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py
@@ -153,7 +153,7 @@ 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=3, wait=0.5)
+ success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assert (
result is None
), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router1.name)
@@ -163,7 +163,7 @@ 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=3, wait=0.5)
+ success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assert (
result is None
), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router2.name)
diff --git a/tests/topotests/bgp_unnumbered/__init__.py b/tests/topotests/bgp_unnumbered/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_unnumbered/__init__.py
diff --git a/tests/topotests/bgp_unnumbered/r1/bgpd.conf b/tests/topotests/bgp_unnumbered/r1/bgpd.conf
new file mode 100644
index 0000000000..a9d0ec8dbd
--- /dev/null
+++ b/tests/topotests/bgp_unnumbered/r1/bgpd.conf
@@ -0,0 +1,9 @@
+!
+router bgp 65001
+ timers bgp 1 9
+ no bgp ebgp-requires-policy
+ neighbor r1-eth0 interface remote-as external
+ address-family ipv4 unicast
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_unnumbered/r1/zebra.conf b/tests/topotests/bgp_unnumbered/r1/zebra.conf
new file mode 100644
index 0000000000..1cbaea44f8
--- /dev/null
+++ b/tests/topotests/bgp_unnumbered/r1/zebra.conf
@@ -0,0 +1,10 @@
+!
+interface lo
+ ip address 172.16.250.254/32
+!
+interface r1-eth0
+ ip address 192.168.0.1/24
+!
+ip forwarding
+!
+
diff --git a/tests/topotests/bgp_unnumbered/r2/bgpd.conf b/tests/topotests/bgp_unnumbered/r2/bgpd.conf
new file mode 100644
index 0000000000..fd29cd3c99
--- /dev/null
+++ b/tests/topotests/bgp_unnumbered/r2/bgpd.conf
@@ -0,0 +1,9 @@
+!
+router bgp 65002
+ no bgp network import-check
+ no bgp ebgp-requires-policy
+ timers bgp 1 9
+ neighbor r2-eth0 interface remote-as external
+ address-family ipv4 uni
+ network 172.16.255.254/32
+!
diff --git a/tests/topotests/bgp_unnumbered/r2/zebra.conf b/tests/topotests/bgp_unnumbered/r2/zebra.conf
new file mode 100644
index 0000000000..cf6fb6d984
--- /dev/null
+++ b/tests/topotests/bgp_unnumbered/r2/zebra.conf
@@ -0,0 +1,12 @@
+!
+interface r2-eth0
+ ip address 192.168.0.2/24
+!
+interface r2-eth1
+ ip address 192.168.1.1/24
+!
+interface r2-eth2
+ ip address 192.168.2.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py
new file mode 100644
index 0000000000..de4c4cff37
--- /dev/null
+++ b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2022 by
+# Donald Sharp
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test some bgp interface based issues that show up
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+#
+# Test these events:
+# a) create an unnumbered neighbor
+# b) shutdown the interface
+# c) remove the unnumbered peer in bgp and bgp does not crash
+def test_bgp_unnumbered_removal():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_nexthop_cache():
+ output = tgen.gears["r1"].vtysh_cmd("show bgp nexthop")
+ expected = "Current BGP nexthop cache:\n"
+ return output == expected
+
+ def _bgp_converge():
+ output = json.loads(
+ tgen.gears["r1"].vtysh_cmd("show ip bgp 172.16.255.254/32 json")
+ )
+ expected = {"prefix": "172.16.255.254/32"}
+
+ return topotest.json_cmp(output, expected)
+
+ step("Ensure Convergence of BGP")
+ test_func = functools.partial(_bgp_converge)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+
+ assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"])
+
+ step("Shutdown interface r1-eth0")
+
+ tgen.gears["r1"].vtysh_cmd(
+ """
+ configure
+ int r1-eth0
+ shutdown
+ """
+ )
+
+ step("Remove the neighbor from r1")
+ tgen.gears["r1"].vtysh_cmd(
+ """
+ configure
+ router bgp
+ no neighbor r1-eth0 interface remote-as external
+ """
+ )
+
+ 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)
+
+ assert result is True, "BGP did not crash on r1"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_vpn_5549_route_map/__init__.py b/tests/topotests/bgp_vpn_5549_route_map/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/__init__.py
diff --git a/tests/topotests/bgp_vpn_5549_route_map/cpe1/bgpd.conf b/tests/topotests/bgp_vpn_5549_route_map/cpe1/bgpd.conf
new file mode 100644
index 0000000000..013cd8c258
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/cpe1/bgpd.conf
@@ -0,0 +1,9 @@
+router bgp 65000
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/cpe1/zebra.conf b/tests/topotests/bgp_vpn_5549_route_map/cpe1/zebra.conf
new file mode 100644
index 0000000000..49dcfc3b02
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/cpe1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.1/32
+!
+interface cpe1-eth0
+ ip address 192.168.1.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/cpe2/bgpd.conf b/tests/topotests/bgp_vpn_5549_route_map/cpe2/bgpd.conf
new file mode 100644
index 0000000000..d65d507bf4
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/cpe2/bgpd.conf
@@ -0,0 +1,6 @@
+router bgp 65000
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers 1 3
+ neighbor 192.168.2.2 timers connect 1
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/cpe2/zebra.conf b/tests/topotests/bgp_vpn_5549_route_map/cpe2/zebra.conf
new file mode 100644
index 0000000000..a47319e45f
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/cpe2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface cpe2-eth0
+ ip address 192.168.2.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/pe1/bgpd.conf b/tests/topotests/bgp_vpn_5549_route_map/pe1/bgpd.conf
new file mode 100644
index 0000000000..93da025463
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/pe1/bgpd.conf
@@ -0,0 +1,38 @@
+router bgp 65001
+ bgp router-id 10.10.10.10
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 2001:db8:1::2 remote-as internal
+ neighbor 2001:db8:1::2 update-source 2001:db8:1::1
+ neighbor 2001:db8:1::2 timers 1 3
+ neighbor 2001:db8:1::2 timers connect 1
+ neighbor 2001:db8:1::2 capability extended-nexthop
+ address-family ipv4 vpn
+ neighbor 2001:db8:1::2 activate
+ neighbor 2001:db8:1::2 route-map pe2 out
+ exit-address-family
+!
+router bgp 65001 vrf RED
+ bgp router-id 192.168.1.2
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ address-family ipv4 unicast
+ label vpn export 1111
+ rd vpn export 192.168.1.2:2
+ rt vpn import 192.168.2.2:2 192.168.1.2:2
+ rt vpn export 192.168.1.2:2
+ export vpn
+ import vpn
+ exit-address-family
+!
+ip prefix-list cpe1 seq 5 permit 172.16.255.1/32
+!
+route-map pe2 permit 10
+ match ip address prefix-list cpe1
+ set ipv6 vpn next-hop 2001:db8::1
+!
+route-map pe2 permit 20
+exit
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/pe1/ldpd.conf b/tests/topotests/bgp_vpn_5549_route_map/pe1/ldpd.conf
new file mode 100644
index 0000000000..fb40f06fa7
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/pe1/ldpd.conf
@@ -0,0 +1,10 @@
+mpls ldp
+ router-id 10.10.10.10
+ !
+ address-family ipv4
+ discovery transport-address 10.10.10.10
+ !
+ interface pe1-eth1
+ !
+ !
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/pe1/ospf6d.conf b/tests/topotests/bgp_vpn_5549_route_map/pe1/ospf6d.conf
new file mode 100644
index 0000000000..0053d1ecb5
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/pe1/ospf6d.conf
@@ -0,0 +1,12 @@
+!
+interface lo
+ ipv6 ospf6 area 0
+!
+interface pe1-eth1
+ ipv6 ospf6 area 0
+ ipv6 ospf6 hello-interval 1
+ ipv6 ospf6 dead-interval 3
+!
+router ospf6
+ ospf6 router-id 10.10.10.10
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/pe1/zebra.conf b/tests/topotests/bgp_vpn_5549_route_map/pe1/zebra.conf
new file mode 100644
index 0000000000..da91055135
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/pe1/zebra.conf
@@ -0,0 +1,14 @@
+!
+interface lo
+ ip address 10.10.10.10/32
+ ipv6 address 2001:db8:1::1/128
+!
+interface pe1-eth0 vrf RED
+ ip address 192.168.1.2/24
+!
+interface pe1-eth1
+ ip address 10.0.1.1/24
+ ipv6 address 2001:db8::1/64
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/pe2/bgpd.conf b/tests/topotests/bgp_vpn_5549_route_map/pe2/bgpd.conf
new file mode 100644
index 0000000000..6db1eef993
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/pe2/bgpd.conf
@@ -0,0 +1,29 @@
+router bgp 65001
+ bgp router-id 10.10.10.20
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 2001:db8:1::1 remote-as internal
+ neighbor 2001:db8:1::1 update-source 2001:db8:1::2
+ neighbor 2001:db8:1::1 timers 1 3
+ neighbor 2001:db8:1::1 timers connect 1
+ neighbor 2001:db8:1::1 capability extended-nexthop
+ address-family ipv4 vpn
+ neighbor 2001:db8:1::1 activate
+ exit-address-family
+!
+router bgp 65001 vrf RED
+ bgp router-id 192.168.2.2
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 1 3
+ neighbor 192.168.2.1 timers connect 1
+ address-family ipv4 unicast
+ label vpn export 2222
+ rd vpn export 192.168.2.2:2
+ rt vpn import 192.168.2.2:2 192.168.1.2:2
+ rt vpn export 192.168.2.2:2
+ export vpn
+ import vpn
+ exit-address-family
+!
+
diff --git a/tests/topotests/bgp_vpn_5549_route_map/pe2/ldpd.conf b/tests/topotests/bgp_vpn_5549_route_map/pe2/ldpd.conf
new file mode 100644
index 0000000000..e2b5359993
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/pe2/ldpd.conf
@@ -0,0 +1,10 @@
+mpls ldp
+ router-id 10.10.10.20
+ !
+ address-family ipv4
+ discovery transport-address 10.10.10.20
+ !
+ interface pe2-eth0
+ !
+ !
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/pe2/ospf6d.conf b/tests/topotests/bgp_vpn_5549_route_map/pe2/ospf6d.conf
new file mode 100644
index 0000000000..f79bb4f5f7
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/pe2/ospf6d.conf
@@ -0,0 +1,12 @@
+!
+interface lo
+ ipv6 ospf6 area 0
+!
+interface pe2-eth0
+ ipv6 ospf6 area 0
+ ipv6 ospf6 hello-interval 1
+ ipv6 ospf6 dead-interval 3
+!
+router ospf6
+ ospf6 router-id 10.10.10.20
+!
diff --git a/tests/topotests/bgp_vpn_5549_route_map/pe2/zebra.conf b/tests/topotests/bgp_vpn_5549_route_map/pe2/zebra.conf
new file mode 100644
index 0000000000..19ef7bf911
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/pe2/zebra.conf
@@ -0,0 +1,14 @@
+!
+interface lo
+ ip address 10.10.10.20/32
+ ipv6 address 2001:db8:1::2/128
+!
+interface pe2-eth1 vrf RED
+ ip address 192.168.2.2/24
+!
+interface pe2-eth0
+ ip address 10.0.1.2/24
+ ipv6 address 2001:db8::2/64
+!
+ip forwarding
+!
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
new file mode 100644
index 0000000000..e567d3654f
--- /dev/null
+++ b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Check if we can override VPN underlay next-hop from PE1 to PE2.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ tgen.add_router("cpe1")
+ tgen.add_router("cpe2")
+ tgen.add_router("pe1")
+ tgen.add_router("pe2")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["cpe1"])
+ switch.add_link(tgen.gears["pe1"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["pe1"])
+ switch.add_link(tgen.gears["pe2"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["pe2"])
+ switch.add_link(tgen.gears["cpe2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ pe1 = tgen.gears["pe1"]
+ pe2 = tgen.gears["pe2"]
+
+ pe1.run("ip link add RED type vrf table 1001")
+ pe1.run("ip link set up dev RED")
+ pe2.run("ip link add RED type vrf table 1001")
+ pe2.run("ip link set up dev RED")
+ pe1.run("ip link set pe1-eth0 master RED")
+ pe2.run("ip link set pe2-eth1 master RED")
+
+ pe1.run("sysctl -w net.ipv4.ip_forward=1")
+ pe2.run("sysctl -w net.ipv4.ip_forward=1")
+ pe1.run("sysctl -w net.mpls.conf.pe1-eth0.input=1")
+ pe2.run("sysctl -w net.mpls.conf.pe2-eth1.input=1")
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF6, os.path.join(CWD, "{}/ospf6d.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_vpn_5549():
+ tgen = get_topogen()
+
+ pe2 = tgen.gears["pe2"]
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_vpn_nexthop_changed():
+ output = json.loads(pe2.vtysh_cmd("show bgp ipv4 vpn json"))
+ expected = {
+ "routes": {
+ "routeDistinguishers": {
+ "192.168.1.2:2": {
+ "172.16.255.1/32": [
+ {"valid": True, "nexthops": [{"ip": "2001:db8::1"}]}
+ ],
+ "192.168.1.0/24": [
+ {"valid": True, "nexthops": [{"ip": "2001:db8:1::1"}]}
+ ],
+ }
+ }
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_vpn_nexthop_changed)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed overriding IPv6 next-hop for VPN underlay"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
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 391c272dbc..f193317b1e 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
@@ -75,15 +75,6 @@ from lib.topojson import build_topo_from_json, build_config_from_json
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
-
-# Reading the data from JSON File for topology creation
-jsonFile = "{}/bgp_vrf_dynamic_route_leak_topo2.json".format(CWD)
-try:
- with open(jsonFile, "r") as topoJson:
- topo = json.load(topoJson)
-except IOError:
- assert False, "Could not read file {}".format(jsonFile)
-
# Global variables
NETWORK1_1 = {"ipv4": "11.11.11.1/32", "ipv6": "11:11::1/128"}
NETWORK3_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"}
@@ -92,13 +83,6 @@ NETWORK3_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"}
PREFERRED_NEXT_HOP = "global"
-def build_topo(tgen):
- """Build function"""
-
- # Building topology from json file
- build_topo_from_json(tgen, topo)
-
-
def setup_module(mod):
"""
Sets up the pytest environment
@@ -114,7 +98,9 @@ def setup_module(mod):
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
- tgen = Topogen(build_topo, mod.__name__)
+ json_file = "{}/bgp_vrf_dynamic_route_leak_topo2.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
# Starting topology, create tmp files which are loaded to routers
diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/bgpd.conf b/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/bgpd.conf
new file mode 100644
index 0000000000..66493f0fea
--- /dev/null
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/bgpd.conf
@@ -0,0 +1,23 @@
+frr defaults traditional
+!
+hostname ce1
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+router bgp 65002
+ bgp router-id 192.0.2.2
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor eth0 interface
+ neighbor eth0 remote-as external
+ neighbor eth0 timers connect 1
+ !
+ address-family ipv4 unicast
+ neighbor eth0 activate
+ redistribute connected
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/zebra.conf b/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/zebra.conf
new file mode 100644
index 0000000000..a163295844
--- /dev/null
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/zebra.conf
@@ -0,0 +1,13 @@
+log file zebra.log
+!
+hostname ce1
+!
+interface lo
+ ip address 172.16.0.1/32
+!
+interface eth0
+ ipv6 nd ra-interval 1
+ no ipv6 nd suppress-ra
+!
+line vty
+!
diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/bgpd.conf b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/bgpd.conf
new file mode 100644
index 0000000000..c5c99270e7
--- /dev/null
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/bgpd.conf
@@ -0,0 +1,41 @@
+frr defaults traditional
+!
+hostname pe1
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+router bgp 65001
+ bgp router-id 192.0.2.1
+ !
+!
+router bgp 65001 vrf vrf10
+ bgp router-id 192.0.2.1
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor eth0 interface
+ neighbor eth0 remote-as external
+ neighbor eth0 timers connect 1
+ !
+ address-family ipv4 unicast
+ neighbor eth0 activate
+ rd vpn export 65001:10
+ rt vpn both 0:10
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
+router bgp 65001 vrf vrf20
+ bgp router-id 192.0.2.1
+ !
+ address-family ipv4 unicast
+ rd vpn export 65001:20
+ rt vpn both 0:10
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/default_ipv4_vpn.json b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/default_ipv4_vpn.json
new file mode 100644
index 0000000000..9516016fc2
--- /dev/null
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/default_ipv4_vpn.json
@@ -0,0 +1,32 @@
+{
+ "vrfName": "default",
+ "routerId": "192.0.2.1",
+ "localAS": 65001,
+ "routes": {
+ "routeDistinguishers": {
+ "65001:10": {
+ "172.16.0.1/32": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "172.16.0.1",
+ "prefixLen": 32,
+ "network": "172.16.0.1\/32",
+ "path": "65002",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "hostname": "pe1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json
new file mode 100644
index 0000000000..768bffbe9d
--- /dev/null
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf10_ipv4_unicast.json
@@ -0,0 +1,32 @@
+{
+ "vrfName": "vrf10",
+ "routerId": "192.0.2.1",
+ "localAS": 65001,
+ "routes": {
+ "172.16.0.1/32": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "172.16.0.1",
+ "prefixLen": 32,
+ "network": "172.16.0.1\/32",
+ "path": "65002",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "hostname": "ce1",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ },
+ {
+ "hostname": "ce1",
+ "afi": "ipv6",
+ "scope": "link-local"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json
new file mode 100644
index 0000000000..1e93715270
--- /dev/null
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/results/vrf20_ipv4_unicast.json
@@ -0,0 +1,34 @@
+{
+ "vrfName": "vrf20",
+ "routerId": "192.0.2.1",
+ "localAS": 65001,
+ "routes": {
+ "172.16.0.1/32": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "172.16.0.1",
+ "prefixLen": 32,
+ "network": "172.16.0.1\/32",
+ "path": "65002",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "hostname": "pe1",
+ "afi": "ipv6",
+ "scope": "global",
+ "used": true
+ },
+ {
+ "hostname": "pe1",
+ "afi": "ipv6",
+ "scope": "link-local"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/zebra.conf b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/zebra.conf
new file mode 100644
index 0000000000..d40041ab3c
--- /dev/null
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/zebra.conf
@@ -0,0 +1,10 @@
+log file zebra.log
+!
+hostname pe1
+!
+interface eth0 vrf vrf10
+ ipv6 nd ra-interval 1
+ no ipv6 nd suppress-ra
+!
+line vty
+!
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
new file mode 100755
index 0000000000..dd27ad3ed1
--- /dev/null
+++ b/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2022, LINE Corporation
+# Authored by Ryoga Saito <ryoga.saito@linecorp.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+import os
+import re
+import sys
+import json
+import functools
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import required_linux_kernel_version
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ tgen.add_router("pe1")
+ tgen.add_router("ce1")
+
+ tgen.add_link(tgen.gears["pe1"], tgen.gears["ce1"], "eth0", "eth0")
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ for rname, router in tgen.routers().items():
+ router.load_config(TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)))
+ router.load_config(TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname)))
+
+ tgen.gears["pe1"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["pe1"].run("ip link set vrf10 up")
+ tgen.gears["pe1"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["pe1"].run("ip link set vrf20 up")
+ tgen.gears["pe1"].run("ip link set eth0 master vrf10")
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def open_json_file(path):
+ try:
+ with open(path, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(path)
+
+
+def check_vrf10_rib(output):
+ expected = open_json_file("%s/pe1/results/vrf10_ipv4_unicast.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def check_default_vpn_rib(output):
+ expected = open_json_file("%s/pe1/results/default_ipv4_vpn.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def check_vrf20_rib(output):
+ expected = open_json_file("%s/pe1/results/vrf20_ipv4_unicast.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def check(name, command, checker):
+ tgen = get_topogen()
+ router = tgen.gears[name]
+
+ def _check():
+ try:
+ return checker(router.vtysh_cmd(command))
+ except:
+ return False
+
+ logger.info('[+] check {} "{}"'.format(name, command))
+ _, result = topotest.run_and_expect(_check, None, count=10, wait=0.5)
+ assert result is None, "Failed"
+
+
+def test_rib():
+ check("pe1", "show bgp vrf vrf10 ipv4 unicast json", check_vrf10_rib)
+ check("pe1", "show bgp ipv4 vpn json", check_default_vpn_rib)
+ check("pe1", "show bgp vrf vrf20 ipv4 unicast json", check_vrf20_rib)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
index 03dfbf9322..0540a62096 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
+++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
@@ -1,5 +1,11 @@
hostname r1
+
+#debug bgp vpn leak-to-vrf
+#debug bgp vpn leak-from-vrf
+#debug bgp nht
+
+
router bgp 99 vrf DONNA
no bgp ebgp-requires-policy
address-family ipv4 unicast
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf
index 35038557df..731a00829d 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf
+++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf
@@ -16,3 +16,9 @@ int dummy4
ip address 10.0.3.1/24
no shut
!
+int EVA
+ no shut
+!
+int DONNA
+ no shut
+!
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
index 191a0b53ec..be07c85997 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
+++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
@@ -29,6 +29,7 @@ import os
import sys
from functools import partial
import pytest
+import time
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
@@ -77,7 +78,117 @@ def teardown_module(mod):
tgen.stop_topology()
-def test_vrf_route_leak():
+def check_bgp_rib(router, vrf, in_fib):
+ if in_fib:
+ attr = [{"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}]
+ else:
+ attr = [{"protocol": "bgp", "nexthops": []}]
+
+ if vrf == "DONNA":
+ expect = {
+ "10.0.0.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ "10.0.1.0/24": attr,
+ "10.0.2.0/24": [{"protocol": "connected"}],
+ "10.0.3.0/24": attr,
+ }
+ else:
+ expect = {
+ "10.0.0.0/24": attr,
+ "10.0.1.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ "10.0.2.0/24": attr,
+ "10.0.3.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip route vrf %s json" % vrf, expect
+ )
+ return topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+
+
+def check_bgp_fib(router, vrf, in_rib):
+ # Check FIB
+ # DONNA
+ # 10.0.1.0/24 dev EVA proto bgp metric 20
+ # 10.0.3.0/24 dev EVA proto bgp metric 20
+ # EVA
+ # 10.0.0.0/24 dev DONNA proto bgp metric 20
+ # 10.0.2.0/24 dev DONNA proto bgp metric 20
+
+ if vrf == "DONNA":
+ table = 1001
+ nh_vrf = "EVA"
+ else:
+ table = 1002
+ nh_vrf = "DONNA"
+
+ negate = "" if in_rib else "! "
+
+ cmd = "%sip route show table %s | grep %s" % (negate, table, nh_vrf)
+ result = False
+ retry = 5
+ output = ""
+ while retry:
+ retry -= 1
+ try:
+ output = router.cmd_raises(cmd)
+ result = True
+ break
+ except:
+ time.sleep(0.1)
+
+ logger.info("VRF %s leaked FIB content %s: %s", vrf, cmd, output)
+
+ return result, output
+
+
+def check_bgp_ping(router, vrf):
+ if vrf == "DONNA":
+ cmd = "ip vrf exec DONNA ping -c1 10.0.1.1 -I 10.0.0.1"
+ else:
+ cmd = "ip vrf exec EVA ping -c1 10.0.0.1 -I 10.0.1.1"
+
+ result = False
+ retry = 5
+ output = ""
+ while retry:
+ retry -= 1
+ try:
+ output = router.cmd_raises(cmd)
+ result = True
+ break
+ except:
+ time.sleep(0.1)
+
+ return result, output
+
+
+def check_bgp_ping_own_ip(router):
+ cmd = "ip vrf exec DONNA ping -c1 10.0.0.1 -I 10.0.0.1"
+
+ output = ""
+ try:
+ output = router.cmd_raises(cmd)
+ result = True
+ except:
+ result = False
+ pass
+
+ return result, output
+
+
+def test_vrf_route_leak_test1():
logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen()
# Don't run this test if we have any failure.
@@ -86,53 +197,86 @@ def test_vrf_route_leak():
r1 = tgen.gears["r1"]
- # Test DONNA VRF.
- expect = {
- "10.0.0.0/24": [
- {
- "protocol": "connected",
- }
- ],
- "10.0.1.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
- ],
- "10.0.2.0/24": [{"protocol": "connected"}],
- "10.0.3.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
- ],
- }
-
- test_func = partial(
- topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect
+ result, output = check_bgp_ping_own_ip(r1)
+ assert (
+ result
+ ), "Ping from VRF fails - check https://bugzilla.kernel.org/show_bug.cgi?id=203483\n:{}".format(
+ output
)
- result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
- assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
-
- # Test EVA VRF.
- expect = {
- "10.0.0.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
- ],
- "10.0.1.0/24": [
- {
- "protocol": "connected",
- }
- ],
- "10.0.2.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
- ],
- "10.0.3.0/24": [
- {
- "protocol": "connected",
- }
- ],
- }
- test_func = partial(
- topotest.router_json_cmp, r1, "show ip route vrf EVA json", expect
+ for vrf in ["EVA", "DONNA"]:
+ result, diff = check_bgp_rib(r1, vrf, True)
+ assert result, "BGP RIB VRF {} check failed:\n{}".format(vrf, diff)
+ result, output = check_bgp_fib(r1, vrf, True)
+ assert result, "BGP FIB VRF {} check failed:\n{}".format(vrf, output)
+ result, output = check_bgp_ping(r1, vrf)
+ assert result, "Ping from VRF {} failed:\n{}".format(vrf, output)
+
+
+def test_vrf_route_leak_test2():
+ logger.info(
+ "Ensure that leaked are still present after VRF iface IP address deletion"
)
- result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
- assert result, "BGP VRF EVA check failed:\n{}".format(diff)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ logger.info("Adding and removing an IPv4 address to EVA and DONNA VRF ifaces")
+ r1.cmd("ip address add 1.1.1.1/32 dev EVA && ip address del 1.1.1.1/32 dev EVA")
+ r1.cmd("ip address add 2.2.2.2/32 dev DONNA && ip address del 2.2.2.2/32 dev DONNA")
+
+ for vrf in ["EVA", "DONNA"]:
+ result, diff = check_bgp_rib(r1, vrf, True)
+ assert result, "BGP RIB VRF {} check failed:\n{}".format(vrf, diff)
+ result, output = check_bgp_fib(r1, vrf, True)
+ assert result, "BGP FIB VRF {} check failed:\n{}".format(vrf, output)
+ result, output = check_bgp_ping(r1, vrf)
+ assert result, "Ping from VRF {} failed:\n{}".format(vrf, output)
+
+
+def test_vrf_route_leak_test3():
+ logger.info("Ensure that setting down the VRF ifaces invalidates leaked routes")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ logger.info("Setting down EVA and DONNA VRF ifaces")
+ r1.cmd("ip link set EVA down")
+ r1.cmd("ip link set DONNA down")
+
+ for vrf in ["EVA", "DONNA"]:
+ result, diff = check_bgp_rib(r1, vrf, False)
+ assert result, "BGP RIB VRF {} check failed:\n{}".format(vrf, diff)
+ result, output = check_bgp_fib(r1, vrf, False)
+ assert result, "BGP FIB VRF {} check failed:\n{}".format(vrf, output)
+
+
+def test_vrf_route_leak_test4():
+ logger.info("Ensure that setting up the VRF ifaces validates leaked routes")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ logger.info("Setting up EVA and DONNA VRF ifaces")
+ r1.cmd("ip link set EVA up")
+ r1.cmd("ip link set DONNA up")
+
+ for vrf in ["EVA", "DONNA"]:
+ result, diff = check_bgp_rib(r1, vrf, True)
+ assert result, "BGP RIB VRF {} check failed:\n{}".format(vrf, diff)
+ result, output = check_bgp_fib(r1, vrf, True)
+ assert result, "BGP FIB VRF {} check failed:\n{}".format(vrf, output)
+ result, output = check_bgp_ping(r1, vrf)
+ assert result, "Ping from VRF {} failed:\n{}".format(vrf, output)
def test_memory_leak():
diff --git a/tests/topotests/config_timing/test_config_timing.py b/tests/topotests/config_timing/test_config_timing.py
index 7ab8619b01..0e5508b56d 100644
--- a/tests/topotests/config_timing/test_config_timing.py
+++ b/tests/topotests/config_timing/test_config_timing.py
@@ -161,8 +161,17 @@ def test_static_timing():
return tot_delta
+
# Number of static routes
- prefix_count = 10000
+ router = tgen.gears["r1"]
+ output = router.run("vtysh -h | grep address-sanitizer")
+ if output == "":
+ logger.info("No Address Sanitizer, generating 10000 routes")
+ prefix_count = 10000
+ else:
+ logger.info("Address Sanitizer build, only testing 50 routes")
+ prefix_count = 50
+
prefix_base = [
[u"10.0.0.0/8", u"11.0.0.0/8"],
[u"2100:1111:2220::/44", u"2100:3333:4440::/44"],
diff --git a/tests/topotests/cspf_topo1/test_cspf_topo1.py b/tests/topotests/cspf_topo1/test_cspf_topo1.py
index 220ec49768..7fe86cfabc 100644
--- a/tests/topotests/cspf_topo1/test_cspf_topo1.py
+++ b/tests/topotests/cspf_topo1/test_cspf_topo1.py
@@ -177,7 +177,7 @@ def compare_cspf_output(tgen, rname, fileref, src, dst, cost, bw=""):
test_func = partial(
topotest.router_output_cmp, tgen.gears[rname], command, expected
)
- result, diff = topotest.run_and_expect(test_func, "", count=2, wait=2)
+ result, diff = topotest.run_and_expect(test_func, "", count=5, wait=2)
assert result, "CSPF output mismatches the expected result on {}:\n{}".format(
rname, diff
)
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 a641fec584..b6a6037128 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
@@ -71,7 +71,7 @@ from lib.common_config import (
configure_brctl,
create_interface_in_kernel,
kill_router_daemons,
- start_router_daemons
+ start_router_daemons,
)
from lib.topolog import logger
@@ -86,15 +86,6 @@ from lib.topojson import build_topo_from_json, build_config_from_json
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
-
-# Reading the data from JSON File for topology creation
-jsonFile = "{}/evpn_type5_topo1.json".format(CWD)
-try:
- with open(jsonFile, "r") as topoJson:
- topo = json.load(topoJson)
-except IOError:
- assert False, "Could not read file {}".format(jsonFile)
-
# Global variables
NETWORK1_1 = {"ipv4": "10.1.1.1/32", "ipv6": "10::1/128"}
NETWORK1_2 = {"ipv4": "40.1.1.1/32", "ipv6": "40::1/128"}
@@ -135,10 +126,6 @@ BRCTL = {
}
-def build_topo(tgen):
- build_topo_from_json(tgen, topo)
-
-
def setup_module(mod):
"""
Sets up the pytest environment
@@ -154,7 +141,10 @@ def setup_module(mod):
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
- tgen = Topogen(build_topo, mod.__name__)
+ json_file = "{}/evpn_type5_topo1.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ topo = tgen.json_topo
+
# ... and here it calls Mininet initialization functions.
# Starting topology, create tmp files which are loaded to routers
@@ -1775,34 +1765,41 @@ def test_evpn_address_family_with_graceful_restart_p0(request):
for addr_type in ADDR_TYPES:
input_dict_1 = {
"r3": {
- "static_routes": [{
- "network": NETWORK1_2[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "RED"
- }]
+ "static_routes": [
+ {
+ "network": NETWORK1_2[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ }
+ ]
+ },
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK1_3[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ },
+ {
+ "network": NETWORK1_4[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "GREEN",
+ },
+ ]
},
- "r4":{
- "static_routes": [{
- "network": NETWORK1_3[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "BLUE"
- },
- {
- "network": NETWORK1_4[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "GREEN"
- }]
- }
}
result = create_static_routes(tgen, input_dict_1)
- assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
- step("Redistribute static in (IPv4 and IPv6) address-family "
- "on Edge-1 for all VRFs.")
+ step(
+ "Redistribute static in (IPv4 and IPv6) address-family "
+ "on Edge-1 for all VRFs."
+ )
- input_dict_2={}
+ input_dict_2 = {}
for dut in ["r3", "r4"]:
temp = {dut: {"bgp": []}}
input_dict_2.update(temp)
@@ -1821,108 +1818,116 @@ def test_evpn_address_family_with_graceful_restart_p0(request):
"vrf": vrf,
"address_family": {
"ipv4": {
- "unicast": {
- "redistribute": [{
- "redist_type": "static"
- }]
- }
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
},
"ipv6": {
- "unicast": {
- "redistribute": [{
- "redist_type": "static"
- }]
- }
- }
- }
- })
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
result = create_router_bgp(tgen, topo, input_dict_2)
- assert result is True, "Testcase {} :Failed \n Error: {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
- step("Verify on router Edge-1 that EVPN routes corresponding to "
- "all VRFs are received from both routers DCG-1 and DCG-2")
+ step(
+ "Verify on router Edge-1 that EVPN routes corresponding to "
+ "all VRFs are received from both routers DCG-1 and DCG-2"
+ )
for addr_type in ADDR_TYPES:
input_routes = {
"r3": {
- "static_routes": [{
- "network": NETWORK1_2[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "RED"
- }]
+ "static_routes": [
+ {
+ "network": NETWORK1_2[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ }
+ ]
+ },
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK1_3[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ },
+ {
+ "network": NETWORK1_4[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "GREEN",
+ },
+ ]
},
- "r4":{
- "static_routes": [{
- "network": NETWORK1_3[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "BLUE"
- },
- {
- "network": NETWORK1_4[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "GREEN"
- }]
- }
}
result = verify_rib(tgen, addr_type, "e1", input_routes)
- assert result is True, "Testcase {} :Failed \n Error: {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
- step("Configure DCG-2 as GR restarting node for EVPN session between"
+ step(
+ "Configure DCG-2 as GR restarting node for EVPN session between"
" DCG-2 and EDGE-1, following by a session reset using 'clear bgp *'"
- " command.")
+ " command."
+ )
input_dict_gr = {
"d2": {
- "bgp":
- [
+ "bgp": [
{
"local_as": "200",
"graceful-restart": {
"graceful-restart": True,
- }
+ },
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_gr)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
- step("Verify that DCG-2 changes it's role to GR-restarting router "
- "and EDGE-1 becomes the GR-helper.")
+ step(
+ "Verify that DCG-2 changes it's role to GR-restarting router "
+ "and EDGE-1 becomes the GR-helper."
+ )
step("Kill BGPd daemon on DCG-2.")
kill_router_daemons(tgen, "d2", ["bgpd"])
- step("Verify that EDGE-1 keep stale entries for EVPN RT-5 routes "
- "received from DCG-2 before the restart.")
+ step(
+ "Verify that EDGE-1 keep stale entries for EVPN RT-5 routes "
+ "received from DCG-2 before the restart."
+ )
for addr_type in ADDR_TYPES:
input_routes = {
- "r4":{
- "static_routes": [{
- "network": NETWORK1_3[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "BLUE"
- },
- {
- "network": NETWORK1_4[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "GREEN"
- }]
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK1_3[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ },
+ {
+ "network": NETWORK1_4[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "GREEN",
+ },
+ ]
}
}
result = verify_evpn_routes(tgen, topo, "e1", input_routes)
- assert result is True, "Testcase {} :Failed \n Error: {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
- step("Verify that DCG-2 keeps BGP routes in Zebra until BGPd "
- "comes up or end of 'rib-stale-time'")
+ step(
+ "Verify that DCG-2 keeps BGP routes in Zebra until BGPd "
+ "comes up or end of 'rib-stale-time'"
+ )
step("Start BGPd daemon on DCG-2.")
start_router_daemons(tgen, "d2", ["bgpd"])
@@ -1930,44 +1935,52 @@ def test_evpn_address_family_with_graceful_restart_p0(request):
step("Verify that EDGE-1 removed all the stale entries.")
for addr_type in ADDR_TYPES:
input_routes = {
- "r4":{
- "static_routes": [{
- "network": NETWORK1_3[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "BLUE"
- },
- {
- "network": NETWORK1_4[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "GREEN"
- }]
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK1_3[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ },
+ {
+ "network": NETWORK1_4[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "GREEN",
+ },
+ ]
}
}
result = verify_evpn_routes(tgen, topo, "e1", input_routes)
- assert result is True, "Testcase {} :Failed \n Error: {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
- step("Verify that DCG-2 refresh zebra with EVPN routes. "
- "(no significance of 'rib-stale-time'")
+ step(
+ "Verify that DCG-2 refresh zebra with EVPN routes. "
+ "(no significance of 'rib-stale-time'"
+ )
for addr_type in ADDR_TYPES:
input_routes = {
- "r4":{
- "static_routes": [{
- "network": NETWORK1_3[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "BLUE"
- },
- {
- "network": NETWORK1_4[addr_type],
- "next_hop": NEXT_HOP_IP[addr_type],
- "vrf": "GREEN"
- }]
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK1_3[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ },
+ {
+ "network": NETWORK1_4[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "GREEN",
+ },
+ ]
}
}
result = verify_rib(tgen, addr_type, "d2", input_routes)
- assert result is True, "Testcase {} :Failed \n Error: {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
write_test_footer(tc_name)
diff --git a/tests/topotests/isis_lfa_topo1/rt1/bfdd.conf b/tests/topotests/isis_lfa_topo1/rt1/bfdd.conf
index 86cf68dd8d..ef67eae0cf 100644
--- a/tests/topotests/isis_lfa_topo1/rt1/bfdd.conf
+++ b/tests/topotests/isis_lfa_topo1/rt1/bfdd.conf
@@ -1,6 +1,4 @@
hostname rt1
!
bfd
- peer 2001:db8:1000::2 multihop local-address 2001:db8:1000::1
- !
!
diff --git a/tests/topotests/isis_lfa_topo1/rt2/bfdd.conf b/tests/topotests/isis_lfa_topo1/rt2/bfdd.conf
index 40357a4d03..25fa0d8a46 100644
--- a/tests/topotests/isis_lfa_topo1/rt2/bfdd.conf
+++ b/tests/topotests/isis_lfa_topo1/rt2/bfdd.conf
@@ -1,6 +1,4 @@
hostname rt2
!
bfd
- peer 2001:db8:1000::1 multihop local-address 2001:db8:1000::2
- !
!
diff --git a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
index f72942b607..012814919d 100755
--- a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
+++ b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
@@ -676,8 +676,8 @@ def test_rib_ipv6_step15():
rname,
"show ipv6 route isis json",
outputs[rname][15]["show_ipv6_route.ref"],
- count=2,
- wait=0.05,
+ count=10,
+ wait=0.5,
)
@@ -758,6 +758,80 @@ def test_rib_ipv6_step17():
# - Route switchover of routes via eth-rt2
#
def test_rib_ipv6_step18():
+ def _rt2_neigh_down(router):
+ output = json.loads(router.vtysh_cmd("show isis neighbor rt2 json"))
+
+ """
+ Previous output was:
+ {
+ "areas":[
+ {
+ "area":"1",
+ "circuits":[
+ {
+ "circuit":0,
+ "adj":"rt2",
+ "interface":{
+ "name":"eth-rt2",
+ "state":"Up",
+ "adj-flaps":1,
+ "last-ago":"21s",
+ "circuit-type":"L1",
+ "speaks":"IPv6",
+ "topologies":{
+ "topo-0":"ipv6-unicast"
+ },
+ "snpa":"2020.2020.2020",
+ "area-address":{
+ "isonet":"49.0000"
+ },
+ "ipv6-link-local":{
+ "ipv6":"fe80::ac19:a8ff:fee5:f48f"
+ },
+ "adj-sid":{
+ }
+ },
+ "level":1,
+ "expires-in":"2s"
+ },
+ {
+ "circuit":0
+ },
+ {
+ "circuit":0
+ },
+ {
+ "circuit":0
+ },
+ {
+ "circuit":0
+ },
+ {
+ "circuit":0
+ }
+ ]
+ }
+ ]
+ """
+
+ expected = {
+ "areas": [
+ {
+ "area": "1",
+ "circuits": [
+ {"circuit": 0},
+ {"circuit": 0},
+ {"circuit": 0},
+ {"circuit": 0},
+ {"circuit": 0},
+ {"circuit": 0},
+ ],
+ }
+ ]
+ }
+
+ return topotest.json_cmp(output, expected, exact=True)
+
logger.info("Test (step 18): verify IPv6 RIB")
tgen = get_topogen()
@@ -769,30 +843,17 @@ def test_rib_ipv6_step18():
tgen.net.cmd_raises("ip link set s1 down")
rname = "rt1"
-
- retry = 200 + 1
-
- while retry:
- retry -= 1
- output = tgen.gears[rname].vtysh_cmd("show isis neighbor json")
- output_json = json.loads(output)
- found = False
- for neighbor in output_json["areas"][0]["circuits"]:
- if "adj" in neighbor and neighbor["adj"] == "rt2":
- found = True
- break
- if not found:
- break
- time.sleep(0.05)
-
- assert not found, "rt2 neighbor is still present"
+ router = tgen.gears[rname]
+ test_func = partial(_rt2_neigh_down, router)
+ success, 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(
rname,
"show ipv6 route isis json",
outputs[rname][15]["show_ipv6_route.ref"],
- count=2,
- wait=0.05,
+ count=10,
+ wait=0.5,
)
@@ -887,8 +948,8 @@ def test_rib_ipv6_step21():
rname,
"show ipv6 route isis json",
outputs[rname][15]["show_ipv6_route.ref"],
- count=2,
- wait=0.05,
+ count=10,
+ wait=0.5,
)
@@ -941,14 +1002,14 @@ def test_rib_ipv6_step23():
conf_file = os.path.join(CWD, "{}/bfdd.conf".format(rname))
tgen.net[rname].cmd("vtysh -f {}".format(conf_file))
- rname = "rt1"
- expect = '[{"multihop":true,"peer":"2001:db8:1000::2","local":"2001:db8:1000::1","status":"up"}]'
- router_compare_json_output(rname, "show bfd peers json", expect)
-
logger.info("Set ISIS BFD")
tgen.net["rt1"].cmd('vtysh -c "conf t" -c "int eth-rt2" -c "isis bfd"')
tgen.net["rt2"].cmd('vtysh -c "conf t" -c "int eth-rt1" -c "isis bfd"')
+ rname = "rt1"
+ expect = '[{"multihop":false,"interface":"eth-rt2","status":"up"}]'
+ router_compare_json_output(rname, "show bfd peers json", expect)
+
router_compare_json_output(
rname,
"show ipv6 route isis json",
@@ -968,6 +1029,11 @@ def test_rib_ipv6_step23():
# - Route switchover of routes via eth-rt2
#
def test_rib_ipv6_step24():
+ def _bfd_down(router):
+ output = json.loads(router.vtysh_cmd("show bfd peers json"))
+ expected = []
+ return topotest.json_cmp(output, expected, exact=True)
+
logger.info("Test (step 24): verify IPv6 RIB")
tgen = get_topogen()
@@ -979,20 +1045,16 @@ def test_rib_ipv6_step24():
tgen.net.cmd_raises("ip link set s1 down")
rname = "rt1"
- expect = '[{"multihop":true,"peer":"2001:db8:1000::2","local":"2001:db8:1000::1","status":"down"}]'
- router_compare_json_output(
- rname,
- "show bfd peers json",
- expect,
- count=40,
- wait=0.05,
- )
+ router = tgen.gears[rname]
+ test_func = partial(_bfd_down, router)
+ success, 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(
rname,
"show ipv6 route isis json",
outputs[rname][15]["show_ipv6_route.ref"],
- count=4,
+ count=10,
)
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 5a5b9c59de..213439d3f5 100755
--- a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
+++ b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
@@ -831,19 +831,19 @@ def test_rt6_step11():
rname,
"show ip route isis json",
outputs[rname][11]["show_ip_route.ref"],
- count=1,
+ count=10,
)
router_compare_json_output(
rname,
"show ipv6 route isis json",
outputs[rname][11]["show_ipv6_route.ref"],
- count=1,
+ count=10,
)
router_compare_json_output(
rname,
"show mpls table json",
outputs[rname][11]["show_mpls_table.ref"],
- count=1,
+ count=10,
)
@@ -1021,26 +1021,26 @@ def test_rt6_step14():
"show bfd peers json",
expect,
count=40,
- wait=0.05,
+ wait=0.5,
)
router_compare_json_output(
rname,
"show ip route isis json",
outputs[rname][11]["show_ip_route.ref"],
- count=4,
+ count=10,
)
router_compare_json_output(
rname,
"show ipv6 route isis json",
outputs[rname][11]["show_ipv6_route.ref"],
- count=4,
+ count=10,
)
router_compare_json_output(
rname,
"show mpls table json",
outputs[rname][11]["show_mpls_table.ref"],
- count=4,
+ count=10,
)
diff --git a/tests/topotests/lib/bgprib.py b/tests/topotests/lib/bgprib.py
index 35a57d0a99..01439373c5 100644
--- a/tests/topotests/lib/bgprib.py
+++ b/tests/topotests/lib/bgprib.py
@@ -37,6 +37,7 @@
from lib.lutil import luCommand, luResult, LUtil
import json
import re
+import time
# gpz: get rib in json form and compare against desired routes
class BgpRib:
@@ -48,7 +49,15 @@ class BgpRib:
for pfx in pfxtbl.keys():
if debug:
self.log("trying pfx %s" % pfx)
- if pfx != want["p"]:
+ if "exist" in want and want["exist"] == False:
+ if pfx == want["p"]:
+ if debug:
+ self.log("unexpected route: pfx=" + want["p"])
+ return 0
+ if debug:
+ self.log("unwant pfx=" + want["p"] + ", not " + pfx)
+ continue
+ elif pfx != want["p"]:
if debug:
self.log("want pfx=" + want["p"] + ", not " + pfx)
continue
@@ -75,53 +84,67 @@ class BgpRib:
if debug:
self.log("missing route: pfx=" + want["p"] + ", nh=" + want["n"])
return 0
+ if "exist" in want and want["exist"] == False:
+ return 1
+ return 0
- def RequireVpnRoutes(self, target, title, wantroutes, debug=0):
+ def RequireVpnRoutes(self, target, title, wantroutes, retry=0, wait=1, debug=0):
import json
logstr = "RequireVpnRoutes " + str(wantroutes)
- # non json form for humans
- luCommand(
- target,
- 'vtysh -c "show bgp ipv4 vpn"',
- ".",
- "None",
- "Get VPN RIB (non-json)",
- )
- ret = luCommand(
- target,
- 'vtysh -c "show bgp ipv4 vpn json"',
- ".*",
- "None",
- "Get VPN RIB (json)",
- )
- 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)
- rib = json.loads(ret)
- rds = rib["routes"]["routeDistinguishers"]
- for want in wantroutes:
- found = 0
- if debug:
- self.log("want rd %s" % want["rd"])
- for rd in rds.keys():
- if rd != want["rd"]:
- continue
+ retry += 1
+ while retry:
+ retry -= 1
+ # non json form for humans
+ luCommand(
+ target,
+ 'vtysh -c "show bgp ipv4 vpn"',
+ ".",
+ "None",
+ "Get VPN RIB (non-json)",
+ )
+ ret = luCommand(
+ target,
+ 'vtysh -c "show bgp ipv4 vpn json"',
+ ".*",
+ "None",
+ "Get VPN RIB (json)",
+ )
+ 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)
+ rib = json.loads(ret)
+ rds = rib["routes"]["routeDistinguishers"]
+ for want in wantroutes:
+ found = 0
if debug:
- self.log("found rd %s" % rd)
- table = rds[rd]
- if self.routes_include_wanted(table, want, debug):
- found = 1
- break
- if not found:
- luResult(target, False, title, logstr)
- return
- luResult(target, True, title, logstr)
+ self.log("want rd %s" % want["rd"])
+ for rd in rds.keys():
+ if rd != want["rd"]:
+ continue
+ if debug:
+ self.log("found rd %s" % rd)
+ table = rds[rd]
+ if self.routes_include_wanted(table, want, debug):
+ found = 1
+ break
+ if not found:
+ if retry:
+ break
+ luResult(target, False, title, logstr)
+ return
+ if not found and retry:
+ time.sleep(wait)
+ continue
+ luResult(target, True, title, logstr)
+ break
- def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0):
+ def RequireUnicastRoutes(
+ self, target, afi, vrf, title, wantroutes, retry=0, wait=1, debug=0
+ ):
logstr = "RequireUnicastRoutes %s" % str(wantroutes)
vrfstr = ""
if vrf != "":
@@ -130,48 +153,62 @@ class BgpRib:
if (afi != "ipv4") and (afi != "ipv6"):
self.log("ERROR invalid afi")
- cmdstr = "show bgp %s %s unicast" % (vrfstr, afi)
- # non json form for humans
- cmd = 'vtysh -c "%s"' % cmdstr
- luCommand(target, cmd, ".", "None", "Get %s %s RIB (non-json)" % (vrfstr, afi))
- cmd = 'vtysh -c "%s json"' % cmdstr
- ret = luCommand(
- target, cmd, ".*", "None", "Get %s %s RIB (json)" % (vrfstr, afi)
- )
- if re.search(r"^\s*$", ret):
- # degenerate case: empty json means no routes
- if len(wantroutes) > 0:
- luResult(target, False, title, logstr)
+ retry += 1
+ while retry:
+ retry -= 1
+ cmdstr = "show bgp %s %s unicast" % (vrfstr, afi)
+ # non json form for humans
+ cmd = 'vtysh -c "%s"' % cmdstr
+ luCommand(
+ target, cmd, ".", "None", "Get %s %s RIB (non-json)" % (vrfstr, afi)
+ )
+ cmd = 'vtysh -c "%s json"' % cmdstr
+ ret = luCommand(
+ target, cmd, ".*", "None", "Get %s %s RIB (json)" % (vrfstr, afi)
+ )
+ 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)
+ rib = json.loads(ret)
+ try:
+ table = rib["routes"]
+ # KeyError: 'routes' probably means missing/bad VRF
+ except KeyError as err:
+ if vrf != "":
+ errstr = "-script ERROR: check if wrong vrf (%s)" % (vrf)
+ else:
+ errstr = "-script ERROR: check if vrf missing"
+ if retry:
+ time.sleep(wait)
+ continue
+ luResult(target, False, title + errstr, logstr)
return
+ # 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):
+ if retry:
+ time.sleep(wait)
+ continue
+ luResult(target, False, title, logstr)
+ return
luResult(target, True, title, logstr)
- rib = json.loads(ret)
- try:
- table = rib["routes"]
- # KeyError: 'routes' probably means missing/bad VRF
- except KeyError as err:
- if vrf != "":
- errstr = "-script ERROR: check if wrong vrf (%s)" % (vrf)
- else:
- errstr = "-script ERROR: check if vrf missing"
- luResult(target, False, title + errstr, logstr)
- return
- # 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)
+ break
BgpRib = BgpRib()
-def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0):
- BgpRib.RequireVpnRoutes(target, title, wantroutes, debug)
+def bgpribRequireVpnRoutes(target, title, wantroutes, retry=0, wait=1, debug=0):
+ BgpRib.RequireVpnRoutes(target, title, wantroutes, retry, wait, debug)
-def bgpribRequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug=0):
- BgpRib.RequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug)
+def bgpribRequireUnicastRoutes(
+ target, afi, vrf, title, wantroutes, retry=0, wait=1, debug=0
+):
+ BgpRib.RequireUnicastRoutes(target, afi, vrf, title, wantroutes, retry, wait, debug)
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 737226c7fe..676a5704e5 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -961,7 +961,7 @@ def generate_support_bundle():
return True
-def start_topology(tgen, daemon=None):
+def start_topology(tgen):
"""
Starting topology, create tmp files which are loaded to routers
to start daemons and then start routers
@@ -1009,38 +1009,70 @@ def start_topology(tgen, daemon=None):
except IOError as err:
logger.error("I/O error({0}): {1}".format(err.errno, err.strerror))
- # Loading empty zebra.conf file to router, to start the zebra daemon
+ topo = tgen.json_topo
+ feature = set()
+
+ if "feature" in topo:
+ feature.update(topo["feature"])
+
+ if rname in topo["routers"]:
+ for key in topo["routers"][rname].keys():
+ feature.add(key)
+
+ for val in topo["routers"][rname]["links"].values():
+ if "pim" in val:
+ feature.add("pim")
+ break
+ for val in topo["routers"][rname]["links"].values():
+ if "pim6" in val:
+ feature.add("pim6")
+ break
+ for val in topo["routers"][rname]["links"].values():
+ if "ospf6" in val:
+ feature.add("ospf6")
+ break
+ if "switches" in topo and rname in topo["switches"]:
+ for val in topo["switches"][rname]["links"].values():
+ if "ospf" in val:
+ feature.add("ospf")
+ break
+ if "ospf6" in val:
+ feature.add("ospf6")
+ break
+
+ # Loading empty zebra.conf file to router, to start the zebra deamon
router.load_config(
TopoRouter.RD_ZEBRA, "{}/{}/zebra.conf".format(tgen.logdir, rname)
)
- # Loading empty bgpd.conf file to router, to start the bgp daemon
- router.load_config(
- TopoRouter.RD_BGP, "{}/{}/bgpd.conf".format(tgen.logdir, rname)
- )
+ # Loading empty bgpd.conf file to router, to start the bgp deamon
+ if "bgp" in feature:
+ router.load_config(
+ TopoRouter.RD_BGP, "{}/{}/bgpd.conf".format(tgen.logdir, rname)
+ )
- if daemon and "ospfd" in daemon:
- # Loading empty ospf.conf file to router, to start the bgp daemon
+ # Loading empty pimd.conf file to router, to start the pim deamon
+ if "pim" in feature:
router.load_config(
- TopoRouter.RD_OSPF, "{}/{}/ospfd.conf".format(tgen.logdir, rname)
+ TopoRouter.RD_PIM, "{}/{}/pimd.conf".format(tgen.logdir, rname)
)
- if daemon and "ospf6d" in daemon:
- # Loading empty ospf.conf file to router, to start the bgp daemon
+ # Loading empty pimd.conf file to router, to start the pim deamon
+ if "pim6" in feature:
router.load_config(
- TopoRouter.RD_OSPF6, "{}/{}/ospf6d.conf".format(tgen.logdir, rname)
+ TopoRouter.RD_PIM6, "{}/{}/pim6d.conf".format(tgen.logdir, rname)
)
- if daemon and "pimd" in daemon:
- # Loading empty pimd.conf file to router, to start the pim deamon
+ if "ospf" in feature:
+ # Loading empty ospf.conf file to router, to start the ospf deamon
router.load_config(
- TopoRouter.RD_PIM, "{}/{}/pimd.conf".format(tgen.logdir, rname)
+ TopoRouter.RD_OSPF, "{}/{}/ospfd.conf".format(tgen.logdir, rname)
)
- if daemon and "pim6d" in daemon:
- # Loading empty pimd.conf file to router, to start the pim6d deamon
+ if "ospf6" in feature:
+ # Loading empty ospf.conf file to router, to start the ospf deamon
router.load_config(
- TopoRouter.RD_PIM6, "{}/{}/pim6d.conf".format(tgen.logdir, rname)
+ TopoRouter.RD_OSPF6, "{}/{}/ospf6d.conf".format(tgen.logdir, rname)
)
# Starting routers
diff --git a/tests/topotests/lib/snmptest.py b/tests/topotests/lib/snmptest.py
index fe5ff28979..d695443906 100644
--- a/tests/topotests/lib/snmptest.py
+++ b/tests/topotests/lib/snmptest.py
@@ -36,11 +36,12 @@ from lib.topolog import logger
class SnmpTester(object):
"A helper class for testing SNMP"
- def __init__(self, router, iface, community, version):
+ def __init__(self, router, iface, community, version, options=""):
self.community = community
self.version = version
self.router = router
self.iface = iface
+ self.options = options
logger.info(
"created SNMP tester: SNMPv{0} community:{1}".format(
self.version, self.community
@@ -52,7 +53,9 @@ class SnmpTester(object):
Helper function to build a string with SNMP
configuration for commands.
"""
- return "-v {0} -c {1} {2}".format(self.version, self.community, self.iface)
+ return "-v {0} -c {1} {2} {3}".format(
+ self.version, self.community, self.options, self.iface
+ )
@staticmethod
def _get_snmp_value(snmp_output):
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 5a3f586f82..61cf16944f 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -355,6 +355,16 @@ def run_and_expect(func, what, count=20, wait=3):
else:
func_name = func.__name__
+ # Just a safety-check to avoid running topotests with very
+ # small wait/count arguments.
+ 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
+ )
+
logger.info(
"'{}' polling started (interval {} secs, maximum {} tries)".format(
func_name, wait, count
@@ -402,6 +412,16 @@ def run_and_expect_type(func, etype, count=20, wait=3, avalue=None):
else:
func_name = func.__name__
+ # Just a safety-check to avoid running topotests with very
+ # small wait/count arguments.
+ 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
+ )
+
logger.info(
"'{}' polling started (interval {} secs, maximum wait {} secs)".format(
func_name, wait, int(wait * count)
diff --git a/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py b/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py
index dd8818e92c..285f0dcebc 100755
--- a/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py
+++ b/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py
@@ -86,7 +86,6 @@ from lib.common_config import (
socat_send_mld_join,
socat_send_pim6_traffic,
kill_socat,
- topo_daemons,
)
from lib.pim import (
create_pim_config,
@@ -162,12 +161,9 @@ def setup_module(mod):
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, TOPO)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
@@ -284,8 +280,9 @@ def test_pim6_add_delete_static_RP_p0(request):
shutdown_bringup_interface(tgen, "r1", intf, ifaceaction=False)
step("Enable PIM6 between r1 and r2")
- step("Enable MLD on r1 interface and send MLD " "join {} to r1".\
- format(GROUP_RANGE_1))
+ step(
+ "Enable MLD on r1 interface and send MLD " "join {} to r1".format(GROUP_RANGE_1)
+ )
step("Configure r2 loopback interface as RP")
input_dict = {
"r2": {
@@ -488,8 +485,11 @@ def test_pim6_SPT_RPT_path_same_p1(request):
shutdown_bringup_interface(tgen, "r3", intf, ifaceaction=False)
step("Enable the PIM6 on all the interfaces of r1, r2, r3 and r4 routers")
- step("Configure RP on r2 (loopback interface) for the group range {}".\
- format(GROUP_ADDRESS_1))
+ step(
+ "Configure RP on r2 (loopback interface) for the group range {}".format(
+ GROUP_ADDRESS_1
+ )
+ )
input_dict = {
"r2": {
"pim6": {
@@ -507,7 +507,9 @@ def test_pim6_SPT_RPT_path_same_p1(request):
result = create_pim_config(tgen, TOPO, input_dict)
assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
- step("Enable MLD on r1 interface and send MLD join {} to R1".format(GROUP_ADDRESS_1))
+ step(
+ "Enable MLD on r1 interface and send MLD join {} to R1".format(GROUP_ADDRESS_1)
+ )
intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
result = socat_send_mld_join(
@@ -1088,8 +1090,11 @@ def test_pim6_send_join_on_higher_preffered_rp_p1(request):
step("Enable MLD on r1 interface")
step("Enable the PIM66 on all the interfaces of r1, r2, r3 and r4 routers")
- step("Configure RP on r2 (loopback interface) for the group range {}".\
- format(GROUP_RANGE_4))
+ step(
+ "Configure RP on r2 (loopback interface) for the group range {}".format(
+ GROUP_RANGE_4
+ )
+ )
input_dict = {
"r2": {
"pim6": {
@@ -1259,9 +1264,9 @@ def test_pim6_send_join_on_higher_preffered_rp_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: rp-info is present for group {} \n Error: {}".format(tc_name,
- GROUP_RANGE_4,
- result)
+ "r1: rp-info is present for group {} \n Error: {}".format(
+ tc_name, GROUP_RANGE_4, result
+ )
)
step(
diff --git a/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py b/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py
index f366708ece..6113635783 100755
--- a/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py
+++ b/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py
@@ -75,7 +75,6 @@ from lib.common_config import (
socat_send_mld_join,
socat_send_pim6_traffic,
kill_socat,
- topo_daemons,
)
from lib.pim import (
create_pim_config,
@@ -165,12 +164,9 @@ def setup_module(mod):
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, TOPO)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
@@ -251,6 +247,7 @@ def verify_state_incremented(state_before, state_after):
#
#####################################################
+
def test_pim6_multiple_groups_same_RP_address_p2(request):
"""
Configure multiple groups (10 grps) with same RP address
diff --git a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py
index bcf8e5b5f3..83ed8a6360 100644
--- a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py
+++ b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py
@@ -83,7 +83,6 @@ from lib.common_config import (
apply_raw_config,
run_frr_cmd,
required_linux_kernel_version,
- topo_daemons,
verify_rib,
)
@@ -168,12 +167,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
diff --git a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py
index 8a4ef1d9c7..3da311a08f 100644
--- a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py
+++ b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py
@@ -67,7 +67,6 @@ from lib.common_config import (
reset_config_on_routers,
run_frr_cmd,
required_linux_kernel_version,
- topo_daemons,
verify_rib,
)
@@ -148,12 +147,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
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 d0422e2f72..7034696a8c 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
@@ -166,12 +166,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, tgen.json_topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
@@ -919,7 +916,9 @@ def test_configuring_igmp_local_join_on_reciever_dr_non_dr_nodes_p1(request):
)
for dut, intf in zip(["r1", "r2"], [intf_r1_s1, intf_r2_s1]):
- result = verify_igmp_groups(tgen, dut, intf, IGMP_JOIN_RANGE_3, expected=False)
+ result = verify_igmp_groups(
+ tgen, dut, intf, IGMP_JOIN_RANGE_3, expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"IGMP groups are still present \n Error: {}".format(tc_name, result)
diff --git a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_static_routes_topo1.py b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_static_routes_topo1.py
index 4d17da5f61..7c6928f661 100755
--- a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_static_routes_topo1.py
+++ b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_static_routes_topo1.py
@@ -180,12 +180,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, tgen.json_topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
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 a5d2730373..181151649f 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
@@ -185,12 +185,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, tgen.json_topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
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 b46885c8a5..eb841d6504 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
@@ -175,12 +175,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, tgen.json_topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
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 9228960776..2775464a54 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
@@ -172,12 +172,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
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 b71c2d65eb..721b30140b 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
@@ -186,12 +186,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
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 e7551094ee..d209e42a81 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
@@ -151,12 +151,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
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 2a9fe32b08..e5182fbecf 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
@@ -223,12 +223,9 @@ def setup_module(mod):
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, TOPO)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
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 35303c3f2c..dbeaa9b8f9 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
@@ -128,7 +128,6 @@ from lib.common_config import (
kill_router_daemons,
start_router_daemons,
create_static_routes,
- topo_daemons,
)
from lib.pim import (
create_pim_config,
@@ -223,12 +222,9 @@ def setup_module(mod):
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, TOPO)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
@@ -1417,8 +1413,6 @@ def test_clear_pim_configuration_p1(request):
write_test_footer(tc_name)
-
-
if __name__ == "__main__":
ARGS = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(ARGS))
diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py
index 991d7d5fb6..ef638bc964 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
@@ -128,7 +128,6 @@ from lib.common_config import (
kill_router_daemons,
start_router_daemons,
create_static_routes,
- topo_daemons,
)
from lib.pim import (
create_pim_config,
@@ -223,12 +222,9 @@ def setup_module(mod):
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, TOPO)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
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 8a505a86b5..a750c7fdba 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
@@ -64,7 +64,6 @@ from lib.common_config import (
stop_router,
create_static_routes,
required_linux_kernel_version,
- topo_daemons,
)
from lib.bgp import create_router_bgp
from lib.pim import (
@@ -148,12 +147,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, tgen.json_topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Don"t run this test if we have any failure.
if tgen.routers_have_failure():
@@ -349,8 +345,9 @@ def configure_static_routes_for_rp_reachability(tgen, topo):
}
result = create_static_routes(tgen, static_routes)
- assert result is True, "API {} : Failed Error: {}".\
- format(sys._getframe().f_code.co_name, result)
+ assert result is True, "API {} : Failed Error: {}".format(
+ sys._getframe().f_code.co_name, result
+ )
def verify_state_incremented(state_before, state_after):
@@ -1666,9 +1663,10 @@ def test_mroutes_updated_correctly_after_source_interface_shut_noshut_p1(request
data["oil"],
expected=False,
)
- assert result is not True, (
- "Testcase {} : Failed "
- "Mroute IIF and OIF are same \n Error: {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed " "Mroute IIF and OIF are same \n Error: {}".format(
+ tc_name, result
)
step("Shut and No shut source interface multiple time")
@@ -2339,9 +2337,10 @@ def test_mroutes_updated_after_sending_IGMP_prune_and_join_p1(request):
data["oil"],
expected=False,
)
- assert result is not True, (
- "Testcase {} : Failed "
- " mroute are still present \n Error: {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed " " mroute are still present \n Error: {}".format(
+ tc_name, result
)
for data in input_dict_sg:
@@ -2354,9 +2353,10 @@ def test_mroutes_updated_after_sending_IGMP_prune_and_join_p1(request):
data["oil"],
expected=False,
)
- assert result is not True, (
- "Testcase {} : Failed "
- " mroute are still present \n Error: {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed " " mroute are still present \n Error: {}".format(
+ tc_name, result
)
step(
@@ -2795,10 +2795,11 @@ def test_mroutes_updated_after_changing_rp_config_p1(request):
intf_traffic = topo["routers"]["r4"]["links"]["r3-link1"]["interface"]
state_dict = {"r4": {intf_traffic: ["registerStopRx"]}}
state_before = verify_pim_interface_traffic(tgen, state_dict)
- assert isinstance(state_before, dict), \
- ("Testcase{} : Failed \n state_before is not dictionary \n "
- "Error: {}".\
- format(tc_name, result))
+ assert isinstance(
+ state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
step("Change the RP to R3 loopback for same group range (225.1.1.1-5)")
@@ -2888,10 +2889,11 @@ def test_mroutes_updated_after_changing_rp_config_p1(request):
step("Verify pim interface traffic after changing RP")
state_after = verify_pim_interface_traffic(tgen, state_dict)
- assert isinstance(state_before, dict), \
- ("Testcase{} : Failed \n state_before is not dictionary \n "
- "Error: {}".\
- format(tc_name, result))
+ assert isinstance(
+ state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
result = verify_state_incremented(state_before, state_after)
assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
@@ -3285,9 +3287,10 @@ def test_mroutes_after_restart_frr_services_p2(request):
data["oil"],
expected=False,
)
- assert result is not True, (
- "Testcase {}: Failed "
- "mroutes are still present \n Error: {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {}: Failed " "mroutes are still present \n Error: {}".format(
+ tc_name, result
)
step("Stop FRR on R4 node")
@@ -3310,9 +3313,10 @@ def test_mroutes_after_restart_frr_services_p2(request):
data["oil"],
expected=False,
)
- assert result is not True, (
- "Testcase {} : Failed "
- " Mroutes are still present \n Error: {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed " " Mroutes are still present \n Error: {}".format(
+ tc_name, result
)
step("Start FRR on R4 node")
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 e59333ebd2..1876dabed7 100755
--- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py
+++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py
@@ -224,7 +224,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
if restarting != None:
tries = 40
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname, "show ipv6 route ospf json", "show_ipv6_route.json", tries
)
@@ -246,7 +246,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
if initial_convergence == True or restarting == rname:
tries = 240
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname,
"show ipv6 ospf database json",
diff --git a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py
index d17aeda3ea..f16e8f396e 100644
--- a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py
+++ b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py
@@ -243,7 +243,7 @@ def test_ospf6_default_route():
"show ipv6 route json",
{route: [{"metric": metric}]},
)
- _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = '"{}" convergence failure'.format(router)
assert result is None, assertmsg
diff --git a/tests/topotests/ospf_basic_functionality/ospf_rte_calc.json b/tests/topotests/ospf_basic_functionality/ospf_rte_calc.json
index 9062a09091..1fe076ea15 100644
--- a/tests/topotests/ospf_basic_functionality/ospf_rte_calc.json
+++ b/tests/topotests/ospf_basic_functionality/ospf_rte_calc.json
@@ -1,5 +1,5 @@
{
-
+ "feature": ["bgp"],
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
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 f42bc47d46..5b163d28e4 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
@@ -53,7 +53,6 @@ from lib.common_config import (
start_router_daemons,
create_route_maps,
shutdown_bringup_interface,
- topo_daemons,
create_prefix_lists,
create_route_maps,
create_interfaces_cfg,
@@ -142,12 +141,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
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 2c9959c499..b890f9a8aa 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
@@ -46,7 +46,6 @@ from lib.common_config import (
verify_rib,
create_static_routes,
step,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -134,12 +133,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
index 252481799c..8a94bf1178 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
@@ -47,7 +47,6 @@ from lib.common_config import (
reset_config_on_routers,
step,
shutdown_bringup_interface,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -102,12 +101,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py
index a0ab828717..27c6954d2b 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py
@@ -43,7 +43,6 @@ from lib.common_config import (
write_test_footer,
reset_config_on_routers,
step,
- topo_daemons,
verify_rib,
stop_router,
start_router,
@@ -113,12 +112,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
index 2b479db3c2..d6bcbd0fcc 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
@@ -47,7 +47,6 @@ from lib.common_config import (
create_static_routes,
step,
shutdown_bringup_interface,
- topo_daemons,
)
from lib.topolog import logger
@@ -116,12 +115,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
index 00feefc4d0..049c2b83f0 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
@@ -45,7 +45,6 @@ from lib.common_config import (
verify_rib,
create_static_routes,
step,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -117,12 +116,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
index 497a8b900b..80ca0c8b04 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
@@ -49,7 +49,6 @@ from lib.common_config import (
shutdown_bringup_interface,
stop_router,
start_router,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -116,12 +115,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
index 1917bd42f5..7391379bb9 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
@@ -39,7 +39,6 @@ from lib.common_config import (
verify_rib,
create_static_routes,
step,
- topo_daemons,
)
from lib.topogen import Topogen, get_topogen
import os
@@ -114,12 +113,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py
index e131fba0c3..9e48f8e39b 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py
@@ -46,7 +46,6 @@ from lib.common_config import (
reset_config_on_routers,
step,
create_interfaces_cfg,
- topo_daemons,
retry,
run_frr_cmd,
)
@@ -105,12 +104,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
index 22d768d9f6..c41985e0fe 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
@@ -48,7 +48,6 @@ from lib.common_config import (
step,
create_route_maps,
verify_prefix_lists,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -129,12 +128,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
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 8bd81a3854..b9da460909 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
@@ -48,7 +48,6 @@ from lib.common_config import (
create_static_routes,
step,
shutdown_bringup_interface,
- topo_daemons,
)
from lib.bgp import verify_bgp_convergence, create_router_bgp
from lib.topolog import logger
@@ -125,12 +124,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
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 21a7d83845..37f558b99c 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
@@ -48,7 +48,6 @@ from lib.common_config import (
reset_config_on_routers,
step,
create_interfaces_cfg,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -110,12 +109,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
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 07d4ca01a9..ade55321f9 100644
--- a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py
+++ b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py
@@ -17,7 +17,6 @@ from lib.common_config import (
write_test_footer,
reset_config_on_routers,
step,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -48,12 +47,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_gr_helper/ospf_gr_helper.json b/tests/topotests/ospf_gr_helper/ospf_gr_helper.json
index efd339ef88..b9ca02289d 100644
--- a/tests/topotests/ospf_gr_helper/ospf_gr_helper.json
+++ b/tests/topotests/ospf_gr_helper/ospf_gr_helper.json
@@ -17,7 +17,7 @@
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
- "dead_interval": 40,
+ "dead_interval": 4,
"priority": 98
}
},
@@ -26,7 +26,7 @@
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
- "dead_interval": 40,
+ "dead_interval": 4,
"priority": 99
}
},
@@ -35,7 +35,7 @@
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
- "dead_interval": 40,
+ "dead_interval": 4,
"priority": 0
}
},
@@ -44,7 +44,7 @@
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
- "dead_interval": 40,
+ "dead_interval": 4,
"priority": 0
}
}
@@ -116,4 +116,4 @@
}
}
}
-} \ No newline at end of file
+}
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 58d37a368c..a7ab29d791 100644
--- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py
+++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py
@@ -43,7 +43,6 @@ from lib.common_config import (
reset_config_on_routers,
step,
create_interfaces_cfg,
- topo_daemons,
scapy_send_raw_packet,
)
@@ -121,12 +120,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py
index 85646a8fab..b78fd235d7 100644
--- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py
+++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py
@@ -43,7 +43,6 @@ from lib.common_config import (
reset_config_on_routers,
step,
create_interfaces_cfg,
- topo_daemons,
scapy_send_raw_packet,
)
@@ -121,12 +120,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
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 ec97c254d1..f4e366031f 100644
--- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py
+++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py
@@ -43,7 +43,6 @@ from lib.common_config import (
reset_config_on_routers,
step,
create_interfaces_cfg,
- topo_daemons,
scapy_send_raw_packet,
)
@@ -121,12 +120,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
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 debf7ad766..429b7dc96d 100755
--- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py
+++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py
@@ -233,7 +233,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
if restarting != None:
tries = 60
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname, "show ip route ospf json", "show_ip_route.json", tries
)
@@ -252,7 +252,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
if initial_convergence == True or restarting == rname:
tries = 240
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname, "show ip ospf database json", "show_ip_ospf_database.json", tries
)
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 86c089ab3b..6bafbbb556 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
@@ -5,5 +5,5 @@ B>* 10.0.3.0/24 [20/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
-B>* 10.0.30.0/24 [20/0] is directly connected, r1-eth2 (vrf neno), 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/r2/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
index 9681d8a04e..3ed6b1b3a1 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
@@ -7,4 +7,4 @@ B>* 10.0.4.0/24 [20/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
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, r2-eth2 (vrf ray), 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 ce9903ae71..4ad8441d85 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,9 +1,9 @@
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.2.0/24 [20/0] is directly connected, r2-eth0 (vrf default) inactive, weight 1, XX:XX:XX
+B 10.0.2.0/24 [20/0] is directly connected, lo (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
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.20.0/24 [20/0] is directly connected, lo (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
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
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 59ba8236c7..1a92c597be 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
@@ -55,7 +55,6 @@ from lib.common_config import (
shutdown_bringup_interface,
create_prefix_lists,
create_route_maps,
- topo_daemons,
create_interfaces_cfg,
)
from lib.topolog import logger
@@ -158,12 +157,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py
index d32a05a88e..0fe0fd95b0 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py
@@ -50,7 +50,6 @@ from lib.common_config import (
reset_config_on_routers,
step,
shutdown_bringup_interface,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_topo_from_json, build_config_from_json
@@ -94,6 +93,7 @@ TESTCASES =
"""
+
def setup_module(mod):
"""
Sets up the pytest environment
@@ -112,12 +112,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
@@ -157,6 +154,7 @@ def teardown_module(mod):
# Test cases start here.
# ##################################
+
def test_ospf6_auth_trailer_tc1_md5(request):
"""
OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer
@@ -233,9 +231,7 @@ def test_ospf6_auth_trailer_tc1_md5(request):
tc_name, ospf6_covergence
)
- step(
- "Disable authentication on R2 "
- )
+ step("Disable authentication on R2 ")
r2_ospf6_auth = {
"r2": {
@@ -245,7 +241,7 @@ def test_ospf6_auth_trailer_tc1_md5(request):
"hash-algo": "md5",
"key": "ospf6",
"key-id": "10",
- "del_action": True
+ "del_action": True,
}
}
}
@@ -401,9 +397,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request):
tc_name, ospf6_covergence
)
- step(
- "Disable authentication on R2 "
- )
+ step("Disable authentication on R2 ")
r2_ospf6_auth = {
"r2": {
@@ -413,7 +407,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request):
"hash-algo": "hmac-sha-256",
"key": "ospf6",
"key-id": "10",
- "del_action": True
+ "del_action": True,
}
}
}
@@ -492,6 +486,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request):
write_test_footer(tc_name)
+
def test_ospf6_auth_trailer_tc3_keychain_md5(request):
"""
OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer
@@ -583,21 +578,10 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request):
tc_name, ospf6_covergence
)
- step(
- "Disable authentication on R2 "
- )
+ step("Disable authentication on R2 ")
r2_ospf6_auth = {
- "r2": {
- "links": {
- "r1": {
- "ospf6": {
- "keychain": "auth",
- "del_action": True
- }
- }
- }
- }
+ "r2": {"links": {"r1": {"ospf6": {"keychain": "auth", "del_action": True}}}}
}
result = config_ospf6_interface(tgen, topo, r2_ospf6_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
@@ -670,6 +654,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request):
write_test_footer(tc_name)
+
def test_ospf6_auth_trailer_tc4_keychain_sha256(request):
"""
OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer
@@ -761,21 +746,10 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request):
tc_name, ospf6_covergence
)
- step(
- "Disable authentication on R2 "
- )
+ step("Disable authentication on R2 ")
r2_ospf6_auth = {
- "r2": {
- "links": {
- "r1": {
- "ospf6": {
- "keychain": "auth",
- "del_action": True
- }
- }
- }
- }
+ "r2": {"links": {"r1": {"ospf6": {"keychain": "auth", "del_action": True}}}}
}
result = config_ospf6_interface(tgen, topo, r2_ospf6_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
@@ -848,6 +822,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request):
write_test_footer(tc_name)
+
def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request):
"""
OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer
@@ -963,6 +938,7 @@ def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request):
write_test_footer(tc_name)
+
def test_ospf6_auth_trailer_tc6_sha256_mismatch(request):
"""
OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer
@@ -1073,6 +1049,7 @@ def test_ospf6_auth_trailer_tc6_sha256_mismatch(request):
write_test_footer(tc_name)
+
def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request):
"""
OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer
@@ -1204,6 +1181,7 @@ def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request):
write_test_footer(tc_name)
+
def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request):
"""
OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer
@@ -1335,6 +1313,7 @@ def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request):
write_test_footer(tc_name)
+
def test_ospf6_auth_trailer_tc9_keychain_not_configured(request):
"""
OSPFv3 Neighborship without Authentication Trailer -
@@ -1412,6 +1391,7 @@ def test_ospf6_auth_trailer_tc9_keychain_not_configured(request):
write_test_footer(tc_name)
+
def test_ospf6_auth_trailer_tc10_no_auth_trailer(request):
"""
OSPFv3 Neighborship without Authentication Trailer -
@@ -1441,6 +1421,7 @@ def test_ospf6_auth_trailer_tc10_no_auth_trailer(request):
write_test_footer(tc_name)
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py
index 75be0928ab..6bb88ebca3 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py
@@ -46,7 +46,6 @@ from lib.common_config import (
create_static_routes,
step,
shutdown_bringup_interface,
- topo_daemons,
get_frr_ipv6_linklocal,
)
from lib.topolog import logger
@@ -117,12 +116,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
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 ce880b413b..5cbfb0d6e1 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py
@@ -53,7 +53,6 @@ from lib.common_config import (
create_route_maps,
shutdown_bringup_interface,
create_interfaces_cfg,
- topo_daemons,
get_frr_ipv6_linklocal,
)
from lib.topolog import logger
@@ -130,12 +129,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py
index bdc4c139f7..c0d8d718cc 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py
@@ -7,7 +7,6 @@ from lib.common_config import (
write_test_footer,
reset_config_on_routers,
step,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -62,12 +61,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py
index 7b41c80ce3..4cccd9734f 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py
@@ -57,7 +57,6 @@ from lib.common_config import (
verify_rib,
create_static_routes,
step,
- topo_daemons,
create_route_maps,
shutdown_bringup_interface,
create_interfaces_cfg,
@@ -139,12 +138,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
@@ -406,6 +402,124 @@ def test_ospfv3_nssa_tc26_p0(request):
write_test_footer(tc_name)
+def test_ospfv3_learning_tc15_p0(request):
+ """Verify OSPF can learn different types of LSA and processes them.
+
+ OSPF Learning : Edge learning different types of LSAs.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ step("Configure area 1 as NSSA Area")
+
+ reset_config_on_routers(tgen)
+
+ step("Verify that Type 3 summary LSA is originated for the same Area 0")
+ ip = topo["routers"]["r1"]["links"]["r3-link0"]["ipv6"]
+ ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
+
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": ip_net,
+ "no_of_ip": 1,
+ "routeType": "Network",
+ "pathtype": "Inter-Area",
+ }
+ ]
+ }
+ }
+
+ dut = "r0"
+ result = verify_ospf6_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf6"
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][0], "no_of_ip": 5, "next_hop": "Null0"}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Redistribute static route in R2 ospf.")
+ dut = "r2"
+ red_static(dut)
+
+ step("Verify that Type 5 LSA is originated by R2.")
+ dut = "r0"
+ protocol = "ospf6"
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][0], "no_of_ip": 1, "routeType": "Network"}
+ ]
+ }
+ }
+
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_ospf6_neighbor(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change area 1 as non nssa area (on the fly changing area" " type on DUT).")
+
+ for rtr in ["r1", "r2", "r3"]:
+ input_dict = {
+ rtr: {
+ "ospf6": {"area": [{"id": "0.0.0.2", "type": "nssa", "delete": True}]}
+ }
+ }
+ result = create_router_ospf(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that OSPF neighbours are reset after changing area type.")
+ step("Verify that ABR R2 originates type 5 LSA in area 1.")
+ step("Verify that R1 installs type 5 lsa in its database.")
+ step("Verify that route is calculated and installed in R1.")
+
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][0], "no_of_ip": 1, "routeType": "Network"}
+ ]
+ }
+ }
+
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
# As per internal discussion, this script has to be removed as translator
# function is not supported, for more details kindly check this PR 2565570
def ospfv3_nssa_tc27_p0(request):
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py
index 0c9457b39e..ee15a5fe1c 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py
@@ -48,7 +48,6 @@ from lib.common_config import (
step,
create_route_maps,
verify_prefix_lists,
- topo_daemons,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -131,12 +130,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
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 df3a0249ea..e5b20db6de 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py
@@ -46,7 +46,6 @@ from lib.common_config import (
step,
shutdown_bringup_interface,
create_interfaces_cfg,
- topo_daemons,
get_frr_ipv6_linklocal,
check_router_status,
create_static_routes,
@@ -122,12 +121,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
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 d318ec0906..6aee3b815d 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
@@ -48,7 +48,6 @@ from lib.common_config import (
reset_config_on_routers,
step,
create_interfaces_cfg,
- topo_daemons,
create_debug_log_config,
apply_raw_config,
)
@@ -116,12 +115,9 @@ def setup_module(mod):
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, topo)
-
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
- start_topology(tgen, daemons)
+ start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py
index 6cea521aa9..2c1bc52d09 100644
--- a/tests/topotests/pim_basic/test_pim.py
+++ b/tests/topotests/pim_basic/test_pim.py
@@ -225,7 +225,7 @@ def test_pim_igmp_report():
test_func = partial(
topotest.router_json_cmp, r1, "show ip pim upstream json", expected
)
- _, result = topotest.run_and_expect(test_func, None, count=5, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assertmsg = '"{}" JSON output mismatches'.format(r1.name)
assert result is None, assertmsg
finally:
diff --git a/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py b/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py
index 9506c3c6d1..5aa313137f 100644
--- a/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py
+++ b/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py
@@ -175,7 +175,7 @@ def test_pim_reconvergence():
"show ip pim neighbor json",
{interface: {peer: None}},
)
- _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = '"{}" PIM convergence failure'.format(router)
assert result is None, assertmsg
@@ -201,7 +201,7 @@ def test_pim_bfd_profile():
"show bfd peers json",
[settings],
)
- _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = '"{}" BFD convergence failure'.format(router)
assert result is None, assertmsg
diff --git a/tests/topotests/srv6_locator/test_srv6_locator.py b/tests/topotests/srv6_locator/test_srv6_locator.py
index bc5fa409d2..b918da0655 100755
--- a/tests/topotests/srv6_locator/test_srv6_locator.py
+++ b/tests/topotests/srv6_locator/test_srv6_locator.py
@@ -94,12 +94,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=5, wait=0.5)
+ success, 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=5, wait=0.5)
+ success, 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.py b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py
index ecc0856371..4bd0682bde 100755
--- a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py
+++ b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py
@@ -90,12 +90,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=5, wait=0.5)
+ success, 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=5, wait=0.5)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, "Failed"
# FOR DEVELOPER:
@@ -124,7 +124,7 @@ def test_srv6():
srv6
locators
locator loc3
- prefix 2001:db8:3::/48 func-bits 16 block-len 32 node-len 16
+ prefix 2001:db8:3::/48 block-len 32 node-len 16 func-bits 16
"""
)
check_srv6_locator(router, "expected_locators4.json")
diff --git a/tests/topotests/srv6_locator_usid/r1/zebra.conf b/tests/topotests/srv6_locator_usid/r1/zebra.conf
index 78ef1e9d40..190e831ac1 100644
--- a/tests/topotests/srv6_locator_usid/r1/zebra.conf
+++ b/tests/topotests/srv6_locator_usid/r1/zebra.conf
@@ -12,7 +12,7 @@ segment-routing
srv6
locators
locator loc1
- prefix fc00:0:1::/48 func-bits 16 block-len 32 node-len 16
+ prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16
behavior usid
!
!
diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
index 37fd736d2b..4023555524 100755
--- a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
+++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
@@ -54,12 +54,10 @@ def setup_module(mod):
for rname, router in tgen.routers().items():
router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
router.load_config(
- TopoRouter.RD_ZEBRA, os.path.join(
- CWD, "{}/zebra.conf".format(rname))
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
- TopoRouter.RD_SHARP, os.path.join(
- CWD, "{}/sharpd.conf".format(rname))
+ TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
)
tgen.start_router()
@@ -71,18 +69,14 @@ def teardown_module(mod):
def _check_srv6_locator(router, expected_locator_file):
logger.info("checking zebra locator status")
- output = json.loads(
- router.vtysh_cmd("show segment-routing srv6 locator json")
- )
+ output = json.loads(router.vtysh_cmd("show segment-routing srv6 locator json"))
expected = open_json_file("{}/{}".format(CWD, expected_locator_file))
return topotest.json_cmp(output, expected)
def _check_sharpd_chunk(router, expected_chunk_file):
logger.info("checking sharpd locator chunk status")
- output = json.loads(
- router.vtysh_cmd("show sharp segment-routing srv6 json")
- )
+ output = json.loads(router.vtysh_cmd("show sharp segment-routing srv6 json"))
expected = open_json_file("{}/{}".format(CWD, expected_chunk_file))
return topotest.json_cmp(output, expected)
@@ -164,7 +158,7 @@ def test_srv6_usid_locator_create_locator():
srv6
locators
locator loc2
- prefix fc00:0:2::/48 func-bits 16 block-len 32 node-len 16
+ prefix fc00:0:2::/48 block-len 32 node-len 16 func-bits 16
"""
)
check_srv6_locator(router, "expected_locators_4.json")
@@ -181,9 +175,7 @@ def test_srv6_usid_locator_set_behavior_usid():
# If you want to stop some specific line and start interactive shell,
# please use tgen.mininet_cli() to start it.
- logger.info(
- "Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator"
- )
+ logger.info("Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator")
router.vtysh_cmd(
"""
configure terminal
diff --git a/tests/topotests/tc_basic/test_tc_basic.py b/tests/topotests/tc_basic/test_tc_basic.py
new file mode 100755
index 0000000000..e98e11d71d
--- /dev/null
+++ b/tests/topotests/tc_basic/test_tc_basic.py
@@ -0,0 +1,133 @@
+#!/usr/bin/python
+
+#
+# test_tc_basic.py
+#
+# Copyright (c) 2022 by Shichu Yang
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+test_tc_basic.py: Test basic TC filters, classes and qdiscs.
+"""
+import sys
+import os
+import pytest
+import time
+
+# 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/"))
+
+from lib.topogen import Topogen, TopoRouter
+from lib.topolog import logger
+
+pytestmark = [
+ pytest.mark.sharpd
+]
+
+def build_topo(tgen):
+ "Build function"
+
+ r1 = tgen.add_router("r1")
+ r2 = tgen.add_router("r2")
+
+ # Create a p2p connection between r1 and r2
+ tgen.add_link(r1, r2)
+
+ # Create switches with each router connected to it to simulate a empty network.
+ switch = tgen.add_switch("s1")
+ switch.add_link(r1)
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(r2)
+
+# New form of setup/teardown using pytest fixture
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(build_topo, request.module.__name__)
+
+ # ... and here it calls initialization functions.
+ tgen.start_topology()
+
+ # This is a sample of configuration loading.
+ router_list = tgen.routers()
+
+ # For all routers arrange for:
+ # - starting zebra using config file from <rtrname>/zebra.conf
+ # - starting ospfd using an empty config file.
+ for _, router in router_list.items():
+ router.load_config(TopoRouter.RD_ZEBRA)
+ router.load_config(TopoRouter.RD_SHARP)
+
+ # Start and configure the router daemons
+ tgen.start_router()
+
+ # Provide tgen as argument to each test function
+ yield tgen
+
+ # Teardown after last test runs
+ tgen.stop_topology()
+
+
+# Fixture that executes before each test
+@pytest.fixture(autouse=True)
+def skip_on_failure(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of previous test failure")
+
+def fetch_iproute2_tc_info(r, interface):
+ qdisc = r.cmd("tc qdisc show dev %s" % interface)
+ tclass = r.cmd("tc class show dev %s" % interface)
+ tfilter = r.cmd("tc filter show dev %s" % interface)
+ return qdisc, tclass, tfilter
+
+# ===================
+# The tests functions
+# ===================
+
+def test_tc_basic(tgen):
+ "Test installing one pair of filter & class by sharpd"
+
+ r1 = tgen.gears["r1"]
+ intf = "r1-eth0"
+ r1.vtysh_cmd("sharp tc dev %s source 192.168.100.0/24 destination 192.168.101.0/24 ip-protocol tcp src-port 8000 dst-port 8001 rate 20mbit" % intf)
+
+ time.sleep(3)
+
+ qdisc, tclass, tfilter = fetch_iproute2_tc_info(r1, intf)
+
+ logger.info("tc qdisc on %s: %s", intf, qdisc)
+ logger.info("tc class on %s: %s", intf, tclass)
+ logger.info("tc filter on %s: %s", intf, tfilter)
+
+ assert "htb" in qdisc
+ assert "beef:" in qdisc
+
+ assert "20Mbit" in tclass
+
+ assert "tcp" in tfilter
+ assert "dst_ip 192.168.101.0/24" in tfilter
+ assert "src_ip 192.168.100.0/24" in tfilter
+ assert "dst_port 8001" in tfilter
+ assert "src_port 8000" in tfilter
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args)) \ No newline at end of file
diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons
index 8aa08871e3..2427bfff77 100644
--- a/tools/etc/frr/daemons
+++ b/tools/etc/frr/daemons
@@ -91,6 +91,11 @@ pathd_options=" -A 127.0.0.1"
#
#MAX_FDS=1024
+# Uncomment this option if you want to run FRR as a non-root user. Note that
+# you should know what you are doing since most of the daemons need root
+# to work. This could be useful if you want to run FRR in a container
+# for instance.
+# FRR_NO_ROOT="yes"
# For any daemon, you can specify a "wrap" command to start instead of starting
# the daemon directly. This will simply be prepended to the daemon invocation.
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 7c5d91d4dc..bf402e1bef 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -1514,6 +1514,7 @@ def ignore_unconfigurable_lines(lines_to_add, lines_to_del):
[
ctx_keys[0].startswith(x)
for x in [
+ "agentx",
"frr version",
"frr defaults",
"username",
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index 3c16c27c6d..f1db3a73d5 100755
--- a/tools/frrcommon.sh.in
+++ b/tools/frrcommon.sh.in
@@ -43,6 +43,10 @@ RELOAD_SCRIPT="$D_PATH/frr-reload.py"
#
is_user_root () {
+ if [[ ! -z $FRR_NO_ROOT && "${FRR_NO_ROOT}" == "yes" ]]; then
+ return 0
+ fi
+
[ "${EUID:-$(id -u)}" -eq 0 ] || {
log_failure_msg "Only users having EUID=0 can start/stop daemons"
return 1
@@ -262,7 +266,7 @@ all_start() {
}
all_stop() {
- local pids reversed need_zebra
+ local pids reversed
daemon_list enabled_daemons disabled_daemons
[ "$1" = "--reallyall" ] && enabled_daemons="$enabled_daemons $disabled_daemons"
@@ -272,23 +276,13 @@ all_stop() {
reversed="$dmninst $reversed"
done
- # Stop zebra last, after trying to stop the other daemons
for dmninst in $reversed; do
- if [ "$dmninst" = "zebra" ]; then
- need_zebra="yes"
- continue
- fi
-
daemon_stop "$dmninst" "$1" &
pids="$pids $!"
done
for pid in $pids; do
wait $pid
done
-
- if [ -n "$need_zebra" ]; then
- daemon_stop "zebra"
- fi
}
all_status() {
diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c
index 4a0356411f..e1bb40c28d 100644
--- a/vrrpd/vrrp.c
+++ b/vrrpd/vrrp.c
@@ -647,6 +647,8 @@ struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid,
vr->priority = vd.priority;
vr->preempt_mode = vd.preempt_mode;
vr->accept_mode = vd.accept_mode;
+ vr->checksum_with_ipv4_pseudoheader =
+ vd.checksum_with_ipv4_pseudoheader;
vr->shutdown = vd.shutdown;
vr->v4 = vrrp_router_create(vr, AF_INET);
@@ -789,7 +791,8 @@ static void vrrp_send_advertisement(struct vrrp_router *r)
pktsz = vrrp_pkt_adver_build(&pkt, &r->src, r->vr->version, r->vr->vrid,
r->priority, r->vr->advertisement_interval,
- r->addrs->count, (struct ipaddr **)&addrs);
+ r->addrs->count, (struct ipaddr **)&addrs,
+ r->vr->checksum_with_ipv4_pseudoheader);
if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt, DEBUG_MODE_ALL))
zlog_hexdump(pkt, (size_t)pktsz);
@@ -1027,8 +1030,10 @@ static void vrrp_read(struct thread *thread)
zlog_hexdump(r->ibuf, nbytes);
}
- pktsize = vrrp_pkt_parse_datagram(r->family, r->vr->version, &m, nbytes,
- &src, &pkt, errbuf, sizeof(errbuf));
+ pktsize = vrrp_pkt_parse_datagram(
+ r->family, r->vr->version,
+ r->vr->checksum_with_ipv4_pseudoheader, &m, nbytes, &src, &pkt,
+ errbuf, sizeof(errbuf));
if (pktsize < 0)
DEBUGD(&vrrp_dbg_pkt,
@@ -2347,6 +2352,12 @@ int vrrp_config_write_global(struct vty *vty)
vty_out(vty, "%svrrp default accept\n",
!vd.accept_mode ? "no " : "");
+ if (vd.checksum_with_ipv4_pseudoheader !=
+ VRRP_DEFAULT_CHECKSUM_WITH_IPV4_PSEUDOHEADER &&
+ ++writes)
+ vty_out(vty, "%svrrp default checksum-with-ipv4-pseudoheader\n",
+ !vd.checksum_with_ipv4_pseudoheader ? "no " : "");
+
if (vd.shutdown != VRRP_DEFAULT_SHUTDOWN && ++writes)
vty_out(vty, "%svrrp default shutdown\n",
!vd.shutdown ? "no " : "");
@@ -2387,6 +2398,8 @@ void vrrp_init(void)
vd.preempt_mode = yang_get_default_bool("%s/preempt", VRRP_XPATH_FULL);
vd.accept_mode =
yang_get_default_bool("%s/accept-mode", VRRP_XPATH_FULL);
+ vd.checksum_with_ipv4_pseudoheader = yang_get_default_bool(
+ "%s/checksum-with-ipv4-pseudoheader", VRRP_XPATH_FULL);
vd.shutdown = VRRP_DEFAULT_SHUTDOWN;
vrrp_autoconfig_version = 3;
diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h
index c181c2159b..b3141ef318 100644
--- a/vrrpd/vrrp.h
+++ b/vrrpd/vrrp.h
@@ -53,6 +53,7 @@
#define VRRP_DEFAULT_ADVINT 100
#define VRRP_DEFAULT_PREEMPT true
#define VRRP_DEFAULT_ACCEPT true
+#define VRRP_DEFAULT_CHECKSUM_WITH_IPV4_PSEUDOHEADER true
#define VRRP_DEFAULT_SHUTDOWN false
/* User compatibility constant */
@@ -70,6 +71,7 @@ struct vrrp_defaults {
uint16_t advertisement_interval;
bool preempt_mode;
bool accept_mode;
+ bool checksum_with_ipv4_pseudoheader;
bool shutdown;
};
@@ -266,6 +268,14 @@ struct vrrp_vrouter {
*/
bool accept_mode;
+ /*
+ * Indicates whether this router computes and accepts VRRPv3 checksums
+ * without pseudoheader, for device interoperability.
+ *
+ * This option should only affect IPv4 virtual routers.
+ */
+ bool checksum_with_ipv4_pseudoheader;
+
struct vrrp_router *v4;
struct vrrp_router *v6;
};
diff --git a/vrrpd/vrrp_northbound.c b/vrrpd/vrrp_northbound.c
index d25dc0a197..76d0ad3b1b 100644
--- a/vrrpd/vrrp_northbound.c
+++ b/vrrpd/vrrp_northbound.c
@@ -602,6 +602,26 @@ lib_interface_vrrp_vrrp_group_shutdown_modify(struct nb_cb_modify_args *args)
return NB_OK;
}
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with-
+ * ipv4-pseudoheader
+ */
+static int lib_interface_vrrp_vrrp_group_checksum_with_ipv4_pseudoheader_modify(
+ struct nb_cb_modify_args *args)
+{
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct vrrp_vrouter *vr;
+ bool checksum_with_ipv4_ph;
+
+ vr = nb_running_get_entry(args->dnode, NULL, true);
+ checksum_with_ipv4_ph = yang_dnode_get_bool(args->dnode, NULL);
+ vr->checksum_with_ipv4_pseudoheader = checksum_with_ipv4_ph;
+
+ return NB_OK;
+}
+
/* clang-format off */
const struct frr_yang_module_info frr_vrrpd_info = {
.name = "frr-vrrpd",
@@ -644,6 +664,13 @@ const struct frr_yang_module_info frr_vrrpd_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with-ipv4-pseudoheader",
+ .cbs = {
+ .modify = lib_interface_vrrp_vrrp_group_checksum_with_ipv4_pseudoheader_modify,
+ .cli_show = cli_show_checksum_with_ipv4_pseudoheader,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval",
.cbs = {
.modify = lib_interface_vrrp_vrrp_group_advertisement_interval_modify,
diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c
index 991c030196..96a19da88c 100644
--- a/vrrpd/vrrp_packet.c
+++ b/vrrpd/vrrp_packet.c
@@ -71,7 +71,7 @@ static const char *const vrrp_packet_names[16] = {
* VRRP checksum in network byte order.
*/
static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize,
- struct ipaddr *src)
+ struct ipaddr *src, bool ipv4_ph)
{
uint16_t chksum;
bool v6 = (src->ipa_type == IPADDR_V6);
@@ -89,13 +89,16 @@ static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize,
ph.next_hdr = IPPROTO_VRRP;
chksum = in_cksum_with_ph6(&ph, pkt, pktsize);
} else if (!v6 && ((pkt->hdr.vertype >> 4) == 3)) {
- struct ipv4_ph ph = {};
-
- ph.src = src->ipaddr_v4;
- inet_pton(AF_INET, VRRP_MCASTV4_GROUP_STR, &ph.dst);
- ph.proto = IPPROTO_VRRP;
- ph.len = htons(pktsize);
- chksum = in_cksum_with_ph4(&ph, pkt, pktsize);
+ if (ipv4_ph) {
+ struct ipv4_ph ph = {};
+
+ ph.src = src->ipaddr_v4;
+ inet_pton(AF_INET, VRRP_MCASTV4_GROUP_STR, &ph.dst);
+ ph.proto = IPPROTO_VRRP;
+ ph.len = htons(pktsize);
+ chksum = in_cksum_with_ph4(&ph, pkt, pktsize);
+ } else
+ chksum = in_cksum(pkt, pktsize);
} else if (!v6 && ((pkt->hdr.vertype >> 4) == 2)) {
chksum = in_cksum(pkt, pktsize);
} else {
@@ -110,7 +113,7 @@ static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize,
ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src,
uint8_t version, uint8_t vrid, uint8_t prio,
uint16_t max_adver_int, uint8_t numip,
- struct ipaddr **ips)
+ struct ipaddr **ips, bool ipv4_ph)
{
bool v6 = false;
size_t addrsz = 0;
@@ -147,7 +150,7 @@ ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src,
aptr += addrsz;
}
- (*pkt)->hdr.chksum = vrrp_pkt_checksum(*pkt, pktsize, src);
+ (*pkt)->hdr.chksum = vrrp_pkt_checksum(*pkt, pktsize, src, ipv4_ph);
return pktsize;
}
@@ -188,10 +191,10 @@ size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt)
return rs;
}
-ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m,
- size_t read, struct ipaddr *src,
- struct vrrp_pkt **pkt, char *errmsg,
- size_t errmsg_len)
+ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph,
+ struct msghdr *m, size_t read,
+ struct ipaddr *src, struct vrrp_pkt **pkt,
+ char *errmsg, size_t errmsg_len)
{
/* Source (MAC & IP), Dest (MAC & IP) TTL validation done by kernel */
size_t addrsz = (family == AF_INET) ? sizeof(struct in_addr)
@@ -289,7 +292,7 @@ ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m,
VRRP_PKT_VCHECK(pktver == version, "Bad version %u", pktver);
/* Checksum check */
- uint16_t chksum = vrrp_pkt_checksum(*pkt, pktsize, src);
+ uint16_t chksum = vrrp_pkt_checksum(*pkt, pktsize, src, ipv4_ph);
VRRP_PKT_VCHECK((*pkt)->hdr.chksum == chksum,
"Bad VRRP checksum %hx; should be %hx",
diff --git a/vrrpd/vrrp_packet.h b/vrrpd/vrrp_packet.h
index 082935f080..eec709593e 100644
--- a/vrrpd/vrrp_packet.h
+++ b/vrrpd/vrrp_packet.h
@@ -131,7 +131,7 @@ struct vrrp_pkt {
ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src,
uint8_t version, uint8_t vrid, uint8_t prio,
uint16_t max_adver_int, uint8_t numip,
- struct ipaddr **ips);
+ struct ipaddr **ips, bool ipv4_ph);
/* free memory allocated by vrrp_pkt_adver_build's pkt arg */
void vrrp_pkt_free(struct vrrp_pkt *pkt);
@@ -195,9 +195,9 @@ size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt);
* Returns:
* Size of VRRP packet, or -1 upon error
*/
-ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m,
- size_t read, struct ipaddr *src,
- struct vrrp_pkt **pkt, char *errmsg,
- size_t errmsg_len);
+ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph,
+ struct msghdr *m, size_t read,
+ struct ipaddr *src, struct vrrp_pkt **pkt,
+ char *errmsg, size_t errmsg_len);
#endif /* __VRRP_PACKET_H__ */
diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c
index f822b89854..1e1edb8212 100644
--- a/vrrpd/vrrp_vty.c
+++ b/vrrpd/vrrp_vty.c
@@ -281,6 +281,35 @@ void cli_show_preempt(struct vty *vty, const struct lyd_node *dnode,
vty_out(vty, " %svrrp %s preempt\n", pre ? "" : "no ", vrid);
}
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with-
+ * ipv4-pseudoheader
+ */
+DEFPY_YANG(vrrp_checksum_with_ipv4_pseudoheader,
+ vrrp_checksum_with_ipv4_pseudoheader_cmd,
+ "[no] vrrp (1-255)$vrid checksum-with-ipv4-pseudoheader",
+ NO_STR
+ VRRP_STR
+ VRRP_VRID_STR
+ "Checksum mode in VRRPv3\n")
+{
+ nb_cli_enqueue_change(vty, "./checksum-with-ipv4-pseudoheader",
+ NB_OP_MODIFY, no ? "false" : "true");
+
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
+
+void cli_show_checksum_with_ipv4_pseudoheader(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
+ const bool pre = yang_dnode_get_bool(dnode, NULL);
+
+ vty_out(vty, " %svrrp %s checksum-with-ipv4-pseudoheader\n",
+ pre ? "" : "no ", vrid);
+}
+
/* XXX: yang conversion */
DEFPY_YANG(vrrp_autoconfigure,
vrrp_autoconfigure_cmd,
@@ -304,7 +333,7 @@ DEFPY_YANG(vrrp_autoconfigure,
/* XXX: yang conversion */
DEFPY_YANG(vrrp_default,
vrrp_default_cmd,
- "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|shutdown$s>",
+ "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|checksum-with-ipv4-pseudoheader$ipv4ph|shutdown$s>",
NO_STR
VRRP_STR
"Configure defaults for new VRRP instances\n"
@@ -313,6 +342,7 @@ DEFPY_YANG(vrrp_default,
"Preempt mode\n"
VRRP_PRIORITY_STR
"Priority value\n"
+ "Checksum mode in VRRPv3\n"
"Force VRRP router into administrative shutdown\n")
{
if (adv) {
@@ -329,6 +359,8 @@ DEFPY_YANG(vrrp_default,
vd.preempt_mode = !no;
if (prio)
vd.priority = no ? VRRP_DEFAULT_PRIORITY : prioval;
+ if (ipv4ph)
+ vd.checksum_with_ipv4_pseudoheader = !no;
if (s)
vd.shutdown = !no;
@@ -374,6 +406,8 @@ static struct json_object *vrrp_build_json(struct vrrp_vrouter *vr)
json_object_boolean_add(j, "shutdown", vr->shutdown);
json_object_boolean_add(j, "preemptMode", vr->preempt_mode);
json_object_boolean_add(j, "acceptMode", vr->accept_mode);
+ json_object_boolean_add(j, "checksumWithIpv4Pseudoheader",
+ vr->checksum_with_ipv4_pseudoheader);
json_object_string_add(j, "interface", vr->ifp->name);
json_object_int_add(j, "advertisementInterval",
vr->advertisement_interval * CS2MS);
@@ -499,6 +533,8 @@ static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr)
vr->preempt_mode ? "Yes" : "No");
ttable_add_row(tt, "%s|%s", "Accept Mode",
vr->accept_mode ? "Yes" : "No");
+ ttable_add_row(tt, "%s|%s", "Checksum with IPv4 Pseudoheader",
+ vr->checksum_with_ipv4_pseudoheader ? "Yes" : "No");
ttable_add_row(tt, "%s|%d ms", "Advertisement Interval",
vr->advertisement_interval * CS2MS);
ttable_add_row(tt, "%s|%d ms (stale)",
@@ -752,4 +788,6 @@ void vrrp_vty_init(void)
install_element(INTERFACE_NODE, &vrrp_ip_cmd);
install_element(INTERFACE_NODE, &vrrp_ip6_cmd);
install_element(INTERFACE_NODE, &vrrp_preempt_cmd);
+ install_element(INTERFACE_NODE,
+ &vrrp_checksum_with_ipv4_pseudoheader_cmd);
}
diff --git a/vrrpd/vrrp_vty.h b/vrrpd/vrrp_vty.h
index 587537a6f3..be88349e78 100644
--- a/vrrpd/vrrp_vty.h
+++ b/vrrpd/vrrp_vty.h
@@ -40,5 +40,8 @@ void cli_show_ipv6(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
void cli_show_preempt(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
+void cli_show_checksum_with_ipv4_pseudoheader(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults);
#endif /* __VRRP_VTY_H__ */
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 48274d7170..dea09fa151 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -3413,6 +3413,30 @@ int vtysh_write_config_integrated(void)
return CMD_SUCCESS;
}
+DEFUN_HIDDEN(start_config, start_config_cmd, "XFRR_start_configuration",
+ "The Beginning of Configuration\n")
+{
+ unsigned int i;
+ char line[] = "XFRR_start_configuration";
+
+ for (i = 0; i < array_size(vtysh_client); i++)
+ vtysh_client_execute(&vtysh_client[i], line);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN(end_config, end_config_cmd, "XFRR_end_configuration",
+ "The End of Configuration\n")
+{
+ unsigned int i;
+ char line[] = "XFRR_end_configuration";
+
+ for (i = 0; i < array_size(vtysh_client); i++)
+ vtysh_client_execute(&vtysh_client[i], line);
+
+ return CMD_SUCCESS;
+}
+
static bool want_config_integrated(void)
{
struct stat s;
@@ -3915,6 +3939,12 @@ DEFUN (vtysh_ping,
return CMD_SUCCESS;
}
+DEFUN(vtysh_motd, vtysh_motd_cmd, "show motd", SHOW_STR "Show motd\n")
+{
+ vty_hello(vty);
+ return CMD_SUCCESS;
+}
+
ALIAS(vtysh_ping, vtysh_ping_ip_cmd, "ping ip WORD",
"Send echo messages\n"
"IP echo\n"
@@ -4870,6 +4900,9 @@ void vtysh_init_vty(void)
/* "write memory" command. */
install_element(ENABLE_NODE, &vtysh_write_memory_cmd);
+ install_element(CONFIG_NODE, &start_config_cmd);
+ install_element(CONFIG_NODE, &end_config_cmd);
+
install_element(CONFIG_NODE, &vtysh_terminal_paginate_cmd);
install_element(VIEW_NODE, &vtysh_terminal_paginate_cmd);
install_element(VIEW_NODE, &vtysh_terminal_length_cmd);
@@ -4880,6 +4913,7 @@ void vtysh_init_vty(void)
install_element(VIEW_NODE, &no_vtysh_terminal_monitor_cmd);
install_element(VIEW_NODE, &vtysh_ping_cmd);
+ install_element(VIEW_NODE, &vtysh_motd_cmd);
install_element(VIEW_NODE, &vtysh_ping_ip_cmd);
install_element(VIEW_NODE, &vtysh_traceroute_cmd);
install_element(VIEW_NODE, &vtysh_traceroute_ip_cmd);
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index ac0cdc6ffd..ac32f0a774 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -348,9 +348,13 @@ void vtysh_config_parse_line(void *arg, const char *line)
break;
default:
if (strncmp(line, "exit", strlen("exit")) == 0) {
- if (config)
+ if (config) {
+ if (config->exit)
+ XFREE(MTYPE_VTYSH_CONFIG_LINE,
+ config->exit);
config->exit =
XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line);
+ }
} else if (strncmp(line, "interface", strlen("interface")) == 0)
config = config_get(INTERFACE_NODE, line);
else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index ca119eb900..be7eb3ecdf 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -111,6 +111,8 @@ static void vtysh_rl_callback(char *line_read)
if (!vtysh_loop_exited)
rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+
+ free(line_read);
}
/* SIGTSTP handler. This function care user's ^Z input. */
@@ -352,6 +354,7 @@ int main(int argc, char **argv, char **env)
const char *pathspace_arg = NULL;
char pathspace[MAXPATHLEN] = "";
const char *histfile = NULL;
+ const char *histfile_env = getenv("VTYSH_HISTFILE");
/* SUID: drop down to calling user & go back up when needed */
elevuid = geteuid();
@@ -609,10 +612,8 @@ int main(int argc, char **argv, char **env)
* VTYSH_HISTFILE is preferred over command line
* argument (-H/--histfile).
*/
- if (getenv("VTYSH_HISTFILE")) {
- const char *file = getenv("VTYSH_HISTFILE");
-
- strlcpy(history_file, file, sizeof(history_file));
+ if (histfile_env) {
+ strlcpy(history_file, histfile_env, sizeof(history_file));
} else if (histfile) {
strlcpy(history_file, histfile, sizeof(history_file));
} else {
diff --git a/yang/frr-vrrpd.yang b/yang/frr-vrrpd.yang
index 200eaeb0b5..cd04df2670 100644
--- a/yang/frr-vrrpd.yang
+++ b/yang/frr-vrrpd.yang
@@ -110,6 +110,13 @@ module frr-vrrpd {
address is not owned by the router interface";
}
+ leaf checksum-with-ipv4-pseudoheader {
+ type boolean;
+ default "true";
+ description
+ "Enabled if VRRPv3 checksum for IPv4 involves pseudoheader";
+ }
+
leaf advertisement-interval {
type uint16 {
range "1..4095";
diff --git a/zebra/connected.c b/zebra/connected.c
index c01be58e82..57c7f1925b 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -387,10 +387,14 @@ void connected_down(struct interface *ifp, struct connected *ifc)
.ifindex = ifp->ifindex,
.vrf_id = ifp->vrf->vrf_id,
};
- struct zebra_vrf *zvrf;
- uint32_t count = 0;
+ struct zebra_vrf *zvrf, *zvrf_iter;
+ uint32_t count_ipv4 = 0;
struct listnode *cnode;
struct connected *c;
+ struct route_table *table;
+ struct route_node *rn;
+ struct route_entry *re, *next;
+ struct vrf *vrf;
zvrf = ifp->vrf->info;
if (!zvrf) {
@@ -456,12 +460,14 @@ void connected_down(struct interface *ifp, struct connected *ifc)
prefix_copy(&cp, CONNECTED_PREFIX(c));
apply_mask(&cp);
- if (prefix_same(&p, &cp) &&
- !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
- count++;
+ if (CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
+ continue;
- if (count >= 1)
+ if (prefix_same(&p, &cp))
return;
+
+ if (cp.family == AF_INET)
+ count_ipv4++;
}
/*
@@ -474,6 +480,60 @@ void connected_down(struct interface *ifp, struct connected *ifc)
rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
+ /* When the last IPv4 address of an interface is deleted, Linux removes
+ * all routes using this interface without any Netlink advertisement.
+ * The removed routes include those that only have this particular
+ * interface as a nexthop. Among those, remove the kernel one from the
+ * FRR RIB and reinstall the other that have been added from FRR.
+ */
+ if (afi == AFI_IP && count_ipv4 == 0 && if_is_operative(ifp)) {
+ RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+ zvrf_iter = vrf->info;
+
+ if (!zvrf_iter)
+ continue;
+
+ table = zvrf_iter->table[AFI_IP][SAFI_UNICAST];
+ if (!table)
+ continue;
+
+ for (rn = route_top(table); rn;
+ rn = srcdest_route_next(rn)) {
+ RNODE_FOREACH_RE_SAFE (rn, re, next) {
+ if (CHECK_FLAG(re->status,
+ ROUTE_ENTRY_REMOVED))
+ continue;
+ if (re->nhe->ifp != ifp)
+ continue;
+ if (re->type == ZEBRA_ROUTE_KERNEL)
+ rib_delete(
+ afi, SAFI_UNICAST,
+ zvrf_iter->vrf->vrf_id,
+ re->type, 0, re->flags,
+ &rn->p, NULL, &nh, 0,
+ zvrf_iter->table_id,
+ re->metric,
+ re->distance, false);
+ else if (re->type !=
+ ZEBRA_ROUTE_CONNECT) {
+ SET_FLAG(re->status,
+ ROUTE_ENTRY_CHANGED);
+ UNSET_FLAG(
+ re->status,
+ ROUTE_ENTRY_INSTALLED);
+ rib_add(afi, SAFI_UNICAST,
+ zvrf_iter->vrf->vrf_id,
+ re->type, 0, 0, &rn->p,
+ NULL, &nh, re->nhe_id,
+ zvrf_iter->table_id,
+ re->metric, 0,
+ re->distance, 0, false);
+ }
+ }
+ }
+ }
+ }
+
/* Schedule LSP forwarding entries for processing, if appropriate. */
if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
if (IS_ZEBRA_DEBUG_MPLS)
diff --git a/zebra/debug.c b/zebra/debug.c
index 16aac7909f..977af0e198 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -42,6 +42,7 @@ unsigned long zebra_debug_nexthop;
unsigned long zebra_debug_evpn_mh;
unsigned long zebra_debug_pbr;
unsigned long zebra_debug_neigh;
+unsigned long zebra_debug_tc;
DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
@@ -340,7 +341,7 @@ DEFPY(debug_zebra_dplane_dpdk, debug_zebra_dplane_dpdk_cmd,
SET_FLAG(zebra_debug_dplane_dpdk, ZEBRA_DEBUG_DPLANE_DPDK);
if (detail)
- SET_FLAG(zebra_debug_dplane,
+ SET_FLAG(zebra_debug_dplane_dpdk,
ZEBRA_DEBUG_DPLANE_DPDK_DETAIL);
}
@@ -374,6 +375,17 @@ DEFPY (debug_zebra_neigh,
return CMD_SUCCESS;
}
+DEFUN (debug_zebra_tc,
+ debug_zebra_tc_cmd,
+ "debug zebra tc",
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug zebra tc events\n")
+{
+ SET_FLAG(zebra_debug_tc, ZEBRA_DEBUG_TC);
+ return CMD_SUCCESS;
+}
+
DEFPY (debug_zebra_mlag,
debug_zebra_mlag_cmd,
"[no$no] debug zebra mlag",
@@ -728,10 +740,12 @@ static int config_write_debug(struct vty *vty)
write++;
}
- if (CHECK_FLAG(zebra_debug_dplane, ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)) {
+ if (CHECK_FLAG(zebra_debug_dplane_dpdk,
+ ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)) {
vty_out(vty, "debug zebra dplane dpdk detailed\n");
write++;
- } else if (CHECK_FLAG(zebra_debug_dplane, ZEBRA_DEBUG_DPLANE_DPDK)) {
+ } else if (CHECK_FLAG(zebra_debug_dplane_dpdk,
+ ZEBRA_DEBUG_DPLANE_DPDK)) {
vty_out(vty, "debug zebra dplane dpdk\n");
write++;
}
@@ -797,6 +811,7 @@ void zebra_debug_init(void)
install_element(ENABLE_NODE, &debug_zebra_nexthop_cmd);
install_element(ENABLE_NODE, &debug_zebra_pbr_cmd);
install_element(ENABLE_NODE, &debug_zebra_neigh_cmd);
+ install_element(ENABLE_NODE, &debug_zebra_tc_cmd);
install_element(ENABLE_NODE, &debug_zebra_dplane_dpdk_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_events_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_nht_cmd);
diff --git a/zebra/debug.h b/zebra/debug.h
index 73546de632..514827707a 100644
--- a/zebra/debug.h
+++ b/zebra/debug.h
@@ -75,6 +75,8 @@ extern "C" {
#define ZEBRA_DEBUG_NEIGH 0x01
+#define ZEBRA_DEBUG_TC 0x01
+
/* Debug related macro. */
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
@@ -109,9 +111,9 @@ extern "C" {
(zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DETAILED)
#define IS_ZEBRA_DEBUG_DPLANE_DPDK \
- (zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DPDK)
+ (zebra_debug_dplane_dpdk & ZEBRA_DEBUG_DPLANE_DPDK)
#define IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL \
- (zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
+ (zebra_debug_dplane_dpdk & ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
#define IS_ZEBRA_DEBUG_MLAG (zebra_debug_mlag & ZEBRA_DEBUG_MLAG)
@@ -133,6 +135,8 @@ extern "C" {
#define IS_ZEBRA_DEBUG_NEIGH (zebra_debug_neigh & ZEBRA_DEBUG_NEIGH)
+#define IS_ZEBRA_DEBUG_TC (zebra_debug_tc & ZEBRA_DEBUG_TC)
+
extern unsigned long zebra_debug_event;
extern unsigned long zebra_debug_packet;
extern unsigned long zebra_debug_kernel;
@@ -149,6 +153,7 @@ extern unsigned long zebra_debug_nexthop;
extern unsigned long zebra_debug_evpn_mh;
extern unsigned long zebra_debug_pbr;
extern unsigned long zebra_debug_neigh;
+extern unsigned long zebra_debug_tc;
extern void zebra_debug_init(void);
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index c5e1c113cb..337113988e 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -51,6 +51,7 @@
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
#include "zebra/debug.h"
+#include "fpm/fpm.h"
#define SOUTHBOUND_DEFAULT_ADDR INADDR_LOOPBACK
#define SOUTHBOUND_DEFAULT_PORT 2620
@@ -462,18 +463,17 @@ static void fpm_reconnect(struct fpm_nl_ctx *fnc)
static void fpm_read(struct thread *t)
{
struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ fpm_msg_hdr_t fpm;
ssize_t rv;
+ char buf[65535];
+ struct nlmsghdr *hdr;
+ struct zebra_dplane_ctx *ctx;
+ size_t available_bytes;
+ size_t hdr_available_bytes;
/* Let's ignore the input at the moment. */
rv = stream_read_try(fnc->ibuf, fnc->socket,
STREAM_WRITEABLE(fnc->ibuf));
- /* We've got an interruption. */
- if (rv == -2) {
- /* Schedule next read. */
- thread_add_read(fnc->fthread->master, fpm_read, fnc,
- fnc->socket, &fnc->t_read);
- return;
- }
if (rv == 0) {
atomic_fetch_add_explicit(&fnc->counters.connection_closes, 1,
memory_order_relaxed);
@@ -492,14 +492,131 @@ static void fpm_read(struct thread *t)
FPM_RECONNECT(fnc);
return;
}
- stream_reset(fnc->ibuf);
+
+ /* Schedule the next read */
+ thread_add_read(fnc->fthread->master, fpm_read, fnc, fnc->socket,
+ &fnc->t_read);
+
+ /* We've got an interruption. */
+ if (rv == -2)
+ return;
+
/* Account all bytes read. */
atomic_fetch_add_explicit(&fnc->counters.bytes_read, rv,
memory_order_relaxed);
- thread_add_read(fnc->fthread->master, fpm_read, fnc, fnc->socket,
- &fnc->t_read);
+ available_bytes = STREAM_READABLE(fnc->ibuf);
+ while (available_bytes) {
+ if (available_bytes < (ssize_t)FPM_MSG_HDR_LEN) {
+ stream_pulldown(fnc->ibuf);
+ return;
+ }
+
+ fpm.version = stream_getc(fnc->ibuf);
+ fpm.msg_type = stream_getc(fnc->ibuf);
+ fpm.msg_len = stream_getw(fnc->ibuf);
+
+ if (fpm.version != FPM_PROTO_VERSION &&
+ fpm.msg_type != FPM_MSG_TYPE_NETLINK) {
+ stream_reset(fnc->ibuf);
+ zlog_warn(
+ "%s: Received version/msg_type %u/%u, expected 1/1",
+ __func__, fpm.version, fpm.msg_type);
+
+ FPM_RECONNECT(fnc);
+ return;
+ }
+
+ /*
+ * If the passed in length doesn't even fill in the header
+ * something is wrong and reset.
+ */
+ if (fpm.msg_len < FPM_MSG_HDR_LEN) {
+ zlog_warn(
+ "%s: Received message length: %u that does not even fill the FPM header",
+ __func__, fpm.msg_len);
+ FPM_RECONNECT(fnc);
+ return;
+ }
+
+ /*
+ * If we have not received the whole payload, reset the stream
+ * back to the beginning of the header and move it to the
+ * top.
+ */
+ if (fpm.msg_len > available_bytes) {
+ stream_rewind_getp(fnc->ibuf, FPM_MSG_HDR_LEN);
+ stream_pulldown(fnc->ibuf);
+ return;
+ }
+
+ available_bytes -= FPM_MSG_HDR_LEN;
+
+ /*
+ * Place the data from the stream into a buffer
+ */
+ hdr = (struct nlmsghdr *)buf;
+ stream_get(buf, fnc->ibuf, fpm.msg_len - FPM_MSG_HDR_LEN);
+ hdr_available_bytes = fpm.msg_len - FPM_MSG_HDR_LEN;
+ available_bytes -= hdr_available_bytes;
+
+ /* Sanity check: must be at least header size. */
+ if (hdr->nlmsg_len < sizeof(*hdr)) {
+ zlog_warn(
+ "%s: [seq=%u] invalid message length %u (< %zu)",
+ __func__, hdr->nlmsg_seq, hdr->nlmsg_len,
+ sizeof(*hdr));
+ continue;
+ }
+ if (hdr->nlmsg_len > fpm.msg_len) {
+ zlog_warn(
+ "%s: Received a inner header length of %u that is greater than the fpm total length of %u",
+ __func__, hdr->nlmsg_len, fpm.msg_len);
+ FPM_RECONNECT(fnc);
+ }
+ /* Not enough bytes available. */
+ if (hdr->nlmsg_len > hdr_available_bytes) {
+ zlog_warn(
+ "%s: [seq=%u] invalid message length %u (> %zu)",
+ __func__, hdr->nlmsg_seq, hdr->nlmsg_len,
+ available_bytes);
+ continue;
+ }
+
+ if (!(hdr->nlmsg_flags & NLM_F_REQUEST)) {
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug(
+ "%s: [seq=%u] not a request, skipping",
+ __func__, hdr->nlmsg_seq);
+
+ /*
+ * This request is a bust, go to the next one
+ */
+ continue;
+ }
+
+ switch (hdr->nlmsg_type) {
+ case RTM_NEWROUTE:
+ ctx = dplane_ctx_alloc();
+ dplane_ctx_set_op(ctx, DPLANE_OP_ROUTE_NOTIFY);
+ if (netlink_route_change_read_unicast_internal(
+ hdr, 0, false, ctx) != 1) {
+ dplane_ctx_fini(&ctx);
+ stream_pulldown(fnc->ibuf);
+ return;
+ }
+ break;
+ default:
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug(
+ "%s: Received message type %u which is not currently handled",
+ __func__, hdr->nlmsg_type);
+ break;
+ }
+ }
+
+ stream_reset(fnc->ibuf);
}
static void fpm_write(struct thread *t)
@@ -816,9 +933,14 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
case DPLANE_OP_NONE:
break;
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index b28c468a96..d628e47492 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -1081,8 +1081,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
zif->link_ifindex = link_ifindex;
if (desc) {
- XFREE(MTYPE_TMP, zif->desc);
- zif->desc = XSTRDUP(MTYPE_TMP, desc);
+ XFREE(MTYPE_ZIF_DESC, zif->desc);
+ zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc);
}
/* Hardware type and address. */
@@ -2136,9 +2136,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
zif = ifp->info;
if (zif) {
- XFREE(MTYPE_TMP, zif->desc);
+ XFREE(MTYPE_ZIF_DESC, zif->desc);
if (desc)
- zif->desc = XSTRDUP(MTYPE_TMP, desc);
+ zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc);
}
} else {
/* Delete interface notification from kernel */
diff --git a/zebra/interface.c b/zebra/interface.c
index 32703b59bc..87bb49042a 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -61,6 +61,7 @@ DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
DEFINE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp),
(vty, ifp));
+DEFINE_MTYPE(ZEBRA, ZIF_DESC, "Intf desc");
static void if_down_del_nbr_connected(struct interface *ifp);
@@ -233,7 +234,7 @@ static int if_zebra_delete_hook(struct interface *ifp)
if_nhg_dependents_release(ifp);
zebra_if_nhg_dependents_free(zebra_if);
- XFREE(MTYPE_TMP, zebra_if->desc);
+ XFREE(MTYPE_ZIF_DESC, zebra_if->desc);
THREAD_OFF(zebra_if->speed_update);
@@ -1573,9 +1574,14 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_IPSET_ENTRY_DELETE:
case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_GRE_SET:
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
break; /* should never hit here */
}
}
@@ -4641,7 +4647,7 @@ static int if_config_write(struct vty *vty)
? ""
: "no ");
if (if_data->mpls == IF_ZEBRA_DATA_ON)
- vty_out(vty, " mpls\n");
+ vty_out(vty, " mpls enable\n");
}
hook_call(zebra_if_config_wr, vty, ifp);
diff --git a/zebra/interface.h b/zebra/interface.h
index 801078e83d..0242438dc2 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -109,6 +109,9 @@ enum zebra_if_flags {
#define ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) \
((zif)->protodown_rc == ZEBRA_PROTODOWN_EXTERNAL)
+/* Mem type for zif desc */
+DECLARE_MTYPE(ZIF_DESC);
+
/* `zebra' daemon local interface structure. */
struct zebra_if {
/* back pointer to the interface */
diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c
index 28db2ad87d..36852b65b6 100644
--- a/zebra/irdp_interface.c
+++ b/zebra/irdp_interface.c
@@ -200,12 +200,12 @@ static void if_set_defaults(struct irdp_interface *irdp)
static struct Adv *Adv_new(void)
{
- return XCALLOC(MTYPE_TMP, sizeof(struct Adv));
+ return XCALLOC(MTYPE_IRDP_IF, sizeof(struct Adv));
}
static void Adv_free(struct Adv *adv)
{
- XFREE(MTYPE_TMP, adv);
+ XFREE(MTYPE_IRDP_IF, adv);
}
static void irdp_if_start(struct interface *ifp, int multicast,
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index a8b56bb8f2..54d9561e2b 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -423,6 +423,15 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
return netlink_nexthop_change(h, ns_id, startup);
case RTM_DELNEXTHOP:
return netlink_nexthop_change(h, ns_id, startup);
+ case RTM_NEWQDISC:
+ case RTM_DELQDISC:
+ return netlink_qdisc_change(h, ns_id, startup);
+ case RTM_NEWTCLASS:
+ case RTM_DELTCLASS:
+ return netlink_tclass_change(h, ns_id, startup);
+ case RTM_NEWTFILTER:
+ case RTM_DELTFILTER:
+ return netlink_tfilter_change(h, ns_id, startup);
/* Messages handled in the dplane thread */
case RTM_NEWADDR:
@@ -1640,10 +1649,17 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
case DPLANE_OP_INTF_DELETE:
return netlink_put_intf_update_msg(bth, ctx);
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
- return netlink_put_tc_update_msg(bth, ctx);
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ return netlink_put_tc_qdisc_update_msg(bth, ctx);
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ return netlink_put_tc_class_update_msg(bth, ctx);
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
+ return netlink_put_tc_filter_update_msg(bth, ctx);
}
return FRR_NETLINK_ERROR;
@@ -1757,15 +1773,16 @@ void kernel_init(struct zebra_ns *zns)
* RTNLGRP_XXX to a bit position for ourself
*/
groups = RTMGRP_LINK |
- RTMGRP_IPV4_ROUTE |
- RTMGRP_IPV4_IFADDR |
- RTMGRP_IPV6_ROUTE |
- RTMGRP_IPV6_IFADDR |
- RTMGRP_IPV4_MROUTE |
- RTMGRP_NEIGH |
- ((uint32_t) 1 << (RTNLGRP_IPV4_RULE - 1)) |
- ((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) |
- ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1));
+ RTMGRP_IPV4_ROUTE |
+ RTMGRP_IPV4_IFADDR |
+ RTMGRP_IPV6_ROUTE |
+ RTMGRP_IPV6_IFADDR |
+ RTMGRP_IPV4_MROUTE |
+ RTMGRP_NEIGH |
+ ((uint32_t) 1 << (RTNLGRP_IPV4_RULE - 1)) |
+ ((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) |
+ ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)) |
+ ((uint32_t) 1 << (RTNLGRP_TC - 1));
dplane_groups = (RTMGRP_LINK |
RTMGRP_IPV4_IFADDR |
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index e76d8c0cc4..f84d31cc44 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -1594,9 +1594,14 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list)
res = kernel_intf_update(ctx);
break;
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
res = kernel_tc_update(ctx);
break;
diff --git a/zebra/main.c b/zebra/main.c
index 3de97943fd..e38f9a85e3 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -221,12 +221,12 @@ void zebra_finalize(struct thread *dummy)
{
zlog_info("Zebra final shutdown");
- /* Final shutdown of ns resources */
- ns_walk_func(zebra_ns_final_shutdown, NULL, NULL);
-
/* Stop dplane thread and finish any cleanup */
zebra_dplane_shutdown();
+ /* Final shutdown of ns resources */
+ ns_walk_func(zebra_ns_final_shutdown, NULL, NULL);
+
zebra_router_terminate();
ns_terminate();
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 2396dfe4d6..33fe8db99e 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -692,8 +692,9 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id,
}
/* Looking up routing table by netlink interface. */
-static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
- int startup)
+int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
+ ns_id_t ns_id, int startup,
+ struct zebra_dplane_ctx *ctx)
{
int len;
struct rtmsg *rtm;
@@ -768,9 +769,8 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
selfroute = is_selfroute(rtm->rtm_protocol);
- if (!startup && selfroute
- && h->nlmsg_type == RTM_NEWROUTE
- && !zrouter.asic_offloaded) {
+ if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE &&
+ !zrouter.asic_offloaded && !ctx) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Route type: %d Received that we think we have originated, ignoring",
rtm->rtm_protocol);
@@ -987,10 +987,12 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
}
}
}
- if (nhe_id || ng)
- rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p, re, ng,
- startup);
- else {
+ if (nhe_id || ng) {
+ dplane_rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p,
+ re, ng, startup, ctx);
+ if (ng)
+ nexthop_group_delete(&ng);
+ } else {
/*
* I really don't see how this is possible
* but since we are testing for it let's
@@ -1004,6 +1006,13 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
XFREE(MTYPE_RE, re);
}
} else {
+ if (ctx) {
+ zlog_err(
+ "%s: %pFX RTM_DELROUTE received but received a context as well",
+ __func__, &p);
+ return 0;
+ }
+
if (nhe_id) {
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
&p, &src_p, NULL, nhe_id, table, metric,
@@ -1028,7 +1037,14 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
}
}
- return 0;
+ return 1;
+}
+
+static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
+ int startup)
+{
+ return netlink_route_change_read_unicast_internal(h, ns_id, startup,
+ NULL);
}
static struct mcast_route_data *mroute = NULL;
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index b1af4b20e1..fd2b79a2bf 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -122,6 +122,10 @@ netlink_put_lsp_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
extern enum netlink_msg_status
netlink_put_pw_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
+int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
+ ns_id_t ns_id, int startup,
+ struct zebra_dplane_ctx *ctx);
+
#ifdef NETLINK_DEBUG
const char *nlmsg_type2str(uint16_t type);
const char *af_type2str(int type);
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index a8ec60844c..2b9246515d 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -585,6 +585,28 @@ static void rtadv_process_solicit(struct interface *ifp)
zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS;
}
+static const char *rtadv_optionalhdr2str(uint8_t opt_type)
+{
+ switch (opt_type) {
+ case ND_OPT_SOURCE_LINKADDR:
+ return "Optional Source Link Address";
+ case ND_OPT_TARGET_LINKADDR:
+ return "Optional Target Link Address";
+ case ND_OPT_PREFIX_INFORMATION:
+ return "Optional Prefix Information";
+ case ND_OPT_REDIRECTED_HEADER:
+ return "Optional Redirected Header";
+ case ND_OPT_MTU:
+ return "Optional MTU";
+ case ND_OPT_RTR_ADV_INTERVAL:
+ return "Optional Advertisement Interval";
+ case ND_OPT_HOME_AGENT_INFO:
+ return "Optional Home Agent Information";
+ }
+
+ return "Unknown Optional Type";
+}
+
/*
* This function processes optional attributes off of
* end of a RA packet received. At this point in
@@ -609,6 +631,13 @@ static void rtadv_process_optional(uint8_t *optional, unsigned int len,
&addr->sin6_addr, 1);
break;
default:
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug(
+ "%s:Received Packet with optional Header type %s(%u) that is being ignored",
+ __func__,
+ rtadv_optionalhdr2str(
+ opt_hdr->nd_opt_type),
+ opt_hdr->nd_opt_type);
break;
}
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 26c7823747..2304af19d1 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -308,6 +308,7 @@ struct rtadv_prefix {
#define ND_OPT_HA_INFORMATION 8 /* HA Information Option */
#endif
+
#ifndef HAVE_STRUCT_ND_OPT_ADV_INTERVAL
struct nd_opt_adv_interval { /* Advertisement interval option */
uint8_t nd_opt_ai_type;
@@ -324,6 +325,12 @@ struct nd_opt_adv_interval { /* Advertisement interval option */
#define nd_opt_ai_interval nd_opt_adv_interval_ival
#endif
#endif
+#ifndef ND_OPT_RTR_ADV_INTERVAL
+#define ND_OPT_RTR_ADV_INTERVAL 7
+#endif
+#ifndef ND_OPT_HOME_AGENT_INFO
+#define ND_OPT_HOME_AGENT_INFO 8
+#endif
#ifndef HAVE_STRUCT_ND_OPT_HOMEAGENT_INFO
struct nd_opt_homeagent_info { /* Home Agent info */
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
index f70b006acd..8990f66ef8 100644
--- a/zebra/rtread_netlink.c
+++ b/zebra/rtread_netlink.c
@@ -26,8 +26,10 @@
#include "vty.h"
#include "zebra/rt.h"
#include "zebra/zebra_pbr.h"
+#include "zebra/zebra_tc.h"
#include "zebra/rt_netlink.h"
#include "zebra/rule_netlink.h"
+#include "zebra/tc_netlink.h"
void route_read(struct zebra_ns *zns)
{
@@ -71,4 +73,9 @@ void kernel_read_pbr_rules(struct zebra_ns *zns)
netlink_rules_read(zns);
}
+void kernel_read_tc_qdisc(struct zebra_ns *zns)
+{
+ netlink_qdisc_read(zns);
+}
+
#endif /* GNU_LINUX */
diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c
index 594f7c2dd9..35dde0e686 100644
--- a/zebra/rtread_sysctl.c
+++ b/zebra/rtread_sysctl.c
@@ -30,6 +30,7 @@
#include "zebra/rt.h"
#include "zebra/kernel_socket.h"
#include "zebra/zebra_pbr.h"
+#include "zebra/zebra_tc.h"
#include "zebra/zebra_errors.h"
/* Kernel routing table read up by sysctl function. */
@@ -108,4 +109,8 @@ void kernel_read_pbr_rules(struct zebra_ns *zns)
{
}
+void kernel_read_tc_qdisc(struct zebra_ns *zns)
+{
+}
+
#endif /* !defined(GNU_LINUX) */
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 9842931496..5c4a87b934 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -100,6 +100,7 @@ zebra_zebra_SOURCES = \
zebra/zebra_routemap_nb_config.c \
zebra/zebra_script.c \
zebra/zebra_srte.c \
+ zebra/zebra_tc.c \
zebra/zebra_trace.c \
zebra/zebra_vrf.c \
zebra/zebra_vty.c \
@@ -175,6 +176,7 @@ noinst_HEADERS += \
zebra/zebra_router.h \
zebra/zebra_script.h \
zebra/zebra_srte.h \
+ zebra/zebra_tc.h \
zebra/zebra_trace.h \
zebra/zebra_vrf.h \
zebra/zebra_vxlan.h \
diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c
index afa03a4fa5..1fa80e846a 100644
--- a/zebra/tc_netlink.c
+++ b/zebra/tc_netlink.c
@@ -3,28 +3,27 @@
*
* Copyright (C) 2022 Shichu Yang
*
- * This file is part of FRR.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
*
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
*
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#ifdef HAVE_NETLINK
+#include <linux/pkt_cls.h>
+#include <linux/pkt_sched.h>
#include <netinet/if_ether.h>
#include <sys/socket.h>
@@ -32,34 +31,24 @@
#include "prefix.h"
#include "vrf.h"
-#include <linux/fib_rules.h>
-#include <linux/pkt_cls.h>
-#include <linux/pkt_sched.h>
#include "zebra/zserv.h"
#include "zebra/zebra_ns.h"
-#include "zebra/zebra_vrf.h"
#include "zebra/rt.h"
#include "zebra/interface.h"
#include "zebra/debug.h"
-#include "zebra/rtadv.h"
#include "zebra/kernel_netlink.h"
#include "zebra/tc_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_tc.h"
#include "zebra/zebra_trace.h"
-/* TODO: move these bitflags to zebra_tc.h */
-#define TC_FILTER_SRC_IP (1 << 0)
-#define TC_FILTER_DST_IP (1 << 1)
-#define TC_FILTER_IP_PROTOCOL (1 << 9)
-
#define TC_FREQ_DEFAULT (100)
-#define TC_MAJOR_BASE (0x1000u)
+/* some magic number */
+#define TC_QDISC_MAJOR_ZEBRA (0xbeef0000u)
#define TC_MINOR_NOCLASS (0xffffu)
-#define TC_FILTER_MASK (0x8000u)
-
#define TIME_UNITS_PER_SEC (1000000)
#define xmittime(r, s) (TIME_UNITS_PER_SEC * ((double)(s) / (double)(r)))
@@ -81,19 +70,6 @@ static uint32_t tc_get_freq(void)
return freq == 0 ? TC_FREQ_DEFAULT : freq;
}
-static inline uint32_t tc_make_handle(uint16_t major, uint16_t minor)
-{
- return (major) << 16 | (minor);
-}
-
-static inline uint32_t tc_get_handle(struct zebra_dplane_ctx *ctx,
- uint16_t minor)
-{
- uint16_t major = TC_MAJOR_BASE + (uint16_t)dplane_ctx_get_ifindex(ctx);
-
- return tc_make_handle(major, minor);
-}
-
static void tc_calc_rate_table(struct tc_ratespec *ratespec, uint32_t *table,
uint32_t mtu)
{
@@ -189,11 +165,7 @@ static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
void *data, size_t datalen)
{
struct nlsock *nl;
-
- const char *kind = "htb";
-
- struct tc_htb_glob htb_glob = {
- .rate2quantum = 10, .version = 3, .defcls = TC_MINOR_NOCLASS};
+ const char *kind_str = NULL;
struct rtattr *nest;
@@ -221,16 +193,41 @@ static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
req->t.tcm_family = AF_UNSPEC;
req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
- req->t.tcm_handle = tc_get_handle(ctx, 0);
+ req->t.tcm_info = 0;
+ req->t.tcm_handle = 0;
req->t.tcm_parent = TC_H_ROOT;
- nl_attr_put(&req->n, datalen, TCA_KIND, kind, strlen(kind) + 1);
+ if (cmd == RTM_NEWQDISC) {
+ req->t.tcm_handle = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA, 0);
- nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
+ kind_str = dplane_ctx_tc_qdisc_get_kind_str(ctx);
- nl_attr_put(&req->n, datalen, TCA_HTB_INIT, &htb_glob,
- sizeof(htb_glob));
- nl_attr_nest_end(&req->n, nest);
+ nl_attr_put(&req->n, datalen, TCA_KIND, kind_str,
+ strlen(kind_str) + 1);
+
+ nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
+
+ switch (dplane_ctx_tc_qdisc_get_kind(ctx)) {
+ case TC_QDISC_HTB: {
+ struct tc_htb_glob htb_glob = {
+ .rate2quantum = 10,
+ .version = 3,
+ .defcls = TC_MINOR_NOCLASS};
+ nl_attr_put(&req->n, datalen, TCA_HTB_INIT, &htb_glob,
+ sizeof(htb_glob));
+ break;
+ }
+ case TC_QDISC_NOQUEUE:
+ break;
+ default:
+ break;
+ /* not implemented */
+ }
+
+ nl_attr_nest_end(&req->n, nest);
+ } else {
+ /* ifindex are enough for del/get qdisc */
+ }
return NLMSG_ALIGN(req->n.nlmsg_len);
}
@@ -241,17 +238,10 @@ static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
static ssize_t netlink_tclass_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
void *data, size_t datalen)
{
- struct nlsock *nl;
- struct tc_htb_opt htb_opt = {};
+ enum dplane_op_e op = dplane_ctx_get_op(ctx);
- uint64_t rate, ceil;
- uint64_t buffer, cbuffer;
-
- /* TODO: fetch mtu from interface */
- uint32_t mtu = 0;
-
- uint32_t rtab[256];
- uint32_t ctab[256];
+ struct nlsock *nl;
+ const char *kind_str = NULL;
struct rtattr *nest;
@@ -271,73 +261,239 @@ static ssize_t netlink_tclass_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ if (op == DPLANE_OP_TC_CLASS_UPDATE)
+ req->n.nlmsg_flags |= NLM_F_REPLACE;
+
req->n.nlmsg_type = cmd;
req->n.nlmsg_pid = nl->snl.nl_pid;
req->t.tcm_family = AF_UNSPEC;
req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
- req->t.tcm_handle = tc_get_handle(ctx, 1);
- req->t.tcm_parent = tc_get_handle(ctx, 0);
- rate = dplane_ctx_tc_get_rate(ctx);
- ceil = dplane_ctx_tc_get_ceil(ctx);
+ req->t.tcm_handle = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA,
+ dplane_ctx_tc_class_get_handle(ctx));
+ req->t.tcm_parent = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA, 0);
+ req->t.tcm_info = 0;
+
+ kind_str = dplane_ctx_tc_class_get_kind_str(ctx);
+
+ if (op == DPLANE_OP_TC_CLASS_ADD || op == DPLANE_OP_TC_CLASS_UPDATE) {
+ zlog_debug("netlink tclass encoder: op: %s kind: %s handle: %u",
+ op == DPLANE_OP_TC_CLASS_UPDATE ? "update" : "add",
+ kind_str, dplane_ctx_tc_class_get_handle(ctx));
+
+ nl_attr_put(&req->n, datalen, TCA_KIND, kind_str,
+ strlen(kind_str) + 1);
+
+ nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
+
+ switch (dplane_ctx_tc_class_get_kind(ctx)) {
+ case TC_QDISC_HTB: {
+ struct tc_htb_opt htb_opt = {};
+
+ uint64_t rate = dplane_ctx_tc_class_get_rate(ctx),
+ ceil = dplane_ctx_tc_class_get_ceil(ctx);
+
+ uint64_t buffer, cbuffer;
+
+ /* TODO: fetch mtu from interface */
+ uint32_t mtu = 1500;
+
+ uint32_t rtab[256];
+ uint32_t ctab[256];
+
+ ceil = MAX(rate, ceil);
+
+ htb_opt.rate.rate = (rate >> 32 != 0) ? ~0U : rate;
+ htb_opt.ceil.rate = (ceil >> 32 != 0) ? ~0U : ceil;
+
+ buffer = rate / tc_get_freq() + mtu;
+ cbuffer = ceil / tc_get_freq() + mtu;
+
+ htb_opt.buffer = buffer;
+ htb_opt.cbuffer = cbuffer;
+
+ tc_calc_rate_table(&htb_opt.rate, rtab, mtu);
+ tc_calc_rate_table(&htb_opt.ceil, ctab, mtu);
+
+ htb_opt.ceil.mpu = htb_opt.rate.mpu = 0;
+ htb_opt.ceil.overhead = htb_opt.rate.overhead = 0;
+
+ if (rate >> 32 != 0) {
+ nl_attr_put(&req->n, datalen, TCA_HTB_RATE64,
+ &rate, sizeof(rate));
+ }
+
+ if (ceil >> 32 != 0) {
+ nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64,
+ &ceil, sizeof(ceil));
+ }
+
+ nl_attr_put(&req->n, datalen, TCA_HTB_PARMS, &htb_opt,
+ sizeof(htb_opt));
+
+ nl_attr_put(&req->n, datalen, TCA_HTB_RTAB, rtab,
+ sizeof(rtab));
+ nl_attr_put(&req->n, datalen, TCA_HTB_CTAB, ctab,
+ sizeof(ctab));
+ break;
+ }
+ default:
+ break;
+ }
+
+ nl_attr_nest_end(&req->n, nest);
+ }
+
+ return NLMSG_ALIGN(req->n.nlmsg_len);
+}
+
+static int netlink_tfilter_flower_port_type(uint8_t ip_proto, bool src)
+{
+ if (ip_proto == IPPROTO_TCP)
+ return src ? TCA_FLOWER_KEY_TCP_SRC : TCA_FLOWER_KEY_TCP_DST;
+ else if (ip_proto == IPPROTO_UDP)
+ return src ? TCA_FLOWER_KEY_UDP_SRC : TCA_FLOWER_KEY_UDP_DST;
+ else if (ip_proto == IPPROTO_SCTP)
+ return src ? TCA_FLOWER_KEY_SCTP_SRC : TCA_FLOWER_KEY_SCTP_DST;
+ else
+ return -1;
+}
+
+static void netlink_tfilter_flower_put_options(struct nlmsghdr *n,
+ size_t datalen,
+ struct zebra_dplane_ctx *ctx)
+{
+ struct inet_prefix addr;
+ uint32_t flags = 0, classid;
+ uint8_t protocol = htons(dplane_ctx_tc_filter_get_eth_proto(ctx));
+ uint32_t filter_bm = dplane_ctx_tc_filter_get_filter_bm(ctx);
+
+ if (filter_bm & TC_FLOWER_SRC_IP) {
+ const struct prefix *src_p =
+ dplane_ctx_tc_filter_get_src_ip(ctx);
- ceil = ceil < rate ? rate : ceil;
+ if (tc_flower_get_inet_prefix(src_p, &addr) != 0)
+ return;
+
+ nl_attr_put(n, datalen,
+ (addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_SRC
+ : TCA_FLOWER_KEY_IPV6_SRC,
+ addr.data, addr.bytelen);
- htb_opt.rate.rate = (rate >> 32 != 0) ? ~0U : rate;
- htb_opt.ceil.rate = (ceil >> 32 != 0) ? ~0U : ceil;
+ if (tc_flower_get_inet_mask(src_p, &addr) != 0)
+ return;
- buffer = rate / tc_get_freq(), cbuffer = ceil / tc_get_freq();
+ nl_attr_put(n, datalen,
+ (addr.family == AF_INET)
+ ? TCA_FLOWER_KEY_IPV4_SRC_MASK
+ : TCA_FLOWER_KEY_IPV6_SRC_MASK,
+ addr.data, addr.bytelen);
+ }
- htb_opt.buffer = buffer;
- htb_opt.cbuffer = cbuffer;
+ if (filter_bm & TC_FLOWER_DST_IP) {
+ const struct prefix *dst_p =
+ dplane_ctx_tc_filter_get_dst_ip(ctx);
- tc_calc_rate_table(&htb_opt.rate, rtab, mtu);
- tc_calc_rate_table(&htb_opt.ceil, ctab, mtu);
+ if (tc_flower_get_inet_prefix(dst_p, &addr) != 0)
+ return;
- htb_opt.ceil.mpu = htb_opt.rate.mpu = 0;
- htb_opt.ceil.overhead = htb_opt.rate.overhead = 0;
+ nl_attr_put(n, datalen,
+ (addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_DST
+ : TCA_FLOWER_KEY_IPV6_DST,
+ addr.data, addr.bytelen);
- nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
+ if (tc_flower_get_inet_mask(dst_p, &addr) != 0)
+ return;
- if (rate >> 32 != 0) {
- nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64, &rate,
- sizeof(rate));
+ nl_attr_put(n, datalen,
+ (addr.family == AF_INET)
+ ? TCA_FLOWER_KEY_IPV4_DST_MASK
+ : TCA_FLOWER_KEY_IPV6_DST_MASK,
+ addr.data, addr.bytelen);
}
- if (ceil >> 32 != 0) {
- nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64, &ceil,
- sizeof(ceil));
+ if (filter_bm & TC_FLOWER_IP_PROTOCOL) {
+ nl_attr_put8(n, datalen, TCA_FLOWER_KEY_IP_PROTO,
+ dplane_ctx_tc_filter_get_ip_proto(ctx));
}
- nl_attr_put(&req->n, datalen, TCA_HTB_PARMS, &htb_opt, sizeof(htb_opt));
+ if (filter_bm & TC_FLOWER_SRC_PORT) {
+ uint16_t min, max;
- nl_attr_put(&req->n, datalen, TCA_HTB_RTAB, rtab, sizeof(rtab));
- nl_attr_put(&req->n, datalen, TCA_HTB_CTAB, ctab, sizeof(ctab));
- nl_attr_nest_end(&req->n, nest);
+ min = dplane_ctx_tc_filter_get_src_port_min(ctx);
+ max = dplane_ctx_tc_filter_get_src_port_max(ctx);
- return NLMSG_ALIGN(req->n.nlmsg_len);
+ if (max > min) {
+ nl_attr_put16(n, datalen, TCA_FLOWER_KEY_PORT_SRC_MIN,
+ htons(min));
+
+ nl_attr_put16(n, datalen, TCA_FLOWER_KEY_PORT_SRC_MAX,
+ htons(max));
+ } else {
+ int type = netlink_tfilter_flower_port_type(
+ dplane_ctx_tc_filter_get_ip_proto(ctx), true);
+
+ if (type < 0)
+ return;
+
+ nl_attr_put16(n, datalen, type, htons(min));
+ }
+ }
+
+ if (filter_bm & TC_FLOWER_DST_PORT) {
+ uint16_t min = dplane_ctx_tc_filter_get_dst_port_min(ctx),
+ max = dplane_ctx_tc_filter_get_dst_port_max(ctx);
+
+ if (max > min) {
+ nl_attr_put16(n, datalen, TCA_FLOWER_KEY_PORT_DST_MIN,
+ htons(min));
+
+ nl_attr_put16(n, datalen, TCA_FLOWER_KEY_PORT_DST_MAX,
+ htons(max));
+ } else {
+ int type = netlink_tfilter_flower_port_type(
+ dplane_ctx_tc_filter_get_ip_proto(ctx), false);
+
+ if (type < 0)
+ return;
+
+ nl_attr_put16(n, datalen, type, htons(min));
+ }
+ }
+
+ if (filter_bm & TC_FLOWER_DSFIELD) {
+ nl_attr_put8(n, datalen, TCA_FLOWER_KEY_IP_TOS,
+ dplane_ctx_tc_filter_get_dsfield(ctx));
+ nl_attr_put8(n, datalen, TCA_FLOWER_KEY_IP_TOS_MASK,
+ dplane_ctx_tc_filter_get_dsfield_mask(ctx));
+ }
+
+ classid = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA,
+ dplane_ctx_tc_filter_get_classid(ctx));
+ nl_attr_put32(n, datalen, TCA_FLOWER_CLASSID, classid);
+
+ nl_attr_put32(n, datalen, TCA_FLOWER_FLAGS, flags);
+
+ nl_attr_put16(n, datalen, TCA_FLOWER_KEY_ETH_TYPE, protocol);
}
/*
- * Traffic control filter encoding (only "flower" supported)
+ * Traffic control filter encoding
*/
static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
void *data, size_t datalen)
{
+ enum dplane_op_e op = dplane_ctx_get_op(ctx);
+
struct nlsock *nl;
- struct rtattr *nest;
+ const char *kind_str = NULL;
- const char *kind = "flower";
+ struct rtattr *nest;
uint16_t priority;
uint16_t protocol;
- uint32_t classid;
- uint32_t filter_bm;
- uint32_t flags = 0;
-
- struct inet_prefix addr;
struct {
struct nlmsghdr n;
@@ -355,7 +511,8 @@ static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
- req->n.nlmsg_flags |= NLM_F_EXCL;
+ if (op == DPLANE_OP_TC_FILTER_UPDATE)
+ req->n.nlmsg_flags |= NLM_F_REPLACE;
req->n.nlmsg_type = cmd;
@@ -364,105 +521,361 @@ static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
req->t.tcm_family = AF_UNSPEC;
req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx);
- /* TODO: priority and layer-3 protocol support */
- priority = 0;
- protocol = htons(ETH_P_IP);
- classid = tc_get_handle(ctx, 1);
- filter_bm = dplane_ctx_tc_get_filter_bm(ctx);
+ priority = dplane_ctx_tc_filter_get_priority(ctx);
+ protocol = htons(dplane_ctx_tc_filter_get_eth_proto(ctx));
+
+ req->t.tcm_info = TC_H_MAKE(priority << 16, protocol);
+ req->t.tcm_handle = dplane_ctx_tc_filter_get_handle(ctx);
+ req->t.tcm_parent = TC_H_MAKE(TC_QDISC_MAJOR_ZEBRA, 0);
+
+ kind_str = dplane_ctx_tc_filter_get_kind_str(ctx);
+
+ if (op == DPLANE_OP_TC_FILTER_ADD || op == DPLANE_OP_TC_FILTER_UPDATE) {
+ nl_attr_put(&req->n, datalen, TCA_KIND, kind_str,
+ strlen(kind_str) + 1);
+
+ zlog_debug(
+ "netlink tfilter encoder: op: %s priority: %u protocol: %u kind: %s handle: %u filter_bm: %u ip_proto: %u",
+ op == DPLANE_OP_TC_FILTER_UPDATE ? "update" : "add",
+ priority, protocol, kind_str,
+ dplane_ctx_tc_filter_get_handle(ctx),
+ dplane_ctx_tc_filter_get_filter_bm(ctx),
+ dplane_ctx_tc_filter_get_ip_proto(ctx));
+
+ nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
+ switch (dplane_ctx_tc_filter_get_kind(ctx)) {
+ case TC_FILTER_FLOWER: {
+ netlink_tfilter_flower_put_options(&req->n, datalen,
+ ctx);
+ break;
+ }
+ default:
+ break;
+ }
+ nl_attr_nest_end(&req->n, nest);
+ }
- req->t.tcm_info = tc_make_handle(priority, protocol);
+ return NLMSG_ALIGN(req->n.nlmsg_len);
+}
- req->t.tcm_handle = 1;
- req->t.tcm_parent = tc_get_handle(ctx, 0);
+static ssize_t netlink_newqdisc_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_qdisc_msg_encode(RTM_NEWQDISC, ctx, buf, buflen);
+}
- nl_attr_put(&req->n, datalen, TCA_KIND, kind, strlen(kind) + 1);
- nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS);
+static ssize_t netlink_delqdisc_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_qdisc_msg_encode(RTM_DELQDISC, ctx, buf, buflen);
+}
- nl_attr_put(&req->n, datalen, TCA_FLOWER_CLASSID, &classid,
- sizeof(classid));
+static ssize_t netlink_newtclass_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_tclass_msg_encode(RTM_NEWTCLASS, ctx, buf, buflen);
+}
- if (filter_bm & TC_FILTER_SRC_IP) {
- const struct prefix *src_p = dplane_ctx_tc_get_src_ip(ctx);
+static ssize_t netlink_deltclass_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_tclass_msg_encode(RTM_DELTCLASS, ctx, buf, buflen);
+}
- if (tc_flower_get_inet_prefix(src_p, &addr) != 0)
- return 0;
+static ssize_t netlink_newtfilter_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_tfilter_msg_encode(RTM_NEWTFILTER, ctx, buf, buflen);
+}
- nl_attr_put(&req->n, datalen,
- (addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_SRC
- : TCA_FLOWER_KEY_IPV6_SRC,
- addr.data, addr.bytelen);
+static ssize_t netlink_deltfilter_msg_encoder(struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
+{
+ return netlink_tfilter_msg_encode(RTM_DELTFILTER, ctx, buf, buflen);
+}
- if (tc_flower_get_inet_mask(src_p, &addr) != 0)
- return 0;
+enum netlink_msg_status
+netlink_put_tc_qdisc_update_msg(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx)
+{
+ enum dplane_op_e op;
+ enum netlink_msg_status ret;
- nl_attr_put(&req->n, datalen,
- (addr.family == AF_INET)
- ? TCA_FLOWER_KEY_IPV4_SRC_MASK
- : TCA_FLOWER_KEY_IPV6_SRC_MASK,
- addr.data, addr.bytelen);
+ op = dplane_ctx_get_op(ctx);
+
+ if (op == DPLANE_OP_TC_QDISC_INSTALL) {
+ ret = netlink_batch_add_msg(
+ bth, ctx, netlink_newqdisc_msg_encoder, false);
+ } else if (op == DPLANE_OP_TC_QDISC_UNINSTALL) {
+ ret = netlink_batch_add_msg(
+ bth, ctx, netlink_delqdisc_msg_encoder, false);
+ } else {
+ return FRR_NETLINK_ERROR;
}
- if (filter_bm & TC_FILTER_DST_IP) {
- const struct prefix *dst_p = dplane_ctx_tc_get_dst_ip(ctx);
+ return ret;
+}
- if (tc_flower_get_inet_prefix(dst_p, &addr) != 0)
- return 0;
+enum netlink_msg_status
+netlink_put_tc_class_update_msg(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx)
+{
+ enum dplane_op_e op;
+ enum netlink_msg_status ret;
- nl_attr_put(&req->n, datalen,
- (addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_DST
- : TCA_FLOWER_KEY_IPV6_DST,
- addr.data, addr.bytelen);
+ op = dplane_ctx_get_op(ctx);
- if (tc_flower_get_inet_mask(dst_p, &addr) != 0)
- return 0;
+ if (op == DPLANE_OP_TC_CLASS_ADD || op == DPLANE_OP_TC_CLASS_UPDATE) {
+ ret = netlink_batch_add_msg(
+ bth, ctx, netlink_newtclass_msg_encoder, false);
+ } else if (op == DPLANE_OP_TC_CLASS_DELETE) {
+ ret = netlink_batch_add_msg(
+ bth, ctx, netlink_deltclass_msg_encoder, false);
+ } else {
+ return FRR_NETLINK_ERROR;
+ }
- nl_attr_put(&req->n, datalen,
- (addr.family == AF_INET)
- ? TCA_FLOWER_KEY_IPV4_DST_MASK
- : TCA_FLOWER_KEY_IPV6_DST_MASK,
- addr.data, addr.bytelen);
+ return ret;
+}
+
+enum netlink_msg_status
+netlink_put_tc_filter_update_msg(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx)
+{
+ enum dplane_op_e op;
+ enum netlink_msg_status ret;
+
+ op = dplane_ctx_get_op(ctx);
+
+ if (op == DPLANE_OP_TC_FILTER_ADD) {
+ ret = netlink_batch_add_msg(
+ bth, ctx, netlink_newtfilter_msg_encoder, false);
+ } else if (op == DPLANE_OP_TC_FILTER_UPDATE) {
+ /*
+ * Replace will fail if either filter type or the number of
+ * filter options is changed, so DEL then NEW
+ *
+ * TFILTER may have refs to TCLASS.
+ */
+
+ (void)netlink_batch_add_msg(
+ bth, ctx, netlink_deltfilter_msg_encoder, false);
+ ret = netlink_batch_add_msg(
+ bth, ctx, netlink_newtfilter_msg_encoder, false);
+ } else if (op == DPLANE_OP_TC_FILTER_DELETE) {
+ ret = netlink_batch_add_msg(
+ bth, ctx, netlink_deltfilter_msg_encoder, false);
+ } else {
+ return FRR_NETLINK_ERROR;
}
- if (filter_bm & TC_FILTER_IP_PROTOCOL) {
- nl_attr_put8(&req->n, datalen, TCA_FLOWER_KEY_IP_PROTO,
- dplane_ctx_tc_get_ip_proto(ctx));
+ 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
+ */
+static int netlink_request_qdiscs(struct zebra_ns *zns, int family, int type)
+{
+ 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;
+
+ return netlink_request(&zns->netlink_cmd, &req);
+}
+
+int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
+{
+ struct tcmsg *tcm;
+ struct zebra_tc_qdisc qdisc = {};
+
+ int len;
+ struct rtattr *tb[TCA_MAX + 1];
+
+ frrtrace(3, frr_zebra, netlink_tc_qdisc_change, h, ns_id, startup);
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct tcmsg));
+
+ 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 tcmsg)));
+ return -1;
}
- nl_attr_put32(&req->n, datalen, TCA_FLOWER_FLAGS, flags);
+ tcm = NLMSG_DATA(h);
+ netlink_parse_rtattr(tb, TCA_MAX, TCA_RTA(tcm), len);
- nl_attr_put16(&req->n, datalen, TCA_FLOWER_KEY_ETH_TYPE, protocol);
- nl_attr_nest_end(&req->n, nest);
+ const char *kind_str = (const char *)RTA_DATA(tb[TCA_KIND]);
- return NLMSG_ALIGN(req->n.nlmsg_len);
+ enum tc_qdisc_kind kind = tc_qdisc_str2kind(kind_str);
+
+ qdisc.qdisc.ifindex = tcm->tcm_ifindex;
+
+ switch (kind) {
+ case TC_QDISC_NOQUEUE:
+ /* "noqueue" is the default qdisc */
+ break;
+ default:
+ break;
+ }
+
+ if (tb[TCA_OPTIONS] != NULL) {
+ struct rtattr *options[TCA_HTB_MAX + 1];
+
+ netlink_parse_rtattr_nested(options, TCA_HTB_MAX,
+ tb[TCA_OPTIONS]);
+
+ /* TODO: more details */
+ /* struct tc_htb_glob *glob = RTA_DATA(options[TCA_HTB_INIT]);
+ */
+ }
+
+ if (h->nlmsg_type == RTM_NEWQDISC) {
+ if (startup &&
+ TC_H_MAJ(tcm->tcm_handle) == TC_QDISC_MAJOR_ZEBRA) {
+ enum zebra_dplane_result ret;
+
+ ret = dplane_tc_qdisc_uninstall(&qdisc);
+
+ zlog_debug("%s: %s leftover qdisc: ifindex %d kind %s",
+ __func__,
+ ((ret == ZEBRA_DPLANE_REQUEST_FAILURE)
+ ? "Failed to remove"
+ : "Removed"),
+ qdisc.qdisc.ifindex, kind_str);
+ }
+ }
+
+ return 0;
}
-static ssize_t netlink_newqdisc_msg_encoder(struct zebra_dplane_ctx *ctx,
- void *buf, size_t buflen)
+int netlink_tclass_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
- return netlink_qdisc_msg_encode(RTM_NEWQDISC, ctx, buf, buflen);
+ struct tcmsg *tcm;
+
+ int len;
+ struct rtattr *tb[TCA_MAX + 1];
+
+ frrtrace(3, frr_zebra, netlink_tc_class_change, h, ns_id, startup);
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct tcmsg));
+
+ 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 tcmsg)));
+ return -1;
+ }
+
+ tcm = NLMSG_DATA(h);
+ netlink_parse_rtattr(tb, TCA_MAX, TCA_RTA(tcm), len);
+
+
+ if (tb[TCA_OPTIONS] != NULL) {
+ struct rtattr *options[TCA_HTB_MAX + 1];
+
+ netlink_parse_rtattr_nested(options, TCA_HTB_MAX,
+ tb[TCA_OPTIONS]);
+
+ /* TODO: more details */
+ /* struct tc_htb_opt *opt = RTA_DATA(options[TCA_HTB_PARMS]); */
+ }
+
+ return 0;
}
-static ssize_t netlink_newtclass_msg_encoder(struct zebra_dplane_ctx *ctx,
- void *buf, size_t buflen)
+int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
- return netlink_tclass_msg_encode(RTM_NEWTCLASS, ctx, buf, buflen);
+ struct tcmsg *tcm;
+
+ int len;
+ struct rtattr *tb[TCA_MAX + 1];
+
+ frrtrace(3, frr_zebra, netlink_tc_filter_change, h, ns_id, startup);
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct tcmsg));
+
+ 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 tcmsg)));
+ return -1;
+ }
+
+ tcm = NLMSG_DATA(h);
+ netlink_parse_rtattr(tb, TCA_MAX, TCA_RTA(tcm), len);
+
+ return 0;
}
-static ssize_t netlink_newtfilter_msg_encoder(struct zebra_dplane_ctx *ctx,
- void *buf, size_t buflen)
+int netlink_qdisc_read(struct zebra_ns *zns)
{
- return netlink_tfilter_msg_encode(RTM_NEWTFILTER, ctx, buf, buflen);
+ int ret;
+ struct zebra_dplane_info dp_info;
+
+ zebra_dplane_info_from_zns(&dp_info, zns, true);
+
+ ret = netlink_request_qdiscs(zns, AF_UNSPEC, RTM_GETQDISC);
+ if (ret < 0)
+ return ret;
+
+ ret = netlink_parse_info(netlink_qdisc_change, &zns->netlink_cmd,
+ &dp_info, 0, true);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
-enum netlink_msg_status netlink_put_tc_update_msg(struct nl_batch *bth,
- struct zebra_dplane_ctx *ctx)
+int netlink_tfilter_read_for_interface(struct zebra_ns *zns, ifindex_t ifindex)
{
- /* TODO: error handling and other actions (delete, replace, ...) */
+ int ret;
+ struct zebra_dplane_info dp_info;
+
+ zebra_dplane_info_from_zns(&dp_info, zns, true);
- netlink_batch_add_msg(bth, ctx, netlink_newqdisc_msg_encoder, false);
- netlink_batch_add_msg(bth, ctx, netlink_newtclass_msg_encoder, false);
- return netlink_batch_add_msg(bth, ctx, netlink_newtfilter_msg_encoder,
- false);
+ 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 2190bca4f9..166bd917c6 100644
--- a/zebra/tc_netlink.h
+++ b/zebra/tc_netlink.h
@@ -3,22 +3,19 @@
*
* Copyright (C) 2022 Shichu Yang
*
- * This file is part of FRR.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
*
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
*
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _ZEBRA_TC_NETLINK_H
@@ -51,7 +48,30 @@ enum {
};
extern enum netlink_msg_status
-netlink_put_tc_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
+netlink_put_tc_qdisc_update_msg(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx);
+extern enum netlink_msg_status
+netlink_put_tc_class_update_msg(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx);
+extern enum netlink_msg_status
+netlink_put_tc_filter_update_msg(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx);
+
+/**
+ * "filter" & "class" in the following become "tfilter" & "tclass" for
+ * the sake of consistency with kernel message types (RTM_NEWTFILTER etc.)
+ */
+
+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);
+extern int netlink_tclass_change(struct nlmsghdr *h, ns_id_t ns_id,
+ int startup);
+extern int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
+
#ifdef __cplusplus
}
diff --git a/zebra/tc_socket.c b/zebra/tc_socket.c
index 0bf9e487b0..17373c7af7 100644
--- a/zebra/tc_socket.c
+++ b/zebra/tc_socket.c
@@ -3,22 +3,19 @@
*
* Copyright (C) 2022 Shichu Yang
*
- * This file is part of FRR.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
*
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
*
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
@@ -30,6 +27,7 @@
#include "zebra/rt.h"
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_errors.h"
+#include "zebra/zebra_tc.h"
enum zebra_dplane_result kernel_tc_update(struct zebra_dplane_ctx *ctx)
{
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 130fb972db..a2233a6667 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -53,6 +53,7 @@
#include "zebra/zebra_evpn_mh.h"
#include "zebra/rt.h"
#include "zebra/zebra_pbr.h"
+#include "zebra/zebra_tc.h"
#include "zebra/table_manager.h"
#include "zebra/zapi_msg.h"
#include "zebra/zebra_errors.h"
@@ -3272,6 +3273,171 @@ stream_failure:
return;
}
+static inline void zread_tc_qdisc(ZAPI_HANDLER_ARGS)
+{
+ struct zebra_tc_qdisc qdisc;
+ struct stream *s;
+ uint32_t total, i;
+
+ s = msg;
+ STREAM_GETL(s, total);
+
+ for (i = 0; i < total; i++) {
+ memset(&qdisc, 0, sizeof(qdisc));
+
+ qdisc.sock = client->sock;
+ STREAM_GETL(s, qdisc.qdisc.ifindex);
+ STREAM_GETL(s, qdisc.qdisc.kind);
+
+ if (hdr->command == ZEBRA_TC_QDISC_INSTALL)
+ zebra_tc_qdisc_install(&qdisc);
+ else
+ zebra_tc_qdisc_uninstall(&qdisc);
+ }
+
+stream_failure:
+ return;
+}
+
+static inline void zread_tc_class(ZAPI_HANDLER_ARGS)
+{
+ struct zebra_tc_class class;
+ struct stream *s;
+ uint32_t total, i;
+
+ s = msg;
+ STREAM_GETL(s, total);
+
+ for (i = 0; i < total; i++) {
+ memset(&class, 0, sizeof(class));
+
+ class.sock = client->sock;
+ STREAM_GETL(s, class.class.ifindex);
+ STREAM_GETL(s, class.class.handle);
+ STREAM_GETL(s, class.class.kind);
+ STREAM_GETQ(s, class.class.u.htb.rate);
+ STREAM_GETQ(s, class.class.u.htb.ceil);
+
+ if (hdr->command == ZEBRA_TC_CLASS_ADD)
+ zebra_tc_class_add(&class);
+ else
+ zebra_tc_class_delete(&class);
+ }
+
+stream_failure:
+ return;
+}
+
+static inline void zread_tc_filter(ZAPI_HANDLER_ARGS)
+{
+ struct zebra_tc_filter filter;
+ struct stream *s;
+ uint32_t total, i;
+
+ s = msg;
+ STREAM_GETL(s, total);
+
+ for (i = 0; i < total; i++) {
+ memset(&filter, 0, sizeof(filter));
+
+ filter.sock = client->sock;
+ STREAM_GETL(s, filter.filter.ifindex);
+ STREAM_GETL(s, filter.filter.handle);
+ STREAM_GETL(s, filter.filter.priority);
+ STREAM_GETL(s, filter.filter.protocol);
+ STREAM_GETL(s, filter.filter.kind);
+ switch (filter.filter.kind) {
+ case TC_FILTER_FLOWER: {
+ STREAM_GETL(s, filter.filter.u.flower.filter_bm);
+ uint32_t filter_bm = filter.filter.u.flower.filter_bm;
+
+ if (filter_bm & TC_FLOWER_IP_PROTOCOL)
+ STREAM_GETC(s, filter.filter.u.flower.ip_proto);
+ if (filter_bm & TC_FLOWER_SRC_IP) {
+ STREAM_GETC(
+ s,
+ filter.filter.u.flower.src_ip.family);
+ STREAM_GETC(s, filter.filter.u.flower.src_ip
+ .prefixlen);
+ STREAM_GET(
+ &filter.filter.u.flower.src_ip.u.prefix,
+ s,
+ prefix_blen(&filter.filter.u.flower
+ .src_ip));
+
+ if (!(filter.filter.u.flower.src_ip.family ==
+ AF_INET ||
+ filter.filter.u.flower.src_ip.family ==
+ AF_INET6)) {
+ zlog_warn(
+ "Unsupported TC source IP family: %s (%hhu)",
+ family2str(
+ filter.filter.u.flower
+ .src_ip.family),
+ filter.filter.u.flower.src_ip
+ .family);
+ return;
+ }
+ }
+ if (filter_bm & TC_FLOWER_SRC_PORT) {
+ STREAM_GETW(
+ s, filter.filter.u.flower.src_port_min);
+ STREAM_GETW(
+ s, filter.filter.u.flower.src_port_max);
+ }
+ if (filter_bm & TC_FLOWER_DST_IP) {
+ STREAM_GETC(
+ s,
+ filter.filter.u.flower.dst_ip.family);
+ STREAM_GETC(s, filter.filter.u.flower.dst_ip
+ .prefixlen);
+ STREAM_GET(
+ &filter.filter.u.flower.dst_ip.u.prefix,
+ s,
+ prefix_blen(&filter.filter.u.flower
+ .dst_ip));
+ if (!(filter.filter.u.flower.dst_ip.family ==
+ AF_INET ||
+ filter.filter.u.flower.dst_ip.family ==
+ AF_INET6)) {
+ zlog_warn(
+ "Unsupported TC destination IP family: %s (%hhu)",
+ family2str(
+ filter.filter.u.flower
+ .dst_ip.family),
+ filter.filter.u.flower.dst_ip
+ .family);
+ return;
+ }
+ }
+ if (filter_bm & TC_FLOWER_DST_PORT) {
+ STREAM_GETW(
+ s, filter.filter.u.flower.dst_port_min);
+ STREAM_GETW(
+ s, filter.filter.u.flower.dst_port_max);
+ }
+ if (filter_bm & TC_FLOWER_DSFIELD) {
+ STREAM_GETC(s, filter.filter.u.flower.dsfield);
+ STREAM_GETC(
+ s, filter.filter.u.flower.dsfield_mask);
+ }
+ STREAM_GETL(s, filter.filter.u.flower.classid);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (hdr->command == ZEBRA_TC_FILTER_ADD)
+ zebra_tc_filter_add(&filter);
+ else
+ zebra_tc_filter_delete(&filter);
+ }
+
+stream_failure:
+ return;
+}
+
static inline void zread_ipset(ZAPI_HANDLER_ARGS)
{
struct zebra_pbr_ipset zpi;
@@ -3532,7 +3698,7 @@ static inline void zebra_neigh_ip_del(ZAPI_HANDLER_ARGS)
static inline void zread_iptable(ZAPI_HANDLER_ARGS)
{
struct zebra_pbr_iptable *zpi =
- XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
+ XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable));
struct stream *s;
s = msg;
@@ -3772,6 +3938,12 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_CONFIGURE_ARP] = zebra_configure_arp,
[ZEBRA_GRE_GET] = zebra_gre_get,
[ZEBRA_GRE_SOURCE_SET] = zebra_gre_source_set,
+ [ZEBRA_TC_QDISC_INSTALL] = zread_tc_qdisc,
+ [ZEBRA_TC_QDISC_UNINSTALL] = zread_tc_qdisc,
+ [ZEBRA_TC_CLASS_ADD] = zread_tc_class,
+ [ZEBRA_TC_CLASS_DELETE] = zread_tc_class,
+ [ZEBRA_TC_FILTER_ADD] = zread_tc_filter,
+ [ZEBRA_TC_FILTER_DELETE] = zread_tc_filter,
};
/*
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 6a691a222f..84dae7f2d6 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -37,6 +37,7 @@
#include "zebra/debug.h"
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_neigh.h"
+#include "zebra/zebra_tc.h"
#include "printfrr.h"
/* Memory types */
@@ -134,6 +135,8 @@ struct dplane_route_info {
uint32_t zd_mtu;
uint32_t zd_nexthop_mtu;
+ uint32_t zd_flags;
+
/* Nexthop hash entry info */
struct dplane_nexthop_info nhe;
@@ -313,23 +316,36 @@ struct dplane_netconf_info {
enum dplane_netconf_status_e linkdown_val;
};
-/*
- * Traffic control contexts for the dplane
- */
-struct dplane_tc_info {
- /* Rate spec (unit: Bytes/s) */
+struct dplane_tc_qdisc_info {
+ enum tc_qdisc_kind kind;
+ const char *kind_str;
+};
+
+struct dplane_tc_class_info {
+ uint32_t handle;
+ enum tc_qdisc_kind kind;
+ const char *kind_str;
uint64_t rate;
uint64_t ceil;
+};
- /* TODO: custom burst */
-
- /* Filter components for "tfilter" */
+struct dplane_tc_filter_info {
+ uint32_t handle;
+ uint16_t priority;
+ enum tc_filter_kind kind;
+ const char *kind_str;
uint32_t filter_bm;
+ uint16_t eth_proto;
+ uint8_t ip_proto;
struct prefix src_ip;
struct prefix dst_ip;
- uint8_t ip_proto;
-
- /* TODO: more filter components */
+ uint16_t src_port_min;
+ uint16_t src_port_max;
+ uint16_t dst_port_min;
+ uint16_t dst_port_max;
+ uint8_t dsfield;
+ uint8_t dsfield_mask;
+ uint32_t classid;
};
/*
@@ -381,7 +397,9 @@ struct zebra_dplane_ctx {
struct dplane_mac_info macinfo;
struct dplane_neigh_info neigh;
struct dplane_rule_info rule;
- struct dplane_tc_info tc;
+ struct dplane_tc_qdisc_info tc_qdisc;
+ struct dplane_tc_class_info tc_class;
+ struct dplane_tc_filter_info tc_filter;
struct zebra_pbr_iptable iptable;
struct zebra_pbr_ipset ipset;
struct {
@@ -800,9 +818,14 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
break;
case DPLANE_OP_IPSET_ENTRY_ADD:
@@ -812,20 +835,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
break;
case DPLANE_OP_IPTABLE_ADD:
case DPLANE_OP_IPTABLE_DELETE:
- if (ctx->u.iptable.interface_name_list) {
- struct listnode *node, *nnode;
- char *ifname;
-
- for (ALL_LIST_ELEMENTS(
- ctx->u.iptable.interface_name_list, node,
- nnode, ifname)) {
- LISTNODE_DETACH(
- ctx->u.iptable.interface_name_list,
- node);
- XFREE(MTYPE_DP_NETFILTER, ifname);
- }
+ if (ctx->u.iptable.interface_name_list)
list_delete(&ctx->u.iptable.interface_name_list);
- }
break;
case DPLANE_OP_GRE_SET:
case DPLANE_OP_INTF_NETCONFIG:
@@ -1127,14 +1138,29 @@ const char *dplane_op2str(enum dplane_op_e op)
ret = "INTF_DELETE";
break;
- case DPLANE_OP_TC_INSTALL:
- ret = "TC_INSTALL";
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ ret = "TC_QDISC_INSTALL";
+ break;
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ ret = "TC_QDISC_UNINSTALL";
+ break;
+ case DPLANE_OP_TC_CLASS_ADD:
+ ret = "TC_CLASS_ADD";
+ break;
+ case DPLANE_OP_TC_CLASS_DELETE:
+ ret = "TC_CLASS_DELETE";
+ break;
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ ret = "TC_CLASS_UPDATE";
break;
- case DPLANE_OP_TC_UPDATE:
- ret = "TC_UPDATE";
+ case DPLANE_OP_TC_FILTER_ADD:
+ ret = "TC_FILTER_ADD";
break;
- case DPLANE_OP_TC_DELETE:
- ret = "TC_DELETE";
+ case DPLANE_OP_TC_FILTER_DELETE:
+ ret = "TC_FILTER_DELETE";
+ break;
+ case DPLANE_OP_TC_FILTER_UPDATE:
+ ret = "TC__FILTER_UPDATE";
break;
}
@@ -1406,6 +1432,20 @@ uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx)
return ctx->u.rinfo.zd_old_instance;
}
+uint32_t dplane_ctx_get_flags(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rinfo.zd_flags;
+}
+
+void dplane_ctx_set_flags(struct zebra_dplane_ctx *ctx, uint32_t flags)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.rinfo.zd_flags = flags;
+}
+
uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@@ -1455,48 +1495,175 @@ uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
return ctx->u.rinfo.zd_old_distance;
}
-uint64_t dplane_ctx_tc_get_rate(const struct zebra_dplane_ctx *ctx)
+int dplane_ctx_tc_qdisc_get_kind(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_qdisc.kind;
+}
+
+const char *dplane_ctx_tc_qdisc_get_kind_str(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->u.tc.rate;
+ return ctx->u.tc_qdisc.kind_str;
}
-uint64_t dplane_ctx_tc_get_ceil(const struct zebra_dplane_ctx *ctx)
+uint32_t dplane_ctx_tc_class_get_handle(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->u.tc.ceil;
+ return ctx->u.tc_class.handle;
}
-uint32_t dplane_ctx_tc_get_filter_bm(const struct zebra_dplane_ctx *ctx)
+int dplane_ctx_tc_class_get_kind(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->u.tc.filter_bm;
+ return ctx->u.tc_class.kind;
+}
+
+const char *dplane_ctx_tc_class_get_kind_str(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_class.kind_str;
+}
+
+uint64_t dplane_ctx_tc_class_get_rate(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_class.rate;
+}
+
+uint64_t dplane_ctx_tc_class_get_ceil(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_class.ceil;
+}
+
+int dplane_ctx_tc_filter_get_kind(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.kind;
+}
+
+const char *
+dplane_ctx_tc_filter_get_kind_str(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.kind_str;
+}
+
+uint32_t dplane_ctx_tc_filter_get_priority(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.priority;
+}
+
+uint32_t dplane_ctx_tc_filter_get_handle(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.handle;
+}
+
+uint16_t dplane_ctx_tc_filter_get_eth_proto(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.eth_proto;
+}
+
+uint32_t dplane_ctx_tc_filter_get_filter_bm(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.filter_bm;
}
const struct prefix *
-dplane_ctx_tc_get_src_ip(const struct zebra_dplane_ctx *ctx)
+dplane_ctx_tc_filter_get_src_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &ctx->u.tc_filter.src_ip;
+}
+
+uint16_t
+dplane_ctx_tc_filter_get_src_port_min(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.src_port_min;
+}
+
+
+uint16_t
+dplane_ctx_tc_filter_get_src_port_max(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return &(ctx->u.tc.src_ip);
+ return ctx->u.tc_filter.src_port_max;
}
const struct prefix *
-dplane_ctx_tc_get_dst_ip(const struct zebra_dplane_ctx *ctx)
+dplane_ctx_tc_filter_get_dst_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &ctx->u.tc_filter.dst_ip;
+}
+
+uint16_t
+dplane_ctx_tc_filter_get_dst_port_min(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.dst_port_min;
+}
+
+
+uint16_t
+dplane_ctx_tc_filter_get_dst_port_max(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.dst_port_max;
+}
+
+uint8_t dplane_ctx_tc_filter_get_ip_proto(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.ip_proto;
+}
+
+uint8_t dplane_ctx_tc_filter_get_dsfield(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.tc_filter.dsfield;
+}
+
+uint8_t
+dplane_ctx_tc_filter_get_dsfield_mask(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return &(ctx->u.tc.dst_ip);
+ return ctx->u.tc_filter.dsfield_mask;
}
-uint8_t dplane_ctx_tc_get_ip_proto(const struct zebra_dplane_ctx *ctx)
+uint32_t dplane_ctx_tc_filter_get_classid(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return ctx->u.tc.ip_proto;
+ return ctx->u.tc_filter.classid;
}
/*
@@ -2615,25 +2782,16 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
return AOK;
}
-/*
- * Initialize a context block for a route update from zebra data structs.
- */
-int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
- struct route_node *rn, struct route_entry *re)
+int dplane_ctx_route_init_basic(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op, struct route_entry *re,
+ const struct prefix *p,
+ const struct prefix_ipv6 *src_p, afi_t afi,
+ safi_t safi)
{
int ret = EINVAL;
- const struct route_table *table = NULL;
- const struct rib_table_info *info;
- const struct prefix *p, *src_p;
- struct zebra_ns *zns;
- struct zebra_vrf *zvrf;
- struct nexthop *nexthop;
- struct zebra_l3vni *zl3vni;
- const struct interface *ifp;
- struct dplane_intf_extra *if_extra;
- if (!ctx || !rn || !re)
- goto done;
+ if (!ctx || !re)
+ return ret;
TAILQ_INIT(&ctx->u.rinfo.intf_extra_q);
@@ -2643,9 +2801,6 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
ctx->u.rinfo.zd_type = re->type;
ctx->u.rinfo.zd_old_type = re->type;
- /* Prefixes: dest, and optional source */
- srcdest_rnode_prefixes(rn, &p, &src_p);
-
prefix_copy(&(ctx->u.rinfo.zd_dest), p);
if (src_p)
@@ -2655,6 +2810,7 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
ctx->zd_table_id = re->table;
+ ctx->u.rinfo.zd_flags = re->flags;
ctx->u.rinfo.zd_metric = re->metric;
ctx->u.rinfo.zd_old_metric = re->metric;
ctx->zd_vrf_id = re->vrf_id;
@@ -2665,11 +2821,46 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
ctx->u.rinfo.zd_old_tag = re->tag;
ctx->u.rinfo.zd_distance = re->distance;
+ ctx->u.rinfo.zd_afi = afi;
+ ctx->u.rinfo.zd_safi = safi;
+
+ return AOK;
+}
+
+/*
+ * Initialize a context block for a route update from zebra data structs.
+ */
+int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ struct route_node *rn, struct route_entry *re)
+{
+ int ret = EINVAL;
+ const struct route_table *table = NULL;
+ const struct rib_table_info *info;
+ const struct prefix *p;
+ const struct prefix_ipv6 *src_p;
+ struct zebra_ns *zns;
+ struct zebra_vrf *zvrf;
+ struct nexthop *nexthop;
+ struct zebra_l3vni *zl3vni;
+ const struct interface *ifp;
+ struct dplane_intf_extra *if_extra;
+
+ if (!ctx || !rn || !re)
+ return ret;
+
+ /*
+ * Let's grab the data from the route_node
+ * so that we can call a helper function
+ */
+
+ /* Prefixes: dest, and optional source */
+ srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p);
table = srcdest_rnode_table(rn);
info = table->info;
- ctx->u.rinfo.zd_afi = info->afi;
- ctx->u.rinfo.zd_safi = info->safi;
+ if (dplane_ctx_route_init_basic(ctx, op, re, p, src_p, info->afi,
+ info->safi) != AOK)
+ return ret;
/* Copy nexthops; recursive info is included too */
copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop),
@@ -2724,8 +2915,7 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
/* Don't need some info when capturing a system notification */
if (op == DPLANE_OP_SYS_ROUTE_ADD ||
op == DPLANE_OP_SYS_ROUTE_DELETE) {
- ret = AOK;
- goto done;
+ return AOK;
}
/* Extract ns info - can't use pointers to 'core' structs */
@@ -2746,14 +2936,12 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
* If its a delete we only use the prefix anyway, so this only
* matters for INSTALL/UPDATE.
*/
- if (zebra_nhg_kernel_nexthops_enabled()
- && (((op == DPLANE_OP_ROUTE_INSTALL)
- || (op == DPLANE_OP_ROUTE_UPDATE))
- && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
- && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED))) {
- ret = ENOENT;
- goto done;
- }
+ if (zebra_nhg_kernel_nexthops_enabled() &&
+ (((op == DPLANE_OP_ROUTE_INSTALL) ||
+ (op == DPLANE_OP_ROUTE_UPDATE)) &&
+ !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) &&
+ !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)))
+ return ENOENT;
re->nhe_installed_id = nhe->id;
}
@@ -2765,13 +2953,36 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
re->dplane_sequence = zebra_router_get_next_sequence();
ctx->zd_seq = re->dplane_sequence;
+ return AOK;
+}
+
+static int dplane_ctx_tc_qdisc_init(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op,
+ const struct zebra_tc_qdisc *qdisc)
+{
+ int ret = EINVAL;
+
+ struct zebra_ns *zns = NULL;
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ ctx->zd_ifindex = qdisc->qdisc.ifindex;
+ ctx->u.tc_qdisc.kind = qdisc->qdisc.kind;
+ ctx->u.tc_qdisc.kind_str = tc_qdisc_kind2str(qdisc->qdisc.kind);
+
+ /* TODO: init traffic control qdisc */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+
+ dplane_ctx_ns_init(ctx, zns, true);
+
ret = AOK;
-done:
return ret;
}
-int dplane_ctx_tc_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
+static int dplane_ctx_tc_class_init(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op,
+ struct zebra_tc_class *class)
{
int ret = EINVAL;
@@ -2779,8 +2990,55 @@ int dplane_ctx_tc_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ ctx->zd_ifindex = class->class.ifindex;
+
+ ctx->u.tc_class.handle = class->class.handle;
+ ctx->u.tc_class.kind = class->class.kind;
+ ctx->u.tc_class.kind_str = tc_qdisc_kind2str(class->class.kind);
+ ctx->u.tc_class.rate = class->class.u.htb.rate;
+ ctx->u.tc_class.ceil = class->class.u.htb.ceil;
+
+ zns = zebra_ns_lookup(NS_DEFAULT);
+
+ dplane_ctx_ns_init(ctx, zns, true);
+
+ ret = AOK;
+
+ return ret;
+}
+
+static int dplane_ctx_tc_filter_init(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op,
+ struct zebra_tc_filter *filter)
+{
+ int ret = EINVAL;
+
+ struct zebra_ns *zns = NULL;
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ ctx->zd_ifindex = filter->filter.ifindex;
+
+ ctx->u.tc_filter.eth_proto = filter->filter.protocol;
+ ctx->u.tc_filter.ip_proto = filter->filter.u.flower.ip_proto;
+
+ ctx->u.tc_filter.kind = filter->filter.kind;
+ ctx->u.tc_filter.kind_str = tc_filter_kind2str(filter->filter.kind);
+
+ ctx->u.tc_filter.filter_bm = filter->filter.u.flower.filter_bm;
+ prefix_copy(&ctx->u.tc_filter.src_ip, &filter->filter.u.flower.src_ip);
+ ctx->u.tc_filter.src_port_min = filter->filter.u.flower.src_port_min;
+ ctx->u.tc_filter.src_port_max = filter->filter.u.flower.src_port_max;
+ prefix_copy(&ctx->u.tc_filter.dst_ip, &filter->filter.u.flower.dst_ip);
+ ctx->u.tc_filter.dst_port_min = filter->filter.u.flower.dst_port_min;
+ ctx->u.tc_filter.dst_port_max = filter->filter.u.flower.dst_port_max;
+ ctx->u.tc_filter.dsfield = filter->filter.u.flower.dsfield;
+ ctx->u.tc_filter.dsfield_mask = filter->filter.u.flower.dsfield_mask;
+ ctx->u.tc_filter.classid = filter->filter.u.flower.classid;
+
+ ctx->u.tc_filter.priority = filter->filter.priority;
+ ctx->u.tc_filter.handle = filter->filter.handle;
- /* TODO: init traffic control qdisc */
zns = zebra_ns_lookup(NS_DEFAULT);
dplane_ctx_ns_init(ctx, zns, true);
@@ -2807,7 +3065,7 @@ int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
int ret = EINVAL;
if (!ctx || !nhe)
- goto done;
+ return ret;
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
@@ -2842,7 +3100,6 @@ int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
ret = AOK;
-done:
return ret;
}
@@ -2864,7 +3121,7 @@ int dplane_ctx_intf_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
bool set_pdown, unset_pdown;
if (!ctx || !ifp)
- goto done;
+ return ret;
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
@@ -2909,7 +3166,6 @@ int dplane_ctx_intf_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
ret = AOK;
-done:
return ret;
}
@@ -2937,10 +3193,8 @@ int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
/* This may be called to create/init a dplane context, not necessarily
* to copy an lsp object.
*/
- if (lsp == NULL) {
- ret = AOK;
- goto done;
- }
+ if (lsp == NULL)
+ return ret;
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
zlog_debug("init dplane ctx %s: in-label %u ecmp# %d",
@@ -2983,7 +3237,7 @@ int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
}
if (ret != AOK)
- goto done;
+ return ret;
/* Capture backup nhlfes/nexthops */
frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
@@ -3004,11 +3258,6 @@ int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
}
- /* On error the ctx will be cleaned-up, so we don't need to
- * deal with any allocated nhlfe or nexthop structs here.
- */
-done:
-
return ret;
}
@@ -3069,11 +3318,11 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6;
table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id);
if (table == NULL)
- goto done;
+ return ret;
rn = route_node_match(table, &p);
if (rn == NULL)
- goto done;
+ return ret;
re = NULL;
RNODE_FOREACH_RE(rn, re) {
@@ -3141,10 +3390,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
}
route_unlock_node(rn);
- ret = AOK;
-
-done:
- return ret;
+ return AOK;
}
/**
@@ -3240,6 +3486,11 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx,
return AOK;
}
+static void zebra_dplane_interface_name_list_deletion(void *data)
+{
+ XFREE(MTYPE_DP_NETFILTER, data);
+}
+
/**
* dplane_ctx_iptable_init() - Initialize a context block for a PBR iptable
* update.
@@ -3273,9 +3524,10 @@ static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx,
ctx->zd_vrf_id = iptable->vrf_id;
memcpy(&ctx->u.iptable, iptable, sizeof(struct zebra_pbr_iptable));
- ctx->u.iptable.interface_name_list = NULL;
if (iptable->nb_interface > 0) {
ctx->u.iptable.interface_name_list = list_new();
+ ctx->u.iptable.interface_name_list->del =
+ zebra_dplane_interface_name_list_deletion;
for (ALL_LIST_ELEMENTS_RO(iptable->interface_name_list, node,
ifname)) {
listnode_add(ctx->u.iptable.interface_name_list,
@@ -3509,7 +3761,9 @@ dplane_route_update_internal(struct route_node *rn,
return result;
}
-static enum zebra_dplane_result dplane_tc_update_internal(enum dplane_op_e op)
+static enum zebra_dplane_result
+tc_qdisc_update_internal(enum dplane_op_e op,
+ const struct zebra_tc_qdisc *qdisc)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
int ret;
@@ -3524,7 +3778,7 @@ static enum zebra_dplane_result dplane_tc_update_internal(enum dplane_op_e op)
}
/* Init context with info from zebra data structs */
- ret = dplane_ctx_tc_init(ctx, op);
+ ret = dplane_ctx_tc_qdisc_init(ctx, op, qdisc);
if (ret == AOK)
ret = dplane_update_enqueue(ctx);
@@ -3545,9 +3799,118 @@ done:
return result;
}
-enum zebra_dplane_result dplane_tc_update(void)
+static enum zebra_dplane_result
+tc_class_update_internal(enum dplane_op_e op, struct zebra_tc_class *class)
{
- return dplane_tc_update_internal(DPLANE_OP_TC_UPDATE);
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ /* Obtain context block */
+ ctx = dplane_ctx_alloc();
+
+ if (!ctx) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Init context with info from zebra data structs */
+ ret = dplane_ctx_tc_class_init(ctx, op, class);
+
+ if (ret == AOK)
+ ret = dplane_update_enqueue(ctx);
+
+done:
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1,
+ memory_order_relaxed);
+ if (ret == AOK) {
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ } else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1,
+ memory_order_relaxed);
+ if (ctx)
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
+static enum zebra_dplane_result
+tc_filter_update_internal(enum dplane_op_e op, struct zebra_tc_filter *filter)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ /* Obtain context block */
+ ctx = dplane_ctx_alloc();
+
+ if (!ctx) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Init context with info from zebra data structs */
+ ret = dplane_ctx_tc_filter_init(ctx, op, filter);
+
+ if (ret == AOK)
+ ret = dplane_update_enqueue(ctx);
+
+done:
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1,
+ memory_order_relaxed);
+ if (ret == AOK) {
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ } else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1,
+ memory_order_relaxed);
+ if (ctx)
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
+enum zebra_dplane_result dplane_tc_qdisc_install(struct zebra_tc_qdisc *qdisc)
+{
+ return tc_qdisc_update_internal(DPLANE_OP_TC_QDISC_INSTALL, qdisc);
+}
+
+enum zebra_dplane_result dplane_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc)
+{
+ return tc_qdisc_update_internal(DPLANE_OP_TC_QDISC_UNINSTALL, qdisc);
+}
+
+enum zebra_dplane_result dplane_tc_class_add(struct zebra_tc_class *class)
+{
+ return tc_class_update_internal(DPLANE_OP_TC_CLASS_ADD, class);
+}
+
+enum zebra_dplane_result dplane_tc_class_delete(struct zebra_tc_class *class)
+{
+ return tc_class_update_internal(DPLANE_OP_TC_CLASS_DELETE, class);
+}
+
+enum zebra_dplane_result dplane_tc_class_update(struct zebra_tc_class *class)
+{
+ return tc_class_update_internal(DPLANE_OP_TC_CLASS_UPDATE, class);
+}
+
+enum zebra_dplane_result dplane_tc_filter_add(struct zebra_tc_filter *filter)
+{
+ return tc_filter_update_internal(DPLANE_OP_TC_FILTER_ADD, filter);
+}
+
+enum zebra_dplane_result dplane_tc_filter_delete(struct zebra_tc_filter *filter)
+{
+ return tc_filter_update_internal(DPLANE_OP_TC_FILTER_DELETE, filter);
+}
+
+enum zebra_dplane_result dplane_tc_filter_update(struct zebra_tc_filter *filter)
+{
+ return tc_filter_update_internal(DPLANE_OP_TC_FILTER_UPDATE, filter);
}
/**
@@ -3602,12 +3965,11 @@ enum zebra_dplane_result dplane_route_add(struct route_node *rn,
enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
if (rn == NULL || re == NULL)
- goto done;
+ return ret;
ret = dplane_route_update_internal(rn, re, NULL,
DPLANE_OP_ROUTE_INSTALL);
-done:
return ret;
}
@@ -3621,11 +3983,11 @@ enum zebra_dplane_result dplane_route_update(struct route_node *rn,
enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
if (rn == NULL || re == NULL)
- goto done;
+ return ret;
ret = dplane_route_update_internal(rn, re, old_re,
DPLANE_OP_ROUTE_UPDATE);
-done:
+
return ret;
}
@@ -3638,12 +4000,11 @@ enum zebra_dplane_result dplane_route_delete(struct route_node *rn,
enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
if (rn == NULL || re == NULL)
- goto done;
+ return ret;
ret = dplane_route_update_internal(rn, re, NULL,
DPLANE_OP_ROUTE_DELETE);
-done:
return ret;
}
@@ -3656,18 +4017,16 @@ enum zebra_dplane_result dplane_sys_route_add(struct route_node *rn,
enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
/* Ignore this event unless a provider plugin has requested it. */
- if (!zdplane_info.dg_sys_route_notifs) {
- ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
- goto done;
- }
+ if (!zdplane_info.dg_sys_route_notifs)
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+
if (rn == NULL || re == NULL)
- goto done;
+ return ret;
ret = dplane_route_update_internal(rn, re, NULL,
DPLANE_OP_SYS_ROUTE_ADD);
-done:
return ret;
}
@@ -3680,18 +4039,15 @@ enum zebra_dplane_result dplane_sys_route_del(struct route_node *rn,
enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
/* Ignore this event unless a provider plugin has requested it. */
- if (!zdplane_info.dg_sys_route_notifs) {
- ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
- goto done;
- }
+ if (!zdplane_info.dg_sys_route_notifs)
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
if (rn == NULL || re == NULL)
- goto done;
+ return ret;
ret = dplane_route_update_internal(rn, re, NULL,
DPLANE_OP_SYS_ROUTE_DELETE);
-done:
return ret;
}
@@ -5733,10 +6089,18 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
break;
/* TODO: more detailed log */
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
- zlog_debug("Dplane tc ifidx %u", dplane_ctx_get_ifindex(ctx));
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ zlog_debug("Dplane tc qdisc ifidx %u",
+ dplane_ctx_get_ifindex(ctx));
+ break;
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ break;
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
break;
}
}
@@ -5881,9 +6245,14 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
1, memory_order_relaxed);
break;
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors,
1, memory_order_relaxed);
@@ -5933,6 +6302,20 @@ kernel_dplane_process_ipset_entry(struct zebra_dplane_provider *prov,
dplane_provider_enqueue_out_ctx(prov, ctx);
}
+void dplane_rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
+ struct prefix_ipv6 *src_p, struct route_entry *re,
+ struct nexthop_group *ng, int startup,
+ struct zebra_dplane_ctx *ctx)
+{
+ if (!ctx)
+ rib_add_multipath(afi, safi, p, src_p, re, ng, startup);
+ else {
+ dplane_ctx_route_init_basic(ctx, dplane_ctx_get_op(ctx), re, p,
+ src_p, afi, safi);
+ dplane_provider_enqueue_to_zebra(ctx);
+ }
+}
+
/*
* Kernel provider callback
*/
@@ -6109,7 +6492,7 @@ int dplane_clean_ctx_queue(bool (*context_cb)(struct zebra_dplane_ctx *ctx,
TAILQ_INIT(&work_list);
if (context_cb == NULL)
- goto done;
+ return AOK;
/* Walk the pending context queue under the dplane lock. */
DPLANE_LOCK();
@@ -6133,9 +6516,7 @@ int dplane_clean_ctx_queue(bool (*context_cb)(struct zebra_dplane_ctx *ctx,
dplane_ctx_fini(&ctx);
}
-done:
-
- return 0;
+ return AOK;
}
/* Indicates zebra shutdown/exit is in progress. Some operations may be
@@ -6199,10 +6580,8 @@ static bool dplane_work_pending(void)
}
DPLANE_UNLOCK();
- if (ctx != NULL) {
- ret = true;
- goto done;
- }
+ if (ctx != NULL)
+ return true;
while (prov) {
@@ -6225,7 +6604,6 @@ static bool dplane_work_pending(void)
if (ctx != NULL)
ret = true;
-done:
return ret;
}
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 8b239a9ba1..51f6f3d897 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -195,9 +195,14 @@ enum dplane_op_e {
DPLANE_OP_INTF_DELETE,
/* Traffic control */
- DPLANE_OP_TC_INSTALL,
- DPLANE_OP_TC_UPDATE,
- DPLANE_OP_TC_DELETE,
+ DPLANE_OP_TC_QDISC_INSTALL,
+ DPLANE_OP_TC_QDISC_UNINSTALL,
+ DPLANE_OP_TC_CLASS_ADD,
+ DPLANE_OP_TC_CLASS_DELETE,
+ DPLANE_OP_TC_CLASS_UPDATE,
+ DPLANE_OP_TC_FILTER_ADD,
+ DPLANE_OP_TC_FILTER_DELETE,
+ DPLANE_OP_TC_FILTER_UPDATE
};
/*
@@ -375,6 +380,8 @@ route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx);
uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance);
uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_get_flags(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_flags(struct zebra_dplane_ctx *ctx, uint32_t flags);
uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx);
@@ -384,14 +391,42 @@ void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance);
uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx);
/* Accessors for traffic control context */
-uint64_t dplane_ctx_tc_get_rate(const struct zebra_dplane_ctx *ctx);
-uint64_t dplane_ctx_tc_get_ceil(const struct zebra_dplane_ctx *ctx);
-uint32_t dplane_ctx_tc_get_filter_bm(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_tc_qdisc_get_kind(const struct zebra_dplane_ctx *ctx);
+const char *
+dplane_ctx_tc_qdisc_get_kind_str(const struct zebra_dplane_ctx *ctx);
+
+uint32_t dplane_ctx_tc_class_get_handle(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_tc_class_get_kind(const struct zebra_dplane_ctx *ctx);
+const char *
+dplane_ctx_tc_class_get_kind_str(const struct zebra_dplane_ctx *ctx);
+uint64_t dplane_ctx_tc_class_get_rate(const struct zebra_dplane_ctx *ctx);
+uint64_t dplane_ctx_tc_class_get_ceil(const struct zebra_dplane_ctx *ctx);
+
+int dplane_ctx_tc_filter_get_kind(const struct zebra_dplane_ctx *ctx);
+const char *
+dplane_ctx_tc_filter_get_kind_str(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_tc_filter_get_priority(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_tc_filter_get_handle(const struct zebra_dplane_ctx *ctx);
+uint16_t dplane_ctx_tc_filter_get_minor(const struct zebra_dplane_ctx *ctx);
+uint16_t dplane_ctx_tc_filter_get_eth_proto(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_tc_filter_get_filter_bm(const struct zebra_dplane_ctx *ctx);
const struct prefix *
-dplane_ctx_tc_get_src_ip(const struct zebra_dplane_ctx *ctx);
+dplane_ctx_tc_filter_get_src_ip(const struct zebra_dplane_ctx *ctx);
+uint16_t
+dplane_ctx_tc_filter_get_src_port_min(const struct zebra_dplane_ctx *ctx);
+uint16_t
+dplane_ctx_tc_filter_get_src_port_max(const struct zebra_dplane_ctx *ctx);
const struct prefix *
-dplane_ctx_tc_get_dst_ip(const struct zebra_dplane_ctx *ctx);
-uint8_t dplane_ctx_tc_get_ip_proto(const struct zebra_dplane_ctx *ctx);
+dplane_ctx_tc_filter_get_dst_ip(const struct zebra_dplane_ctx *ctx);
+uint16_t
+dplane_ctx_tc_filter_get_dst_port_min(const struct zebra_dplane_ctx *ctx);
+uint16_t
+dplane_ctx_tc_filter_get_dst_port_max(const struct zebra_dplane_ctx *ctx);
+uint8_t dplane_ctx_tc_filter_get_ip_proto(const struct zebra_dplane_ctx *ctx);
+uint8_t dplane_ctx_tc_filter_get_dsfield(const struct zebra_dplane_ctx *ctx);
+uint8_t
+dplane_ctx_tc_filter_get_dsfield_mask(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_tc_filter_get_classid(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh);
void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx,
@@ -723,11 +758,23 @@ enum zebra_dplane_result dplane_intf_update(const struct interface *ifp);
enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp);
/*
- * Enqueue interface link changes for the dataplane.
+ * Enqueue tc link changes for the dataplane.
*/
-enum zebra_dplane_result dplane_tc_add(void);
-enum zebra_dplane_result dplane_tc_update(void);
-enum zebra_dplane_result dplane_tc_delete(void);
+
+struct zebra_tc_qdisc;
+struct zebra_tc_class;
+struct zebra_tc_filter;
+enum zebra_dplane_result dplane_tc_qdisc_install(struct zebra_tc_qdisc *qdisc);
+enum zebra_dplane_result
+dplane_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc);
+enum zebra_dplane_result dplane_tc_class_add(struct zebra_tc_class *class);
+enum zebra_dplane_result dplane_tc_class_delete(struct zebra_tc_class *class);
+enum zebra_dplane_result dplane_tc_class_update(struct zebra_tc_class *class);
+enum zebra_dplane_result dplane_tc_filter_add(struct zebra_tc_filter *filter);
+enum zebra_dplane_result
+dplane_tc_filter_delete(struct zebra_tc_filter *filter);
+enum zebra_dplane_result
+dplane_tc_filter_update(struct zebra_tc_filter *filter);
/*
* Link layer operations for the dataplane.
@@ -863,6 +910,12 @@ dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset);
int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
struct route_node *rn, struct route_entry *re);
+int dplane_ctx_route_init_basic(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op, struct route_entry *re,
+ const struct prefix *p,
+ const struct prefix_ipv6 *src_p, afi_t afi,
+ safi_t safi);
+
/* Encode next hop information into data plane context. */
int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
struct nhg_hash_entry *nhe);
@@ -1028,6 +1081,16 @@ void zebra_dplane_pre_finish(void);
void zebra_dplane_finish(void);
void zebra_dplane_shutdown(void);
+/*
+ * decision point for sending a routing update through the old
+ * straight to zebra master pthread or through the dplane to
+ * the master pthread for handling
+ */
+void dplane_rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
+ struct prefix_ipv6 *src_p, struct route_entry *re,
+ struct nexthop_group *ng, int startup,
+ struct zebra_dplane_ctx *ctx);
+
#ifdef __cplusplus
}
#endif
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index ca897251e2..5cefa16cdd 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -539,10 +539,15 @@ static void zfpm_log_route_info(struct netlink_route_info *ri,
for (i = 0; i < ri->num_nhs; i++) {
nhi = &ri->nhs[i];
- if (ri->af == AF_INET)
- inet_ntop(AF_INET, &nhi->gateway, buf, sizeof(buf));
- else
- inet_ntop(AF_INET6, &nhi->gateway, buf, sizeof(buf));
+ if (nhi->gateway) {
+ if (ri->af == AF_INET)
+ inet_ntop(AF_INET, nhi->gateway, buf,
+ sizeof(buf));
+ else
+ inet_ntop(AF_INET6, nhi->gateway, buf,
+ sizeof(buf));
+ } else
+ strlcpy(buf, "none", sizeof(buf));
zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s, Encap type: %s",
nhi->if_index, buf, nhi->recursive ? "yes" : "no",
diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c
index 56d0df569c..d3c104cc80 100644
--- a/zebra/zebra_gr.c
+++ b/zebra/zebra_gr.c
@@ -46,6 +46,7 @@
#include "zebra/debug.h"
#include "zebra/zapi_msg.h"
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_GR, "GR");
/*
* Forward declaration.
@@ -111,7 +112,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client)
{
struct client_gr_info *info;
- info = XCALLOC(MTYPE_TMP, sizeof(struct client_gr_info));
+ info = XCALLOC(MTYPE_ZEBRA_GR, sizeof(struct client_gr_info));
TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info);
return info;
@@ -127,7 +128,7 @@ static void zebra_gr_client_info_delte(struct zserv *client,
THREAD_OFF(info->t_stale_removal);
- XFREE(MTYPE_TMP, info->current_prefix);
+ XFREE(MTYPE_ZEBRA_GR, info->current_prefix);
LOG_GR("%s: Instance info is being deleted for client %s", __func__,
zebra_route_string(client->proto));
@@ -136,7 +137,7 @@ static void zebra_gr_client_info_delte(struct zserv *client,
info->do_delete = true;
zebra_gr_delete_stale_routes(info);
- XFREE(MTYPE_TMP, info);
+ XFREE(MTYPE_ZEBRA_GR, info);
}
/*
@@ -222,8 +223,8 @@ static void zebra_gr_delete_stale_client(struct client_gr_info *info)
TAILQ_INIT(&(s_client->gr_info_queue));
listnode_delete(zrouter.stale_client_list, s_client);
if (info->stale_client)
- XFREE(MTYPE_TMP, s_client);
- XFREE(MTYPE_TMP, info);
+ zserv_client_delete(s_client);
+ XFREE(MTYPE_ZEBRA_GR, info);
}
/*
@@ -288,7 +289,7 @@ void zebra_gr_client_reconnect(struct zserv *client)
/* Delete the stale client */
listnode_delete(zrouter.stale_client_list, old_client);
/* Delete old client */
- XFREE(MTYPE_TMP, old_client);
+ zserv_client_delete(old_client);
}
/*
@@ -474,7 +475,7 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct thread *thread)
LOG_GR("%s: Client %s all stale routes processed", __func__,
zebra_route_string(client->proto));
- XFREE(MTYPE_TMP, info->current_prefix);
+ XFREE(MTYPE_ZEBRA_GR, info->current_prefix);
info->current_afi = 0;
zebra_gr_delete_stale_client(info);
}
@@ -579,7 +580,7 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info,
&& (info->do_delete == false)) {
info->current_afi = afi;
info->current_prefix = XCALLOC(
- MTYPE_TMP,
+ MTYPE_ZEBRA_GR,
sizeof(struct prefix));
prefix_copy(
info->current_prefix,
@@ -593,7 +594,7 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info,
* Reset the current prefix to indicate processing completion
* of the current AFI
*/
- XFREE(MTYPE_TMP, info->current_prefix);
+ XFREE(MTYPE_ZEBRA_GR, info->current_prefix);
}
return 0;
}
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 9756d9ba08..fe3f77f3c7 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -1754,7 +1754,6 @@ static void mpls_processq_init(void)
zrouter.lsp_process_q->spec.workfunc = &lsp_process;
zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
- zrouter.lsp_process_q->spec.errorfunc = NULL;
zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
zrouter.lsp_process_q->spec.max_retries = 0;
zrouter.lsp_process_q->spec.hold = 10;
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 5fadd4c82b..286cc0292d 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -3168,9 +3168,14 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
break;
}
}
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 13fd972499..7b076b8a4a 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -34,6 +34,7 @@
#include "zebra_netns_notify.h"
#include "zebra_netns_id.h"
#include "zebra_pbr.h"
+#include "zebra_tc.h"
#include "rib.h"
#include "table_manager.h"
#include "zebra_errors.h"
@@ -127,6 +128,7 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
interface_list(zns);
route_read(zns);
kernel_read_pbr_rules(zns);
+ kernel_read_tc_qdisc(zns);
return 0;
}
@@ -136,7 +138,9 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
*/
static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
{
- route_table_finish(zns->if_table);
+ if (zns->if_table)
+ route_table_finish(zns->if_table);
+ zns->if_table = NULL;
zebra_dplane_ns_enable(zns, false /*Disable*/);
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index 43e21a6d34..405241fc22 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -36,6 +36,7 @@
/* definitions */
DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list");
+DEFINE_MTYPE(ZEBRA, PBR_OBJ, "PBR");
/* definitions */
static const struct message ipset_type_msg[] = {
@@ -163,7 +164,7 @@ void zebra_pbr_rules_free(void *arg)
rule = (struct zebra_pbr_rule *)arg;
(void)dplane_pbr_rule_delete(rule);
- XFREE(MTYPE_TMP, rule);
+ XFREE(MTYPE_PBR_OBJ, rule);
}
uint32_t zebra_pbr_rules_hash_key(const void *arg)
@@ -275,7 +276,7 @@ void zebra_pbr_ipset_free(void *arg)
ipset = (struct zebra_pbr_ipset *)arg;
hook_call(zebra_pbr_ipset_update, 0, ipset);
- XFREE(MTYPE_TMP, ipset);
+ XFREE(MTYPE_PBR_OBJ, ipset);
}
uint32_t zebra_pbr_ipset_hash_key(const void *arg)
@@ -319,7 +320,7 @@ void zebra_pbr_ipset_entry_free(void *arg)
hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
- XFREE(MTYPE_TMP, ipset);
+ XFREE(MTYPE_PBR_OBJ, ipset);
}
uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg)
@@ -396,7 +397,7 @@ static void _zebra_pbr_iptable_free_all(void *arg, bool all)
}
list_delete(&iptable->interface_name_list);
}
- XFREE(MTYPE_TMP, iptable);
+ XFREE(MTYPE_PBR_OBJ, iptable);
}
void zebra_pbr_iptable_free(void *arg)
@@ -478,7 +479,7 @@ static void *pbr_rule_alloc_intern(void *arg)
zpr = (struct zebra_pbr_rule *)arg;
- new = XCALLOC(MTYPE_TMP, sizeof(*new));
+ new = XCALLOC(MTYPE_PBR_OBJ, sizeof(*new));
memcpy(new, zpr, sizeof(*zpr));
@@ -492,7 +493,7 @@ static struct zebra_pbr_rule *pbr_rule_free(struct zebra_pbr_rule *hash_data,
zebra_neigh_deref(hash_data);
hash_release(zrouter.rules_hash, hash_data);
if (free_data) {
- XFREE(MTYPE_TMP, hash_data);
+ XFREE(MTYPE_PBR_OBJ, hash_data);
return NULL;
}
@@ -688,7 +689,7 @@ void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
(void)dplane_pbr_rule_update(found, new);
/* release the old hash data */
if (old)
- XFREE(MTYPE_TMP, old);
+ XFREE(MTYPE_PBR_OBJ, old);
} else {
if (IS_ZEBRA_DEBUG_PBR)
zlog_debug(
@@ -856,7 +857,7 @@ static void *pbr_ipset_alloc_intern(void *arg)
zpi = (struct zebra_pbr_ipset *)arg;
- new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset));
+ new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset));
memcpy(new, zpi, sizeof(*zpi));
@@ -877,7 +878,7 @@ void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset)
(void)dplane_pbr_ipset_delete(ipset);
if (lookup) {
hash_release(zrouter.ipset_hash, lookup);
- XFREE(MTYPE_TMP, lookup);
+ XFREE(MTYPE_PBR_OBJ, lookup);
} else
zlog_debug(
"%s: IPSet Entry being deleted we know nothing about",
@@ -930,7 +931,7 @@ static void *pbr_ipset_entry_alloc_intern(void *arg)
zpi = (struct zebra_pbr_ipset_entry *)arg;
- new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry));
+ new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset_entry));
memcpy(new, zpi, sizeof(*zpi));
@@ -952,7 +953,7 @@ void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
(void)dplane_pbr_ipset_entry_delete(ipset);
if (lookup) {
hash_release(zrouter.ipset_entry_hash, lookup);
- XFREE(MTYPE_TMP, lookup);
+ XFREE(MTYPE_PBR_OBJ, lookup);
} else
zlog_debug("%s: IPSet being deleted we know nothing about",
__func__);
@@ -967,7 +968,7 @@ static void *pbr_iptable_alloc_intern(void *arg)
zpi = (struct zebra_pbr_iptable *)arg;
- new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
+ new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable));
/* Deep structure copy */
memcpy(new, zpi, sizeof(*zpi));
@@ -1009,7 +1010,7 @@ void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable)
node);
}
list_delete(&iptable->interface_name_list);
- XFREE(MTYPE_TMP, lookup);
+ XFREE(MTYPE_PBR_OBJ, lookup);
} else
zlog_debug("%s: IPTable being deleted we know nothing about",
__func__);
diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h
index baa8755fa5..60457914cc 100644
--- a/zebra/zebra_pbr.h
+++ b/zebra/zebra_pbr.h
@@ -36,6 +36,9 @@
extern "C" {
#endif
+/* Memory type for PBR objects. */
+DECLARE_MTYPE(PBR_OBJ);
+
struct zebra_pbr_action {
afi_t afi;
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 54ef4768eb..9551f26d80 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1523,8 +1523,7 @@ static bool rib_route_match_ctx(const struct route_entry *re,
}
done:
-
- return (result);
+ return result;
}
static void zebra_rib_fixup_system(struct route_node *rn)
@@ -2261,10 +2260,8 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
}
/* Ensure we clear the QUEUED flag */
- if (!zrouter.asic_offloaded) {
- UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
- UNSET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING);
- }
+ UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ UNSET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING);
/* Is this a notification that ... matters? We mostly care about
* the route that is currently selected for installation; we may also
@@ -2307,6 +2304,19 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
dplane_ctx_get_type(ctx)));
}
goto done;
+ } else {
+ uint32_t flags = dplane_ctx_get_flags(ctx);
+
+ if (CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOADED)) {
+ UNSET_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED);
+ SET_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED);
+ }
+ if (CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOAD_FAILED)) {
+ UNSET_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED);
+ SET_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED);
+ }
+ if (CHECK_FLAG(flags, ZEBRA_FLAG_TRAPPED))
+ SET_FLAG(re->flags, ZEBRA_FLAG_TRAPPED);
}
/* We'll want to determine whether the installation status of the
@@ -2340,55 +2350,70 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
/* Various fib transitions: changed nexthops; from installed to
* not-installed; or not-installed to installed.
*/
- if (start_count > 0 && end_count > 0) {
- if (debug_p)
- zlog_debug(
- "%s(%u:%u):%pRN applied nexthop changes from dplane notification",
- VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
- dplane_ctx_get_table(ctx), rn);
+ if (zrouter.asic_notification_nexthop_control) {
+ if (start_count > 0 && end_count > 0) {
+ if (debug_p)
+ zlog_debug(
+ "%s(%u:%u):%pRN applied nexthop changes from dplane notification",
+ VRF_LOGNAME(vrf),
+ dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(ctx), rn);
- /* Changed nexthops - update kernel/others */
- dplane_route_notif_update(rn, re,
- DPLANE_OP_ROUTE_UPDATE, ctx);
+ /* Changed nexthops - update kernel/others */
+ dplane_route_notif_update(rn, re,
+ DPLANE_OP_ROUTE_UPDATE, ctx);
- } else if (start_count == 0 && end_count > 0) {
- if (debug_p)
- zlog_debug(
- "%s(%u:%u):%pRN installed transition from dplane notification",
- VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
- dplane_ctx_get_table(ctx), rn);
+ } else if (start_count == 0 && end_count > 0) {
+ if (debug_p)
+ zlog_debug(
+ "%s(%u:%u):%pRN installed transition from dplane notification",
+ VRF_LOGNAME(vrf),
+ dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(ctx), rn);
- /* We expect this to be the selected route, so we want
- * to tell others about this transition.
- */
- SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ /* We expect this to be the selected route, so we want
+ * to tell others about this transition.
+ */
+ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
- /* Changed nexthops - update kernel/others */
- dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_UPDATE, ctx);
+ /* Changed nexthops - update kernel/others */
+ dplane_route_notif_update(rn, re,
+ DPLANE_OP_ROUTE_UPDATE, ctx);
- /* Redistribute, lsp, and nht update */
- redistribute_update(rn, re, NULL);
+ /* Redistribute, lsp, and nht update */
+ redistribute_update(rn, re, NULL);
- } else if (start_count > 0 && end_count == 0) {
- if (debug_p)
- zlog_debug(
- "%s(%u:%u):%pRN un-installed transition from dplane notification",
- VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
- dplane_ctx_get_table(ctx), rn);
+ } else if (start_count > 0 && end_count == 0) {
+ if (debug_p)
+ zlog_debug(
+ "%s(%u:%u):%pRN un-installed transition from dplane notification",
+ VRF_LOGNAME(vrf),
+ dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(ctx), rn);
- /* Transition from _something_ installed to _nothing_
- * installed.
- */
- /* We expect this to be the selected route, so we want
- * to tell others about this transistion.
- */
- UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ /* Transition from _something_ installed to _nothing_
+ * installed.
+ */
+ /* We expect this to be the selected route, so we want
+ * to tell others about this transistion.
+ */
+ UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
- /* Changed nexthops - update kernel/others */
- dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_DELETE, ctx);
+ /* Changed nexthops - update kernel/others */
+ dplane_route_notif_update(rn, re,
+ DPLANE_OP_ROUTE_DELETE, ctx);
- /* Redistribute, lsp, and nht update */
- redistribute_delete(rn, re, NULL);
+ /* Redistribute, lsp, and nht update */
+ redistribute_delete(rn, re, NULL);
+ }
+ }
+
+ if (!zebra_router_notify_on_ack()) {
+ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED))
+ zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED);
+ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED))
+ zsend_route_notify_owner_ctx(ctx,
+ ZAPI_ROUTE_FAIL_INSTALL);
}
/* Make any changes visible for lsp and nexthop-tracking processing */
@@ -3656,14 +3681,14 @@ 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)
{
- struct zebra_early_route *zer;
+ struct zebra_early_route *ere;
struct listnode *node, *nnode;
- for (ALL_LIST_ELEMENTS(l, node, nnode, zer)) {
- if (zvrf && zer->re->vrf_id != zvrf->vrf->vrf_id)
+ for (ALL_LIST_ELEMENTS(l, node, nnode, ere)) {
+ if (zvrf && ere->re->vrf_id != zvrf->vrf->vrf_id)
continue;
- XFREE(MTYPE_RE, zer);
+ early_route_memory_free(ere);
node->data = NULL;
list_delete_node(l, node);
mq->size--;
@@ -3718,7 +3743,6 @@ static void rib_queue_init(void)
/* fill in the work queue spec */
zrouter.ribq->spec.workfunc = &meta_queue_process;
- zrouter.ribq->spec.errorfunc = NULL;
zrouter.ribq->spec.completion_func = NULL;
/* XXX: TODO: These should be runtime configurable via vty */
zrouter.ribq->spec.max_retries = 3;
@@ -4710,9 +4734,14 @@ static void rib_process_dplane_results(struct thread *thread)
zebra_if_dplane_result(ctx);
break;
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
break;
/* Some op codes not handled here */
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 7934a9d206..599c679864 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -62,7 +62,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
static void copy_state(struct rnh *rnh, const struct route_entry *re,
struct route_node *rn);
static bool compare_state(struct route_entry *r1, struct route_entry *r2);
-static void print_rnh(struct route_node *rn, struct vty *vty);
+static void print_rnh(struct route_node *rn, struct vty *vty,
+ json_object *json);
static int zebra_client_cleanup_rnh(struct zserv *client);
void zebra_rnh_init(void)
@@ -803,7 +804,8 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
}
void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
- struct vty *vty, const struct prefix *p)
+ struct vty *vty, const struct prefix *p,
+ json_object *json)
{
struct route_table *table;
struct route_node *rn;
@@ -820,7 +822,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
continue;
if (rn->info)
- print_rnh(rn, vty);
+ print_rnh(rn, vty, json);
}
}
@@ -1268,73 +1270,178 @@ failure:
return -1;
}
-static void print_nh(struct nexthop *nexthop, struct vty *vty)
+static void print_nh(struct nexthop *nexthop, struct vty *vty,
+ json_object *json)
{
- char buf[BUFSIZ];
struct zebra_ns *zns = zebra_ns_lookup(nexthop->vrf_id);
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ if (json) {
+ json_object_string_addf(json, "ip", "%pI4",
+ &nexthop->gate.ipv4);
+ if (nexthop->ifindex)
+ json_object_string_add(
+ json, "interface",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ } else {
+ vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
+ if (nexthop->ifindex)
+ vty_out(vty, ", %s",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ }
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
- if (nexthop->ifindex)
- vty_out(vty, ", via %s",
- ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ if (json) {
+ json_object_string_addf(json, "ip", "%pI6",
+ &nexthop->gate.ipv6);
+ if (nexthop->ifindex)
+ json_object_string_add(
+ json, "interface",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ } else {
+ vty_out(vty, " %pI6", &nexthop->gate.ipv6);
+ if (nexthop->ifindex)
+ vty_out(vty, ", via %s",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ }
break;
case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " is directly connected, %s",
- ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ if (json) {
+ json_object_string_add(
+ json, "interface",
+ ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ json_object_boolean_true_add(json, "directlyConnected");
+ } else {
+ vty_out(vty, " is directly connected, %s",
+ ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ }
break;
case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " is directly connected, Null0");
+ if (json) {
+ json_object_string_add(json, "interface", "Null0");
+ json_object_boolean_true_add(json, "directlyConnected");
+ } else {
+ vty_out(vty, " is directly connected, Null0");
+ }
break;
default:
break;
}
- vty_out(vty, "\n");
+
+ if (!json)
+ vty_out(vty, "\n");
}
-static void print_rnh(struct route_node *rn, struct vty *vty)
+static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json)
{
struct rnh *rnh;
struct nexthop *nexthop;
struct listnode *node;
struct zserv *client;
char buf[BUFSIZ];
+ json_object *json_nht = NULL;
+ json_object *json_client_array = NULL;
+ json_object *json_client = NULL;
+ json_object *json_nexthop_array = NULL;
+ json_object *json_nexthop = NULL;
rnh = rn->info;
- vty_out(vty, "%s%s\n",
- inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
- CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)"
- : "");
- if (rnh->state) {
- vty_out(vty, " resolved via %s\n",
- zebra_route_string(rnh->state->type));
- for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
- nexthop = nexthop->next)
- print_nh(nexthop, vty);
- } else
- vty_out(vty, " unresolved%s\n",
+
+ if (json) {
+ json_nht = json_object_new_object();
+ json_nexthop_array = json_object_new_array();
+ json_client_array = json_object_new_array();
+
+ json_object_object_add(
+ json,
+ inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
+ json_nht);
+ json_object_boolean_add(
+ json_nht, "nhtConnected",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED));
+ json_object_object_add(json_nht, "clientList",
+ json_client_array);
+ json_object_object_add(json_nht, "gates", json_nexthop_array);
+ } else {
+ vty_out(vty, "%s%s\n",
+ inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
? "(Connected)"
: "");
+ }
+
+ if (rnh->state) {
+ 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));
+
+ for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
+ nexthop = nexthop->next) {
+ if (json) {
+ json_nexthop = json_object_new_object();
+ json_object_array_add(json_nexthop_array,
+ json_nexthop);
+ }
+ print_nh(nexthop, vty, json_nexthop);
+ }
+ } else {
+ if (json)
+ json_object_boolean_add(
+ json_nht, "unresolved",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED));
+ else
+ vty_out(vty, " unresolved%s\n",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
+ ? "(Connected)"
+ : "");
+ }
+
+ if (!json)
+ vty_out(vty, " Client list:");
+
+ for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
+ if (json) {
+ json_client = json_object_new_object();
+ json_object_array_add(json_client_array, json_client);
+
+ json_object_string_add(
+ json_client, "protocol",
+ zebra_route_string(client->proto));
+ json_object_int_add(json_client, "socket",
+ client->sock);
+ json_object_string_add(json_client, "protocolFiltered",
+ (rnh->filtered[client->proto]
+ ? "(filtered)"
+ : "none"));
+ } else {
+ vty_out(vty, " %s(fd %d)%s",
+ zebra_route_string(client->proto), client->sock,
+ rnh->filtered[client->proto] ? "(filtered)"
+ : "");
+ }
+ }
+
+ if (!list_isempty(rnh->zebra_pseudowire_list)) {
+ if (json)
+ json_object_boolean_true_add(json_nht,
+ "zebraPseudowires");
+ else
+ vty_out(vty, " zebra[pseudowires]");
+ }
- vty_out(vty, " Client list:");
- for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
- vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
- client->sock,
- rnh->filtered[client->proto] ? "(filtered)" : "");
- if (!list_isempty(rnh->zebra_pseudowire_list))
- vty_out(vty, " zebra[pseudowires]");
- vty_out(vty, "\n");
+ if (!json)
+ vty_out(vty, "\n");
}
static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, safi_t safi,
diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h
index 70eda725c4..44ce65b4b6 100644
--- a/zebra/zebra_rnh.h
+++ b/zebra/zebra_rnh.h
@@ -46,7 +46,8 @@ extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client);
extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
const struct prefix *p, safi_t safi);
extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
- struct vty *vty, const struct prefix *p);
+ struct vty *vty, const struct prefix *p,
+ json_object *json);
extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family);
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 13d1995d58..4f43cea493 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -143,26 +143,48 @@ static void show_vrf_proto_rm(struct vty *vty, struct zebra_vrf *zvrf,
}
static void show_vrf_nht_rm(struct vty *vty, struct zebra_vrf *zvrf,
- int af_type)
+ int af_type, json_object *json)
{
int i;
- vty_out(vty, "Protocol : route-map\n");
- vty_out(vty, "-------------------------------------\n");
+ if (!json) {
+ vty_out(vty, "Protocol : route-map\n");
+ vty_out(vty, "-------------------------------------\n");
+ }
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+ if (json) {
+ if (NHT_RM_NAME(zvrf, af_type, i))
+ json_object_string_add(
+ json, zebra_route_string(i),
+ NHT_RM_NAME(zvrf, af_type, i));
+ else
+ json_object_string_add(
+ json, zebra_route_string(i), "none");
+ } else {
+ if (NHT_RM_NAME(zvrf, af_type, i))
+ vty_out(vty, "%-24s : %-10s\n",
+ zebra_route_string(i),
+ NHT_RM_NAME(zvrf, af_type, i));
+ else
+ vty_out(vty, "%-24s : none\n",
+ zebra_route_string(i));
+ }
+ }
+
+ if (json) {
if (NHT_RM_NAME(zvrf, af_type, i))
- vty_out(vty, "%-24s : %-10s\n", zebra_route_string(i),
+ json_object_string_add(json, "any",
+ NHT_RM_NAME(zvrf, af_type, i));
+ else
+ json_object_string_add(json, "any", "none");
+ } else {
+ if (NHT_RM_NAME(zvrf, af_type, i))
+ vty_out(vty, "%-24s : %-10s\n", "any",
NHT_RM_NAME(zvrf, af_type, i));
else
- vty_out(vty, "%-24s : none\n", zebra_route_string(i));
+ vty_out(vty, "%-24s : none\n", "any");
}
-
- if (NHT_RM_NAME(zvrf, af_type, i))
- vty_out(vty, "%-24s : %-10s\n", "any",
- NHT_RM_NAME(zvrf, af_type, i));
- else
- vty_out(vty, "%-24s : none\n", "any");
}
static int show_proto_rm(struct vty *vty, int af_type, const char *vrf_all,
@@ -198,35 +220,78 @@ static int show_proto_rm(struct vty *vty, int af_type, const char *vrf_all,
}
static int show_nht_rm(struct vty *vty, int af_type, const char *vrf_all,
- const char *vrf_name)
+ const char *vrf_name, bool use_json)
{
struct zebra_vrf *zvrf;
+ json_object *json = NULL;
+ json_object *json_vrfs = NULL;
+
+ if (use_json) {
+ json = json_object_new_object();
+ json_vrfs = json_object_new_object();
+ json_object_string_add(json, "afi",
+ (af_type == AFI_IP) ? "ipv4" : "ipv6");
+ }
if (vrf_all) {
struct vrf *vrf;
+ if (use_json)
+ json_object_object_add(json, "vrfs", json_vrfs);
+
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
zvrf = (struct zebra_vrf *)vrf->info;
if (zvrf == NULL)
continue;
- vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
- show_vrf_nht_rm(vty, zvrf, af_type);
+ if (use_json) {
+ json_object *json_proto = NULL;
+ json_object *json_vrf = NULL;
+ json_vrf = json_object_new_object();
+ json_object_object_add(
+ json_vrfs, zvrf->vrf->name, json_vrf);
+ json_proto = json_object_new_object();
+ json_object_object_add(json_vrf, "protocols",
+ json_proto);
+ show_vrf_nht_rm(vty, zvrf, af_type, json_proto);
+ } else {
+ vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
+ show_vrf_nht_rm(vty, zvrf, af_type, NULL);
+ }
}
} else {
+ json_object *json_proto = NULL;
+ json_object *json_vrf = NULL;
vrf_id_t vrf_id = VRF_DEFAULT;
if (vrf_name)
VRF_GET_ID(vrf_id, vrf_name, false);
zvrf = zebra_vrf_lookup_by_id(vrf_id);
- if (!zvrf)
+ if (!zvrf) {
+ json_object_free(json);
+ json_object_free(json_vrfs);
return CMD_SUCCESS;
+ }
- vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
- show_vrf_nht_rm(vty, zvrf, af_type);
+ if (use_json) {
+ json_object_object_add(json, "vrfs", json_vrfs);
+ json_vrf = json_object_new_object();
+ json_object_object_add(json_vrfs, zvrf->vrf->name,
+ json_vrf);
+ json_proto = json_object_new_object();
+ json_object_object_add(json_vrf, "protocols",
+ json_proto);
+ show_vrf_nht_rm(vty, zvrf, af_type, json_proto);
+ } else {
+ vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
+ show_vrf_nht_rm(vty, zvrf, af_type, NULL);
+ }
}
+ if (use_json)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}
@@ -854,14 +919,19 @@ DEFPY_YANG (no_ip_protocol_nht_rmap,
DEFPY_YANG (show_ip_protocol_nht,
show_ip_protocol_nht_cmd,
- "show ip nht route-map [vrf <NAME$vrf_name|all$vrf_all>]",
+ "show ip nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]",
SHOW_STR
IP_STR
- "IP nexthop tracking table\n"
- "IP Next Hop tracking filtering status\n"
- VRF_FULL_CMD_HELP_STR)
+ "IPv4 nexthop tracking table\n"
+ "IPv4 Next Hop tracking filtering status\n"
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ JSON_STR)
{
- int ret = show_nht_rm(vty, AFI_IP, vrf_all, vrf_name);
+ int ret;
+ bool uj = use_json(argc, argv);
+
+ ret = show_nht_rm(vty, AFI_IP, vrf_all, vrf_name, uj);
return ret;
}
@@ -936,14 +1006,19 @@ DEFPY_YANG (no_ipv6_protocol_nht_rmap,
DEFPY_YANG (show_ipv6_protocol_nht,
show_ipv6_protocol_nht_cmd,
- "show ipv6 nht route-map [vrf <NAME$vrf_name|all$vrf_all>]",
+ "show ipv6 nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]",
SHOW_STR
IP6_STR
- "Next Hop filtering status\n"
- "Route-map\n"
- VRF_FULL_CMD_HELP_STR)
+ "IPv6 nexthop tracking table\n"
+ "IPv6 Next Hop tracking filtering status\n"
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ JSON_STR)
{
- int ret = show_nht_rm(vty, AFI_IP6, vrf_all, vrf_name);
+ int ret;
+ bool uj = use_json(argc, argv);
+
+ ret = show_nht_rm(vty, AFI_IP6, vrf_all, vrf_name, uj);
return ret;
}
@@ -1818,6 +1893,23 @@ static void zebra_route_map_event(const char *rmap_name)
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
+void zebra_routemap_vrf_delete(struct zebra_vrf *zvrf)
+{
+ afi_t afi;
+ uint8_t type;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
+ if (PROTO_RM_NAME(zvrf, afi, type))
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ PROTO_RM_NAME(zvrf, afi, type));
+ if (NHT_RM_NAME(zvrf, afi, type))
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ NHT_RM_NAME(zvrf, afi, type));
+ }
+ }
+}
+
/* ip protocol configuration write function */
void zebra_routemap_config_write_protocol(struct vty *vty,
struct zebra_vrf *zvrf)
diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h
index 3f58e14e10..02b01fa53a 100644
--- a/zebra/zebra_routemap.h
+++ b/zebra/zebra_routemap.h
@@ -50,6 +50,8 @@ zebra_nht_route_map_check(afi_t afi, int client_proto, const struct prefix *p,
struct zebra_vrf *zvrf, struct route_entry *,
struct nexthop *nexthop);
+extern void zebra_routemap_vrf_delete(struct zebra_vrf *zvrf);
+
#ifdef __cplusplus
}
#endif
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index c66849863e..a9a7b66ce7 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -30,6 +30,7 @@
#include "zebra_mlag.h"
#include "zebra_nhg.h"
#include "zebra_neigh.h"
+#include "zebra/zebra_tc.h"
#include "debug.h"
#include "zebra_script.h"
@@ -312,9 +313,34 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack)
hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal,
"Zebra Router Nexthop Groups ID index");
+ zrouter.rules_hash =
+ hash_create_size(8, zebra_pbr_rules_hash_key,
+ zebra_pbr_rules_hash_equal, "Rules Hash");
+
+ zrouter.qdisc_hash =
+ hash_create_size(8, zebra_tc_qdisc_hash_key,
+ zebra_tc_qdisc_hash_equal, "TC (qdisc) Hash");
+ zrouter.class_hash = hash_create_size(8, zebra_tc_class_hash_key,
+ zebra_tc_class_hash_equal,
+ "TC (classes) Hash");
+ zrouter.filter_hash = hash_create_size(8, zebra_tc_filter_hash_key,
+ zebra_tc_filter_hash_equal,
+ "TC (filter) Hash");
+
zrouter.asic_offloaded = asic_offload;
zrouter.notify_on_ack = notify_on_ack;
+ /*
+ * If you start using asic_notification_nexthop_control
+ * come talk to the FRR community about what you are doing
+ * We would like to know.
+ */
+#if CONFDATE > 20251231
+ CPP_NOTICE(
+ "Remove zrouter.asic_notification_nexthop_control as that it's not being maintained or used");
+#endif
+ zrouter.asic_notification_nexthop_control = false;
+
#ifdef HAVE_SCRIPTING
zebra_script_init();
#endif
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index 992bcd5c08..e0ef86f082 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -172,6 +172,10 @@ struct zebra_router {
struct hash *iptable_hash;
+ struct hash *qdisc_hash;
+ struct hash *class_hash;
+ struct hash *filter_hash;
+
/* A sequence number used for tracking routes */
_Atomic uint32_t sequence_num;
@@ -220,6 +224,14 @@ struct zebra_router {
bool asic_offloaded;
bool notify_on_ack;
+ /*
+ * If the asic is notifying us about successful nexthop
+ * allocation/control. Some developers have made their
+ * asic take control of how many nexthops/ecmp they can
+ * have and will report what is successfull or not
+ */
+ bool asic_notification_nexthop_control;
+
bool supports_nhgs;
bool all_mc_forwardingv4, default_mc_forwardingv4;
diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c
index 2e2f4159cd..5c67ad4f16 100644
--- a/zebra/zebra_script.c
+++ b/zebra/zebra_script.c
@@ -417,9 +417,14 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx)
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:
- case DPLANE_OP_TC_INSTALL:
- case DPLANE_OP_TC_UPDATE:
- case DPLANE_OP_TC_DELETE:
+ case DPLANE_OP_TC_QDISC_INSTALL:
+ case DPLANE_OP_TC_QDISC_UNINSTALL:
+ case DPLANE_OP_TC_CLASS_ADD:
+ case DPLANE_OP_TC_CLASS_DELETE:
+ case DPLANE_OP_TC_CLASS_UPDATE:
+ case DPLANE_OP_TC_FILTER_ADD:
+ case DPLANE_OP_TC_FILTER_DELETE:
+ case DPLANE_OP_TC_FILTER_UPDATE:
/* Not currently handled */
case DPLANE_OP_INTF_NETCONFIG: /*NYI*/
case DPLANE_OP_NONE:
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index 1221365d4d..b4fd5f0181 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -276,16 +276,16 @@ DEFUN (no_srv6_locator,
DEFPY (locator_prefix,
locator_prefix_cmd,
- "prefix X:X::X:X/M$prefix [func-bits (0-64)$func_bit_len] \
- [block-len (16-64)$block_bit_len] [node-len (16-64)$node_bit_len]",
+ "prefix X:X::X:X/M$prefix [block-len (16-64)$block_bit_len] \
+ [node-len (16-64)$node_bit_len] [func-bits (0-64)$func_bit_len]",
"Configure SRv6 locator prefix\n"
"Specify SRv6 locator prefix\n"
- "Configure SRv6 locator function length in bits\n"
- "Specify SRv6 locator function length in bits\n"
"Configure SRv6 locator block length in bits\n"
"Specify SRv6 locator block length in bits\n"
"Configure SRv6 locator node length in bits\n"
- "Specify SRv6 locator node length in bits\n")
+ "Specify SRv6 locator node length in bits\n"
+ "Configure SRv6 locator function length in bits\n"
+ "Specify SRv6 locator function length in bits\n")
{
VTY_DECLVAR_CONTEXT(srv6_locator, locator);
struct srv6_locator_chunk *chunk = NULL;
@@ -434,9 +434,9 @@ static int zebra_sr_config(struct vty *vty)
if (locator->argument_bits_length)
vty_out(vty, " arg-len %u",
locator->argument_bits_length);
- if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
- vty_out(vty, " behavior usid");
vty_out(vty, "\n");
+ if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ vty_out(vty, " behavior usid\n");
vty_out(vty, " exit\n");
vty_out(vty, " !\n");
}
diff --git a/zebra/zebra_tc.c b/zebra/zebra_tc.c
new file mode 100644
index 0000000000..09d9986fb3
--- /dev/null
+++ b/zebra/zebra_tc.c
@@ -0,0 +1,444 @@
+/*
+ * Zebra Traffic Control (TC) main handling.
+ *
+ * Copyright (C) 2022 Shichu Yang
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include <jhash.h>
+#include <hash.h>
+#include <memory.h>
+#include <hook.h>
+
+#include "zebra/zebra_router.h"
+#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_tc.h"
+#include "zebra/debug.h"
+
+DEFINE_MTYPE_STATIC(ZEBRA, TC_QDISC, "TC queue discipline");
+DEFINE_MTYPE_STATIC(ZEBRA, TC_CLASS, "TC class");
+DEFINE_MTYPE_STATIC(ZEBRA, TC_FILTER, "TC filter");
+
+const struct message tc_qdisc_kinds[] = {
+ {TC_QDISC_HTB, "htb"},
+ {TC_QDISC_NOQUEUE, "noqueue"},
+ {0},
+};
+
+const struct message tc_filter_kinds[] = {
+ {TC_FILTER_BPF, "bpf"},
+ {TC_FILTER_FLOW, "flow"},
+ {TC_FILTER_FLOWER, "flower"},
+ {TC_FILTER_U32, "u32"},
+ {0},
+};
+
+const struct message *tc_class_kinds = tc_qdisc_kinds;
+
+static uint32_t lookup_key(const struct message *mz, const char *msg,
+ uint32_t nf)
+{
+ static struct message nt = {0};
+ uint32_t rz = nf ? nf : UINT32_MAX;
+ const struct message *pnt;
+
+ for (pnt = mz; memcmp(pnt, &nt, sizeof(struct message)); pnt++)
+ if (strcmp(pnt->str, msg) == 0) {
+ rz = pnt->key;
+ break;
+ }
+ return rz;
+}
+
+const char *tc_qdisc_kind2str(uint32_t type)
+{
+ return lookup_msg(tc_qdisc_kinds, type, "Unrecognized QDISC Type");
+}
+
+enum tc_qdisc_kind tc_qdisc_str2kind(const char *type)
+{
+ return lookup_key(tc_qdisc_kinds, type, TC_QDISC_UNSPEC);
+}
+
+uint32_t zebra_tc_qdisc_hash_key(const void *arg)
+{
+ const struct zebra_tc_qdisc *qdisc;
+ uint32_t key;
+
+ qdisc = arg;
+
+ key = jhash_1word(qdisc->qdisc.ifindex, 0);
+
+ return key;
+}
+
+bool zebra_tc_qdisc_hash_equal(const void *arg1, const void *arg2)
+{
+ const struct zebra_tc_qdisc *q1, *q2;
+
+ q1 = (const struct zebra_tc_qdisc *)arg1;
+ q2 = (const struct zebra_tc_qdisc *)arg2;
+
+ if (q1->qdisc.ifindex != q2->qdisc.ifindex)
+ return false;
+
+ return true;
+}
+
+struct tc_qdisc_ifindex_lookup {
+ struct zebra_tc_qdisc *qdisc;
+ ifindex_t ifindex;
+};
+
+
+static int tc_qdisc_lookup_ifindex_walker(struct hash_bucket *b, void *data)
+{
+ struct tc_qdisc_ifindex_lookup *lookup = data;
+ struct zebra_tc_qdisc *qdisc = b->data;
+
+ if (lookup->ifindex == qdisc->qdisc.ifindex) {
+ lookup->qdisc = qdisc;
+ return HASHWALK_ABORT;
+ }
+
+ return HASHWALK_CONTINUE;
+}
+
+static struct zebra_tc_qdisc *
+tc_qdisc_lookup_ifindex(struct zebra_tc_qdisc *qdisc)
+{
+ struct tc_qdisc_ifindex_lookup lookup;
+
+ lookup.ifindex = qdisc->qdisc.ifindex;
+ lookup.qdisc = NULL;
+ hash_walk(zrouter.rules_hash, &tc_qdisc_lookup_ifindex_walker, &lookup);
+
+ return lookup.qdisc;
+}
+
+static void *tc_qdisc_alloc_intern(void *arg)
+{
+ struct zebra_tc_qdisc *ztq;
+ struct zebra_tc_qdisc *new;
+
+ ztq = (struct zebra_tc_qdisc *)arg;
+
+ new = XCALLOC(MTYPE_TC_QDISC, sizeof(*new));
+
+ memcpy(new, ztq, sizeof(*ztq));
+
+ return new;
+}
+
+static struct zebra_tc_qdisc *tc_qdisc_free(struct zebra_tc_qdisc *hash_data,
+ bool free_data)
+{
+ hash_release(zrouter.qdisc_hash, hash_data);
+
+ if (free_data) {
+ XFREE(MTYPE_TC_QDISC, hash_data);
+ return NULL;
+ }
+
+ return hash_data;
+}
+
+static struct zebra_tc_qdisc *tc_qdisc_release(struct zebra_tc_qdisc *qdisc,
+ bool free_data)
+{
+ struct zebra_tc_qdisc *lookup;
+
+ lookup = hash_lookup(zrouter.qdisc_hash, qdisc);
+
+ if (!lookup)
+ return NULL;
+
+ return tc_qdisc_free(lookup, free_data);
+}
+
+void zebra_tc_qdisc_install(struct zebra_tc_qdisc *qdisc)
+{
+ if (IS_ZEBRA_DEBUG_TC)
+ zlog_debug("%s: install tc qdisc ifindex %d kind %s", __func__,
+ qdisc->qdisc.ifindex,
+ tc_qdisc_kind2str(qdisc->qdisc.kind));
+
+ struct zebra_tc_qdisc *found;
+ struct zebra_tc_qdisc *old;
+ struct zebra_tc_qdisc *new;
+
+ found = tc_qdisc_lookup_ifindex(qdisc);
+
+ if (found) {
+ if (!zebra_tc_qdisc_hash_equal(qdisc, found)) {
+ old = tc_qdisc_release(found, false);
+ (void)dplane_tc_qdisc_uninstall(old);
+ new = hash_get(zrouter.qdisc_hash, qdisc,
+ tc_qdisc_alloc_intern);
+ (void)dplane_tc_qdisc_install(new);
+ XFREE(MTYPE_TC_QDISC, old);
+ }
+ } else {
+ new = hash_get(zrouter.qdisc_hash, qdisc,
+ tc_qdisc_alloc_intern);
+ (void)dplane_tc_qdisc_install(new);
+ }
+}
+
+void zebra_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc)
+{
+ if (IS_ZEBRA_DEBUG_TC)
+ zlog_debug("%s: uninstall tc qdisc ifindex %d kind %s",
+ __func__, qdisc->qdisc.ifindex,
+ tc_qdisc_kind2str(qdisc->qdisc.kind));
+
+ (void)dplane_tc_qdisc_uninstall(qdisc);
+
+ if (tc_qdisc_release(qdisc, true))
+ zlog_debug("%s: tc qdisc being deleted we know nothing about",
+ __func__);
+}
+
+uint32_t zebra_tc_class_hash_key(const void *arg)
+{
+ const struct zebra_tc_class *class;
+ uint32_t key;
+
+ class = arg;
+
+ key = jhash_2words(class->class.ifindex, class->class.handle, 0);
+
+ return key;
+}
+
+bool zebra_tc_class_hash_equal(const void *arg1, const void *arg2)
+{
+ const struct zebra_tc_class *c1, *c2;
+
+ c1 = (const struct zebra_tc_class *)arg1;
+ c2 = (const struct zebra_tc_class *)arg2;
+
+ if (c1->class.ifindex != c2->class.ifindex)
+ return false;
+
+ if (c1->class.handle != c2->class.handle)
+ return false;
+
+ return true;
+}
+
+static void *tc_class_alloc_intern(void *arg)
+{
+ struct zebra_tc_class *class;
+ struct zebra_tc_class *new;
+
+ class = (struct zebra_tc_class *)arg;
+
+ new = XCALLOC(MTYPE_TC_CLASS, sizeof(*new));
+
+ memcpy(new, class, sizeof(*class));
+
+ return new;
+}
+
+static struct zebra_tc_class *tc_class_free(struct zebra_tc_class *hash_data,
+ bool free_data)
+{
+ hash_release(zrouter.class_hash, hash_data);
+
+ if (free_data) {
+ XFREE(MTYPE_TC_CLASS, hash_data);
+ return NULL;
+ }
+
+ return hash_data;
+}
+
+static struct zebra_tc_class *tc_class_release(struct zebra_tc_class *class,
+ bool free_data)
+{
+ struct zebra_tc_class *lookup;
+
+ lookup = hash_lookup(zrouter.class_hash, class);
+
+ if (!lookup)
+ return NULL;
+
+ return tc_class_free(lookup, free_data);
+}
+
+void zebra_tc_class_add(struct zebra_tc_class *class)
+{
+ if (IS_ZEBRA_DEBUG_TC)
+ zlog_debug(
+ "%s: add tc class ifindex %d handle %04x:%04x kind %s",
+ __func__, class->class.ifindex,
+ (class->class.handle & 0xffff0000u) >> 16,
+ class->class.handle & 0x0000ffffu,
+ tc_qdisc_kind2str(class->class.kind));
+
+ struct zebra_tc_class *found;
+ struct zebra_tc_class *new;
+
+ /*
+ * We find the class in the hash by (ifindex, handle) directly, and by
+ * testing their deep equality to seek out whether it's an update.
+ *
+ * Currently deep equality is not checked since it will be okay to
+ * update the totally same class again.
+ */
+ found = hash_lookup(zrouter.class_hash, class);
+ new = hash_get(zrouter.class_hash, class, tc_class_alloc_intern);
+
+ if (found)
+ (void)dplane_tc_class_update(new);
+ else
+ (void)dplane_tc_class_add(new);
+}
+
+void zebra_tc_class_delete(struct zebra_tc_class *class)
+{
+ if (IS_ZEBRA_DEBUG_TC)
+ zlog_debug(
+ "%s: delete tc class ifindex %d handle %04x:%04x kind %s",
+ __func__, class->class.ifindex,
+ (class->class.handle & 0xffff0000u) >> 16,
+ class->class.handle & 0x0000ffffu,
+ tc_qdisc_kind2str(class->class.kind));
+
+ (void)dplane_tc_class_delete(class);
+
+ if (tc_class_release(class, true))
+ zlog_debug("%s: tc class being deleted we know nothing about",
+ __func__);
+}
+
+const char *tc_filter_kind2str(uint32_t type)
+{
+ return lookup_msg(tc_filter_kinds, type, "Unrecognized TFILTER Type");
+}
+
+enum tc_qdisc_kind tc_filter_str2kind(const char *type)
+{
+ return lookup_key(tc_filter_kinds, type, TC_FILTER_UNSPEC);
+}
+
+uint32_t zebra_tc_filter_hash_key(const void *arg)
+{
+ const struct zebra_tc_filter *filter;
+ uint32_t key;
+
+ filter = arg;
+
+ key = jhash_2words(filter->filter.ifindex, filter->filter.handle, 0);
+
+ return key;
+}
+
+bool zebra_tc_filter_hash_equal(const void *arg1, const void *arg2)
+{
+ const struct zebra_tc_filter *f1, *f2;
+
+ f1 = (const struct zebra_tc_filter *)arg1;
+ f2 = (const struct zebra_tc_filter *)arg2;
+
+ if (f1->filter.ifindex != f2->filter.ifindex)
+ return false;
+
+ if (f1->filter.handle != f2->filter.handle)
+ return false;
+
+ return true;
+}
+
+static struct zebra_tc_filter *tc_filter_free(struct zebra_tc_filter *hash_data,
+ bool free_data)
+{
+ hash_release(zrouter.filter_hash, hash_data);
+
+ if (free_data) {
+ XFREE(MTYPE_TC_FILTER, hash_data);
+ return NULL;
+ }
+
+ return hash_data;
+}
+
+static struct zebra_tc_filter *tc_filter_release(struct zebra_tc_filter *filter,
+ bool free_data)
+{
+ struct zebra_tc_filter *lookup;
+
+ lookup = hash_lookup(zrouter.filter_hash, filter);
+
+ if (!lookup)
+ return NULL;
+
+ return tc_filter_free(lookup, free_data);
+}
+
+static void *tc_filter_alloc_intern(void *arg)
+{
+ struct zebra_tc_filter *ztf;
+ struct zebra_tc_filter *new;
+
+ ztf = (struct zebra_tc_filter *)arg;
+
+ new = XCALLOC(MTYPE_TC_FILTER, sizeof(*new));
+
+ memcpy(new, ztf, sizeof(*ztf));
+
+ return new;
+}
+
+void zebra_tc_filter_add(struct zebra_tc_filter *filter)
+{
+ if (IS_ZEBRA_DEBUG_TC)
+ zlog_debug(
+ "%s: add tc filter ifindex %d priority %u handle %08x kind %s",
+ __func__, filter->filter.ifindex,
+ filter->filter.priority, filter->filter.handle,
+ tc_filter_kind2str(filter->filter.kind));
+
+ struct zebra_tc_filter *found;
+ struct zebra_tc_filter *new;
+
+ found = hash_lookup(zrouter.filter_hash, filter);
+ new = hash_get(zrouter.filter_hash, filter, tc_filter_alloc_intern);
+
+ if (found)
+ (void)dplane_tc_filter_update(new);
+ else
+ (void)dplane_tc_filter_add(new);
+}
+
+void zebra_tc_filter_delete(struct zebra_tc_filter *filter)
+{
+ if (IS_ZEBRA_DEBUG_PBR)
+ zlog_debug(
+ "%s: delete tc filter ifindex %d priority %u handle %08x kind %s",
+ __func__, filter->filter.ifindex,
+ filter->filter.priority, filter->filter.handle,
+ tc_filter_kind2str(filter->filter.kind));
+
+ (void)dplane_tc_filter_delete(filter);
+
+ if (tc_filter_release(filter, true))
+ zlog_debug("%s: tc filter being deleted we know nothing about",
+ __func__);
+}
diff --git a/zebra/zebra_tc.h b/zebra/zebra_tc.h
new file mode 100644
index 0000000000..832972b713
--- /dev/null
+++ b/zebra/zebra_tc.h
@@ -0,0 +1,79 @@
+/*
+ * Zebra Traffic Control (TC) Data structures and definitions
+ * These are public definitions referenced by multiple files.
+ *
+ * Copyright (C) 2022 Shichu Yang
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ZEBRA_TC_H
+#define _ZEBRA_TC_H
+
+#include <zebra.h>
+#include "rt.h"
+#include "tc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct zebra_tc_qdisc {
+ int sock;
+
+ struct tc_qdisc qdisc;
+};
+
+struct zebra_tc_class {
+ int sock;
+
+ struct tc_class class;
+};
+
+struct zebra_tc_filter {
+ int sock;
+
+ struct tc_filter filter;
+};
+
+const char *tc_qdisc_kind2str(uint32_t type);
+enum tc_qdisc_kind tc_qdisc_str2kind(const char *type);
+
+uint32_t zebra_tc_qdisc_hash_key(const void *arg);
+bool zebra_tc_qdisc_hash_equal(const void *arg1, const void *arg2);
+void zebra_tc_qdisc_install(struct zebra_tc_qdisc *qdisc);
+void zebra_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc);
+
+uint32_t zebra_tc_class_hash_key(const void *arg);
+bool zebra_tc_class_hash_equal(const void *arg1, const void *arg2);
+void zebra_tc_class_add(struct zebra_tc_class *class);
+void zebra_tc_class_delete(struct zebra_tc_class *class);
+
+const char *tc_filter_kind2str(uint32_t type);
+enum tc_qdisc_kind tc_filter_str2kind(const char *type);
+void zebra_tc_filter_add(struct zebra_tc_filter *filter);
+void zebra_tc_filter_delete(struct zebra_tc_filter *filter);
+
+void zebra_tc_filters_free(void *arg);
+uint32_t zebra_tc_filter_hash_key(const void *arg);
+bool zebra_tc_filter_hash_equal(const void *arg1, const void *arg2);
+
+void kernel_read_tc_qdisc(struct zebra_ns *zns);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZEBRA_TC_H */
diff --git a/zebra/zebra_trace.h b/zebra/zebra_trace.h
index 49a0c8e793..374305fcda 100644
--- a/zebra/zebra_trace.h
+++ b/zebra/zebra_trace.h
@@ -123,6 +123,49 @@ TRACEPOINT_EVENT(
)
)
+TRACEPOINT_EVENT(
+ frr_zebra,
+ netlink_tc_qdisc_change,
+ 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_tc_class_change,
+ 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_tc_filter_change,
+ 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)
+ )
+ )
+
#include <lttng/tracepoint-event.h>
#endif /* HAVE_LTTNG */
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index c99aa2e8ff..be5e91495f 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -268,6 +268,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
/* Cleanup EVPN states for vrf */
zebra_vxlan_vrf_delete(zvrf);
+ zebra_routemap_vrf_delete(zvrf);
list_delete_all_node(zvrf->rid_all_sorted_list);
list_delete_all_node(zvrf->rid_lo_sorted_list);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 6561ac95fa..8ed8abe304 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -630,8 +630,7 @@ static void show_route_nexthop_helper(struct vty *vty,
case NEXTHOP_TYPE_IFINDEX:
vty_out(vty, " is directly connected, %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
+ ifindex2ifname(nexthop->ifindex, nexthop->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
vty_out(vty, " unreachable");
@@ -703,8 +702,10 @@ static void show_route_nexthop_helper(struct vty *vty,
seg6local_context2str(buf, sizeof(buf),
&nexthop->nh_srv6->seg6local_ctx,
nexthop->nh_srv6->seg6local_action);
- vty_out(vty, ", seg6local %s %s", seg6local_action2str(
- nexthop->nh_srv6->seg6local_action), buf);
+ vty_out(vty, ", seg6local %s %s",
+ seg6local_action2str(
+ nexthop->nh_srv6->seg6local_action),
+ buf);
inet_ntop(AF_INET6, &nexthop->nh_srv6->seg6_segs, buf,
sizeof(buf));
@@ -722,6 +723,7 @@ static void show_route_nexthop_helper(struct vty *vty,
}
}
+
/*
* Render a nexthop into a json object; the caller allocates and owns
* the json object memory.
@@ -806,9 +808,8 @@ static void show_nexthop_json_helper(json_object *json_nexthop,
json_nexthop, "reject");
break;
case BLACKHOLE_ADMINPROHIB:
- json_object_boolean_true_add(
- json_nexthop,
- "admin-prohibited");
+ json_object_boolean_true_add(json_nexthop,
+ "adminProhibited");
break;
case BLACKHOLE_NULL:
json_object_boolean_true_add(
@@ -827,7 +828,7 @@ static void show_nexthop_json_helper(json_object *json_nexthop,
if (nexthop->rparent)
json_object_boolean_true_add(json_nexthop, "resolver");
- if (nexthop->vrf_id != re->vrf_id)
+ if ((re == NULL || (nexthop->vrf_id != re->vrf_id)))
json_object_string_add(json_nexthop, "vrf",
vrf_id_to_name(nexthop->vrf_id));
@@ -840,8 +841,7 @@ static void show_nexthop_json_helper(json_object *json_nexthop,
"active");
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
- json_object_boolean_true_add(json_nexthop,
- "onLink");
+ json_object_boolean_true_add(json_nexthop, "onLink");
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_LINKDOWN))
json_object_boolean_true_add(json_nexthop, "linkDown");
@@ -1370,7 +1370,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
DEFPY (show_ip_nht,
show_ip_nht_cmd,
- "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib]",
+ "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib] [json]",
SHOW_STR
IP_STR
IP6_STR
@@ -1382,23 +1382,48 @@ DEFPY (show_ip_nht,
"IPv4 Address\n"
"IPv6 Address\n"
VRF_ALL_CMD_HELP_STR
- "Show Multicast (MRIB) NHT state\n")
+ "Show Multicast (MRIB) NHT state\n"
+ JSON_STR)
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
vrf_id_t vrf_id = VRF_DEFAULT;
struct prefix prefix, *p = NULL;
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+ json_object *json_vrf = NULL;
+ json_object *json_nexthop = NULL;
+
+ if (uj)
+ json = json_object_new_object();
if (vrf_all) {
struct vrf *vrf;
struct zebra_vrf *zvrf;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if ((zvrf = vrf->info) != NULL) {
- vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf));
+ if (uj) {
+ json_vrf = json_object_new_object();
+ json_nexthop = json_object_new_object();
+ json_object_object_add(json,
+ zvrf_name(zvrf),
+ json_vrf);
+ json_object_object_add(json_vrf,
+ "nexthops",
+ json_nexthop);
+ } else {
+ vty_out(vty, "\nVRF %s:\n",
+ zvrf_name(zvrf));
+ }
zebra_print_rnh_table(zvrf_id(zvrf), afi, safi,
- vty, NULL);
+ vty, NULL, json_nexthop);
}
+ }
+
+ if (uj)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}
if (vrf_name)
@@ -1407,11 +1432,29 @@ DEFPY (show_ip_nht,
memset(&prefix, 0, sizeof(prefix));
if (addr) {
p = sockunion2hostprefix(addr, &prefix);
- if (!p)
+ if (!p) {
+ if (uj)
+ json_object_free(json);
return CMD_WARNING;
+ }
}
- zebra_print_rnh_table(vrf_id, afi, safi, vty, p);
+ if (uj) {
+ json_vrf = json_object_new_object();
+ json_nexthop = json_object_new_object();
+ if (vrf_name)
+ json_object_object_add(json, vrf_name, json_vrf);
+ else
+ json_object_object_add(json, "default", json_vrf);
+
+ json_object_object_add(json_vrf, "nexthops", json_nexthop);
+ }
+
+ zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop);
+
+ if (uj)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}
@@ -1436,125 +1479,264 @@ DEFUN (ip_nht_default_route,
return CMD_SUCCESS;
}
-static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
+static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe,
+ json_object *json_nhe_hdr)
{
struct nexthop *nexthop = NULL;
struct nhg_connected *rb_node_dep = NULL;
struct nexthop_group *backup_nhg;
char up_str[MONOTIME_STRLEN];
char time_left[MONOTIME_STRLEN];
+ json_object *json_dependants = NULL;
+ json_object *json_depends = NULL;
+ json_object *json_nexthop_array = NULL;
+ json_object *json_nexthops = NULL;
+ json_object *json = NULL;
+ json_object *json_backup_nexthop_array = NULL;
+ json_object *json_backup_nexthops = NULL;
+
uptime2str(nhe->uptime, up_str, sizeof(up_str));
- vty_out(vty, "ID: %u (%s)\n", nhe->id, zebra_route_string(nhe->type));
- vty_out(vty, " RefCnt: %u", nhe->refcnt);
- if (thread_is_scheduled(nhe->timer))
- vty_out(vty, " Time to Deletion: %s",
- thread_timer_to_hhmmss(time_left, sizeof(time_left),
- nhe->timer));
- vty_out(vty, "\n");
+ if (json_nhe_hdr)
+ json = json_object_new_object();
- vty_out(vty, " Uptime: %s\n", up_str);
- vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id));
+ if (json) {
+ json_object_string_add(json, "type",
+ zebra_route_string(nhe->type));
+ json_object_int_add(json, "refCount", nhe->refcnt);
+ if (thread_is_scheduled(nhe->timer))
+ json_object_string_add(
+ json, "timeToDeletion",
+ thread_timer_to_hhmmss(time_left,
+ sizeof(time_left),
+ nhe->timer));
+ json_object_string_add(json, "uptime", up_str);
+ json_object_string_add(json, "vrf",
+ vrf_id_to_name(nhe->vrf_id));
+ } else {
+ vty_out(vty, "ID: %u (%s)\n", nhe->id,
+ zebra_route_string(nhe->type));
+ vty_out(vty, " RefCnt: %u", nhe->refcnt);
+ if (thread_is_scheduled(nhe->timer))
+ vty_out(vty, " Time to Deletion: %s",
+ thread_timer_to_hhmmss(time_left,
+ sizeof(time_left),
+ nhe->timer));
+ 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));
+ }
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
- vty_out(vty, " Valid");
- if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED))
- vty_out(vty, ", Installed");
- vty_out(vty, "\n");
+ if (json)
+ json_object_boolean_true_add(json, "valid");
+ else
+ vty_out(vty, " Valid");
+
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
+ if (json)
+ json_object_boolean_true_add(json, "installed");
+ else
+ vty_out(vty, ", Installed");
+ }
+ if (!json)
+ vty_out(vty, "\n");
+ }
+ if (nhe->ifp) {
+ if (json)
+ json_object_int_add(json, "interfaceIndex",
+ nhe->ifp->ifindex);
+ else
+ vty_out(vty, " Interface Index: %d\n",
+ nhe->ifp->ifindex);
}
- if (nhe->ifp)
- vty_out(vty, " Interface Index: %d\n", nhe->ifp->ifindex);
if (!zebra_nhg_depends_is_empty(nhe)) {
- vty_out(vty, " Depends:");
+ if (json)
+ json_depends = json_object_new_array();
+ else
+ vty_out(vty, " Depends:");
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
- vty_out(vty, " (%u)", rb_node_dep->nhe->id);
+ if (json_depends)
+ json_object_array_add(
+ json_depends,
+ json_object_new_int(
+ rb_node_dep->nhe->id));
+ else
+ vty_out(vty, " (%u)", rb_node_dep->nhe->id);
}
- vty_out(vty, "\n");
+ if (!json_depends)
+ vty_out(vty, "\n");
+ else
+ json_object_object_add(json, "depends", json_depends);
}
/* Output nexthops */
- for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " ");
- else
- /* Make recursive nexthops a bit more clear */
- vty_out(vty, " ");
+ if (json)
+ json_nexthop_array = json_object_new_array();
- show_route_nexthop_helper(vty, NULL, nexthop);
+
+ for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
+ if (json_nexthop_array) {
+ json_nexthops = json_object_new_object();
+ show_nexthop_json_helper(json_nexthops, nexthop, NULL);
+ } else {
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ vty_out(vty, " ");
+ else
+ /* Make recursive nexthops a bit more clear */
+ vty_out(vty, " ");
+ show_route_nexthop_helper(vty, NULL, nexthop);
+ }
if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL) {
if (CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_HAS_BACKUP))
- vty_out(vty, " [backup %d]",
- nexthop->backup_idx[0]);
+ NEXTHOP_FLAG_HAS_BACKUP)) {
+ if (json)
+ json_object_int_add(
+ json_nexthops, "backup",
+ nexthop->backup_idx[0]);
+ else
+ vty_out(vty, " [backup %d]",
+ nexthop->backup_idx[0]);
+ }
+
+ if (!json)
+ vty_out(vty, "\n");
+ else
+ json_object_array_add(json_nexthop_array,
+ json_nexthops);
- vty_out(vty, "\n");
continue;
}
- /* TODO -- print more useful backup info */
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
- int i;
-
- vty_out(vty, "[backup");
- for (i = 0; i < nexthop->backup_num; i++)
- vty_out(vty, " %d", nexthop->backup_idx[i]);
-
- vty_out(vty, "]");
+ if (!json) {
+ /* TODO -- print more useful backup info */
+ if (CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_HAS_BACKUP)) {
+ int i;
+
+ vty_out(vty, "[backup");
+ for (i = 0; i < nexthop->backup_num; i++)
+ vty_out(vty, " %d",
+ nexthop->backup_idx[i]);
+ vty_out(vty, "]");
+ }
+ vty_out(vty, "\n");
+ } else {
+ json_object_array_add(json_nexthop_array,
+ json_nexthops);
}
-
- vty_out(vty, "\n");
}
+ if (json)
+ json_object_object_add(json, "nexthops", json_nexthop_array);
+
/* Output backup nexthops (if any) */
backup_nhg = zebra_nhg_get_backup_nhg(nhe);
if (backup_nhg) {
- vty_out(vty, " Backups:\n");
+ if (json)
+ json_backup_nexthop_array = json_object_new_array();
+ else
+ vty_out(vty, " Backups:\n");
for (ALL_NEXTHOPS_PTR(backup_nhg, nexthop)) {
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " ");
- else
- /* Make recursive nexthops a bit more clear */
- vty_out(vty, " ");
+ if (json_backup_nexthop_array) {
+ json_backup_nexthops = json_object_new_object();
+ show_nexthop_json_helper(json_backup_nexthops,
+ nexthop, NULL);
+ json_object_array_add(json_backup_nexthop_array,
+ json_backup_nexthops);
+ } else {
- show_route_nexthop_helper(vty, NULL, nexthop);
- vty_out(vty, "\n");
+ if (!CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_RECURSIVE))
+ vty_out(vty, " ");
+ else
+ /* Make recursive nexthops a bit more
+ * clear
+ */
+ vty_out(vty, " ");
+ show_route_nexthop_helper(vty, NULL, nexthop);
+ vty_out(vty, "\n");
+ }
}
+
+ if (json)
+ json_object_object_add(json, "backupNexthops",
+ json_backup_nexthop_array);
}
if (!zebra_nhg_dependents_is_empty(nhe)) {
- vty_out(vty, " Dependents:");
+ if (json)
+ json_dependants = json_object_new_array();
+ else
+ vty_out(vty, " Dependents:");
frr_each(nhg_connected_tree, &nhe->nhg_dependents,
rb_node_dep) {
- vty_out(vty, " (%u)", rb_node_dep->nhe->id);
+ if (json)
+ json_object_array_add(
+ json_dependants,
+ json_object_new_int(
+ rb_node_dep->nhe->id));
+ else
+ vty_out(vty, " (%u)", rb_node_dep->nhe->id);
}
- vty_out(vty, "\n");
+ if (json)
+ json_object_object_add(json, "dependents",
+ json_dependants);
+ else
+ vty_out(vty, "\n");
}
- if (nhe->nhg.nhgr.buckets)
- vty_out(vty,
- " Buckets: %u Idle Timer: %u Unbalanced Timer: %u Unbalanced time: %" PRIu64 "\n",
- nhe->nhg.nhgr.buckets, nhe->nhg.nhgr.idle_timer,
- nhe->nhg.nhgr.unbalanced_timer,
- nhe->nhg.nhgr.unbalanced_time);
+ if (nhe->nhg.nhgr.buckets) {
+ if (json) {
+ json_object_int_add(json, "buckets",
+ nhe->nhg.nhgr.buckets);
+ json_object_int_add(json, "idleTimer",
+ nhe->nhg.nhgr.idle_timer);
+ json_object_int_add(json, "unbalancedTimer",
+ nhe->nhg.nhgr.unbalanced_timer);
+ json_object_int_add(json, "unbalancedTime",
+ nhe->nhg.nhgr.unbalanced_time);
+ } else {
+ vty_out(vty,
+ " Buckets: %u Idle Timer: %u Unbalanced Timer: %u Unbalanced time: %" PRIu64
+ "\n",
+ nhe->nhg.nhgr.buckets, nhe->nhg.nhgr.idle_timer,
+ nhe->nhg.nhgr.unbalanced_timer,
+ nhe->nhg.nhgr.unbalanced_time);
+ }
+ }
+
+ if (json_nhe_hdr)
+ json_object_object_addf(json_nhe_hdr, json, "%u", nhe->id);
}
-static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id)
+static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id,
+ json_object *json)
{
struct nhg_hash_entry *nhe = NULL;
nhe = zebra_nhg_lookup_id(id);
if (nhe)
- show_nexthop_group_out(vty, nhe);
+ show_nexthop_group_out(vty, nhe, json);
else {
- vty_out(vty, "Nexthop Group ID: %u does not exist\n", id);
+ if (json)
+ vty_json(vty, json);
+ else
+ vty_out(vty, "Nexthop Group ID: %u does not exist\n",
+ id);
return CMD_WARNING;
}
+
+ if (json)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}
@@ -1565,6 +1747,7 @@ struct nhe_show_context {
vrf_id_t vrf_id;
afi_t afi;
int type;
+ json_object *json;
};
static int nhe_show_walker(struct hash_bucket *bucket, void *arg)
@@ -1583,7 +1766,7 @@ static int nhe_show_walker(struct hash_bucket *bucket, void *arg)
if (ctx->type && nhe->type != ctx->type)
goto done;
- show_nexthop_group_out(ctx->vty, nhe);
+ show_nexthop_group_out(ctx->vty, nhe, ctx->json);
done:
return HASHWALK_CONTINUE;
@@ -1591,7 +1774,7 @@ done:
static void show_nexthop_group_cmd_helper(struct vty *vty,
struct zebra_vrf *zvrf, afi_t afi,
- int type)
+ int type, json_object *json)
{
struct nhe_show_context ctx;
@@ -1599,6 +1782,7 @@ static void show_nexthop_group_cmd_helper(struct vty *vty,
ctx.afi = afi;
ctx.vrf_id = zvrf->vrf->vrf_id;
ctx.type = type;
+ ctx.json = json;
hash_walk(zrouter.nhgs_id, nhe_show_walker, &ctx);
}
@@ -1616,7 +1800,7 @@ static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp)
frr_each(nhg_connected_tree, &zebra_if->nhg_dependents,
rb_node_dep) {
vty_out(vty, " ");
- show_nexthop_group_out(vty, rb_node_dep->nhe);
+ show_nexthop_group_out(vty, rb_node_dep->nhe, NULL);
}
}
}
@@ -1655,29 +1839,36 @@ DEFPY (show_interface_nexthop_group,
return CMD_SUCCESS;
}
-DEFPY (show_nexthop_group,
- show_nexthop_group_cmd,
- "show nexthop-group rib <(0-4294967295)$id|[singleton <ip$v4|ipv6$v6>] [<kernel|zebra|bgp|sharp>$type_str] [vrf <NAME$vrf_name|all$vrf_all>]>",
- SHOW_STR
- "Show Nexthop Groups\n"
- "RIB information\n"
- "Nexthop Group ID\n"
- "Show Singleton Nexthop-Groups\n"
- IP_STR
- IP6_STR
- "Kernel (not installed via the zebra RIB)\n"
- "Zebra (implicitly created by zebra)\n"
- "Border Gateway Protocol (BGP)\n"
- "Super Happy Advanced Routing Protocol (SHARP)\n"
- VRF_FULL_CMD_HELP_STR)
+DEFPY(show_nexthop_group,
+ show_nexthop_group_cmd,
+ "show nexthop-group rib <(0-4294967295)$id|[singleton <ip$v4|ipv6$v6>] [<kernel|zebra|bgp|sharp>$type_str] [vrf <NAME$vrf_name|all$vrf_all>]> [json]",
+ SHOW_STR
+ "Show Nexthop Groups\n"
+ "RIB information\n"
+ "Nexthop Group ID\n"
+ "Show Singleton Nexthop-Groups\n"
+ IP_STR
+ IP6_STR
+ "Kernel (not installed via the zebra RIB)\n"
+ "Zebra (implicitly created by zebra)\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Super Happy Advanced Routing Protocol (SHARP)\n"
+ VRF_FULL_CMD_HELP_STR
+ JSON_STR)
{
struct zebra_vrf *zvrf = NULL;
afi_t afi = AFI_UNSPEC;
int type = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+ json_object *json_vrf = NULL;
+
+ if (uj)
+ json = json_object_new_object();
if (id)
- return show_nexthop_group_id_cmd_helper(vty, id);
+ return show_nexthop_group_id_cmd_helper(vty, id, json);
if (v4)
afi = AFI_IP;
@@ -1693,8 +1884,11 @@ DEFPY (show_nexthop_group,
}
if (!vrf_is_backend_netns() && (vrf_name || vrf_all)) {
- vty_out(vty,
- "VRF subcommand does not make any sense in l3mdev based vrf's\n");
+ if (uj)
+ vty_json(vty, json);
+ else
+ vty_out(vty,
+ "VRF subcommand does not make any sense in l3mdev based vrf's\n");
return CMD_WARNING;
}
@@ -1707,11 +1901,21 @@ DEFPY (show_nexthop_group,
zvrf = vrf->info;
if (!zvrf)
continue;
+ if (uj)
+ json_vrf = json_object_new_object();
+ else
+ vty_out(vty, "VRF: %s\n", vrf->name);
- vty_out(vty, "VRF: %s\n", vrf->name);
- show_nexthop_group_cmd_helper(vty, zvrf, afi, type);
+ show_nexthop_group_cmd_helper(vty, zvrf, afi, type,
+ json_vrf);
+ if (uj)
+ json_object_object_add(json, vrf->name,
+ json_vrf);
}
+ if (uj)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}
@@ -1721,12 +1925,18 @@ DEFPY (show_nexthop_group,
zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
if (!zvrf) {
- vty_out(vty, "%% VRF '%s' specified does not exist\n",
- vrf_name);
+ if (uj)
+ vty_json(vty, json);
+ else
+ vty_out(vty, "%% VRF '%s' specified does not exist\n",
+ vrf_name);
return CMD_WARNING;
}
- show_nexthop_group_cmd_helper(vty, zvrf, afi, type);
+ show_nexthop_group_cmd_helper(vty, zvrf, afi, type, json);
+
+ if (uj)
+ vty_json(vty, json);
return CMD_SUCCESS;
}
@@ -4030,6 +4240,15 @@ DEFUN (show_zebra,
ttable_add_row(table, "ASIC offload|%s",
zrouter.asic_offloaded ? "Used" : "Unavailable");
+ /*
+ * Do not display this unless someone is actually using it
+ *
+ * Why this distinction? I think this is effectively dead code
+ * and should not be exposed. Maybe someone proves me wrong.
+ */
+ if (zrouter.asic_notification_nexthop_control)
+ ttable_add_row(table, "ASIC offload and nexthop control|Used");
+
ttable_add_row(table, "RA|%s",
rtadv_compiled_in() ? "Compiled in" : "Not Compiled in");
ttable_add_row(table, "RFC 5549|%s",
diff --git a/zebra/zserv.c b/zebra/zserv.c
index ebe246ffbc..d788811d3d 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -78,6 +78,8 @@ static struct zserv *find_client_internal(uint8_t proto,
unsigned short instance,
uint32_t session_id);
+/* Mem type for zclients. */
+DEFINE_MTYPE_STATIC(ZEBRA, ZSERV_CLIENT, "ZClients");
/*
* Client thread events.
@@ -146,6 +148,14 @@ static void zserv_event(struct zserv *client, enum zserv_event event);
/* Client thread lifecycle -------------------------------------------------- */
/*
+ * Free a zserv client object.
+ */
+void zserv_client_delete(struct zserv *client)
+{
+ XFREE(MTYPE_ZSERV_CLIENT, client);
+}
+
+/*
* Log zapi message to zlog.
*
* errmsg (optional)
@@ -644,7 +654,7 @@ static void zserv_client_free(struct zserv *client)
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("%s: Deleting client %s", __func__,
zebra_route_string(client->proto));
- XFREE(MTYPE_TMP, client);
+ zserv_client_delete(client);
} else {
/* Handle cases where client has GR instance. */
if (IS_ZEBRA_DEBUG_EVENT)
@@ -733,7 +743,7 @@ static struct zserv *zserv_client_create(int sock)
int i;
afi_t afi;
- client = XCALLOC(MTYPE_TMP, sizeof(struct zserv));
+ client = XCALLOC(MTYPE_ZSERV_CLIENT, sizeof(struct zserv));
/* Make client input/output buffer. */
client->sock = sock;
diff --git a/zebra/zserv.h b/zebra/zserv.h
index db7b70d7c4..de784e382a 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -364,6 +364,13 @@ extern void zserv_release_client(struct zserv *client);
extern void zserv_close_client(struct zserv *client);
/*
+ * Free memory for a zserv client object - note that this does not
+ * clean up the internal allocations associated with the zserv client,
+ * this just free the struct's memory.
+ */
+void zserv_client_delete(struct zserv *client);
+
+/*
* Log a ZAPI message hexdump.
*
* errmsg