summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alpine/APKBUILD.in2
-rw-r--r--bfdd/bfd_packet.c2
-rw-r--r--bfdd/config.c41
-rw-r--r--bgpd/bgp_attr.c61
-rw-r--r--bgpd/bgp_attr.h34
-rw-r--r--bgpd/bgp_attr_evpn.c2
-rw-r--r--bgpd/bgp_bmp.c35
-rw-r--r--bgpd/bgp_clist.c136
-rw-r--r--bgpd/bgp_clist.h14
-rw-r--r--bgpd/bgp_damp.c6
-rw-r--r--bgpd/bgp_debug.c16
-rw-r--r--bgpd/bgp_debug.h17
-rw-r--r--bgpd/bgp_dump.c13
-rw-r--r--bgpd/bgp_ecommunity.c2
-rw-r--r--bgpd/bgp_evpn.c176
-rw-r--r--bgpd/bgp_evpn.h31
-rw-r--r--bgpd/bgp_evpn_private.h11
-rw-r--r--bgpd/bgp_evpn_vty.c88
-rw-r--r--bgpd/bgp_flowspec.h2
-rw-r--r--bgpd/bgp_flowspec_util.c8
-rw-r--r--bgpd/bgp_flowspec_util.h2
-rw-r--r--bgpd/bgp_flowspec_vty.c12
-rw-r--r--bgpd/bgp_label.c18
-rw-r--r--bgpd/bgp_lcommunity.c4
-rw-r--r--bgpd/bgp_lcommunity.h2
-rw-r--r--bgpd/bgp_mac.c20
-rw-r--r--bgpd/bgp_mac.h4
-rw-r--r--bgpd/bgp_main.c4
-rw-r--r--bgpd/bgp_mpath.c35
-rw-r--r--bgpd/bgp_mplsvpn.c97
-rw-r--r--bgpd/bgp_nexthop.c19
-rw-r--r--bgpd/bgp_nht.c56
-rw-r--r--bgpd/bgp_packet.c5
-rw-r--r--bgpd/bgp_pbr.c8
-rw-r--r--bgpd/bgp_pbr.h4
-rw-r--r--bgpd/bgp_rd.c22
-rw-r--r--bgpd/bgp_rd.h19
-rw-r--r--bgpd/bgp_route.c612
-rw-r--r--bgpd/bgp_route.h59
-rw-r--r--bgpd/bgp_routemap.c33
-rw-r--r--bgpd/bgp_rpki.c8
-rw-r--r--bgpd/bgp_snmp.c11
-rw-r--r--bgpd/bgp_table.c43
-rw-r--r--bgpd/bgp_table.h9
-rw-r--r--bgpd/bgp_updgrp_adv.c37
-rw-r--r--bgpd/bgp_updgrp_packet.c56
-rw-r--r--bgpd/bgp_vnc_types.h2
-rw-r--r--bgpd/bgp_vpn.c19
-rw-r--r--bgpd/bgp_vty.c180
-rw-r--r--bgpd/bgp_zebra.c19
-rw-r--r--bgpd/bgp_zebra.h7
-rw-r--r--bgpd/bgpd.c25
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.h2
-rw-r--r--bgpd/rfapi/rfapi.c4
-rw-r--r--bgpd/rfapi/rfapi.h2
-rw-r--r--bgpd/rfapi/rfapi_ap.c6
-rw-r--r--bgpd/rfapi/rfapi_backend.h20
-rw-r--r--bgpd/rfapi/rfapi_import.c208
-rw-r--r--bgpd/rfapi/rfapi_import.h6
-rw-r--r--bgpd/rfapi/rfapi_monitor.c27
-rw-r--r--bgpd/rfapi/rfapi_monitor.h2
-rw-r--r--bgpd/rfapi/rfapi_nve_addr.c6
-rw-r--r--bgpd/rfapi/rfapi_nve_addr.h2
-rw-r--r--bgpd/rfapi/rfapi_private.h7
-rw-r--r--bgpd/rfapi/rfapi_rib.c92
-rw-r--r--bgpd/rfapi/rfapi_rib.h2
-rw-r--r--bgpd/rfapi/rfapi_vty.c44
-rw-r--r--bgpd/rfapi/rfapi_vty.h2
-rw-r--r--bgpd/rfapi/vnc_debug.h2
-rw-r--r--bgpd/rfapi/vnc_export_bgp.c160
-rw-r--r--bgpd/rfapi/vnc_export_bgp_p.h4
-rw-r--r--bgpd/rfapi/vnc_export_table.c11
-rw-r--r--bgpd/rfapi/vnc_export_table.h16
-rw-r--r--bgpd/rfapi/vnc_import_bgp.c209
-rw-r--r--bgpd/rfapi/vnc_import_bgp.h18
-rw-r--r--bgpd/rfapi/vnc_zebra.c50
-rwxr-xr-xconfigure.ac49
-rw-r--r--doc/developer/ospf-sr.rst2
-rw-r--r--doc/developer/workflow.rst5
-rw-r--r--doc/user/ldpd.rst5
-rw-r--r--isisd/fabricd.c6
-rw-r--r--isisd/fabricd.h2
-rw-r--r--isisd/isis_adjacency.c2
-rw-r--r--isisd/isis_circuit.c6
-rw-r--r--isisd/isis_cli.c8
-rw-r--r--isisd/isis_mt.c2
-rw-r--r--isisd/isis_mt.h2
-rw-r--r--isisd/isis_spf_private.h8
-rw-r--r--isisd/isis_tx_queue.c2
-rw-r--r--isisd/isis_tx_queue.h2
-rw-r--r--ldpd/lde.c151
-rw-r--r--ldpd/lde.h3
-rw-r--r--ldpd/lde_lib.c91
-rw-r--r--ldpd/ldp_vty.h1
-rw-r--r--ldpd/ldp_vty_cmds.c10
-rw-r--r--ldpd/ldp_vty_conf.c16
-rw-r--r--ldpd/ldpd.c21
-rw-r--r--ldpd/ldpd.h2
-rw-r--r--lib/agg_table.h10
-rw-r--r--lib/compiler.h9
-rw-r--r--lib/frrlua.c2
-rw-r--r--lib/frrlua.h2
-rw-r--r--lib/grammar_sandbox_main.c2
-rw-r--r--lib/ipaddr.h2
-rw-r--r--lib/log.c88
-rw-r--r--lib/log.h2
-rw-r--r--lib/mpls.c2
-rw-r--r--lib/mpls.h5
-rw-r--r--lib/nexthop.c50
-rw-r--r--lib/nexthop.h26
-rw-r--r--lib/nexthop_group.c94
-rw-r--r--lib/nexthop_group.h9
-rw-r--r--lib/northbound_grpc.cpp21
-rw-r--r--lib/plist.c2
-rw-r--r--lib/prefix.h18
-rw-r--r--lib/printfrr.h14
-rw-r--r--lib/routemap_cli.c38
-rw-r--r--lib/skiplist.c11
-rw-r--r--lib/skiplist.h13
-rw-r--r--lib/smux.h2
-rw-r--r--lib/snmp.c4
-rw-r--r--lib/spf_backoff.c2
-rw-r--r--lib/spf_backoff.h2
-rw-r--r--lib/srcdest_table.c2
-rw-r--r--lib/srcdest_table.h2
-rw-r--r--lib/stream.c2
-rw-r--r--lib/stream.h5
-rw-r--r--lib/table.h4
-rw-r--r--lib/thread.c9
-rw-r--r--lib/vty.c9
-rw-r--r--lib/yang_wrappers.c5
-rw-r--r--lib/zclient.c128
-rw-r--r--lib/zclient.h32
-rw-r--r--ospf6d/ospf6_abr.c4
-rw-r--r--ospf6d/ospf6_asbr.c2
-rw-r--r--ospf6d/ospf6_intra.c8
-rw-r--r--ospf6d/ospf6_lsa.c6
-rw-r--r--ospf6d/ospf6_lsa.h4
-rw-r--r--ospf6d/ospf6_top.c4
-rw-r--r--ospfd/ospf_ase.c2
-rw-r--r--ospfd/ospf_lsa.c2
-rw-r--r--ospfd/ospf_packet.c2
-rw-r--r--ospfd/ospf_ri.c5
-rw-r--r--ospfd/ospf_route.c25
-rw-r--r--ospfd/ospf_spf.c12
-rw-r--r--ospfd/ospf_te.c2
-rw-r--r--ospfd/ospf_vty.c4
-rw-r--r--pbrd/pbr_vty.c49
-rw-r--r--pimd/README4
-rw-r--r--pimd/pim_bsm.c38
-rw-r--r--pimd/pim_cmd.c81
-rw-r--r--pimd/pim_iface.c18
-rw-r--r--pimd/pim_instance.c1
-rw-r--r--pimd/pim_instance.h1
-rw-r--r--pimd/pim_join.c21
-rw-r--r--pimd/pim_mroute.c7
-rw-r--r--pimd/pim_neighbor.c11
-rw-r--r--pimd/pim_pim.c30
-rw-r--r--pimd/pim_pim.h1
-rw-r--r--pimd/pim_register.c2
-rw-r--r--pimd/pim_tlv.c8
-rw-r--r--pimd/pim_upstream.c2
-rw-r--r--pimd/pim_zlookup.c14
-rw-r--r--ripngd/ripng_interface.c9
-rw-r--r--ripngd/ripng_nb_state.c5
-rw-r--r--ripngd/ripng_zebra.c18
-rw-r--r--ripngd/ripngd.c30
-rw-r--r--sharpd/sharp_globals.h4
-rw-r--r--sharpd/sharp_logpump.c153
-rw-r--r--sharpd/sharp_vty.c74
-rw-r--r--sharpd/sharp_vty.h6
-rw-r--r--sharpd/sharp_zebra.c41
-rw-r--r--sharpd/sharp_zebra.h8
-rw-r--r--sharpd/subdir.am1
-rw-r--r--staticd/static_debug.c2
-rw-r--r--staticd/static_debug.h2
-rw-r--r--staticd/static_vty.c8
-rw-r--r--tests/bgpd/test_bgp_table.c4
-rw-r--r--tests/lib/test_atomlist.c19
-rw-r--r--tests/lib/test_srcdest_table.c2
-rw-r--r--tests/lib/test_stream.c18
-rw-r--r--tests/lib/test_typelist.c5
-rw-r--r--tests/lib/test_typelist.h8
-rw-r--r--tests/lib/test_zlog.c8
-rw-r--r--tests/subdir.am3
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json4
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json2
-rwxr-xr-xtests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py4
-rw-r--r--tests/topotests/bfd-topo1/r1/bgp_prefixes.json6
-rw-r--r--tests/topotests/bfd-topo1/r2/bgp_prefixes.json6
-rw-r--r--tests/topotests/bfd-topo1/r3/bgp_prefixes.json6
-rw-r--r--tests/topotests/bfd-topo1/r4/bgp_prefixes.json6
-rw-r--r--tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json6
-rw-r--r--tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json6
-rw-r--r--tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json6
-rw-r--r--tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json6
-rwxr-xr-xtests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py36
-rwxr-xr-xtests/topotests/bgp-route-map/test_route_map_topo1.py18
-rwxr-xr-xtests/topotests/bgp-route-map/test_route_map_topo2.py58
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py2
-rw-r--r--tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py2
-rwxr-xr-xtests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py2
-rw-r--r--tests/topotests/bgp_multiview_topo1/README.md2
-rw-r--r--tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py6
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref28
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf8
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref162
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine2/staticd.conf1
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine2/zebra.conf9
-rwxr-xr-xtests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py53
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref64
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor1/zebra.conf4
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref64
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor2/zebra.conf4
-rw-r--r--tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py4
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/ldpd.conf25
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf7
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/show_ip_ospf_neighbor.json12
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/show_ip_route.ref171
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_all_binding.ref61
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_binding.ref55
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_discovery.ref11
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_neighbor.ref10
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/zebra.conf17
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/ldpd.conf28
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf7
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/show_ip_ospf_neighbor.json31
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/show_ip_route.ref209
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_all_binding.ref63
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_binding.ref63
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_discovery.ref18
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/zebra.conf27
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/ldpd.conf24
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf8
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/show_ip_ospf_neighbor.json20
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/show_ip_route.ref209
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_all_binding.ref61
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_binding.ref62
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_discovery.ref11
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_neighbor.ref10
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/zebra.conf22
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/ldpd.conf24
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf7
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/show_ip_ospf_neighbor.json21
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/show_ip_route.ref196
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_all_binding.ref68
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_binding.ref68
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_discovery.ref2
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_neighbor.ref2
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/zebra.conf17
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.dot76
-rwxr-xr-xtests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py243
-rw-r--r--tests/topotests/ldp-oc-topo1/r1/ldpd.conf24
-rw-r--r--tests/topotests/ldp-oc-topo1/r1/ospfd.conf7
-rw-r--r--tests/topotests/ldp-oc-topo1/r1/show_ip_ospf_neighbor.json12
-rw-r--r--tests/topotests/ldp-oc-topo1/r1/show_ip_route.ref171
-rw-r--r--tests/topotests/ldp-oc-topo1/r1/show_ldp_binding.ref61
-rw-r--r--tests/topotests/ldp-oc-topo1/r1/show_ldp_discovery.ref11
-rw-r--r--tests/topotests/ldp-oc-topo1/r1/show_ldp_neighbor.ref10
-rw-r--r--tests/topotests/ldp-oc-topo1/r1/zebra.conf17
-rw-r--r--tests/topotests/ldp-oc-topo1/r2/ldpd.conf28
-rw-r--r--tests/topotests/ldp-oc-topo1/r2/ospfd.conf7
-rw-r--r--tests/topotests/ldp-oc-topo1/r2/show_ip_ospf_neighbor.json31
-rw-r--r--tests/topotests/ldp-oc-topo1/r2/show_ip_route.ref209
-rw-r--r--tests/topotests/ldp-oc-topo1/r2/show_ldp_binding.ref63
-rw-r--r--tests/topotests/ldp-oc-topo1/r2/show_ldp_discovery.ref18
-rw-r--r--tests/topotests/ldp-oc-topo1/r2/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-oc-topo1/r2/zebra.conf27
-rw-r--r--tests/topotests/ldp-oc-topo1/r3/ldpd.conf24
-rw-r--r--tests/topotests/ldp-oc-topo1/r3/ospfd.conf8
-rw-r--r--tests/topotests/ldp-oc-topo1/r3/show_ip_ospf_neighbor.json20
-rw-r--r--tests/topotests/ldp-oc-topo1/r3/show_ip_route.ref209
-rw-r--r--tests/topotests/ldp-oc-topo1/r3/show_ldp_binding.ref61
-rw-r--r--tests/topotests/ldp-oc-topo1/r3/show_ldp_discovery.ref11
-rw-r--r--tests/topotests/ldp-oc-topo1/r3/show_ldp_neighbor.ref10
-rw-r--r--tests/topotests/ldp-oc-topo1/r3/zebra.conf22
-rw-r--r--tests/topotests/ldp-oc-topo1/r4/ldpd.conf24
-rw-r--r--tests/topotests/ldp-oc-topo1/r4/ospfd.conf7
-rw-r--r--tests/topotests/ldp-oc-topo1/r4/show_ip_ospf_neighbor.json21
-rw-r--r--tests/topotests/ldp-oc-topo1/r4/show_ip_route.ref196
-rw-r--r--tests/topotests/ldp-oc-topo1/r4/show_ldp_binding.ref68
-rw-r--r--tests/topotests/ldp-oc-topo1/r4/show_ldp_discovery.ref2
-rw-r--r--tests/topotests/ldp-oc-topo1/r4/show_ldp_neighbor.ref2
-rw-r--r--tests/topotests/ldp-oc-topo1/r4/zebra.conf17
-rw-r--r--tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.dot76
-rwxr-xr-xtests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py227
-rw-r--r--tests/topotests/ldp-topo1/r1/ip_mpls_route.ref1
-rw-r--r--tests/topotests/lib/bgp.py14
-rw-r--r--tests/topotests/lib/common_config.py12
-rw-r--r--tests/topotests/pytest.ini2
-rw-r--r--tools/gcc-plugins/.gitignore7
-rw-r--r--tools/gcc-plugins/COPYING.GPLv3674
-rw-r--r--tools/gcc-plugins/Makefile19
-rw-r--r--tools/gcc-plugins/README.md99
-rw-r--r--tools/gcc-plugins/debian/changelog5
-rw-r--r--tools/gcc-plugins/debian/compat1
-rw-r--r--tools/gcc-plugins/debian/control19
-rw-r--r--tools/gcc-plugins/debian/copyright9
-rwxr-xr-xtools/gcc-plugins/debian/rules11
-rw-r--r--tools/gcc-plugins/debian/source/format1
-rw-r--r--tools/gcc-plugins/format-test.c107
-rw-r--r--tools/gcc-plugins/format-test.py57
-rw-r--r--tools/gcc-plugins/frr-format.c4457
-rw-r--r--tools/gcc-plugins/frr-format.h364
-rw-r--r--tools/gcc-plugins/gcc-common.h981
-rw-r--r--tools/gcc-plugins/gcc-retain-typeinfo.patch11
-rw-r--r--watchfrr/watchfrr.c11
-rw-r--r--yang/frr-bfdd.yang2
-rw-r--r--yang/frr-eigrpd.yang2
-rw-r--r--yang/frr-filter.yang2
-rw-r--r--yang/frr-interface.yang2
-rw-r--r--yang/frr-isisd.yang2
-rw-r--r--yang/frr-module-translator.yang2
-rw-r--r--yang/frr-nexthop.yang2
-rw-r--r--yang/frr-ripd.yang2
-rw-r--r--yang/frr-ripngd.yang2
-rw-r--r--yang/frr-route-map.yang42
-rw-r--r--yang/frr-route-types.yang10
-rw-r--r--yang/frr-vrrpd.yang2
-rw-r--r--yang/frr-zebra.yang65
-rw-r--r--yang/ietf/frr-deviations-ietf-interfaces.yang2
-rw-r--r--yang/ietf/frr-deviations-ietf-rip.yang2
-rw-r--r--yang/ietf/frr-deviations-ietf-routing.yang2
-rw-r--r--yang/subdir.am2
-rw-r--r--zebra/kernel_socket.c2
-rw-r--r--zebra/label_manager.c2
-rw-r--r--zebra/label_manager.h2
-rw-r--r--zebra/main.c2
-rw-r--r--zebra/redistribute.c53
-rw-r--r--zebra/rib.h10
-rw-r--r--zebra/rt_netlink.c261
-rw-r--r--zebra/rtadv.c161
-rw-r--r--zebra/rtadv.h3
-rw-r--r--zebra/subdir.am6
-rw-r--r--zebra/zapi_msg.c402
-rw-r--r--zebra/zebra_dplane.c70
-rw-r--r--zebra/zebra_dplane.h8
-rw-r--r--zebra/zebra_mpls.c56
-rw-r--r--zebra/zebra_mpls.h4
-rw-r--r--zebra/zebra_nhg.c918
-rw-r--r--zebra/zebra_nhg.h39
-rw-r--r--zebra/zebra_northbound.c2212
-rw-r--r--zebra/zebra_rib.c239
-rw-r--r--zebra/zebra_rnh.c14
-rw-r--r--zebra/zebra_routemap.c479
-rw-r--r--zebra/zebra_router.c7
-rw-r--r--zebra/zebra_router.h3
-rw-r--r--zebra/zebra_vrf.c16
-rw-r--r--zebra/zebra_vty.c608
-rw-r--r--zebra/zebra_vxlan.c61
-rw-r--r--zebra/zebra_vxlan.h6
-rw-r--r--zebra/zserv.h3
355 files changed, 18233 insertions, 3579 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in
index f740a34583..d4657dfe55 100644
--- a/alpine/APKBUILD.in
+++ b/alpine/APKBUILD.in
@@ -2,7 +2,7 @@
pkgname=frr
pkgver=@VERSION@
pkgrel=0
-pkgdesc="Free Range Routing is a fork of quagga"
+pkgdesc="FRRouting is a fork of quagga"
url="https://frrouting.org/"
arch="x86_64"
license="GPL-2.0"
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 1ec761e3b8..12e508c601 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -779,7 +779,7 @@ int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_HOPLIMIT;
} else {
-#if BFD_LINUX
+#ifdef BFD_LINUX
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_TTL;
#else
diff --git a/bfdd/config.c b/bfdd/config.c
index dd4a192694..4ae7bfdc08 100644
--- a/bfdd/config.c
+++ b/bfdd/config.c
@@ -178,7 +178,7 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
int family_type = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
int error = 0;
- log_debug("\tpeer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6");
+ log_debug(" peer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6");
JSON_FOREACH (jo, joi, join) {
key = json_object_iter_peek_name(&joi);
@@ -186,7 +186,7 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
if (strcmp(key, "multihop") == 0) {
bpc->bpc_mhop = json_object_get_boolean(jo_val);
- log_debug("\tmultihop: %s",
+ log_debug(" multihop: %s",
bpc->bpc_mhop ? "true" : "false");
} else if (strcmp(key, "peer-address") == 0) {
sval = json_object_get_string(jo_val);
@@ -197,7 +197,7 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
__func__, __LINE__, sval);
error++;
}
- log_debug("\tpeer-address: %s", sval);
+ log_debug(" peer-address: %s", sval);
} else if (strcmp(key, "local-address") == 0) {
sval = json_object_get_string(jo_val);
if (strtosa(sval, &bpc->bpc_local) != 0
@@ -208,18 +208,19 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
__func__, __LINE__, sval);
error++;
}
- log_debug("\tlocal-address: %s", sval);
+ log_debug(" local-address: %s", sval);
} else if (strcmp(key, "local-interface") == 0) {
bpc->bpc_has_localif = true;
sval = json_object_get_string(jo_val);
if (strlcpy(bpc->bpc_localif, sval,
sizeof(bpc->bpc_localif))
> sizeof(bpc->bpc_localif)) {
- log_debug("\tlocal-interface: %s (truncated)",
- sval);
+ log_debug(
+ " local-interface: %s (truncated)",
+ sval);
error++;
} else {
- log_debug("\tlocal-interface: %s", sval);
+ log_debug(" local-interface: %s", sval);
}
} else if (strcmp(key, "vrf-name") == 0) {
bpc->bpc_has_vrfname = true;
@@ -227,43 +228,44 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
if (strlcpy(bpc->bpc_vrfname, sval,
sizeof(bpc->bpc_vrfname))
> sizeof(bpc->bpc_vrfname)) {
- log_debug("\tvrf-name: %s (truncated)", sval);
+ log_debug(" vrf-name: %s (truncated)",
+ sval);
error++;
} else {
- log_debug("\tvrf-name: %s", sval);
+ log_debug(" vrf-name: %s", sval);
}
} else if (strcmp(key, "detect-multiplier") == 0) {
bpc->bpc_detectmultiplier =
json_object_get_int64(jo_val);
bpc->bpc_has_detectmultiplier = true;
- log_debug("\tdetect-multiplier: %u",
+ log_debug(" detect-multiplier: %u",
bpc->bpc_detectmultiplier);
} else if (strcmp(key, "receive-interval") == 0) {
bpc->bpc_recvinterval = json_object_get_int64(jo_val);
bpc->bpc_has_recvinterval = true;
- log_debug("\treceive-interval: %llu",
+ log_debug(" receive-interval: %" PRIu64,
bpc->bpc_recvinterval);
} else if (strcmp(key, "transmit-interval") == 0) {
bpc->bpc_txinterval = json_object_get_int64(jo_val);
bpc->bpc_has_txinterval = true;
- log_debug("\ttransmit-interval: %llu",
+ log_debug(" transmit-interval: %" PRIu64,
bpc->bpc_txinterval);
} else if (strcmp(key, "echo-interval") == 0) {
bpc->bpc_echointerval = json_object_get_int64(jo_val);
bpc->bpc_has_echointerval = true;
- log_debug("\techo-interval: %llu",
+ log_debug(" echo-interval: %" PRIu64,
bpc->bpc_echointerval);
} else if (strcmp(key, "create-only") == 0) {
bpc->bpc_createonly = json_object_get_boolean(jo_val);
- log_debug("\tcreate-only: %s",
+ log_debug(" create-only: %s",
bpc->bpc_createonly ? "true" : "false");
} else if (strcmp(key, "shutdown") == 0) {
bpc->bpc_shutdown = json_object_get_boolean(jo_val);
- log_debug("\tshutdown: %s",
+ log_debug(" shutdown: %s",
bpc->bpc_shutdown ? "true" : "false");
} else if (strcmp(key, "echo-mode") == 0) {
bpc->bpc_echo = json_object_get_boolean(jo_val);
- log_debug("\techo-mode: %s",
+ log_debug(" echo-mode: %s",
bpc->bpc_echo ? "true" : "false");
} else if (strcmp(key, "label") == 0) {
bpc->bpc_has_label = true;
@@ -271,10 +273,11 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
if (strlcpy(bpc->bpc_label, sval,
sizeof(bpc->bpc_label))
> sizeof(bpc->bpc_label)) {
- log_debug("\tlabel: %s (truncated)", sval);
+ log_debug(" label: %s (truncated)",
+ sval);
error++;
} else {
- log_debug("\tlabel: %s", sval);
+ log_debug(" label: %s", sval);
}
} else {
sval = json_object_get_string(jo_val);
@@ -309,7 +312,7 @@ static int parse_peer_label_config(struct json_object *jo,
if (pl == NULL)
return 1;
- log_debug("\tpeer-label: %s", sval);
+ log_debug(" peer-label: %s", sval);
/* Translate the label into BFD address keys. */
bs_to_bpc(pl->pl_bs, bpc);
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 0d170e5a30..221386e38d 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -898,14 +898,11 @@ struct attr *bgp_attr_default_set(struct attr *attr, uint8_t origin)
}
/* Create the attributes for an aggregate */
-struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
- struct aspath *aspath,
- struct community *community,
- struct ecommunity *ecommunity,
- struct lcommunity *lcommunity,
- struct bgp_aggregate *aggregate,
- uint8_t atomic_aggregate,
- struct prefix *p)
+struct attr *bgp_attr_aggregate_intern(
+ struct bgp *bgp, uint8_t origin, struct aspath *aspath,
+ struct community *community, struct ecommunity *ecommunity,
+ struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
+ uint8_t atomic_aggregate, const struct prefix *p)
{
struct attr attr;
struct attr *new;
@@ -1655,20 +1652,21 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
else
aggregator_as = stream_getw(peer->curr);
+ attr->aggregator_as = aggregator_as;
+ attr->aggregator_addr.s_addr = stream_get_ipv4(peer->curr);
+
+ /* Set atomic aggregate flag. */
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
+
/* Codification of AS 0 Processing */
if (aggregator_as == BGP_AS_ZERO) {
flog_err(EC_BGP_ATTR_LEN,
- "AGGREGATOR attribute is BGP_AS_ZERO(0)");
+ "AGGREGATOR AS number is 0 for aspath: %s",
+ aspath_print(attr->aspath));
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
args->total);
}
- attr->aggregator_as = aggregator_as;
- attr->aggregator_addr.s_addr = stream_get_ipv4(peer->curr);
-
- /* Set atomic aggregate flag. */
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
-
return BGP_ATTR_PARSE_PROCEED;
}
@@ -1690,20 +1688,21 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
0);
}
- /* Codification of AS 0 Processing */
aggregator_as = stream_getl(peer->curr);
+ *as4_aggregator_as = aggregator_as;
+ as4_aggregator_addr->s_addr = stream_get_ipv4(peer->curr);
+
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR);
+
+ /* Codification of AS 0 Processing */
if (aggregator_as == BGP_AS_ZERO) {
flog_err(EC_BGP_ATTR_LEN,
- "AS4_AGGREGATOR attribute is BGP_AS_ZERO(0)");
+ "AS4_AGGREGATOR AS number is 0 for aspath: %s",
+ aspath_print(attr->aspath));
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
0);
}
- *as4_aggregator_as = aggregator_as;
- as4_aggregator_addr->s_addr = stream_get_ipv4(peer->curr);
-
- attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR);
-
return BGP_ATTR_PARSE_PROCEED;
}
@@ -3416,10 +3415,10 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
}
void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
- struct prefix *p, struct prefix_rd *prd,
- mpls_label_t *label, uint32_t num_labels,
- int addpath_encode, uint32_t addpath_tx_id,
- struct attr *attr)
+ const struct prefix *p,
+ const struct prefix_rd *prd, mpls_label_t *label,
+ uint32_t num_labels, int addpath_encode,
+ uint32_t addpath_tx_id, struct attr *attr)
{
if (safi == SAFI_MPLS_VPN) {
if (addpath_encode)
@@ -3445,7 +3444,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
stream_put_prefix_addpath(s, p, addpath_encode, addpath_tx_id);
}
-size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, struct prefix *p)
+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)
@@ -4079,8 +4079,9 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
return attrlen_pnt;
}
-void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi,
- safi_t safi, struct prefix_rd *prd,
+void bgp_packet_mpunreach_prefix(struct stream *s, const struct prefix *p,
+ afi_t afi, safi_t safi,
+ const struct prefix_rd *prd,
mpls_label_t *label, uint32_t num_labels,
int addpath_encode, uint32_t addpath_tx_id,
struct attr *attr)
@@ -4130,7 +4131,7 @@ void bgp_attr_finish(void)
/* Make attribute packet. */
void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
- struct prefix *prefix)
+ const struct prefix *prefix)
{
unsigned long cp;
unsigned long len;
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index f90631c5b9..8a9902bb9f 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -87,7 +87,7 @@ struct bgp_attr_encap_subtlv {
uint8_t value[0]; /* will be extended */
};
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
/*
* old rfp<->rfapi representation
*/
@@ -233,7 +233,7 @@ struct attr {
uint16_t encap_tunneltype; /* grr */
struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */
#endif
/* EVPN */
@@ -310,22 +310,19 @@ extern void bgp_attr_unintern_sub(struct attr *);
extern void bgp_attr_unintern(struct attr **);
extern void bgp_attr_flush(struct attr *);
extern struct attr *bgp_attr_default_set(struct attr *attr, uint8_t);
-extern struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
- struct aspath *aspath,
- struct community *community,
- struct ecommunity *ecommunity,
- struct lcommunity *lcommunity,
- struct bgp_aggregate *aggregate,
- uint8_t atomic_aggregate,
- struct prefix *p);
+extern struct attr *bgp_attr_aggregate_intern(
+ struct bgp *bgp, uint8_t origin, struct aspath *aspath,
+ struct community *community, struct ecommunity *ecommunity,
+ struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
+ uint8_t atomic_aggregate, const struct prefix *p);
extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *,
struct stream *, struct attr *,
struct bpacket_attr_vec_arr *vecarr,
struct prefix *, afi_t, safi_t,
struct peer *, struct prefix_rd *,
mpls_label_t *, uint32_t, int, uint32_t);
-extern void bgp_dump_routes_attr(struct stream *, struct attr *,
- struct prefix *);
+extern void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
+ const struct prefix *p);
extern bool attrhash_cmp(const void *arg1, const void *arg2);
extern unsigned int attrhash_key_make(const void *);
extern void attr_show_all(struct vty *);
@@ -372,20 +369,21 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer,
struct bpacket_attr_vec_arr *vecarr,
struct attr *attr);
extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
- struct prefix *p, struct prefix_rd *prd,
+ const struct prefix *p,
+ const struct prefix_rd *prd,
mpls_label_t *label, uint32_t num_labels,
int addpath_encode, uint32_t addpath_tx_id,
struct attr *);
extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
- struct prefix *p);
+ const struct prefix *p);
extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep);
extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi,
safi_t safi);
-extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p,
- afi_t afi, safi_t safi,
- struct prefix_rd *prd, mpls_label_t *,
- uint32_t, int, uint32_t, struct attr *);
+extern void bgp_packet_mpunreach_prefix(
+ struct stream *s, const struct prefix *p, afi_t afi, safi_t safi,
+ const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels,
+ int addpath_encode, uint32_t addpath_tx_id, struct attr *attr);
extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
extern bgp_attr_parse_ret_t bgp_attr_nexthop_valid(struct peer *peer,
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c
index 6941e1f9b5..7239ddef93 100644
--- a/bgpd/bgp_attr_evpn.c
+++ b/bgpd/bgp_attr_evpn.c
@@ -186,7 +186,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
* one.
*/
for (i = 0; i < ecom->size; i++) {
- uint8_t *pnt;
+ const uint8_t *pnt;
uint8_t type, sub_type;
uint32_t seq_num;
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 32865da376..a6fc4ebd03 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -385,15 +385,15 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
stream_put(s, bbpeer->open_tx, bbpeer->open_tx_len);
else {
stream_put(s, dummy_open, sizeof(dummy_open));
- zlog_warn("bmp: missing TX OPEN message for peer %s\n",
- peer->host);
+ zlog_warn("bmp: missing TX OPEN message for peer %s",
+ peer->host);
}
if (bbpeer && bbpeer->open_rx)
stream_put(s, bbpeer->open_rx, bbpeer->open_rx_len);
else {
stream_put(s, dummy_open, sizeof(dummy_open));
- zlog_warn("bmp: missing RX OPEN message for peer %s\n",
- peer->host);
+ zlog_warn("bmp: missing RX OPEN message for peer %s",
+ peer->host);
}
if (peer->desc)
@@ -765,8 +765,8 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags)
stream_free(s);
}
-static struct stream *bmp_update(struct prefix *p, struct peer *peer,
- struct attr *attr, afi_t afi, safi_t safi)
+static struct stream *bmp_update(const struct prefix *p, struct peer *peer,
+ struct attr *attr, afi_t afi, safi_t safi)
{
struct bpacket_attr_vec_arr vecarr;
struct stream *s;
@@ -813,7 +813,8 @@ static struct stream *bmp_update(struct prefix *p, struct peer *peer,
return s;
}
-static struct stream *bmp_withdraw(struct prefix *p, afi_t afi, safi_t safi)
+static struct stream *bmp_withdraw(const struct prefix *p, afi_t afi,
+ safi_t safi)
{
struct stream *s;
size_t attrlen_pos = 0, mp_start, mplen_pos;
@@ -853,7 +854,7 @@ static struct stream *bmp_withdraw(struct prefix *p, afi_t afi, safi_t safi)
}
static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
- struct prefix *p, struct attr *attr, afi_t afi,
+ const struct prefix *p, struct attr *attr, afi_t afi,
safi_t safi, time_t uptime)
{
struct stream *hdr, *msg;
@@ -940,7 +941,7 @@ afibreak:
return true;
}
bmp->syncpeerid = 0;
- prefix_copy(&bmp->syncpos, &bn->p);
+ prefix_copy(&bmp->syncpos, bgp_node_get_prefix(bn));
}
if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
@@ -988,12 +989,14 @@ afibreak:
bmp->syncpeerid = adjin->peer->qobj_node.nid;
}
+ const struct prefix *bn_p = bgp_node_get_prefix(bn);
+
if (bpi)
- bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, &bn->p, bpi->attr,
+ bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, bpi->attr,
afi, safi, bpi->uptime);
if (adjin)
- bmp_monitor(bmp, adjin->peer, 0, &bn->p, adjin->attr,
- afi, safi, adjin->uptime);
+ bmp_monitor(bmp, adjin->peer, 0, bn_p, adjin->attr, afi, safi,
+ adjin->uptime);
return true;
}
@@ -1130,16 +1133,13 @@ static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp,
struct bmp *bmp;
struct bmp_queue_entry *bqe, bqeref;
size_t refcount;
- char buf[256];
-
- prefix2str(&bn->p, buf, sizeof(buf));
refcount = bmp_session_count(&bt->sessions);
if (refcount == 0)
return;
memset(&bqeref, 0, sizeof(bqeref));
- prefix_copy(&bqeref.p, &bn->p);
+ prefix_copy(&bqeref.p, bgp_node_get_prefix(bn));
bqeref.peerid = peer->qobj_node.nid;
bqeref.afi = afi;
bqeref.safi = safi;
@@ -1342,8 +1342,7 @@ static int bmp_accept(struct thread *thread)
/* We can handle IPv4 or IPv6 socket. */
bmp_sock = sockunion_accept(bl->sock, &su);
if (bmp_sock < 0) {
- zlog_info("bmp: accept_sock failed: %s\n",
- safe_strerror (errno));
+ zlog_info("bmp: accept_sock failed: %s", safe_strerror(errno));
return -1;
}
bmp_open(bl->targets, bmp_sock);
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 5c461dbe77..cf4d44ea22 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -311,9 +311,9 @@ static void community_list_delete(struct community_list_master *cm,
community_list_free(list);
}
-static int community_list_empty_p(struct community_list *list)
+static bool community_list_empty_p(struct community_list *list)
{
- return (list->head == NULL && list->tail == NULL) ? 1 : 0;
+ return list->head == NULL && list->tail == NULL;
}
/* Delete community-list entry from the list. */
@@ -497,7 +497,7 @@ static char *community_str_get(struct community *com, int i)
/* Internal function to perform regular expression match for
* a single community. */
-static int community_regexp_include(regex_t *reg, struct community *com, int i)
+static bool community_regexp_include(regex_t *reg, struct community *com, int i)
{
char *str;
int rv;
@@ -514,16 +514,12 @@ static int community_regexp_include(regex_t *reg, struct community *com, int i)
XFREE(MTYPE_COMMUNITY_STR, str);
- if (rv == 0)
- return 1;
-
- /* No match. */
- return 0;
+ return rv == 0;
}
/* Internal function to perform regular expression match for community
attribute. */
-static int community_regexp_match(struct community *com, regex_t *reg)
+static bool community_regexp_match(struct community *com, regex_t *reg)
{
const char *str;
@@ -536,10 +532,10 @@ static int community_regexp_match(struct community *com, regex_t *reg)
/* Regular expression match. */
if (regexec(reg, str, 0, NULL, 0) == 0)
- return 1;
+ return true;
/* No match. */
- return 0;
+ return false;
}
static char *lcommunity_str_get(struct lcommunity *lcom, int i)
@@ -549,7 +545,7 @@ static char *lcommunity_str_get(struct lcommunity *lcom, int i)
uint32_t localdata1;
uint32_t localdata2;
char *str;
- uint8_t *ptr;
+ const uint8_t *ptr;
char *pnt;
ptr = lcom->val + (i * LCOMMUNITY_SIZE);
@@ -574,8 +570,8 @@ static char *lcommunity_str_get(struct lcommunity *lcom, int i)
/* Internal function to perform regular expression match for
* a single community. */
-static int lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom,
- int i)
+static bool lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom,
+ int i)
{
char *str;
@@ -589,15 +585,15 @@ static int lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom,
/* Regular expression match. */
if (regexec(reg, str, 0, NULL, 0) == 0) {
XFREE(MTYPE_LCOMMUNITY_STR, str);
- return 1;
+ return true;
}
XFREE(MTYPE_LCOMMUNITY_STR, str);
/* No match. */
- return 0;
+ return false;
}
-static int lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
+static bool lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
{
const char *str;
@@ -610,14 +606,14 @@ static int lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
/* Regular expression match. */
if (regexec(reg, str, 0, NULL, 0) == 0)
- return 1;
+ return true;
/* No match. */
- return 0;
+ return false;
}
-static int ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg)
+static bool ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg)
{
const char *str;
@@ -630,10 +626,10 @@ static int ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg)
/* Regular expression match. */
if (regexec(reg, str, 0, NULL, 0) == 0)
- return 1;
+ return true;
/* No match. */
- return 0;
+ return false;
}
#if 0
@@ -718,125 +714,113 @@ community_regexp_delete (struct community *com, regex_t * reg)
/* When given community attribute matches to the community-list return
1 else return 0. */
-int community_list_match(struct community *com, struct community_list *list)
+bool community_list_match(struct community *com, struct community_list *list)
{
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
- return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+ return entry->direct == COMMUNITY_PERMIT;
if (entry->style == COMMUNITY_LIST_STANDARD) {
if (community_include(entry->u.com, COMMUNITY_INTERNET))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
if (community_match(com, entry->u.com))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
} else if (entry->style == COMMUNITY_LIST_EXPANDED) {
if (community_regexp_match(com, entry->reg))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
}
}
- return 0;
+ return false;
}
-int lcommunity_list_match(struct lcommunity *lcom, struct community_list *list)
+bool lcommunity_list_match(struct lcommunity *lcom, struct community_list *list)
{
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
- return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+ return entry->direct == COMMUNITY_PERMIT;
if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
if (lcommunity_match(lcom, entry->u.lcom))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
} else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) {
if (lcommunity_regexp_match(lcom, entry->reg))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
}
}
- return 0;
+ return false;
}
/* Perform exact matching. In case of expanded large-community-list, do
* same thing as lcommunity_list_match().
*/
-int lcommunity_list_exact_match(struct lcommunity *lcom,
- struct community_list *list)
+bool lcommunity_list_exact_match(struct lcommunity *lcom,
+ struct community_list *list)
{
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
- return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+ return entry->direct == COMMUNITY_PERMIT;
if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
if (lcommunity_cmp(lcom, entry->u.com))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
} else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) {
if (lcommunity_regexp_match(lcom, entry->reg))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
}
}
- return 0;
+ return false;
}
-int ecommunity_list_match(struct ecommunity *ecom, struct community_list *list)
+bool ecommunity_list_match(struct ecommunity *ecom, struct community_list *list)
{
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
- return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+ return entry->direct == COMMUNITY_PERMIT;
if (entry->style == EXTCOMMUNITY_LIST_STANDARD) {
if (ecommunity_match(ecom, entry->u.ecom))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
} else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) {
if (ecommunity_regexp_match(ecom, entry->reg))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
}
}
- return 0;
+ return false;
}
/* Perform exact matching. In case of expanded community-list, do
same thing as community_list_match(). */
-int community_list_exact_match(struct community *com,
- struct community_list *list)
+bool community_list_exact_match(struct community *com,
+ struct community_list *list)
{
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next) {
if (entry->any)
- return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+ return entry->direct == COMMUNITY_PERMIT;
if (entry->style == COMMUNITY_LIST_STANDARD) {
if (community_include(entry->u.com, COMMUNITY_INTERNET))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
if (community_cmp(com, entry->u.com))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
} else if (entry->style == COMMUNITY_LIST_EXPANDED) {
if (community_regexp_match(com, entry->reg))
- return entry->direct == COMMUNITY_PERMIT ? 1
- : 0;
+ return entry->direct == COMMUNITY_PERMIT;
}
}
- return 0;
+ return false;
}
/* Delete all permitted communities in the list from com. */
@@ -900,8 +884,8 @@ struct community *community_list_match_delete(struct community *com,
/* To avoid duplicated entry in the community-list, this function
compares specified entry to existing entry. */
-static int community_list_dup_check(struct community_list *list,
- struct community_entry *new)
+static bool community_list_dup_check(struct community_list *list,
+ struct community_entry *new)
{
struct community_entry *entry;
@@ -916,32 +900,32 @@ static int community_list_dup_check(struct community_list *list,
continue;
if (entry->any)
- return 1;
+ return true;
switch (entry->style) {
case COMMUNITY_LIST_STANDARD:
if (community_cmp(entry->u.com, new->u.com))
- return 1;
+ return true;
break;
case LARGE_COMMUNITY_LIST_STANDARD:
if (lcommunity_cmp(entry->u.lcom, new->u.lcom))
- return 1;
+ return true;
break;
case EXTCOMMUNITY_LIST_STANDARD:
if (ecommunity_cmp(entry->u.ecom, new->u.ecom))
- return 1;
+ return true;
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
case LARGE_COMMUNITY_LIST_EXPANDED:
if (strcmp(entry->config, new->config) == 0)
- return 1;
+ return true;
break;
default:
break;
}
}
- return 0;
+ return false;
}
/* Set community-list. */
@@ -1104,7 +1088,7 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
}
/* Helper to check if every octet do not exceed UINT_MAX */
-static int lcommunity_list_valid(const char *community)
+static bool lcommunity_list_valid(const char *community)
{
int octets = 0;
char **splits;
@@ -1114,10 +1098,10 @@ static int lcommunity_list_valid(const char *community)
for (int i = 0; i < num; i++) {
if (strtoul(splits[i], NULL, 10) > UINT_MAX)
- return 0;
+ return false;
if (strlen(splits[i]) == 0)
- return 0;
+ return false;
octets++;
XFREE(MTYPE_TMP, splits[i]);
@@ -1125,9 +1109,9 @@ static int lcommunity_list_valid(const char *community)
XFREE(MTYPE_TMP, splits);
if (octets < 3)
- return 0;
+ return false;
- return 1;
+ return true;
}
/* Set lcommunity-list. */
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
index c5718aecac..4cb5d7c593 100644
--- a/bgpd/bgp_clist.h
+++ b/bgpd/bgp_clist.h
@@ -165,13 +165,13 @@ extern struct community_list *
community_list_lookup(struct community_list_handler *c, const char *name,
uint32_t name_hash, int master);
-extern int community_list_match(struct community *, struct community_list *);
-extern int ecommunity_list_match(struct ecommunity *, struct community_list *);
-extern int lcommunity_list_match(struct lcommunity *, struct community_list *);
-extern int community_list_exact_match(struct community *,
- struct community_list *);
-extern int lcommunity_list_exact_match(struct lcommunity *lcom,
- struct community_list *list);
+extern bool community_list_match(struct community *, struct community_list *);
+extern bool ecommunity_list_match(struct ecommunity *, struct community_list *);
+extern bool lcommunity_list_match(struct lcommunity *, struct community_list *);
+extern bool community_list_exact_match(struct community *,
+ struct community_list *);
+extern bool lcommunity_list_exact_match(struct lcommunity *lcom,
+ struct community_list *list);
extern struct community *community_list_match_delete(struct community *,
struct community_list *);
extern struct lcommunity *
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 792f3cea70..538610f6d7 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -155,9 +155,9 @@ static int bgp_reuse_timer(struct thread *t)
if (bdi->lastrecord == BGP_RECORD_UPDATE) {
bgp_path_info_unset_flag(bdi->rn, bdi->path,
BGP_PATH_HISTORY);
- bgp_aggregate_increment(bgp, &bdi->rn->p,
- bdi->path, bdi->afi,
- bdi->safi);
+ bgp_aggregate_increment(
+ bgp, bgp_node_get_prefix(bdi->rn),
+ bdi->path, bdi->afi, bdi->safi);
bgp_process(bgp, bdi->rn, bdi->afi, bdi->safi);
}
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index b552b8811c..5104e23515 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -2404,7 +2404,7 @@ void bgp_debug_init(void)
/* Return true if this prefix is on the per_prefix_list of prefixes to debug
* for BGP_DEBUG_TYPE
*/
-static int bgp_debug_per_prefix(struct prefix *p,
+static int bgp_debug_per_prefix(const struct prefix *p,
unsigned long term_bgp_debug_type,
unsigned int BGP_DEBUG_TYPE,
struct list *per_prefix_list)
@@ -2489,7 +2489,7 @@ int bgp_debug_keepalive(struct peer *peer)
bgp_debug_keepalive_peers);
}
-bool bgp_debug_update(struct peer *peer, struct prefix *p,
+bool bgp_debug_update(struct peer *peer, const struct prefix *p,
struct update_group *updgrp, unsigned int inbound)
{
char *host = NULL;
@@ -2528,19 +2528,19 @@ bool bgp_debug_update(struct peer *peer, struct prefix *p,
return false;
}
-bool bgp_debug_bestpath(struct prefix *p)
+bool bgp_debug_bestpath(struct bgp_node *rn)
{
if (BGP_DEBUG(bestpath, BESTPATH)) {
- if (bgp_debug_per_prefix(p, term_bgp_debug_bestpath,
- BGP_DEBUG_BESTPATH,
- bgp_debug_bestpath_prefixes))
+ if (bgp_debug_per_prefix(
+ bgp_node_get_prefix(rn), term_bgp_debug_bestpath,
+ BGP_DEBUG_BESTPATH, bgp_debug_bestpath_prefixes))
return true;
}
return false;
}
-bool bgp_debug_zebra(struct prefix *p)
+bool bgp_debug_zebra(const struct prefix *p)
{
if (BGP_DEBUG(zebra, ZEBRA)) {
if (bgp_debug_per_prefix(p, term_bgp_debug_zebra,
@@ -2553,7 +2553,7 @@ bool bgp_debug_zebra(struct prefix *p)
}
const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
- struct prefix_rd *prd,
+ const struct prefix_rd *prd,
union prefixconstptr pu,
mpls_label_t *label, uint32_t num_labels,
int addpath_valid, uint32_t addpath_id,
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index 73007fe819..7352b7917a 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -166,15 +166,16 @@ extern void bgp_notify_print(struct peer *, struct bgp_notify *, const char *);
extern const struct message bgp_status_msg[];
extern int bgp_debug_neighbor_events(struct peer *peer);
extern int bgp_debug_keepalive(struct peer *peer);
-extern bool bgp_debug_update(struct peer *peer, struct prefix *p,
+extern bool bgp_debug_update(struct peer *peer, const struct prefix *p,
struct update_group *updgrp, unsigned int inbound);
-extern bool bgp_debug_bestpath(struct prefix *p);
-extern bool bgp_debug_zebra(struct prefix *p);
-
-extern const char *bgp_debug_rdpfxpath2str(afi_t, safi_t, struct prefix_rd *,
- union prefixconstptr, mpls_label_t *,
- uint32_t, int, uint32_t, char *,
- int);
+extern bool bgp_debug_bestpath(struct bgp_node *rn);
+extern bool bgp_debug_zebra(const struct prefix *p);
+
+extern const char *
+bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, const struct prefix_rd *prd,
+ union prefixconstptr pu, mpls_label_t *label,
+ uint32_t num_labels, int addpath_valid,
+ uint32_t addpath_id, char *str, int size);
const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data,
size_t datalen);
diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c
index c448b9894a..cd1722ccca 100644
--- a/bgpd/bgp_dump.c
+++ b/bgpd/bgp_dump.c
@@ -307,6 +307,7 @@ bgp_dump_route_node_record(int afi, struct bgp_node *rn,
struct stream *obuf;
size_t sizep;
size_t endp;
+ const struct prefix *p = bgp_node_get_prefix(rn);
obuf = bgp_dump_obuf;
stream_reset(obuf);
@@ -325,19 +326,19 @@ bgp_dump_route_node_record(int afi, struct bgp_node *rn,
stream_putl(obuf, seq);
/* Prefix length */
- stream_putc(obuf, rn->p.prefixlen);
+ stream_putc(obuf, p->prefixlen);
/* Prefix */
if (afi == AFI_IP) {
/* We'll dump only the useful bits (those not 0), but have to
* align on 8 bits */
- stream_write(obuf, (uint8_t *)&rn->p.u.prefix4,
- (rn->p.prefixlen + 7) / 8);
+ stream_write(obuf, (uint8_t *)&p->u.prefix4,
+ (p->prefixlen + 7) / 8);
} else if (afi == AFI_IP6) {
/* We'll dump only the useful bits (those not 0), but have to
* align on 8 bits */
- stream_write(obuf, (uint8_t *)&rn->p.u.prefix6,
- (rn->p.prefixlen + 7) / 8);
+ stream_write(obuf, (uint8_t *)&p->u.prefix6,
+ (p->prefixlen + 7) / 8);
}
/* Save where we are now, so we can overwride the entry count later */
@@ -361,7 +362,7 @@ bgp_dump_route_node_record(int afi, struct bgp_node *rn,
/* Dump attribute. */
/* Skip prefix & AFI/SAFI for MP_NLRI */
- bgp_dump_routes_attr(obuf, path->attr, &rn->p);
+ bgp_dump_routes_attr(obuf, path->attr, p);
cur_endp = stream_get_endp(obuf);
if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 21bfe3f126..fc66494742 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -555,7 +555,7 @@ struct ecommunity *ecommunity_str2com(const char *str, int type,
return ecom;
}
-static int ecommunity_rt_soo_str(char *buf, size_t bufsz, uint8_t *pnt,
+static int ecommunity_rt_soo_str(char *buf, size_t bufsz, const uint8_t *pnt,
int type, int sub_type, int format)
{
int len = 0;
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index c3a9527b66..a77a1e912e 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -496,7 +496,7 @@ static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn,
}
static void bgp_evpn_get_rmac_nexthop(struct bgpevpn *vpn,
- struct prefix_evpn *p,
+ const struct prefix_evpn *p,
struct attr *attr, uint8_t flags)
{
struct bgp *bgp_vrf = vpn->bgp_vrf;
@@ -583,7 +583,7 @@ static void evpn_convert_nexthop_to_ipv6(struct attr *attr)
* Add (update) or delete MACIP from zebra.
*/
static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
- struct prefix_evpn *p,
+ const struct prefix_evpn *p,
struct in_addr remote_vtep_ip, int add,
uint8_t flags, uint32_t seq)
{
@@ -651,8 +651,8 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
* Add (update) or delete remote VTEP from zebra.
*/
static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
- struct prefix_evpn *p,
- int flood_control, int add)
+ const struct prefix_evpn *p,
+ int flood_control, int add)
{
struct stream *s;
@@ -930,7 +930,8 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr)
/* Install EVPN route into zebra. */
static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
- struct prefix_evpn *p, struct bgp_path_info *pi)
+ const struct prefix_evpn *p,
+ struct bgp_path_info *pi)
{
int ret;
uint8_t flags;
@@ -970,7 +971,7 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
/* Uninstall EVPN route from zebra. */
static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
- struct prefix_evpn *p,
+ const struct prefix_evpn *p,
struct in_addr remote_vtep_ip)
{
int ret;
@@ -1004,7 +1005,7 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn,
* L3VPN routes.
*/
global_rn = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi,
- (struct prefix *)&rn->p, &vpn->prd);
+ bgp_node_get_prefix(rn), &vpn->prd);
if (global_rn) {
/* Delete route entry in the global EVPN table. */
delete_evpn_route_entry(bgp, afi, safi, global_rn, &pi);
@@ -1054,9 +1055,8 @@ static int is_vtep_present_in_list(struct list *list,
* Best path for ES route was changed,
* update the list of VTEPs for this ES
*/
-static int evpn_es_install_vtep(struct bgp *bgp,
- struct evpnes *es,
- struct prefix_evpn *p,
+static int evpn_es_install_vtep(struct bgp *bgp, struct evpnes *es,
+ const struct prefix_evpn *p,
struct in_addr rvtep)
{
struct in_addr *vtep_ip;
@@ -1128,7 +1128,7 @@ static int evpn_es_route_select_install(struct bgp *bgp,
&& !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
if (bgp_zebra_has_route_changed(rn, old_select)) {
ret = evpn_es_install_vtep(bgp, es,
- (struct prefix_evpn *)&rn->p,
+ (const struct prefix_evpn *)bgp_node_get_prefix(rn),
old_select->attr->nexthop);
}
UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
@@ -1157,13 +1157,13 @@ static int evpn_es_route_select_install(struct bgp *bgp,
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_IMPORTED) {
ret = evpn_es_install_vtep(bgp, es,
- (struct prefix_evpn *)&rn->p,
+ (const struct prefix_evpn *)bgp_node_get_prefix(rn),
new_select->attr->nexthop);
} else {
if (old_select && old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_IMPORTED)
ret = evpn_es_uninstall_vtep(
- bgp, es, (struct prefix_evpn *)&rn->p,
+ bgp, es, (struct prefix_evpn *)bgp_node_get_prefix(rn),
old_select->attr->nexthop);
}
@@ -1208,7 +1208,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
&& !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
if (bgp_zebra_has_route_changed(rn, old_select))
ret = evpn_zebra_install(
- bgp, vpn, (struct prefix_evpn *)&rn->p,
+ bgp, vpn, (const struct prefix_evpn *)bgp_node_get_prefix(rn),
old_select);
UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
bgp_zebra_clear_route_change_flags(rn);
@@ -1234,8 +1234,9 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_IMPORTED) {
- ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
- new_select);
+ ret = evpn_zebra_install(
+ bgp, vpn, (struct prefix_evpn *)bgp_node_get_prefix(rn),
+ new_select);
/* If an old best existed and it was a "local" route, the only
* reason
@@ -1251,9 +1252,11 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
} else {
if (old_select && old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_IMPORTED)
- ret = evpn_zebra_uninstall(bgp, vpn,
- (struct prefix_evpn *)&rn->p,
- old_select->attr->nexthop);
+ ret = evpn_zebra_uninstall(
+ bgp, vpn,
+ (const struct prefix_evpn *)bgp_node_get_prefix(
+ rn),
+ old_select->attr->nexthop);
}
/* Clear any route change flags. */
@@ -1330,11 +1333,11 @@ static int update_evpn_type4_route_entry(struct bgp *bgp, struct evpnes *es,
struct bgp_path_info *local_pi = NULL; /* local route entry if any */
struct bgp_path_info *remote_pi = NULL; /* remote route entry if any */
struct attr *attr_new = NULL;
- struct prefix_evpn *evp = NULL;
+ const struct prefix_evpn *evp = NULL;
*ri = NULL;
*route_changed = 1;
- evp = (struct prefix_evpn *)&rn->p;
+ evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn);
/* locate the local and remote entries if any */
for (tmp_pi = bgp_node_get_bgp_path_info(rn); tmp_pi;
@@ -1662,10 +1665,10 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
uint32_t num_labels = 1;
int route_change = 1;
uint8_t sticky = 0;
- struct prefix_evpn *evp;
+ const struct prefix_evpn *evp;
*pi = NULL;
- evp = (struct prefix_evpn *)&rn->p;
+ evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn);
memset(&label, 0, sizeof(label));
/* See if this is an update of an existing route, or a new add. */
@@ -1797,8 +1800,8 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp,
if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP
&& curr_select->sub_type == BGP_ROUTE_IMPORTED)
evpn_zebra_install(bgp, vpn,
- (struct prefix_evpn *)&rn->p,
- curr_select);
+ (const struct prefix_evpn *)bgp_node_get_prefix(rn),
+ curr_select);
}
/*
@@ -1820,13 +1823,10 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp,
struct bgp_node *rn,
struct bgp_path_info *local_pi)
{
- char buf[PREFIX_STRLEN];
-
/* local path was not picked as the winner; kick it out */
- if (bgp_debug_zebra(NULL)) {
- zlog_debug("evicting local evpn prefix %s as remote won",
- prefix2str(&rn->p, buf, sizeof(buf)));
- }
+ if (bgp_debug_zebra(NULL))
+ zlog_debug("evicting local evpn prefix %pRN as remote won", rn);
+
evpn_delete_old_local_route(bgp, vpn, rn, local_pi);
bgp_path_info_reap(rn, local_pi);
@@ -2145,7 +2145,7 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
*/
for (rn = bgp_table_top(vpn->route_table); rn;
rn = bgp_route_next(rn)) {
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn);
struct bgp_node *rd_rn;
struct bgp_path_info *global_pi;
@@ -2278,7 +2278,7 @@ static int delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
if (rdrn && bgp_node_has_bgp_path_info_data(rdrn)) {
table = bgp_node_get_bgp_table_info(rdrn);
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn);
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
continue;
@@ -2319,7 +2319,7 @@ static int delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
/* Next, walk this VNI's route table and delete local type-2 routes. */
for (rn = bgp_table_top(vpn->route_table); rn;
rn = bgp_route_next(rn)) {
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn);
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
continue;
@@ -2555,7 +2555,7 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi,
/* Install EVPN route entry in ES */
static int install_evpn_route_entry_in_es(struct bgp *bgp, struct evpnes *es,
- struct prefix_evpn *p,
+ const struct prefix_evpn *p,
struct bgp_path_info *parent_pi)
{
int ret = 0;
@@ -2619,7 +2619,7 @@ static int install_evpn_route_entry_in_es(struct bgp *bgp, struct evpnes *es,
* Install route entry into the VRF routing table and invoke route selection.
*/
static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
- struct prefix_evpn *evp,
+ const struct prefix_evpn *evp,
struct bgp_path_info *parent_pi)
{
struct bgp_node *rn;
@@ -2709,7 +2709,8 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
/* as it is an importation, change nexthop */
bgp_path_info_set_flag(rn, pi, BGP_PATH_ANNC_NH_SELF);
- bgp_aggregate_increment(bgp_vrf, &rn->p, pi, afi, safi);
+ bgp_aggregate_increment(bgp_vrf, bgp_node_get_prefix(rn), pi, afi,
+ safi);
/* Perform route selection and update zebra, if required. */
bgp_process(bgp_vrf, rn, afi, safi);
@@ -2726,7 +2727,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
* Install route entry into the VNI routing table and invoke route selection.
*/
static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
- struct prefix_evpn *p,
+ const struct prefix_evpn *p,
struct bgp_path_info *parent_pi)
{
struct bgp_node *rn;
@@ -2782,7 +2783,7 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
/* Uninstall EVPN route entry from ES route table */
static int uninstall_evpn_route_entry_in_es(struct bgp *bgp, struct evpnes *es,
- struct prefix_evpn *p,
+ const struct prefix_evpn *p,
struct bgp_path_info *parent_pi)
{
int ret;
@@ -2825,7 +2826,7 @@ static int uninstall_evpn_route_entry_in_es(struct bgp *bgp, struct evpnes *es,
* to zebra, if appropriate.
*/
static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
- struct prefix_evpn *evp,
+ const struct prefix_evpn *evp,
struct bgp_path_info *parent_pi)
{
struct bgp_node *rn;
@@ -2876,7 +2877,8 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
/* Process for route leaking. */
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi);
- bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi);
+ bgp_aggregate_decrement(bgp_vrf, bgp_node_get_prefix(rn), pi, afi,
+ safi);
/* Mark entry for deletion */
bgp_path_info_delete(rn, pi);
@@ -2895,7 +2897,7 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
* to zebra, if appropriate.
*/
static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
- struct prefix_evpn *p,
+ const struct prefix_evpn *p,
struct bgp_path_info *parent_pi)
{
struct bgp_node *rn;
@@ -2932,7 +2934,7 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
/*
* Given a prefix, see if it belongs to ES.
*/
-static int is_prefix_matching_for_es(struct prefix_evpn *p,
+static int is_prefix_matching_for_es(const struct prefix_evpn *p,
struct evpnes *es)
{
/* if not an ES route return false */
@@ -3107,7 +3109,9 @@ static int install_uninstall_routes_for_es(struct bgp *bgp,
continue;
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_node_get_prefix(
+ rn);
for (pi = bgp_node_get_bgp_path_info(rn); pi;
pi = pi->next) {
@@ -3153,7 +3157,7 @@ static int install_uninstall_routes_for_es(struct bgp *bgp,
* route into bgp vrf table and remote rmac in bridge table.
*/
static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
- struct prefix_evpn *evp,
+ const struct prefix_evpn *evp,
struct bgp_path_info *pi)
{
/* evpn route could have learnt prior to L3vni has come up,
@@ -3214,7 +3218,7 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
continue;
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn);
/* if not mac-ip route skip this route */
if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
@@ -3302,7 +3306,9 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
continue;
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_node_get_prefix(
+ rn);
if (evp->prefix.route_type != rtype)
continue;
@@ -3524,7 +3530,7 @@ static int install_uninstall_route_in_vnis(struct bgp *bgp, afi_t afi,
* Install or uninstall route for appropriate VNIs/ESIs.
*/
static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
- struct prefix *p,
+ const struct prefix *p,
struct bgp_path_info *pi, int import)
{
struct prefix_evpn *evp = (struct prefix_evpn *)p;
@@ -3774,7 +3780,8 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
*/
for (rn = bgp_table_top(vpn->route_table); rn;
rn = bgp_route_next(rn)) {
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_node_get_prefix(rn);
/* Identify MAC-IP local routes. */
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
@@ -4297,13 +4304,14 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
return ret;
}
-static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
- struct prefix_rd *prd, mpls_label_t *label,
- uint32_t num_labels, struct attr *attr)
+static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
+ const struct prefix_rd *prd,
+ mpls_label_t *label, uint32_t num_labels,
+ struct attr *attr)
{
int len;
char temp[16];
- struct evpn_addr *p_evpn_p;
+ const struct evpn_addr *p_evpn_p;
memset(&temp, 0, 16);
if (p->family != AF_EVPN)
@@ -4465,7 +4473,7 @@ static void update_autort_vni(struct hash_bucket *bucket, struct bgp *bgp)
*/
/* withdraw type-5 route corresponding to ip prefix */
-void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
+void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, const struct prefix *p,
afi_t afi, safi_t safi)
{
int ret = 0;
@@ -4499,8 +4507,9 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi)
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
&& is_route_injectable_into_evpn(pi)) {
- bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
- afi, safi);
+ bgp_evpn_withdraw_type5_route(
+ bgp_vrf, bgp_node_get_prefix(rn), afi,
+ safi);
break;
}
}
@@ -4535,7 +4544,7 @@ void bgp_evpn_install_uninstall_default_route(struct bgp *bgp_vrf, afi_t afi,
* path in the case of the attr. In the case of a local prefix (when we
* are advertising local subnets), the src_attr will be NULL.
*/
-void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p,
+void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, const struct prefix *p,
struct attr *src_attr, afi_t afi,
safi_t safi)
{
@@ -4592,18 +4601,21 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
ret = route_map_apply(
bgp_vrf->adv_cmd_rmap[afi][safi]
.map,
- &rn->p, RMAP_BGP, &tmp_pi);
+ bgp_node_get_prefix(rn),
+ RMAP_BGP, &tmp_pi);
if (ret == RMAP_DENYMATCH) {
bgp_attr_flush(&tmp_attr);
continue;
}
bgp_evpn_advertise_type5_route(
- bgp_vrf, &rn->p, &tmp_attr,
- afi, safi);
+ bgp_vrf,
+ bgp_node_get_prefix(rn),
+ &tmp_attr, afi, safi);
} else
bgp_evpn_advertise_type5_route(
- bgp_vrf, &rn->p, pi->attr,
- afi, safi);
+ bgp_vrf,
+ bgp_node_get_prefix(rn),
+ pi->attr, afi, safi);
break;
}
}
@@ -4900,7 +4912,7 @@ char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, char *buf,
* Function to convert evpn route to json format.
* NOTE: We don't use prefix2str as the output here is a bit different.
*/
-void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
+void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json)
{
char buf1[ETHER_ADDR_STRLEN];
char buf2[PREFIX2STR_BUFFER];
@@ -4965,7 +4977,7 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
* Function to convert evpn route to string.
* NOTE: We don't use prefix2str as the output here is a bit different.
*/
-char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
+char *bgp_evpn_route2str(const struct prefix_evpn *p, char *buf, int len)
{
char buf1[ETHER_ADDR_STRLEN];
char buf2[PREFIX2STR_BUFFER];
@@ -5030,8 +5042,8 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
/*
* Encode EVPN prefix in Update (MP_REACH)
*/
-void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
- struct prefix_rd *prd, mpls_label_t *label,
+void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p,
+ const struct prefix_rd *prd, mpls_label_t *label,
uint32_t num_labels, struct attr *attr,
int addpath_encode, uint32_t addpath_tx_id)
{
@@ -5550,7 +5562,7 @@ void bgp_evpn_es_free(struct bgp *bgp, struct evpnes *es)
* Import evpn route from global table to VNI/VRF/ESI.
*/
int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi,
- struct prefix *p, struct bgp_path_info *pi)
+ const struct prefix *p, struct bgp_path_info *pi)
{
return install_uninstall_evpn_route(bgp, afi, safi, p, pi, 1);
}
@@ -5559,7 +5571,7 @@ int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi,
* Unimport evpn route from VNI/VRF/ESI.
*/
int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi,
- struct prefix *p, struct bgp_path_info *pi)
+ const struct prefix *p, struct bgp_path_info *pi)
{
return install_uninstall_evpn_route(bgp, afi, safi, p, pi, 0);
}
@@ -5601,25 +5613,23 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp)
if (bgp_nexthop_self(bgp, afi,
pi->type, pi->sub_type,
pi->attr, rn)) {
+ const struct prefix *p =
+ bgp_node_get_prefix(rn);
- char attr_str[BUFSIZ] = {0};
- char pbuf[PREFIX_STRLEN];
+ if (bgp_debug_update(pi->peer, p, NULL,
+ 1)) {
+ char attr_str[BUFSIZ] = {0};
- bgp_dump_attr(pi->attr, attr_str,
- BUFSIZ);
+ bgp_dump_attr(pi->attr,
+ attr_str, BUFSIZ);
- if (bgp_debug_update(pi->peer, &rn->p,
- NULL, 1))
zlog_debug(
- "%u: prefix %s with attr %s - DENIED due to martian or self nexthop",
- bgp->vrf_id,
- prefix2str(
- &rn->p, pbuf,
- sizeof(pbuf)),
+ "%u: prefix %pRN with attr %s - DENIED due to martian or self nexthop",
+ bgp->vrf_id, rn,
attr_str);
-
+ }
bgp_evpn_unimport_route(bgp, afi, safi,
- &rn->p, pi);
+ p, pi);
bgp_rib_remove(rn, pi, pi->peer, afi,
safi);
@@ -6264,7 +6274,7 @@ void bgp_evpn_vrf_delete(struct bgp *bgp_vrf)
/*
* Get the prefixlen of the ip prefix carried within the type5 evpn route.
*/
-int bgp_evpn_get_type5_prefixlen(struct prefix *pfx)
+int bgp_evpn_get_type5_prefixlen(const struct prefix *pfx)
{
struct prefix_evpn *evp = (struct prefix_evpn *)pfx;
@@ -6280,7 +6290,7 @@ int bgp_evpn_get_type5_prefixlen(struct prefix *pfx)
/*
* Should we register nexthop for this EVPN prefix for nexthop tracking?
*/
-bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx)
+bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx)
{
struct prefix_evpn *evp = (struct prefix_evpn *)pfx;
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
index b030f0a33e..a48a707b94 100644
--- a/bgpd/bgp_evpn.h
+++ b/bgpd/bgp_evpn.h
@@ -140,11 +140,12 @@ static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
}
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
- struct prefix *p,
+ const struct prefix *p,
struct attr *src_attr, afi_t afi,
safi_t safi);
-extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
- afi_t afi, safi_t safi);
+extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf,
+ const struct prefix *p, afi_t afi,
+ safi_t safi);
extern void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi,
safi_t safi);
extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
@@ -153,18 +154,22 @@ extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf);
extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw);
extern char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels,
char *buf, int len);
-extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len);
-extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json);
-extern void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
- struct prefix_rd *prd, mpls_label_t *label,
- uint32_t num_labels, struct attr *attr,
- int addpath_encode, uint32_t addpath_tx_id);
+extern char *bgp_evpn_route2str(const struct prefix_evpn *p, char *buf,
+ int len);
+extern void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json);
+extern void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p,
+ const struct prefix_rd *prd,
+ mpls_label_t *label, uint32_t num_labels,
+ struct attr *attr, int addpath_encode,
+ uint32_t addpath_tx_id);
extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
struct bgp_nlri *packet, int withdraw);
extern int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi,
- struct prefix *p, struct bgp_path_info *ri);
+ const struct prefix *p,
+ struct bgp_path_info *ri);
extern int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi,
- struct prefix *p, struct bgp_path_info *ri);
+ const struct prefix *p,
+ struct bgp_path_info *ri);
extern int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp);
extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip,
@@ -191,8 +196,8 @@ extern void bgp_evpn_flood_control_change(struct bgp *bgp);
extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp);
extern void bgp_evpn_cleanup(struct bgp *bgp);
extern void bgp_evpn_init(struct bgp *bgp);
-extern int bgp_evpn_get_type5_prefixlen(struct prefix *pfx);
-extern bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx);
+extern int bgp_evpn_get_type5_prefixlen(const struct prefix *pfx);
+extern bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx);
extern void update_advertise_vrf_routes(struct bgp *bgp_vrf);
#endif /* _QUAGGA_BGP_EVPN_H */
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index 76cf8b2cd6..ea1ae087f1 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -366,7 +366,7 @@ static inline void encode_na_flag_extcomm(struct ecommunity_val *eval,
eval->val[2] |= ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG;
}
-static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp,
+static inline void ip_prefix_from_type5_prefix(const struct prefix_evpn *evp,
struct prefix *ip)
{
memset(ip, 0, sizeof(struct prefix));
@@ -392,7 +392,7 @@ static inline int is_evpn_prefix_default(const struct prefix *evp)
1 : 0);
}
-static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp,
+static inline void ip_prefix_from_type2_prefix(const struct prefix_evpn *evp,
struct prefix *ip)
{
memset(ip, 0, sizeof(struct prefix));
@@ -409,7 +409,7 @@ static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp,
}
}
-static inline void ip_prefix_from_evpn_prefix(struct prefix_evpn *evp,
+static inline void ip_prefix_from_evpn_prefix(const struct prefix_evpn *evp,
struct prefix *ip)
{
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
@@ -432,8 +432,9 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
memcpy(&p->prefix.macip_addr.ip, ip, sizeof(*ip));
}
-static inline void build_type5_prefix_from_ip_prefix(struct prefix_evpn *evp,
- struct prefix *ip_prefix)
+static inline void
+build_type5_prefix_from_ip_prefix(struct prefix_evpn *evp,
+ const struct prefix *ip_prefix)
{
struct ipaddr ip;
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 4f9d2a7b53..fddb00b6e2 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -59,7 +59,7 @@ struct vni_walk_ctx {
static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt,
json_object *json)
{
- uint8_t *pnt;
+ const uint8_t *pnt;
uint8_t type, sub_type;
struct ecommunity_as eas;
struct ecommunity_ip eip;
@@ -167,7 +167,7 @@ static void show_vrf_import_rt_entry(struct hash_bucket *bucket, void *args[])
static void display_import_rt(struct vty *vty, struct irt_node *irt,
json_object *json)
{
- uint8_t *pnt;
+ const uint8_t *pnt;
uint8_t type, sub_type;
struct ecommunity_as eas;
struct ecommunity_ip eip;
@@ -281,9 +281,10 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty,
uint16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
- uint8_t *pnt;
+ const uint8_t *pnt;
+ const struct prefix *p = bgp_node_get_prefix(rd_rn);
- pnt = rd_rn->p.u.val;
+ pnt = p->u.val;
/* Decode RD type. */
type = decode_rd_type(pnt);
@@ -647,8 +648,9 @@ static void show_esi_routes(struct bgp *bgp,
char prefix_str[BUFSIZ];
json_object *json_paths = NULL;
json_object *json_prefix = NULL;
+ const struct prefix *p = bgp_node_get_prefix(rn);
- bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
+ bgp_evpn_route2str((struct prefix_evpn *)p, prefix_str,
sizeof(prefix_str));
if (json)
@@ -678,7 +680,7 @@ static void show_esi_routes(struct bgp *bgp,
if (json)
json_path = json_object_new_array();
- route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN, json_path);
+ route_vty_out(vty, p, pi, 0, SAFI_EVPN, json_path);
if (json)
json_object_array_add(json_paths, json_path);
@@ -692,7 +694,7 @@ static void show_esi_routes(struct bgp *bgp,
json_object_string_add(json_prefix, "prefix",
prefix_str);
json_object_int_add(json_prefix, "prefixLen",
- rn->p.prefixlen);
+ p->prefixlen);
json_object_object_add(json_prefix, "paths",
json_paths);
json_object_object_add(json, prefix_str,
@@ -735,13 +737,15 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
tbl_ver = table->version;
for (rn = bgp_table_top(table); rn;
rn = bgp_route_next(rn)) {
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_node_get_prefix(rn);
int add_prefix_to_json = 0;
char prefix_str[BUFSIZ];
json_object *json_paths = NULL;
json_object *json_prefix = NULL;
+ const struct prefix *p = bgp_node_get_prefix(rn);
- bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
+ bgp_evpn_route2str((const struct prefix_evpn *)p, prefix_str,
sizeof(prefix_str));
if (type && evp->prefix.route_type != type)
@@ -784,7 +788,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
AFI_L2VPN, SAFI_EVPN,
json_path);
else
- route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN,
+ route_vty_out(vty, p, pi, 0, SAFI_EVPN,
json_path);
if (json)
@@ -799,7 +803,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
json_object_string_add(json_prefix, "prefix",
prefix_str);
json_object_int_add(json_prefix, "prefixLen",
- rn->p.prefixlen);
+ p->prefixlen);
json_object_object_add(json_prefix, "paths",
json_paths);
json_object_object_add(json, prefix_str,
@@ -1188,8 +1192,9 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
rn = bgp_route_next(rn)) {
uint64_t tbl_ver;
json_object *json_nroute = NULL;
+ const struct prefix *p = bgp_node_get_prefix(rn);
- if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
+ if (prd && memcmp(p->u.val, prd->val, 8) != 0)
continue;
table = bgp_node_get_bgp_table_info(rn);
@@ -1290,16 +1295,18 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
json_array = json_object_new_array();
if (option == SHOW_DISPLAY_TAGS)
- route_vty_out_tag(vty, &rm->p, pi,
- no_display, SAFI_EVPN,
- json_array);
+ route_vty_out_tag(
+ vty, bgp_node_get_prefix(rm),
+ pi, no_display, SAFI_EVPN,
+ json_array);
else if (option == SHOW_DISPLAY_OVERLAY)
- route_vty_out_overlay(vty, &rm->p, pi,
- no_display,
- json_array);
+ route_vty_out_overlay(
+ vty, bgp_node_get_prefix(rm),
+ pi, no_display, json_array);
else
- route_vty_out(vty, &rm->p, pi,
- no_display, SAFI_EVPN,
+ route_vty_out(vty,
+ bgp_node_get_prefix(rm),
+ pi, no_display, SAFI_EVPN,
json_array);
no_display = 1;
}
@@ -1308,15 +1315,19 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
output_count++;
if (use_json && json_array) {
+ const struct prefix *p =
+ bgp_node_get_prefix(rm);
+
json_prefix_info = json_object_new_object();
- json_object_string_add(json_prefix_info,
- "prefix", bgp_evpn_route2str(
- (struct prefix_evpn *)&rm->p, buf,
- BUFSIZ));
+ json_object_string_add(
+ json_prefix_info, "prefix",
+ bgp_evpn_route2str(
+ (struct prefix_evpn *)p, buf,
+ BUFSIZ));
json_object_int_add(json_prefix_info,
- "prefixLen", rm->p.prefixlen);
+ "prefixLen", p->prefixlen);
json_object_object_add(json_prefix_info,
"paths", json_array);
@@ -2580,13 +2591,14 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
/* Display all prefixes with this RD. */
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_node_get_prefix(rn);
json_object *json_prefix = NULL;
json_object *json_paths = NULL;
char prefix_str[BUFSIZ];
int add_prefix_to_json = 0;
- bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
+ bgp_evpn_route2str((struct prefix_evpn *)evp, prefix_str,
sizeof(prefix_str));
if (type && evp->prefix.route_type != type)
@@ -2703,13 +2715,14 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
json_object *json_rd = NULL; /* contains routes for an RD */
int add_rd_to_json = 0;
uint64_t tbl_ver;
+ const struct prefix *rd_rnp = bgp_node_get_prefix(rd_rn);
table = bgp_node_get_bgp_table_info(rd_rn);
if (table == NULL)
continue;
tbl_ver = table->version;
- prefix_rd2str((struct prefix_rd *)&rd_rn->p, rd_str,
+ prefix_rd2str((struct prefix_rd *)rd_rnp, rd_str,
sizeof(rd_str));
if (json)
@@ -2723,12 +2736,15 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
NULL; /* contains prefix under a RD */
json_object *json_paths =
NULL; /* array of paths under a prefix*/
- struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_node_get_prefix(
+ rn);
char prefix_str[BUFSIZ];
int add_prefix_to_json = 0;
+ const struct prefix *p = bgp_node_get_prefix(rn);
- bgp_evpn_route2str((struct prefix_evpn *)&rn->p,
- prefix_str, sizeof(prefix_str));
+ bgp_evpn_route2str((struct prefix_evpn *)p, prefix_str,
+ sizeof(prefix_str));
if (type && evp->prefix.route_type != type)
continue;
@@ -2764,15 +2780,15 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
json_object_string_add(json_prefix, "prefix",
prefix_str);
json_object_int_add(json_prefix, "prefixLen",
- rn->p.prefixlen);
+ p->prefixlen);
}
/* Prefix and num paths displayed once per prefix. */
if (detail)
route_vty_out_detail_header(
vty, bgp, rn,
- (struct prefix_rd *)&rd_rn->p,
- AFI_L2VPN, SAFI_EVPN, json_prefix);
+ (struct prefix_rd *)rd_rnp, AFI_L2VPN,
+ SAFI_EVPN, json_prefix);
/* For EVPN, the prefix is displayed for each path (to
* fit in
@@ -2792,8 +2808,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
vty, bgp, rn, pi, AFI_L2VPN,
SAFI_EVPN, json_path);
} else
- route_vty_out(vty, &rn->p, pi, 0,
- SAFI_EVPN, json_path);
+ route_vty_out(vty, p, pi, 0, SAFI_EVPN,
+ json_path);
if (json)
json_object_array_add(json_paths,
diff --git a/bgpd/bgp_flowspec.h b/bgpd/bgp_flowspec.h
index bc201b739f..94c571f2fc 100644
--- a/bgpd/bgp_flowspec.h
+++ b/bgpd/bgp_flowspec.h
@@ -43,7 +43,7 @@ extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
char *return_string, int format,
json_object *json_path);
-extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
+extern void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display,
json_object *json_paths);
extern int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp,
diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c
index c117d08bfb..9d824a8641 100644
--- a/bgpd/bgp_flowspec_util.c
+++ b/bgpd/bgp_flowspec_util.c
@@ -76,9 +76,8 @@ static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content, int len,
return ret;
}
-bool bgp_flowspec_contains_prefix(struct prefix *pfs,
- struct prefix *input,
- int prefix_check)
+bool bgp_flowspec_contains_prefix(const struct prefix *pfs,
+ struct prefix *input, int prefix_check)
{
uint32_t offset = 0;
int type;
@@ -608,7 +607,8 @@ bool bgp_flowspec_get_first_nh(struct bgp *bgp, struct bgp_path_info *pi,
struct bgp_pbr_entry_action *api_action;
memset(&api, 0, sizeof(struct bgp_pbr_entry_main));
- if (bgp_pbr_build_and_validate_entry(&rn->p, pi, &api) < 0)
+ if (bgp_pbr_build_and_validate_entry(bgp_node_get_prefix(rn), pi, &api)
+ < 0)
return true;
for (i = 0; i < api.action_num; i++) {
api_action = &api.actions[i];
diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h
index bd89176bec..0e78c7a53c 100644
--- a/bgpd/bgp_flowspec_util.h
+++ b/bgpd/bgp_flowspec_util.h
@@ -50,7 +50,7 @@ struct bgp_pbr_entry_main;
extern int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
struct bgp_pbr_entry_main *bpem);
-extern bool bgp_flowspec_contains_prefix(struct prefix *pfs,
+extern bool bgp_flowspec_contains_prefix(const struct prefix *pfs,
struct prefix *input,
int prefix_check);
diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c
index 80384c12c6..c852e18c46 100644
--- a/bgpd/bgp_flowspec_vty.c
+++ b/bgpd/bgp_flowspec_vty.c
@@ -252,7 +252,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
}
}
-void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
+void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display,
json_object *json_paths)
{
@@ -409,8 +409,8 @@ int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi,
}
for (; pi; pi = pi->next) {
total_count++;
- route_vty_out_flowspec(vty, &rn->p, pi, display,
- json_paths);
+ route_vty_out_flowspec(vty, bgp_node_get_prefix(rn), pi,
+ display, json_paths);
}
if (use_json) {
vty_out(vty, "%s\n",
@@ -554,18 +554,18 @@ extern int bgp_flowspec_display_match_per_ip(afi_t afi, struct bgp_table *rib,
json_object *json_paths)
{
struct bgp_node *rn;
- struct prefix *prefix;
+ const struct prefix *prefix;
int display = 0;
for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
- prefix = &rn->p;
+ prefix = bgp_node_get_prefix(rn);
if (prefix->family != AF_FLOWSPEC)
continue;
if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) {
route_vty_out_flowspec(
- vty, &rn->p, bgp_node_get_bgp_path_info(rn),
+ vty, prefix, bgp_node_get_bgp_path_info(rn),
use_json ? NLRI_STRING_FORMAT_JSON
: NLRI_STRING_FORMAT_LARGE,
json_paths);
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
index ff1ab1a37d..ec44037bf7 100644
--- a/bgpd/bgp_label.c
+++ b/bgpd/bgp_label.c
@@ -132,7 +132,6 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
{
struct bgp_path_info *pi;
struct bgp_node *rn;
- char addr[PREFIX_STRLEN];
pi = labelid;
/* Is this path still valid? */
@@ -145,10 +144,9 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
}
rn = pi->net;
- prefix2str(&rn->p, addr, PREFIX_STRLEN);
if (BGP_DEBUG(labelpool, LABELPOOL))
- zlog_debug("%s: FEC %s label=%u, allocated=%d", __func__, addr,
+ zlog_debug("%s: FEC %pRN label=%u, allocated=%d", __func__, rn,
new_label, allocated);
if (!allocated) {
@@ -174,8 +172,8 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
if (pi->attr->label_index != MPLS_INVALID_LABEL_INDEX) {
flog_err(
EC_BGP_LABEL,
- "%s: FEC %s Rejecting allocated label %u as Label Index is %u",
- __func__, addr, new_label, pi->attr->label_index);
+ "%s: FEC %pRN Rejecting allocated label %u as Label Index is %u",
+ __func__, rn, new_label, pi->attr->label_index);
bgp_register_for_label(pi->net, pi);
@@ -189,8 +187,8 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
}
/* Shouldn't happen: different label allocation */
flog_err(EC_BGP_LABEL,
- "%s: %s had label %u but got new assignment %u",
- __func__, addr, pi->attr->label, new_label);
+ "%s: %pRN had label %u but got new assignment %u",
+ __func__, rn, pi->attr->label, new_label);
/* continue means use new one */
}
@@ -210,14 +208,14 @@ void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi,
{
bool with_label_index = false;
struct stream *s;
- struct prefix *p;
+ const struct prefix *p;
mpls_label_t *local_label;
int command;
uint16_t flags = 0;
size_t flags_pos = 0;
char addr[PREFIX_STRLEN];
- p = &(rn->p);
+ p = bgp_node_get_prefix(rn);
local_label = &(rn->local_label);
/* this prevents the loop when we're called by
* bgp_reg_for_label_callback()
@@ -473,7 +471,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
if (pnt != lim) {
flog_err(
EC_BGP_UPDATE_RCV,
- "%s [Error] Update packet error / L-U (%zu data remaining after parsing)",
+ "%s [Error] Update packet error / L-U (%td data remaining after parsing)",
peer->host, lim - pnt);
return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
}
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
index 324505418c..ec7d07fe73 100644
--- a/bgpd/bgp_lcommunity.c
+++ b/bgpd/bgp_lcommunity.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
*
- * This file is part of FreeRangeRouting (FRR).
+ * 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
@@ -178,7 +178,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
int i;
int len;
char *str_buf;
- uint8_t *pnt;
+ const uint8_t *pnt;
uint32_t global, local1, local2;
json_object *json_lcommunity_list = NULL;
json_object *json_string = NULL;
diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h
index e10ab0eef1..c96df8482d 100644
--- a/bgpd/bgp_lcommunity.h
+++ b/bgpd/bgp_lcommunity.h
@@ -2,7 +2,7 @@
*
* Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
*
- * This file is part of FreeRangeRouting (FRR).
+ * 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
diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c
index 537bb45455..af20e5fdd7 100644
--- a/bgpd/bgp_mac.c
+++ b/bgpd/bgp_mac.c
@@ -142,13 +142,15 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
for (prn = bgp_table_top(table); prn; prn = bgp_route_next(prn)) {
struct bgp_table *sub = prn->info;
+ const struct prefix *prn_p = bgp_node_get_prefix(prn);
if (!sub)
continue;
for (rn = bgp_table_top(sub); rn; rn = bgp_route_next(rn)) {
bool rn_affected;
- struct prefix_evpn *pevpn = (struct prefix_evpn *)&rn->p;
+ const struct prefix *p = bgp_node_get_prefix(rn);
+ const struct prefix_evpn *pevpn = (const struct prefix_evpn *)p;
struct prefix_rd prd;
uint32_t num_labels = 0;
mpls_label_t *label_pnt = NULL;
@@ -156,7 +158,7 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
if (pevpn->family == AF_EVPN &&
pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
- memcmp(&rn->p.u.prefix_evpn.macip_addr.mac,
+ memcmp(&p->u.prefix_evpn.macip_addr.mac,
macaddr, ETH_ALEN) == 0)
rn_affected = true;
else
@@ -185,15 +187,15 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
- memcpy(&prd.val, &prn->p.u.val, 8);
+ memcpy(&prd.val, prn_p->u.val, 8);
if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
- if (bgp_debug_update(peer, &rn->p, NULL, 1)) {
+ if (bgp_debug_update(peer, p, NULL, 1)) {
char pfx_buf[BGP_PRD_PATH_STRLEN];
bgp_debug_rdpfxpath2str(
AFI_L2VPN, SAFI_EVPN, &prd,
- &rn->p, label_pnt, num_labels,
+ p, label_pnt, num_labels,
pi->addpath_rx_id ? 1 : 0,
pi->addpath_rx_id, pfx_buf,
sizeof(pfx_buf));
@@ -205,7 +207,7 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
}
memcpy(&evpn, &pi->attr->evpn_overlay, sizeof(evpn));
- int32_t ret = bgp_update(peer, &rn->p,
+ int32_t ret = bgp_update(peer, p,
pi->addpath_rx_id,
pi->attr, AFI_L2VPN, SAFI_EVPN,
ZEBRA_ROUTE_BGP,
@@ -358,7 +360,7 @@ void bgp_mac_del_mac_entry(struct interface *ifp)
* An example: router-mac attribute in any of evpn update
* requires to compare against local mac.
*/
-bool bgp_mac_exist(struct ethaddr *mac)
+bool bgp_mac_exist(const struct ethaddr *mac)
{
struct bgp_self_mac lookup;
struct bgp_self_mac *bsm;
@@ -379,9 +381,9 @@ bool bgp_mac_exist(struct ethaddr *mac)
* mac against any of local assigned (SVIs) MAC
* address.
*/
-bool bgp_mac_entry_exists(struct prefix *p)
+bool bgp_mac_entry_exists(const struct prefix *p)
{
- struct prefix_evpn *pevpn = (struct prefix_evpn *)p;
+ const struct prefix_evpn *pevpn = (const struct prefix_evpn *)p;
if (pevpn->family != AF_EVPN)
return false;
diff --git a/bgpd/bgp_mac.h b/bgpd/bgp_mac.h
index 68449b574a..4b94d80d1a 100644
--- a/bgpd/bgp_mac.h
+++ b/bgpd/bgp_mac.h
@@ -36,7 +36,7 @@ void bgp_mac_dump_table(struct vty *vty);
/*
* Function to lookup the prefix and see if we have a matching mac
*/
-bool bgp_mac_entry_exists(struct prefix *p);
-bool bgp_mac_exist(struct ethaddr *mac);
+bool bgp_mac_entry_exists(const struct prefix *p);
+bool bgp_mac_exist(const struct ethaddr *mac);
#endif
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index c4ece2f082..c14a1a05ac 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -228,7 +228,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
community_list_terminate(bgp_clist);
bgp_vrf_terminate();
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
vnc_zebra_destroy();
#endif
bgp_zebra_destroy();
@@ -275,7 +275,7 @@ static int bgp_vrf_enable(struct vrf *vrf)
XFREE(MTYPE_BGP, bgp->name_pretty);
bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default");
bgp->inst_type = BGP_INSTANCE_TYPE_DEFAULT;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (!bgp->rfapi) {
bgp->rfapi = bgp_rfapi_new(bgp);
assert(bgp->rfapi);
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 9e73acdc01..cbef41bafd 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -447,7 +447,7 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
struct listnode *mp_node, *mp_next_node;
struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
int mpath_changed, debug;
- char pfx_buf[PREFIX2STR_BUFFER], nh_buf[2][INET6_ADDRSTRLEN];
+ char nh_buf[2][INET6_ADDRSTRLEN];
char path_buf[PATH_ADDPATH_STR_BUFFER];
mpath_changed = 0;
@@ -457,10 +457,7 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
old_mpath_count = 0;
prev_mpath = new_best;
mp_node = listhead(mp_list);
- debug = bgp_debug_bestpath(&rn->p);
-
- if (debug)
- prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
+ debug = bgp_debug_bestpath(rn);
if (new_best) {
mpath_count++;
@@ -480,8 +477,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
if (debug)
zlog_debug(
- "%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d",
- pfx_buf, new_best ? new_best->peer->host : "NONE",
+ "%pRN: starting mpath update, newbest %s num candidates %d old-mpath-count %d",
+ rn, new_best ? new_best->peer->host : "NONE",
mp_list ? listcount(mp_list) : 0, old_mpath_count);
/*
@@ -513,8 +510,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
if (debug)
zlog_debug(
- "%s: comparing candidate %s with existing mpath %s",
- pfx_buf,
+ "%pRN: comparing candidate %s with existing mpath %s",
+ rn,
tmp_info ? tmp_info->peer->host : "NONE",
cur_mpath ? cur_mpath->peer->host : "NONE");
@@ -537,8 +534,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
bgp_path_info_path_with_addpath_rx_str(
cur_mpath, path_buf);
zlog_debug(
- "%s: %s is still multipath, cur count %d",
- pfx_buf, path_buf, mpath_count);
+ "%pRN: %s is still multipath, cur count %d",
+ rn, path_buf, mpath_count);
}
} else {
mpath_changed = 1;
@@ -546,8 +543,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
bgp_path_info_path_with_addpath_rx_str(
cur_mpath, path_buf);
zlog_debug(
- "%s: remove mpath %s nexthop %s, cur count %d",
- pfx_buf, path_buf,
+ "%pRN: remove mpath %s nexthop %s, cur count %d",
+ rn, path_buf,
inet_ntop(AF_INET,
&cur_mpath->attr
->nexthop,
@@ -579,8 +576,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
bgp_path_info_path_with_addpath_rx_str(
cur_mpath, path_buf);
zlog_debug(
- "%s: remove mpath %s nexthop %s, cur count %d",
- pfx_buf, path_buf,
+ "%pRN: remove mpath %s nexthop %s, cur count %d",
+ rn, path_buf,
inet_ntop(AF_INET,
&cur_mpath->attr->nexthop,
nh_buf[0], sizeof(nh_buf[0])),
@@ -624,8 +621,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
bgp_path_info_path_with_addpath_rx_str(
new_mpath, path_buf);
zlog_debug(
- "%s: add mpath %s nexthop %s, cur count %d",
- pfx_buf, path_buf,
+ "%pRN: add mpath %s nexthop %s, cur count %d",
+ rn, path_buf,
inet_ntop(AF_INET,
&new_mpath->attr
->nexthop,
@@ -641,8 +638,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
if (new_best) {
if (debug)
zlog_debug(
- "%s: New mpath count (incl newbest) %d mpath-change %s",
- pfx_buf, mpath_count,
+ "%pRN: New mpath count (incl newbest) %d mpath-change %s",
+ rn, mpath_count,
mpath_changed ? "YES" : "NO");
bgp_path_info_mpath_count_set(new_best, mpath_count - 1);
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 3e2ba9802a..46dcd2864e 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -48,7 +48,7 @@
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_evpn.h"
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
#endif
@@ -214,7 +214,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
decode_rd_ip(pnt + 5, &rd_ip);
break;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
case RD_TYPE_VNC_ETH:
break;
#endif
@@ -244,7 +244,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
if (pnt != lim) {
flog_err(
EC_BGP_UPDATE_RCV,
- "%s [Error] Update packet error / VPN (%zu data remaining after parsing)",
+ "%s [Error] Update packet error / VPN (%td data remaining after parsing)",
peer->host, lim - pnt);
return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
}
@@ -468,18 +468,16 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
struct bgp *bgp_orig, struct prefix *nexthop_orig,
int nexthop_self_flag, int debug)
{
- struct prefix *p = &bn->p;
+ const struct prefix *p = bgp_node_get_prefix(bn);
struct bgp_path_info *bpi;
struct bgp_path_info *bpi_ultimate;
struct bgp_path_info *new;
- char buf_prefix[PREFIX_STRLEN];
- if (debug) {
- prefix2str(&bn->p, buf_prefix, sizeof(buf_prefix));
- zlog_debug("%s: entry: leak-to=%s, p=%s, type=%d, sub_type=%d",
- __func__, bgp->name_pretty, buf_prefix,
- source_bpi->type, source_bpi->sub_type);
- }
+ if (debug)
+ zlog_debug(
+ "%s: entry: leak-to=%s, p=%pRN, type=%d, sub_type=%d",
+ __func__, bgp->name_pretty, bn, source_bpi->type,
+ source_bpi->sub_type);
/*
* Routes that are redistributed into BGP from zebra do not get
@@ -518,9 +516,8 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
bgp_attr_unintern(&new_attr);
if (debug)
zlog_debug(
- "%s: ->%s: %s: Found route, no change",
- __func__, bgp->name_pretty,
- buf_prefix);
+ "%s: ->%s: %pRN: Found route, no change",
+ __func__, bgp->name_pretty, bn);
return NULL;
}
@@ -580,8 +577,8 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
bgp_unlock_node(bn);
if (debug)
- zlog_debug("%s: ->%s: %s Found route, changed attr",
- __func__, bgp->name_pretty, buf_prefix);
+ zlog_debug("%s: ->%s: %pRN Found route, changed attr",
+ __func__, bgp->name_pretty, bn);
return bpi;
}
@@ -645,8 +642,8 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
bgp_process(bgp, bn, afi, safi);
if (debug)
- zlog_debug("%s: ->%s: %s: Added new route", __func__,
- bgp->name_pretty, buf_prefix);
+ zlog_debug("%s: ->%s: %pRN: Added new route", __func__,
+ bgp->name_pretty, bn);
return new;
}
@@ -657,7 +654,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
struct bgp_path_info *path_vrf) /* route */
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
- struct prefix *p = &path_vrf->net->p;
+ const struct prefix *p = bgp_node_get_prefix(path_vrf->net);
afi_t afi = family2afi(p->family);
struct attr static_attr = {0};
struct attr *new_attr = NULL;
@@ -891,19 +888,17 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
struct bgp_path_info *path_vrf) /* route */
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
- struct prefix *p = &path_vrf->net->p;
+ const struct prefix *p = bgp_node_get_prefix(path_vrf->net);
afi_t afi = family2afi(p->family);
safi_t safi = SAFI_MPLS_VPN;
struct bgp_path_info *bpi;
struct bgp_node *bn;
const char *debugmsg;
- char buf_prefix[PREFIX_STRLEN];
if (debug) {
- prefix2str(p, buf_prefix, sizeof(buf_prefix));
zlog_debug(
- "%s: entry: leak-from=%s, p=%s, type=%d, sub_type=%d",
- __func__, bgp_vrf->name_pretty, buf_prefix,
+ "%s: entry: leak-from=%s, p=%pRN, type=%d, sub_type=%d",
+ __func__, bgp_vrf->name_pretty, path_vrf->net,
path_vrf->type, path_vrf->sub_type);
}
@@ -980,14 +975,10 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
continue;
for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
-
- char buf[PREFIX2STR_BUFFER];
-
bpi = bgp_node_get_bgp_path_info(bn);
if (debug && bpi) {
- zlog_debug(
- "%s: looking at prefix %s", __func__,
- prefix2str(&bn->p, buf, sizeof(buf)));
+ zlog_debug("%s: looking at prefix %pRN",
+ __func__, bn);
}
for (; bpi; bpi = bpi->next) {
@@ -1005,8 +996,10 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
if (debug)
zlog_debug("%s: deleting it",
__func__);
- bgp_aggregate_decrement(bgp_vpn, &bn->p,
- bpi, afi, safi);
+ bgp_aggregate_decrement(
+ bgp_vpn,
+ bgp_node_get_prefix(bn), bpi,
+ afi, safi);
bgp_path_info_delete(bn, bpi);
bgp_process(bgp_vpn, bn, afi, safi);
}
@@ -1049,7 +1042,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
struct bgp *bgp_vpn, /* from */
struct bgp_path_info *path_vpn) /* route */
{
- struct prefix *p = &path_vpn->net->p;
+ const struct prefix *p = bgp_node_get_prefix(path_vpn->net);
afi_t afi = family2afi(p->family);
struct attr static_attr = {0};
@@ -1228,12 +1221,9 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
}
}
- if (debug) {
- char buf_prefix[PREFIX_STRLEN];
- prefix2str(p, buf_prefix, sizeof(buf_prefix));
- zlog_debug("%s: pfx %s: num_labels %d", __func__, buf_prefix,
- num_labels);
- }
+ if (debug)
+ zlog_debug("%s: pfx %pRN: num_labels %d", __func__,
+ path_vpn->net, num_labels);
/*
* For VRF-2-VRF route-leaking,
@@ -1273,7 +1263,7 @@ void vpn_leak_to_vrf_update(struct bgp *bgp_vpn, /* from */
void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
struct bgp_path_info *path_vpn) /* route */
{
- struct prefix *p;
+ const struct prefix *p;
afi_t afi;
safi_t safi = SAFI_UNICAST;
struct bgp *bgp;
@@ -1281,21 +1271,18 @@ void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
struct bgp_node *bn;
struct bgp_path_info *bpi;
const char *debugmsg;
- char buf_prefix[PREFIX_STRLEN];
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
- if (debug) {
- prefix2str(&path_vpn->net->p, buf_prefix, sizeof(buf_prefix));
- zlog_debug("%s: entry: p=%s, type=%d, sub_type=%d", __func__,
- buf_prefix, path_vpn->type, path_vpn->sub_type);
- }
+ if (debug)
+ zlog_debug("%s: entry: p=%pRN, type=%d, sub_type=%d", __func__,
+ path_vpn->net, path_vpn->type, path_vpn->sub_type);
if (debug)
zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn);
if (!path_vpn->net) {
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
/* BGP_ROUTE_RFP routes do not have path_vpn->net set (yet) */
if (path_vpn->type == ZEBRA_ROUTE_BGP
&& path_vpn->sub_type == BGP_ROUTE_RFP) {
@@ -1310,7 +1297,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
return;
}
- p = &path_vpn->net->p;
+ p = bgp_node_get_prefix(path_vpn->net);
afi = family2afi(p->family);
/* Loop over VRFs */
@@ -1381,8 +1368,9 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
&& is_pi_family_vpn(bpi->extra->parent)) {
/* delete route */
- bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi,
- afi, safi);
+ bgp_aggregate_decrement(bgp_vrf,
+ bgp_node_get_prefix(bn),
+ bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
bgp_process(bgp_vrf, bn, afi, safi);
}
@@ -1405,7 +1393,7 @@ void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */
*/
for (prn = bgp_table_top(bgp_vpn->rib[afi][safi]); prn;
prn = bgp_route_next(prn)) {
-
+ const struct prefix *p = bgp_node_get_prefix(prn);
struct bgp_table *table;
struct bgp_node *bn;
struct bgp_path_info *bpi;
@@ -1413,7 +1401,7 @@ void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */
memset(&prd, 0, sizeof(prd));
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
- memcpy(prd.val, prn->p.u.val, 8);
+ memcpy(prd.val, &p->u.val, 8);
/* This is the per-RD table of prefixes */
table = bgp_node_get_bgp_table_info(prn);
@@ -1805,8 +1793,9 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
vpn_leak_prechange(idir, afi, bgp_get_default(), to_bgp);
if (to_bgp->vpn_policy[afi].import_vrf->count == 0) {
- UNSET_FLAG(to_bgp->af_flags[afi][safi],
- BGP_CONFIG_VRF_TO_VRF_IMPORT);
+ if (!to_bgp->vpn_policy[afi].rmap[idir])
+ UNSET_FLAG(to_bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT);
if (to_bgp->vpn_policy[afi].rtlist[idir])
ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]);
} else {
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 23c5adbf28..c77238aa33 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -49,7 +49,7 @@ DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Address Intf String");
char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size)
{
- prefix2str(&(bnc->node->p), buf, size);
+ prefix2str(bgp_node_get_prefix(bnc->node), buf, size);
return buf;
}
@@ -476,7 +476,7 @@ bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
uint8_t new_afi = afi == AFI_IP ? AF_INET : AF_INET6;
struct bgp_addr tmp_addr = {{0}}, *addr = NULL;
struct tip_addr tmp_tip, *tip = NULL;
-
+ const struct prefix *p = bgp_node_get_prefix(rn);
bool is_bgp_static_route =
((type == ZEBRA_ROUTE_BGP) && (sub_type == BGP_ROUTE_STATIC))
? true
@@ -489,8 +489,8 @@ bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
switch (new_afi) {
case AF_INET:
if (is_bgp_static_route) {
- tmp_addr.p.u.prefix4 = rn->p.u.prefix4;
- tmp_addr.p.prefixlen = rn->p.prefixlen;
+ tmp_addr.p.u.prefix4 = p->u.prefix4;
+ tmp_addr.p.prefixlen = p->prefixlen;
} else {
/* Here we need to find out which nexthop to be used*/
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
@@ -510,8 +510,8 @@ bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
break;
case AF_INET6:
if (is_bgp_static_route) {
- tmp_addr.p.u.prefix6 = rn->p.u.prefix6;
- tmp_addr.p.prefixlen = rn->p.prefixlen;
+ tmp_addr.p.u.prefix6 = p->u.prefix6;
+ tmp_addr.p.prefixlen = p->prefixlen;
} else {
tmp_addr.p.u.prefix6 = attr->mp_nexthop_global;
tmp_addr.p.prefixlen = IPV6_MAX_BITLEN;
@@ -763,6 +763,7 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail,
for (rn = bgp_table_top(table[afi]); rn;
rn = bgp_route_next(rn)) {
struct peer *peer;
+ const struct prefix *p = bgp_node_get_prefix(rn);
bnc = bgp_node_get_bgp_nexthop_info(rn);
if (!bnc)
@@ -772,8 +773,7 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail,
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
vty_out(vty,
" %s valid [IGP metric %d], #paths %d",
- inet_ntop(rn->p.family,
- &rn->p.u.prefix, buf,
+ inet_ntop(p->family, &p->u.prefix, buf,
sizeof(buf)),
bnc->metric, bnc->path_count);
if (peer)
@@ -787,8 +787,7 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail,
} else {
vty_out(vty, " %s invalid",
- inet_ntop(rn->p.family,
- &rn->p.u.prefix, buf,
+ inet_ntop(p->family, &p->u.prefix, buf,
sizeof(buf)));
if (peer)
vty_out(vty, ", peer %s", peer->host);
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index dfa9ac9398..0531542a38 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -130,6 +130,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
struct bgp_nexthop_cache *bnc;
struct prefix p;
int is_bgp_static_route = 0;
+ const struct prefix *bnc_p;
if (pi) {
is_bgp_static_route = ((pi->type == ZEBRA_ROUTE_BGP)
@@ -181,6 +182,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
}
}
+ bnc_p = bgp_node_get_prefix(bnc->node);
+
bgp_unlock_node(rn);
if (is_bgp_static_route) {
SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
@@ -226,8 +229,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) {
SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
- } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED) &&
- !is_default_host_route(&bnc->node->p))
+ } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)
+ && !is_default_host_route(bnc_p))
register_zebra_rnh(bnc, is_bgp_static_route);
if (pi && pi->nexthop != bnc) {
@@ -528,7 +531,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
? 1
: 0;
struct bgp_node *net = pi->net;
- struct prefix *p_orig = &net->p;
+ const struct prefix *p_orig = bgp_node_get_prefix(net);
if (p_orig->family == AF_FLOWSPEC) {
if (!pi->peer)
@@ -541,8 +544,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
case AFI_IP:
p->family = AF_INET;
if (is_bgp_static) {
- p->u.prefix4 = pi->net->p.u.prefix4;
- p->prefixlen = pi->net->p.prefixlen;
+ p->u.prefix4 = p_orig->u.prefix4;
+ p->prefixlen = p_orig->prefixlen;
} else {
p->u.prefix4 = pi->attr->nexthop;
p->prefixlen = IPV4_MAX_BITLEN;
@@ -552,8 +555,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
p->family = AF_INET6;
if (is_bgp_static) {
- p->u.prefix6 = pi->net->p.u.prefix6;
- p->prefixlen = pi->net->p.prefixlen;
+ p->u.prefix6 = p_orig->u.prefix6;
+ p->prefixlen = p_orig->prefixlen;
} else {
p->u.prefix6 = pi->attr->mp_nexthop_global;
p->prefixlen = IPV6_MAX_BITLEN;
@@ -581,7 +584,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
*/
static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
{
- struct prefix *p;
+ const struct prefix *p;
bool exact_match = false;
int ret;
@@ -603,7 +606,7 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
"%s: We have not connected yet, cannot send nexthops",
__func__);
}
- p = &(bnc->node->p);
+ p = bgp_node_get_prefix(bnc->node);
if ((command == ZEBRA_NEXTHOP_REGISTER
|| command == ZEBRA_IMPORT_ROUTE_REGISTER)
&& (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
@@ -691,6 +694,7 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
struct bgp_table *table;
safi_t safi;
struct bgp *bgp_path;
+ const struct prefix *p;
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
@@ -710,7 +714,8 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
rn = path->net;
assert(rn && bgp_node_table(rn));
- afi = family2afi(rn->p.family);
+ p = bgp_node_get_prefix(rn);
+ afi = family2afi(p->family);
table = bgp_node_table(rn);
safi = table->safi;
@@ -744,27 +749,23 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
bgp_isvalid_nexthop(bnc) ? 1 : 0;
}
- if (BGP_DEBUG(nht, NHT)) {
- char buf[PREFIX_STRLEN];
-
- prefix2str(&rn->p, buf, PREFIX_STRLEN);
- zlog_debug("%s: prefix %s (vrf %s) %svalid",
- __func__, buf, bgp_path->name,
- (bnc_is_valid_nexthop ? "" : "not "));
- }
+ if (BGP_DEBUG(nht, NHT))
+ zlog_debug("%s: prefix %pRN (vrf %s) %svalid", __func__,
+ rn, bgp_path->name,
+ (bnc_is_valid_nexthop ? "" : "not "));
if ((CHECK_FLAG(path->flags, BGP_PATH_VALID) ? 1 : 0)
!= bnc_is_valid_nexthop) {
if (CHECK_FLAG(path->flags, BGP_PATH_VALID)) {
- bgp_aggregate_decrement(bgp_path, &rn->p,
- path, afi, safi);
+ bgp_aggregate_decrement(bgp_path, p, path, afi,
+ safi);
bgp_path_info_unset_flag(rn, path,
BGP_PATH_VALID);
} else {
bgp_path_info_set_flag(rn, path,
BGP_PATH_VALID);
- bgp_aggregate_increment(bgp_path, &rn->p,
- path, afi, safi);
+ bgp_aggregate_increment(bgp_path, p, path, afi,
+ safi);
}
}
@@ -780,14 +781,13 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
|| CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED);
- if (safi == SAFI_EVPN &&
- bgp_evpn_is_prefix_nht_supported(&rn->p)) {
+ if (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p)) {
if (CHECK_FLAG(path->flags, BGP_PATH_VALID))
- bgp_evpn_import_route(bgp_path, afi, safi,
- &rn->p, path);
+ bgp_evpn_import_route(bgp_path, afi, safi, p,
+ path);
else
- bgp_evpn_unimport_route(bgp_path, afi, safi,
- &rn->p, path);
+ bgp_evpn_unimport_route(bgp_path, afi, safi, p,
+ path);
}
bgp_process(bgp_path, rn, afi, safi);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index ae4f521b9c..7137c1a784 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1362,8 +1362,9 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
peer->afc[AFI_IP6][SAFI_FLOWSPEC];
}
- /* When collision is detected and this peer is closed. Retrun
- immidiately. */
+ /* When collision is detected and this peer is closed.
+ * Return immediately.
+ */
ret = bgp_collision_detect(peer, remote_id);
if (ret < 0)
return BGP_Stop;
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 172ec8b42e..fd3fad63f5 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -685,9 +685,9 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
}
/* return -1 if build or validation failed */
-int bgp_pbr_build_and_validate_entry(struct prefix *p,
- struct bgp_path_info *path,
- struct bgp_pbr_entry_main *api)
+int bgp_pbr_build_and_validate_entry(const struct prefix *p,
+ struct bgp_path_info *path,
+ struct bgp_pbr_entry_main *api)
{
int ret;
int i, action_count = 0;
@@ -2610,7 +2610,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
}
}
-void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
+void bgp_pbr_update_entry(struct bgp *bgp, const struct prefix *p,
struct bgp_path_info *info, afi_t afi, safi_t safi,
bool nlri_update)
{
diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h
index 393b08da48..47d5e21692 100644
--- a/bgpd/bgp_pbr.h
+++ b/bgpd/bgp_pbr.h
@@ -291,7 +291,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api);
struct bgp_node;
struct bgp_path_info;
-extern void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
+extern void bgp_pbr_update_entry(struct bgp *bgp, const struct prefix *p,
struct bgp_path_info *new_select, afi_t afi,
safi_t safi, bool nlri_update);
@@ -301,7 +301,7 @@ extern void bgp_pbr_reset(struct bgp *bgp, afi_t afi);
extern struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name,
struct bgp_pbr_interface_head *head);
-extern int bgp_pbr_build_and_validate_entry(struct prefix *p,
+extern int bgp_pbr_build_and_validate_entry(const struct prefix *p,
struct bgp_path_info *path,
struct bgp_pbr_entry_main *api);
#endif /* __BGP_PBR_H__ */
diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c
index be950dfa51..66d64066c4 100644
--- a/bgpd/bgp_rd.c
+++ b/bgpd/bgp_rd.c
@@ -33,16 +33,16 @@
#include "bgpd/bgp_rd.h"
#include "bgpd/bgp_attr.h"
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
#endif
-uint16_t decode_rd_type(uint8_t *pnt)
+uint16_t decode_rd_type(const uint8_t *pnt)
{
uint16_t v;
v = ((uint16_t)*pnt++ << 8);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
/*
* VNC L2 stores LHI in lower byte, so omit it
*/
@@ -60,7 +60,7 @@ void encode_rd_type(uint16_t v, uint8_t *pnt)
}
/* type == RD_TYPE_AS */
-void decode_rd_as(uint8_t *pnt, struct rd_as *rd_as)
+void decode_rd_as(const uint8_t *pnt, struct rd_as *rd_as)
{
rd_as->as = (uint16_t)*pnt++ << 8;
rd_as->as |= (uint16_t)*pnt++;
@@ -68,7 +68,7 @@ void decode_rd_as(uint8_t *pnt, struct rd_as *rd_as)
}
/* type == RD_TYPE_AS4 */
-void decode_rd_as4(uint8_t *pnt, struct rd_as *rd_as)
+void decode_rd_as4(const uint8_t *pnt, struct rd_as *rd_as)
{
pnt = ptr_get_be32(pnt, &rd_as->as);
rd_as->val = ((uint16_t)*pnt++ << 8);
@@ -76,7 +76,7 @@ void decode_rd_as4(uint8_t *pnt, struct rd_as *rd_as)
}
/* type == RD_TYPE_IP */
-void decode_rd_ip(uint8_t *pnt, struct rd_ip *rd_ip)
+void decode_rd_ip(const uint8_t *pnt, struct rd_ip *rd_ip)
{
memcpy(&rd_ip->ip, pnt, 4);
pnt += 4;
@@ -85,9 +85,9 @@ void decode_rd_ip(uint8_t *pnt, struct rd_ip *rd_ip)
rd_ip->val |= (uint16_t)*pnt;
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
/* type == RD_TYPE_VNC_ETH */
-void decode_rd_vnc_eth(uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth)
+void decode_rd_vnc_eth(const uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth)
{
rd_vnc_eth->type = RD_TYPE_VNC_ETH;
rd_vnc_eth->local_nve_id = pnt[1];
@@ -159,9 +159,9 @@ out:
return lret;
}
-char *prefix_rd2str(struct prefix_rd *prd, char *buf, size_t size)
+char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size)
{
- uint8_t *pnt;
+ const uint8_t *pnt;
uint16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
@@ -186,7 +186,7 @@ char *prefix_rd2str(struct prefix_rd *prd, char *buf, size_t size)
rd_ip.val);
return buf;
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
else if (type == RD_TYPE_VNC_ETH) {
snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x",
*(pnt + 1), /* LHI */
diff --git a/bgpd/bgp_rd.h b/bgpd/bgp_rd.h
index c5ea34103f..b5ad9d624d 100644
--- a/bgpd/bgp_rd.h
+++ b/bgpd/bgp_rd.h
@@ -28,7 +28,7 @@
#define RD_TYPE_IP 1
#define RD_TYPE_AS4 2
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#define RD_TYPE_VNC_ETH 0xff00 /* VNC L2VPN */
#endif
@@ -46,7 +46,7 @@ struct rd_ip {
uint16_t val;
};
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
struct rd_vnc_eth {
uint16_t type;
uint8_t local_nve_id;
@@ -54,18 +54,19 @@ struct rd_vnc_eth {
};
#endif
-extern uint16_t decode_rd_type(uint8_t *pnt);
+extern uint16_t decode_rd_type(const uint8_t *pnt);
extern void encode_rd_type(uint16_t, uint8_t *);
-extern void decode_rd_as(uint8_t *pnt, struct rd_as *rd_as);
-extern void decode_rd_as4(uint8_t *pnt, struct rd_as *rd_as);
-extern void decode_rd_ip(uint8_t *pnt, struct rd_ip *rd_ip);
-#if ENABLE_BGP_VNC
-extern void decode_rd_vnc_eth(uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth);
+extern void decode_rd_as(const uint8_t *pnt, struct rd_as *rd_as);
+extern void decode_rd_as4(const uint8_t *pnt, struct rd_as *rd_as);
+extern void decode_rd_ip(const uint8_t *pnt, struct rd_ip *rd_ip);
+#ifdef ENABLE_BGP_VNC
+extern void decode_rd_vnc_eth(const uint8_t *pnt,
+ struct rd_vnc_eth *rd_vnc_eth);
#endif
extern int str2prefix_rd(const char *, struct prefix_rd *);
-extern char *prefix_rd2str(struct prefix_rd *, char *, size_t);
+extern char *prefix_rd2str(const struct prefix_rd *, char *, size_t);
extern void form_auto_rd(struct in_addr router_id, uint16_t rd_id,
struct prefix_rd *prd);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 265f122c23..7aea1fec14 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -71,7 +71,7 @@
#include "bgpd/bgp_mac.h"
#include "bgpd/bgp_network.h"
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
#include "bgpd/rfapi/vnc_import_bgp.h"
#include "bgpd/rfapi/vnc_export_bgp.h"
@@ -116,7 +116,7 @@ DEFINE_HOOK(bgp_process,
struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
- safi_t safi, struct prefix *p,
+ safi_t safi, const struct prefix *p,
struct prefix_rd *prd)
{
struct bgp_node *rn;
@@ -146,7 +146,7 @@ struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
}
struct bgp_node *bgp_afi_node_lookup(struct bgp_table *table, afi_t afi,
- safi_t safi, struct prefix *p,
+ safi_t safi, const struct prefix *p,
struct prefix_rd *prd)
{
struct bgp_node *rn;
@@ -303,7 +303,6 @@ static int bgp_node_set_defer_flag(struct bgp_node *rn, bool delete)
struct bgp_table *table = NULL;
afi_t afi = 0;
safi_t safi = 0;
- char buf[PREFIX2STR_BUFFER];
/* If the flag BGP_NODE_SELECT_DEFER is set and new path is added
* then the route selection is deferred
@@ -312,12 +311,11 @@ static int bgp_node_set_defer_flag(struct bgp_node *rn, bool delete)
return 0;
if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED)) {
- if (BGP_DEBUG(update, UPDATE_OUT)) {
- prefix2str(&rn->p, buf, PREFIX2STR_BUFFER);
+ if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug(
- "Route %s is in workqueue and being processed, not deferred.",
- buf);
- }
+ "Route %pRN is in workqueue and being processed, not deferred.",
+ rn);
+
return 0;
}
@@ -361,13 +359,12 @@ static int bgp_node_set_defer_flag(struct bgp_node *rn, bool delete)
if (set_flag && table) {
if (bgp && (bgp->gr_info[afi][safi].t_select_deferral)) {
SET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
- prefix2str(&rn->p, buf, PREFIX2STR_BUFFER);
if (rn->rt_node == NULL)
rn->rt_node = listnode_add(
bgp->gr_info[afi][safi].route_list, rn);
if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("DEFER route %s, rn %p, node %p",
- buf, rn, rn->rt_node);
+ zlog_debug("DEFER route %pRN, rn %p, node %p",
+ rn, rn, rn->rt_node);
return 0;
}
}
@@ -594,7 +591,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
*/
if (newattr->sticky != existattr->sticky) {
if (!debug) {
- prefix2str(&new->net->p, pfx_buf,
+ prefix2str(bgp_node_get_prefix(new->net),
+ pfx_buf,
sizeof(*pfx_buf)
* PREFIX2STR_BUFFER);
bgp_path_info_path_with_addpath_rx_str(new,
@@ -1202,7 +1200,8 @@ int bgp_path_info_cmp_compatible(struct bgp *bgp, struct bgp_path_info *new,
return ret;
}
-static enum filter_type bgp_input_filter(struct peer *peer, struct prefix *p,
+static enum filter_type bgp_input_filter(struct peer *peer,
+ const struct prefix *p,
struct attr *attr, afi_t afi,
safi_t safi)
{
@@ -1241,7 +1240,8 @@ static enum filter_type bgp_input_filter(struct peer *peer, struct prefix *p,
#undef FILTER_EXIST_WARN
}
-static enum filter_type bgp_output_filter(struct peer *peer, struct prefix *p,
+static enum filter_type bgp_output_filter(struct peer *peer,
+ const struct prefix *p,
struct attr *attr, afi_t afi,
safi_t safi)
{
@@ -1321,7 +1321,7 @@ static bool bgp_cluster_filter(struct peer *peer, struct attr *attr)
return false;
}
-static int bgp_input_modifier(struct peer *peer, struct prefix *p,
+static int bgp_input_modifier(struct peer *peer, const struct prefix *p,
struct attr *attr, afi_t afi, safi_t safi,
const char *rmap_name, mpls_label_t *label,
uint32_t num_labels, struct bgp_node *rn)
@@ -1379,7 +1379,7 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p,
return RMAP_PERMIT;
}
-static int bgp_output_modifier(struct peer *peer, struct prefix *p,
+static int bgp_output_modifier(struct peer *peer, const struct prefix *p,
struct attr *attr, afi_t afi, safi_t safi,
const char *rmap_name)
{
@@ -1544,8 +1544,8 @@ static void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr)
}
bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
- struct update_subgroup *subgrp, struct prefix *p,
- struct attr *attr)
+ struct update_subgroup *subgrp,
+ const struct prefix *p, struct attr *attr)
{
struct bgp_filter *filter;
struct peer *from;
@@ -1577,7 +1577,7 @@ bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
piattr = bgp_path_info_mpath_count(pi) ? bgp_path_info_mpath_attr(pi)
: pi->attr;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (((afi == AFI_IP) || (afi == AFI_IP6)) && (safi == SAFI_MPLS_VPN)
&& ((pi->type == ZEBRA_ROUTE_BGP_DIRECT)
|| (pi->type == ZEBRA_ROUTE_BGP_DIRECT_EXT))) {
@@ -2095,10 +2095,10 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn,
do_mpath =
(mpath_cfg->maxpaths_ebgp > 1 || mpath_cfg->maxpaths_ibgp > 1);
- debug = bgp_debug_bestpath(&rn->p);
+ debug = bgp_debug_bestpath(rn);
if (debug)
- prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
+ prefix2str(bgp_node_get_prefix(rn), pfx_buf, sizeof(pfx_buf));
rn->reason = bgp_path_selection_none;
/* bgp deterministic-med */
@@ -2318,13 +2318,13 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp,
struct bgp_node *rn,
uint32_t addpath_tx_id)
{
- struct prefix *p;
+ const struct prefix *p;
struct peer *onlypeer;
struct attr attr;
afi_t afi;
safi_t safi;
- p = &rn->p;
+ p = bgp_node_get_prefix(rn);
afi = SUBGRP_AFI(subgrp);
safi = SUBGRP_SAFI(subgrp);
onlypeer = ((SUBGRP_PCOUNT(subgrp) == 1) ? (SUBGRP_PFIRST(subgrp))->peer
@@ -2444,18 +2444,15 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
struct bgp_path_info *new_select;
struct bgp_path_info *old_select;
struct bgp_path_info_pair old_and_new;
- char pfx_buf[PREFIX2STR_BUFFER];
int debug = 0;
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {
if (rn)
- debug = bgp_debug_bestpath(&rn->p);
- if (debug) {
- prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
+ debug = bgp_debug_bestpath(rn);
+ if (debug)
zlog_debug(
- "%s: bgp delete in progress, ignoring event, p=%s",
- __func__, pfx_buf);
- }
+ "%s: bgp delete in progress, ignoring event, p=%pRN",
+ __func__, rn);
return;
}
/* Is it end of initial update? (after startup) */
@@ -2474,14 +2471,12 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
return;
}
- struct prefix *p = &rn->p;
+ const struct prefix *p = bgp_node_get_prefix(rn);
- debug = bgp_debug_bestpath(&rn->p);
- if (debug) {
- prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
- zlog_debug("%s: p=%s afi=%s, safi=%s start", __func__, pfx_buf,
+ debug = bgp_debug_bestpath(rn);
+ if (debug)
+ zlog_debug("%s: p=%pRN afi=%s, safi=%s start", __func__, rn,
afi2str(afi), safi2str(safi));
- }
/* The best path calculation for the route is deferred if
* BGP_NODE_SELECT_DEFER is set
@@ -2538,13 +2533,11 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
bgp_unregister_for_label(rn);
}
- if (debug) {
- prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
+ if (debug)
zlog_debug(
- "%s: p=%s afi=%s, safi=%s, old_select=%p, new_select=%p",
- __func__, pfx_buf, afi2str(afi), safi2str(safi),
+ "%s: p=%pRN afi=%s, safi=%s, old_select=%p, new_select=%p",
+ __func__, rn, afi2str(afi), safi2str(safi),
old_select, new_select);
- }
/* If best route remains the same and this is not due to user-initiated
* clear, see exactly what needs to be done.
@@ -2554,7 +2547,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
&& !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
&& !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
if (bgp_zebra_has_route_changed(rn, old_select)) {
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
vnc_import_bgp_add_route(bgp, p, old_select);
vnc_import_bgp_exterior_add_route(bgp, p, old_select);
#endif
@@ -2622,7 +2615,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG);
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
if (old_select != new_select) {
if (old_select) {
@@ -2677,6 +2670,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
/* advertise/withdraw type-5 routes */
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
+ const struct prefix *p = bgp_node_get_prefix(rn);
+
if (advertise_type5_routes(bgp, afi) &&
new_select &&
is_route_injectable_into_evpn(new_select)) {
@@ -2700,18 +2695,17 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
ret = route_map_apply(
bgp->adv_cmd_rmap[afi][safi].map,
- &rn->p, RMAP_BGP, &rmap_path);
+ p, RMAP_BGP, &rmap_path);
if (ret == RMAP_DENYMATCH) {
bgp_attr_flush(&dummy_attr);
bgp_evpn_withdraw_type5_route(
- bgp, &rn->p, afi, safi);
+ bgp, p, afi, safi);
} else
bgp_evpn_advertise_type5_route(
- bgp, &rn->p, &dummy_attr,
+ bgp, p, &dummy_attr,
afi, safi);
} else {
- bgp_evpn_advertise_type5_route(bgp,
- &rn->p,
+ bgp_evpn_advertise_type5_route(bgp, p,
new_select->attr,
afi, safi);
@@ -2719,7 +2713,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
} else if (advertise_type5_routes(bgp, afi) &&
old_select &&
is_route_injectable_into_evpn(old_select))
- bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
+ bgp_evpn_withdraw_type5_route(bgp, p, afi, safi);
}
/* Clear any route change flags. */
@@ -3046,7 +3040,8 @@ void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
struct bgp *bgp = NULL;
bool delete_route = false;
- bgp_aggregate_decrement(peer->bgp, &rn->p, pi, afi, safi);
+ bgp_aggregate_decrement(peer->bgp, bgp_node_get_prefix(rn),
+ pi, afi, safi);
if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
bgp_path_info_delete(rn, pi); /* keep historical info */
@@ -3081,6 +3076,8 @@ static void bgp_rib_withdraw(struct bgp_node *rn, struct bgp_path_info *pi,
struct peer *peer, afi_t afi, safi_t safi,
struct prefix_rd *prd)
{
+ const struct prefix *p = bgp_node_get_prefix(rn);
+
/* apply dampening, if result is suppressed, we'll be retaining
* the bgp_path_info in the RIB for historical reference.
*/
@@ -3088,12 +3085,12 @@ static void bgp_rib_withdraw(struct bgp_node *rn, struct bgp_path_info *pi,
&& peer->sort == BGP_PEER_EBGP)
if ((bgp_damp_withdraw(pi, rn, afi, safi, 0))
== BGP_DAMP_SUPPRESSED) {
- bgp_aggregate_decrement(peer->bgp, &rn->p, pi, afi,
+ bgp_aggregate_decrement(peer->bgp, p, pi, afi,
safi);
return;
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (safi == SAFI_MPLS_VPN) {
struct bgp_node *prn = NULL;
struct bgp_table *table = NULL;
@@ -3104,23 +3101,22 @@ static void bgp_rib_withdraw(struct bgp_node *rn, struct bgp_path_info *pi,
table = bgp_node_get_bgp_table_info(prn);
vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
- peer->bgp, prd, table, &rn->p, pi);
+ peer->bgp, prd, table, p, pi);
}
bgp_unlock_node(prn);
}
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
- vnc_import_bgp_del_route(peer->bgp, &rn->p, pi);
- vnc_import_bgp_exterior_del_route(peer->bgp, &rn->p,
- pi);
+ vnc_import_bgp_del_route(peer->bgp, p, pi);
+ vnc_import_bgp_exterior_del_route(peer->bgp, p, pi);
}
}
#endif
/* If this is an EVPN route, process for un-import. */
if (safi == SAFI_EVPN)
- bgp_evpn_unimport_route(peer->bgp, afi, safi, &rn->p, pi);
+ bgp_evpn_unimport_route(peer->bgp, afi, safi, p, pi);
bgp_rib_remove(rn, pi, peer, afi, safi);
}
@@ -3257,7 +3253,7 @@ static bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
return ret;
}
-int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
+int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
struct attr *attr, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd, mpls_label_t *label,
uint32_t num_labels, int soft_reconfig,
@@ -3281,7 +3277,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
uint8_t pi_type = 0;
uint8_t pi_sub_type = 0;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
int vnc_implicit_withdraw = 0;
#endif
int same_attr = 0;
@@ -3581,7 +3577,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
bgp_damp_withdraw(pi, rn, afi, safi, 1);
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (safi == SAFI_MPLS_VPN) {
struct bgp_node *prn = NULL;
struct bgp_table *table = NULL;
@@ -3671,7 +3667,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
}
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if ((afi == AFI_IP || afi == AFI_IP6)
&& (safi == SAFI_UNICAST)) {
if (vnc_implicit_withdraw) {
@@ -3754,7 +3750,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
} else
bgp_path_info_set_flag(rn, pi, BGP_PATH_VALID);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (safi == SAFI_MPLS_VPN) {
struct bgp_node *prn = NULL;
struct bgp_table *table = NULL;
@@ -3805,7 +3801,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
vpn_leak_to_vrf_update(bgp, pi);
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (SAFI_MPLS_VPN == safi) {
mpls_label_t label_decoded = decode_label(label);
@@ -3914,7 +3910,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
/* route_node_get lock */
bgp_unlock_node(rn);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (safi == SAFI_MPLS_VPN) {
struct bgp_node *prn = NULL;
struct bgp_table *table = NULL;
@@ -3954,7 +3950,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
vpn_leak_to_vrf_update(bgp, new);
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (SAFI_MPLS_VPN == safi) {
mpls_label_t label_decoded = decode_label(label);
@@ -4011,7 +4007,7 @@ filtered:
bgp_unlock_node(rn);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
/*
* Filtered update is treated as an implicit withdrawal (see
* bgp_rib_remove()
@@ -4026,7 +4022,7 @@ filtered:
return 0;
}
-int bgp_withdraw(struct peer *peer, struct prefix *p, uint32_t addpath_id,
+int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
struct attr *attr, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd, mpls_label_t *label,
uint32_t num_labels, struct bgp_route_evpn *evpn)
@@ -4036,7 +4032,7 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, uint32_t addpath_id,
struct bgp_node *rn;
struct bgp_path_info *pi;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if ((SAFI_MPLS_VPN == safi) || (SAFI_ENCAP == safi)) {
rfapiProcessWithdraw(peer, NULL, p, prd, NULL, afi, safi, type,
0);
@@ -4252,8 +4248,9 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
else
memset(&evpn, 0, sizeof(evpn));
- ret = bgp_update(peer, &rn->p, ain->addpath_rx_id,
- ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
+ ret = bgp_update(peer, bgp_node_get_prefix(rn),
+ ain->addpath_rx_id, ain->attr,
+ afi, safi, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, prd, label_pnt,
num_labels, 1, &evpn);
@@ -4279,16 +4276,18 @@ void bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi)
for (rn = bgp_table_top(peer->bgp->rib[afi][safi]); rn;
rn = bgp_route_next(rn)) {
table = bgp_node_get_bgp_table_info(rn);
- if (table != NULL) {
- struct prefix_rd prd;
- prd.family = AF_UNSPEC;
- prd.prefixlen = 64;
- memcpy(&prd.val, rn->p.u.val, 8);
+ if (table == NULL)
+ continue;
- bgp_soft_reconfig_table(peer, afi, safi, table,
- &prd);
- }
+ const struct prefix *p = bgp_node_get_prefix(rn);
+ struct prefix_rd prd;
+
+ prd.family = AF_UNSPEC;
+ prd.prefixlen = 64;
+ memcpy(&prd.val, p->u.val, 8);
+
+ bgp_soft_reconfig_table(peer, afi, safi, table, &prd);
}
}
@@ -4327,7 +4326,8 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data)
/* If this is an EVPN route, process for
* un-import. */
if (safi == SAFI_EVPN)
- bgp_evpn_unimport_route(bgp, afi, safi, &rn->p,
+ bgp_evpn_unimport_route(bgp, afi, safi,
+ bgp_node_get_prefix(rn),
pi);
/* Handle withdraw for VRF route-leaking and L3VPN */
if (SAFI_UNICAST == safi
@@ -4530,7 +4530,7 @@ void bgp_clear_route_all(struct peer *peer)
FOREACH_AFI_SAFI (afi, safi)
bgp_clear_route(peer, afi, safi);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
rfapiProcessPeerDown(peer);
#endif
}
@@ -4643,13 +4643,14 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = next) {
+ const struct prefix *p = bgp_node_get_prefix(rn);
+
next = pi->next;
/* Unimport EVPN routes from VRFs */
if (safi == SAFI_EVPN)
bgp_evpn_unimport_route(bgp, AFI_L2VPN,
- SAFI_EVPN,
- &rn->p, pi);
+ SAFI_EVPN, p, pi);
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
&& pi->type == ZEBRA_ROUTE_BGP
@@ -4658,8 +4659,7 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
|| pi->sub_type == BGP_ROUTE_IMPORTED)) {
if (bgp_fibupd_safi(safi))
- bgp_zebra_withdraw(&rn->p, pi, bgp,
- safi);
+ bgp_zebra_withdraw(p, pi, bgp, safi);
bgp_path_info_reap(rn, pi);
}
}
@@ -4908,7 +4908,7 @@ static void bgp_static_free(struct bgp_static *bgp_static)
XFREE(MTYPE_BGP_STATIC, bgp_static);
}
-void bgp_static_update(struct bgp *bgp, struct prefix *p,
+void bgp_static_update(struct bgp *bgp, const struct prefix *p,
struct bgp_static *bgp_static, afi_t afi, safi_t safi)
{
struct bgp_node *rn;
@@ -4918,7 +4918,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
struct attr attr;
struct attr *attr_new;
route_map_result_t ret;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
int vnc_implicit_withdraw = 0;
#endif
@@ -5000,7 +5000,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
bgp_path_info_restore(rn, pi);
else
bgp_aggregate_decrement(bgp, p, pi, afi, safi);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if ((afi == AFI_IP || afi == AFI_IP6)
&& (safi == SAFI_UNICAST)) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
@@ -5019,7 +5019,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
bgp_attr_unintern(&pi->attr);
pi->attr = attr_new;
pi->uptime = bgp_clock();
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if ((afi == AFI_IP || afi == AFI_IP6)
&& (safi == SAFI_UNICAST)) {
if (vnc_implicit_withdraw) {
@@ -5137,7 +5137,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
aspath_unintern(&attr.aspath);
}
-void bgp_static_withdraw(struct bgp *bgp, struct prefix *p, afi_t afi,
+void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, afi_t afi,
safi_t safi)
{
struct bgp_node *rn;
@@ -5171,7 +5171,7 @@ void bgp_static_withdraw(struct bgp *bgp, struct prefix *p, afi_t afi,
/*
* Used for SAFI_MPLS_VPN and SAFI_ENCAP
*/
-static void bgp_static_withdraw_safi(struct bgp *bgp, struct prefix *p,
+static void bgp_static_withdraw_safi(struct bgp *bgp, const struct prefix *p,
afi_t afi, safi_t safi,
struct prefix_rd *prd)
{
@@ -5188,7 +5188,7 @@ static void bgp_static_withdraw_safi(struct bgp *bgp, struct prefix *p,
/* Withdraw static BGP route from routing table. */
if (pi) {
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
rfapiProcessWithdraw(
pi->peer, NULL, p, prd, pi->attr, afi, safi, pi->type,
1); /* Kill, since it is an administrative change */
@@ -5206,7 +5206,7 @@ static void bgp_static_withdraw_safi(struct bgp *bgp, struct prefix *p,
bgp_unlock_node(rn);
}
-static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
+static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
struct bgp_static *bgp_static, afi_t afi,
safi_t safi)
{
@@ -5215,7 +5215,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
struct attr *attr_new;
struct attr attr = {0};
struct bgp_path_info *pi;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
mpls_label_t label = 0;
#endif
uint32_t num_labels = 0;
@@ -5317,7 +5317,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
bgp_attr_unintern(&pi->attr);
pi->attr = attr_new;
pi->uptime = bgp_clock();
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (pi->extra)
label = decode_label(&pi->extra->label[0]);
#endif
@@ -5330,7 +5330,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
vpn_leak_to_vrf_update(bgp, pi);
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
rfapiProcessUpdate(pi->peer, NULL, p, &bgp_static->prd,
pi->attr, afi, safi, pi->type,
pi->sub_type, &label);
@@ -5351,7 +5351,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
new->extra->label[0] = bgp_static->label;
new->extra->num_labels = num_labels;
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
label = decode_label(&bgp_static->label);
#endif
@@ -5370,7 +5370,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
vpn_leak_to_vrf_update(bgp, new);
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd, new->attr, afi,
safi, new->type, new->sub_type, &label);
#endif
@@ -5540,13 +5540,14 @@ void bgp_static_add(struct bgp *bgp)
bgp_static =
bgp_node_get_bgp_static_info(
rm);
- bgp_static_update_safi(bgp, &rm->p,
+ bgp_static_update_safi(bgp,
+ bgp_node_get_prefix(rm),
bgp_static, afi,
safi);
}
} else {
bgp_static_update(
- bgp, &rn->p,
+ bgp, bgp_node_get_prefix(rn),
bgp_node_get_bgp_static_info(rn), afi,
safi);
}
@@ -5583,15 +5584,20 @@ void bgp_static_delete(struct bgp *bgp)
continue;
bgp_static_withdraw_safi(
- bgp, &rm->p, AFI_IP, safi,
- (struct prefix_rd *)&rn->p);
+ bgp, bgp_node_get_prefix(rm),
+ AFI_IP, safi,
+ (struct prefix_rd *)
+ bgp_node_get_prefix(
+ rn));
bgp_static_free(bgp_static);
bgp_node_set_bgp_static_info(rn, NULL);
bgp_unlock_node(rn);
}
} else {
bgp_static = bgp_node_get_bgp_static_info(rn);
- bgp_static_withdraw(bgp, &rn->p, afi, safi);
+ bgp_static_withdraw(bgp,
+ bgp_node_get_prefix(rn),
+ afi, safi);
bgp_static_free(bgp_static);
bgp_node_set_bgp_static_info(rn, NULL);
bgp_unlock_node(rn);
@@ -5625,13 +5631,15 @@ void bgp_static_redo_import_check(struct bgp *bgp)
bgp_static =
bgp_node_get_bgp_static_info(
rm);
- bgp_static_update_safi(bgp, &rm->p,
+ bgp_static_update_safi(bgp,
+ bgp_node_get_prefix(rm),
bgp_static, afi,
safi);
}
} else {
bgp_static = bgp_node_get_bgp_static_info(rn);
- bgp_static_update(bgp, &rn->p, bgp_static, afi,
+ bgp_static_update(bgp, bgp_node_get_prefix(rn),
+ bgp_static, afi,
safi);
}
}
@@ -5662,8 +5670,9 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi,
|| (pi->type != ZEBRA_ROUTE_BGP
&& pi->sub_type
== BGP_ROUTE_REDISTRIBUTE))) {
- bgp_aggregate_decrement(bgp, &rn->p, pi, afi,
- safi);
+ bgp_aggregate_decrement(bgp,
+ bgp_node_get_prefix(rn),
+ pi, afi, safi);
bgp_unlink_nexthop(pi);
bgp_path_info_delete(rn, pi);
bgp_process(bgp, rn, afi, safi);
@@ -6056,14 +6065,11 @@ static bool bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin,
return true;
}
-static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi,
- struct prefix *p, uint8_t origin,
- struct aspath *aspath,
- struct community *community,
- struct ecommunity *ecommunity,
- struct lcommunity *lcommunity,
- uint8_t atomic_aggregate,
- struct bgp_aggregate *aggregate)
+static void bgp_aggregate_install(
+ struct bgp *bgp, afi_t afi, safi_t safi, const struct prefix *p,
+ uint8_t origin, struct aspath *aspath, struct community *community,
+ struct ecommunity *ecommunity, struct lcommunity *lcommunity,
+ uint8_t atomic_aggregate, struct bgp_aggregate *aggregate)
{
struct bgp_node *rn;
struct bgp_table *table;
@@ -6140,9 +6146,8 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi,
}
/* Update an aggregate as routes are added/removed from the BGP table */
-void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
- afi_t afi, safi_t safi,
- struct bgp_aggregate *aggregate)
+void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
+ safi_t safi, struct bgp_aggregate *aggregate)
{
struct bgp_table *table;
struct bgp_node *top;
@@ -6178,7 +6183,9 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
top = bgp_node_get(table, p);
for (rn = bgp_node_get(table, p); rn;
rn = bgp_route_next_until(rn, top)) {
- if (rn->p.prefixlen <= p->prefixlen)
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
+ if (rn_p->prefixlen <= p->prefixlen)
continue;
match = 0;
@@ -6312,8 +6319,8 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
aggregate);
}
-void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
- safi_t safi, struct bgp_aggregate *aggregate)
+void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi,
+ safi_t safi, struct bgp_aggregate *aggregate)
{
struct bgp_table *table;
struct bgp_node *top;
@@ -6327,7 +6334,9 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
top = bgp_node_get(table, p);
for (rn = bgp_node_get(table, p); rn;
rn = bgp_route_next_until(rn, top)) {
- if (rn->p.prefixlen <= p->prefixlen)
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
+ if (rn_p->prefixlen <= p->prefixlen)
continue;
match = 0;
@@ -6403,7 +6412,8 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
bgp_unlock_node(top);
}
-static void bgp_add_route_to_aggregate(struct bgp *bgp, struct prefix *aggr_p,
+static void bgp_add_route_to_aggregate(struct bgp *bgp,
+ const struct prefix *aggr_p,
struct bgp_path_info *pinew, afi_t afi,
safi_t safi,
struct bgp_aggregate *aggregate)
@@ -6509,7 +6519,7 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
safi_t safi,
struct bgp_path_info *pi,
struct bgp_aggregate *aggregate,
- struct prefix *aggr_p)
+ const struct prefix *aggr_p)
{
uint8_t origin;
struct aspath *aspath = NULL;
@@ -6613,7 +6623,7 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
lcommunity, atomic_aggregate, aggregate);
}
-void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p,
+void bgp_aggregate_increment(struct bgp *bgp, const struct prefix *p,
struct bgp_path_info *pi, afi_t afi, safi_t safi)
{
struct bgp_node *child;
@@ -6637,16 +6647,18 @@ void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p,
/* Aggregate address configuration check. */
for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) {
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
aggregate = bgp_node_get_bgp_aggregate_info(rn);
- if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) {
- bgp_add_route_to_aggregate(bgp, &rn->p, pi, afi,
- safi, aggregate);
+ if (aggregate != NULL && rn_p->prefixlen < p->prefixlen) {
+ bgp_add_route_to_aggregate(bgp, rn_p, pi, afi, safi,
+ aggregate);
}
}
bgp_unlock_node(child);
}
-void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p,
+void bgp_aggregate_decrement(struct bgp *bgp, const struct prefix *p,
struct bgp_path_info *del, afi_t afi, safi_t safi)
{
struct bgp_node *child;
@@ -6667,10 +6679,12 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p,
/* Aggregate address configuration check. */
for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) {
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
aggregate = bgp_node_get_bgp_aggregate_info(rn);
- if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) {
- bgp_remove_route_from_aggregate(bgp, afi, safi,
- del, aggregate, &rn->p);
+ if (aggregate != NULL && rn_p->prefixlen < p->prefixlen) {
+ bgp_remove_route_from_aggregate(bgp, afi, safi, del,
+ aggregate, rn_p);
}
}
bgp_unlock_node(child);
@@ -6844,7 +6858,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
if (as_set == AGGREGATE_AS_SET) {
as_set_new = AGGREGATE_AS_UNSET;
zlog_warn(
- "%s: Ignoring as-set because `bgp reject-as-sets` is enabled.\n",
+ "%s: Ignoring as-set because `bgp reject-as-sets` is enabled.",
__func__);
vty_out(vty,
"Ignoring as-set because `bgp reject-as-sets` is enabled.\n");
@@ -7333,8 +7347,8 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type,
vpn_leak_from_vrf_withdraw(bgp_get_default(),
bgp, pi);
}
- bgp_aggregate_decrement(bgp, &rn->p, pi, afi,
- SAFI_UNICAST);
+ bgp_aggregate_decrement(bgp, bgp_node_get_prefix(rn),
+ pi, afi, SAFI_UNICAST);
bgp_path_info_delete(rn, pi);
bgp_process(bgp, rn, afi, SAFI_UNICAST);
}
@@ -7342,7 +7356,7 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type,
}
/* Static function to display route. */
-static void route_vty_out_route(struct prefix *p, struct vty *vty,
+static void route_vty_out_route(const struct prefix *p, struct vty *vty,
json_object *json)
{
int len = 0;
@@ -7499,7 +7513,7 @@ static char *bgp_nexthop_hostname(struct peer *peer, struct attr *attr)
}
/* called from terminal list command */
-void route_vty_out(struct vty *vty, struct prefix *p,
+void route_vty_out(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display, safi_t safi,
json_object *json_paths)
{
@@ -7805,32 +7819,19 @@ void route_vty_out(struct vty *vty, struct prefix *p,
/* MED/Metric */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
- if (json_paths) {
-
- /*
- * Adding "metric" field to match with corresponding
- * CLI. "med" will be deprecated in future.
- */
- json_object_int_add(json_path, "med", attr->med);
+ if (json_paths)
json_object_int_add(json_path, "metric", attr->med);
- } else
+ else
vty_out(vty, "%10u", attr->med);
else if (!json_paths)
vty_out(vty, " ");
/* Local Pref */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
- if (json_paths) {
-
- /*
- * Adding "locPrf" field to match with corresponding
- * CLI. "localPref" will be deprecated in future.
- */
- json_object_int_add(json_path, "localpref",
- attr->local_pref);
+ if (json_paths)
json_object_int_add(json_path, "locPrf",
- attr->local_pref);
- } else
+ attr->local_pref);
+ else
vty_out(vty, "%7u", attr->local_pref);
else if (!json_paths)
vty_out(vty, " ");
@@ -7849,17 +7850,10 @@ void route_vty_out(struct vty *vty, struct prefix *p,
/* Print aspath */
if (attr->aspath) {
- if (json_paths) {
-
- /*
- * Adding "path" field to match with corresponding
- * CLI. "aspath" will be deprecated in future.
- */
- json_object_string_add(json_path, "aspath",
- attr->aspath->str);
+ if (json_paths)
json_object_string_add(json_path, "path",
- attr->aspath->str);
- } else
+ attr->aspath->str);
+ else
aspath_print_vty(vty, "%s", attr->aspath, " ");
}
@@ -7922,7 +7916,7 @@ void route_vty_out(struct vty *vty, struct prefix *p,
vty_out(vty, "%s\n", attr->ecommunity->str);
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
/* prints an additional line, indented, with VNC info, if
* present */
if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
@@ -7932,8 +7926,9 @@ void route_vty_out(struct vty *vty, struct prefix *p,
}
/* called from terminal list command */
-void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
- safi_t safi, bool use_json, json_object *json_ar)
+void route_vty_out_tmp(struct vty *vty, const struct prefix *p,
+ struct attr *attr, safi_t safi, bool use_json,
+ json_object *json_ar)
{
json_object *json_status = NULL;
json_object *json_net = NULL;
@@ -8001,34 +7996,16 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
json_object_int_add(json_net, "metric",
attr->med);
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
-
- /*
- * Adding "locPrf" field to match with
- * corresponding CLI. "localPref" will be
- * deprecated in future.
- */
- json_object_int_add(json_net, "localPref",
- attr->local_pref);
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
json_object_int_add(json_net, "locPrf",
- attr->local_pref);
- }
+ attr->local_pref);
json_object_int_add(json_net, "weight", attr->weight);
/* Print aspath */
- if (attr->aspath) {
-
- /*
- * Adding "path" field to match with
- * corresponding CLI. "localPref" will be
- * deprecated in future.
- */
- json_object_string_add(json_net, "asPath",
- attr->aspath->str);
+ if (attr->aspath)
json_object_string_add(json_net, "path",
- attr->aspath->str);
- }
+ attr->aspath->str);
/* Print origin */
json_object_string_add(json_net, "bgpOriginCode",
@@ -8095,7 +8072,7 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
vty_out(vty, "\n");
}
-void route_vty_out_tag(struct vty *vty, struct prefix *p,
+void route_vty_out_tag(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display, safi_t safi,
json_object *json)
{
@@ -8188,7 +8165,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
}
}
-void route_vty_out_overlay(struct vty *vty, struct prefix *p,
+void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display,
json_object *json_paths)
{
@@ -8312,9 +8289,10 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p,
}
/* dampening route */
-static void damp_route_vty_out(struct vty *vty, struct prefix *p,
- struct bgp_path_info *path, int display, afi_t afi,
- safi_t safi, bool use_json, json_object *json)
+static void damp_route_vty_out(struct vty *vty, const struct prefix *p,
+ struct bgp_path_info *path, int display,
+ afi_t afi, safi_t safi, bool use_json,
+ json_object *json)
{
struct attr *attr;
int len;
@@ -8376,9 +8354,10 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p,
}
/* flap route */
-static void flap_route_vty_out(struct vty *vty, struct prefix *p,
- struct bgp_path_info *path, int display, afi_t afi,
- safi_t safi, bool use_json, json_object *json)
+static void flap_route_vty_out(struct vty *vty, const struct prefix *p,
+ struct bgp_path_info *path, int display,
+ afi_t afi, safi_t safi, bool use_json,
+ json_object *json)
{
struct attr *attr;
struct bgp_damp_info *bdi;
@@ -8641,8 +8620,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
}
if (safi == SAFI_EVPN) {
if (!json_paths) {
- bgp_evpn_route2str((struct prefix_evpn *)&bn->p,
- buf2, sizeof(buf2));
+ bgp_evpn_route2str(
+ (struct prefix_evpn *)
+ bgp_node_get_prefix(bn),
+ buf2, sizeof(buf2));
vty_out(vty, " Route %s", buf2);
if (tag_buf[0] != '\0')
vty_out(vty, " VNI %s", tag_buf);
@@ -8662,11 +8643,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
rn = parent_ri->net;
if (rn && rn->prn) {
prn = rn->prn;
- prefix_rd2str((struct prefix_rd *)&prn->p,
+ prefix_rd2str((struct prefix_rd *)
+ bgp_node_get_prefix(prn),
buf1, sizeof(buf1));
if (is_pi_family_evpn(parent_ri)) {
- bgp_evpn_route2str((struct prefix_evpn *)&rn->p,
- buf2, sizeof(buf2));
+ bgp_evpn_route2str(
+ (struct prefix_evpn *)
+ bgp_node_get_prefix(rn),
+ buf2, sizeof(buf2));
vty_out(vty, " Imported from %s:%s, VNI %s\n", buf1, buf2, tag_buf);
} else
vty_out(vty, " Imported from %s:%s\n", buf1, buf2);
@@ -8711,10 +8695,22 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
json_object_string_add(
json_path, "aggregatorId",
inet_ntoa(attr->aggregator_addr));
+ if (attr->aggregator_as == BGP_AS_ZERO)
+ json_object_boolean_true_add(
+ json_path, "aggregatorAsMalformed");
+ else
+ json_object_boolean_false_add(
+ json_path, "aggregatorAsMalformed");
} else {
- vty_out(vty, ", (aggregated by %u %s)",
- attr->aggregator_as,
- inet_ntoa(attr->aggregator_addr));
+ if (attr->aggregator_as == BGP_AS_ZERO)
+ vty_out(vty,
+ ", (aggregated by %u(malformed) %s)",
+ attr->aggregator_as,
+ inet_ntoa(attr->aggregator_addr));
+ else
+ vty_out(vty, ", (aggregated by %u %s)",
+ attr->aggregator_as,
+ inet_ntoa(attr->aggregator_addr));
}
}
@@ -8755,8 +8751,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
/* Line2 display Next-hop, Neighbor, Router-id */
/* Display the nexthop */
- if ((bn->p.family == AF_INET || bn->p.family == AF_ETHERNET
- || bn->p.family == AF_EVPN)
+ const struct prefix *bn_p = bgp_node_get_prefix(bn);
+
+ if ((bn_p->family == AF_INET || bn_p->family == AF_ETHERNET
+ || bn_p->family == AF_EVPN)
&& (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN
|| !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
@@ -8857,7 +8855,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
if (path->peer == bgp->peer_self) {
if (safi == SAFI_EVPN
- || (bn->p.family == AF_INET
+ || (bn_p->family == AF_INET
&& !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
if (json_paths)
json_object_string_add(json_peer, "peerId",
@@ -9041,21 +9039,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
bgp_origin_long_str[attr->origin]);
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) {
- if (json_paths) {
- /*
- * Adding "metric" field to match with
- * corresponding CLI. "med" will be
- * deprecated in future.
- */
- json_object_int_add(json_path, "med", attr->med);
+ if (json_paths)
json_object_int_add(json_path, "metric", attr->med);
- } else
+ else
vty_out(vty, ", metric %u", attr->med);
}
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
if (json_paths)
- json_object_int_add(json_path, "localpref",
+ json_object_int_add(json_path, "locPrf",
attr->local_pref);
else
vty_out(vty, ", localpref %u", attr->local_pref);
@@ -9527,6 +9519,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
/* Start processing of routes. */
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
pi = bgp_node_get_bgp_path_info(rn);
if (pi == NULL)
continue;
@@ -9556,7 +9550,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
if (type == bgp_show_type_prefix_list) {
struct prefix_list *plist = output_arg;
- if (prefix_list_apply(plist, &rn->p)
+ if (prefix_list_apply(plist, rn_p)
!= PREFIX_PERMIT)
continue;
}
@@ -9578,7 +9572,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
path.peer = pi->peer;
path.attr = &dummy_attr;
- ret = route_map_apply(rmap, &rn->p, RMAP_BGP,
+ ret = route_map_apply(rmap, rn_p, RMAP_BGP,
&path);
if (ret == RMAP_DENYMATCH)
continue;
@@ -9596,20 +9590,20 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
if (type == bgp_show_type_cidr_only) {
uint32_t destination;
- destination = ntohl(rn->p.u.prefix4.s_addr);
+ destination = ntohl(rn_p->u.prefix4.s_addr);
if (IN_CLASSC(destination)
- && rn->p.prefixlen == 24)
+ && rn_p->prefixlen == 24)
continue;
if (IN_CLASSB(destination)
- && rn->p.prefixlen == 16)
+ && rn_p->prefixlen == 16)
continue;
if (IN_CLASSA(destination)
- && rn->p.prefixlen == 8)
+ && rn_p->prefixlen == 8)
continue;
}
if (type == bgp_show_type_prefix_longer) {
p = output_arg;
- if (!prefix_match(p, &rn->p))
+ if (!prefix_match(p, rn_p))
continue;
}
if (type == bgp_show_type_community_all) {
@@ -9722,14 +9716,16 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
}
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
- damp_route_vty_out(vty, &rn->p, pi, display, AFI_IP,
- safi, use_json, json_paths);
+ damp_route_vty_out(vty, rn_p, pi, display,
+ AFI_IP, safi, use_json,
+ json_paths);
else if (type == bgp_show_type_flap_statistics
|| type == bgp_show_type_flap_neighbor)
- flap_route_vty_out(vty, &rn->p, pi, display, AFI_IP,
- safi, use_json, json_paths);
+ flap_route_vty_out(vty, rn_p, pi, display,
+ AFI_IP, safi, use_json,
+ json_paths);
else
- route_vty_out(vty, &rn->p, pi, display, safi,
+ route_vty_out(vty, rn_p, pi, display, safi,
json_paths);
display++;
}
@@ -9739,28 +9735,25 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
if (!use_json)
continue;
- p = &rn->p;
/* encode prefix */
- if (p->family == AF_FLOWSPEC) {
+ if (rn_p->family == AF_FLOWSPEC) {
char retstr[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
- bgp_fs_nlri_get_string((unsigned char *)
- p->u.prefix_flowspec.ptr,
- p->u.prefix_flowspec
- .prefixlen,
- retstr,
- NLRI_STRING_FORMAT_MIN,
- NULL);
+ bgp_fs_nlri_get_string(
+ (unsigned char *)
+ rn_p->u.prefix_flowspec.ptr,
+ rn_p->u.prefix_flowspec.prefixlen,
+ retstr, NLRI_STRING_FORMAT_MIN, NULL);
if (first)
- vty_out(vty, "\"%s/%d\": ",
- retstr,
- p->u.prefix_flowspec.prefixlen);
+ vty_out(vty, "\"%s/%d\": ", retstr,
+ rn_p->u.prefix_flowspec
+ .prefixlen);
else
- vty_out(vty, ",\"%s/%d\": ",
- retstr,
- p->u.prefix_flowspec.prefixlen);
+ vty_out(vty, ",\"%s/%d\": ", retstr,
+ rn_p->u.prefix_flowspec
+ .prefixlen);
} else {
- prefix2str(p, buf2, sizeof(buf2));
+ prefix2str(rn_p, buf2, sizeof(buf2));
if (first)
vty_out(vty, "\"%s\": ", buf2);
else
@@ -9826,8 +9819,10 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
show_msg = (!use_json && type == bgp_show_type_normal);
for (rn = bgp_table_top(table); rn; rn = next) {
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
next = bgp_route_next(rn);
- if (prd_match && memcmp(rn->p.u.val, prd_match->val, 8) != 0)
+ if (prd_match && memcmp(rn_p->u.val, prd_match->val, 8) != 0)
continue;
itable = bgp_node_get_bgp_table_info(rn);
@@ -9835,7 +9830,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
struct prefix_rd prd;
char rd[RD_ADDRSTRLEN];
- memcpy(&prd, &(rn->p), sizeof(struct prefix_rd));
+ memcpy(&prd, rn_p, sizeof(struct prefix_rd));
prefix_rd2str(&prd, rd, sizeof(rd));
bgp_show_table(vty, bgp, safi, itable, type, output_arg,
use_json, rd, next == NULL, &output_cum,
@@ -9938,7 +9933,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
afi_t afi, safi_t safi, json_object *json)
{
struct bgp_path_info *pi;
- struct prefix *p;
+ const struct prefix *p;
struct peer *peer;
struct listnode *node, *nnode;
char buf1[RD_ADDRSTRLEN];
@@ -9966,7 +9961,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
mpls_label_t label = 0;
json_object *json_adv_to = NULL;
- p = &rn->p;
+ p = bgp_node_get_prefix(rn);
has_valid_label = bgp_is_valid_label(&rn->local_label);
if (has_valid_label)
@@ -10226,7 +10221,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) {
for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
- if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
+ if (prd && memcmp(rn_p->u.val, prd->val, 8) != 0)
continue;
table = bgp_node_get_bgp_table_info(rn);
if (!table)
@@ -10235,15 +10232,16 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
if ((rm = bgp_node_match(table, &match)) == NULL)
continue;
+ const struct prefix *rm_p = bgp_node_get_prefix(rm);
if (prefix_check
- && rm->p.prefixlen != match.prefixlen) {
+ && rm_p->prefixlen != match.prefixlen) {
bgp_unlock_node(rm);
continue;
}
- bgp_show_path_info((struct prefix_rd *)&rn->p, rm,
- vty, bgp, afi, safi, json,
- pathtype, &display);
+ bgp_show_path_info((struct prefix_rd *)rn_p, rm, vty,
+ bgp, afi, safi, json, pathtype,
+ &display);
bgp_unlock_node(rm);
}
@@ -10252,7 +10250,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
bool is_exact_pfxlen_match = FALSE;
for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
- if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
+ if (prd && memcmp(&rn_p->u.val, prd->val, 8) != 0)
continue;
table = bgp_node_get_bgp_table_info(rn);
if (!table)
@@ -10268,15 +10268,18 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
*/
for (rm = bgp_table_top(table); rm;
rm = bgp_route_next(rm)) {
+ const struct prefix *rm_p =
+ bgp_node_get_prefix(rm);
/*
* Get prefixlen of the ip-prefix within type5
* evpn route
*/
- if (evpn_type5_prefix_match(&rm->p,
- &match) && rm->info) {
+ if (evpn_type5_prefix_match(rm_p, &match)
+ && rm->info) {
longest_pfx = rm;
int type5_pfxlen =
- bgp_evpn_get_type5_prefixlen(&rm->p);
+ bgp_evpn_get_type5_prefixlen(
+ rm_p);
if (type5_pfxlen == match.prefixlen) {
is_exact_pfxlen_match = TRUE;
bgp_unlock_node(rm);
@@ -10294,9 +10297,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
rm = longest_pfx;
bgp_lock_node(rm);
- bgp_show_path_info((struct prefix_rd *)&rn->p, rm,
- vty, bgp, afi, safi, json,
- pathtype, &display);
+ bgp_show_path_info((struct prefix_rd *)rn_p, rm, vty,
+ bgp, afi, safi, json, pathtype,
+ &display);
bgp_unlock_node(rm);
}
@@ -10313,8 +10316,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
json_object_object_add(json, "paths", json_paths);
} else {
if ((rn = bgp_node_match(rib, &match)) != NULL) {
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
if (!prefix_check
- || rn->p.prefixlen == match.prefixlen) {
+ || rn_p->prefixlen == match.prefixlen) {
bgp_show_path_info(NULL, rn, vty, bgp, afi,
safi, json,
pathtype, &display);
@@ -11025,6 +11029,7 @@ static void bgp_table_stats_rn(struct bgp_node *rn, struct bgp_node *top,
{
struct bgp_node *prn = bgp_node_parent_nolock(rn);
struct bgp_path_info *pi;
+ const struct prefix *rn_p;
if (rn == top)
return;
@@ -11032,14 +11037,15 @@ static void bgp_table_stats_rn(struct bgp_node *rn, struct bgp_node *top,
if (!bgp_node_has_bgp_path_info_data(rn))
return;
+ rn_p = bgp_node_get_prefix(rn);
ts->counts[BGP_STATS_PREFIXES]++;
- ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen;
+ ts->counts[BGP_STATS_TOTPLEN] += rn_p->prefixlen;
#if 0
ts->counts[BGP_STATS_AVGPLEN]
= ravg_tally (ts->counts[BGP_STATS_PREFIXES],
ts->counts[BGP_STATS_AVGPLEN],
- rn->p.prefixlen);
+ rn_p->prefixlen);
#endif
/* check if the prefix is included by any other announcements */
@@ -11050,7 +11056,7 @@ static void bgp_table_stats_rn(struct bgp_node *rn, struct bgp_node *top,
ts->counts[BGP_STATS_UNAGGREGATEABLE]++;
/* announced address space */
if (space)
- ts->total_space += pow(2.0, space - rn->p.prefixlen);
+ ts->total_space += pow(2.0, space - rn_p->prefixlen);
} else if (bgp_node_has_bgp_path_info_data(prn))
ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++;
@@ -11722,14 +11728,17 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
/* Filter prefix using distribute list,
* filter list or prefix list
*/
- if ((bgp_input_filter(peer, &rn->p, &attr, afi,
- safi)) == FILTER_DENY)
+ const struct prefix *rn_p =
+ bgp_node_get_prefix(rn);
+ if ((bgp_input_filter(peer, rn_p, &attr, afi,
+ safi))
+ == FILTER_DENY)
route_filtered = true;
/* Filter prefix using route-map */
- ret = bgp_input_modifier(peer, &rn->p, &attr,
- afi, safi, rmap_name, NULL, 0,
- NULL);
+ ret = bgp_input_modifier(peer, rn_p, &attr, afi,
+ safi, rmap_name, NULL,
+ 0, NULL);
if (type == bgp_show_adj_route_filtered &&
!route_filtered && ret != RMAP_DENY) {
@@ -11741,7 +11750,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
(route_filtered || ret == RMAP_DENY))
filtered_count++;
- route_vty_out_tmp(vty, &rn->p, &attr, safi,
+ route_vty_out_tmp(vty, rn_p, &attr, safi,
use_json, json_ar);
bgp_attr_undup(&attr, ain->attr);
output_count++;
@@ -11818,16 +11827,18 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
header2 = 0;
}
+ const struct prefix *rn_p =
+ bgp_node_get_prefix(rn);
+
attr = *adj->attr;
ret = bgp_output_modifier(
- peer, &rn->p, &attr, afi, safi,
+ peer, rn_p, &attr, afi, safi,
rmap_name);
if (ret != RMAP_DENY) {
- route_vty_out_tmp(vty, &rn->p,
- &attr, safi,
- use_json,
- json_ar);
+ route_vty_out_tmp(
+ vty, rn_p, &attr, safi,
+ use_json, json_ar);
output_count++;
} else {
filtered_count++;
@@ -12296,7 +12307,7 @@ static int bgp_distance_unset(struct vty *vty, const char *distance_str,
}
/* Apply BGP information to distance method. */
-uint8_t bgp_distance_apply(struct prefix *p, struct bgp_path_info *pinfo,
+uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo,
afi_t afi, safi_t safi, struct bgp *bgp)
{
struct bgp_node *rn;
@@ -12657,7 +12668,9 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
|| (safi == SAFI_EVPN)) {
for (rn = bgp_table_top(bgp->rib[AFI_IP][safi]); rn;
rn = bgp_route_next(rn)) {
- if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
+ if (prd && memcmp(rn_p->u.val, prd->val, 8) != 0)
continue;
table = bgp_node_get_bgp_table_info(rn);
if (!table)
@@ -12665,8 +12678,10 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
if ((rm = bgp_node_match(table, &match)) == NULL)
continue;
+ const struct prefix *rm_p = bgp_node_get_prefix(rn);
+
if (!prefix_check
- || rm->p.prefixlen == match.prefixlen) {
+ || rm_p->prefixlen == match.prefixlen) {
pi = bgp_node_get_bgp_path_info(rm);
while (pi) {
if (pi->extra && pi->extra->damp_info) {
@@ -12685,8 +12700,10 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
} else {
if ((rn = bgp_node_match(bgp->rib[afi][safi], &match))
!= NULL) {
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
if (!prefix_check
- || rn->p.prefixlen == match.prefixlen) {
+ || rn_p->prefixlen == match.prefixlen) {
pi = bgp_node_get_bgp_path_info(rn);
while (pi) {
if (pi->extra && pi->extra->damp_info) {
@@ -12822,8 +12839,8 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
struct bgp_node *prn;
struct bgp_node *rn;
struct bgp_table *table;
- struct prefix *p;
- struct prefix_rd *prd;
+ const struct prefix *p;
+ const struct prefix_rd *prd;
struct bgp_static *bgp_static;
mpls_label_t label;
char buf[SU_ADDRSTRLEN];
@@ -12841,8 +12858,9 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
if (bgp_static == NULL)
continue;
- p = &rn->p;
- prd = (struct prefix_rd *)&prn->p;
+ p = bgp_node_get_prefix(rn);
+ prd = (const struct prefix_rd *)bgp_node_get_prefix(
+ prn);
/* "network" configuration display. */
prefix_rd2str(prd, rdbuf, sizeof(rdbuf));
@@ -12873,8 +12891,8 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
struct bgp_node *prn;
struct bgp_node *rn;
struct bgp_table *table;
- struct prefix *p;
- struct prefix_rd *prd;
+ const struct prefix *p;
+ const struct prefix_rd *prd;
struct bgp_static *bgp_static;
char buf[PREFIX_STRLEN * 2];
char buf2[SU_ADDRSTRLEN];
@@ -12900,8 +12918,8 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
bgp_static->router_mac, NULL, 0);
if (bgp_static->eth_s_id)
esi = esi2str(bgp_static->eth_s_id);
- p = &rn->p;
- prd = (struct prefix_rd *)&prn->p;
+ p = bgp_node_get_prefix(rn);
+ prd = (struct prefix_rd *)bgp_node_get_prefix(prn);
/* "network" configuration display. */
prefix_rd2str(prd, rdbuf, sizeof(rdbuf));
@@ -12944,7 +12962,7 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi)
{
struct bgp_node *rn;
- struct prefix *p;
+ const struct prefix *p;
struct bgp_static *bgp_static;
struct bgp_aggregate *bgp_aggregate;
char buf[SU_ADDRSTRLEN];
@@ -12966,7 +12984,7 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp_static == NULL)
continue;
- p = &rn->p;
+ p = bgp_node_get_prefix(rn);
vty_out(vty, " network %s/%d",
inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
@@ -12992,7 +13010,7 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp_aggregate == NULL)
continue;
- p = &rn->p;
+ p = bgp_node_get_prefix(rn);
vty_out(vty, " aggregate-address %s/%d",
inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
@@ -13037,15 +13055,11 @@ void bgp_config_write_distance(struct vty *vty, struct bgp *bgp, afi_t afi,
for (rn = bgp_table_top(bgp_distance_table[afi][safi]); rn;
rn = bgp_route_next(rn)) {
bdistance = bgp_node_get_bgp_distance_info(rn);
- if (bdistance != NULL) {
- char buf[PREFIX_STRLEN];
-
- vty_out(vty, " distance %d %s %s\n",
- bdistance->distance,
- prefix2str(&rn->p, buf, sizeof(buf)),
+ if (bdistance != NULL)
+ vty_out(vty, " distance %d %pRN %s\n",
+ bdistance->distance, rn,
bdistance->access_list ? bdistance->access_list
: "");
- }
}
}
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 628c933c07..e1998633d7 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -125,7 +125,7 @@ struct bgp_path_info_extra {
struct in6_addr sid[BGP_MAX_SIDS];
uint32_t num_sids;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
union {
struct {
@@ -510,7 +510,7 @@ extern bool bgp_outbound_policy_exists(struct peer *, struct bgp_filter *);
extern bool bgp_inbound_policy_exists(struct peer *, struct bgp_filter *);
extern struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
- safi_t safi, struct prefix *p,
+ safi_t safi, const struct prefix *p,
struct prefix_rd *prd);
extern struct bgp_path_info *bgp_path_info_lock(struct bgp_path_info *path);
extern struct bgp_path_info *bgp_path_info_unlock(struct bgp_path_info *path);
@@ -544,9 +544,10 @@ extern void bgp_static_add(struct bgp *);
extern void bgp_static_delete(struct bgp *);
extern void bgp_static_redo_import_check(struct bgp *);
extern void bgp_purge_static_redist_routes(struct bgp *bgp);
-extern void bgp_static_update(struct bgp *, struct prefix *,
- struct bgp_static *, afi_t, safi_t);
-extern void bgp_static_withdraw(struct bgp *, struct prefix *, afi_t, safi_t);
+extern void bgp_static_update(struct bgp *bgp, const struct prefix *p,
+ struct bgp_static *s, afi_t afi, safi_t safi);
+extern void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p,
+ afi_t afi, safi_t safi);
extern int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
const char *, const char *, const char *,
@@ -558,12 +559,17 @@ extern int bgp_static_unset_safi(afi_t afi, safi_t safi, struct vty *,
const char *, const char *, const char *);
/* this is primarily for MPLS-VPN */
-extern int bgp_update(struct peer *, struct prefix *, uint32_t, struct attr *,
- afi_t, safi_t, int, int, struct prefix_rd *,
- mpls_label_t *, uint32_t, int, struct bgp_route_evpn *);
-extern int bgp_withdraw(struct peer *, struct prefix *, uint32_t, struct attr *,
- afi_t, safi_t, int, int, struct prefix_rd *,
- mpls_label_t *, uint32_t, struct bgp_route_evpn *);
+extern int bgp_update(struct peer *peer, const struct prefix *p,
+ uint32_t addpath_id, struct attr *attr,
+ afi_t afi, safi_t safi, int type, int sub_type,
+ struct prefix_rd *prd, mpls_label_t *label,
+ uint32_t num_labels, int soft_reconfig,
+ struct bgp_route_evpn *evpn);
+extern int bgp_withdraw(struct peer *peer, const struct prefix *p,
+ uint32_t addpath_id, struct attr *attr, afi_t afi,
+ safi_t safi, int type, int sub_type,
+ struct prefix_rd *prd, mpls_label_t *label,
+ uint32_t num_labels, struct bgp_route_evpn *evpn);
/* for bgp_nexthop and bgp_damp */
extern void bgp_process(struct bgp *, struct bgp_node *, afi_t, safi_t);
@@ -579,19 +585,22 @@ extern void bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t);
extern void bgp_config_write_distance(struct vty *, struct bgp *, afi_t,
safi_t);
-extern void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
- safi_t safi, struct bgp_aggregate *aggregate);
-extern void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, afi_t afi,
- safi_t safi, struct bgp_aggregate *aggregate);
-extern void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p,
+extern void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p,
+ afi_t afi, safi_t safi,
+ struct bgp_aggregate *aggregate);
+extern void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p,
+ afi_t afi, safi_t safi,
+ struct bgp_aggregate *aggregate);
+extern void bgp_aggregate_increment(struct bgp *bgp, const struct prefix *p,
struct bgp_path_info *path, afi_t afi,
safi_t safi);
-extern void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p,
+extern void bgp_aggregate_decrement(struct bgp *bgp, const struct prefix *p,
struct bgp_path_info *path, afi_t afi,
safi_t safi);
-extern uint8_t bgp_distance_apply(struct prefix *p, struct bgp_path_info *path,
- afi_t afi, safi_t safi, struct bgp *bgp);
+extern uint8_t bgp_distance_apply(const struct prefix *p,
+ struct bgp_path_info *path, afi_t afi,
+ safi_t safi, struct bgp *bgp);
extern afi_t bgp_node_afi(struct vty *);
extern safi_t bgp_node_safi(struct vty *);
@@ -601,16 +610,16 @@ extern struct bgp_path_info *info_make(int type, int sub_type,
struct peer *peer, struct attr *attr,
struct bgp_node *rn);
-extern void route_vty_out(struct vty *vty, struct prefix *p,
+extern void route_vty_out(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display, safi_t safi,
json_object *json_paths);
-extern void route_vty_out_tag(struct vty *vty, struct prefix *p,
+extern void route_vty_out_tag(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display,
safi_t safi, json_object *json);
-extern void route_vty_out_tmp(struct vty *vty, struct prefix *p,
+extern void route_vty_out_tmp(struct vty *vty, const struct prefix *p,
struct attr *attr, safi_t safi, bool use_json,
json_object *json_ar);
-extern void route_vty_out_overlay(struct vty *vty, struct prefix *p,
+extern void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display,
json_object *json);
@@ -622,14 +631,14 @@ extern void subgroup_process_announce_selected(struct update_subgroup *subgrp,
extern bool subgroup_announce_check(struct bgp_node *rn,
struct bgp_path_info *pi,
struct update_subgroup *subgrp,
- struct prefix *p, struct attr *attr);
+ const struct prefix *p, struct attr *attr);
extern void bgp_peer_clear_node_queue_drain_immediate(struct peer *peer);
extern void bgp_process_queues_drain_immediate(void);
/* for encap/vpn */
extern struct bgp_node *bgp_afi_node_lookup(struct bgp_table *table, afi_t afi,
- safi_t safi, struct prefix *p,
+ safi_t safi, const struct prefix *p,
struct prefix_rd *prd);
extern void bgp_path_info_restore(struct bgp_node *rn,
struct bgp_path_info *path);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 029570df35..8bc4ef6893 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -64,7 +64,7 @@
#include "bgpd/bgp_flowspec_util.h"
#include "bgpd/bgp_encap_types.h"
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#endif
@@ -1015,7 +1015,7 @@ route_match_rd(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_rd *prd_rule = NULL;
- struct prefix_rd *prd_route = NULL;
+ const struct prefix_rd *prd_route = NULL;
struct bgp_path_info *path = NULL;
if (type == RMAP_BGP) {
@@ -1028,7 +1028,8 @@ route_match_rd(void *rule, const struct prefix *prefix,
if (path->net == NULL || path->net->prn == NULL)
return RMAP_NOMATCH;
- prd_route = (struct prefix_rd *)&path->net->prn->p;
+ prd_route =
+ (struct prefix_rd *)bgp_node_get_prefix(path->net->prn);
if (memcmp(prd_route->val, prd_rule->val, ECOMMUNITY_SIZE) == 0)
return RMAP_MATCH;
}
@@ -3637,14 +3638,17 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
bgp_static->rmap.map = map;
if (route_update && !bgp_static->backdoor) {
- if (bgp_debug_zebra(&bn->p))
+ const struct prefix *bn_p =
+ bgp_node_get_prefix(bn);
+
+ if (bgp_debug_zebra(bn_p))
zlog_debug(
"Processing route_map %s update on static route %s",
rmap_name,
- inet_ntop(bn->p.family,
- &bn->p.u.prefix, buf,
+ inet_ntop(bn_p->family,
+ &bn_p->u.prefix, buf,
INET6_ADDRSTRLEN));
- bgp_static_update(bgp, &bn->p, bgp_static, afi,
+ bgp_static_update(bgp, bn_p, bgp_static, afi,
safi);
}
}
@@ -3666,14 +3670,17 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
aggregate->rmap.map = map;
if (route_update) {
- if (bgp_debug_zebra(&bn->p))
+ const struct prefix *bn_p =
+ bgp_node_get_prefix(bn);
+
+ if (bgp_debug_zebra(bn_p))
zlog_debug(
"Processing route_map %s update on aggregate-address route %s",
rmap_name,
- inet_ntop(bn->p.family,
- &bn->p.u.prefix, buf,
+ inet_ntop(bn_p->family,
+ &bn_p->u.prefix, buf,
INET6_ADDRSTRLEN));
- bgp_aggregate_route(bgp, &bn->p, afi, safi,
+ bgp_aggregate_route(bgp, bn_p, afi, safi,
aggregate);
}
}
@@ -3742,7 +3749,7 @@ static void bgp_route_map_process_update_cb(char *rmap_name)
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
bgp_route_map_process_update(bgp, rmap_name, 1);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
/* zlog_debug("%s: calling vnc_routemap_update", __func__); */
vnc_routemap_update(bgp, __func__);
#endif
@@ -3786,7 +3793,7 @@ static void bgp_route_map_mark_update(const char *rmap_name)
} else {
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
bgp_route_map_process_update(bgp, rmap_name, 0);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
zlog_debug("%s: calling vnc_routemap_update", __func__);
vnc_routemap_update(bgp, __func__);
#endif
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index ee1c49666b..e40c7231a7 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -438,10 +438,10 @@ static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi,
label = path->extra->label;
num_labels = path->extra->num_labels;
}
- ret = bgp_update(ain->peer, &bgp_node->p, ain->addpath_rx_id,
- ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
- BGP_ROUTE_NORMAL, NULL, label, num_labels, 1,
- NULL);
+ ret = bgp_update(ain->peer, bgp_node_get_prefix(bgp_node),
+ ain->addpath_rx_id, ain->attr, afi, safi,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label,
+ num_labels, 1, NULL);
if (ret < 0)
return;
diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c
index 5cf0b73984..28eea46a5a 100644
--- a/bgpd/bgp_snmp.c
+++ b/bgpd/bgp_snmp.c
@@ -761,20 +761,23 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[],
}
if (min) {
+ const struct prefix *rn_p =
+ bgp_node_get_prefix(rn);
+
*length =
v->namelen + BGP_PATHATTR_ENTRY_OFFSET;
offset = name + v->namelen;
- oid_copy_addr(offset, &rn->p.u.prefix4,
+ oid_copy_addr(offset, &rn_p->u.prefix4,
IN_ADDR_SIZE);
offset += IN_ADDR_SIZE;
- *offset = rn->p.prefixlen;
+ *offset = rn_p->prefixlen;
offset++;
oid_copy_addr(offset,
&min->peer->su.sin.sin_addr,
IN_ADDR_SIZE);
- addr->prefix = rn->p.u.prefix4;
- addr->prefixlen = rn->p.prefixlen;
+ addr->prefix = rn_p->u.prefix4;
+ addr->prefixlen = rn_p->prefixlen;
bgp_unlock_node(rn);
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 3d74128da4..dcf9852a67 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -168,13 +168,22 @@ static struct bgp_node *
bgp_route_next_until_maxlen(struct bgp_node *node, const struct bgp_node *limit,
const uint8_t maxlen)
{
- if (node->l_left && node->p.prefixlen < maxlen
- && node->l_left->p.prefixlen <= maxlen) {
- return bgp_node_from_rnode(node->l_left);
+ const struct prefix *p = bgp_node_get_prefix(node);
+
+ if (node->l_left) {
+ const struct prefix *left_p =
+ bgp_node_get_prefix(bgp_node_from_rnode(node->l_left));
+
+ if (p->prefixlen < maxlen && left_p->prefixlen <= maxlen)
+ return bgp_node_from_rnode(node->l_left);
}
- if (node->l_right && node->p.prefixlen < maxlen
- && node->l_right->p.prefixlen <= maxlen) {
- return bgp_node_from_rnode(node->l_right);
+
+ if (node->l_right) {
+ const struct prefix *right_p =
+ bgp_node_get_prefix(bgp_node_from_rnode(node->l_right));
+
+ if (p->prefixlen < maxlen && right_p->prefixlen <= maxlen)
+ return bgp_node_from_rnode(node->l_right);
}
while (node->parent && node != limit) {
@@ -197,24 +206,29 @@ void bgp_table_range_lookup(const struct bgp_table *table,
if (node == NULL)
return;
- while (node &&
- node->p.prefixlen <= p->prefixlen && prefix_match(&node->p, p)) {
+ const struct prefix *node_p = bgp_node_get_prefix(node);
+
+ while (node && node_p->prefixlen <= p->prefixlen
+ && prefix_match(node_p, p)) {
if (bgp_node_has_bgp_path_info_data(node)
- && node->p.prefixlen == p->prefixlen) {
+ && node_p->prefixlen == p->prefixlen) {
matched = node;
break;
}
node = bgp_node_from_rnode(node->link[prefix_bit(
- &p->u.prefix, node->p.prefixlen)]);
+ &p->u.prefix, node_p->prefixlen)]);
+ node_p = bgp_node_get_prefix(node);
}
if (!node)
return;
- if (matched == NULL && node->p.prefixlen <= maxlen
- && prefix_match(p, &node->p) && node->parent == NULL)
+ node_p = bgp_node_get_prefix(node);
+ if (matched == NULL && node_p->prefixlen <= maxlen
+ && prefix_match(p, node_p) && node->parent == NULL)
matched = node;
- else if ((matched == NULL && node->p.prefixlen > maxlen) || !node->parent)
+ else if ((matched == NULL && node_p->prefixlen > maxlen)
+ || !node->parent)
return;
else if (matched == NULL && node->parent)
matched = node = bgp_node_from_rnode(node->parent);
@@ -228,7 +242,8 @@ void bgp_table_range_lookup(const struct bgp_table *table,
}
while ((node = bgp_route_next_until_maxlen(node, matched, maxlen))) {
- if (prefix_match(p, &node->p)) {
+ node_p = bgp_node_get_prefix(node);
+ if (prefix_match(p, node_p)) {
if (bgp_node_has_bgp_path_info_data(node)) {
bgp_lock_node(node);
listnode_add(matches, node);
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index 7b468cc036..da2ca3181a 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -443,4 +443,13 @@ static inline bool bgp_node_has_bgp_path_info_data(struct bgp_node *node)
return !!node->info;
}
+static inline const struct prefix *bgp_node_get_prefix(struct bgp_node *node)
+{
+ return &node->p;
+}
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pRN" (struct bgp_node *)
+#endif
+
#endif /* _QUAGGA_BGP_TABLE_H */
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 34f80def8c..e40b3320ea 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -148,12 +148,9 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg)
peer = UPDGRP_PEER(updgrp);
addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
- if (BGP_DEBUG(update, UPDATE_OUT)) {
- char buf_prefix[PREFIX_STRLEN];
- prefix2str(&ctx->rn->p, buf_prefix, sizeof(buf_prefix));
- zlog_debug("%s: afi=%s, safi=%s, p=%s", __func__, afi2str(afi),
- safi2str(safi), buf_prefix);
- }
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("%s: afi=%s, safi=%s, p=%pRN", __func__,
+ afi2str(afi), safi2str(safi), ctx->rn);
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
@@ -242,7 +239,9 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp,
output_count = 0;
- for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
+ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
RB_FOREACH (adj, bgp_adj_out_rb, &rn->adj_out)
if (adj->subgroup == subgrp) {
if (header1) {
@@ -261,20 +260,20 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp,
}
if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv
&& adj->adv->baa) {
- route_vty_out_tmp(vty, &rn->p,
- adj->adv->baa->attr,
- SUBGRP_SAFI(subgrp),
- 0, NULL);
+ route_vty_out_tmp(
+ vty, rn_p, adj->adv->baa->attr,
+ SUBGRP_SAFI(subgrp), 0, NULL);
output_count++;
}
if ((flags & UPDWALK_FLAGS_ADVERTISED)
&& adj->attr) {
- route_vty_out_tmp(
- vty, &rn->p, adj->attr,
- SUBGRP_SAFI(subgrp), 0, NULL);
+ route_vty_out_tmp(vty, rn_p, adj->attr,
+ SUBGRP_SAFI(subgrp),
+ 0, NULL);
output_count++;
}
}
+ }
if (output_count != 0)
vty_out(vty, "\nTotal number of prefixes %ld\n", output_count);
}
@@ -623,7 +622,9 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
PEER_FLAG_DEFAULT_ORIGINATE))
subgroup_default_originate(subgrp, 0);
- for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
+ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
for (ri = bgp_node_get_bgp_path_info(rn); ri; ri = ri->next)
if (CHECK_FLAG(ri->flags, BGP_PATH_SELECTED)
@@ -632,7 +633,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
peer->addpath_type[afi][safi],
ri))) {
if (subgroup_announce_check(rn, ri, subgrp,
- &rn->p, &attr))
+ rn_p, &attr))
bgp_adj_out_set_subgroup(rn, subgrp,
&attr, ri);
else
@@ -642,6 +643,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
peer, afi, safi,
&ri->tx_addpath));
}
+ }
/*
* We walked through the whole table -- make sure our version number
@@ -761,7 +763,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
rn = bgp_route_next(rn)) {
ret = route_map_apply(peer->default_rmap[afi][safi].map,
- &rn->p, RMAP_BGP, &bpi_rmap);
+ bgp_node_get_prefix(rn), RMAP_BGP,
+ &bpi_rmap);
if (ret != RMAP_DENYMATCH)
break;
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 6553211b0f..8d6fc1f6a2 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -726,8 +726,11 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
adv = bgp_adv_fifo_first(&subgrp->sync->update);
while (adv) {
+ const struct prefix *rn_p;
+
assert(adv->rn);
rn = adv->rn;
+ rn_p = bgp_node_get_prefix(rn);
adj = adv->adj;
addpath_tx_id = adj->addpath_tx_id;
path = adv->pathi;
@@ -750,9 +753,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
- BGP_MAX_PACKET_SIZE_OVERFLOW;
- space_needed =
- BGP_NLRI_LENGTH + addpath_overhead
- + bgp_packet_mpattr_prefix_size(afi, safi, &rn->p);
+ space_needed = BGP_NLRI_LENGTH + addpath_overhead
+ + bgp_packet_mpattr_prefix_size(afi, safi, rn_p);
/* When remaining space can't include NLRI and it's length. */
if (space_remaining < space_needed)
@@ -798,7 +800,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
- BGP_MAX_PACKET_SIZE_OVERFLOW;
space_needed = BGP_NLRI_LENGTH + addpath_overhead
+ bgp_packet_mpattr_prefix_size(
- afi, safi, &rn->p);
+ afi, safi, rn_p);
/* If the attributes alone do not leave any room for
* NLRI then
@@ -828,12 +830,13 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
if ((afi == AFI_IP && safi == SAFI_UNICAST)
&& !peer_cap_enhe(peer, afi, safi))
- stream_put_prefix_addpath(s, &rn->p, addpath_encode,
+ stream_put_prefix_addpath(s, rn_p, addpath_encode,
addpath_tx_id);
else {
/* Encode the prefix in MP_REACH_NLRI attribute */
if (rn->prn)
- prd = (struct prefix_rd *)&rn->prn->p;
+ prd = (struct prefix_rd *)bgp_node_get_prefix(
+ rn->prn);
if (safi == SAFI_LABELED_UNICAST) {
label = bgp_adv_label(rn, path, peer, afi,
@@ -850,7 +853,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
snlri, peer, afi, safi, &vecarr,
adv->baa->attr);
- bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd,
+ bgp_packet_mpattr_prefix(snlri, afi, safi, rn_p, prd,
label_pnt, num_labels,
addpath_encode, addpath_tx_id,
adv->baa->attr);
@@ -858,7 +861,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
num_pfx++;
- if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) {
+ if (bgp_debug_update(NULL, rn_p, subgrp->update_group, 0)) {
char pfx_buf[BGP_PRD_PATH_STRLEN];
if (!send_attr_printed) {
@@ -882,10 +885,10 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
send_attr_printed = 1;
}
- bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p,
- label_pnt, num_labels,
- addpath_encode, addpath_tx_id,
- pfx_buf, sizeof(pfx_buf));
+ bgp_debug_rdpfxpath2str(afi, safi, prd, rn_p, label_pnt,
+ num_labels, addpath_encode,
+ addpath_tx_id, pfx_buf,
+ sizeof(pfx_buf));
zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
subgrp->update_group->id, subgrp->id,
pfx_buf);
@@ -964,7 +967,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
int addpath_encode = 0;
int addpath_overhead = 0;
uint32_t addpath_tx_id = 0;
- struct prefix_rd *prd = NULL;
+ const struct prefix_rd *prd = NULL;
if (!subgrp)
@@ -982,16 +985,19 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
addpath_overhead = addpath_encode ? BGP_ADDPATH_ID_LEN : 0;
while ((adv = bgp_adv_fifo_first(&subgrp->sync->withdraw)) != NULL) {
+ const struct prefix *rn_p;
+
assert(adv->rn);
adj = adv->adj;
rn = adv->rn;
+ rn_p = bgp_node_get_prefix(rn);
addpath_tx_id = adj->addpath_tx_id;
space_remaining =
STREAM_WRITEABLE(s) - BGP_MAX_PACKET_SIZE_OVERFLOW;
- space_needed =
- BGP_NLRI_LENGTH + addpath_overhead + BGP_TOTAL_ATTR_LEN
- + bgp_packet_mpattr_prefix_size(afi, safi, &rn->p);
+ space_needed = BGP_NLRI_LENGTH + addpath_overhead
+ + BGP_TOTAL_ATTR_LEN
+ + bgp_packet_mpattr_prefix_size(afi, safi, rn_p);
if (space_remaining < space_needed)
break;
@@ -1004,13 +1010,15 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
if (afi == AFI_IP && safi == SAFI_UNICAST
&& !peer_cap_enhe(peer, afi, safi))
- stream_put_prefix_addpath(s, &rn->p, addpath_encode,
+ stream_put_prefix_addpath(s, rn_p, addpath_encode,
addpath_tx_id);
else {
if (rn->prn)
- prd = (struct prefix_rd *)&rn->prn->p;
+ prd = (struct prefix_rd *)bgp_node_get_prefix(
+ rn->prn);
- /* If first time, format the MP_UNREACH header */
+ /* If first time, format the MP_UNREACH header
+ */
if (first_time) {
iana_afi_t pkt_afi;
iana_safi_t pkt_safi;
@@ -1019,8 +1027,8 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
pkt_safi = safi_int2iana(safi);
attrlen_pos = stream_get_endp(s);
- /* total attr length = 0 for now. reevaluate
- * later */
+ /* total attr length = 0 for now.
+ * reevaluate later */
stream_putw(s, 0);
mp_start = stream_get_endp(s);
mplen_pos = bgp_packet_mpunreach_start(s, afi,
@@ -1034,17 +1042,17 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
subgrp->id, pkt_afi, pkt_safi);
}
- bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd,
+ bgp_packet_mpunreach_prefix(s, rn_p, afi, safi, prd,
NULL, 0, addpath_encode,
addpath_tx_id, NULL);
}
num_pfx++;
- if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) {
+ if (bgp_debug_update(NULL, rn_p, subgrp->update_group, 0)) {
char pfx_buf[BGP_PRD_PATH_STRLEN];
- bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL, 0,
+ bgp_debug_rdpfxpath2str(afi, safi, prd, rn_p, NULL, 0,
addpath_encode, addpath_tx_id,
pfx_buf, sizeof(pfx_buf));
zlog_debug("u%" PRIu64 ":s%" PRIu64
diff --git a/bgpd/bgp_vnc_types.h b/bgpd/bgp_vnc_types.h
index f4202ff75e..04847ce6c9 100644
--- a/bgpd/bgp_vnc_types.h
+++ b/bgpd/bgp_vnc_types.h
@@ -19,7 +19,7 @@
#ifndef _QUAGGA_BGP_VNC_TYPES_H
#define _QUAGGA_BGP_VNC_TYPES_H
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
typedef enum {
BGP_VNC_SUBTLV_TYPE_LIFETIME = 1,
BGP_VNC_SUBTLV_TYPE_RFPOPTION = 2, /* deprecated */
diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c
index b67b0c322e..af632a1340 100644
--- a/bgpd/bgp_vpn.c
+++ b/bgpd/bgp_vpn.c
@@ -78,7 +78,9 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
rn = bgp_route_next(rn)) {
- if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
+ if (prd && memcmp(rn_p->u.val, prd->val, 8) != 0)
continue;
table = bgp_node_get_bgp_table_info(rn);
@@ -153,12 +155,12 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
uint16_t type;
struct rd_as rd_as = {0};
struct rd_ip rd_ip = {0};
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
struct rd_vnc_eth rd_vnc_eth = {0};
#endif
- uint8_t *pnt;
+ const uint8_t *pnt;
- pnt = rn->p.u.val;
+ pnt = rn_p->u.val;
/* Decode RD type. */
type = decode_rd_type(pnt);
@@ -169,7 +171,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
decode_rd_as4(pnt + 2, &rd_as);
else if (type == RD_TYPE_IP)
decode_rd_ip(pnt + 2, &rd_ip);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
else if (type == RD_TYPE_VNC_ETH)
decode_rd_vnc_eth(pnt, &rd_vnc_eth);
#endif
@@ -198,7 +200,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
vty_out(vty, "%s:%d",
inet_ntoa(rd_ip.ip),
rd_ip.val);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
else if (type == RD_TYPE_VNC_ETH)
vty_out(vty,
"%u:%02x:%02x:%02x:%02x:%02x:%02x",
@@ -221,9 +223,8 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
}
rd_header = 0;
}
- route_vty_out_tmp(vty, &rm->p, attr,
- safi, use_json,
- json_routes);
+ route_vty_out_tmp(vty, bgp_node_get_prefix(rm), attr,
+ safi, use_json, json_routes);
output_count++;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 3db9866a99..9f4347e736 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -68,25 +68,25 @@
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_mac.h"
#include "bgpd/bgp_flowspec.h"
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#endif
FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK,
- { .val_long = true, .match_profile = "datacenter", },
- { .val_long = false },
+ { .val_bool = true, .match_profile = "datacenter", },
+ { .val_bool = false },
)
FRR_CFG_DEFAULT_BOOL(BGP_SHOW_HOSTNAME,
- { .val_long = true, .match_profile = "datacenter", },
- { .val_long = false },
+ { .val_bool = true, .match_profile = "datacenter", },
+ { .val_bool = false },
)
FRR_CFG_DEFAULT_BOOL(BGP_LOG_NEIGHBOR_CHANGES,
- { .val_long = true, .match_profile = "datacenter", },
- { .val_long = false },
+ { .val_bool = true, .match_profile = "datacenter", },
+ { .val_bool = false },
)
FRR_CFG_DEFAULT_BOOL(BGP_DETERMINISTIC_MED,
- { .val_long = true, .match_profile = "datacenter", },
- { .val_long = false },
+ { .val_bool = true, .match_profile = "datacenter", },
+ { .val_bool = false },
)
FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY,
{ .val_ulong = 10, .match_profile = "datacenter", },
@@ -6590,6 +6590,7 @@ DEFUN(no_neighbor_maximum_prefix_out,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT);
peer->pmax_out[afi][safi] = 0;
return CMD_SUCCESS;
@@ -7520,8 +7521,7 @@ ALIAS (af_route_map_vpn_imexport,
"For routes leaked from current address-family to vpn\n")
DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd,
- "[no] import vrf route-map RMAP$rmap_str",
- NO_STR
+ "import vrf route-map RMAP$rmap_str",
"Import routes from another VRF\n"
"Vrf routes being filtered\n"
"Specify route map\n"
@@ -7530,13 +7530,8 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd,
VTY_DECLVAR_CONTEXT(bgp, bgp);
vpn_policy_direction_t dir = BGP_VPN_POLICY_DIR_FROMVPN;
afi_t afi;
- int idx = 0;
- int yes = 1;
struct bgp *bgp_default;
- if (argv_find(argv, argc, "no", &idx))
- yes = 0;
-
afi = vpn_policy_getafi(vty, bgp, true);
if (afi == AFI_MAX)
return CMD_WARNING_CONFIG_FAILED;
@@ -7559,35 +7554,56 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd,
vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
- if (yes) {
- if (bgp->vpn_policy[afi].rmap_name[dir])
- XFREE(MTYPE_ROUTE_MAP_NAME,
- bgp->vpn_policy[afi].rmap_name[dir]);
- bgp->vpn_policy[afi].rmap_name[dir] =
- XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str);
- bgp->vpn_policy[afi].rmap[dir] =
- route_map_lookup_warn_noexist(vty, rmap_str);
- if (!bgp->vpn_policy[afi].rmap[dir])
- return CMD_SUCCESS;
- } else {
- if (bgp->vpn_policy[afi].rmap_name[dir])
- XFREE(MTYPE_ROUTE_MAP_NAME,
- bgp->vpn_policy[afi].rmap_name[dir]);
- bgp->vpn_policy[afi].rmap_name[dir] = NULL;
- bgp->vpn_policy[afi].rmap[dir] = NULL;
- }
+ if (bgp->vpn_policy[afi].rmap_name[dir])
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ bgp->vpn_policy[afi].rmap_name[dir]);
+ bgp->vpn_policy[afi].rmap_name[dir] =
+ XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str);
+ bgp->vpn_policy[afi].rmap[dir] =
+ route_map_lookup_warn_noexist(vty, rmap_str);
+ if (!bgp->vpn_policy[afi].rmap[dir])
+ return CMD_SUCCESS;
+
+ SET_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT);
vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
return CMD_SUCCESS;
}
-ALIAS(af_import_vrf_route_map, af_no_import_vrf_route_map_cmd,
- "no import vrf route-map",
+DEFPY(af_no_import_vrf_route_map, af_no_import_vrf_route_map_cmd,
+ "no import vrf route-map [RMAP$rmap_str]",
NO_STR
"Import routes from another VRF\n"
"Vrf routes being filtered\n"
- "Specify route map\n")
+ "Specify route map\n"
+ "name of route-map\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ vpn_policy_direction_t dir = BGP_VPN_POLICY_DIR_FROMVPN;
+ afi_t afi;
+
+ afi = vpn_policy_getafi(vty, bgp, true);
+ if (afi == AFI_MAX)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ vpn_leak_prechange(dir, afi, bgp_get_default(), bgp);
+
+ if (bgp->vpn_policy[afi].rmap_name[dir])
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ bgp->vpn_policy[afi].rmap_name[dir]);
+ bgp->vpn_policy[afi].rmap_name[dir] = NULL;
+ bgp->vpn_policy[afi].rmap[dir] = NULL;
+
+ if (bgp->vpn_policy[afi].import_vrf->count == 0)
+ UNSET_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT);
+
+ vpn_leak_postchange(dir, afi, bgp_get_default(), bgp);
+
+ return CMD_SUCCESS;
+}
DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
"[no] import vrf VIEWVRFNAME$import_name",
@@ -7613,6 +7629,11 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
return CMD_WARNING;
}
+ if (strcmp(import_name, "route-map") == 0) {
+ vty_out(vty, "%% Must include route-map name\n");
+ return CMD_WARNING;
+ }
+
if (argv_find(argv, argc, "no", &idx))
remove = true;
@@ -7935,27 +7956,32 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
if (safi == SAFI_MPLS_VPN) {
for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
- if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
+ if (prd && memcmp(rn_p->u.val, prd->val, 8) != 0)
continue;
table = bgp_node_get_bgp_table_info(rn);
- if (table != NULL) {
+ if (table == NULL)
+ continue;
- if ((rm = bgp_node_match(table, &match))
- != NULL) {
- if (rm->p.prefixlen
- == match.prefixlen) {
- SET_FLAG(rm->flags,
- BGP_NODE_USER_CLEAR);
- bgp_process(bgp, rm, afi, safi);
- }
- bgp_unlock_node(rm);
+ if ((rm = bgp_node_match(table, &match)) != NULL) {
+ const struct prefix *rm_p =
+ bgp_node_get_prefix(rm);
+
+ if (rm_p->prefixlen == match.prefixlen) {
+ SET_FLAG(rm->flags,
+ BGP_NODE_USER_CLEAR);
+ bgp_process(bgp, rm, afi, safi);
}
+ bgp_unlock_node(rm);
}
}
} else {
if ((rn = bgp_node_match(rib, &match)) != NULL) {
- if (rn->p.prefixlen == match.prefixlen) {
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
+
+ if (rn_p->prefixlen == match.prefixlen) {
SET_FLAG(rn->flags, BGP_NODE_USER_CLEAR);
bgp_process(bgp, rn, afi, safi);
}
@@ -9010,11 +9036,20 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_object_int_add(json_peer, "msgSent",
PEER_TOTAL_TX(peer));
+ atomic_size_t outq_count, inq_count;
+ outq_count = atomic_load_explicit(
+ &peer->obuf->count,
+ memory_order_relaxed);
+ inq_count = atomic_load_explicit(
+ &peer->ibuf->count,
+ memory_order_relaxed);
+
json_object_int_add(json_peer, "tableVersion",
peer->version[afi][safi]);
json_object_int_add(json_peer, "outq",
- peer->obuf->count);
- json_object_int_add(json_peer, "inq", 0);
+ outq_count);
+ json_object_int_add(json_peer, "inq",
+ inq_count);
peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN,
use_json, json_peer);
@@ -9096,10 +9131,21 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
vty_out(vty, "%*s", max_neighbor_width - len,
" ");
- vty_out(vty, "4 %10u %9u %9u %8" PRIu64 " %4d %4zd %8s",
+ atomic_size_t outq_count, inq_count;
+ outq_count = atomic_load_explicit(
+ &peer->obuf->count,
+ memory_order_relaxed);
+ inq_count = atomic_load_explicit(
+ &peer->ibuf->count,
+ memory_order_relaxed);
+
+ vty_out(vty,
+ "4 %10u %9u %9u %8" PRIu64
+ " %4zu %4zu %8s",
peer->as, PEER_TOTAL_RX(peer),
- PEER_TOTAL_TX(peer), peer->version[afi][safi],
- 0, peer->obuf->count,
+ PEER_TOTAL_TX(peer),
+ peer->version[afi][safi], inq_count,
+ outq_count,
peer_uptime(peer->uptime, timebuf,
BGP_UPTIME_LEN, 0, NULL));
@@ -11683,9 +11729,17 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object *json_stat = NULL;
json_stat = json_object_new_object();
/* Packet counts. */
- json_object_int_add(json_stat, "depthInq", 0);
+
+ atomic_size_t outq_count, inq_count;
+ outq_count = atomic_load_explicit(&p->obuf->count,
+ memory_order_relaxed);
+ inq_count = atomic_load_explicit(&p->ibuf->count,
+ memory_order_relaxed);
+
+ json_object_int_add(json_stat, "depthInq",
+ (unsigned long)inq_count);
json_object_int_add(json_stat, "depthOutq",
- (unsigned long)p->obuf->count);
+ (unsigned long)outq_count);
json_object_int_add(json_stat, "opensSent",
atomic_load_explicit(&p->open_out,
memory_order_relaxed));
@@ -11726,11 +11780,16 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object_int_add(json_stat, "totalRecv", PEER_TOTAL_RX(p));
json_object_object_add(json_neigh, "messageStats", json_stat);
} else {
+ atomic_size_t outq_count, inq_count;
+ outq_count = atomic_load_explicit(&p->obuf->count,
+ memory_order_relaxed);
+ inq_count = atomic_load_explicit(&p->ibuf->count,
+ memory_order_relaxed);
+
/* Packet counts. */
vty_out(vty, " Message statistics:\n");
- vty_out(vty, " Inq depth is 0\n");
- vty_out(vty, " Outq depth is %lu\n",
- (unsigned long)p->obuf->count);
+ vty_out(vty, " Inq depth is %zu\n", inq_count);
+ vty_out(vty, " Outq depth is %zu\n", outq_count);
vty_out(vty, " Sent Rcvd\n");
vty_out(vty, " Opens: %10d %10d\n",
atomic_load_explicit(&p->open_out,
@@ -14116,7 +14175,8 @@ static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
int indent = 2;
if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]) {
- if (listcount(bgp->vpn_policy[afi].import_vrf))
+ if (CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT))
vty_out(vty, "%*simport vrf route-map %s\n", indent, "",
bgp->vpn_policy[afi]
.rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]);
@@ -15212,7 +15272,7 @@ int bgp_config_write(struct vty *vty)
hook_call(bgp_inst_config_write, bgp, vty);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
bgp_rfapi_cfg_write(vty, bgp);
#endif
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 1c0f3c99b7..dd0e35a745 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -51,7 +51,7 @@
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_bfd.h"
#include "bgpd/bgp_label.h"
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
#include "bgpd/rfapi/vnc_export_bgp.h"
#endif
@@ -928,7 +928,7 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex)
return nexthop;
}
-static bool bgp_table_map_apply(struct route_map *map, struct prefix *p,
+static bool bgp_table_map_apply(struct route_map *map, const struct prefix *p,
struct bgp_path_info *path)
{
route_map_result_t ret;
@@ -1148,7 +1148,7 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
return true;
}
-void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
+void bgp_zebra_announce(struct bgp_node *rn, const struct prefix *p,
struct bgp_path_info *info, struct bgp *bgp, afi_t afi,
safi_t safi)
{
@@ -1184,7 +1184,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
prefix2str(p, buf_prefix, sizeof(buf_prefix));
if (safi == SAFI_FLOWSPEC) {
- bgp_pbr_update_entry(bgp, &rn->p, info, afi, safi, true);
+ bgp_pbr_update_entry(bgp, bgp_node_get_prefix(rn),
+ info, afi, safi, true);
return;
}
@@ -1480,11 +1481,11 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi)
&& (pi->sub_type == BGP_ROUTE_NORMAL
|| pi->sub_type == BGP_ROUTE_IMPORTED)))
- bgp_zebra_announce(rn, &rn->p, pi, bgp, afi,
- safi);
+ bgp_zebra_announce(rn, bgp_node_get_prefix(rn),
+ pi, bgp, afi, safi);
}
-void bgp_zebra_withdraw(struct prefix *p, struct bgp_path_info *info,
+void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info,
struct bgp *bgp, safi_t safi)
{
struct zapi_route api;
@@ -1604,7 +1605,7 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type,
if (vrf_bitmap_check(zclient->redist[afi][type], bgp->vrf_id))
return CMD_WARNING;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (EVPN_ENABLED(bgp) && type == ZEBRA_ROUTE_VNC_DIRECT) {
vnc_export_bgp_enable(
bgp, afi); /* only enables if mode bits cfg'd */
@@ -1765,7 +1766,7 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
* they operate within bgpd irrespective of zebra connection
* status. red lookup fails if there is no zebra connection.
*/
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (EVPN_ENABLED(bgp) && type == ZEBRA_ROUTE_VNC_DIRECT) {
vnc_export_bgp_disable(bgp, afi);
}
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 39c28c452c..e546cd5da7 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -32,12 +32,13 @@ extern void bgp_zebra_destroy(void);
extern int bgp_zebra_get_table_range(uint32_t chunk_size,
uint32_t *start, uint32_t *end);
extern int bgp_if_update_all(void);
-extern void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
+extern void bgp_zebra_announce(struct bgp_node *rn, const struct prefix *p,
struct bgp_path_info *path, struct bgp *bgp,
afi_t afi, safi_t safi);
extern void bgp_zebra_announce_table(struct bgp *, afi_t, safi_t);
-extern void bgp_zebra_withdraw(struct prefix *p, struct bgp_path_info *path,
- struct bgp *bgp, safi_t safi);
+extern void bgp_zebra_withdraw(const struct prefix *p,
+ struct bgp_path_info *path, struct bgp *bgp,
+ safi_t safi);
extern void bgp_zebra_initiate_radv(struct bgp *bgp, struct peer *peer);
extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 9452770100..238a692bdf 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -65,7 +65,7 @@
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_damp.h"
#include "bgpd/bgp_mplsvpn.h"
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#include "bgpd/rfapi/rfapi_backend.h"
#endif
@@ -2976,7 +2976,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->as = *as;
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
if (inst_type != BGP_INSTANCE_TYPE_VRF) {
bgp->rfapi = bgp_rfapi_new(bgp);
assert(bgp->rfapi);
@@ -3375,7 +3375,7 @@ int bgp_delete(struct bgp *bgp)
/* TODO - Other memory may need to be freed - e.g., NHT */
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
rfapi_delete(bgp);
#endif
bgp_cleanup_routes(bgp);
@@ -4199,6 +4199,19 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
}
}
+ /*
+ * If the peer is a route server client let's not
+ * muck with the nexthop on the way out the door
+ */
+ if (flag & PEER_FLAG_RSERVER_CLIENT) {
+ if (set)
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_NEXTHOP_UNCHANGED);
+ else
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_NEXTHOP_UNCHANGED);
+ }
+
/* Inherit from peer-group or set/unset flags accordingly. */
if (peer_group_active(peer) && set == invert)
peer_af_flag_inherit(peer, afi, safi, flag);
@@ -5787,7 +5800,7 @@ static void peer_distribute_update(struct access_list *access)
}
}
}
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
vnc_prefix_list_update(bgp);
#endif
}
@@ -7023,7 +7036,7 @@ void bgp_init(unsigned short instance)
/* Init zebra. */
bgp_zebra_init(bm->master, instance);
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
vnc_zebra_init(bm->master);
#endif
@@ -7038,7 +7051,7 @@ void bgp_init(unsigned short instance)
bgp_route_map_init();
bgp_scan_vty_init();
bgp_mplsvpn_init();
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
rfapi_init();
#endif
bgp_ethernetvpn_init();
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.h b/bgpd/rfapi/bgp_rfapi_cfg.h
index b72d38220b..f1548a6173 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.h
+++ b/bgpd/rfapi/bgp_rfapi_cfg.h
@@ -24,7 +24,7 @@
#include "lib/table.h"
#include "lib/routemap.h"
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include "rfapi.h"
struct rfapi_l2_group_cfg {
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index d87292f652..435b61edf0 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -355,7 +355,7 @@ int rfapi_check(void *handle)
void del_vnc_route(struct rfapi_descriptor *rfd,
struct peer *peer, /* rfd->peer for RFP regs */
- struct bgp *bgp, safi_t safi, struct prefix *p,
+ struct bgp *bgp, safi_t safi, const struct prefix *p,
struct prefix_rd *prd, uint8_t type, uint8_t sub_type,
struct rfapi_nexthop *lnh, int kill)
{
@@ -557,7 +557,7 @@ void rfapi_vn_options_free(struct rfapi_vn_option *p)
/* Based on bgp_redistribute_add() */
void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
- struct bgp *bgp, int safi, struct prefix *p,
+ struct bgp *bgp, int safi, const struct prefix *p,
struct prefix_rd *prd, struct rfapi_ip_addr *nexthop,
uint32_t *local_pref,
uint32_t *lifetime, /* NULL => dont send lifetime */
diff --git a/bgpd/rfapi/rfapi.h b/bgpd/rfapi/rfapi.h
index 6af2ebeeb8..beb44aa780 100644
--- a/bgpd/rfapi/rfapi.h
+++ b/bgpd/rfapi/rfapi.h
@@ -21,7 +21,7 @@
#ifndef _QUAGGA_BGP_RFAPI_H
#define _QUAGGA_BGP_RFAPI_H
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include <stdint.h>
#include <netinet/in.h>
diff --git a/bgpd/rfapi/rfapi_ap.c b/bgpd/rfapi/rfapi_ap.c
index c5fda15d33..abb18aeb2c 100644
--- a/bgpd/rfapi/rfapi_ap.c
+++ b/bgpd/rfapi/rfapi_ap.c
@@ -81,10 +81,10 @@
* is used to spread out the sort for adbs with the same lifetime
* and thereby make the skip list operations more efficient.
*/
-static int sl_adb_lifetime_cmp(void *adb1, void *adb2)
+static int sl_adb_lifetime_cmp(const void *adb1, const void *adb2)
{
- struct rfapi_adb *a1 = adb1;
- struct rfapi_adb *a2 = adb2;
+ const struct rfapi_adb *a1 = adb1;
+ const struct rfapi_adb *a2 = adb2;
if (a1->lifetime < a2->lifetime)
return -1;
diff --git a/bgpd/rfapi/rfapi_backend.h b/bgpd/rfapi/rfapi_backend.h
index 96e464d2ae..4d2ae0b02f 100644
--- a/bgpd/rfapi/rfapi_backend.h
+++ b/bgpd/rfapi/rfapi_backend.h
@@ -21,7 +21,7 @@
#ifndef _QUAGGA_BGP_RFAPI_BACKEND_H
#define _QUAGGA_BGP_RFAPI_BACKEND_H
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_nexthop.h"
@@ -35,16 +35,16 @@ extern void rfapi_delete(struct bgp *);
struct rfapi *bgp_rfapi_new(struct bgp *bgp);
void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h);
-extern void rfapiProcessUpdate(struct peer *peer, void *rfd, struct prefix *p,
- struct prefix_rd *prd, struct attr *attr,
- afi_t afi, safi_t safi, uint8_t type,
- uint8_t sub_type, uint32_t *label);
+extern void rfapiProcessUpdate(struct peer *peer, void *rfd,
+ const struct prefix *p, struct prefix_rd *prd,
+ struct attr *attr, afi_t afi, safi_t safi,
+ uint8_t type, uint8_t sub_type, uint32_t *label);
-extern void rfapiProcessWithdraw(struct peer *peer, void *rfd, struct prefix *p,
- struct prefix_rd *prd, struct attr *attr,
- afi_t afi, safi_t safi, uint8_t type,
- int kill);
+extern void rfapiProcessWithdraw(struct peer *peer, void *rfd,
+ const struct prefix *p, struct prefix_rd *prd,
+ struct attr *attr, afi_t afi, safi_t safi,
+ uint8_t type, int kill);
extern void rfapiProcessPeerDown(struct peer *peer);
@@ -56,7 +56,7 @@ extern void vnc_zebra_withdraw(struct prefix *p,
struct bgp_path_info *old_select);
-extern void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p,
+extern void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
struct bgp_path_info *bpi, safi_t safi);
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 2f274015fc..d058fe3b28 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -663,14 +663,17 @@ rfapiMonitorMoveShorter(struct agg_node *original_vpn_node, int lockoffset)
* If no less-specific routes, try to use the 0/0 node
*/
if (!par) {
+ const struct prefix *p;
/* this isn't necessarily 0/0 */
par = agg_route_table_top(original_vpn_node);
+ if (par)
+ p = agg_node_get_prefix(par);
/*
* If we got the top node but it wasn't 0/0,
* ignore it
*/
- if (par && par->p.prefixlen) {
+ if (par && p->prefixlen) {
agg_unlock_node(par); /* maybe free */
par = NULL;
}
@@ -685,9 +688,10 @@ rfapiMonitorMoveShorter(struct agg_node *original_vpn_node, int lockoffset)
*/
if (!par) {
struct prefix pfx_default;
+ const struct prefix *p = agg_node_get_prefix(original_vpn_node);
memset(&pfx_default, 0, sizeof(pfx_default));
- pfx_default.family = original_vpn_node->p.family;
+ pfx_default.family = p->family;
/* creates default node if none exists */
par = agg_node_get(agg_get_table(original_vpn_node),
@@ -768,6 +772,7 @@ static void rfapiMonitorMoveLonger(struct agg_node *new_vpn_node)
struct rfapi_monitor_vpn *mlast;
struct bgp_path_info *bpi;
struct agg_node *par;
+ const struct prefix *new_vpn_node_p = agg_node_get_prefix(new_vpn_node);
RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0);
@@ -808,12 +813,11 @@ static void rfapiMonitorMoveLonger(struct agg_node *new_vpn_node)
* specific updated node
*/
for (mlast = NULL, monitor = RFAPI_MONITOR_VPN(par); monitor;) {
-
/*
* If new longest match for monitor prefix is the new
* route's prefix, move monitor to new route's prefix
*/
- if (prefix_match(&new_vpn_node->p, &monitor->p)) {
+ if (prefix_match(new_vpn_node_p, &monitor->p)) {
/* detach */
if (mlast) {
mlast->next = monitor->next;
@@ -1040,7 +1044,7 @@ int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id)
for (i = 0; i < ecom->size; ++i) {
as_t as = 0;
int encode = 0;
- uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
+ const uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
/* High-order octet of type. */
encode = *p++;
@@ -1266,6 +1270,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
{
struct rfapi_next_hop_entry *new;
int have_vnc_tunnel_un = 0;
+ const struct prefix *p = agg_node_get_prefix(rn);
#ifdef DEBUG_ENCAP_MONITOR
vnc_zlog_debug_verbose("%s: entry, bpi %p, rn %p", __func__, bpi, rn);
@@ -1289,8 +1294,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
- memcpy(&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet,
- ETH_ALEN);
+ memcpy(&vo->v.l2addr.macaddr, &p->u.prefix_eth.octet, ETH_ALEN);
/* only low 3 bytes of this are significant */
(void)rfapiEcommunityGetLNI(bpi->attr->ecommunity,
&vo->v.l2addr.logical_net_id);
@@ -1493,7 +1497,8 @@ static int rfapiNhlAddNodeRoutes(
struct prefix pfx_un;
struct skiplist *seen_nexthops;
int count = 0;
- int is_l2 = (rn->p.family == AF_ETHERNET);
+ const struct prefix *p = agg_node_get_prefix(rn);
+ int is_l2 = (p->family == AF_ETHERNET);
if (rfd_rib_node) {
struct agg_table *atable = agg_get_table(rfd_rib_node);
@@ -1626,14 +1631,14 @@ static int rfapiNhlAddSubtree(
* hands in node->link */
if (agg_node_left(rn) && agg_node_left(rn) != omit_node) {
if (agg_node_left(rn)->info) {
+ const struct prefix *p =
+ agg_node_get_prefix(agg_node_left(rn));
int count = 0;
struct agg_node *rib_rn = NULL;
- rfapiQprefix2Rprefix(&agg_node_left(rn)->p, &rprefix);
- if (rfd_rib_table) {
- rib_rn = agg_node_get(rfd_rib_table,
- &agg_node_left(rn)->p);
- }
+ rfapiQprefix2Rprefix(p, &rprefix);
+ if (rfd_rib_table)
+ rib_rn = agg_node_get(rfd_rib_table, p);
count = rfapiNhlAddNodeRoutes(
agg_node_left(rn), &rprefix, lifetime, 0, head,
@@ -1653,14 +1658,15 @@ static int rfapiNhlAddSubtree(
if (agg_node_right(rn) && agg_node_right(rn) != omit_node) {
if (agg_node_right(rn)->info) {
+ const struct prefix *p =
+ agg_node_get_prefix(agg_node_right(rn));
int count = 0;
struct agg_node *rib_rn = NULL;
- rfapiQprefix2Rprefix(&agg_node_right(rn)->p, &rprefix);
- if (rfd_rib_table) {
- rib_rn = agg_node_get(rfd_rib_table,
- &agg_node_right(rn)->p);
- }
+ rfapiQprefix2Rprefix(p, &rprefix);
+ if (rfd_rib_table)
+ rib_rn = agg_node_get(rfd_rib_table, p);
+
count = rfapiNhlAddNodeRoutes(
agg_node_right(rn), &rprefix, lifetime, 0, head,
tail, exclude_vnaddr, rib_rn,
@@ -1712,23 +1718,18 @@ struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList(
struct rfapi_next_hop_entry *answer = NULL;
struct rfapi_next_hop_entry *last = NULL;
struct agg_node *parent;
+ const struct prefix *p = agg_node_get_prefix(rn);
int count = 0;
struct agg_node *rib_rn;
#ifdef DEBUG_RETURNED_NHL
- {
- char buf[PREFIX_STRLEN];
-
- prefix2str(&rn->p, buf, sizeof(buf));
- vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__,
- buf);
- }
+ vnc_zlog_debug_verbose("%s: called with node pfx=%rRN", __func__, rn);
rfapiDebugBacktrace();
#endif
- rfapiQprefix2Rprefix(&rn->p, &rprefix);
+ rfapiQprefix2Rprefix(p, &rprefix);
- rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, &rn->p) : NULL;
+ rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL;
/*
* Add non-withdrawn routes at this node
@@ -1780,9 +1781,10 @@ struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList(
* Add non-withdrawn routes from less-specific prefix
*/
if (parent) {
- rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, &parent->p)
- : NULL;
- rfapiQprefix2Rprefix(&parent->p, &rprefix);
+ const struct prefix *p = agg_node_get_prefix(parent);
+
+ rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL;
+ rfapiQprefix2Rprefix(p, &rprefix);
count += rfapiNhlAddNodeRoutes(parent, &rprefix, lifetime, 0,
&answer, &last, exclude_vnaddr,
rib_rn, pfx_target_original);
@@ -1863,7 +1865,9 @@ struct rfapi_next_hop_entry *rfapiEthRouteNode2NextHopList(
struct rfapi_next_hop_entry *last = NULL;
struct agg_node *rib_rn;
- rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, &rn->p) : NULL;
+ rib_rn = rfd_rib_table
+ ? agg_node_get(rfd_rib_table, agg_node_get_prefix(rn))
+ : NULL;
count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 0, &answer, &last,
NULL, rib_rn, pfx_target_original);
@@ -2006,10 +2010,10 @@ static void rfapiBgpInfoDetach(struct agg_node *rn, struct bgp_path_info *bpi)
/*
* For L3-indexed import tables
*/
-static int rfapi_bi_peer_rd_cmp(void *b1, void *b2)
+static int rfapi_bi_peer_rd_cmp(const void *b1, const void *b2)
{
- struct bgp_path_info *bpi1 = b1;
- struct bgp_path_info *bpi2 = b2;
+ const struct bgp_path_info *bpi1 = b1;
+ const struct bgp_path_info *bpi2 = b2;
/*
* Compare peers
@@ -2022,8 +2026,9 @@ static int rfapi_bi_peer_rd_cmp(void *b1, void *b2)
/*
* compare RDs
*/
- return vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc.import.rd,
- (struct prefix *)&bpi2->extra->vnc.import.rd);
+ return vnc_prefix_cmp(
+ (const struct prefix *)&bpi1->extra->vnc.import.rd,
+ (const struct prefix *)&bpi2->extra->vnc.import.rd);
}
/*
@@ -2031,10 +2036,10 @@ static int rfapi_bi_peer_rd_cmp(void *b1, void *b2)
* The BPIs in these tables should ALWAYS have an aux_prefix set because
* they arrive via IPv4 or IPv6 advertisements.
*/
-static int rfapi_bi_peer_rd_aux_cmp(void *b1, void *b2)
+static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2)
{
- struct bgp_path_info *bpi1 = b1;
- struct bgp_path_info *bpi2 = b2;
+ const struct bgp_path_info *bpi1 = b1;
+ const struct bgp_path_info *bpi2 = b2;
int rc;
/*
@@ -2089,6 +2094,7 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */
struct bgp_path_info *bpi) /* new BPI */
{
struct skiplist *sl;
+ const struct prefix *p;
assert(rn);
assert(bpi);
@@ -2105,7 +2111,8 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */
sl = RFAPI_RDINDEX_W_ALLOC(rn);
if (!sl) {
- if (AF_ETHERNET == rn->p.family) {
+ p = agg_node_get_prefix(rn);
+ if (AF_ETHERNET == p->family) {
sl = skiplist_new(0, rfapi_bi_peer_rd_aux_cmp, NULL);
} else {
sl = skiplist_new(0, rfapi_bi_peer_rd_cmp, NULL);
@@ -2152,7 +2159,7 @@ static void rfapiItBiIndexDump(struct agg_node *rn)
static struct bgp_path_info *rfapiItBiIndexSearch(
struct agg_node *rn, /* Import table VPN node */
struct prefix_rd *prd, struct peer *peer,
- struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */
+ const struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */
{
struct skiplist *sl;
int rc;
@@ -2375,7 +2382,7 @@ static int rfapiWithdrawTimerVPN(struct thread *t)
struct rfapi_withdraw *wcb = t->arg;
struct bgp_path_info *bpi = wcb->info;
struct bgp *bgp = bgp_get_default();
-
+ const struct prefix *p;
struct rfapi_monitor_vpn *moved;
afi_t afi;
@@ -2398,15 +2405,8 @@ static int rfapiWithdrawTimerVPN(struct thread *t)
RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, wcb->lockoffset);
- {
- char buf[BUFSIZ];
-
- vnc_zlog_debug_verbose(
- "%s: removing bpi %p at prefix %s/%d", __func__, bpi,
- rfapi_ntop(wcb->node->p.family, &wcb->node->p.u.prefix,
- buf, BUFSIZ),
- wcb->node->p.prefixlen);
- }
+ vnc_zlog_debug_verbose("%s: removing bpi %p at prefix %pRN", __func__,
+ bpi, wcb->node);
/*
* Remove the route (doubly-linked)
@@ -2415,7 +2415,8 @@ static int rfapiWithdrawTimerVPN(struct thread *t)
&& VALID_INTERIOR_TYPE(bpi->type))
RFAPI_MONITOR_EXTERIOR(wcb->node)->valid_interior_count--;
- afi = family2afi(wcb->node->p.family);
+ p = agg_node_get_prefix(wcb->node);
+ afi = family2afi(p->family);
wcb->import_table->holddown_count[afi] -= 1; /* keep count consistent */
rfapiItBiIndexDel(wcb->node, bpi);
rfapiBgpInfoDetach(wcb->node, bpi); /* with removed bpi */
@@ -2846,11 +2847,13 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table,
}
-typedef void(rfapi_bi_filtered_import_f)(struct rfapi_import_table *, int,
- struct peer *, void *, struct prefix *,
- struct prefix *, afi_t,
- struct prefix_rd *, struct attr *,
- uint8_t, uint8_t, uint32_t *);
+typedef void(rfapi_bi_filtered_import_f)(struct rfapi_import_table *table,
+ int action, struct peer *peer,
+ void *rfd, const struct prefix *prefix,
+ const struct prefix *aux_prefix,
+ afi_t afi, struct prefix_rd *prd,
+ struct attr *attr, uint8_t type,
+ uint8_t sub_type, uint32_t *label);
static void rfapiExpireEncapNow(struct rfapi_import_table *it,
@@ -2899,11 +2902,11 @@ static int rfapiGetNexthop(struct attr *attr, struct prefix *prefix)
static void rfapiBgpInfoFilteredImportEncap(
struct rfapi_import_table *import_table, int action, struct peer *peer,
void *rfd, /* set for looped back routes */
- struct prefix *p,
- struct prefix *aux_prefix, /* Unused for encap routes */
+ const struct prefix *p,
+ const struct prefix *aux_prefix, /* Unused for encap routes */
afi_t afi, struct prefix_rd *prd,
struct attr *attr, /* part of bgp_path_info */
- uint8_t type, /* part of bgp_path_info */
+ uint8_t type, /* part of bgp_path_info */
uint8_t sub_type, /* part of bgp_path_info */
uint32_t *label) /* part of bgp_path_info */
{
@@ -3074,11 +3077,8 @@ static void rfapiBgpInfoFilteredImportEncap(
if (action == FIF_ACTION_WITHDRAW) {
vnc_zlog_debug_verbose(
- "%s: withdrawing at prefix %s/%d",
- __func__,
- inet_ntop(rn->p.family, &rn->p.u.prefix,
- buf, BUFSIZ),
- rn->p.prefixlen);
+ "%s: withdrawing at prefix %pRN",
+ __func__, rn);
rfapiBiStartWithdrawTimer(
import_table, rn, bpi, afi, SAFI_ENCAP,
@@ -3086,13 +3086,11 @@ static void rfapiBgpInfoFilteredImportEncap(
} else {
vnc_zlog_debug_verbose(
- "%s: %s at prefix %s/%d", __func__,
+ "%s: %s at prefix %pRN", __func__,
((action == FIF_ACTION_KILL)
? "killing"
: "replacing"),
- inet_ntop(rn->p.family, &rn->p.u.prefix,
- buf, BUFSIZ),
- rn->p.prefixlen);
+ rn);
/*
* If this route is waiting to be deleted
@@ -3160,10 +3158,8 @@ static void rfapiBgpInfoFilteredImportEncap(
rn = agg_node_get(rt, p);
}
- vnc_zlog_debug_verbose(
- "%s: (afi=%d, rn=%p) inserting at prefix %s/%d", __func__, afi,
- rn, inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
- rn->p.prefixlen);
+ vnc_zlog_debug_verbose("%s: (afi=%d, rn=%p) inserting at prefix %pRN",
+ __func__, afi, rn, rn);
rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_ENCAP);
@@ -3246,6 +3242,7 @@ static void rfapiBgpInfoFilteredImportEncap(
__func__, rn);
#endif
for (m = RFAPI_MONITOR_ENCAP(rn); m; m = m->next) {
+ const struct prefix *p;
/*
* For each referenced bpi/route, copy the ENCAP route's
@@ -3273,9 +3270,9 @@ static void rfapiBgpInfoFilteredImportEncap(
* list
* per prefix.
*/
-
+ p = agg_node_get_prefix(m->node);
referenced_vpn_prefix =
- agg_node_get(referenced_vpn_table, &m->node->p);
+ agg_node_get(referenced_vpn_table, p);
assert(referenced_vpn_prefix);
for (mnext = referenced_vpn_prefix->info; mnext;
mnext = mnext->next) {
@@ -3360,11 +3357,11 @@ static void rfapiExpireVpnNow(struct rfapi_import_table *it,
void rfapiBgpInfoFilteredImportVPN(
struct rfapi_import_table *import_table, int action, struct peer *peer,
void *rfd, /* set for looped back routes */
- struct prefix *p,
- struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
+ const struct prefix *p,
+ const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
afi_t afi, struct prefix_rd *prd,
struct attr *attr, /* part of bgp_path_info */
- uint8_t type, /* part of bgp_path_info */
+ uint8_t type, /* part of bgp_path_info */
uint8_t sub_type, /* part of bgp_path_info */
uint32_t *label) /* part of bgp_path_info */
{
@@ -3525,11 +3522,8 @@ void rfapiBgpInfoFilteredImportVPN(
BGP_PATH_REMOVED);
vnc_zlog_debug_verbose(
- "%s: withdrawing at prefix %s/%d%s",
- __func__, rfapi_ntop(rn->p.family,
- &rn->p.u.prefix,
- buf, BUFSIZ),
- rn->p.prefixlen,
+ "%s: withdrawing at prefix %pRN%s",
+ __func__, rn,
(washolddown
? " (already being withdrawn)"
: ""));
@@ -3548,14 +3542,11 @@ void rfapiBgpInfoFilteredImportVPN(
VNC_ITRCCK;
} else {
vnc_zlog_debug_verbose(
- "%s: %s at prefix %s/%d", __func__,
+ "%s: %s at prefix %pRN", __func__,
((action == FIF_ACTION_KILL)
? "killing"
: "replacing"),
- rfapi_ntop(rn->p.family,
- &rn->p.u.prefix, buf,
- BUFSIZ),
- rn->p.prefixlen);
+ rn);
/*
* If this route is waiting to be deleted
@@ -3673,10 +3664,8 @@ void rfapiBgpInfoFilteredImportVPN(
info_new->extra->vnc.import.aux_prefix = *aux_prefix;
}
- vnc_zlog_debug_verbose(
- "%s: inserting bpi %p at prefix %s/%d #%d", __func__, info_new,
- rfapi_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
- rn->p.prefixlen, rn->lock);
+ vnc_zlog_debug_verbose("%s: inserting bpi %p at prefix %pRN #%d",
+ __func__, info_new, rn, rn->lock);
rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_MPLS_VPN);
rfapiItBiIndexAdd(rn, info_new);
@@ -3839,11 +3828,11 @@ void rfapiBgpInfoFilteredImportVPN(
static void rfapiBgpInfoFilteredImportBadSafi(
struct rfapi_import_table *import_table, int action, struct peer *peer,
void *rfd, /* set for looped back routes */
- struct prefix *p,
- struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
+ const struct prefix *p,
+ const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
afi_t afi, struct prefix_rd *prd,
struct attr *attr, /* part of bgp_path_info */
- uint8_t type, /* part of bgp_path_info */
+ uint8_t type, /* part of bgp_path_info */
uint8_t sub_type, /* part of bgp_path_info */
uint32_t *label) /* part of bgp_path_info */
{
@@ -3869,7 +3858,7 @@ rfapiBgpInfoFilteredImportFunction(safi_t safi)
void rfapiProcessUpdate(struct peer *peer,
void *rfd, /* set when looped from RFP/RFAPI */
- struct prefix *p, struct prefix_rd *prd,
+ const struct prefix *p, struct prefix_rd *prd,
struct attr *attr, afi_t afi, safi_t safi, uint8_t type,
uint8_t sub_type, uint32_t *label)
{
@@ -3953,7 +3942,7 @@ void rfapiProcessUpdate(struct peer *peer,
}
-void rfapiProcessWithdraw(struct peer *peer, void *rfd, struct prefix *p,
+void rfapiProcessWithdraw(struct peer *peer, void *rfd, const struct prefix *p,
struct prefix_rd *prd, struct attr *attr, afi_t afi,
safi_t safi, uint8_t type, int kill)
{
@@ -4224,9 +4213,11 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp,
safi))(
it, /* which import table */
FIF_ACTION_UPDATE, bpi->peer,
- NULL, &rn2->p, /* prefix */
+ NULL, bgp_node_get_prefix(rn2),
NULL, afi,
- (struct prefix_rd *)&rn1->p,
+ (struct prefix_rd *)
+ bgp_node_get_prefix(
+ rn1),
bpi->attr, bpi->type,
bpi->sub_type, &label);
}
@@ -4444,27 +4435,20 @@ static void rfapiDeleteRemotePrefixesIt(
for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
struct bgp_path_info *bpi;
struct bgp_path_info *next;
+ const struct prefix *rn_p = agg_node_get_prefix(rn);
if (p && VNC_DEBUG(IMPORT_DEL_REMOTE)) {
char p1line[PREFIX_STRLEN];
- char p2line[PREFIX_STRLEN];
prefix2str(p, p1line, sizeof(p1line));
- prefix2str(&rn->p, p2line, sizeof(p2line));
- vnc_zlog_debug_any("%s: want %s, have %s",
- __func__, p1line, p2line);
+ vnc_zlog_debug_any("%s: want %s, have %pRN",
+ __func__, p1line, rn);
}
- if (p && prefix_cmp(p, &rn->p))
+ if (p && prefix_cmp(p, rn_p))
continue;
- {
- char buf_pfx[PREFIX_STRLEN];
-
- prefix2str(&rn->p, buf_pfx, sizeof(buf_pfx));
- vnc_zlog_debug_verbose("%s: rn pfx=%s",
- __func__, buf_pfx);
- }
+ vnc_zlog_debug_verbose("%s: rn pfx=%pRN", __func__, rn);
/* TBD is this valid for afi == AFI_L2VPN? */
RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1);
@@ -4596,7 +4580,7 @@ static void rfapiDeleteRemotePrefixesIt(
}
}
- vnc_direct_bgp_rh_del_route(bgp, afi, &rn->p,
+ vnc_direct_bgp_rh_del_route(bgp, afi, rn_p,
bpi->peer);
RFAPI_UPDATE_ITABLE_COUNT(bpi, it, afi, -1);
diff --git a/bgpd/rfapi/rfapi_import.h b/bgpd/rfapi/rfapi_import.h
index 1ab9cc5193..50093111c2 100644
--- a/bgpd/rfapi/rfapi_import.h
+++ b/bgpd/rfapi/rfapi_import.h
@@ -143,11 +143,11 @@ extern void rfapiUnicastNexthop2Prefix(afi_t afi, struct attr *attr,
extern void rfapiBgpInfoFilteredImportVPN(
struct rfapi_import_table *import_table, int action, struct peer *peer,
void *rfd, /* set for looped back routes */
- struct prefix *p,
- struct prefix *aux_prefix, /* AFI_ETHER: optional IP */
+ const struct prefix *p,
+ const struct prefix *aux_prefix, /* AFI_ETHER: optional IP */
afi_t afi, struct prefix_rd *prd,
struct attr *attr, /* part of bgp_path_info */
- uint8_t type, /* part of bgp_path_info */
+ uint8_t type, /* part of bgp_path_info */
uint8_t sub_type, /* part of bgp_path_info */
uint32_t *label); /* part of bgp_path_info */
diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c
index dc1f7e0fbb..0b8dfc3554 100644
--- a/bgpd/rfapi/rfapi_monitor.c
+++ b/bgpd/rfapi/rfapi_monitor.c
@@ -789,7 +789,8 @@ static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn *m)
* been responsible for the response, i.e., any monitors for
* the exact prefix or a parent of it.
*/
-void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd, struct prefix *p)
+void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd,
+ const struct prefix *p)
{
struct agg_node *rn;
@@ -818,12 +819,14 @@ void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd, struct prefix *p)
for (rn = agg_route_top(rfd->mon); rn;
rn = agg_route_next(rn)) {
struct rfapi_monitor_vpn *m;
+ const struct prefix *p_node;
if (!((m = rn->info)))
continue;
+ p_node = agg_node_get_prefix(m->node);
/* NB order of test is significant ! */
- if (!m->node || prefix_match(&m->node->p, p)) {
+ if (!m->node || prefix_match(p_node, p)) {
rfapiMonitorTimerRestart(m);
}
}
@@ -841,7 +844,8 @@ void rfapiMonitorItNodeChanged(
struct skiplist *nves_seen;
struct agg_node *rn = it_node;
struct bgp *bgp = bgp_get_default();
- afi_t afi = family2afi(rn->p.family);
+ const struct prefix *p = agg_node_get_prefix(rn);
+ afi_t afi = family2afi(p->family);
#if DEBUG_L2_EXTRA
char buf_prefix[PREFIX_STRLEN];
#endif
@@ -931,17 +935,14 @@ void rfapiMonitorItNodeChanged(
assert(!skiplist_insert(nves_seen,
m->rfd, NULL));
- char buf_attach_pfx[PREFIX_STRLEN];
char buf_target_pfx[PREFIX_STRLEN];
- prefix2str(&m->node->p, buf_attach_pfx,
- sizeof(buf_attach_pfx));
prefix2str(&m->p, buf_target_pfx,
sizeof(buf_target_pfx));
vnc_zlog_debug_verbose(
- "%s: update rfd %p attached to pfx %s (targ=%s)",
- __func__, m->rfd,
- buf_attach_pfx, buf_target_pfx);
+ "%s: update rfd %p attached to pfx %pRN (targ=%s)",
+ __func__, m->rfd, m->node,
+ buf_target_pfx);
/*
* update its RIB
@@ -1103,10 +1104,10 @@ static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth *m)
m->rfd->response_lifetime, &m->timer);
}
-static int mon_eth_cmp(void *a, void *b)
+static int mon_eth_cmp(const void *a, const void *b)
{
- struct rfapi_monitor_eth *m1;
- struct rfapi_monitor_eth *m2;
+ const struct rfapi_monitor_eth *m1;
+ const struct rfapi_monitor_eth *m2;
int i;
@@ -1272,7 +1273,7 @@ static void rfapiMonitorEthDetachImport(
#if DEBUG_L2_EXTRA
char buf_prefix[PREFIX_STRLEN];
- prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
+ prefix2str(agg_node_get_prefix(rn), buf_prefix, sizeof(buf_prefix));
#endif
/*
diff --git a/bgpd/rfapi/rfapi_monitor.h b/bgpd/rfapi/rfapi_monitor.h
index b8eec56475..3a2248aa60 100644
--- a/bgpd/rfapi/rfapi_monitor.h
+++ b/bgpd/rfapi/rfapi_monitor.h
@@ -167,7 +167,7 @@ extern void rfapiMonitorResponseRemovalOn(struct bgp *bgp);
extern void rfapiMonitorExtraPrune(safi_t safi, struct agg_node *rn);
extern void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd,
- struct prefix *p);
+ const struct prefix *p);
extern void rfapiMonitorItNodeChanged(struct rfapi_import_table *import_table,
struct agg_node *it_node,
diff --git a/bgpd/rfapi/rfapi_nve_addr.c b/bgpd/rfapi/rfapi_nve_addr.c
index ee54d88c3f..b8193f1431 100644
--- a/bgpd/rfapi/rfapi_nve_addr.c
+++ b/bgpd/rfapi/rfapi_nve_addr.c
@@ -58,10 +58,10 @@ static void logdifferent(const char *tag, struct rfapi_nve_addr *a,
#endif
-int rfapi_nve_addr_cmp(void *k1, void *k2)
+int rfapi_nve_addr_cmp(const void *k1, const void *k2)
{
- struct rfapi_nve_addr *a = (struct rfapi_nve_addr *)k1;
- struct rfapi_nve_addr *b = (struct rfapi_nve_addr *)k2;
+ const struct rfapi_nve_addr *a = (struct rfapi_nve_addr *)k1;
+ const struct rfapi_nve_addr *b = (struct rfapi_nve_addr *)k2;
int ret = 0;
if (!a || !b) {
diff --git a/bgpd/rfapi/rfapi_nve_addr.h b/bgpd/rfapi/rfapi_nve_addr.h
index 2d54d4a3cc..7bcb3cab69 100644
--- a/bgpd/rfapi/rfapi_nve_addr.h
+++ b/bgpd/rfapi/rfapi_nve_addr.h
@@ -30,7 +30,7 @@ struct rfapi_nve_addr {
};
-extern int rfapi_nve_addr_cmp(void *k1, void *k2);
+extern int rfapi_nve_addr_cmp(const void *k1, const void *k2);
extern void rfapiNveAddr2Str(struct rfapi_nve_addr *na, char *buf, int bufsize);
diff --git a/bgpd/rfapi/rfapi_private.h b/bgpd/rfapi/rfapi_private.h
index ff1cf7ef42..68caba600a 100644
--- a/bgpd/rfapi/rfapi_private.h
+++ b/bgpd/rfapi/rfapi_private.h
@@ -272,16 +272,13 @@ struct rfapi {
? ((prefix)->prefixlen == 128) \
: 0))
-extern void rfapiQprefix2Rprefix(struct prefix *qprefix,
- struct rfapi_ip_prefix *rprefix);
-
extern int rfapi_find_rfd(struct bgp *bgp, struct rfapi_ip_addr *vn_addr,
struct rfapi_ip_addr *un_addr,
struct rfapi_descriptor **rfd);
extern void
add_vnc_route(struct rfapi_descriptor *rfd, /* cookie + UN addr for VPN */
- struct bgp *bgp, int safi, struct prefix *p,
+ struct bgp *bgp, int safi, const struct prefix *p,
struct prefix_rd *prd, struct rfapi_ip_addr *nexthop,
uint32_t *local_pref, /* host byte order */
uint32_t *lifetime, /* host byte order */
@@ -297,7 +294,7 @@ add_vnc_route(struct rfapi_descriptor *rfd, /* cookie + UN addr for VPN */
#endif
extern void del_vnc_route(struct rfapi_descriptor *rfd, struct peer *peer,
- struct bgp *bgp, safi_t safi, struct prefix *p,
+ struct bgp *bgp, safi_t safi, const struct prefix *p,
struct prefix_rd *prd, uint8_t type, uint8_t sub_type,
struct rfapi_nexthop *lnh, int kill);
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index 3d4bdef75a..04a538dc63 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -340,7 +340,6 @@ static void rfapiRibStartTimer(struct rfapi_descriptor *rfd,
{
struct thread *t = ri->timer;
struct rfapi_rib_tcb *tcb = NULL;
- char buf_prefix[PREFIX_STRLEN];
if (t) {
tcb = t->arg;
@@ -361,9 +360,8 @@ static void rfapiRibStartTimer(struct rfapi_descriptor *rfd,
UNSET_FLAG(tcb->flags, RFAPI_RIB_TCB_FLAG_DELETED);
}
- prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
- vnc_zlog_debug_verbose("%s: rfd %p pfx %s life %u", __func__, rfd,
- buf_prefix, ri->lifetime);
+ vnc_zlog_debug_verbose("%s: rfd %p pfx %pRN life %u", __func__, rfd, rn,
+ ri->lifetime);
ri->timer = NULL;
thread_add_timer(bm->master, rfapiRibExpireTimer, tcb, ri->lifetime,
&ri->timer);
@@ -388,10 +386,10 @@ extern void rfapi_rib_key_init(struct prefix *prefix, /* may be NULL */
/*
* Compares two <struct rfapi_rib_key>s
*/
-int rfapi_rib_key_cmp(void *k1, void *k2)
+int rfapi_rib_key_cmp(const void *k1, const void *k2)
{
- struct rfapi_rib_key *a = (struct rfapi_rib_key *)k1;
- struct rfapi_rib_key *b = (struct rfapi_rib_key *)k2;
+ const struct rfapi_rib_key *a = (struct rfapi_rib_key *)k1;
+ const struct rfapi_rib_key *b = (struct rfapi_rib_key *)k2;
int ret;
if (!a || !b)
@@ -741,11 +739,12 @@ int rfapiRibPreloadBi(
struct rfapi_rib_key rk;
struct agg_node *trn;
afi_t afi;
+ const struct prefix *p = agg_node_get_prefix(rfd_rib_node);
if (!rfd_rib_node)
return 0;
- afi = family2afi(rfd_rib_node->p.family);
+ afi = family2afi(p->family);
rfd = agg_get_table_info(agg_get_table(rfd_rib_node));
@@ -803,8 +802,7 @@ int rfapiRibPreloadBi(
/*
* Update last sent time for prefix
*/
- trn = agg_node_get(rfd->rsp_times[afi],
- &rfd_rib_node->p); /* locks trn */
+ trn = agg_node_get(rfd->rsp_times[afi], p); /* locks trn */
trn->info = (void *)(uintptr_t)bgp_clock();
if (trn->lock > 1)
agg_unlock_node(trn);
@@ -852,10 +850,9 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
struct list *lPendCost = NULL;
struct list *delete_list = NULL;
int printedprefix = 0;
- char buf_prefix[PREFIX_STRLEN];
int rib_node_started_nonempty = 0;
int sendingsomeroutes = 0;
-
+ const struct prefix *p;
#if DEBUG_PROCESS_PENDING_NODE
unsigned int count_rib_initial = 0;
unsigned int count_pend_vn_initial = 0;
@@ -863,12 +860,12 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
#endif
assert(pn);
- prefix2str(&pn->p, buf_prefix, sizeof(buf_prefix));
- vnc_zlog_debug_verbose("%s: afi=%d, %s pn->info=%p", __func__, afi,
- buf_prefix, pn->info);
+ p = agg_node_get_prefix(pn);
+ vnc_zlog_debug_verbose("%s: afi=%d, %pRN pn->info=%p", __func__, afi,
+ pn, pn->info);
if (AFI_L2VPN != afi) {
- rfapiQprefix2Rprefix(&pn->p, &hp);
+ rfapiQprefix2Rprefix(p, &hp);
}
RFAPI_RIB_CHECK_COUNTS(1, 0);
@@ -876,7 +873,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
/*
* Find corresponding RIB node
*/
- rn = agg_node_get(rfd->rib[afi], &pn->p); /* locks rn */
+ rn = agg_node_get(rfd->rib[afi], p); /* locks rn */
/*
* RIB skiplist has key=rfapi_addr={vn,un}, val = rfapi_info,
@@ -935,9 +932,9 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
prefix2str(&ri->rk.vn, buf, sizeof(buf));
prefix2str(&ri->un, buf2, sizeof(buf2));
vnc_zlog_debug_verbose(
- "%s: put dl pfx=%s vn=%s un=%s cost=%d life=%d vn_options=%p",
- __func__, buf_prefix, buf, buf2,
- ri->cost, ri->lifetime, ri->vn_options);
+ "%s: put dl pfx=%pRN vn=%s un=%s cost=%d life=%d vn_options=%p",
+ __func__, pn, buf, buf2, ri->cost,
+ ri->lifetime, ri->vn_options);
skiplist_delete_first(slRibPt);
}
@@ -1186,8 +1183,7 @@ callback:
vnc_zlog_debug_verbose("%s: lPendCost->count now %d", __func__,
lPendCost->count);
- vnc_zlog_debug_verbose("%s: For prefix %s (a)", __func__,
- buf_prefix);
+ vnc_zlog_debug_verbose("%s: For prefix %pRN (a)", __func__, pn);
printedprefix = 1;
for (ALL_LIST_ELEMENTS(lPendCost, node, nnode, ri)) {
@@ -1246,7 +1242,7 @@ callback:
* update this NVE's timestamp for this prefix
*/
trn = agg_node_get(rfd->rsp_times[afi],
- &pn->p); /* locks trn */
+ p); /* locks trn */
trn->info = (void *)(uintptr_t)bgp_clock();
if (trn->lock > 1)
agg_unlock_node(trn);
@@ -1268,8 +1264,8 @@ callback:
char buf2[BUFSIZ];
if (!printedprefix) {
- vnc_zlog_debug_verbose("%s: For prefix %s (d)",
- __func__, buf_prefix);
+ vnc_zlog_debug_verbose("%s: For prefix %pRN (d)",
+ __func__, pn);
}
vnc_zlog_debug_verbose("%s: delete_list has %d elements",
__func__, delete_list->count);
@@ -1465,7 +1461,7 @@ callback:
}
if (sendingsomeroutes)
- rfapiMonitorTimersRestart(rfd, &pn->p);
+ rfapiMonitorTimersRestart(rfd, p);
agg_unlock_node(rn); /* agg_node_get() */
@@ -1589,7 +1585,7 @@ void rfapiRibUpdatePendingNode(
struct rfapi_import_table *it, /* needed for L2 */
struct agg_node *it_node, uint32_t lifetime)
{
- struct prefix *prefix;
+ const struct prefix *prefix;
struct bgp_path_info *bpi;
struct agg_node *pn;
afi_t afi;
@@ -1606,7 +1602,7 @@ void rfapiRibUpdatePendingNode(
RFAPI_RIB_CHECK_COUNTS(1, 0);
- prefix = &it_node->p;
+ prefix = agg_node_get_prefix(it_node);
afi = family2afi(prefix->family);
prefix2str(prefix, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s: prefix=%s", __func__, buf);
@@ -1794,7 +1790,8 @@ int rfapiRibFTDFilterRecentPrefix(
struct prefix *pfx_target_original) /* query target */
{
struct bgp *bgp = rfd->bgp;
- afi_t afi = family2afi(it_rn->p.family);
+ const struct prefix *p = agg_node_get_prefix(it_rn);
+ afi_t afi = family2afi(p->family);
time_t prefix_time;
struct agg_node *trn;
@@ -1809,14 +1806,15 @@ int rfapiRibFTDFilterRecentPrefix(
* This matches behavior of now-obsolete rfapiRibFTDFilterRecent(),
* but we need to decide if that is correct.
*/
- if (it_rn->p.family == AF_ETHERNET)
+ if (p->family == AF_ETHERNET)
return 0;
#ifdef DEBUG_FTD_FILTER_RECENT
{
char buf_pfx[PREFIX_STRLEN];
- prefix2str(&it_rn->p, buf_pfx, sizeof(buf_pfx));
+ prefix2str(agg_node_get_prefix(it_rn), buf_pfx,
+ sizeof(buf_pfx));
vnc_zlog_debug_verbose("%s: prefix %s", __func__, buf_pfx);
}
#endif
@@ -1824,7 +1822,7 @@ int rfapiRibFTDFilterRecentPrefix(
/*
* prefix covers target address, so allow prefix
*/
- if (prefix_match(&it_rn->p, pfx_target_original)) {
+ if (prefix_match(p, pfx_target_original)) {
#ifdef DEBUG_FTD_FILTER_RECENT
vnc_zlog_debug_verbose("%s: prefix covers target, allowed",
__func__);
@@ -1835,7 +1833,7 @@ int rfapiRibFTDFilterRecentPrefix(
/*
* check this NVE's timestamp for this prefix
*/
- trn = agg_node_get(rfd->rsp_times[afi], &it_rn->p); /* locks trn */
+ trn = agg_node_get(rfd->rsp_times[afi], p); /* locks trn */
prefix_time = (time_t)trn->info;
if (trn->lock > 1)
agg_unlock_node(trn);
@@ -1997,7 +1995,8 @@ rfapiRibPreload(struct bgp *bgp, struct rfapi_descriptor *rfd,
}
vnc_zlog_debug_verbose(
"%s: RIB skiplist for this prefix follows", __func__);
- rfapiRibShowRibSl(NULL, &rn->p, (struct skiplist *)rn->info);
+ rfapiRibShowRibSl(NULL, agg_node_get_prefix(rn),
+ (struct skiplist *)rn->info);
#endif
@@ -2114,11 +2113,10 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it,
{
struct rfapi_descriptor *rfd;
struct listnode *node;
- char buf[PREFIX_STRLEN];
+ const struct prefix *p = agg_node_get_prefix(it_node);
- prefix2str(&it_node->p, buf, sizeof(buf));
- vnc_zlog_debug_verbose("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%s",
- __func__, it, afi, it_node, buf);
+ vnc_zlog_debug_verbose("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%pRN",
+ __func__, it, afi, it_node, it_node);
if (AFI_L2VPN == afi) {
/*
@@ -2157,7 +2155,7 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it,
* delete
*/
if ((rn = agg_node_lookup(m->rfd->rib[afi],
- &it_node->p))) {
+ p))) {
rfapiRibUpdatePendingNode(
bgp, m->rfd, it, it_node,
m->rfd->response_lifetime);
@@ -2179,8 +2177,7 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it,
* this
* NVE, it's OK to send an update with the delete
*/
- if ((rn = agg_node_lookup(m->rfd->rib[afi],
- &it_node->p))) {
+ if ((rn = agg_node_lookup(m->rfd->rib[afi], p))) {
rfapiRibUpdatePendingNode(
bgp, m->rfd, it, it_node,
m->rfd->response_lifetime);
@@ -2212,8 +2209,7 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it,
* prefix
* previously, we should send an updated response.
*/
- if ((rn = agg_node_lookup(rfd->rib[afi],
- &it_node->p))) {
+ if ((rn = agg_node_lookup(rfd->rib[afi], p))) {
rfapiRibUpdatePendingNode(
bgp, rfd, it, it_node,
rfd->response_lifetime);
@@ -2416,7 +2412,8 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match,
for (rn = agg_route_top(rfd->rib[afi]); rn;
rn = agg_route_next(rn)) {
-
+ const struct prefix *p =
+ agg_node_get_prefix(rn);
struct skiplist *sl;
char str_pfx[PREFIX_STRLEN];
int printedprefix = 0;
@@ -2433,9 +2430,8 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match,
nhs_total += skiplist_count(sl);
++prefixes_total;
- if (pfx_match
- && !prefix_match(pfx_match, &rn->p)
- && !prefix_match(&rn->p, pfx_match))
+ if (pfx_match && !prefix_match(pfx_match, p)
+ && !prefix_match(p, pfx_match))
continue;
++prefixes_displayed;
@@ -2472,7 +2468,7 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match,
str_un,
BUFSIZ));
}
- prefix2str(&rn->p, str_pfx, sizeof(str_pfx));
+ prefix2str(p, str_pfx, sizeof(str_pfx));
// fp(out, " %s\n", buf); /* prefix */
routes_displayed++;
diff --git a/bgpd/rfapi/rfapi_rib.h b/bgpd/rfapi/rfapi_rib.h
index 38a6df9fbf..3ad021b4f4 100644
--- a/bgpd/rfapi/rfapi_rib.h
+++ b/bgpd/rfapi/rfapi_rib.h
@@ -147,7 +147,7 @@ extern void rfapi_rib_key_init(struct prefix *prefix, /* may be NULL */
struct prefix *aux, /* may be NULL */
struct rfapi_rib_key *rk);
-extern int rfapi_rib_key_cmp(void *k1, void *k2);
+extern int rfapi_rib_key_cmp(const void *k1, const void *k2);
extern void rfapiAdbFree(struct rfapi_adb *adb);
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 58fdc7c130..5a84d14bd9 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -194,7 +194,7 @@ int rfapiQprefix2Raddr(struct prefix *qprefix, struct rfapi_ip_addr *raddr)
* Translate Quagga prefix to RFAPI prefix
*/
/* rprefix->cost set to 0 */
-void rfapiQprefix2Rprefix(struct prefix *qprefix,
+void rfapiQprefix2Rprefix(const struct prefix *qprefix,
struct rfapi_ip_prefix *rprefix)
{
memset(rprefix, 0, sizeof(struct rfapi_ip_prefix));
@@ -393,7 +393,7 @@ int rfapiStream2Vty(void *stream, /* input */
}
/* called from bgpd/bgp_vty.c'route_vty_out() */
-void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p,
+void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
struct bgp_path_info *bpi, safi_t safi)
{
char *s;
@@ -743,7 +743,6 @@ static void rfapiDebugPrintMonitorEncap(void *stream,
void rfapiShowItNode(void *stream, struct agg_node *rn)
{
struct bgp_path_info *bpi;
- char buf[BUFSIZ];
int (*fp)(void *, const char *, ...);
struct vty *vty;
@@ -753,9 +752,7 @@ void rfapiShowItNode(void *stream, struct agg_node *rn)
if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0)
return;
- fp(out, "%s/%d @%p #%d%s",
- rfapi_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
- rn->p.prefixlen, rn, rn->lock, HVTYNL);
+ fp(out, "%pRN @%p #%d%s", rn, rn, rn->lock, HVTYNL);
for (bpi = rn->info; bpi; bpi = bpi->next) {
rfapiPrintBi(stream, bpi);
@@ -782,14 +779,15 @@ void rfapiShowImportTable(void *stream, const char *label, struct agg_table *rt,
for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
struct bgp_path_info *bpi;
+ const struct prefix *p = agg_node_get_prefix(rn);
- if (rn->p.family == AF_ETHERNET) {
- rfapiEthAddr2Str(&rn->p.u.prefix_eth, buf, BUFSIZ);
+ if (p->family == AF_ETHERNET) {
+ rfapiEthAddr2Str(&p->u.prefix_eth, buf, BUFSIZ);
} else {
- inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ);
+ inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ);
}
- fp(out, "%s/%d @%p #%d%s", buf, rn->p.prefixlen, rn,
+ fp(out, "%s/%d @%p #%d%s", buf, p->prefixlen, rn,
rn->lock - 1, /* account for loop iterator locking */
HVTYNL);
@@ -868,6 +866,8 @@ int rfapiShowVncQueries(void *stream, struct prefix *pfx_match)
if (rfd->mon) {
for (rn = agg_route_top(rfd->mon); rn;
rn = agg_route_next(rn)) {
+ const struct prefix *p =
+ agg_node_get_prefix(rn);
struct rfapi_monitor_vpn *m;
char buf_remain[BUFSIZ];
char buf_pfx[BUFSIZ];
@@ -879,9 +879,8 @@ int rfapiShowVncQueries(void *stream, struct prefix *pfx_match)
++queries_total;
- if (pfx_match
- && !prefix_match(pfx_match, &rn->p)
- && !prefix_match(&rn->p, pfx_match))
+ if (pfx_match && !prefix_match(pfx_match, p)
+ && !prefix_match(p, pfx_match))
continue;
++queries_displayed;
@@ -1028,6 +1027,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
char buf_vn[BUFSIZ];
char buf_lifetime[BUFSIZ];
int nlines = 0;
+ const struct prefix *p = agg_node_get_prefix(rn);
if (!stream)
return 0; /* for debug log, print into buf & call output once */
@@ -1040,8 +1040,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
*/
buf_pfx[0] = 0;
snprintf(buf_pfx, BUFSIZ, "%s/%d",
- rfapi_ntop(rn->p.family, &rn->p.u.prefix, buf_ntop, BUFSIZ),
- rn->p.prefixlen);
+ rfapi_ntop(p->family, &p->u.prefix, buf_ntop, BUFSIZ),
+ p->prefixlen);
buf_pfx[BUFSIZ - 1] = 0;
nlines++;
@@ -1155,7 +1155,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
}
fp(out, "%s", HVTYNL);
- if (rn->p.family == AF_ETHERNET) {
+ if (p->family == AF_ETHERNET) {
/*
* If there is a corresponding IP address && != VN address,
* print that on the next line
@@ -1221,13 +1221,13 @@ static int rfapiShowRemoteRegistrationsIt(struct bgp *bgp, void *stream,
for (rn = agg_route_top(it->imported_vpn[afi]); rn;
rn = agg_route_next(rn)) {
-
+ const struct prefix *p = agg_node_get_prefix(rn);
struct bgp_path_info *bpi;
int count_only;
/* allow for wider or more narrow mask from user */
- if (prefix_only && !prefix_match(prefix_only, &rn->p)
- && !prefix_match(&rn->p, prefix_only))
+ if (prefix_only && !prefix_match(prefix_only, p)
+ && !prefix_match(p, prefix_only))
count_only = 1;
else
count_only = 0;
@@ -2754,10 +2754,10 @@ static void nve_addr_free(void *hap)
XFREE(MTYPE_RFAPI_NVE_ADDR, hap);
}
-static int nve_addr_cmp(void *k1, void *k2)
+static int nve_addr_cmp(const void *k1, const void *k2)
{
- struct nve_addr *a = (struct nve_addr *)k1;
- struct nve_addr *b = (struct nve_addr *)k2;
+ const struct nve_addr *a = (struct nve_addr *)k1;
+ const struct nve_addr *b = (struct nve_addr *)k2;
int ret = 0;
if (!a || !b) {
diff --git a/bgpd/rfapi/rfapi_vty.h b/bgpd/rfapi/rfapi_vty.h
index 8b881292ac..b5e1c38b0d 100644
--- a/bgpd/rfapi/rfapi_vty.h
+++ b/bgpd/rfapi/rfapi_vty.h
@@ -43,7 +43,7 @@ extern void rfapiRprefixApplyMask(struct rfapi_ip_prefix *rprefix);
extern int rfapiQprefix2Raddr(struct prefix *qprefix,
struct rfapi_ip_addr *raddr);
-extern void rfapiQprefix2Rprefix(struct prefix *qprefix,
+extern void rfapiQprefix2Rprefix(const struct prefix *qprefix,
struct rfapi_ip_prefix *rprefix);
extern int rfapiRprefix2Qprefix(struct rfapi_ip_prefix *rprefix,
diff --git a/bgpd/rfapi/vnc_debug.h b/bgpd/rfapi/vnc_debug.h
index dd49383072..c472b6366e 100644
--- a/bgpd/rfapi/vnc_debug.h
+++ b/bgpd/rfapi/vnc_debug.h
@@ -20,7 +20,7 @@
#ifndef _QUAGGA_BGP_VNC_DEBUG_H
#define _QUAGGA_BGP_VNC_DEBUG_H
-#if ENABLE_BGP_VNC
+#ifdef ENABLE_BGP_VNC
/*
* debug state storage
diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c
index 3d34d696b5..a7aa4c66fa 100644
--- a/bgpd/rfapi/vnc_export_bgp.c
+++ b/bgpd/rfapi/vnc_export_bgp.c
@@ -177,7 +177,7 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct agg_node *rn,
{
struct attr *attr = bpi->attr;
struct peer *peer = bpi->peer;
- struct prefix *prefix = &rn->p;
+ const struct prefix *prefix = agg_node_get_prefix(rn);
afi_t afi = family2afi(prefix->family);
struct bgp_node *urn;
struct bgp_path_info *ubpi;
@@ -330,7 +330,8 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct agg_node *rn,
void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn,
struct bgp_path_info *bpi)
{
- afi_t afi = family2afi(rn->p.family);
+ const struct prefix *p = agg_node_get_prefix(rn);
+ afi_t afi = family2afi(p->family);
struct bgp_path_info *vbpi;
struct prefix ce_nexthop;
@@ -395,8 +396,8 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn,
/*
* withdraw the route
*/
- bgp_withdraw(bpi->peer, &rn->p, 0, /* addpath_id */
- NULL, /* attr, ignored */
+ bgp_withdraw(bpi->peer, p, 0, /* addpath_id */
+ NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, 0, NULL); /* tag not used for unicast */
@@ -432,17 +433,11 @@ static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi)
*/
for (rn = agg_route_top(bgp->rfapi->it_ce->imported_vpn[afi]); rn;
rn = agg_route_next(rn)) {
-
if (!rn->info)
continue;
- {
- char prefixstr[PREFIX_STRLEN];
-
- prefix2str(&rn->p, prefixstr, sizeof(prefixstr));
- vnc_zlog_debug_verbose("%s: checking prefix %s",
- __func__, prefixstr);
- }
+ vnc_zlog_debug_verbose("%s: checking prefix %pRN", __func__,
+ rn);
for (ri = rn->info; ri; ri = ri->next) {
@@ -492,9 +487,9 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi)
&& ri->sub_type == BGP_ROUTE_REDISTRIBUTE) {
bgp_withdraw(
- ri->peer, &rn->p, /* prefix */
- 0, /* addpath_id */
- NULL, /* ignored */
+ ri->peer, bgp_node_get_prefix(rn),
+ 0, /* addpath_id */
+ NULL, /* ignored */
AFI_IP, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
@@ -698,7 +693,8 @@ void vnc_direct_bgp_add_prefix(struct bgp *bgp,
struct attr attr = {0};
struct listnode *node, *nnode;
struct rfapi_rfg_name *rfgn;
- afi_t afi = family2afi(rn->p.family);
+ const struct prefix *p = agg_node_get_prefix(rn);
+ afi_t afi = family2afi(p->family);
if (!afi) {
flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of route node",
@@ -769,7 +765,7 @@ void vnc_direct_bgp_add_prefix(struct bgp *bgp,
*/
if (rfgn->rfg->plist_export_bgp[afi]) {
if (prefix_list_apply(rfgn->rfg->plist_export_bgp[afi],
- &rn->p)
+ p)
== PREFIX_DENY)
continue;
@@ -808,7 +804,8 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
{
struct listnode *node, *nnode;
struct rfapi_rfg_name *rfgn;
- afi_t afi = family2afi(rn->p.family);
+ const struct prefix *p = agg_node_get_prefix(rn);
+ afi_t afi = family2afi(p->family);
if (!afi) {
flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi route node",
@@ -877,9 +874,9 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
continue;
- bgp_withdraw(irfd->peer, &rn->p, /* prefix */
- 0, /* addpath_id */
- NULL, /* attr, ignored */
+ bgp_withdraw(irfd->peer, p, /* prefix */
+ 0, /* addpath_id */
+ NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */
@@ -907,9 +904,9 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp))
continue;
- bgp_withdraw(irfd->peer, &rn->p, /* prefix */
- 0, /* addpath_id */
- NULL, /* attr, ignored */
+ bgp_withdraw(irfd->peer, p, /* prefix */
+ 0, /* addpath_id */
+ NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */
@@ -998,6 +995,8 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
struct attr hattr;
struct attr *iattr;
struct bgp_path_info info;
+ const struct prefix *p =
+ agg_node_get_prefix(rn);
if (rfapiRaddr2Qprefix(&irfd->vn_addr,
&nhp))
@@ -1010,7 +1009,7 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
if (prefix_list_apply(
rfgn->rfg->plist_export_bgp
[afi],
- &rn->p)
+ p)
== PREFIX_DENY)
continue;
@@ -1033,8 +1032,7 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
ret = route_map_apply(
rfgn->rfg
->routemap_export_bgp,
- &rn->p, RMAP_BGP,
- &info);
+ p, RMAP_BGP, &info);
if (ret == RMAP_DENYMATCH) {
bgp_attr_flush(&hattr);
continue;
@@ -1044,8 +1042,8 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
iattr = bgp_attr_intern(&hattr);
bgp_attr_flush(&hattr);
bgp_update(
- irfd->peer, &rn->p, /* prefix */
- 0, /* addpath_id */
+ irfd->peer, p, /* prefix */
+ 0, /* addpath_id */
iattr, /* bgp_update copies
it */
afi, SAFI_UNICAST,
@@ -1134,7 +1132,8 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
rn = agg_route_next(rn)) {
if (rn->info) {
-
+ const struct prefix *p =
+ agg_node_get_prefix(rn);
struct prefix nhp;
struct rfapi_descriptor *irfd = rfd;
@@ -1142,10 +1141,9 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
&nhp))
continue;
- bgp_withdraw(irfd->peer,
- &rn->p, /* prefix */
- 0, /* addpath_id */
- NULL, /* attr, ignored */
+ bgp_withdraw(irfd->peer, p, /* prefix */
+ 0, /* addpath_id */
+ NULL, /* attr, ignored */
afi, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
@@ -1169,6 +1167,7 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
struct bgp_path_info info;
struct attr hattr;
struct attr *iattr;
+ const struct prefix *p = agg_node_get_prefix(rn);
if (irfd == NULL && rfg->type != RFAPI_GROUP_CFG_VRF) {
/* need new rfapi_handle, for peer strcture
@@ -1242,8 +1241,8 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
info.peer = irfd->peer;
info.attr = &hattr;
- ret = route_map_apply(rfg->routemap_export_bgp, &rn->p,
- RMAP_BGP, &info);
+ ret = route_map_apply(rfg->routemap_export_bgp, p, RMAP_BGP,
+ &info);
if (ret == RMAP_DENYMATCH) {
bgp_attr_flush(&hattr);
vnc_zlog_debug_verbose(
@@ -1261,9 +1260,9 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
iattr = bgp_attr_intern(&hattr);
bgp_attr_flush(&hattr);
- bgp_update(irfd->peer, &rn->p, /* prefix */
- 0, /* addpath_id */
- iattr, /* bgp_update copies it */
+ bgp_update(irfd->peer, p, /* prefix */
+ 0, /* addpath_id */
+ iattr, /* bgp_update copies it */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, /* tag not used for unicast */
@@ -1317,7 +1316,7 @@ static void vnc_direct_bgp_add_group_afi(struct bgp *bgp,
for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
if (rn->info) {
-
+ const struct prefix *p = agg_node_get_prefix(rn);
struct listnode *ln;
/*
@@ -1325,7 +1324,7 @@ static void vnc_direct_bgp_add_group_afi(struct bgp *bgp,
*/
if (rfg->plist_export_bgp[afi]) {
if (prefix_list_apply(
- rfg->plist_export_bgp[afi], &rn->p)
+ rfg->plist_export_bgp[afi], p)
== PREFIX_DENY)
continue;
@@ -1374,9 +1373,10 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
{
if (irfd == NULL)
return;
- bgp_withdraw(irfd->peer, &rn->p, /* prefix */
- 0, /* addpath_id */
- NULL, /* attr, ignored */
+
+ bgp_withdraw(irfd->peer, agg_node_get_prefix(rn), /* prefix */
+ 0, /* addpath_id */
+ NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, 0, NULL); /* tag not used for unicast */
@@ -1493,9 +1493,9 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt,
irfd)) {
bgp_withdraw(irfd->peer,
- &rn->p, /* prefix */
- 0, /* addpath_id */
- NULL, /* attr, ignored */
+ agg_node_get_prefix(rn),
+ 0, /* addpath_id */
+ NULL, /* attr, ignored */
afi, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
@@ -1633,7 +1633,7 @@ void vnc_direct_bgp_vpn_disable(struct bgp *bgp, afi_t afi)
* caller do it?
*/
void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
- struct prefix *prefix, struct peer *peer,
+ const struct prefix *prefix, struct peer *peer,
struct attr *attr)
{
struct vnc_export_info *eti;
@@ -1732,13 +1732,14 @@ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
static int vncExportWithdrawTimer(struct thread *t)
{
struct vnc_export_info *eti = t->arg;
+ const struct prefix *p = agg_node_get_prefix(eti->node);
/*
* withdraw the route
*/
- bgp_withdraw(eti->peer, &eti->node->p, 0, /* addpath_id */
- NULL, /* attr, ignored */
- family2afi(eti->node->p.family), SAFI_UNICAST, eti->type,
+ bgp_withdraw(eti->peer, p, 0, /* addpath_id */
+ NULL, /* attr, ignored */
+ family2afi(p->family), SAFI_UNICAST, eti->type,
eti->subtype, NULL, /* RD not used for unicast */
NULL, 0,
NULL); /* tag not used for unicast, EVPN neither */
@@ -1757,7 +1758,7 @@ static int vncExportWithdrawTimer(struct thread *t)
* caller do it?
*/
void vnc_direct_bgp_rh_del_route(struct bgp *bgp, afi_t afi,
- struct prefix *prefix, struct peer *peer)
+ const struct prefix *prefix, struct peer *peer)
{
struct vnc_export_info *eti;
@@ -1840,11 +1841,12 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
struct bgp_table *table;
struct bgp_node *rn;
struct bgp_path_info *ri;
+ const struct prefix *prn_p = bgp_node_get_prefix(prn);
memset(&prd, 0, sizeof(prd));
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
- memcpy(prd.val, prn->p.u.val, 8);
+ memcpy(prd.val, prn_p->u.val, 8);
/* This is the per-RD table of prefixes */
table = bgp_node_get_bgp_table_info(prn);
@@ -1853,6 +1855,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
continue;
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+ const struct prefix *rn_p;
/*
* skip prefix list check if no routes here
@@ -1860,21 +1863,17 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
if (!bgp_node_has_bgp_path_info_data(rn))
continue;
- {
- char prefixstr[PREFIX_STRLEN];
+ vnc_zlog_debug_verbose("%s: checking prefix %pRN",
+ __func__, rn);
- prefix2str(&rn->p, prefixstr,
- sizeof(prefixstr));
- vnc_zlog_debug_verbose("%s: checking prefix %s",
- __func__, prefixstr);
- }
+ rn_p = bgp_node_get_prefix(rn);
/*
* prefix list check
*/
if (hc->plist_export_bgp[afi]) {
if (prefix_list_apply(hc->plist_export_bgp[afi],
- &rn->p)
+ rn_p)
== PREFIX_DENY) {
vnc_zlog_debug_verbose(
@@ -1919,8 +1918,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
info.attr = &hattr;
ret = route_map_apply(
hc->routemap_export_bgp,
- &rn->p, RMAP_BGP,
- &info);
+ rn_p, RMAP_BGP, &info);
if (ret == RMAP_DENYMATCH) {
bgp_attr_flush(&hattr);
vnc_zlog_debug_verbose(
@@ -1939,7 +1937,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
* this route
*/
eti = vnc_eti_get(
- bgp, EXPORT_TYPE_BGP, &rn->p,
+ bgp, EXPORT_TYPE_BGP, rn_p,
ri->peer,
ZEBRA_ROUTE_VNC_DIRECT_RH,
BGP_ROUTE_REDISTRIBUTE);
@@ -1960,19 +1958,19 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
"%s: calling bgp_update",
__func__);
- bgp_update(
- ri->peer, &rn->p, /* prefix */
- 0, /* addpath_id */
- iattr, /* bgp_update copies
- it */
- AFI_IP, SAFI_UNICAST,
- ZEBRA_ROUTE_VNC_DIRECT_RH,
- BGP_ROUTE_REDISTRIBUTE, NULL,
- /* RD not used for unicast */
- NULL,
- /* tag not used for unicast,
- or EVPN */
- 0, 0, NULL); /* EVPN not used */
+ bgp_update(ri->peer, rn_p, /* prefix */
+ 0, /* addpath_id */
+ iattr, /* bgp_update copies
+ it */
+ AFI_IP, SAFI_UNICAST,
+ ZEBRA_ROUTE_VNC_DIRECT_RH,
+ BGP_ROUTE_REDISTRIBUTE, NULL,
+ /* RD not used for unicast */
+ NULL,
+ /* tag not used for unicast,
+ or EVPN */
+ 0, 0,
+ NULL); /* EVPN not used */
bgp_attr_unintern(&iattr);
}
@@ -2001,7 +1999,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
*/
for (rn = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); rn;
rn = bgp_route_next(rn)) {
-
+ const struct prefix *rn_p = bgp_node_get_prefix(rn);
struct bgp_path_info *ri;
struct bgp_path_info *next;
@@ -2018,7 +2016,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
* Delete routes immediately (no timer)
*/
eti = vnc_eti_checktimer(
- bgp, EXPORT_TYPE_BGP, &rn->p, ri->peer,
+ bgp, EXPORT_TYPE_BGP, rn_p, ri->peer,
ZEBRA_ROUTE_VNC_DIRECT_RH,
BGP_ROUTE_REDISTRIBUTE);
if (eti) {
@@ -2027,8 +2025,8 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
vnc_eti_delete(eti);
}
- bgp_withdraw(ri->peer, &rn->p, /* prefix */
- 0, /* addpath_id */
+ bgp_withdraw(ri->peer, rn_p, /* prefix */
+ 0, /* addpath_id */
NULL, /* ignored */
AFI_IP, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT_RH,
diff --git a/bgpd/rfapi/vnc_export_bgp_p.h b/bgpd/rfapi/vnc_export_bgp_p.h
index a1cb972740..bf292abb0a 100644
--- a/bgpd/rfapi/vnc_export_bgp_p.h
+++ b/bgpd/rfapi/vnc_export_bgp_p.h
@@ -61,12 +61,12 @@ extern void vnc_direct_bgp_reexport_group_afi(struct bgp *bgp,
extern void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
- struct prefix *prefix,
+ const struct prefix *prefix,
struct peer *peer, struct attr *attr);
extern void vnc_direct_bgp_rh_del_route(struct bgp *bgp, afi_t afi,
- struct prefix *prefix,
+ const struct prefix *prefix,
struct peer *peer);
extern void vnc_direct_bgp_reexport(struct bgp *bgp, afi_t afi);
diff --git a/bgpd/rfapi/vnc_export_table.c b/bgpd/rfapi/vnc_export_table.c
index 5e00a1017b..255f868bdf 100644
--- a/bgpd/rfapi/vnc_export_table.c
+++ b/bgpd/rfapi/vnc_export_table.c
@@ -34,7 +34,7 @@
#include "bgpd/rfapi/vnc_debug.h"
struct agg_node *vnc_etn_get(struct bgp *bgp, vnc_export_type_t type,
- struct prefix *p)
+ const struct prefix *p)
{
struct agg_table *t = NULL;
struct agg_node *rn = NULL;
@@ -66,7 +66,7 @@ struct agg_node *vnc_etn_get(struct bgp *bgp, vnc_export_type_t type,
}
struct agg_node *vnc_etn_lookup(struct bgp *bgp, vnc_export_type_t type,
- struct prefix *p)
+ const struct prefix *p)
{
struct agg_table *t = NULL;
struct agg_node *rn = NULL;
@@ -98,7 +98,7 @@ struct agg_node *vnc_etn_lookup(struct bgp *bgp, vnc_export_type_t type,
}
struct vnc_export_info *vnc_eti_get(struct bgp *bgp, vnc_export_type_t etype,
- struct prefix *p, struct peer *peer,
+ const struct prefix *p, struct peer *peer,
uint8_t type, uint8_t subtype)
{
struct agg_node *etn;
@@ -165,8 +165,9 @@ void vnc_eti_delete(struct vnc_export_info *goner)
struct vnc_export_info *vnc_eti_checktimer(struct bgp *bgp,
vnc_export_type_t etype,
- struct prefix *p, struct peer *peer,
- uint8_t type, uint8_t subtype)
+ const struct prefix *p,
+ struct peer *peer, uint8_t type,
+ uint8_t subtype)
{
struct agg_node *etn;
struct vnc_export_info *eti;
diff --git a/bgpd/rfapi/vnc_export_table.h b/bgpd/rfapi/vnc_export_table.h
index fdb35e81e1..8a1fc9aaef 100644
--- a/bgpd/rfapi/vnc_export_table.h
+++ b/bgpd/rfapi/vnc_export_table.h
@@ -46,21 +46,21 @@ struct vnc_export_info {
};
extern struct agg_node *vnc_etn_get(struct bgp *bgp, vnc_export_type_t type,
- struct prefix *p);
+ const struct prefix *p);
extern struct agg_node *vnc_etn_lookup(struct bgp *bgp, vnc_export_type_t type,
- struct prefix *p);
+ const struct prefix *p);
-extern struct vnc_export_info *vnc_eti_get(struct bgp *bgp,
- vnc_export_type_t etype,
- struct prefix *p, struct peer *peer,
- uint8_t type, uint8_t subtype);
+extern struct vnc_export_info *
+vnc_eti_get(struct bgp *bgp, vnc_export_type_t etype, const struct prefix *p,
+ struct peer *peer, uint8_t type, uint8_t subtype);
extern void vnc_eti_delete(struct vnc_export_info *goner);
extern struct vnc_export_info *
-vnc_eti_checktimer(struct bgp *bgp, vnc_export_type_t etype, struct prefix *p,
- struct peer *peer, uint8_t type, uint8_t subtype);
+vnc_eti_checktimer(struct bgp *bgp, vnc_export_type_t etype,
+ const struct prefix *p, struct peer *peer, uint8_t type,
+ uint8_t subtype);
#endif /* _QUAGGA_VNC_VNC_EXPORT_TABLE_H_ */
diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c
index ba6ef14257..915dfaabf2 100644
--- a/bgpd/rfapi/vnc_import_bgp.c
+++ b/bgpd/rfapi/vnc_import_bgp.c
@@ -104,7 +104,7 @@ uint32_t calc_local_pref(struct attr *attr, struct peer *peer)
return local_pref;
}
-static int is_host_prefix(struct prefix *p)
+static int is_host_prefix(const struct prefix *p)
{
switch (p->family) {
case AF_INET:
@@ -128,14 +128,14 @@ struct prefix_bag {
static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
0xf8, 0xfc, 0xfe, 0xff};
-int vnc_prefix_cmp(void *pfx1, void *pfx2)
+int vnc_prefix_cmp(const void *pfx1, const void *pfx2)
{
int offset;
int shift;
uint8_t mask;
- struct prefix *p1 = pfx1;
- struct prefix *p2 = pfx2;
+ const struct prefix *p1 = pfx1;
+ const struct prefix *p2 = pfx2;
if (p1->family < p2->family)
return -1;
@@ -299,9 +299,9 @@ static void vnc_rhnck(char *tag)
*/
static int process_unicast_route(struct bgp *bgp, /* in */
afi_t afi, /* in */
- struct prefix *prefix, /* in */
- struct bgp_path_info *info, /* in */
- struct ecommunity **ecom, /* OUT */
+ const struct prefix *prefix, /* in */
+ struct bgp_path_info *info, /* in */
+ struct ecommunity **ecom, /* OUT */
struct prefix *unicast_nexthop) /* OUT */
{
struct rfapi_cfg *hc = bgp->rfapi_cfg;
@@ -425,10 +425,10 @@ static int process_unicast_route(struct bgp *bgp, /* in */
static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi(
struct bgp *bgp, afi_t afi, struct bgp_path_info *bpi, /* VPN bpi */
struct prefix_rd *prd, /* RD */
- struct prefix *prefix, /* unicast route prefix */
- uint32_t *local_pref, /* NULL = no local_pref */
- uint32_t *med, /* NULL = no med */
- struct ecommunity *ecom) /* generated ecoms */
+ const struct prefix *prefix, /* unicast route prefix */
+ uint32_t *local_pref, /* NULL = no local_pref */
+ uint32_t *med, /* NULL = no med */
+ struct ecommunity *ecom) /* generated ecoms */
{
struct prefix un;
struct prefix nexthop;
@@ -509,11 +509,12 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi(
}
static void vnc_import_bgp_add_route_mode_resolve_nve_one_rd(
- struct prefix_rd *prd, /* RD */
+ struct prefix_rd *prd, /* RD */
struct bgp_table *table_rd, /* per-rd VPN route table */
- afi_t afi, struct bgp *bgp, struct prefix *prefix, /* unicast prefix */
- struct ecommunity *ecom, /* generated ecoms */
- uint32_t *local_pref, /* NULL = no local_pref */
+ afi_t afi, struct bgp *bgp,
+ const struct prefix *prefix, /* unicast prefix */
+ struct ecommunity *ecom, /* generated ecoms */
+ uint32_t *local_pref, /* NULL = no local_pref */
uint32_t *med, /* NULL = no med */
struct prefix *ubpi_nexthop) /* unicast nexthop */
{
@@ -552,8 +553,8 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_rd(
}
static void vnc_import_bgp_add_route_mode_resolve_nve(
- struct bgp *bgp, struct prefix *prefix, /* unicast prefix */
- struct bgp_path_info *info) /* unicast info */
+ struct bgp *bgp, const struct prefix *prefix, /* unicast prefix */
+ struct bgp_path_info *info) /* unicast info */
{
afi_t afi = family2afi(prefix->family);
@@ -673,8 +674,9 @@ static void vnc_import_bgp_add_route_mode_resolve_nve(
continue;
vnc_import_bgp_add_route_mode_resolve_nve_one_rd(
- (struct prefix_rd *)&bnp->p, table, afi, bgp, prefix,
- ecom, &local_pref, med, &pfx_unicast_nexthop);
+ (struct prefix_rd *)bgp_node_get_prefix(bnp), table,
+ afi, bgp, prefix, ecom, &local_pref, med,
+ &pfx_unicast_nexthop);
}
@@ -686,7 +688,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve(
static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp,
- struct prefix *prefix,
+ const struct prefix *prefix,
struct bgp_path_info *info)
{
afi_t afi = family2afi(prefix->family);
@@ -874,10 +876,9 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp,
ecommunity_free(&ecom);
}
-static void
-vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix,
- struct bgp_path_info *info,
- struct rfapi_nve_group_cfg *rfg)
+static void vnc_import_bgp_add_route_mode_nvegroup(
+ struct bgp *bgp, const struct prefix *prefix,
+ struct bgp_path_info *info, struct rfapi_nve_group_cfg *rfg)
{
afi_t afi = family2afi(prefix->family);
struct peer *peer = info->peer;
@@ -1080,7 +1081,7 @@ vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix,
}
static void vnc_import_bgp_del_route_mode_plain(struct bgp *bgp,
- struct prefix *prefix,
+ const struct prefix *prefix,
struct bgp_path_info *info)
{
struct prefix_rd prd;
@@ -1153,7 +1154,7 @@ static void vnc_import_bgp_del_route_mode_plain(struct bgp *bgp,
}
static void vnc_import_bgp_del_route_mode_nvegroup(struct bgp *bgp,
- struct prefix *prefix,
+ const struct prefix *prefix,
struct bgp_path_info *info)
{
struct prefix_rd prd;
@@ -1236,7 +1237,7 @@ static void vnc_import_bgp_del_route_mode_nvegroup(struct bgp *bgp,
static void vnc_import_bgp_del_route_mode_resolve_nve_one_bi(
struct bgp *bgp, afi_t afi, struct bgp_path_info *bpi, /* VPN bpi */
struct prefix_rd *prd, /* RD */
- struct prefix *prefix) /* unicast route prefix */
+ const struct prefix *prefix) /* unicast route prefix */
{
struct prefix un;
@@ -1272,8 +1273,9 @@ static void vnc_import_bgp_del_route_mode_resolve_nve_one_bi(
static void vnc_import_bgp_del_route_mode_resolve_nve_one_rd(
struct prefix_rd *prd,
struct bgp_table *table_rd, /* per-rd VPN route table */
- afi_t afi, struct bgp *bgp, struct prefix *prefix, /* unicast prefix */
- struct prefix *ubpi_nexthop) /* unicast bpi's nexthop */
+ afi_t afi, struct bgp *bgp,
+ const struct prefix *prefix, /* unicast prefix */
+ const struct prefix *ubpi_nexthop) /* unicast bpi's nexthop */
{
struct bgp_node *bn;
struct bgp_path_info *bpi;
@@ -1312,7 +1314,7 @@ static void vnc_import_bgp_del_route_mode_resolve_nve_one_rd(
static void
vnc_import_bgp_del_route_mode_resolve_nve(struct bgp *bgp, afi_t afi,
- struct prefix *prefix,
+ const struct prefix *prefix,
struct bgp_path_info *info)
{
struct ecommunity *ecom = NULL;
@@ -1376,8 +1378,8 @@ vnc_import_bgp_del_route_mode_resolve_nve(struct bgp *bgp, afi_t afi,
continue;
vnc_import_bgp_del_route_mode_resolve_nve_one_rd(
- (struct prefix_rd *)&bnp->p, table, afi, bgp, prefix,
- &pfx_unicast_nexthop); /* TBD how is this set? */
+ (struct prefix_rd *)bgp_node_get_prefix(bnp), table,
+ afi, bgp, prefix, &pfx_unicast_nexthop);
}
if (ecom)
@@ -1396,7 +1398,7 @@ vnc_import_bgp_del_route_mode_resolve_nve(struct bgp *bgp, afi_t afi,
void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
struct bgp *bgp, struct prefix_rd *prd, /* RD */
struct bgp_table *table_rd, /* per-rd VPN route table */
- struct prefix *prefix, /* VPN prefix */
+ const struct prefix *prefix, /* VPN prefix */
struct bgp_path_info *bpi) /* new VPN host route */
{
afi_t afi = family2afi(prefix->family);
@@ -1533,7 +1535,7 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
struct bgp *bgp, struct prefix_rd *prd, /* RD */
struct bgp_table *table_rd, /* per-rd VPN route table */
- struct prefix *prefix, /* VPN prefix */
+ const struct prefix *prefix, /* VPN prefix */
struct bgp_path_info *bpi) /* old VPN host route */
{
afi_t afi = family2afi(prefix->family);
@@ -1675,8 +1677,8 @@ static int is_usable_interior_route(struct bgp_path_info *bpi_interior)
*/
static void vnc_import_bgp_exterior_add_route_it(
struct bgp *bgp, /* exterior instance, we hope */
- struct prefix *prefix, /* unicast prefix */
- struct bgp_path_info *info, /* unicast info */
+ const struct prefix *prefix, /* unicast prefix */
+ struct bgp_path_info *info, /* unicast info */
struct rfapi_import_table *it_only) /* NULL, or limit to this IT */
{
struct rfapi *h;
@@ -1844,9 +1846,9 @@ static void vnc_import_bgp_exterior_add_route_it(
}
void vnc_import_bgp_exterior_add_route(
- struct bgp *bgp, /* exterior instance, we hope */
- struct prefix *prefix, /* unicast prefix */
- struct bgp_path_info *info) /* unicast info */
+ struct bgp *bgp, /* exterior instance, we hope */
+ const struct prefix *prefix, /* unicast prefix */
+ struct bgp_path_info *info) /* unicast info */
{
vnc_import_bgp_exterior_add_route_it(bgp, prefix, info, NULL);
}
@@ -1861,8 +1863,8 @@ void vnc_import_bgp_exterior_add_route(
* right routes.
*/
void vnc_import_bgp_exterior_del_route(
- struct bgp *bgp, struct prefix *prefix, /* unicast prefix */
- struct bgp_path_info *info) /* unicast info */
+ struct bgp *bgp, const struct prefix *prefix, /* unicast prefix */
+ struct bgp_path_info *info) /* unicast info */
{
struct rfapi *h;
struct rfapi_cfg *hc;
@@ -2027,7 +2029,8 @@ void vnc_import_bgp_exterior_add_route_interior(
struct agg_node *rn_interior, /* VPN IT node */
struct bgp_path_info *bpi_interior) /* VPN IT route */
{
- afi_t afi = family2afi(rn_interior->p.family);
+ const struct prefix *p = agg_node_get_prefix(rn_interior);
+ afi_t afi = family2afi(p->family);
struct agg_node *par;
struct bgp_path_info *bpi_exterior;
struct prefix *pfx_exterior; /* exterior pfx */
@@ -2057,13 +2060,8 @@ void vnc_import_bgp_exterior_add_route_interior(
}
/*debugging */
- {
- char str_pfx[PREFIX_STRLEN];
-
- prefix2str(&rn_interior->p, str_pfx, sizeof(str_pfx));
- vnc_zlog_debug_verbose("%s: interior prefix=%s, bpi type=%d",
- __func__, str_pfx, bpi_interior->type);
- }
+ vnc_zlog_debug_verbose("%s: interior prefix=%pRN, bpi type=%d",
+ __func__, rn_interior, bpi_interior->type);
if (RFAPI_HAS_MONITOR_EXTERIOR(rn_interior)) {
@@ -2178,7 +2176,7 @@ void vnc_import_bgp_exterior_add_route_interior(
rfapiUnicastNexthop2Prefix(afi, bpi_exterior->attr,
&pfx_nexthop);
- if (prefix_match(&rn_interior->p, &pfx_nexthop)) {
+ if (prefix_match(p, &pfx_nexthop)) {
struct bgp_path_info *bpi;
struct prefix_rd *prd;
@@ -2321,7 +2319,7 @@ void vnc_import_bgp_exterior_add_route_interior(
rfapiUnicastNexthop2Prefix(afi, bpi_exterior->attr,
&pfx_nexthop);
- if (prefix_match(&rn_interior->p, &pfx_nexthop)) {
+ if (prefix_match(p, &pfx_nexthop)) {
struct prefix_rd *prd;
struct attr new_attr;
@@ -2409,7 +2407,8 @@ void vnc_import_bgp_exterior_del_route_interior(
struct agg_node *rn_interior, /* VPN IT node */
struct bgp_path_info *bpi_interior) /* VPN IT route */
{
- afi_t afi = family2afi(rn_interior->p.family);
+ const struct prefix *p = agg_node_get_prefix(rn_interior);
+ afi_t afi = family2afi(p->family);
struct agg_node *par;
struct bgp_path_info *bpi_exterior;
struct prefix *pfx_exterior; /* exterior pfx */
@@ -2443,14 +2442,8 @@ void vnc_import_bgp_exterior_del_route_interior(
}
/*debugging */
- {
- char str_pfx[PREFIX_STRLEN];
-
- prefix2str(&rn_interior->p, str_pfx, sizeof(str_pfx));
-
- vnc_zlog_debug_verbose("%s: interior prefix=%s, bpi type=%d",
- __func__, str_pfx, bpi_interior->type);
- }
+ vnc_zlog_debug_verbose("%s: interior prefix=%pRN, bpi type=%d",
+ __func__, rn_interior, bpi_interior->type);
/*
* Remove constructed routes based on the deleted interior route
@@ -2597,7 +2590,7 @@ void vnc_import_bgp_exterior_del_route_interior(
* Generic add/delete unicast routes
***********************************************************************/
-void vnc_import_bgp_add_route(struct bgp *bgp, struct prefix *prefix,
+void vnc_import_bgp_add_route(struct bgp *bgp, const struct prefix *prefix,
struct bgp_path_info *info)
{
afi_t afi = family2afi(prefix->family);
@@ -2666,7 +2659,7 @@ void vnc_import_bgp_add_route(struct bgp *bgp, struct prefix *prefix,
/*
* "Withdrawing a Route" import process
*/
-void vnc_import_bgp_del_route(struct bgp *bgp, struct prefix *prefix,
+void vnc_import_bgp_del_route(struct bgp *bgp, const struct prefix *prefix,
struct bgp_path_info *info) /* unicast info */
{
afi_t afi = family2afi(prefix->family);
@@ -2762,7 +2755,8 @@ void vnc_import_bgp_redist_enable(struct bgp *bgp, afi_t afi)
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
continue;
- vnc_import_bgp_add_route(bgp, &rn->p, bpi);
+ vnc_import_bgp_add_route(bgp, bgp_node_get_prefix(rn),
+ bpi);
}
}
vnc_zlog_debug_verbose(
@@ -2803,8 +2797,8 @@ void vnc_import_bgp_exterior_redist_enable(struct bgp *bgp, afi_t afi)
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
continue;
- vnc_import_bgp_exterior_add_route(bgp_exterior, &rn->p,
- bpi);
+ vnc_import_bgp_exterior_add_route(
+ bgp_exterior, bgp_node_get_prefix(rn), bpi);
}
}
vnc_zlog_debug_verbose(
@@ -2850,7 +2844,8 @@ void vnc_import_bgp_exterior_redist_enable_it(
continue;
vnc_import_bgp_exterior_add_route_it(
- bgp_exterior, &rn->p, bpi, it_only);
+ bgp_exterior, bgp_node_get_prefix(rn), bpi,
+ it_only);
}
}
}
@@ -2880,58 +2875,49 @@ void vnc_import_bgp_redist_disable(struct bgp *bgp, afi_t afi)
*/
for (rn1 = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn1;
rn1 = bgp_route_next(rn1)) {
+ const struct prefix *rn1_p;
- if (bgp_node_has_bgp_path_info_data(rn1)) {
-
- for (rn2 = bgp_table_top(
- bgp_node_get_bgp_table_info(rn1));
- rn2; rn2 = bgp_route_next(rn2)) {
-
- struct bgp_path_info *bpi;
- struct bgp_path_info *nextbpi;
-
- for (bpi = bgp_node_get_bgp_path_info(rn2); bpi;
- bpi = nextbpi) {
-
- nextbpi = bpi->next;
+ if (!bgp_node_has_bgp_path_info_data(rn1))
+ continue;
- if (bpi->type
- == ZEBRA_ROUTE_BGP_DIRECT) {
+ rn1_p = bgp_node_get_prefix(rn1);
+ for (rn2 = bgp_table_top(bgp_node_get_bgp_table_info(rn1)); rn2;
+ rn2 = bgp_route_next(rn2)) {
+ const struct prefix *rn2_p = bgp_node_get_prefix(rn2);
+ struct bgp_path_info *bpi;
+ struct bgp_path_info *nextbpi;
- struct rfapi_descriptor *rfd;
- vncHDBgpDirect.peer = bpi->peer;
+ for (bpi = bgp_node_get_bgp_path_info(rn2); bpi;
+ bpi = nextbpi) {
- assert(bpi->extra);
+ nextbpi = bpi->next;
- rfd = bpi->extra->vnc.export
- .rfapi_handle;
+ if (bpi->type != ZEBRA_ROUTE_BGP_DIRECT)
+ continue;
- vnc_zlog_debug_verbose(
- "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p [passing rfd=%p]",
- __func__, bpi,
- bpi->peer, bpi->type,
- bpi->sub_type,
- (bpi->extra
- ? bpi->extra
- ->vnc
- .export
- .rfapi_handle
- : NULL),
- rfd);
+ struct rfapi_descriptor *rfd;
+ vncHDBgpDirect.peer = bpi->peer;
+ assert(bpi->extra);
- del_vnc_route(
- rfd, bpi->peer, bgp,
- SAFI_MPLS_VPN, &rn2->p,
- (struct prefix_rd *)&rn1
- ->p,
- bpi->type,
- bpi->sub_type, NULL,
- 1); /* kill */
+ rfd = bpi->extra->vnc.export.rfapi_handle;
- vncHDBgpDirect.peer = NULL;
- }
- }
+ vnc_zlog_debug_verbose(
+ "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p [passing rfd=%p]",
+ __func__, bpi, bpi->peer, bpi->type,
+ bpi->sub_type,
+ (bpi->extra ? bpi->extra->vnc.export
+ .rfapi_handle
+ : NULL),
+ rfd);
+
+ del_vnc_route(rfd, bpi->peer, bgp,
+ SAFI_MPLS_VPN, rn2_p,
+ (struct prefix_rd *)rn1_p,
+ bpi->type, bpi->sub_type, NULL,
+ 1); /* kill */
+
+ vncHDBgpDirect.peer = NULL;
}
}
}
@@ -2987,8 +2973,9 @@ void vnc_import_bgp_exterior_redist_disable(struct bgp *bgp, afi_t afi)
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
continue;
- vnc_import_bgp_exterior_del_route(bgp_exterior,
- &rn->p, bpi);
+ vnc_import_bgp_exterior_del_route(
+ bgp_exterior, bgp_node_get_prefix(rn),
+ bpi);
}
}
#if DEBUG_RHN_LIST
diff --git a/bgpd/rfapi/vnc_import_bgp.h b/bgpd/rfapi/vnc_import_bgp.h
index 3db6f4010a..ab2ec1a748 100644
--- a/bgpd/rfapi/vnc_import_bgp.h
+++ b/bgpd/rfapi/vnc_import_bgp.h
@@ -32,12 +32,14 @@
extern uint32_t calc_local_pref(struct attr *attr, struct peer *peer);
-extern int vnc_prefix_cmp(void *pfx1, void *pfx2);
+extern int vnc_prefix_cmp(const void *pfx1, const void *pfx2);
-extern void vnc_import_bgp_add_route(struct bgp *bgp, struct prefix *prefix,
+extern void vnc_import_bgp_add_route(struct bgp *bgp,
+ const struct prefix *prefix,
struct bgp_path_info *info);
-extern void vnc_import_bgp_del_route(struct bgp *bgp, struct prefix *prefix,
+extern void vnc_import_bgp_del_route(struct bgp *bgp,
+ const struct prefix *prefix,
struct bgp_path_info *info);
extern void vnc_import_bgp_redist_enable(struct bgp *bgp, afi_t afi);
@@ -51,23 +53,23 @@ extern void vnc_import_bgp_exterior_redist_disable(struct bgp *bgp, afi_t afi);
extern void vnc_import_bgp_exterior_add_route(
struct bgp *bgp, /* exterior instance, we hope */
- struct prefix *prefix, /* unicast prefix */
+ const struct prefix *prefix, /* unicast prefix */
struct bgp_path_info *info); /* unicast info */
extern void vnc_import_bgp_exterior_del_route(
- struct bgp *bgp, struct prefix *prefix, /* unicast prefix */
- struct bgp_path_info *info); /* unicast info */
+ struct bgp *bgp, const struct prefix *prefix, /* unicast prefix */
+ struct bgp_path_info *info); /* unicast info */
extern void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
struct bgp *bgp, struct prefix_rd *prd, /* RD */
struct bgp_table *table_rd, /* per-rd VPN route table */
- struct prefix *prefix, /* VPN prefix */
+ const struct prefix *prefix, /* VPN prefix */
struct bgp_path_info *bpi); /* new VPN host route */
extern void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
struct bgp *bgp, struct prefix_rd *prd, /* RD */
struct bgp_table *table_rd, /* per-rd VPN route table */
- struct prefix *prefix, /* VPN prefix */
+ const struct prefix *prefix, /* VPN prefix */
struct bgp_path_info *bpi); /* old VPN host route */
#endif /* _QUAGGA_RFAPI_VNC_IMPORT_BGP_H_ */
diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c
index 80a590f56a..686dc394a7 100644
--- a/bgpd/rfapi/vnc_zebra.c
+++ b/bgpd/rfapi/vnc_zebra.c
@@ -304,10 +304,12 @@ static void vnc_redistribute_withdraw(struct bgp *bgp, afi_t afi, uint8_t type)
*/
for (prn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); prn;
prn = bgp_route_next(prn)) {
+ const struct prefix *prn_p = bgp_node_get_prefix(prn);
+
memset(&prd, 0, sizeof(prd));
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
- memcpy(prd.val, prn->p.u.val, 8);
+ memcpy(prd.val, prn_p->u.val, 8);
/* This is the per-RD table of prefixes */
table = bgp_node_get_bgp_table_info(prn);
@@ -329,7 +331,7 @@ static void vnc_redistribute_withdraw(struct bgp *bgp, afi_t afi, uint8_t type)
del_vnc_route(
&vncHD1VR, /* use dummy ptr as cookie */
vncHD1VR.peer, bgp, SAFI_MPLS_VPN,
- &(rn->p), &prd, type,
+ bgp_node_get_prefix(rn), &prd, type,
BGP_ROUTE_REDISTRIBUTE, NULL, 0);
}
}
@@ -380,7 +382,7 @@ static int vnc_zebra_read_route(ZAPI_CALLBACK_ARGS)
/*
* low-level message builder
*/
-static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
+static void vnc_zebra_route_msg(const struct prefix *p, unsigned int nhp_count,
void *nhp_ary, int add) /* 1 = add, 0 = del */
{
struct zapi_route api;
@@ -560,7 +562,7 @@ static void vnc_zebra_add_del_prefix(struct bgp *bgp,
int add) /* !0 = add, 0 = del */
{
struct list *nves;
-
+ const struct prefix *p = agg_node_get_prefix(rn);
unsigned int nexthop_count = 0;
void *nh_ary = NULL;
void *nhp_ary = NULL;
@@ -570,15 +572,15 @@ static void vnc_zebra_add_del_prefix(struct bgp *bgp,
if (zclient_vnc->sock < 0)
return;
- if (rn->p.family != AF_INET && rn->p.family != AF_INET6) {
+ if (p->family != AF_INET && p->family != AF_INET6) {
flog_err(EC_LIB_DEVELOPMENT,
"%s: invalid route node addr family", __func__);
return;
}
- if (!vrf_bitmap_check(zclient_vnc->redist[family2afi(rn->p.family)]
- [ZEBRA_ROUTE_VNC],
- VRF_DEFAULT))
+ if (!vrf_bitmap_check(
+ zclient_vnc->redist[family2afi(p->family)][ZEBRA_ROUTE_VNC],
+ VRF_DEFAULT))
return;
if (!bgp->rfapi_cfg) {
@@ -592,17 +594,16 @@ static void vnc_zebra_add_del_prefix(struct bgp *bgp,
return;
}
- import_table_to_nve_list_zebra(bgp, import_table, &nves, rn->p.family);
+ import_table_to_nve_list_zebra(bgp, import_table, &nves, p->family);
if (nves) {
- nve_list_to_nh_array(rn->p.family, nves, &nexthop_count,
- &nh_ary, &nhp_ary);
+ nve_list_to_nh_array(p->family, nves, &nexthop_count, &nh_ary,
+ &nhp_ary);
list_delete(&nves);
if (nexthop_count)
- vnc_zebra_route_msg(&rn->p, nexthop_count, nhp_ary,
- add);
+ vnc_zebra_route_msg(p, nexthop_count, nhp_ary, add);
}
XFREE(MTYPE_TMP, nhp_ary);
@@ -695,15 +696,14 @@ static void vnc_zebra_add_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd,
*/
for (rn = agg_route_top(rt); rn;
rn = agg_route_next(rn)) {
-
- if (rn->info) {
-
- vnc_zlog_debug_verbose(
- "%s: sending %s", __func__,
- (add ? "add" : "del"));
- vnc_zebra_route_msg(&rn->p, 1, &pAddr,
- add);
- }
+ if (!rn->info)
+ continue;
+
+ vnc_zlog_debug_verbose("%s: sending %s",
+ __func__,
+ (add ? "add" : "del"));
+ vnc_zebra_route_msg(agg_node_get_prefix(rn), 1,
+ &pAddr, add);
}
}
}
@@ -778,9 +778,9 @@ static void vnc_zebra_add_del_group_afi(struct bgp *bgp,
for (rn = agg_route_top(rt); rn;
rn = agg_route_next(rn)) {
if (rn->info) {
- vnc_zebra_route_msg(&rn->p,
- nexthop_count,
- nhp_ary, add);
+ vnc_zebra_route_msg(
+ agg_node_get_prefix(rn),
+ nexthop_count, nhp_ary, add);
}
}
}
diff --git a/configure.ac b/configure.ac
index 41d1911c37..628e0c8afc 100755
--- a/configure.ac
+++ b/configure.ac
@@ -182,13 +182,13 @@ dnl - specifically, options to control warnings
AC_USE_SYSTEM_EXTENSIONS
AC_DEFUN([AC_C_FLAG], [{
- m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+],[____])])
+ m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+/{}$],[________])])
AC_CACHE_CHECK([[whether $CC supports $1]], cachename, [
AC_LANG_PUSH([C])
ac_c_flag_save="$CFLAGS"
CFLAGS="$CFLAGS $1"
AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM([[]])],
+ [AC_LANG_PROGRAM([[$4]])],
[
cachename=yes
], [
@@ -295,6 +295,7 @@ AC_C_FLAG([-Wmissing-declarations])
AC_C_FLAG([-Wpointer-arith])
AC_C_FLAG([-Wbad-function-cast])
AC_C_FLAG([-Wwrite-strings])
+AC_C_FLAG([-Wundef])
if test "$enable_gcc_ultra_verbose" = "yes" ; then
AC_C_FLAG([-Wcast-qual])
AC_C_FLAG([-Wstrict-prototypes])
@@ -354,6 +355,44 @@ if test "$enable_undefined_sanitizer" = "yes"; then
fi
AC_SUBST([SAN_FLAGS])
+dnl frr-format.so
+if test "$with_frr_format" != "no" -a "$with_frr_format" != "yes" -a -n "$with_frr_format"; then
+ AC_C_FLAG([-fplugin=${with_frr_format}], [
+ AC_MSG_ERROR([specified frr-format plugin ($with_frr_format) does not work])
+ ],,[
+#ifndef _FRR_ATTRIBUTE_PRINTFRR
+#error plugin not loaded
+#endif
+#if _FRR_ATTRIBUTE_PRINTFRR < 0x10000
+#error plugin too old
+#endif
+ ])
+elif test "$with_frr_format" = "no"; then
+ : #nothing
+else
+ AC_C_FLAG([-fplugin=tools/gcc-plugins/frr-format.so],[
+ AC_C_FLAG([-fplugin=frr-format],[
+ if test "$with_frr_format" = "yes"; then
+ AC_MSG_ERROR([frr-format plugin requested but not found])
+ fi
+ ],,[
+#ifndef _FRR_ATTRIBUTE_PRINTFRR
+#error plugin not loaded
+#endif
+#if _FRR_ATTRIBUTE_PRINTFRR < 0x10000
+#error plugin too old
+#endif
+ ])
+ ],,[
+#ifndef _FRR_ATTRIBUTE_PRINTFRR
+#error plugin not loaded
+#endif
+#if _FRR_ATTRIBUTE_PRINTFRR < 0x10000
+#error plugin too old
+#endif
+ ])
+fi
+
dnl ----------
dnl Essentials
dnl ----------
@@ -600,6 +639,8 @@ AC_ARG_ENABLE([undefined-sanitizer],
AS_HELP_STRING([--undefined-sanitizer], [enable UndefinedBehaviorSanitizer support for detecting undefined behavior]))
AC_ARG_WITH([crypto],
AS_HELP_STRING([--with-crypto=<internal|openssl>], [choose between different implementations of cryptographic functions(default value is --with-crypto=internal)]))
+AC_ARG_WITH([frr-format],
+ AS_HELP_STRING([--with-frr-format[=<.../frr-format.so>]], [use frr-format GCC plugin]))
#if openssl, else use the internal
AS_IF([test "$with_crypto" = "openssl"], [
@@ -2006,6 +2047,10 @@ AC_CHECK_DECL([CLOCK_MONOTONIC],
AC_DEFINE([HAVE_CLOCK_MONOTONIC], [1], [Have monotonic clock])
], [AC_MSG_RESULT([no])], [FRR_INCLUDES])
+AC_SEARCH_LIBS([clock_nanosleep], [rt], [
+ AC_DEFINE([HAVE_CLOCK_NANOSLEEP], [1], [Have clock_nanosleep()])
+])
+
dnl --------------------------------------
dnl checking for flex and bison
dnl --------------------------------------
diff --git a/doc/developer/ospf-sr.rst b/doc/developer/ospf-sr.rst
index d798ba78ef..070465db5b 100644
--- a/doc/developer/ospf-sr.rst
+++ b/doc/developer/ospf-sr.rst
@@ -22,7 +22,7 @@ Interoperability
----------------
* Tested on various topology including point-to-point and LAN interfaces
- in a mix of Free Range Routing instance and Cisco IOS-XR 6.0.x
+ in a mix of FRRouting instance and Cisco IOS-XR 6.0.x
* Check OSPF LSA conformity with latest wireshark release 2.5.0-rc
Implementation details
diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst
index 8ce3bdeeb2..e36b57a5aa 100644
--- a/doc/developer/workflow.rst
+++ b/doc/developer/workflow.rst
@@ -992,6 +992,11 @@ Miscellaneous
When in doubt, follow the guidelines in the Linux kernel style guide, or ask on
the development mailing list / public Slack instance.
+JSON Output
+^^^^^^^^^^^
+
+All JSON keys are to be camelCased, with no spaces.
+
.. _documentation:
diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst
index 977195d6a7..2df4ba3005 100644
--- a/doc/user/ldpd.rst
+++ b/doc/user/ldpd.rst
@@ -108,6 +108,11 @@ LDP Configuration
The following command located under MPLS router node configures the MPLS
router-id of the local device.
+.. index:: [no] ordered-control
+.. clicmd:: [no] ordered-control
+
+ Configure LDP Ordered Label Distribution Control.
+
.. index:: [no] address-family [ipv4 | ipv6]
.. clicmd:: [no] address-family [ipv4 | ipv6]
diff --git a/isisd/fabricd.c b/isisd/fabricd.c
index b9c27d51bd..4a4b25fa1d 100644
--- a/isisd/fabricd.c
+++ b/isisd/fabricd.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2018 Christian Franke
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
@@ -122,9 +122,9 @@ static bool neighbor_entry_hash_cmp(const void *a, const void *b)
return memcmp(na->id, nb->id, sizeof(na->id)) == 0;
}
-static int neighbor_entry_list_cmp(void *a, void *b)
+static int neighbor_entry_list_cmp(const void *a, const void *b)
{
- struct neighbor_entry *na = a, *nb = b;
+ const struct neighbor_entry *na = a, *nb = b;
return -memcmp(na->id, nb->id, sizeof(na->id));
}
diff --git a/isisd/fabricd.h b/isisd/fabricd.h
index 6e93440f3a..9455cdb0f0 100644
--- a/isisd/fabricd.h
+++ b/isisd/fabricd.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2018 Christian Franke
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 1d70521e68..9beed206e8 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -353,7 +353,7 @@ void isis_adj_print(struct isis_adjacency *adj)
if (dyn)
zlog_debug("%s", dyn->hostname);
- zlog_debug("SystemId %20s SNPA %s, level %d\nHolding Time %d",
+ zlog_debug("SystemId %20s SNPA %s, level %d; Holding Time %d",
sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level,
adj->hold_time);
if (adj->ipv4_address_count) {
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index e4152a8712..7d4f7b355d 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -345,8 +345,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit,
} else {
prefix2str(connected->address, buf, sizeof(buf));
zlog_warn(
- "Nonexistent ip address %s removal attempt from \
- circuit %s",
+ "Nonexistent ip address %s removal attempt from circuit %s",
buf, circuit->interface->name);
zlog_warn("Current ip addresses on %s:",
circuit->interface->name);
@@ -394,8 +393,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit,
if (!found) {
prefix2str(connected->address, buf, sizeof(buf));
zlog_warn(
- "Nonexistent ip address %s removal attempt from \
- circuit %s",
+ "Nonexistent ip address %s removal attempt from circuit %s",
buf, circuit->interface->name);
zlog_warn("Current ip addresses on %s:",
circuit->interface->name);
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index fc70a344c8..2483d26833 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -1456,8 +1456,8 @@ void cli_show_ip_isis_hello_interval(struct vty *vty, struct lyd_node *dnode,
if (strmatch(l1, l2))
vty_out(vty, " isis hello-interval %s\n", l1);
else {
- vty_out(vty, " isis hello-interval %s level-1\n", l1);
- vty_out(vty, " isis hello-interval %s level-2\n", l2);
+ vty_out(vty, " isis hello-interval level-1 %s\n", l1);
+ vty_out(vty, " isis hello-interval level-2 %s\n", l2);
}
}
@@ -1514,8 +1514,8 @@ void cli_show_ip_isis_hello_multi(struct vty *vty, struct lyd_node *dnode,
if (strmatch(l1, l2))
vty_out(vty, " isis hello-multiplier %s\n", l1);
else {
- vty_out(vty, " isis hello-multiplier %s level-1\n", l1);
- vty_out(vty, " isis hello-multiplier %s level-2\n", l2);
+ vty_out(vty, " isis hello-multiplier level-1 %s\n", l1);
+ vty_out(vty, " isis hello-multiplier level-2 %s\n", l2);
}
}
diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c
index 36413bac59..e8e35ae63b 100644
--- a/isisd/isis_mt.c
+++ b/isisd/isis_mt.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2017 Christian Franke
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h
index b40139c50a..fd9ee133ca 100644
--- a/isisd/isis_mt.h
+++ b/isisd/isis_mt.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2017 Christian Franke
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h
index a8185a8be0..05aae14b94 100644
--- a/isisd/isis_spf_private.h
+++ b/isisd/isis_spf_private.h
@@ -117,11 +117,11 @@ static bool isis_vertex_queue_hash_cmp(const void *a, const void *b)
* Compares vertizes for sorting in the TENT list. Returns true
* if candidate should be considered before current, false otherwise.
*/
-__attribute__((__unused__))
-static int isis_vertex_queue_tent_cmp(void *a, void *b)
+__attribute__((__unused__)) static int isis_vertex_queue_tent_cmp(const void *a,
+ const void *b)
{
- struct isis_vertex *va = a;
- struct isis_vertex *vb = b;
+ const struct isis_vertex *va = a;
+ const struct isis_vertex *vb = b;
if (va->d_N < vb->d_N)
return -1;
diff --git a/isisd/isis_tx_queue.c b/isisd/isis_tx_queue.c
index 507fd489bc..27e57db16c 100644
--- a/isisd/isis_tx_queue.c
+++ b/isisd/isis_tx_queue.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2018 Christian Franke
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/isisd/isis_tx_queue.h b/isisd/isis_tx_queue.h
index c2beda45b7..f0f1184d58 100644
--- a/isisd/isis_tx_queue.h
+++ b/isisd/isis_tx_queue.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2018 Christian Franke
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 5f94031320..ae883078dd 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -61,6 +61,8 @@ static void lde_label_list_init(void);
static int lde_get_label_chunk(void);
static void on_get_label_chunk_response(uint32_t start, uint32_t end);
static uint32_t lde_get_next_label(void);
+static bool lde_fec_connected(const struct fec_node *);
+static bool lde_fec_outside_mpls_network(const struct fec_node *);
RB_GENERATE(nbr_tree, lde_nbr, entry, lde_nbr_compare)
RB_GENERATE(lde_map_head, lde_map, entry, lde_map_compare)
@@ -658,18 +660,31 @@ lde_acl_check(char *acl_name, int af, union ldpd_addr *addr, uint8_t prefixlen)
return ldp_acl_request(iev_main_sync, acl_name, af, addr, prefixlen);
}
+static bool lde_fec_connected(const struct fec_node *fn)
+{
+ struct fec_nh *fnh;
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry)
+ if (fnh->flags & F_FEC_NH_CONNECTED)
+ return true;
+
+ return false;
+}
+
+static bool lde_fec_outside_mpls_network(const struct fec_node *fn)
+{
+ struct fec_nh *fnh;
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry)
+ if (!(fnh->flags & F_FEC_NH_NO_LDP))
+ return false;
+
+ return true;
+}
+
uint32_t
lde_update_label(struct fec_node *fn)
{
- struct fec_nh *fnh;
- int connected = 0;
-
- LIST_FOREACH(fnh, &fn->nexthops, entry) {
- if (fnh->flags & F_FEC_NH_CONNECTED) {
- connected = 1;
- break;
- }
- }
/* should we allocate a label for this fec? */
switch (fn->fec.type) {
@@ -695,7 +710,14 @@ lde_update_label(struct fec_node *fn)
break;
}
- if (connected) {
+ /*
+ * If connected interface act as egress for fec.
+ * If LDP is not configured on an interface but there
+ * are other NHs with interfaces configured with LDP
+ * then don't act as an egress for the fec, otherwise
+ * act as an egress for the fec
+ */
+ if (lde_fec_connected(fn) || lde_fec_outside_mpls_network(fn)) {
/* choose implicit or explicit-null depending on configuration */
switch (fn->fec.type) {
case FEC_TYPE_IPV4:
@@ -735,6 +757,13 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
struct zapi_pw zpw;
struct l2vpn_pw *pw;
+ /*
+ * Ordered Control: don't program label into HW until a
+ * labelmap msg has been received from upstream router
+ */
+ if (fnh->flags & F_FEC_NH_DEFER)
+ return;
+
switch (fn->fec.type) {
case FEC_TYPE_IPV4:
memset(&kr, 0, sizeof(kr));
@@ -901,6 +930,27 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
struct lde_req *lre;
struct map map;
struct l2vpn_pw *pw;
+ struct fec_nh *fnh;
+ bool allow = false;
+
+ /*
+ * Ordered Control: do not send a labelmap msg until
+ * a labelmap message is received from downstream router
+ * and don't send labelmap back to downstream router
+ */
+ if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ if (fnh->flags & F_FEC_NH_DEFER)
+ continue;
+
+ if (lde_address_find(ln, fnh->af, &fnh->nexthop))
+ return;
+ allow = true;
+ break;
+ }
+ if (!allow)
+ return;
+ }
/*
* We shouldn't send a new label mapping if we have a pending
@@ -1241,6 +1291,7 @@ lde_nbr_del(struct lde_nbr *ln)
struct fec_node *fn;
struct fec_nh *fnh;
struct l2vpn_pw *pw;
+ struct lde_nbr *lnbr;
if (ln == NULL)
return;
@@ -1256,6 +1307,25 @@ lde_nbr_del(struct lde_nbr *ln)
if (!lde_address_find(ln, fnh->af,
&fnh->nexthop))
continue;
+
+ /*
+ * Ordered Control: must mark any non-connected
+ * NH to wait until we receive a labelmap msg
+ * before installing in kernel and sending to
+ * peer, must do this as NHs are not removed
+ * when lsps go down. Also send label withdraw
+ * to other neighbors for all fecs from neighbor
+ * going down
+ */
+ if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+ fnh->flags |= F_FEC_NH_DEFER;
+
+ RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) {
+ if (ln->peerid == lnbr->peerid)
+ continue;
+ lde_send_labelwithdraw(lnbr, fn, NULL, NULL);
+ }
+ }
break;
case FEC_TYPE_PWID:
if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
@@ -1567,6 +1637,56 @@ lde_change_egress_label(int af)
NULL, 0);
}
+void
+lde_change_host_label(int af)
+{
+ struct lde_nbr *ln;
+ struct fec *f;
+ struct fec_node *fn;
+ uint32_t new_label;
+
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+
+ switch (af) {
+ case AF_INET:
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+ break;
+ case AF_INET6:
+ if (fn->fec.type != FEC_TYPE_IPV6)
+ continue;
+ break;
+ default:
+ fatalx("lde_change_host_label: unknown af");
+ }
+
+ /*
+ * If the local label has changed to NO_LABEL, send a label
+ * withdraw to all peers.
+ * If the local label has changed and it's different from
+ * NO_LABEL, send a label mapping to all peers advertising
+ * the new label.
+ * If the local label hasn't changed, do nothing
+ */
+ new_label = lde_update_label(fn);
+ if (fn->local_label != new_label) {
+ if (new_label == NO_LABEL)
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelwithdraw(ln, fn,
+ NULL, NULL);
+
+ fn->local_label = new_label;
+ if (fn->local_label != NO_LABEL)
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(ln, fn, 0);
+ }
+ }
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0,
+ NULL, 0);
+}
+
static int
lde_address_add(struct lde_nbr *ln, struct lde_addr *lde_addr)
{
@@ -1628,8 +1748,11 @@ lde_address_list_free(struct lde_nbr *ln)
static void zclient_sync_init(unsigned short instance)
{
+ struct zclient_options options = zclient_options_default;
+ options.synchronous = true;
+
/* Initialize special zclient for synchronous message exchanges. */
- zclient_sync = zclient_new(master, &zclient_options_default);
+ zclient_sync = zclient_new(master, &options);
zclient_sync->sock = -1;
zclient_sync->redist_default = ZEBRA_ROUTE_LDP;
zclient_sync->instance = instance;
@@ -1642,6 +1765,12 @@ static void zclient_sync_init(unsigned short instance)
/* make socket non-blocking */
sock_set_nonblock(zclient_sync->sock);
+ /* Send hello to notify zebra this is a synchronous client */
+ while (zclient_send_hello(zclient_sync) < 0) {
+ log_warnx("Error sending hello for synchronous zclient!");
+ sleep(1);
+ }
+
/* Connect to label manager */
while (lm_label_manager_connect(zclient_sync, 0) != 0) {
log_warnx("Error connecting to label manager!");
diff --git a/ldpd/lde.h b/ldpd/lde.h
index ce466c16b9..36196a3d08 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -114,6 +114,8 @@ struct fec_nh {
};
#define F_FEC_NH_NEW 0x01
#define F_FEC_NH_CONNECTED 0x02
+#define F_FEC_NH_DEFER 0x04 /* running ordered control */
+#define F_FEC_NH_NO_LDP 0x08 /* no ldp on this interface */
struct fec_node {
struct fec fec;
@@ -181,6 +183,7 @@ void lde_req_del(struct lde_nbr *, struct lde_req *, int);
struct lde_wdraw *lde_wdraw_add(struct lde_nbr *, struct fec_node *);
void lde_wdraw_del(struct lde_nbr *, struct lde_wdraw *);
void lde_change_egress_label(int);
+void lde_change_host_label(int);
struct lde_addr *lde_address_find(struct lde_nbr *, int,
union ldpd_addr *);
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index eb1a6d9434..8f524e0aa9 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -20,6 +20,7 @@
#include <zebra.h>
#include "ldpd.h"
+#include "ldpe.h"
#include "lde.h"
#include "log.h"
@@ -325,6 +326,7 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
{
struct fec_node *fn;
struct fec_nh *fnh;
+ struct iface *iface;
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
@@ -333,9 +335,21 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
fn->data = data;
fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
- if (fnh == NULL)
+ if (fnh == NULL) {
fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type,
route_instance);
+ /*
+ * Ordered Control: if not a connected route and not a route
+ * learned over an interface not running LDP and not a PW
+ * then mark to wait until we receive labelmap msg before
+ * installing in kernel and sending to peer
+ */
+ iface = if_lookup(ldeconf, ifindex);
+ if ((ldeconf->flags & F_LDPD_ORDERED_CONTROL) &&
+ !connected && iface != NULL && fec->type != FEC_TYPE_PWID)
+ fnh->flags |= F_FEC_NH_DEFER;
+ }
+
fnh->flags |= F_FEC_NH_NEW;
if (connected)
fnh->flags |= F_FEC_NH_CONNECTED;
@@ -374,15 +388,25 @@ lde_kernel_update(struct fec *fec)
struct fec_nh *fnh, *safe;
struct lde_nbr *ln;
struct lde_map *me;
+ struct iface *iface;
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
return;
LIST_FOREACH_SAFE(fnh, &fn->nexthops, entry, safe) {
- if (fnh->flags & F_FEC_NH_NEW)
+ if (fnh->flags & F_FEC_NH_NEW) {
fnh->flags &= ~F_FEC_NH_NEW;
- else {
+ /*
+ * if LDP configured on interface or a static route
+ * clear flag else treat fec as a connected route
+ */
+ iface = if_lookup(ldeconf,fnh->ifindex);
+ if (iface || fnh->route_type == ZEBRA_ROUTE_STATIC)
+ fnh->flags &=~F_FEC_NH_NO_LDP;
+ else
+ fnh->flags |= F_FEC_NH_NO_LDP;
+ } else {
lde_send_delete_klabel(fn, fnh);
fec_nh_del(fnh);
}
@@ -445,6 +469,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
struct lde_req *lre;
struct lde_map *me;
struct l2vpn_pw *pw;
+ bool send_map = false;
lde_map2fec(map, ln->id, &fec);
@@ -525,6 +550,15 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
continue;
+ /*
+ * Ordered Control: labelmap msg received from
+ * NH so clear flag and send labelmap msg to
+ * peer
+ */
+ if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+ send_map = true;
+ fnh->flags &= ~F_FEC_NH_DEFER;
+ }
fnh->remote_label = map->label;
lde_send_change_klabel(fn, fnh);
break;
@@ -558,6 +592,15 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
* loop detection. LMp.28 - LMp.30 are unnecessary because we are
* merging capable.
*/
+
+ /*
+ * Ordered Control: just received a labelmap for this fec from NH so
+ * need to send labelmap to all peers
+ * LMp.20 - LMp21 Execute procedure to send Label Mapping
+ */
+ if (send_map && fn->local_label != NO_LABEL)
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(ln, fn, 1);
}
void
@@ -757,6 +800,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
struct fec_nh *fnh;
struct lde_map *me;
struct l2vpn_pw *pw;
+ struct lde_nbr *lnbr;
/* wildcard label withdraw */
if (map->type == MAP_TYPE_WILDCARD ||
@@ -803,6 +847,26 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
if (me && (map->label == NO_LABEL || map->label == me->map.label))
/* LWd.4: remove record of previously received lbl mapping */
lde_map_del(ln, me, 0);
+
+ /* Ordered Control: additional withdraw steps */
+ if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+ /* LWd.8: for each neighbor other that src of withdraw msg */
+ RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) {
+ if (ln->peerid == lnbr->peerid)
+ continue;
+
+ /* LWd.9: check if previously sent a label mapping */
+ me = (struct lde_map *)fec_find(&lnbr->sent_map,
+ &fn->fec);
+ /*
+ * LWd.10: does label sent to peer "map" to withdraw
+ * label
+ */
+ if (me)
+ /* LWd.11: send label withdraw */
+ lde_send_labelwithdraw(lnbr, fn, NULL, NULL);
+ }
+ }
}
void
@@ -813,6 +877,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
struct fec_nh *fnh;
struct lde_map *me;
struct l2vpn_pw *pw;
+ struct lde_nbr *lnbr;
/* LWd.2: send label release */
lde_send_labelrelease(ln, NULL, map, map->label);
@@ -859,6 +924,26 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
* label mapping
*/
lde_map_del(ln, me, 0);
+
+ /* Ordered Control: additional withdraw steps */
+ if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+ /* LWd.8: for each neighbor other that src of withdraw msg */
+ RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) {
+ if (ln->peerid == lnbr->peerid)
+ continue;
+
+ /* LWd.9: check if previously sent a label mapping */
+ me = (struct lde_map *)fec_find(&lnbr->sent_map,
+ &fn->fec);
+ /*
+ * LWd.10: does label sent to peer "map" to withdraw
+ * label
+ */
+ if (me)
+ /* LWd.11: send label withdraw */
+ lde_send_labelwithdraw(lnbr, fn, NULL, NULL);
+ }
+ }
}
}
diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h
index 5e9df4aafe..af5f1d5616 100644
--- a/ldpd/ldp_vty.h
+++ b/ldpd/ldp_vty.h
@@ -52,6 +52,7 @@ int ldp_vty_label_expnull(struct vty *, const char *, const char *);
int ldp_vty_label_accept(struct vty *, const char *, const char *, const char *);
int ldp_vty_ttl_security(struct vty *, const char *);
int ldp_vty_router_id(struct vty *, const char *, struct in_addr);
+int ldp_vty_ordered_control(struct vty *, const char *);
int ldp_vty_ds_cisco_interop(struct vty *, const char *);
int ldp_vty_trans_pref_ipv4(struct vty *, const char *);
int ldp_vty_neighbor_password(struct vty *, const char *, struct in_addr, const char *);
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index c24e1917cc..c10c6ae35c 100644
--- a/ldpd/ldp_vty_cmds.c
+++ b/ldpd/ldp_vty_cmds.c
@@ -221,6 +221,15 @@ DEFPY (ldp_router_id,
return (ldp_vty_router_id(vty, no, address));
}
+DEFPY (ldp_ordered_control,
+ ldp_ordered_control_cmd,
+ "[no] ordered-control",
+ NO_STR
+ "Configure LDP ordered label distribution control mode\n")
+{
+ return (ldp_vty_ordered_control(vty, no));
+}
+
DEFPY (ldp_discovery_targeted_hello_accept,
ldp_discovery_targeted_hello_accept_cmd,
"[no] discovery targeted-hello accept [from <(1-199)|(1300-2699)|WORD>$from_acl]",
@@ -807,6 +816,7 @@ ldp_vty_init (void)
install_element(LDP_NODE, &ldp_neighbor_session_holdtime_cmd);
install_element(LDP_NODE, &ldp_neighbor_ttl_security_cmd);
install_element(LDP_NODE, &ldp_router_id_cmd);
+ install_element(LDP_NODE, &ldp_ordered_control_cmd);
install_element(LDP_IPV4_NODE, &ldp_discovery_link_holdtime_cmd);
install_element(LDP_IPV4_NODE, &ldp_discovery_targeted_holdtime_cmd);
diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c
index 816fcc64b8..05b8962563 100644
--- a/ldpd/ldp_vty_conf.c
+++ b/ldpd/ldp_vty_conf.c
@@ -278,6 +278,9 @@ ldp_config_write(struct vty *vty)
if (ldpd_conf->flags & F_LDPD_DS_CISCO_INTEROP)
vty_out (vty, " dual-stack cisco-interop\n");
+ if (ldpd_conf->flags & F_LDPD_ORDERED_CONTROL)
+ vty_out (vty, " ordered-control\n");
+
RB_FOREACH(nbrp, nbrp_head, &ldpd_conf->nbrp_tree) {
if (nbrp->flags & F_NBRP_KEEPALIVE)
vty_out (vty, " neighbor %s session holdtime %u\n",
@@ -997,6 +1000,19 @@ ldp_vty_router_id(struct vty *vty, const char *negate, struct in_addr address)
}
int
+ldp_vty_ordered_control(struct vty *vty, const char *negate)
+{
+ if (negate)
+ vty_conf->flags &= ~F_LDPD_ORDERED_CONTROL;
+ else
+ vty_conf->flags |= F_LDPD_ORDERED_CONTROL;
+
+ ldp_config_apply(vty, vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
ldp_vty_ds_cisco_interop(struct vty *vty, const char * negate)
{
if (negate)
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 78b1c3e544..741c8c4655 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -1285,6 +1285,14 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
conf->rtr_id = xconf->rtr_id;
}
+ /*
+ * Configuration of ordered-control or independent-control
+ * requires resetting all neighborships.
+ */
+ if ((conf->flags & F_LDPD_ORDERED_CONTROL) !=
+ (xconf->flags & F_LDPD_ORDERED_CONTROL))
+ ldpe_reset_nbrs(AF_UNSPEC);
+
conf->lhello_holdtime = xconf->lhello_holdtime;
conf->lhello_interval = xconf->lhello_interval;
conf->thello_holdtime = xconf->thello_holdtime;
@@ -1311,6 +1319,7 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
int stop_init_backoff = 0;
int remove_dynamic_tnbrs = 0;
int change_egress_label = 0;
+ int change_host_label = 0;
int reset_nbrs_ipv4 = 0;
int reset_nbrs = 0;
int update_sockets = 0;
@@ -1341,6 +1350,12 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
if ((af_conf->flags & F_LDPD_AF_EXPNULL) !=
(xa->flags & F_LDPD_AF_EXPNULL))
change_egress_label = 1;
+
+ /* changing config of host only fec filtering */
+ if ((af_conf->flags & F_LDPD_AF_ALLOCHOSTONLY)
+ != (xa->flags & F_LDPD_AF_ALLOCHOSTONLY))
+ change_host_label = 1;
+
af_conf->flags = xa->flags;
/* update the transport address */
@@ -1350,6 +1365,10 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
}
/* update ACLs */
+ if (strcmp(af_conf->acl_label_allocate_for,
+ xa->acl_label_allocate_for))
+ change_host_label = 1;
+
if (strcmp(af_conf->acl_label_advertise_to,
xa->acl_label_advertise_to) ||
strcmp(af_conf->acl_label_advertise_for,
@@ -1383,6 +1402,8 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
case PROC_LDE_ENGINE:
if (change_egress_label)
lde_change_egress_label(af);
+ if (change_host_label)
+ lde_change_host_label(af);
break;
case PROC_LDP_ENGINE:
if (stop_init_backoff)
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index 006780f032..a736b4ca37 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -511,6 +511,8 @@ DECLARE_QOBJ_TYPE(ldpd_conf)
#define F_LDPD_NO_FIB_UPDATE 0x0001
#define F_LDPD_DS_CISCO_INTEROP 0x0002
#define F_LDPD_ENABLED 0x0004
+#define F_LDPD_ORDERED_CONTROL 0x0008
+
struct ldpd_af_global {
struct thread *disc_ev;
diff --git a/lib/agg_table.h b/lib/agg_table.h
index f95fed6758..e98476f1b7 100644
--- a/lib/agg_table.h
+++ b/lib/agg_table.h
@@ -155,6 +155,16 @@ static inline struct agg_table *agg_get_table(struct agg_node *node)
return (struct agg_table *)route_table_get_info(node->table);
}
+static inline const struct prefix *
+agg_node_get_prefix(const struct agg_node *node)
+{
+ return &node->p;
+}
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pRN" (struct agg_node *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/compiler.h b/lib/compiler.h
index e430925e69..217a60d888 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -305,7 +305,14 @@ extern "C" {
#include <inttypes.h>
#ifdef _FRR_ATTRIBUTE_PRINTFRR
-#define PRINTFRR(a, b) __attribute__((printfrr(a, b)))
+#define PRINTFRR(a, b) __attribute__((frr_format("frr_printf", a, b)))
+
+#undef PRIu64
+#undef PRId64
+#undef PRIx64
+#define PRIu64 "Lu"
+#define PRId64 "Ld"
+#define PRIx64 "Lx"
#else /* !_FRR_ATTRIBUTE_PRINTFRR */
#define PRINTFRR(a, b) __attribute__((format(printf, a, b)))
diff --git a/lib/frrlua.c b/lib/frrlua.c
index 26610556dc..9f9cf8c1f6 100644
--- a/lib/frrlua.c
+++ b/lib/frrlua.c
@@ -5,7 +5,7 @@
* Copyright (C) 2016 Cumulus Networks, Inc.
* Donald Sharp
*
- * This file is part of FreeRangeRouting (FRR).
+ * 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
diff --git a/lib/frrlua.h b/lib/frrlua.h
index 374eb70311..40c7a67b89 100644
--- a/lib/frrlua.h
+++ b/lib/frrlua.h
@@ -5,7 +5,7 @@
* Copyright (C) 2016 Cumulus Networks, Inc.
* Donald Sharp
*
- * This file is part of FreeRangeRouting (FRR).
+ * 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
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
index 4bd8f5138a..5d3f6675a3 100644
--- a/lib/grammar_sandbox_main.c
+++ b/lib/grammar_sandbox_main.c
@@ -7,7 +7,7 @@
* Copyright (C) 2016 Cumulus Networks, Inc.
* Copyright (C) 2017 David Lamparter for NetDEF, Inc.
*
- * This file is part of FreeRangeRouting (FRR).
+ * 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
diff --git a/lib/ipaddr.h b/lib/ipaddr.h
index c6372f1abb..cd7f79a04e 100644
--- a/lib/ipaddr.h
+++ b/lib/ipaddr.h
@@ -112,7 +112,7 @@ static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6,
/*
* convert an ipv4 mapped ipv6 address back to ipv4 address
*/
-static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6,
+static inline void ipv4_mapped_ipv6_to_ipv4(const struct in6_addr *in6,
struct in_addr *in)
{
memset(in, 0, sizeof(struct in_addr));
diff --git a/lib/log.c b/lib/log.c
index 2101e0225c..b3be5216aa 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -1228,59 +1228,47 @@ int proto_redistnum(int afi, const char *s)
return -1;
}
-void zlog_hexdump(const void *mem, unsigned int len)
+void zlog_hexdump(const void *mem, size_t len)
{
- unsigned long i = 0;
- unsigned int j = 0;
- unsigned int columns = 8;
- /*
- * 19 bytes for 0xADDRESS:
- * 24 bytes for data; 2 chars plus a space per data byte
- * 1 byte for space
- * 8 bytes for ASCII representation
- * 1 byte for a newline
- * =====================
- * 53 bytes per 8 bytes of data
- * 1 byte for null term
- */
- size_t bs = ((len / 8) + 1) * 53 + 1;
- char buf[bs];
- char *s = buf;
- const unsigned char *memch = mem;
-
- memset(buf, 0, sizeof(buf));
-
- for (i = 0; i < len + ((len % columns) ? (columns - len % columns) : 0);
- i++) {
- /* print offset */
- if (i % columns == 0)
- s += snprintf(s, bs - (s - buf),
- "0x%016lx: ", (unsigned long)memch + i);
-
- /* print hex data */
- if (i < len)
- s += snprintf(s, bs - (s - buf), "%02x ", memch[i]);
-
- /* end of block, just aligning for ASCII dump */
- else
- s += snprintf(s, bs - (s - buf), " ");
-
- /* print ASCII dump */
- if (i % columns == (columns - 1)) {
- for (j = i - (columns - 1); j <= i; j++) {
- /* end of block not really printing */
- if (j >= len)
- s += snprintf(s, bs - (s - buf), " ");
- else if (isprint(memch[j]))
- s += snprintf(s, bs - (s - buf), "%c",
- memch[j]);
- else /* other char */
- s += snprintf(s, bs - (s - buf), ".");
- }
- s += snprintf(s, bs - (s - buf), "\n");
+ char line[64];
+ const uint8_t *src = mem;
+ const uint8_t *end = src + len;
+
+ if (len == 0) {
+ zlog_debug("%016lx: (zero length / no data)", (long)src);
+ return;
+ }
+
+ while (src < end) {
+ struct fbuf fb = {
+ .buf = line,
+ .pos = line,
+ .len = sizeof(line),
+ };
+ const uint8_t *lineend = src + 8;
+ unsigned line_bytes = 0;
+
+ bprintfrr(&fb, "%016lx: ", (long)src);
+
+ while (src < lineend && src < end) {
+ bprintfrr(&fb, "%02x ", *src++);
+ line_bytes++;
+ }
+ if (line_bytes < 8)
+ bprintfrr(&fb, "%*s", (8 - line_bytes) * 3, "");
+
+ src -= line_bytes;
+ while (src < lineend && src < end && fb.pos < fb.buf + fb.len) {
+ uint8_t byte = *src++;
+
+ if (isprint(byte))
+ *fb.pos++ = byte;
+ else
+ *fb.pos++ = '.';
}
+
+ zlog_debug("%.*s", (int)(fb.pos - fb.buf), fb.buf);
}
- zlog_debug("\n%s", buf);
}
const char *zlog_sanitize(char *buf, size_t bufsz, const void *in, size_t inlen)
diff --git a/lib/log.h b/lib/log.h
index 501da88a54..d79ad9f805 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -152,7 +152,7 @@ extern void zlog_backtrace_sigsafe(int priority, void *program_counter);
extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */,
char *buf, size_t buflen);
-extern void zlog_hexdump(const void *mem, unsigned int len);
+extern void zlog_hexdump(const void *mem, size_t len);
extern const char *zlog_sanitize(char *buf, size_t bufsz, const void *in,
size_t inlen);
diff --git a/lib/mpls.c b/lib/mpls.c
index 759fe1206d..ac5792a686 100644
--- a/lib/mpls.c
+++ b/lib/mpls.c
@@ -79,7 +79,7 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels,
/*
* Label to string conversion, labels in string separated by '/'.
*/
-char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
+char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf,
int len, int pretty)
{
char label_buf[BUFSIZ];
diff --git a/lib/mpls.h b/lib/mpls.h
index 635ecc77a1..05cf2935e8 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -209,10 +209,13 @@ static inline char *label2str(mpls_label_t label, char *buf, size_t len)
int mpls_str2label(const char *label_str, uint8_t *num_labels,
mpls_label_t *labels);
+/* Generic string buffer for label-stack-to-str */
+#define MPLS_LABEL_STRLEN 1024
+
/*
* Label to string conversion, labels in string separated by '/'.
*/
-char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
+char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf,
int len, int pretty);
#ifdef __cplusplus
diff --git a/lib/nexthop.c b/lib/nexthop.c
index e23f8b0792..0d239e091b 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -23,11 +23,9 @@
#include "table.h"
#include "memory.h"
#include "command.h"
-#include "if.h"
#include "log.h"
#include "sockunion.h"
#include "linklist.h"
-#include "thread.h"
#include "prefix.h"
#include "nexthop.h"
#include "mpls.h"
@@ -155,7 +153,24 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
}
ret = _nexthop_source_cmp(next1, next2);
+ if (ret != 0)
+ goto done;
+
+ if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return -1;
+
+ if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return 1;
+
+ if (next1->backup_idx < next2->backup_idx)
+ return -1;
+ if (next1->backup_idx > next2->backup_idx)
+ return 1;
+
+done:
return ret;
}
@@ -240,7 +255,7 @@ struct nexthop *nexthop_new(void)
* The linux kernel does some weird stuff with adding +1 to
* all nexthop weights it gets over netlink.
* To handle this, just default everything to 1 right from
- * from the beggining so we don't have to special case
+ * from the beginning so we don't have to special case
* default weights in the linux netlink code.
*
* 1 should be a valid on all platforms anyway.
@@ -393,8 +408,8 @@ struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type)
}
/* Update nexthop with label information. */
-void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
- uint8_t num_labels, mpls_label_t *label)
+void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype,
+ uint8_t num_labels, const mpls_label_t *labels)
{
struct mpls_label_stack *nh_label;
int i;
@@ -402,23 +417,26 @@ void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
if (num_labels == 0)
return;
- nexthop->nh_label_type = type;
+ /* Enforce limit on label stack size */
+ if (num_labels > MPLS_MAX_LABELS)
+ num_labels = MPLS_MAX_LABELS;
+
+ nexthop->nh_label_type = ltype;
+
nh_label = XCALLOC(MTYPE_NH_LABEL,
sizeof(struct mpls_label_stack)
+ num_labels * sizeof(mpls_label_t));
nh_label->num_labels = num_labels;
for (i = 0; i < num_labels; i++)
- nh_label->label[i] = *(label + i);
+ nh_label->label[i] = *(labels + i);
nexthop->nh_label = nh_label;
}
/* Free label information of nexthop, if present. */
void nexthop_del_labels(struct nexthop *nexthop)
{
- if (nexthop->nh_label) {
- XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
- nexthop->nh_label_type = ZEBRA_LSP_NONE;
- }
+ XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
+ nexthop->nh_label_type = ZEBRA_LSP_NONE;
}
const char *nexthop2str(const struct nexthop *nexthop, char *str, int size)
@@ -505,6 +523,7 @@ unsigned int nexthop_level(struct nexthop *nexthop)
uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
{
uint32_t key = 0x45afe398;
+ uint32_t val;
key = jhash_3words(nexthop->type, nexthop->vrf_id,
nexthop->nh_label_type, key);
@@ -534,8 +553,12 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
key = jhash_1word(nexthop->nh_label->label[i], key);
}
- key = jhash_2words(nexthop->ifindex,
- CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK),
+ val = 0;
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ val = (uint32_t)nexthop->backup_idx;
+
+ key = jhash_3words(nexthop->ifindex,
+ CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), val,
key);
return key;
@@ -575,6 +598,7 @@ void nexthop_copy_no_recurse(struct nexthop *copy,
copy->type = nexthop->type;
copy->flags = nexthop->flags;
copy->weight = nexthop->weight;
+ copy->backup_idx = nexthop->backup_idx;
memcpy(&copy->gate, &nexthop->gate, sizeof(nexthop->gate));
memcpy(&copy->src, &nexthop->src, sizeof(nexthop->src));
memcpy(&copy->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 6710914e40..c4e88dd844 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -86,6 +86,8 @@ struct nexthop {
* active one
*/
#define NEXTHOP_FLAG_RNH_FILTERED (1 << 5) /* rmap filtered, used by rnh */
+#define NEXTHOP_FLAG_HAS_BACKUP (1 << 6) /* Backup nexthop index is set */
+
#define NEXTHOP_IS_ACTIVE(flags) \
(CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
&& !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE))
@@ -116,15 +118,31 @@ struct nexthop {
/* Weight of the nexthop ( for unequal cost ECMP ) */
uint8_t weight;
+
+ /* Index of a corresponding backup nexthop in a backup list;
+ * only meaningful if the HAS_BACKUP flag is set.
+ */
+ uint8_t backup_idx;
};
+/* Backup index value is limited */
+#define NEXTHOP_BACKUP_IDX_MAX 255
+
+/* Utility to append one nexthop to another. */
+#define NEXTHOP_APPEND(to, new) \
+ do { \
+ (to)->next = (new); \
+ (new)->prev = (to); \
+ (new)->next = NULL; \
+ } while (0)
+
struct nexthop *nexthop_new(void);
void nexthop_free(struct nexthop *nexthop);
void nexthops_free(struct nexthop *nexthop);
-void nexthop_add_labels(struct nexthop *, enum lsp_types_t, uint8_t,
- mpls_label_t *);
+void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype,
+ uint8_t num_labels, const mpls_label_t *labels);
void nexthop_del_labels(struct nexthop *);
/*
@@ -201,6 +219,10 @@ extern struct nexthop *nexthop_dup(const struct nexthop *nexthop,
extern struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop,
struct nexthop *rparent);
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pNH" (struct nexthop *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index d660428bcd..8c3bbbdcd4 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -43,8 +43,12 @@ struct nexthop_hold {
char *intf;
char *labels;
uint32_t weight;
+ int backup_idx; /* Index of backup nexthop, if >= 0 */
};
+/* Invalid/unset value for nexthop_hold's backup_idx */
+#define NHH_BACKUP_IDX_INVALID -1
+
struct nexthop_group_hooks {
void (*new)(const char *name);
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
@@ -225,6 +229,10 @@ void nexthop_group_copy(struct nexthop_group *to,
void nexthop_group_delete(struct nexthop_group **nhg)
{
+ /* OK to call with NULL group */
+ if ((*nhg) == NULL)
+ return;
+
if ((*nhg)->nexthop)
nexthops_free((*nhg)->nexthop);
@@ -567,11 +575,36 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",
return CMD_SUCCESS;
}
+DEFPY(nexthop_group_backup, nexthop_group_backup_cmd,
+ "backup-group WORD$name",
+ "Specify a group name containing backup nexthops\n"
+ "The name of the backup group\n")
+{
+ VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+
+ strlcpy(nhgc->backup_list_name, name, sizeof(nhgc->backup_list_name));
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_nexthop_group_backup, no_nexthop_group_backup_cmd,
+ "no backup-group [WORD$name]",
+ NO_STR
+ "Clear group name containing backup nexthops\n"
+ "The name of the backup group\n")
+{
+ VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+
+ nhgc->backup_list_name[0] = 0;
+
+ return CMD_SUCCESS;
+}
+
static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
const char *nhvrf_name,
const union sockunion *addr,
const char *intf, const char *labels,
- const uint32_t weight)
+ const uint32_t weight, int backup_idx)
{
struct nexthop_hold *nh;
@@ -588,6 +621,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
nh->weight = weight;
+ nh->backup_idx = backup_idx;
+
listnode_add_sort(nhgc->nhg_list, nh);
}
@@ -629,7 +664,7 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
const union sockunion *addr,
const char *intf, const char *name,
const char *labels, int *lbl_ret,
- uint32_t weight)
+ uint32_t weight, int backup_idx)
{
int ret = 0;
struct vrf *vrf;
@@ -688,6 +723,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
nhop->weight = weight;
+ if (backup_idx != NHH_BACKUP_IDX_INVALID) {
+ /* Validate index value */
+ if (backup_idx > NEXTHOP_BACKUP_IDX_MAX)
+ return false;
+
+ SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ nhop->backup_idx = backup_idx;
+ }
+
return true;
}
@@ -699,7 +743,7 @@ static bool nexthop_group_parse_nhh(struct nexthop *nhop,
{
return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf,
nhh->nhvrf_name, nhh->labels, NULL,
- nhh->weight));
+ nhh->weight, nhh->backup_idx));
}
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
@@ -712,6 +756,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
nexthop-vrf NAME$vrf_name \
|label WORD \
|weight (1-255) \
+ |backup-idx$bi_str (0-254)$idx \
}]",
NO_STR
"Specify one of the nexthops in this ECMP group\n"
@@ -724,16 +769,23 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"Specify label(s) for this nexthop\n"
"One or more labels in the range (16-1048575) separated by '/'\n"
"Weight to be used by the nexthop for purposes of ECMP\n"
- "Weight value to be used\n")
+ "Weight value to be used\n"
+ "Backup nexthop index in another group\n"
+ "Nexthop index value\n")
{
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
struct nexthop nhop;
struct nexthop *nh;
int lbl_ret = 0;
bool legal;
+ int backup_idx = idx;
+ bool add_update = false;
+
+ if (bi_str == NULL)
+ backup_idx = NHH_BACKUP_IDX_INVALID;
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label,
- &lbl_ret, weight);
+ &lbl_ret, weight, backup_idx);
if (nhop.type == NEXTHOP_TYPE_IPV6
&& IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
@@ -765,19 +817,30 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
nh = nexthop_exists(&nhgc->nhg, &nhop);
- if (no) {
+ if (no || nh) {
+ /* Remove or replace cases */
+
+ /* Remove existing config */
nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label,
weight);
if (nh) {
+ /* Remove nexthop object */
_nexthop_del(&nhgc->nhg, nh);
if (nhg_hooks.del_nexthop)
nhg_hooks.del_nexthop(nhgc, nh);
nexthop_free(nh);
+ nh = NULL;
}
- } else if (!nh) {
- /* must be adding new nexthop since !no and !nexthop_exists */
+ }
+
+ add_update = !no;
+
+ if (add_update) {
+ /* Add or replace cases */
+
+ /* If valid config, add nexthop object */
if (legal) {
nh = nexthop_new();
@@ -785,8 +848,9 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
_nexthop_add(&nhgc->nhg.nexthop, nh);
}
+ /* Save config always */
nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label,
- weight);
+ weight, backup_idx);
if (legal && nhg_hooks.add_nexthop)
nhg_hooks.add_nexthop(nhgc, nh);
@@ -849,6 +913,9 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
if (nh->weight)
vty_out(vty, " weight %u", nh->weight);
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ vty_out(vty, " backup-idx %d", nh->backup_idx);
+
vty_out(vty, "\n");
}
@@ -874,6 +941,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
if (nh->weight)
vty_out(vty, " weight %u", nh->weight);
+ if (nh->backup_idx != NHH_BACKUP_IDX_INVALID)
+ vty_out(vty, " backup-idx %d", nh->backup_idx);
+
vty_out(vty, "\n");
}
@@ -887,6 +957,10 @@ static int nexthop_group_write(struct vty *vty)
vty_out(vty, "nexthop-group %s\n", nhgc->name);
+ if (nhgc->backup_list_name[0])
+ vty_out(vty, " backup-group %s\n",
+ nhgc->backup_list_name);
+
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
vty_out(vty, " ");
nexthop_group_write_nexthop_internal(vty, nh);
@@ -1067,6 +1141,8 @@ void nexthop_group_init(void (*new)(const char *name),
install_element(CONFIG_NODE, &no_nexthop_group_cmd);
install_default(NH_GROUP_NODE);
+ install_element(NH_GROUP_NODE, &nexthop_group_backup_cmd);
+ install_element(NH_GROUP_NODE, &no_nexthop_group_backup_cmd);
install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);
memset(&nhg_hooks, 0, sizeof(nhg_hooks));
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index f99a53f694..3a5a1299c1 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -57,6 +57,8 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg);
uint32_t nexthop_group_hash(const struct nexthop_group *nhg);
void nexthop_group_mark_duplicates(struct nexthop_group *nhg);
+
+/* Add a nexthop to a list, enforcing the canonical sort order. */
void nexthop_group_add_sorted(struct nexthop_group *nhg,
struct nexthop *nexthop);
@@ -79,11 +81,16 @@ void nexthop_group_add_sorted(struct nexthop_group *nhg,
(nhop) = nexthop_next(nhop)
+#define NHGC_NAME_SIZE 80
+
struct nexthop_group_cmd {
RB_ENTRY(nexthop_group_cmd) nhgc_entry;
- char name[80];
+ char name[NHGC_NAME_SIZE];
+
+ /* Name of group containing backup nexthops (if set) */
+ char backup_list_name[NHGC_NAME_SIZE];
struct nexthop_group nhg;
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index 089899368d..b195f1aeca 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -884,7 +884,14 @@ static int frr_grpc_finish(void)
return 0;
}
-static int frr_grpc_module_late_init(struct thread_master *tm)
+/*
+ * This is done this way because module_init and module_late_init are both
+ * called during daemon pre-fork initialization. Because the GRPC library
+ * spawns threads internally, we need to delay initializing it until after
+ * fork. This is done by scheduling this init function as an event task, since
+ * the event loop doesn't run until after fork.
+ */
+static int frr_grpc_module_very_late_init(struct thread *thread)
{
static unsigned long port = GRPC_DEFAULT_PORT;
const char *args = THIS_MODULE->load_args;
@@ -910,15 +917,19 @@ static int frr_grpc_module_late_init(struct thread_master *tm)
if (frr_grpc_init(&port) < 0)
goto error;
- hook_register(frr_fini, frr_grpc_finish);
-
- return 0;
-
error:
flog_err(EC_LIB_GRPC_INIT, "failed to initialize the gRPC module");
return -1;
}
+static int frr_grpc_module_late_init(struct thread_master *tm)
+{
+ thread_add_event(tm, frr_grpc_module_very_late_init, NULL, 0, NULL);
+ hook_register(frr_fini, frr_grpc_finish);
+
+ return 0;
+}
+
static int frr_grpc_module_init(void)
{
hook_register(frr_late_init, frr_grpc_module_late_init);
diff --git a/lib/plist.c b/lib/plist.c
index 40131aebed..b7a020c6f7 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -778,7 +778,7 @@ static void __attribute__((unused)) prefix_list_print(struct prefix_list *plist)
p = &pentry->prefix;
- printf(" seq %" PRId64 " %s %s/%d", pentry->seq,
+ printf(" seq %lld %s %s/%d", (long long)pentry->seq,
prefix_list_type_str(pentry),
inet_ntop(p->family, p->u.val, buf, BUFSIZ),
p->prefixlen);
diff --git a/lib/prefix.h b/lib/prefix.h
index b01f7d1fdc..f2952c38c3 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -531,7 +531,7 @@ static inline int is_host_route(struct prefix *p)
return 0;
}
-static inline int is_default_host_route(struct prefix *p)
+static inline int is_default_host_route(const struct prefix *p)
{
if (p->family == AF_INET) {
return (p->u.prefix4.s_addr == INADDR_ANY &&
@@ -544,6 +544,22 @@ static inline int is_default_host_route(struct prefix *p)
return 0;
}
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pI4" (struct in_addr *)
+#pragma FRR printfrr_ext "%pI4" (in_addr_t *)
+
+#pragma FRR printfrr_ext "%pI6" (struct in6_addr *)
+
+#pragma FRR printfrr_ext "%pFX" (struct prefix *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_ipv4 *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_ipv6 *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_eth *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_fs *)
+
+#pragma FRR printfrr_ext "%pSG4" (struct prefix_sg *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/printfrr.h b/lib/printfrr.h
index f9584bcacc..7d9e288655 100644
--- a/lib/printfrr.h
+++ b/lib/printfrr.h
@@ -30,8 +30,7 @@ struct fbuf {
size_t len;
};
-#define at(a, b) \
- __attribute__((format(printf, a, b)))
+#define at(a, b) PRINTFRR(a, b)
#define atn(a, b) \
at(a, b) __attribute__((nonnull(1) _RET_NONNULL))
#define atm(a, b) \
@@ -73,8 +72,19 @@ char *vasnprintfrr(struct memtype *mt, char *out, size_t sz,
char *asnprintfrr(struct memtype *mt, char *out, size_t sz,
const char *fmt, ...) atn(4, 5);
+#define printfrr(fmt, ...) \
+ do { \
+ char buf[256], *out; \
+ out = asnprintfrr(MTYPE_TMP, buf, sizeof(buf), fmt, \
+ ##__VA_ARGS__); \
+ fputs(out, stdout); \
+ if (out != buf) \
+ XFREE(MTYPE_TMP, out); \
+ } while (0)
+
#undef at
#undef atm
+#undef atn
/* extension specs must start with a capital letter (this is a restriction
* for both performance's and human understanding's sake.)
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 5b03b5266f..41e8cacd81 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -148,6 +148,12 @@ void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
SKIP_RULE("ipv6 next-hop type");
SKIP_RULE("metric");
SKIP_RULE("tag");
+ /* Zebra specific match conditions. */
+ SKIP_RULE("ip address prefix-len");
+ SKIP_RULE("ipv6 address prefix-len");
+ SKIP_RULE("ip next-hop prefix-len");
+ SKIP_RULE("source-protocol");
+ SKIP_RULE("source-instance");
vty_out(vty, " match %s %s\n", rmr->cmd->str,
rmr->rule_str ? rmr->rule_str : "");
@@ -158,6 +164,8 @@ void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
/* Skip all sets implemented by northbound. */
SKIP_RULE("metric");
SKIP_RULE("tag");
+ /* Zebra specific set actions. */
+ SKIP_RULE("src");
vty_out(vty, " set %s %s\n", rmr->cmd->str,
rmr->rule_str ? rmr->rule_str : "");
@@ -666,8 +674,25 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, " match tag %s\n",
yang_dnode_get_string(dnode, "./tag"));
break;
- case 100:
- /* NOTHING: custom field, should be handled by daemon. */
+ case 100: /* ipv4-prefix-length */
+ vty_out(vty, " match ip address prefix-len %s\n",
+ yang_dnode_get_string(dnode,"./frr-zebra:ipv4-prefix-length"));
+ break;
+ case 101: /* ipv6-prefix-length */
+ vty_out(vty, " match ipv6 address prefix-len %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:ipv6-prefix-length"));
+ break;
+ case 102: /* ipv4-next-hop-prefix-length */
+ vty_out(vty, " match ip next-hop prefix-len %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:ipv4-prefix-length"));
+ break;
+ case 103: /* source-protocol */
+ vty_out(vty, " match source-protocol %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:source-protocol"));
+ break;
+ case 104: /* source-instance */
+ vty_out(vty, " match source-instance %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:source-instance"));
break;
}
}
@@ -868,8 +893,13 @@ void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, " set tag %s\n",
yang_dnode_get_string(dnode, "./tag"));
break;
- case 100:
- /* NOTHING: custom field, should be handled by daemon. */
+ case 100: /* source */
+ if (yang_dnode_exists(dnode, "./frr-zebra:source-v4"))
+ vty_out(vty, " set src %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:source-v4"));
+ else
+ vty_out(vty, " set src %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:source-v6"));
break;
}
}
diff --git a/lib/skiplist.c b/lib/skiplist.c
index d955c6eb9e..fa25770efa 100644
--- a/lib/skiplist.c
+++ b/lib/skiplist.c
@@ -112,7 +112,7 @@ static int randomLevel(void)
return level;
}
-static int default_cmp(void *key1, void *key2)
+static int default_cmp(const void *key1, const void *key2)
{
if (key1 < key2)
return -1;
@@ -126,7 +126,8 @@ unsigned int skiplist_count(struct skiplist *l)
return l->count;
}
-struct skiplist *skiplist_new(int flags, int (*cmp)(void *key1, void *key2),
+struct skiplist *skiplist_new(int flags,
+ int (*cmp)(const void *key1, const void *key2),
void (*del)(void *val))
{
struct skiplist *new;
@@ -329,8 +330,8 @@ int skiplist_delete(register struct skiplist *l, register void *key,
* Also set a cursor for use with skiplist_next_value.
*/
int skiplist_first_value(register struct skiplist *l, /* in */
- register void *key, /* in */
- void **valuePointer, /* out */
+ register const void *key, /* in */
+ void **valuePointer, /* out */
void **cursor) /* out */
{
register int k;
@@ -374,7 +375,7 @@ int skiplist_search(register struct skiplist *l, register void *key,
* last element with the given key, -1 is returned.
*/
int skiplist_next_value(register struct skiplist *l, /* in */
- register void *key, /* in */
+ register const void *key, /* in */
void **valuePointer, /* in/out */
void **cursor) /* in/out */
{
diff --git a/lib/skiplist.h b/lib/skiplist.h
index 2ab37331c9..a106a455d6 100644
--- a/lib/skiplist.h
+++ b/lib/skiplist.h
@@ -68,7 +68,7 @@ struct skiplist {
* Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2.
* Used as definition of sorted for listnode_add_sort
*/
- int (*cmp)(void *val1, void *val2);
+ int (*cmp)(const void *val1, const void *val2);
/* callback to free user-owned data when listnode is deleted. supplying
* this callback is very much encouraged!
@@ -81,8 +81,9 @@ struct skiplist {
extern struct skiplist *
skiplist_new(/* encouraged: set list.del callback on new lists */
int flags,
- int (*cmp)(void *key1, void *key2), /* NULL => default cmp */
- void (*del)(void *val)); /* NULL => no auto val free */
+ int (*cmp)(const void *key1,
+ const void *key2), /* NULL => default cmp */
+ void (*del)(void *val)); /* NULL => no auto val free */
extern void skiplist_free(struct skiplist *);
@@ -96,12 +97,12 @@ extern int skiplist_search(register struct skiplist *l, register void *key,
void **valuePointer);
extern int skiplist_first_value(register struct skiplist *l, /* in */
- register void *key, /* in */
- void **valuePointer, /* in/out */
+ register const void *key, /* in */
+ void **valuePointer, /* in/out */
void **cursor); /* out */
extern int skiplist_next_value(register struct skiplist *l, /* in */
- register void *key, /* in */
+ register const void *key, /* in */
void **valuePointer, /* in/out */
void **cursor); /* in/out */
diff --git a/lib/smux.h b/lib/smux.h
index 3f860db0dc..6896f02354 100644
--- a/lib/smux.h
+++ b/lib/smux.h
@@ -105,7 +105,7 @@ extern int smux_trap(struct variable *, size_t, const oid *, size_t,
extern int oid_compare(const oid *, int, const oid *, int);
extern void oid2in_addr(oid[], int, struct in_addr *);
extern void *oid_copy(void *, const void *, size_t);
-extern void oid_copy_addr(oid[], struct in_addr *, int);
+extern void oid_copy_addr(oid[], const struct in_addr *, int);
#ifdef __cplusplus
}
diff --git a/lib/snmp.c b/lib/snmp.c
index f11d9dc8cf..736a3c62b8 100644
--- a/lib/snmp.c
+++ b/lib/snmp.c
@@ -64,10 +64,10 @@ void oid2in_addr(oid oid[], int len, struct in_addr *addr)
*pnt++ = oid[i];
}
-void oid_copy_addr(oid oid[], struct in_addr *addr, int len)
+void oid_copy_addr(oid oid[], const struct in_addr *addr, int len)
{
int i;
- uint8_t *pnt;
+ const uint8_t *pnt;
if (len == 0)
return;
diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c
index 41d4e2bb57..4e74714489 100644
--- a/lib/spf_backoff.c
+++ b/lib/spf_backoff.c
@@ -7,7 +7,7 @@
* Copyright (C) 2017 Orange Labs http://www.orange.com/
* Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc.
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/lib/spf_backoff.h b/lib/spf_backoff.h
index 11b2701e3e..2617195d79 100644
--- a/lib/spf_backoff.h
+++ b/lib/spf_backoff.h
@@ -7,7 +7,7 @@
* Copyright (C) 2017 Orange Labs http://www.orange.com/
* Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc.
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c
index ee87d73077..66b735919b 100644
--- a/lib/srcdest_table.c
+++ b/lib/srcdest_table.c
@@ -4,7 +4,7 @@
* Copyright (C) 2017 by David Lamparter & Christian Franke,
* Open Source Routing / NetDEF Inc.
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h
index 90418944c7..7982260777 100644
--- a/lib/srcdest_table.h
+++ b/lib/srcdest_table.h
@@ -4,7 +4,7 @@
* Copyright (C) 2017 by David Lamparter & Christian Franke,
* Open Source Routing / NetDEF Inc.
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/lib/stream.c b/lib/stream.c
index dd4d5bd96d..f046572f41 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -898,7 +898,7 @@ int stream_put_prefix(struct stream *s, const struct prefix *p)
}
/* Put NLRI with label */
-int stream_put_labeled_prefix(struct stream *s, struct prefix *p,
+int stream_put_labeled_prefix(struct stream *s, const struct prefix *p,
mpls_label_t *label, int addpath_encode,
uint32_t addpath_tx_id)
{
diff --git a/lib/stream.h b/lib/stream.h
index 36c65afa3c..6fcf9a53cf 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -196,7 +196,7 @@ extern int stream_put_prefix_addpath(struct stream *s,
int addpath_encode,
uint32_t addpath_tx_id);
extern int stream_put_prefix(struct stream *s, const struct prefix *p);
-extern int stream_put_labeled_prefix(struct stream *, struct prefix *,
+extern int stream_put_labeled_prefix(struct stream *, const struct prefix *,
mpls_label_t *, int addpath_encode,
uint32_t addpath_tx_id);
extern void stream_get(void *, struct stream *, size_t);
@@ -354,9 +354,10 @@ extern void stream_fifo_free(struct stream_fifo *fifo);
* bit), for 64-bit values (you need to cast them anyway), and neither for
* encoding (because it's downcasted.)
*/
-static inline uint8_t *ptr_get_be32(uint8_t *ptr, uint32_t *out)
+static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
{
uint32_t tmp;
+
memcpy(&tmp, ptr, sizeof(tmp));
*out = ntohl(tmp);
return ptr + 4;
diff --git a/lib/table.h b/lib/table.h
index 7743d51681..9cd9503376 100644
--- a/lib/table.h
+++ b/lib/table.h
@@ -331,6 +331,10 @@ static inline int route_table_iter_started(route_table_iter_t *iter)
return iter->state != RT_ITER_STATE_INIT;
}
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pRN" (struct route_node *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/thread.c b/lib/thread.c
index 2217a60f0a..dbf668a699 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -114,11 +114,10 @@ static void vty_out_cpu_thread_history(struct vty *vty,
struct cpu_thread_history *a)
{
vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu",
- (size_t)a->total_active,
- a->cpu.total / 1000, a->cpu.total % 1000,
- (size_t)a->total_calls,
- a->cpu.total / a->total_calls, a->cpu.max,
- a->real.total / a->total_calls, a->real.max);
+ (size_t)a->total_active, a->cpu.total / 1000,
+ a->cpu.total % 1000, (size_t)a->total_calls,
+ (size_t)(a->cpu.total / a->total_calls), a->cpu.max,
+ (size_t)(a->real.total / a->total_calls), a->real.max);
vty_out(vty, " %c%c%c%c%c %s\n",
a->types & (1 << THREAD_READ) ? 'R' : ' ',
a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
diff --git a/lib/vty.c b/lib/vty.c
index 4dd6ec1b35..8056236de9 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -231,8 +231,13 @@ int vty_out(struct vty *vty, const char *format, ...)
strlen(filtered));
break;
case VTY_SHELL:
- fprintf(vty->of, "%s", filtered);
- fflush(vty->of);
+ if (vty->of) {
+ fprintf(vty->of, "%s", filtered);
+ fflush(vty->of);
+ } else if (vty->of_saved) {
+ fprintf(vty->of_saved, "%s", filtered);
+ fflush(vty->of_saved);
+ }
break;
case VTY_SHELL_SERV:
case VTY_FILE:
diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c
index a308b18b73..2b502d635b 100644
--- a/lib/yang_wrappers.c
+++ b/lib/yang_wrappers.c
@@ -22,6 +22,7 @@
#include "log.h"
#include "lib_errors.h"
#include "northbound.h"
+#include "printfrr.h"
static const char *yang_get_default_value(const char *xpath)
{
@@ -443,7 +444,7 @@ struct yang_data *yang_data_new_int64(const char *xpath, int64_t value)
{
char value_str[BUFSIZ];
- snprintf(value_str, sizeof(value_str), "%" PRId64, value);
+ snprintfrr(value_str, sizeof(value_str), "%" PRId64, value);
return yang_data_new(xpath, value_str);
}
@@ -651,7 +652,7 @@ struct yang_data *yang_data_new_uint64(const char *xpath, uint64_t value)
{
char value_str[BUFSIZ];
- snprintf(value_str, sizeof(value_str), "%" PRIu64, value);
+ snprintfrr(value_str, sizeof(value_str), "%" PRIu64, value);
return yang_data_new(xpath, value_str);
}
diff --git a/lib/zclient.c b/lib/zclient.c
index eac6c7081d..d380267a70 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -52,7 +52,8 @@ static void zclient_event(enum event, struct zclient *);
static void zebra_interface_if_set_value(struct stream *s,
struct interface *ifp);
-struct zclient_options zclient_options_default = {.receive_notify = false};
+struct zclient_options zclient_options_default = {.receive_notify = false,
+ .synchronous = false};
struct sockaddr_storage zclient_addr;
socklen_t zclient_addr_len;
@@ -76,6 +77,7 @@ struct zclient *zclient_new(struct thread_master *master,
zclient->master = master;
zclient->receive_notify = opt->receive_notify;
+ zclient->synchronous = opt->synchronous;
return zclient;
}
@@ -374,11 +376,11 @@ static int zebra_message_send(struct zclient *zclient, int command,
return zclient_send_message(zclient);
}
-static int zebra_hello_send(struct zclient *zclient)
+int zclient_send_hello(struct zclient *zclient)
{
struct stream *s;
- if (zclient->redist_default) {
+ if (zclient->redist_default || zclient->synchronous) {
s = zclient->obuf;
stream_reset(s);
@@ -390,6 +392,10 @@ static int zebra_hello_send(struct zclient *zclient)
stream_putc(s, 1);
else
stream_putc(s, 0);
+ if (zclient->synchronous)
+ stream_putc(s, 1);
+ else
+ stream_putc(s, 0);
stream_putw_at(s, 0, stream_get_endp(s));
return zclient_send_message(zclient);
@@ -629,7 +635,7 @@ int zclient_start(struct zclient *zclient)
/* Create read thread. */
zclient_event(ZCLIENT_READ, zclient);
- zebra_hello_send(zclient);
+ zclient_send_hello(zclient);
zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, VRF_DEFAULT);
@@ -690,8 +696,9 @@ static int zclient_connect(struct thread *t)
return zclient_start(zclient);
}
-int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p,
- bool exact_match, vrf_id_t vrf_id)
+int zclient_send_rnh(struct zclient *zclient, int command,
+ const struct prefix *p, bool exact_match,
+ vrf_id_t vrf_id)
{
struct stream *s;
@@ -897,6 +904,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
}
}
+ /* If present, set 'weight' flag before encoding flags */
if (api_nh->weight)
SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_WEIGHT);
@@ -941,6 +949,10 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
stream_put(s, &(api_nh->rmac),
sizeof(struct ethaddr));
+ /* Index of backup nexthop */
+ if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
+ stream_putc(s, api_nh->backup_idx);
+
done:
return ret;
}
@@ -1000,6 +1012,10 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
return -1;
}
+ /* We canonicalize the nexthops by sorting them; this allows
+ * zebra to resolve the list of nexthops to a nexthop-group
+ * more efficiently.
+ */
zapi_nexthop_group_sort(api->nexthops, api->nexthop_num);
stream_putw(s, api->nexthop_num);
@@ -1026,6 +1042,50 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
}
}
+ /* Backup nexthops */
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) {
+ /* limit the number of nexthops if necessary */
+ if (api->backup_nexthop_num > MULTIPATH_NUM) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&api->prefix, buf, sizeof(buf));
+ flog_err(
+ EC_LIB_ZAPI_ENCODE,
+ "%s: prefix %s: can't encode %u backup nexthops (maximum is %u)",
+ __func__, buf, api->backup_nexthop_num,
+ MULTIPATH_NUM);
+ return -1;
+ }
+
+ /* Note that we do not sort the list of backup nexthops -
+ * this list is treated as an array and indexed by each
+ * primary nexthop that is associated with a backup.
+ */
+
+ stream_putw(s, api->backup_nexthop_num);
+
+ for (i = 0; i < api->backup_nexthop_num; i++) {
+ api_nh = &api->backup_nexthops[i];
+
+ /* MPLS labels for BGP-LU or Segment Routing */
+ if (api_nh->label_num > MPLS_MAX_LABELS) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&api->prefix, buf, sizeof(buf));
+
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: prefix %s: backup: can't encode %u labels (maximum is %u)",
+ __func__, buf,
+ api_nh->label_num,
+ MPLS_MAX_LABELS);
+ return -1;
+ }
+
+ if (zapi_nexthop_encode(s, api_nh, api->flags) != 0)
+ return -1;
+ }
+ }
+
/* Attributes. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
stream_putc(s, api->distance);
@@ -1101,6 +1161,10 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
STREAM_GET(&(api_nh->rmac), s,
sizeof(struct ethaddr));
+ /* Backup nexthop index */
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
+ STREAM_GETC(s, api_nh->backup_idx);
+
/* Success */
ret = 0;
@@ -1207,6 +1271,24 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
}
}
+ /* Backup nexthops. */
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) {
+ STREAM_GETW(s, api->backup_nexthop_num);
+ if (api->backup_nexthop_num > MULTIPATH_NUM) {
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: invalid number of backup nexthops (%u)",
+ __func__, api->backup_nexthop_num);
+ return -1;
+ }
+
+ for (i = 0; i < api->backup_nexthop_num; i++) {
+ api_nh = &api->backup_nexthops[i];
+
+ if (zapi_nexthop_decode(s, api_nh, api->flags) != 0)
+ return -1;
+ }
+ }
+
/* Attributes. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
STREAM_GETC(s, api->distance);
@@ -1381,7 +1463,7 @@ stream_failure:
return false;
}
-struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
+struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
{
struct nexthop *n = nexthop_new();
@@ -1398,6 +1480,11 @@ struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
znh->labels);
}
+ if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
+ SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ n->backup_idx = znh->backup_idx;
+ }
+
return n;
}
@@ -1413,10 +1500,16 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
znh->type = nh->type;
znh->vrf_id = nh->vrf_id;
+ znh->weight = nh->weight;
znh->ifindex = nh->ifindex;
znh->gate = nh->gate;
if (nh->nh_label && (nh->nh_label->num_labels > 0)) {
+
+ /* Validate */
+ if (nh->nh_label->num_labels > MPLS_MAX_LABELS)
+ return -1;
+
for (i = 0; i < nh->nh_label->num_labels; i++)
znh->labels[i] = nh->nh_label->label[i];
@@ -1424,10 +1517,31 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
}
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
+ znh->backup_idx = nh->backup_idx;
+ }
+
return 0;
}
/*
+ * Wrapper that converts backup nexthop
+ */
+int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh,
+ const struct nexthop *nh)
+{
+ int ret;
+
+ /* Ensure that zapi flags are correct: backups don't have backups */
+ ret = zapi_nexthop_from_nexthop(znh, nh);
+ if (ret == 0)
+ UNSET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
+
+ return ret;
+}
+
+/*
* Decode the nexthop-tracking update message
*/
bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
diff --git a/lib/zclient.h b/lib/zclient.h
index e6f4c747e3..e747809f16 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -255,6 +255,9 @@ struct zclient {
/* Do we care about failure events for route install? */
bool receive_notify;
+ /* Is this a synchronous client? */
+ bool synchronous;
+
/* Socket to zebra daemon. */
int sock;
@@ -338,6 +341,9 @@ struct zclient {
#define ZAPI_MESSAGE_TAG 0x08
#define ZAPI_MESSAGE_MTU 0x10
#define ZAPI_MESSAGE_SRCPFX 0x20
+/* Backup nexthops are present */
+#define ZAPI_MESSAGE_BACKUP_NEXTHOPS 0x40
+
/*
* This should only be used by a DAEMON that needs to communicate
* the table being used is not in the VRF. You must pass the
@@ -374,14 +380,21 @@ struct zapi_nexthop {
struct ethaddr rmac;
uint32_t weight;
+
+ /* Index of backup nexthop */
+ uint8_t backup_idx;
};
/*
- * ZAPI nexthop flags values
+ * ZAPI nexthop flags values - we're encoding a single octet
+ * initially, so ensure that the on-the-wire encoding continues
+ * to match the number of valid flags.
*/
+
#define ZAPI_NEXTHOP_FLAG_ONLINK 0x01
#define ZAPI_NEXTHOP_FLAG_LABEL 0x02
#define ZAPI_NEXTHOP_FLAG_WEIGHT 0x04
+#define ZAPI_NEXTHOP_FLAG_HAS_BACKUP 0x08 /* Nexthop has a backup */
/*
* Some of these data structures do not map easily to
@@ -445,6 +458,10 @@ struct zapi_route {
uint16_t nexthop_num;
struct zapi_nexthop nexthops[MULTIPATH_NUM];
+ /* Support backup routes for IP FRR, TI-LFA, traffic engineering */
+ uint16_t backup_nexthop_num;
+ struct zapi_nexthop backup_nexthops[MULTIPATH_NUM];
+
uint8_t distance;
uint32_t metric;
@@ -569,6 +586,7 @@ enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
struct zclient_options {
bool receive_notify;
+ bool synchronous;
};
extern struct zclient_options zclient_options_default;
@@ -738,7 +756,7 @@ extern void zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_statu
extern int zclient_route_send(uint8_t, struct zclient *, struct zapi_route *);
extern int zclient_send_rnh(struct zclient *zclient, int command,
- struct prefix *p, bool exact_match,
+ const struct prefix *p, bool exact_match,
vrf_id_t vrf_id);
int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
uint32_t api_flags);
@@ -765,9 +783,12 @@ bool zapi_iptable_notify_decode(struct stream *s,
uint32_t *unique,
enum zapi_iptable_notify_owner *note);
-extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh);
+extern struct nexthop *
+nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh);
int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
const struct nexthop *nh);
+int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh,
+ const struct nexthop *nh);
extern bool zapi_nexthop_update_decode(struct stream *s,
struct zapi_route *nhr);
@@ -796,4 +817,9 @@ extern void zclient_send_mlag_deregister(struct zclient *client);
extern void zclient_send_mlag_data(struct zclient *client,
struct stream *client_s);
+/* Send the hello message.
+ * Returns 0 for success or -1 on an I/O error.
+ */
+extern int zclient_send_hello(struct zclient *client);
+
#endif /* _ZEBRA_ZCLIENT_H */
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index ead186b6fc..9721446112 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -1427,7 +1427,7 @@ void install_element_ospf6_debug_abr(void)
install_element(CONFIG_NODE, &no_debug_ospf6_abr_cmd);
}
-static const struct ospf6_lsa_handler inter_prefix_handler = {
+static struct ospf6_lsa_handler inter_prefix_handler = {
.lh_type = OSPF6_LSTYPE_INTER_PREFIX,
.lh_name = "Inter-Prefix",
.lh_short_name = "IAP",
@@ -1435,7 +1435,7 @@ static const struct ospf6_lsa_handler inter_prefix_handler = {
.lh_get_prefix_str = ospf6_inter_area_prefix_lsa_get_prefix_str,
.lh_debug = 0};
-static const struct ospf6_lsa_handler inter_router_handler = {
+static struct ospf6_lsa_handler inter_router_handler = {
.lh_type = OSPF6_LSTYPE_INTER_ROUTER,
.lh_name = "Inter-Router",
.lh_short_name = "IAR",
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 805e411c7b..e059bfbc55 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -1853,7 +1853,7 @@ DEFUN (show_ipv6_ospf6_redistribute,
return CMD_SUCCESS;
}
-static const struct ospf6_lsa_handler as_external_handler = {
+static struct ospf6_lsa_handler as_external_handler = {
.lh_type = OSPF6_LSTYPE_AS_EXTERNAL,
.lh_name = "AS-External",
.lh_short_name = "ASE",
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index 9c239b75ff..b700899ccf 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -2235,7 +2235,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
__func__, oa->name);
}
-static const struct ospf6_lsa_handler router_handler = {
+static struct ospf6_lsa_handler router_handler = {
.lh_type = OSPF6_LSTYPE_ROUTER,
.lh_name = "Router",
.lh_short_name = "Rtr",
@@ -2243,7 +2243,7 @@ static const struct ospf6_lsa_handler router_handler = {
.lh_get_prefix_str = ospf6_router_lsa_get_nbr_id,
.lh_debug = 0};
-static const struct ospf6_lsa_handler network_handler = {
+static struct ospf6_lsa_handler network_handler = {
.lh_type = OSPF6_LSTYPE_NETWORK,
.lh_name = "Network",
.lh_short_name = "Net",
@@ -2251,7 +2251,7 @@ static const struct ospf6_lsa_handler network_handler = {
.lh_get_prefix_str = ospf6_network_lsa_get_ar_id,
.lh_debug = 0};
-static const struct ospf6_lsa_handler link_handler = {
+static struct ospf6_lsa_handler link_handler = {
.lh_type = OSPF6_LSTYPE_LINK,
.lh_name = "Link",
.lh_short_name = "Lnk",
@@ -2259,7 +2259,7 @@ static const struct ospf6_lsa_handler link_handler = {
.lh_get_prefix_str = ospf6_link_lsa_get_prefix_str,
.lh_debug = 0};
-static const struct ospf6_lsa_handler intra_prefix_handler = {
+static struct ospf6_lsa_handler intra_prefix_handler = {
.lh_type = OSPF6_LSTYPE_INTRA_PREFIX,
.lh_name = "Intra-Prefix",
.lh_short_name = "INP",
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index 9acbd09b1a..c63ea47f29 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -77,16 +77,16 @@ static struct ospf6_lsa_handler unknown_handler = {
.lh_debug = 0 /* No default debug */
};
-void ospf6_install_lsa_handler(const struct ospf6_lsa_handler *handler)
+void ospf6_install_lsa_handler(struct ospf6_lsa_handler *handler)
{
/* type in handler is host byte order */
int index = handler->lh_type & OSPF6_LSTYPE_FCODE_MASK;
vector_set_index(ospf6_lsa_handler_vector, index, (void *)handler);
}
-const struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type)
+struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type)
{
- const struct ospf6_lsa_handler *handler = NULL;
+ struct ospf6_lsa_handler *handler = NULL;
unsigned int index = ntohs(type) & OSPF6_LSTYPE_FCODE_MASK;
if (index >= vector_active(ospf6_lsa_handler_vector))
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index d871a8842e..02f9f9d26c 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -237,8 +237,8 @@ extern int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *);
extern int ospf6_lsa_prohibited_duration(uint16_t type, uint32_t id,
uint32_t adv_router, void *scope);
-extern void ospf6_install_lsa_handler(const struct ospf6_lsa_handler *handler);
-extern const struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type);
+extern void ospf6_install_lsa_handler(struct ospf6_lsa_handler *handler);
+extern struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type);
extern void ospf6_lsa_init(void);
extern void ospf6_lsa_terminate(void);
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 96eee51929..dc10fa52cb 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -52,8 +52,8 @@
DEFINE_QOBJ_TYPE(ospf6)
FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES,
- { .val_long = true, .match_profile = "datacenter", },
- { .val_long = false },
+ { .val_bool = true, .match_profile = "datacenter", },
+ { .val_bool = false },
)
/* global ospf6d variable */
diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c
index 2c80d485a3..30940cf010 100644
--- a/ospfd/ospf_ase.c
+++ b/ospfd/ospf_ase.c
@@ -691,7 +691,7 @@ static int ospf_ase_calculate_timer(struct thread *t)
if (IS_DEBUG_OSPF_EVENT)
zlog_info(
- "SPF Processing Time(usecs): External Routes: %lld\n",
+ "SPF Processing Time(usecs): External Routes: %lld",
(stop_time.tv_sec - start_time.tv_sec)
* 1000000LL
+ (stop_time.tv_usec
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 55ec638522..d50f390e30 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -2805,7 +2805,7 @@ static int ospf_maxage_lsa_remover(struct thread *thread)
if (CHECK_FLAG(lsa->flags, OSPF_LSA_PREMATURE_AGE)) {
if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
zlog_debug(
- "originating new lsa for lsa 0x%p\n",
+ "originating new lsa for lsa 0x%p",
(void *)lsa);
ospf_lsa_refresh(ospf, lsa);
}
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 0808f245e2..aa50aeacbc 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -611,7 +611,7 @@ static void ospf_write_frags(int fd, struct ospf_packet *op, struct ip *iph,
if (IS_DEBUG_OSPF_PACKET(type - 1, SEND)) {
zlog_debug(
- "ospf_write_frags: sent id %d, off %d, len %d to %s\n",
+ "ospf_write_frags: sent id %d, off %d, len %d to %s",
iph->ip_id, iph->ip_off, iph->ip_len,
inet_ntoa(iph->ip_dst));
}
diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c
index 5f01edfbdf..fbe513cea0 100644
--- a/ospfd/ospf_ri.c
+++ b/ospfd/ospf_ri.c
@@ -1382,9 +1382,8 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
zlog_debug(" Algorithm %d: Strict SPF", i);
break;
default:
- zlog_debug(
- " Algorithm %d: Unknown value %d\n",
- i, algo->value[i]);
+ zlog_debug(" Algorithm %d: Unknown value %d",
+ i, algo->value[i]);
break;
}
}
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index b6e8338ee7..a661c80a91 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -631,27 +631,15 @@ void ospf_route_table_dump(struct route_table *rt)
{
struct route_node *rn;
struct ospf_route * or ;
- char buf1[BUFSIZ];
- char buf2[BUFSIZ];
struct listnode *pnode;
struct ospf_path *path;
-#if 0
- zlog_debug ("Type Dest Area Path Type Cost Next Adv.");
- zlog_debug (" Hop(s) Router(s)");
-#endif /* 0 */
-
zlog_debug("========== OSPF routing table ==========");
for (rn = route_top(rt); rn; rn = route_next(rn))
if ((or = rn->info) != NULL) {
if (or->type == OSPF_DESTINATION_NETWORK) {
- zlog_debug("N %s/%d\t%s\t%s\t%d",
- inet_ntop(AF_INET, &rn->p.u.prefix4,
- buf1, BUFSIZ),
- rn->p.prefixlen,
- inet_ntop(AF_INET,
- & or->u.std.area_id, buf2,
- BUFSIZ),
+ zlog_debug("N %-18pFX %-15pI4 %s %d", &rn->p,
+ &or->u.std.area_id,
ospf_path_type_str[or->path_type],
or->cost);
for (ALL_LIST_ELEMENTS_RO(or->paths, pnode,
@@ -659,12 +647,9 @@ void ospf_route_table_dump(struct route_table *rt)
zlog_debug(" -> %s",
inet_ntoa(path->nexthop));
} else
- zlog_debug("R %s\t%s\t%s\t%d",
- inet_ntop(AF_INET, &rn->p.u.prefix4,
- buf1, BUFSIZ),
- inet_ntop(AF_INET,
- & or->u.std.area_id, buf2,
- BUFSIZ),
+ zlog_debug("R %-18pI4 %-15pI4 %s %d",
+ &rn->p.u.prefix4,
+ &or->u.std.area_id,
ospf_path_type_str[or->path_type],
or->cost);
}
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 8b605b3bac..ae70a5c789 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -1401,13 +1401,13 @@ static int ospf_spf_calculate_timer(struct thread *thread)
if (IS_DEBUG_OSPF_EVENT) {
zlog_info("SPF Processing Time(usecs): %ld", total_spf_time);
- zlog_info("\t SPF Time: %ld", spf_time);
- zlog_info("\t InterArea: %ld", ia_time);
- zlog_info("\t Prune: %ld", prune_time);
- zlog_info("\tRouteInstall: %ld", rt_time);
+ zlog_info(" SPF Time: %ld", spf_time);
+ zlog_info(" InterArea: %ld", ia_time);
+ zlog_info(" Prune: %ld", prune_time);
+ zlog_info(" RouteInstall: %ld", rt_time);
if (IS_OSPF_ABR(ospf))
- zlog_info("\t ABR: %ld (%d areas)", abr_time,
- areas_processed);
+ zlog_info(" ABR: %ld (%d areas)",
+ abr_time, areas_processed);
zlog_info("Reason(s) for SPF: %s", rbuf);
}
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
index 8da99843e6..a2084e3214 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -1780,7 +1780,7 @@ static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty,
i, fval1, i + 1, fval2);
else
zlog_debug(
- " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)",
+ " [%d]: %g (Bytes/sec), [%d]: %g (Bytes/sec)",
i, fval1, i + 1, fval2);
}
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 75f556e39f..ea73834a66 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -54,8 +54,8 @@
#include "ospfd/ospf_bfd.h"
FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
- { .val_long = true, .match_profile = "datacenter", },
- { .val_long = false },
+ { .val_bool = true, .match_profile = "datacenter", },
+ { .val_bool = false },
)
static const char *const ospf_network_type_str[] = {
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index e395b7831d..dfc8bec1bc 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -423,7 +423,6 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
"Use the interface's VRF for lookup\n")
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
- int ret = CMD_SUCCESS;
if (no) {
pbr_map_delete_vrf(pbrms);
@@ -434,28 +433,51 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
pbrms->vrf_lookup = false;
pbrms->vrf_unchanged = false;
- goto done;
+ return CMD_SUCCESS;
}
if (pbrms->nhgrp_name || pbrms->nhg) {
vty_out(vty,
"A `set nexthop/nexthop-group XX` command already exits, please remove that first\n");
- ret = CMD_WARNING_CONFIG_FAILED;
- goto done;
+ return CMD_WARNING_CONFIG_FAILED;
}
- if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
- vty_out(vty, SET_VRF_EXISTS_STR);
- ret = CMD_WARNING_CONFIG_FAILED;
- goto done;
+ /*
+ * Determine if a set vrf * command already exists.
+ *
+ * If its equivalent, just return success.
+ *
+ * Else, return failure, we don't allow atomic swaps yet.
+ */
+ if (vrf_name && pbrms->vrf_lookup) {
+ /* New vrf specified and one already exists */
+
+ /* Is this vrf different from one already configured? */
+ if (strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name))
+ != 0)
+ goto vrf_exists;
+
+ return CMD_SUCCESS;
+
+ } else if (!vrf_name && pbrms->vrf_unchanged) {
+ /* Unchanged specified and unchanged already exists */
+ return CMD_SUCCESS;
+
+ } else if (vrf_name && pbrms->vrf_unchanged) {
+ /* New vrf specified and unchanged is already set */
+ goto vrf_exists;
+
+ } else if (!vrf_name && pbrms->vrf_lookup) {
+ /* Unchanged specified and vrf to lookup already exists */
+ goto vrf_exists;
}
+ /* Create new lookup VRF or Unchanged */
if (vrf_name) {
if (!pbr_vrf_lookup_by_name(vrf_name)) {
vty_out(vty, "Specified: %s is non-existent\n",
vrf_name);
- ret = CMD_WARNING_CONFIG_FAILED;
- goto done;
+ return CMD_WARNING_CONFIG_FAILED;
}
pbrms->vrf_lookup = true;
@@ -465,8 +487,11 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
pbr_map_check(pbrms);
-done:
- return ret;
+ return CMD_SUCCESS;
+
+vrf_exists:
+ vty_out(vty, SET_VRF_EXISTS_STR);
+ return CMD_WARNING_CONFIG_FAILED;
}
DEFPY (pbr_policy,
diff --git a/pimd/README b/pimd/README
index 3d03979a9a..1db0aad83c 100644
--- a/pimd/README
+++ b/pimd/README
@@ -33,7 +33,7 @@ HOME SITE
qpimd lives at:
- https://github.com/freerangerouting/frr
+ https://github.com/frrouting/frr
PLATFORMS
@@ -57,7 +57,7 @@ SUPPORT
Please post comments, questions, patches, bug reports at the
support site:
- https://freerangerouting/frr
+ https://frrouting.org/frr
RELATED WORK
diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c
index bcf11aedbd..ad47427101 100644
--- a/pimd/pim_bsm.c
+++ b/pimd/pim_bsm.c
@@ -601,7 +601,8 @@ static bool is_preferred_bsr(struct pim_instance *pim, struct in_addr bsr,
return true;
else if (bsr_prio == pim->global_scope.current_bsr_prio) {
- if (bsr.s_addr >= pim->global_scope.current_bsr.s_addr)
+ if (ntohl(bsr.s_addr)
+ >= ntohl(pim->global_scope.current_bsr.s_addr))
return true;
else
return false;
@@ -874,6 +875,17 @@ static void pim_bsm_fwd_whole_sz(struct pim_instance *pim, uint8_t *buf,
pim_ifp = ifp->info;
if ((!pim_ifp) || (!pim_ifp->bsm_enable))
continue;
+
+ /*
+ * RFC 5059 Sec 3.4:
+ * When a Bootstrap message is forwarded, it is forwarded out
+ * of every multicast-capable interface that has PIM neighbors.
+ *
+ * So skipping pim interfaces with no neighbors.
+ */
+ if (listcount(pim_ifp->pim_neighbor_list) == 0)
+ continue;
+
pim_hello_require(ifp);
pim_mtu = ifp->mtu - MAX_IP_HDR_LEN;
if (pim_mtu < len) {
@@ -1056,13 +1068,13 @@ static bool pim_install_bsm_grp_rp(struct pim_instance *pim,
if (listnode_add_sort_nodup(grpnode->partial_bsrp_list, bsm_rpinfo)) {
if (PIM_DEBUG_BSM)
zlog_debug(
- "%s, bs_rpinfo node added to the partial bs_rplist.\r\n",
+ "%s, bs_rpinfo node added to the partial bs_rplist.",
__func__);
return true;
}
if (PIM_DEBUG_BSM)
- zlog_debug("%s: list node not added\n", __func__);
+ zlog_debug("%s: list node not added", __func__);
XFREE(MTYPE_PIM_BSRP_NODE, bsm_rpinfo);
return false;
@@ -1080,7 +1092,7 @@ static void pim_update_pending_rp_cnt(struct bsm_scope *sz,
if (bsm_frag_tag != bsgrp->frag_tag) {
if (PIM_DEBUG_BSM)
zlog_debug(
- "%s,Received a new BSM ,so clear the pending bs_rpinfo list.\r\n",
+ "%s,Received a new BSM ,so clear the pending bs_rpinfo list.",
__func__);
list_delete_all_node(bsgrp->partial_bsrp_list);
bsgrp->pend_rp_cnt = total_rp_count;
@@ -1120,7 +1132,7 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
pim_inet4_dump("<Group?>", grpinfo.group.addr, grp_str,
sizeof(grp_str));
zlog_debug(
- "%s, Group %s Rpcount:%d Fragment-Rp-count:%d\r\n",
+ "%s, Group %s Rpcount:%d Fragment-Rp-count:%d",
__func__, grp_str, grpinfo.rp_count,
grpinfo.frag_rp_count);
}
@@ -1134,9 +1146,8 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
pim_inet4_dump("<Group?>", grpinfo.group.addr,
grp_str, sizeof(grp_str));
- zlog_debug(
- "%s, Rp count is zero for group: %s\r\n",
- __func__, grp_str);
+ zlog_debug("%s, Rp count is zero for group: %s",
+ __func__, grp_str);
}
return false;
}
@@ -1157,9 +1168,8 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
if (!bsgrp) {
if (PIM_DEBUG_BSM)
- zlog_debug(
- "%s, Create new BSM Group node.\r\n",
- __func__);
+ zlog_debug("%s, Create new BSM Group node.",
+ __func__);
/* create a new node to be added to the tree. */
bsgrp = pim_bsm_new_bsgrp_node(scope->bsrp_table,
@@ -1167,7 +1177,7 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
if (!bsgrp) {
zlog_debug(
- "%s, Failed to get the BSM group node.\r\n",
+ "%s, Failed to get the BSM group node.",
__func__);
continue;
}
@@ -1202,7 +1212,7 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
pim_inet4_dump("<Rpaddr?>", rpinfo.rpaddr.addr,
rp_str, sizeof(rp_str));
zlog_debug(
- "%s, Rp address - %s; pri:%d hold:%d\r\n",
+ "%s, Rp address - %s; pri:%d hold:%d",
__func__, rp_str, rpinfo.rp_pri,
rpinfo.rp_holdtime);
}
@@ -1366,7 +1376,7 @@ int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf,
(buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN),
frag_tag)) {
if (PIM_DEBUG_BSM) {
- zlog_debug("%s, Parsing BSM failed.\r\n", __func__);
+ zlog_debug("%s, Parsing BSM failed.", __func__);
}
pim->bsm_dropped++;
return -1;
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 8bfad8ee27..0c14aff9ff 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -3023,7 +3023,7 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
}
for (ALL_LIST_ELEMENTS_RO(pim->global_scope.bsm_list, bsmnode, bsm)) {
- char grp_str[INET_ADDRSTRLEN];
+ char grp_str[PREFIX_STRLEN];
char rp_str[INET_ADDRSTRLEN];
char bsr_str[INET_ADDRSTRLEN];
struct bsmmsg_grpinfo *group;
@@ -3192,7 +3192,7 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
if (!bsgrp)
continue;
- char grp_str[INET_ADDRSTRLEN];
+ char grp_str[PREFIX_STRLEN];
prefix2str(&bsgrp->group, grp_str, sizeof(grp_str));
@@ -5807,7 +5807,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
vty_out(vty,
" R - RP-bit set, F - Register flag, T - SPT-bit set\n");
vty_out(vty,
- "\nSource Group Flags Proto Input Output TTL Uptime\n");
+ "\nSource Group Flags Proto Input Output TTL Uptime\n");
}
now = pim_time_monotonic_sec();
@@ -7289,11 +7289,20 @@ DEFUN (no_ip_pim_ecmp_rebalance,
static int pim_cmd_igmp_start(struct vty *vty, struct interface *ifp)
{
struct pim_interface *pim_ifp;
+ struct pim_instance *pim;
uint8_t need_startup = 0;
pim_ifp = ifp->info;
if (!pim_ifp) {
+ pim = pim_get_pim_instance(ifp->vrf_id);
+ /* Limit mcast interfaces to number of vifs available */
+ if (pim->mcast_if_count == MAXVIFS) {
+ vty_out(vty,
+ "Max multicast interfaces(%d) Reached. Could not enable IGMP on interface %s\n",
+ MAXVIFS, ifp->name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
(void)pim_if_new(ifp, true, false, false, false);
need_startup = 1;
} else {
@@ -8043,13 +8052,21 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate,
return CMD_SUCCESS;
}
-static int pim_cmd_interface_add(struct interface *ifp)
+static int pim_cmd_interface_add(struct vty *vty, struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
+ struct pim_instance *pim;
- if (!pim_ifp)
+ if (!pim_ifp) {
+ pim = pim_get_pim_instance(ifp->vrf_id);
+ /* Limiting mcast interfaces to number of VIFs */
+ if (pim->mcast_if_count == MAXVIFS) {
+ vty_out(vty, "Max multicast interfaces(%d) reached.",
+ MAXVIFS);
+ return 0;
+ }
pim_ifp = pim_if_new(ifp, false, true, false, false);
- else
+ } else
PIM_IF_DO_PIM(pim_ifp->options);
pim_if_addr_add_all(ifp);
@@ -8120,15 +8137,17 @@ DEFPY (interface_ip_pim_activeactive,
VTY_DECLVAR_CONTEXT(interface, ifp);
struct pim_interface *pim_ifp;
- if (!no && !pim_cmd_interface_add(ifp)) {
- vty_out(vty, "Could not enable PIM SM active-active on interface\n");
+ if (!no && !pim_cmd_interface_add(vty, ifp)) {
+ vty_out(vty,
+ "Could not enable PIM SM active-active on interface %s\n",
+ ifp->name);
return CMD_WARNING_CONFIG_FAILED;
}
- if (PIM_DEBUG_MLAG)
- zlog_debug("%sConfiguring PIM active-active on Interface: %s",
- no ? "Un-":" ", ifp->name);
+ if (PIM_DEBUG_MLAG)
+ zlog_debug("%sConfiguring PIM active-active on Interface: %s",
+ no ? "Un-" : " ", ifp->name);
pim_ifp = ifp->info;
if (no)
@@ -8148,8 +8167,9 @@ DEFUN_HIDDEN (interface_ip_pim_ssm,
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- if (!pim_cmd_interface_add(ifp)) {
- vty_out(vty, "Could not enable PIM SM on interface\n");
+ if (!pim_cmd_interface_add(vty, ifp)) {
+ vty_out(vty, "Could not enable PIM SM on interface %s\n",
+ ifp->name);
return CMD_WARNING_CONFIG_FAILED;
}
@@ -8165,8 +8185,9 @@ static int interface_ip_pim_helper(struct vty *vty)
VTY_DECLVAR_CONTEXT(interface, ifp);
- if (!pim_cmd_interface_add(ifp)) {
- vty_out(vty, "Could not enable PIM SM on interface\n");
+ if (!pim_cmd_interface_add(vty, ifp)) {
+ vty_out(vty, "Could not enable PIM SM on interface %s\n",
+ ifp->name);
return CMD_WARNING_CONFIG_FAILED;
}
@@ -8454,8 +8475,10 @@ DEFUN (interface_ip_pim_hello,
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp) {
- if (!pim_cmd_interface_add(ifp)) {
- vty_out(vty, "Could not enable PIM SM on interface\n");
+ if (!pim_cmd_interface_add(vty, ifp)) {
+ vty_out(vty,
+ "Could not enable PIM SM on interface %s\n",
+ ifp->name);
return CMD_WARNING_CONFIG_FAILED;
}
}
@@ -9197,8 +9220,10 @@ DEFUN (ip_pim_bfd,
struct bfd_info *bfd_info = NULL;
if (!pim_ifp) {
- if (!pim_cmd_interface_add(ifp)) {
- vty_out(vty, "Could not enable PIM SM on interface\n");
+ if (!pim_cmd_interface_add(vty, ifp)) {
+ vty_out(vty,
+ "Could not enable PIM SM on interface %s\n",
+ ifp->name);
return CMD_WARNING;
}
}
@@ -9248,8 +9273,10 @@ DEFUN (ip_pim_bsm,
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp) {
- if (!pim_cmd_interface_add(ifp)) {
- vty_out(vty, "Could not enable PIM SM on interface\n");
+ if (!pim_cmd_interface_add(vty, ifp)) {
+ vty_out(vty,
+ "Could not enable PIM SM on interface %s\n",
+ ifp->name);
return CMD_WARNING;
}
}
@@ -9292,8 +9319,10 @@ DEFUN (ip_pim_ucast_bsm,
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp) {
- if (!pim_cmd_interface_add(ifp)) {
- vty_out(vty, "Could not enable PIM SM on interface\n");
+ if (!pim_cmd_interface_add(vty, ifp)) {
+ vty_out(vty,
+ "Could not enable PIM SM on interface %s\n",
+ ifp->name);
return CMD_WARNING;
}
}
@@ -9360,8 +9389,10 @@ DEFUN(
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp) {
- if (!pim_cmd_interface_add(ifp)) {
- vty_out(vty, "Could not enable PIM SM on interface\n");
+ if (!pim_cmd_interface_add(vty, ifp)) {
+ vty_out(vty,
+ "Could not enable PIM SM on interface %s\n",
+ ifp->name);
return CMD_WARNING;
}
}
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index cb31878e01..07c4172f22 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -186,6 +186,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
pim_sock_reset(ifp);
pim_if_add_vif(ifp, ispimreg, is_vxlan_term);
+ pim_ifp->pim->mcast_if_count++;
return pim_ifp;
}
@@ -209,6 +210,7 @@ void pim_if_delete(struct interface *ifp)
pim_neighbor_delete_all(ifp, "Interface removed from configuration");
pim_if_del_vif(ifp);
+ pim_ifp->pim->mcast_if_count--;
list_delete(&pim_ifp->igmp_socket_list);
list_delete(&pim_ifp->pim_neighbor_list);
@@ -275,7 +277,7 @@ static void pim_addr_change(struct interface *ifp)
1) Before an interface goes down or changes primary IP address, a
Hello message with a zero HoldTime should be sent immediately
(with the old IP address if the IP address changed).
- -- FIXME See CAVEAT C13
+ -- Done at the caller of the function as new ip already updated here
2) After an interface has changed its IP address, it MUST send a
Hello message with its new IP address.
@@ -320,6 +322,10 @@ static int detect_primary_address_change(struct interface *ifp,
}
if (changed) {
+ /* Before updating pim_ifp send Hello time with 0 hold time */
+ if (PIM_IF_TEST_PIM(pim_ifp->options)) {
+ pim_hello_send(ifp, 0 /* zero-sec holdtime */);
+ }
pim_ifp->primary_address = new_prim_addr;
}
@@ -1583,8 +1589,14 @@ int pim_ifp_create(struct interface *ifp)
}
if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME,
- sizeof(PIM_VXLAN_TERM_DEV_NAME)))
- pim_vxlan_add_term_dev(pim, ifp);
+ sizeof(PIM_VXLAN_TERM_DEV_NAME))) {
+ if (pim->mcast_if_count < MAXVIFS)
+ pim_vxlan_add_term_dev(pim, ifp);
+ else
+ zlog_warn(
+ "%s: Cannot enable pim on %s. MAXVIFS(%d) reached. Deleting and readding the vxlan termimation device after unconfiguring pim from other interfaces may succeed.",
+ __func__, ifp->name, MAXVIFS);
+ }
return 0;
}
diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c
index 2cda628a90..b4c2dd28cc 100644
--- a/pimd/pim_instance.c
+++ b/pimd/pim_instance.c
@@ -83,6 +83,7 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf)
pim_if_init(pim);
+ pim->mcast_if_count = 0;
pim->keep_alive_time = PIM_KEEPALIVE_PERIOD;
pim->rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h
index 48dc2d9530..71bd7c1089 100644
--- a/pimd/pim_instance.h
+++ b/pimd/pim_instance.h
@@ -168,6 +168,7 @@ struct pim_instance {
struct route_table *rp_table;
int iface_vif_index[MAXVIFS];
+ int mcast_if_count;
struct rb_pim_oil_head channel_oil_head;
diff --git a/pimd/pim_join.c b/pimd/pim_join.c
index 62bd2360c3..3a88de2070 100644
--- a/pimd/pim_join.c
+++ b/pimd/pim_join.c
@@ -140,18 +140,19 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh,
if ((source_flags & PIM_RPT_BIT_MASK)
&& (source_flags & PIM_WILDCARD_BIT_MASK)) {
- struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
+ /*
+ * RFC 4601 Section 4.5.2:
+ * Received Prune(*,G) messages are processed even if the
+ * RP in the message does not match RP(G).
+ */
+ if (PIM_DEBUG_PIM_TRACE) {
+ char received_rp[INET_ADDRSTRLEN];
- if (!rp) {
- if (PIM_DEBUG_PIM_TRACE)
- zlog_debug(
- "%s: RP for %pSG4 completely failed lookup",
- __func__, sg);
- return;
+ pim_inet4_dump("<received?>", sg->src, received_rp,
+ sizeof(received_rp));
+ zlog_debug("%s: Prune received with RP(%s) for %pSG4",
+ __func__, received_rp, sg);
}
- // Ignoring Prune *,G's at the moment.
- if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
- return;
sg->src.s_addr = INADDR_ANY;
}
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index 2e08ae28be..9060b6a95a 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -232,6 +232,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
pim_upstream_mroute_iif_update(up->channel_oil, __func__);
}
pim_register_join(up);
+ /* if we have receiver, inherit from parent */
+ pim_upstream_inherited_olist_decide(pim_ifp->pim, up);
return 0;
}
@@ -484,7 +486,10 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
struct pim_upstream *parent;
struct pim_nexthop source;
struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
- if (!rpf || !rpf->source_nexthop.interface)
+
+ /* No RPF or No RPF interface or No mcast on RPF interface */
+ if (!rpf || !rpf->source_nexthop.interface
+ || !rpf->source_nexthop.interface->info)
return 0;
/*
diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c
index ca7ca11402..d8a797f980 100644
--- a/pimd/pim_neighbor.c
+++ b/pimd/pim_neighbor.c
@@ -779,6 +779,7 @@ void pim_neighbor_update(struct pim_neighbor *neigh,
uint32_t dr_priority, struct list *addr_list)
{
struct pim_interface *pim_ifp = neigh->interface->info;
+ uint32_t old, new;
/* Received holdtime ? */
if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
@@ -818,6 +819,16 @@ void pim_neighbor_update(struct pim_neighbor *neigh,
neigh->prefix_list = addr_list;
update_dr_priority(neigh, hello_options, dr_priority);
+ new = PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
+ old = PIM_OPTION_IS_SET(neigh->hello_options,
+ PIM_OPTION_MASK_LAN_PRUNE_DELAY);
+
+ if (old != new) {
+ if (old)
+ ++pim_ifp->pim_number_of_nonlandelay_neighbors;
+ else
+ --pim_ifp->pim_number_of_nonlandelay_neighbors;
+ }
/*
Copy flags
*/
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 8d7a921cf4..f37c140bf2 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -42,7 +42,6 @@
#include "pim_bsm.h"
static int on_pim_hello_send(struct thread *t);
-static int pim_hello_send(struct interface *ifp, uint16_t holdtime);
static const char *pim_pim_msgtype2str(enum pim_msg_type type)
{
@@ -137,6 +136,18 @@ void pim_sock_delete(struct interface *ifp, const char *delete_message)
sock_close(ifp);
}
+/* For now check dst address for hello, assrt and join/prune is all pim rtr */
+static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, in_addr_t addr)
+{
+ if ((type == PIM_MSG_TYPE_HELLO) || (type == PIM_MSG_TYPE_ASSERT)
+ || (type == PIM_MSG_TYPE_JOIN_PRUNE)) {
+ if (addr != qpim_all_pim_routers_addr.s_addr)
+ return false;
+ }
+
+ return true;
+}
+
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
{
struct ip *ip_hdr;
@@ -237,6 +248,21 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
}
}
+ if (!pim_pkt_dst_addr_ok(header->type, ip_hdr->ip_dst.s_addr)) {
+ char dst_str[INET_ADDRSTRLEN];
+ char src_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str,
+ sizeof(dst_str));
+ pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
+ sizeof(src_str));
+ zlog_warn(
+ "%s: Ignoring Pkt. Unexpected IP destination %s for %s (Expected: all_pim_routers_addr) from %s",
+ __func__, dst_str, pim_pim_msgtype2str(header->type),
+ src_str);
+ return -1;
+ }
+
switch (header->type) {
case PIM_MSG_TYPE_HELLO:
return pim_hello_recv(ifp, ip_hdr->ip_src,
@@ -662,7 +688,7 @@ static int hello_send(struct interface *ifp, uint16_t holdtime)
return 0;
}
-static int pim_hello_send(struct interface *ifp, uint16_t holdtime)
+int pim_hello_send(struct interface *ifp, uint16_t holdtime)
{
struct pim_interface *pim_ifp = ifp->info;
diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h
index e930ab7c2d..b9fdb14dc0 100644
--- a/pimd/pim_pim.h
+++ b/pimd/pim_pim.h
@@ -59,4 +59,5 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len);
int pim_msg_send(int fd, struct in_addr src, struct in_addr dst,
uint8_t *pim_msg, int pim_msg_size, const char *ifname);
+int pim_hello_send(struct interface *ifp, uint16_t holdtime);
#endif /* PIM_PIM_H */
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index 7b0af89993..cb6aae7fae 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -186,7 +186,7 @@ void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src,
if (!pinfo) {
if (PIM_DEBUG_PIM_REG)
zlog_debug(
- "%s: Interface: %s not configured for pim to trasmit on!\n",
+ "%s: Interface: %s not configured for pim to transmit on!",
__func__, ifp->name);
return;
}
diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c
index 5a751ac929..881a3e332a 100644
--- a/pimd/pim_tlv.c
+++ b/pimd/pim_tlv.c
@@ -473,7 +473,7 @@ int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size)
case PIM_MSG_ADDRESS_FAMILY_IPV4:
if ((addr + sizeof(struct in_addr)) > pastend) {
zlog_warn(
- "%s: IPv4 unicast address overflow: left=%zd needed=%zu",
+ "%s: IPv4 unicast address overflow: left=%td needed=%zu",
__func__, pastend - addr,
sizeof(struct in_addr));
return -3;
@@ -489,7 +489,7 @@ int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size)
case PIM_MSG_ADDRESS_FAMILY_IPV6:
if ((addr + sizeof(struct in6_addr)) > pastend) {
zlog_warn(
- "%s: IPv6 unicast address overflow: left=%zd needed %zu",
+ "%s: IPv6 unicast address overflow: left=%td needed %zu",
__func__, pastend - addr,
sizeof(struct in6_addr));
return -3;
@@ -548,7 +548,7 @@ int pim_parse_addr_group(struct prefix_sg *sg, const uint8_t *buf, int buf_size)
if ((addr + sizeof(struct in_addr)) > pastend) {
zlog_warn(
- "%s: IPv4 group address overflow: left=%zd needed=%zu from",
+ "%s: IPv4 group address overflow: left=%td needed=%zu from",
__func__, pastend - addr,
sizeof(struct in_addr));
return -3;
@@ -607,7 +607,7 @@ int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags,
case PIM_MSG_ADDRESS_FAMILY_IPV4:
if ((addr + sizeof(struct in_addr)) > pastend) {
zlog_warn(
- "%s: IPv4 source address overflow: left=%zd needed=%zu",
+ "%s: IPv4 source address overflow: left=%td needed=%zu",
__func__, pastend - addr,
sizeof(struct in_addr));
return -3;
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 07f8315a19..872883dfde 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -1697,10 +1697,12 @@ static int pim_upstream_register_stop_timer(struct thread *t)
case PIM_REG_JOIN:
break;
case PIM_REG_PRUNE:
+ /* This is equalent to Couldreg -> False */
if (!up->rpf.source_nexthop.interface) {
if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s: up %s RPF is not present",
__func__, up->sg_str);
+ up->reg_state = PIM_REG_NOINFO;
return 0;
}
diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c
index fc486f4998..84fac4f951 100644
--- a/pimd/pim_zlookup.c
+++ b/pimd/pim_zlookup.c
@@ -61,6 +61,14 @@ static int zclient_lookup_connect(struct thread *t)
zlookup->fail = 0; /* reset counter on connection */
}
+ if (zclient_send_hello(zlookup) < 0) {
+ if (close(zlookup->sock)) {
+ zlog_warn("%s: closing fd=%d: errno=%d %s", __func__,
+ zlookup->sock, errno, safe_strerror(errno));
+ }
+ zlookup->sock = -1;
+ }
+
if (zlookup->sock < 0) {
/* Since last connect failed, retry within 10 secs */
zclient_lookup_sched(zlookup, 10);
@@ -125,7 +133,10 @@ void zclient_lookup_free(void)
void zclient_lookup_new(void)
{
- zlookup = zclient_new(router->master, &zclient_options_default);
+ struct zclient_options options = zclient_options_default;
+ options.synchronous = true;
+
+ zlookup = zclient_new(router->master, &options);
if (!zlookup) {
flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_new() failure",
__func__);
@@ -161,6 +172,7 @@ static int zclient_read_nexthop(struct pim_instance *pim,
if (PIM_DEBUG_PIM_NHT_DETAIL) {
char addr_str[INET_ADDRSTRLEN];
+
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: addr=%s(%s)", __func__, addr_str,
pim->vrf->name);
diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c
index 6a30c07d99..25d9ed2b9e 100644
--- a/ripngd/ripng_interface.c
+++ b/ripngd/ripng_interface.c
@@ -867,17 +867,12 @@ int ripng_network_write(struct vty *vty, struct ripng *ripng)
unsigned int i;
const char *ifname;
struct agg_node *node;
- char buf[BUFSIZ];
/* Write enable network. */
for (node = agg_route_top(ripng->enable_network); node;
node = agg_route_next(node))
- if (node->info) {
- struct prefix *p = &node->p;
- vty_out(vty, " %s/%d\n",
- inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
- p->prefixlen);
- }
+ if (node->info)
+ vty_out(vty, " %pRN\n", node);
/* Write enable interface. */
for (i = 0; i < vector_active(ripng->enable_if); i++)
diff --git a/ripngd/ripng_nb_state.c b/ripngd/ripng_nb_state.c
index 167077ea29..75dec3cb3e 100644
--- a/ripngd/ripng_nb_state.c
+++ b/ripngd/ripng_nb_state.c
@@ -158,7 +158,8 @@ int ripngd_instance_state_routes_route_get_keys(const void *list_entry,
const struct agg_node *rn = list_entry;
keys->num = 1;
- (void)prefix2str(&rn->p, keys->key[0], sizeof(keys->key[0]));
+ (void)prefix2str(agg_node_get_prefix(rn), keys->key[0],
+ sizeof(keys->key[0]));
return NB_OK;
}
@@ -191,7 +192,7 @@ ripngd_instance_state_routes_route_prefix_get_elem(const char *xpath,
const struct agg_node *rn = list_entry;
const struct ripng_info *rinfo = listnode_head(rn->info);
- return yang_data_new_ipv6p(xpath, &rinfo->rp->p);
+ return yang_data_new_ipv6p(xpath, agg_node_get_prefix(rinfo->rp));
}
/*
diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c
index f9bd56d1df..baf7f00961 100644
--- a/ripngd/ripng_zebra.c
+++ b/ripngd/ripng_zebra.c
@@ -46,12 +46,13 @@ static void ripng_zebra_ipv6_send(struct ripng *ripng, struct agg_node *rp,
struct listnode *listnode = NULL;
struct ripng_info *rinfo = NULL;
int count = 0;
+ const struct prefix *p = agg_node_get_prefix(rp);
memset(&api, 0, sizeof(api));
api.vrf_id = ripng->vrf->vrf_id;
api.type = ZEBRA_ROUTE_RIPNG;
api.safi = SAFI_UNICAST;
- api.prefix = rp->p;
+ api.prefix = *p;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
@@ -85,18 +86,17 @@ static void ripng_zebra_ipv6_send(struct ripng *ripng, struct agg_node *rp,
if (IS_RIPNG_DEBUG_ZEBRA) {
if (ripng->ecmp)
- zlog_debug("%s: %s/%d nexthops %d",
+ zlog_debug("%s: %pRN nexthops %d",
(cmd == ZEBRA_ROUTE_ADD)
? "Install into zebra"
: "Delete from zebra",
- inet6_ntoa(rp->p.u.prefix6), rp->p.prefixlen,
- count);
+ rp, count);
else
- zlog_debug(
- "%s: %s/%d",
- (cmd == ZEBRA_ROUTE_ADD) ? "Install into zebra"
- : "Delete from zebra",
- inet6_ntoa(rp->p.u.prefix6), rp->p.prefixlen);
+ zlog_debug("%s: %pRN",
+ (cmd == ZEBRA_ROUTE_ADD)
+ ? "Install into zebra"
+ : "Delete from zebra",
+ rp);
}
}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index bb33abdb2c..1ea006abd6 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -1087,7 +1087,8 @@ void ripng_redistribute_withdraw(struct ripng *ripng, int type)
if (IS_RIPNG_DEBUG_EVENT) {
struct prefix_ipv6 *p =
- (struct prefix_ipv6 *)&rp->p;
+ (struct prefix_ipv6 *)
+ agg_node_get_prefix(rp);
zlog_debug(
"Poisone %s/%d on the interface %s [withdraw]",
@@ -1619,7 +1620,7 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
* following
* information.
*/
- p = (struct prefix_ipv6 *)&rp->p;
+ p = (struct prefix_ipv6 *)agg_node_get_prefix(rp);
rinfo->metric_out = rinfo->metric;
rinfo->tag_out = rinfo->tag;
memset(&rinfo->nexthop_out, 0,
@@ -1761,7 +1762,7 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
* following
* information.
*/
- p = (struct prefix_ipv6 *)&rp->p;
+ p = (struct prefix_ipv6 *)agg_node_get_prefix(rp);
aggregate->metric_set = 0;
aggregate->metric_out = aggregate->metric;
aggregate->tag_out = aggregate->tag;
@@ -2053,7 +2054,6 @@ DEFUN (show_ipv6_ripng,
struct agg_node *rp;
struct ripng_info *rinfo;
struct ripng_aggregate *aggregate;
- struct prefix_ipv6 *p;
struct list *list = NULL;
struct listnode *listnode = NULL;
int len;
@@ -2085,15 +2085,11 @@ DEFUN (show_ipv6_ripng,
for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
if ((aggregate = rp->aggregate) != NULL) {
- p = (struct prefix_ipv6 *)&rp->p;
-
#ifdef DEBUG
- vty_out(vty, "R(a) %d/%d %s/%d ", aggregate->count,
- aggregate->suppress, inet6_ntoa(p->prefix),
- p->prefixlen);
+ vty_out(vty, "R(a) %d/%d %pRN ", aggregate->count,
+ aggregate->suppress, rp);
#else
- vty_out(vty, "R(a) %s/%d ", inet6_ntoa(p->prefix),
- p->prefixlen);
+ vty_out(vty, "R(a) %pRN ", rp);
#endif /* DEBUG */
vty_out(vty, "\n");
vty_out(vty, "%*s", 18, " ");
@@ -2105,19 +2101,15 @@ DEFUN (show_ipv6_ripng,
if ((list = rp->info) != NULL)
for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- p = (struct prefix_ipv6 *)&rp->p;
-
#ifdef DEBUG
- vty_out(vty, "%c(%s) 0/%d %s/%d ",
+ vty_out(vty, "%c(%s) 0/%d %pRN ",
zebra_route_char(rinfo->type),
ripng_route_subtype_print(rinfo),
- rinfo->suppress, inet6_ntoa(p->prefix),
- p->prefixlen);
+ rinfo->suppress, rp);
#else
- vty_out(vty, "%c(%s) %s/%d ",
+ vty_out(vty, "%c(%s) %pRN ",
zebra_route_char(rinfo->type),
- ripng_route_subtype_print(rinfo),
- inet6_ntoa(p->prefix), p->prefixlen);
+ ripng_route_subtype_print(rinfo), rp);
#endif /* DEBUG */
vty_out(vty, "\n");
vty_out(vty, "%*s", 18, " ");
diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h
index 4e5c933667..8eba57f4dd 100644
--- a/sharpd/sharp_globals.h
+++ b/sharpd/sharp_globals.h
@@ -28,9 +28,11 @@ struct sharp_routes {
/* The original prefix for route installation */
struct prefix orig_prefix;
- /* The nexthop group we are using for installation */
+ /* The nexthop info we are using for installation */
struct nexthop nhop;
+ struct nexthop backup_nhop;
struct nexthop_group nhop_group;
+ struct nexthop_group backup_nhop_group;
uint32_t total_routes;
uint32_t installed_routes;
diff --git a/sharpd/sharp_logpump.c b/sharpd/sharp_logpump.c
new file mode 100644
index 0000000000..d07e2d273f
--- /dev/null
+++ b/sharpd/sharp_logpump.c
@@ -0,0 +1,153 @@
+/*
+ * testing log message generator
+ * Copyright (C) 2019-2020 David Lamparter for NetDEF, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "vty.h"
+#include "command.h"
+#include "prefix.h"
+#include "nexthop.h"
+#include "log.h"
+#include "thread.h"
+#include "vrf.h"
+#include "zclient.h"
+#include "frr_pthread.h"
+
+#include "sharpd/sharp_vty.h"
+
+/* this is quite hacky, but then again it's a test tool and it does its job. */
+static struct frr_pthread *lpt;
+
+static unsigned long lp_duration;
+static unsigned lp_frequency;
+static unsigned lp_burst;
+static size_t lp_ctr, lp_expect;
+static struct rusage lp_rusage;
+static struct vty *lp_vty;
+
+extern struct thread_master *master;
+
+static int logpump_done(struct thread *thread)
+{
+ double x;
+
+ vty_out(lp_vty, "\nlogpump done\n");
+ vty_out(lp_vty, "%9zu messages written\n", lp_ctr);
+ x = (double)lp_ctr / (double)lp_expect * 100.;
+ vty_out(lp_vty, "%9zu messages targeted = %5.1lf%%\n", lp_expect, x);
+
+ x = lp_rusage.ru_utime.tv_sec * 1000000 + lp_rusage.ru_utime.tv_usec;
+ x /= (double)lp_ctr;
+ vty_out(lp_vty, "%6llu.%06u usr %9.1lfns/msg\n",
+ (unsigned long long)lp_rusage.ru_utime.tv_sec,
+ (unsigned)lp_rusage.ru_utime.tv_usec, x * 1000.);
+
+ x = lp_rusage.ru_stime.tv_sec * 1000000 + lp_rusage.ru_stime.tv_usec;
+ x /= (double)lp_ctr;
+ vty_out(lp_vty, "%6llu.%06u sys %9.1lfns/msg\n",
+ (unsigned long long)lp_rusage.ru_stime.tv_sec,
+ (unsigned)lp_rusage.ru_stime.tv_usec, x * 1000.);
+
+ frr_pthread_stop(lpt, NULL);
+ frr_pthread_destroy(lpt);
+ lpt = NULL;
+ return 0;
+}
+
+static void *logpump_run(void *arg)
+{
+ struct timespec start, next, now;
+ unsigned long delta, period;
+
+ period = 1000000000L / lp_frequency;
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ next = start;
+ do {
+ for (size_t inburst = 0; inburst < lp_burst; inburst++)
+ zlog_debug("log pump: %zu (burst %zu)",
+ lp_ctr++, inburst);
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ delta = (now.tv_sec - start.tv_sec) * 1000000000L
+ + (now.tv_nsec - start.tv_nsec);
+
+ next.tv_nsec += period;
+ if (next.tv_nsec > 1000000000L) {
+ next.tv_sec++;
+ next.tv_nsec -= 1000000000L;
+ }
+#ifdef HAVE_CLOCK_NANOSLEEP
+ clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
+#else
+ struct timespec slpdur;
+
+ slpdur.tv_sec = next.tv_sec - now.tv_sec;
+ slpdur.tv_nsec = next.tv_nsec - now.tv_nsec;
+ if (slpdur.tv_nsec < 0) {
+ slpdur.tv_sec--;
+ slpdur.tv_nsec += 1000000000L;
+ }
+
+ nanosleep(&slpdur, NULL);
+#endif
+ } while (delta < lp_duration);
+
+#ifdef RUSAGE_THREAD
+ getrusage(RUSAGE_THREAD, &lp_rusage);
+#else
+ getrusage(RUSAGE_SELF, &lp_rusage);
+#endif
+
+ thread_add_timer_msec(master, logpump_done, NULL, 0, NULL);
+ return NULL;
+}
+
+static int logpump_halt(struct frr_pthread *fpt, void **res)
+{
+ return 0;
+}
+
+/* default frr_pthread attributes */
+static const struct frr_pthread_attr attr = {
+ .start = logpump_run,
+ .stop = logpump_halt,
+};
+
+void sharp_logpump_run(struct vty *vty, unsigned duration, unsigned frequency,
+ unsigned burst)
+{
+ if (lpt != NULL) {
+ vty_out(vty, "logpump already running\n");
+ return;
+ }
+
+ vty_out(vty, "starting logpump...\n");
+ vty_out(vty, "keep this VTY open and press Enter to see results\n");
+
+ lp_vty = vty;
+ lp_duration = duration * 1000000000UL;
+ lp_frequency = frequency;
+ lp_burst = burst;
+ lp_expect = duration * frequency * burst;
+ lp_ctr = 0;
+
+ lpt = frr_pthread_new(&attr, "logpump", "logpump");
+ frr_pthread_run(lpt, NULL);
+}
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index fd2e37e675..8a787c8e83 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -162,7 +162,12 @@ DEFPY (install_routes_data_dump,
DEFPY (install_routes,
install_routes_cmd,
- "sharp install routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NHGNAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
+ "sharp install routes [vrf NAME$vrf_name]\
+ <A.B.C.D$start4|X:X::X:X$start6>\
+ <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
+ nexthop-group NHGNAME$nexthop_group>\
+ [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
+ (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
"Sharp routing Protocol\n"
"install some routes\n"
"Routes to install\n"
@@ -175,6 +180,9 @@ DEFPY (install_routes,
"V6 Nexthop address to use\n"
"Nexthop-Group to use\n"
"The Name of the nexthop-group\n"
+ "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n"
+ "Backup V4 Nexthop address to use\n"
+ "Backup V6 Nexthop address to use\n"
"How many to create\n"
"Instance to use\n"
"Instance\n"
@@ -197,6 +205,8 @@ DEFPY (install_routes,
memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix));
memset(&sg.r.nhop, 0, sizeof(sg.r.nhop));
memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group));
+ memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop));
+ memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group));
if (start4.s_addr != 0) {
prefix.family = AF_INET;
@@ -219,6 +229,12 @@ DEFPY (install_routes,
return CMD_WARNING;
}
+ /* Explicit backup not available with named nexthop-group */
+ if (backup && nexthop_group) {
+ vty_out(vty, "%% Invalid: cannot specify both nexthop-group and backup\n");
+ return CMD_WARNING;
+ }
+
if (nexthop_group) {
struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group);
if (!nhgc) {
@@ -229,6 +245,22 @@ DEFPY (install_routes,
}
sg.r.nhop_group.nexthop = nhgc->nhg.nexthop;
+
+ /* Use group's backup nexthop info if present */
+ if (nhgc->backup_list_name[0]) {
+ struct nexthop_group_cmd *bnhgc =
+ nhgc_find(nhgc->backup_list_name);
+
+ if (!bnhgc) {
+ vty_out(vty, "%% Backup group %s not found for group %s\n",
+ nhgc->backup_list_name,
+ nhgc->name);
+ return CMD_WARNING;
+ }
+
+ sg.r.backup_nhop.vrf_id = vrf->vrf_id;
+ sg.r.backup_nhop_group.nexthop = bnhgc->nhg.nexthop;
+ }
} else {
if (nexthop4.s_addr != INADDR_ANY) {
sg.r.nhop.gate.ipv4 = nexthop4;
@@ -242,11 +274,30 @@ DEFPY (install_routes,
sg.r.nhop_group.nexthop = &sg.r.nhop;
}
+ /* Use single backup nexthop if specified */
+ if (backup) {
+ /* Set flag and index in primary nexthop */
+ SET_FLAG(sg.r.nhop.flags, NEXTHOP_FLAG_HAS_BACKUP);
+ sg.r.nhop.backup_idx = 0;
+
+ if (backup_nexthop4.s_addr != INADDR_ANY) {
+ sg.r.backup_nhop.gate.ipv4 = backup_nexthop4;
+ sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV4;
+ } else {
+ sg.r.backup_nhop.gate.ipv6 = backup_nexthop6;
+ sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV6;
+ }
+
+ sg.r.backup_nhop.vrf_id = vrf->vrf_id;
+ sg.r.backup_nhop_group.nexthop = &sg.r.backup_nhop;
+ }
+
sg.r.inst = instance;
sg.r.vrf_id = vrf->vrf_id;
rts = routes;
- sharp_install_routes_helper(&prefix, sg.r.vrf_id,
- sg.r.inst, &sg.r.nhop_group, rts);
+ sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst,
+ &sg.r.nhop_group, &sg.r.backup_nhop_group,
+ rts);
return CMD_SUCCESS;
}
@@ -460,6 +511,22 @@ DEFPY(sharp_remove_lsp_prefix_v4, sharp_remove_lsp_prefix_v4_cmd,
}
}
+DEFPY (logpump,
+ logpump_cmd,
+ "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
+ "Sharp Routing Protocol\n"
+ "Generate bulk log messages for testing\n"
+ "Duration of run (s)\n"
+ "Duration of run (s)\n"
+ "Frequency of bursts (s^-1)\n"
+ "Frequency of bursts (s^-1)\n"
+ "Number of log messages per each burst\n"
+ "Number of log messages per each burst\n")
+{
+ sharp_logpump_run(vty, duration, frequency, burst);
+ return CMD_SUCCESS;
+}
+
void sharp_vty_init(void)
{
install_element(ENABLE_NODE, &install_routes_data_dump_cmd);
@@ -471,6 +538,7 @@ void sharp_vty_init(void)
install_element(ENABLE_NODE, &watch_nexthop_v4_cmd);
install_element(ENABLE_NODE, &sharp_lsp_prefix_v4_cmd);
install_element(ENABLE_NODE, &sharp_remove_lsp_prefix_v4_cmd);
+ install_element(ENABLE_NODE, &logpump_cmd);
install_element(VIEW_NODE, &show_debugging_sharpd_cmd);
diff --git a/sharpd/sharp_vty.h b/sharpd/sharp_vty.h
index d4af095e89..0d1327259c 100644
--- a/sharpd/sharp_vty.h
+++ b/sharpd/sharp_vty.h
@@ -23,4 +23,10 @@
#define __SHARP_VTY_H__
extern void sharp_vty_init(void);
+
+struct vty;
+
+extern void sharp_logpump_run(struct vty *vty, unsigned duration,
+ unsigned frequency, unsigned burst);
+
#endif
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index 882e73f873..e1bd6f5722 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -143,7 +143,9 @@ int sharp_install_lsps_helper(bool install_p, const struct prefix *p,
}
void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
- uint8_t instance, struct nexthop_group *nhg,
+ uint8_t instance,
+ const struct nexthop_group *nhg,
+ const struct nexthop_group *backup_nhg,
uint32_t routes)
{
uint32_t temp, i;
@@ -157,9 +159,13 @@ void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
} else
temp = ntohl(p->u.val32[3]);
+ /* Only use backup route/nexthops if present */
+ if (backup_nhg && (backup_nhg->nexthop == NULL))
+ backup_nhg = NULL;
+
monotime(&sg.r.t_start);
for (i = 0; i < routes; i++) {
- route_add(p, vrf_id, (uint8_t)instance, nhg);
+ route_add(p, vrf_id, (uint8_t)instance, nhg, backup_nhg);
if (v4)
p->u.prefix4.s_addr = htonl(++temp);
else
@@ -209,6 +215,7 @@ static void handle_repeated(bool installed)
sg.r.installed_routes = 0;
sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
&sg.r.nhop_group,
+ &sg.r.backup_nhop_group,
sg.r.total_routes);
}
}
@@ -276,8 +283,9 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label)
zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP);
}
-void route_add(struct prefix *p, vrf_id_t vrf_id,
- uint8_t instance, struct nexthop_group *nhg)
+void route_add(const struct prefix *p, vrf_id_t vrf_id,
+ uint8_t instance, const struct nexthop_group *nhg,
+ const struct nexthop_group *backup_nhg)
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
@@ -298,10 +306,27 @@ void route_add(struct prefix *p, vrf_id_t vrf_id,
api_nh = &api.nexthops[i];
zapi_nexthop_from_nexthop(api_nh, nh);
+
i++;
}
api.nexthop_num = i;
+ /* Include backup nexthops, if present */
+ if (backup_nhg && backup_nhg->nexthop) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
+
+ i = 0;
+ for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
+ api_nh = &api.backup_nexthops[i];
+
+ zapi_backup_nexthop_from_nexthop(api_nh, nh);
+
+ i++;
+ }
+
+ api.backup_nexthop_num = i;
+ }
+
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
}
@@ -353,7 +378,7 @@ static int sharp_debug_nexthops(struct zapi_route *api)
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
zlog_debug(
- "\tNexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
+ " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
inet_ntop(AF_INET, &znh->gate.ipv4.s_addr, buf,
sizeof(buf)),
znh->type, znh->ifindex, znh->vrf_id,
@@ -362,18 +387,18 @@ static int sharp_debug_nexthops(struct zapi_route *api)
case NEXTHOP_TYPE_IPV6_IFINDEX:
case NEXTHOP_TYPE_IPV6:
zlog_debug(
- "\tNexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
+ " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
inet_ntop(AF_INET6, &znh->gate.ipv6, buf,
sizeof(buf)),
znh->type, znh->ifindex, znh->vrf_id,
znh->label_num);
break;
case NEXTHOP_TYPE_IFINDEX:
- zlog_debug("\tNexthop IFINDEX: %d, ifindex: %d",
+ zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d",
znh->type, znh->ifindex);
break;
case NEXTHOP_TYPE_BLACKHOLE:
- zlog_debug("\tNexthop blackhole");
+ zlog_debug(" Nexthop blackhole");
break;
}
}
diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h
index c995d557af..926bff676b 100644
--- a/sharpd/sharp_zebra.h
+++ b/sharpd/sharp_zebra.h
@@ -25,15 +25,17 @@
extern void sharp_zebra_init(void);
extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
-extern void route_add(struct prefix *p, vrf_id_t, uint8_t instance,
- struct nexthop_group *nhg);
+extern void route_add(const struct prefix *p, vrf_id_t, uint8_t instance,
+ const struct nexthop_group *nhg,
+ const struct nexthop_group *backup_nhg);
extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance);
extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id,
bool import, bool watch, bool connected);
extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
uint8_t instance,
- struct nexthop_group *nhg,
+ const struct nexthop_group *nhg,
+ const struct nexthop_group *backup_nhg,
uint32_t routes);
extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
uint8_t instance, uint32_t routes);
diff --git a/sharpd/subdir.am b/sharpd/subdir.am
index 89b183d832..8b32b2370c 100644
--- a/sharpd/subdir.am
+++ b/sharpd/subdir.am
@@ -14,6 +14,7 @@ sharpd_libsharp_a_SOURCES = \
sharpd/sharp_nht.c \
sharpd/sharp_zebra.c \
sharpd/sharp_vty.c \
+ sharpd/sharp_logpump.c \
# end
noinst_HEADERS += \
diff --git a/staticd/static_debug.c b/staticd/static_debug.c
index 9906e805a7..e43d4e79ff 100644
--- a/staticd/static_debug.c
+++ b/staticd/static_debug.c
@@ -3,7 +3,7 @@
* Copyright (C) 2019 Volta Networks Inc.
* Mark Stapp
*
- * This file is part of Free Range Routing (FRR).
+ * This file is part of FRRouting (FRR).
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
diff --git a/staticd/static_debug.h b/staticd/static_debug.h
index 8932e2d429..481c266e14 100644
--- a/staticd/static_debug.h
+++ b/staticd/static_debug.h
@@ -3,7 +3,7 @@
* Copyright (C) 2019 Volta Networks Inc.
* Mark Stapp
*
- * This file is part of Free Range Routing (FRR).
+ * This file is part of FRRouting (FRR).
*
* 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
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index 40bcf2b5d3..a950b0473e 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -867,7 +867,7 @@ DEFPY(ip_route_address_interface,
"Table to configure\n"
"The table number to configure\n"
VRF_CMD_HELP_STR
- "Treat the nexthop as directly attached to the interface")
+ "Treat the nexthop as directly attached to the interface\n")
{
struct static_vrf *svrf;
struct static_vrf *nh_svrf;
@@ -935,7 +935,7 @@ DEFPY(ip_route_address_interface_vrf,
"Table to configure\n"
"The table number to configure\n"
VRF_CMD_HELP_STR
- "Treat the nexthop as directly attached to the interface")
+ "Treat the nexthop as directly attached to the interface\n")
{
VTY_DECLVAR_CONTEXT(vrf, vrf);
const char *flag = NULL;
@@ -1211,7 +1211,7 @@ DEFPY(ipv6_route_address_interface,
"Table to configure\n"
"The table number to configure\n"
VRF_CMD_HELP_STR
- "Treat the nexthop as directly attached to the interface")
+ "Treat the nexthop as directly attached to the interface\n")
{
struct static_vrf *svrf;
struct static_vrf *nh_svrf;
@@ -1279,7 +1279,7 @@ DEFPY(ipv6_route_address_interface_vrf,
"Table to configure\n"
"The table number to configure\n"
VRF_CMD_HELP_STR
- "Treat the nexthop as directly attached to the interface")
+ "Treat the nexthop as directly attached to the interface\n")
{
VTY_DECLVAR_CONTEXT(vrf, vrf);
struct static_vrf *svrf = vrf->info;
diff --git a/tests/bgpd/test_bgp_table.c b/tests/bgpd/test_bgp_table.c
index 819c2d7282..79a8bb4408 100644
--- a/tests/bgpd/test_bgp_table.c
+++ b/tests/bgpd/test_bgp_table.c
@@ -82,7 +82,7 @@ static void print_range_result(struct list *list)
for (ALL_LIST_ELEMENTS_RO(list, listnode, bnode)) {
char buf[PREFIX2STR_BUFFER];
- prefix2str(&bnode->p, buf, PREFIX2STR_BUFFER);
+ prefix2str(bgp_node_get_prefix(bnode), buf, PREFIX2STR_BUFFER);
printf("%s\n", buf);
}
}
@@ -106,7 +106,7 @@ static void check_lookup_result(struct list *list, va_list arglist)
assert(0);
for (ALL_LIST_ELEMENTS_RO(list, listnode, bnode)) {
- if (prefix_same(&bnode->p, &p))
+ if (prefix_same(bgp_node_get_prefix(bnode), &p))
found = true;
}
diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c
index 238ee9539e..40837b4722 100644
--- a/tests/lib/test_atomlist.c
+++ b/tests/lib/test_atomlist.c
@@ -29,6 +29,7 @@
#include "atomlist.h"
#include "seqlock.h"
#include "monotime.h"
+#include "printfrr.h"
/*
* maybe test:
@@ -288,7 +289,7 @@ static void run_tr(struct testrun *tr)
size_t c = 0, s = 0, n = 0;
struct item *item, *prev, dummy;
- printf("[%02u] %35s %s\n", seqlock_cur(&sqlo) >> 2, "", desc);
+ printfrr("[%02u] %35s %s\n", seqlock_cur(&sqlo) >> 2, "", desc);
fflush(stdout);
if (tr->prefill != NOCLEAR)
@@ -324,7 +325,7 @@ static void run_tr(struct testrun *tr)
}
assert(c == alist_count(&ahead));
}
- printf("\033[1A[%02u] %9"PRId64"us c=%5zu s=%5zu n=%5zu %s\n",
+ printfrr("\033[1A[%02u] %9"PRId64"us c=%5zu s=%5zu n=%5zu %s\n",
sv >> 2, delta, c, s, n, desc);
}
@@ -334,9 +335,9 @@ static void dump(const char *lbl)
struct item *item, *safe;
size_t ctr = 0;
- printf("dumping %s:\n", lbl);
+ printfrr("dumping %s:\n", lbl);
frr_each_safe(alist, &ahead, item) {
- printf("%s %3zu %p %3"PRIu64" %3"PRIu64"\n", lbl, ctr++,
+ printfrr("%s %3zu %p %3"PRIu64" %3"PRIu64"\n", lbl, ctr++,
(void *)item, item->val1, item->val2);
}
}
@@ -362,12 +363,12 @@ static void basic_tests(void)
dump("");
alist_del(&ahead, &itm[1]);
dump("");
- printf("POP: %p\n", alist_pop(&ahead));
+ printfrr("POP: %p\n", alist_pop(&ahead));
dump("");
- printf("POP: %p\n", alist_pop(&ahead));
- printf("POP: %p\n", alist_pop(&ahead));
- printf("POP: %p\n", alist_pop(&ahead));
- printf("POP: %p\n", alist_pop(&ahead));
+ printfrr("POP: %p\n", alist_pop(&ahead));
+ printfrr("POP: %p\n", alist_pop(&ahead));
+ printfrr("POP: %p\n", alist_pop(&ahead));
+ printfrr("POP: %p\n", alist_pop(&ahead));
dump("");
}
#else
diff --git a/tests/lib/test_srcdest_table.c b/tests/lib/test_srcdest_table.c
index 0fca571d28..935ee500a3 100644
--- a/tests/lib/test_srcdest_table.c
+++ b/tests/lib/test_srcdest_table.c
@@ -4,7 +4,7 @@
* Copyright (C) 2017 by David Lamparter & Christian Franke,
* Open Source Routing / NetDEF Inc.
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/tests/lib/test_stream.c b/tests/lib/test_stream.c
index 2ecfc87942..a45c2b4d54 100644
--- a/tests/lib/test_stream.c
+++ b/tests/lib/test_stream.c
@@ -23,6 +23,8 @@
#include <stream.h>
#include <thread.h>
+#include "printfrr.h"
+
static unsigned long long ham = 0xdeadbeefdeadbeef;
struct thread_master *master;
@@ -30,15 +32,15 @@ static void print_stream(struct stream *s)
{
size_t getp = stream_get_getp(s);
- printf("endp: %zu, readable: %zu, writeable: %zu\n", stream_get_endp(s),
- STREAM_READABLE(s), STREAM_WRITEABLE(s));
+ printfrr("endp: %zu, readable: %zu, writeable: %zu\n",
+ stream_get_endp(s), STREAM_READABLE(s), STREAM_WRITEABLE(s));
while (STREAM_READABLE(s)) {
- printf("0x%x ", *stream_pnt(s));
+ printfrr("0x%x ", *stream_pnt(s));
stream_forward_getp(s, 1);
}
- printf("\n");
+ printfrr("\n");
/* put getp back to where it was */
stream_set_getp(s, getp);
@@ -61,10 +63,10 @@ int main(void)
print_stream(s);
- printf("c: 0x%hhx\n", stream_getc(s));
- printf("w: 0x%hx\n", stream_getw(s));
- printf("l: 0x%x\n", stream_getl(s));
- printf("q: 0x%" PRIx64 "\n", stream_getq(s));
+ printfrr("c: 0x%hhx\n", stream_getc(s));
+ printfrr("w: 0x%hx\n", stream_getw(s));
+ printfrr("l: 0x%x\n", stream_getl(s));
+ printfrr("q: 0x%" PRIx64 "\n", stream_getq(s));
return 0;
}
diff --git a/tests/lib/test_typelist.c b/tests/lib/test_typelist.c
index 2438fb5f08..607e29e56b 100644
--- a/tests/lib/test_typelist.c
+++ b/tests/lib/test_typelist.c
@@ -35,6 +35,7 @@
#include "monotime.h"
#include "jhash.h"
#include "sha256.h"
+#include "printfrr.h"
#include "tests/helpers/c/prng.h"
@@ -90,14 +91,14 @@ static void ts_ref(const char *text)
{
int64_t us;
us = monotime_since(&ref, NULL);
- printf("%7"PRId64"us %s\n", us, text);
+ printfrr("%7"PRId64"us %s\n", us, text);
monotime(&ref);
}
static void ts_end(void)
{
int64_t us;
us = monotime_since(&ref0, NULL);
- printf("%7"PRId64"us total\n", us);
+ printfrr("%7"PRId64"us total\n", us);
}
#define TYPE LIST
diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h
index 9039fa8a46..da3530e9c0 100644
--- a/tests/lib/test_typelist.h
+++ b/tests/lib/test_typelist.h
@@ -123,10 +123,10 @@ static void ts_hash(const char *text, const char *expect)
for (i = 0; i < sizeof(hash); i++)
sprintf(hashtext + i * 2, "%02x", hash[i]);
- printf("%7"PRId64"us %-25s %s%s\n", us, text,
+ printfrr("%7"PRId64"us %-25s %s%s\n", us, text,
expect ? " " : "*", hashtext);
if (expect && strcmp(expect, hashtext)) {
- printf("%-21s %s\n", "EXPECTED:", expect);
+ printfrr("%-21s %s\n", "EXPECTED:", expect);
assert(0);
}
monotime(&ref);
@@ -149,7 +149,7 @@ static void concat(test_, TYPE)(void)
for (i = 0; i < NITEM; i++)
itm[i].val = i;
- printf("%s start\n", str(TYPE));
+ printfrr("%s start\n", str(TYPE));
ts_start();
list_init(&head);
@@ -530,7 +530,7 @@ static void concat(test_, TYPE)(void)
list_fini(&head);
ts_ref("fini");
ts_end();
- printf("%s end\n", str(TYPE));
+ printfrr("%s end\n", str(TYPE));
}
#undef ts_hashx
diff --git a/tests/lib/test_zlog.c b/tests/lib/test_zlog.c
index 790e65cfe9..07885d9847 100644
--- a/tests/lib/test_zlog.c
+++ b/tests/lib/test_zlog.c
@@ -34,12 +34,14 @@ static bool test_zlog_hexdump(void)
unsigned int nl = 1;
do {
- long d[nl];
+ uint8_t d[nl];
for (unsigned int i = 0; i < nl; i++)
d[i] = random();
- zlog_hexdump(d, nl * sizeof(long));
- } while (++nl * sizeof(long) <= MAXDATA);
+ zlog_hexdump(d, nl - 1);
+
+ nl += 1 + (nl / 2);
+ } while (nl <= MAXDATA);
return true;
}
diff --git a/tests/subdir.am b/tests/subdir.am
index d87d348949..bce08c4034 100644
--- a/tests/subdir.am
+++ b/tests/subdir.am
@@ -38,8 +38,11 @@ else
TESTS_OSPF6D =
endif
+tests/lib/cli/test_cli_clippy.c: $(CLIPPY_DEPS)
tests/lib/cli/tests_lib_cli_test_cli-test_cli.$(OBJEXT): tests/lib/cli/test_cli_clippy.c
tests/lib/cli/test_cli-test_cli.$(OBJEXT): tests/lib/cli/test_cli_clippy.c
+
+tests/ospf6d/test_lsdb_clippy.c: $(CLIPPY_DEPS)
tests/ospf6d/tests_ospf6d_test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_clippy.c
tests/ospf6d/test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_clippy.c
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json
index 54ae57f7be..ac5fd04074 100644
--- a/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json
@@ -14,7 +14,6 @@
"prefix": "2001:db8:6::",
"prefixLen": 64,
"network": "2001:db8:6::\/64",
- "med": 0,
"metric": 0,
"weight": 0,
"peerId": "2001:db8:4::1",
@@ -37,7 +36,6 @@
"prefix": "2001:db8:7::",
"prefixLen": 64, "network":
"2001:db8:7::\/64",
- "med": 0,
"metric": 0,
"weight": 0,
"peerId": "2001:db8:4::1",
@@ -60,7 +58,6 @@
"prefix": "2001:db8:8::",
"prefixLen": 64,
"network": "2001:db8:8::\/64",
- "med": 0,
"metric": 0,
"weight": 32768,
"peerId": "(unspec)",
@@ -83,7 +80,6 @@
"prefix": "2001:db8:9::",
"prefixLen": 64,
"network": "2001:db8:9::\/64",
- "med": 0,
"metric": 0,
"weight": 32768,
"peerId": "(unspec)",
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json
index a3bb222504..ab42b05e85 100644
--- a/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json
@@ -13,7 +13,6 @@
"prefix": "2001:db8:6::",
"prefixLen": 64,
"network": "2001:db8:6::\/64",
- "med": 0,
"metric": 0,
"weight": 32768,
"peerId": "(unspec)",
@@ -36,7 +35,6 @@
"prefix": "2001:db8:7::",
"prefixLen": 64,
"network": "2001:db8:7::\/64",
- "med": 0,
"metric": 0,
"weight": 32768,
"peerId": "(unspec)",
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
index e2bd80daa8..22a4547a30 100755
--- a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
+++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
@@ -142,7 +142,7 @@ def test_bfd_connection():
test_func = partial(topotest.router_json_cmp,
router, 'show bfd peers json', expected)
- _, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=32, wait=0.5)
assertmsg = '"{}" JSON output mismatches'.format(router.name)
assert result is None, assertmsg
@@ -173,7 +173,7 @@ def test_bfd_loss_intermediate():
test_func = partial(topotest.router_json_cmp,
router, 'show bfd peers json', expected)
- _, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=32, wait=0.5)
assertmsg = '"{}" JSON output mismatches'.format(router.name)
assert result is None, assertmsg
diff --git a/tests/topotests/bfd-topo1/r1/bgp_prefixes.json b/tests/topotests/bfd-topo1/r1/bgp_prefixes.json
index 4b2cc1ad62..1262f5e984 100644
--- a/tests/topotests/bfd-topo1/r1/bgp_prefixes.json
+++ b/tests/topotests/bfd-topo1/r1/bgp_prefixes.json
@@ -2,7 +2,7 @@
"routes": {
"10.254.254.2/32": [
{
- "aspath": "102",
+ "path": "102",
"prefix": "10.254.254.2",
"valid": true,
"peerId": "192.168.0.2",
@@ -18,7 +18,7 @@
],
"10.254.254.3/32": [
{
- "aspath": "102 103",
+ "path": "102 103",
"prefix": "10.254.254.3",
"valid": true,
"peerId": "192.168.0.2",
@@ -34,7 +34,7 @@
],
"10.254.254.4/32": [
{
- "aspath": "102 104",
+ "path": "102 104",
"prefix": "10.254.254.4",
"valid": true,
"peerId": "192.168.0.2",
diff --git a/tests/topotests/bfd-topo1/r2/bgp_prefixes.json b/tests/topotests/bfd-topo1/r2/bgp_prefixes.json
index 39f3c0a835..0d47c0fc30 100644
--- a/tests/topotests/bfd-topo1/r2/bgp_prefixes.json
+++ b/tests/topotests/bfd-topo1/r2/bgp_prefixes.json
@@ -2,7 +2,7 @@
"routes": {
"10.254.254.1/32": [
{
- "aspath": "101",
+ "path": "101",
"prefix": "10.254.254.1",
"valid": true,
"peerId": "192.168.0.1",
@@ -18,7 +18,7 @@
],
"10.254.254.3/32": [
{
- "aspath": "103",
+ "path": "103",
"prefix": "10.254.254.3",
"valid": true,
"peerId": "192.168.1.1",
@@ -34,7 +34,7 @@
],
"10.254.254.4/32": [
{
- "aspath": "104",
+ "path": "104",
"prefix": "10.254.254.4",
"valid": true,
"peerId": "192.168.2.1",
diff --git a/tests/topotests/bfd-topo1/r3/bgp_prefixes.json b/tests/topotests/bfd-topo1/r3/bgp_prefixes.json
index c92d4e052a..36fca17bbf 100644
--- a/tests/topotests/bfd-topo1/r3/bgp_prefixes.json
+++ b/tests/topotests/bfd-topo1/r3/bgp_prefixes.json
@@ -2,7 +2,7 @@
"routes": {
"10.254.254.1/32": [
{
- "aspath": "102 101",
+ "path": "102 101",
"prefix": "10.254.254.1",
"valid": true,
"peerId": "192.168.1.2",
@@ -18,7 +18,7 @@
],
"10.254.254.2/32": [
{
- "aspath": "102",
+ "path": "102",
"prefix": "10.254.254.2",
"valid": true,
"peerId": "192.168.1.2",
@@ -34,7 +34,7 @@
],
"10.254.254.4/32": [
{
- "aspath": "102 104",
+ "path": "102 104",
"prefix": "10.254.254.4",
"valid": true,
"peerId": "192.168.1.2",
diff --git a/tests/topotests/bfd-topo1/r4/bgp_prefixes.json b/tests/topotests/bfd-topo1/r4/bgp_prefixes.json
index cc8510dd61..efe7d47b1a 100644
--- a/tests/topotests/bfd-topo1/r4/bgp_prefixes.json
+++ b/tests/topotests/bfd-topo1/r4/bgp_prefixes.json
@@ -2,7 +2,7 @@
"routes": {
"10.254.254.1/32": [
{
- "aspath": "102 101",
+ "path": "102 101",
"prefix": "10.254.254.1",
"valid": true,
"peerId": "192.168.2.2",
@@ -18,7 +18,7 @@
],
"10.254.254.2/32": [
{
- "aspath": "102",
+ "path": "102",
"prefix": "10.254.254.2",
"valid": true,
"peerId": "192.168.2.2",
@@ -34,7 +34,7 @@
],
"10.254.254.3/32": [
{
- "aspath": "102 103",
+ "path": "102 103",
"prefix": "10.254.254.3",
"valid": true,
"peerId": "192.168.2.2",
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json
index 4b2cc1ad62..1262f5e984 100644
--- a/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json
+++ b/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json
@@ -2,7 +2,7 @@
"routes": {
"10.254.254.2/32": [
{
- "aspath": "102",
+ "path": "102",
"prefix": "10.254.254.2",
"valid": true,
"peerId": "192.168.0.2",
@@ -18,7 +18,7 @@
],
"10.254.254.3/32": [
{
- "aspath": "102 103",
+ "path": "102 103",
"prefix": "10.254.254.3",
"valid": true,
"peerId": "192.168.0.2",
@@ -34,7 +34,7 @@
],
"10.254.254.4/32": [
{
- "aspath": "102 104",
+ "path": "102 104",
"prefix": "10.254.254.4",
"valid": true,
"peerId": "192.168.0.2",
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json
index 39f3c0a835..0d47c0fc30 100644
--- a/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json
+++ b/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json
@@ -2,7 +2,7 @@
"routes": {
"10.254.254.1/32": [
{
- "aspath": "101",
+ "path": "101",
"prefix": "10.254.254.1",
"valid": true,
"peerId": "192.168.0.1",
@@ -18,7 +18,7 @@
],
"10.254.254.3/32": [
{
- "aspath": "103",
+ "path": "103",
"prefix": "10.254.254.3",
"valid": true,
"peerId": "192.168.1.1",
@@ -34,7 +34,7 @@
],
"10.254.254.4/32": [
{
- "aspath": "104",
+ "path": "104",
"prefix": "10.254.254.4",
"valid": true,
"peerId": "192.168.2.1",
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json
index c92d4e052a..36fca17bbf 100644
--- a/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json
+++ b/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json
@@ -2,7 +2,7 @@
"routes": {
"10.254.254.1/32": [
{
- "aspath": "102 101",
+ "path": "102 101",
"prefix": "10.254.254.1",
"valid": true,
"peerId": "192.168.1.2",
@@ -18,7 +18,7 @@
],
"10.254.254.2/32": [
{
- "aspath": "102",
+ "path": "102",
"prefix": "10.254.254.2",
"valid": true,
"peerId": "192.168.1.2",
@@ -34,7 +34,7 @@
],
"10.254.254.4/32": [
{
- "aspath": "102 104",
+ "path": "102 104",
"prefix": "10.254.254.4",
"valid": true,
"peerId": "192.168.1.2",
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json
index cc8510dd61..efe7d47b1a 100644
--- a/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json
+++ b/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json
@@ -2,7 +2,7 @@
"routes": {
"10.254.254.1/32": [
{
- "aspath": "102 101",
+ "path": "102 101",
"prefix": "10.254.254.1",
"valid": true,
"peerId": "192.168.2.2",
@@ -18,7 +18,7 @@
],
"10.254.254.2/32": [
{
- "aspath": "102",
+ "path": "102",
"prefix": "10.254.254.2",
"valid": true,
"peerId": "192.168.2.2",
@@ -34,7 +34,7 @@
],
"10.254.254.3/32": [
{
- "aspath": "102 103",
+ "path": "102 103",
"prefix": "10.254.254.3",
"valid": true,
"peerId": "192.168.2.2",
diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
index 3b2d9c25d7..1cd2c4417f 100755
--- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
+++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
@@ -430,7 +430,7 @@ def test_aspath_attribute(request):
# Verifying best path
dut = "r1"
- attribute = "aspath"
+ attribute = "path"
for addr_type in ADDR_TYPES:
result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
{"r7": input_dict["r7"]},
@@ -479,7 +479,7 @@ def test_aspath_attribute(request):
}
},
"set": {
- "aspath": {
+ "path": {
"as_num": "111 222",
"as_action": "prepend"
}
@@ -493,7 +493,7 @@ def test_aspath_attribute(request):
}
},
"set": {
- "aspath": {
+ "path": {
"as_num": "111 222",
"as_action": "prepend"
}
@@ -553,7 +553,7 @@ def test_aspath_attribute(request):
# Verifying best path
dut = "r1"
- attribute = "aspath"
+ attribute = "path"
for addr_type in ADDR_TYPES:
result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
{"r7": input_dict["r7"]},
@@ -714,7 +714,7 @@ def test_localpref_attribute(request):
}
},
"set": {
- "localpref": 1111
+ "locPrf": 1111
}
},
{
@@ -726,7 +726,7 @@ def test_localpref_attribute(request):
}
},
"set": {
- "localpref": 1111
+ "locPrf": 1111
}
}]
}
@@ -783,7 +783,7 @@ def test_localpref_attribute(request):
# Verifying best path
dut = "r1"
- attribute = "localpref"
+ attribute = "locPrf"
for addr_type in ADDR_TYPES:
result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
{"r7": input_dict["r7"]},
@@ -804,7 +804,7 @@ def test_localpref_attribute(request):
}
},
"set": {
- "localpref": 50
+ "locPrf": 50
}
},
{
@@ -816,7 +816,7 @@ def test_localpref_attribute(request):
}
},
"set": {
- "localpref": 50
+ "locPrf": 50
}
}]
}
@@ -828,7 +828,7 @@ def test_localpref_attribute(request):
# Verifying best path
dut = "r1"
- attribute = "localpref"
+ attribute = "locPrf"
for addr_type in ADDR_TYPES:
result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
{"r7": input_dict["r7"]},
@@ -1437,7 +1437,7 @@ def test_med_attribute(request):
}
},
"set": {
- "med": 100
+ "metric": 100
}
},
{
@@ -1449,7 +1449,7 @@ def test_med_attribute(request):
}
},
"set": {
- "med": 100
+ "metric": 100
}
}]
}
@@ -1465,7 +1465,7 @@ def test_med_attribute(request):
}
},
"set": {
- "med": 10
+ "metric": 10
}
},
{
@@ -1477,7 +1477,7 @@ def test_med_attribute(request):
}
},
"set": {
- "med": 10
+ "metric": 10
}
}]
}
@@ -1593,7 +1593,7 @@ def test_med_attribute(request):
# Verifying best path
dut = "r1"
- attribute = "med"
+ attribute = "metric"
for addr_type in ADDR_TYPES:
result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
input_dict, attribute)
@@ -1613,7 +1613,7 @@ def test_med_attribute(request):
}
},
"set": {
- "med": 200
+ "metric": 200
}
},
{
@@ -1625,7 +1625,7 @@ def test_med_attribute(request):
}
},
"set": {
- "med": 200
+ "metric": 200
}
}]
}
@@ -1638,7 +1638,7 @@ def test_med_attribute(request):
# Verifying best path
dut = "r1"
- attribute = "med"
+ attribute = "metric"
for addr_type in ADDR_TYPES:
result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
input_dict, attribute)
diff --git a/tests/topotests/bgp-route-map/test_route_map_topo1.py b/tests/topotests/bgp-route-map/test_route_map_topo1.py
index 22dd3a6380..c854e5a444 100755
--- a/tests/topotests/bgp-route-map/test_route_map_topo1.py
+++ b/tests/topotests/bgp-route-map/test_route_map_topo1.py
@@ -763,7 +763,7 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request):
}
},
"set": {
- "aspath": {
+ "path": {
"as_num": 500
}
}
@@ -777,7 +777,7 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request):
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
}
},
{
@@ -789,7 +789,7 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request):
}
},
"set": {
- "med": 50
+ "metric": 50
}
}
]
@@ -878,7 +878,7 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request):
"route_maps": {
"rmap_match_pf_list1": [{
"set": {
- "med": 50,
+ "metric": 50,
}
}],
}
@@ -972,8 +972,8 @@ def test_route_map_set_only_no_match_p0(request):
{
"action": "permit",
"set": {
- "med": 50,
- "localpref": 150,
+ "metric": 50,
+ "locPrf": 150,
"weight": 4000
}
}
@@ -1059,7 +1059,7 @@ def test_route_map_set_only_no_match_p0(request):
{
"action": "permit",
"set": {
- "med": 50,
+ "metric": 50,
}
}
]
@@ -1176,8 +1176,8 @@ def test_route_map_match_only_no_set_p0(request):
"rmap_match_pf_1_{}".format(addr_type): [{
"action": "permit",
"set": {
- "med": 50,
- "localpref": 150,
+ "metric": 50,
+ "locPrf": 150,
}
}
]
diff --git a/tests/topotests/bgp-route-map/test_route_map_topo2.py b/tests/topotests/bgp-route-map/test_route_map_topo2.py
index f2398c33ff..609cea5f92 100755
--- a/tests/topotests/bgp-route-map/test_route_map_topo2.py
+++ b/tests/topotests/bgp-route-map/test_route_map_topo2.py
@@ -288,7 +288,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
"weight": 100
}
},
@@ -302,7 +302,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0():
}
},
"set": {
- "med": 50
+ "metric": 50
}
},
]
@@ -506,7 +506,7 @@ def test_modify_set_match_clauses_in_rmap_p0():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
}
}],
"rmap_match_pf_2_{}".format(addr_type): [{
@@ -518,7 +518,7 @@ def test_modify_set_match_clauses_in_rmap_p0():
}
},
"set": {
- "med": 50
+ "metric": 50
}
}]
}
@@ -658,7 +658,7 @@ def test_modify_set_match_clauses_in_rmap_p0():
}
},
"set": {
- "localpref": 1000,
+ "locPrf": 1000,
}
}],
"rmap_match_pf_2_{}".format(addr_type): [{
@@ -670,7 +670,7 @@ def test_modify_set_match_clauses_in_rmap_p0():
}
},
"set": {
- "med": 2000
+ "metric": 2000
}
}]
}
@@ -844,7 +844,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
"weight": 100
}
}],
@@ -857,7 +857,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0():
}
},
"set": {
- "med": 50
+ "metric": 50
}
}]
}
@@ -1093,7 +1093,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
}
}],
"rmap_match_pf_2_{}".format(addr_type): [{
@@ -1105,7 +1105,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0():
}
},
"set": {
- "med": 50
+ "metric": 50
}
}]
}
@@ -1639,7 +1639,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0():
}
},
"set": {
- "localpref": 150
+ "locPrf": 150
}
}]
}
@@ -1664,7 +1664,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0():
}
},
"set": {
- "localpref": 200
+ "locPrf": 200
}
}]
}
@@ -1894,7 +1894,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
}
}]
}
@@ -1919,7 +1919,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
}
}]
}
@@ -2043,7 +2043,7 @@ def test_add_remove_rmap_to_specific_neighbor_p0():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
}
}]
}
@@ -2234,7 +2234,7 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
"weight": 100
}
}]
@@ -2578,7 +2578,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0():
}
},
"set": {
- "med": 50
+ "metric": 50
}
}],
"rmap_match_pf_2_{}".format(addr_type): [{
@@ -2589,7 +2589,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0():
addr_type)
}},
"set": {
- "localpref": 150
+ "locPrf": 150
}
}],
"rmap_match_pf_3_{}".format(addr_type): [{
@@ -2841,9 +2841,9 @@ def test_multiple_set_on_single_sequence_in_rmap_p0():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
"weight": 100,
- "med": 50
+ "metric": 50
}
}]
}
@@ -2985,7 +2985,7 @@ def test_route_maps_with_continue_clause_p0():
}
},
"set": {
- "localpref": 150
+ "locPrf": 150
},
"continue": "30"
},
@@ -2998,7 +2998,7 @@ def test_route_maps_with_continue_clause_p0():
}
},
"set": {
- "med": 200
+ "metric": 200
}
},
{
@@ -3010,7 +3010,7 @@ def test_route_maps_with_continue_clause_p0():
}
},
"set": {
- "med": 100
+ "metric": 100
}
}
]
@@ -3167,7 +3167,7 @@ def test_route_maps_with_goto_clause_p0():
}
},
"set": {
- "med": 100
+ "metric": 100
}
},
{
@@ -3179,7 +3179,7 @@ def test_route_maps_with_goto_clause_p0():
}
},
"set": {
- "med": 200
+ "metric": 200
}
}
]
@@ -3325,7 +3325,7 @@ def test_route_maps_with_call_clause_p0():
}
},
"set": {
- "localpref": 150
+ "locPrf": 150
},
"call": "rmap_match_pf_2_{}".format(addr_type)
}],
@@ -3337,7 +3337,7 @@ def test_route_maps_with_call_clause_p0():
}
},
"set": {
- "med": 200
+ "metric": 200
}
}]
}
@@ -3486,7 +3486,7 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0():
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
}
}],
"rmap_match_pf_2_{}".format(addr_type): [{
@@ -3497,7 +3497,7 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0():
}
},
"set": {
- "med": 50
+ "metric": 50
}
}]
}
diff --git a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py
index d6753e9b23..053f928810 100644
--- a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py
+++ b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py
@@ -110,7 +110,7 @@ def test_bgp_maximum_prefix_invalid():
expected = {
'paths': [
{
- 'med': 123
+ 'metric': 123
}
]
}
diff --git a/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py b/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py
index 992ee85ab1..04a04cce37 100644
--- a/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py
+++ b/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py
@@ -110,7 +110,7 @@ def test_bgp_default_originate_route_map():
expected = {
'paths': [
{
- 'med': 123
+ 'metric': 123
}
]
}
diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
index 83ec1e784d..fcea958a93 100755
--- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
+++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
@@ -598,7 +598,7 @@ def config_for_as_path(tgen, topo, tc_name):
"community_list": {"id": "ANY"}
},
"set": {
- "aspath": {
+ "path": {
"as_num": "4000000",
"as_action": "prepend"
}
diff --git a/tests/topotests/bgp_multiview_topo1/README.md b/tests/topotests/bgp_multiview_topo1/README.md
index 2a2747344a..c1a1445894 100644
--- a/tests/topotests/bgp_multiview_topo1/README.md
+++ b/tests/topotests/bgp_multiview_topo1/README.md
@@ -1,4 +1,4 @@
-# Simple FreeRangeRouting Route-Server Test
+# Simple FRRouting Route-Server Test
## Topology
+----------+ +----------+ +----------+ +----------+ +----------+
diff --git a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py
index f307edc678..d95adc185d 100644
--- a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py
+++ b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py
@@ -130,13 +130,13 @@ def test_bgp_reject_as_sets():
expected = {
'advertisedRoutes': {
'172.16.0.0/16': {
- 'asPath': ''
+ 'path': ''
},
'192.168.254.0/30': {
- 'asPath': '65003'
+ 'path': '65003'
},
'192.168.255.0/30': {
- 'asPath': '65001'
+ 'path': '65001'
}
},
'totalPrefixCounter': 3
diff --git a/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref
index 552e96ddb9..75ce1b149e 100644
--- a/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref
+++ b/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref
@@ -11,15 +11,12 @@
"table":254,
"internalStatus":16,
"internalFlags":13,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"ip":"192.168.2.1",
"afi":"ipv4",
- "interfaceIndex":2,
"interfaceName":"spine1-eth0",
"active":true
}
@@ -38,14 +35,11 @@
"table":254,
"internalStatus":16,
"internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"directlyConnected":true,
- "interfaceIndex":2,
"interfaceName":"spine1-eth0",
"active":true
}
@@ -64,15 +58,12 @@
"table":254,
"internalStatus":16,
"internalFlags":13,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"ip":"192.168.4.2",
"afi":"ipv4",
- "interfaceIndex":3,
"interfaceName":"spine1-eth1",
"active":true
}
@@ -91,23 +82,20 @@
"table":254,
"internalStatus":16,
"internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"directlyConnected":true,
- "interfaceIndex":3,
"interfaceName":"spine1-eth1",
"active":true
}
]
}
],
- "192.168.5.0\/24":[
+ "192.168.5.1\/32":[
{
- "prefix":"192.168.5.0\/24",
+ "prefix":"192.168.5.1\/32",
"protocol":"bgp",
"selected":true,
"destSelected":true,
@@ -117,24 +105,21 @@
"table":254,
"internalStatus":16,
"internalFlags":13,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"ip":"192.168.2.1",
"afi":"ipv4",
- "interfaceIndex":2,
"interfaceName":"spine1-eth0",
"active":true
}
]
}
],
- "192.168.6.0\/24":[
+ "192.168.6.2\/32":[
{
- "prefix":"192.168.6.0\/24",
+ "prefix":"192.168.6.2\/32",
"protocol":"bgp",
"selected":true,
"destSelected":true,
@@ -144,19 +129,16 @@
"table":254,
"internalStatus":16,
"internalFlags":13,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"ip":"192.168.4.2",
"afi":"ipv4",
- "interfaceIndex":3,
"interfaceName":"spine1-eth1",
"active":true
}
]
}
]
-}
+} \ No newline at end of file
diff --git a/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf b/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf
deleted file mode 100644
index a865b388ac..0000000000
--- a/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-hostname spine2
-router bgp 99
- neighbor 192.168.5.1 remote-as internal
- neighbor 192.168.6.2 remote-as internal
- address-family ipv4 uni
- redistribute connected
- neighbor 192.168.5.1 route-reflector-client
- neighbor 192.168.6.2 route-reflector-client
diff --git a/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref
deleted file mode 100644
index c428a8832f..0000000000
--- a/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref
+++ /dev/null
@@ -1,162 +0,0 @@
-{
- "192.168.1.0\/24":[
- {
- "prefix":"192.168.1.0\/24",
- "protocol":"bgp",
- "selected":true,
- "destSelected":true,
- "distance":200,
- "metric":0,
- "installed":true,
- "table":254,
- "internalStatus":16,
- "internalFlags":13,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
- "nexthops":[
- {
- "flags":3,
- "fib":true,
- "ip":"192.168.5.1",
- "afi":"ipv4",
- "interfaceIndex":2,
- "interfaceName":"spine2-eth0",
- "active":true
- }
- ]
- }
- ],
- "192.168.2.0\/24":[
- {
- "prefix":"192.168.2.0\/24",
- "protocol":"bgp",
- "selected":true,
- "destSelected":true,
- "distance":200,
- "metric":0,
- "installed":true,
- "table":254,
- "internalStatus":16,
- "internalFlags":13,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
- "nexthops":[
- {
- "flags":3,
- "fib":true,
- "ip":"192.168.5.1",
- "afi":"ipv4",
- "interfaceIndex":2,
- "interfaceName":"spine2-eth0",
- "active":true
- }
- ]
- }
- ],
- "192.168.3.0\/24":[
- {
- "prefix":"192.168.3.0\/24",
- "protocol":"bgp",
- "selected":true,
- "destSelected":true,
- "distance":200,
- "metric":0,
- "installed":true,
- "table":254,
- "internalStatus":16,
- "internalFlags":13,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
- "nexthops":[
- {
- "flags":3,
- "fib":true,
- "ip":"192.168.6.2",
- "afi":"ipv4",
- "interfaceIndex":3,
- "interfaceName":"spine2-eth1",
- "active":true
- }
- ]
- }
- ],
- "192.168.4.0\/24":[
- {
- "prefix":"192.168.4.0\/24",
- "protocol":"bgp",
- "selected":true,
- "destSelected":true,
- "distance":200,
- "metric":0,
- "installed":true,
- "table":254,
- "internalStatus":16,
- "internalFlags":13,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
- "nexthops":[
- {
- "flags":3,
- "fib":true,
- "ip":"192.168.6.2",
- "afi":"ipv4",
- "interfaceIndex":3,
- "interfaceName":"spine2-eth1",
- "active":true
- }
- ]
- }
- ],
- "192.168.5.0\/24":[
- {
- "prefix":"192.168.5.0\/24",
- "protocol":"connected",
- "selected":true,
- "destSelected":true,
- "distance":0,
- "metric":0,
- "installed":true,
- "table":254,
- "internalStatus":16,
- "internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
- "nexthops":[
- {
- "flags":3,
- "fib":true,
- "directlyConnected":true,
- "interfaceIndex":2,
- "interfaceName":"spine2-eth0",
- "active":true
- }
- ]
- }
- ],
- "192.168.6.0\/24":[
- {
- "prefix":"192.168.6.0\/24",
- "protocol":"connected",
- "selected":true,
- "destSelected":true,
- "distance":0,
- "metric":0,
- "installed":true,
- "table":254,
- "internalStatus":16,
- "internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
- "nexthops":[
- {
- "flags":3,
- "fib":true,
- "directlyConnected":true,
- "interfaceIndex":3,
- "interfaceName":"spine2-eth1",
- "active":true
- }
- ]
- }
- ]
-}
diff --git a/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf b/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf
deleted file mode 100644
index 3ee14d262c..0000000000
--- a/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf
+++ /dev/null
@@ -1 +0,0 @@
-hostname spine2
diff --git a/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf b/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf
deleted file mode 100644
index a06681fbc4..0000000000
--- a/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-hostname spine2
-ip forwarding
-ipv6 forwarding
-
-int spine2-eth0
- ip addr 192.168.5.4/24
-
-int spine2-eth1
- ip addr 192.168.6.4/24
diff --git a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py
index c28394a7a7..c7daa06b76 100755
--- a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py
+++ b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py
@@ -25,47 +25,8 @@
"""
test_bgp_rr_ibgp_topo1.py: Testing IBGP with RR and no IGP
-
- In a leaf/spine topology with only IBGP connections, where
- the same network is being redistributed at multiple points
- in the network ( say a redistribute connected at both leaf and spines )
- we end up in a state where zebra gets very confused.
-
- eva# show ip route
- Codes: K - kernel route, C - connected, S - static, R - RIP,
- O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
- T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
- F - PBR, f - OpenFabric,
- > - selected route, * - FIB route, q - queued route, r - rejected route
-
- C>* 192.168.1.0/24 is directly connected, tor1-eth0, 00:00:30
- C>* 192.168.2.0/24 is directly connected, tor1-eth1, 00:00:30
- B 192.168.3.0/24 [200/0] via 192.168.4.2 inactive, 00:00:25
- via 192.168.6.2 inactive, 00:00:25
- B>* 192.168.4.0/24 [200/0] via 192.168.2.3, tor1-eth1, 00:00:25
- * via 192.168.6.2 inactive, 00:00:25
- C>* 192.168.5.0/24 is directly connected, tor1-eth2, 00:00:30
- B>* 192.168.6.0/24 [200/0] via 192.168.4.2 inactive, 00:00:25
- * via 192.168.5.4, tor1-eth2, 00:00:25
-
- Effectively we have ibgp routes recursing through ibgp routes
- and there is no metric to discern whom to listen to.
-
- This draft:
- https://tools.ietf.org/html/draft-ietf-idr-bgp-optimal-route-reflection-19
-
- appears to address this issue. From looking at both cisco and arista
- deployments they are handling this issue by having the route reflector
- prefer the localy learned routes over from their clients.
-
- Add this topology, in a broken state, so that when we do fix this issue
- it is a simple matter of touching this topology up and re-adding it
- to the normal daily builds. I also wanted to add this topology
- since it is in a state of `doneness` and I wanted to move onto
- my normal day job without having to remember about this test.
-
- This topology is not configured to be run as part of the normal
- topotests.
+Ensure that a basic rr topology comes up and correctly passes
+routes around
"""
@@ -105,7 +66,6 @@ class NetworkTopo(Topo):
tgen.add_router('tor1')
tgen.add_router('tor2')
tgen.add_router('spine1')
- tgen.add_router('spine2')
# First switch is for a dummy interface (for local network)
# on tor1
@@ -128,15 +88,6 @@ class NetworkTopo(Topo):
switch.add_link(tgen.gears['tor2'])
switch.add_link(tgen.gears['spine1'])
- # 192.168.5.0/24 - tor1 <-> spine2 connection
- switch = tgen.add_switch('sw5')
- switch.add_link(tgen.gears['tor1'])
- switch.add_link(tgen.gears['spine2'])
-
- # 192.168.6.0/24 - tor2 <-> spine2 connection
- switch = tgen.add_switch('sw6')
- switch.add_link(tgen.gears['tor2'])
- switch.add_link(tgen.gears['spine2'])
#####################################################
##
diff --git a/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf
index 44a78dffd7..e8ec0f7680 100644
--- a/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf
+++ b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf
@@ -1,5 +1,4 @@
hostname tor1
router bgp 99
neighbor 192.168.2.3 remote-as internal
- neighbor 192.168.5.4 remote-as internal
redistribute connected
diff --git a/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref
index 223dcebbca..6cfa02441f 100644
--- a/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref
+++ b/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref
@@ -11,14 +11,11 @@
"table":254,
"internalStatus":16,
"internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"directlyConnected":true,
- "interfaceIndex":2,
"interfaceName":"tor1-eth0",
"active":true
}
@@ -37,14 +34,11 @@
"table":254,
"internalStatus":16,
"internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"directlyConnected":true,
- "interfaceIndex":3,
"interfaceName":"tor1-eth1",
"active":true
}
@@ -55,23 +49,29 @@
{
"prefix":"192.168.3.0\/24",
"protocol":"bgp",
+ "selected":true,
+ "destSelected":true,
"distance":200,
"metric":0,
+ "installed":true,
"table":254,
- "internalStatus":0,
- "internalFlags":5,
- "internalNextHopNum":2,
- "internalNextHopActiveNum":0,
+ "internalStatus":16,
+ "internalFlags":13,
"nexthops":[
{
- "flags":0,
+ "flags":5,
"ip":"192.168.4.2",
- "afi":"ipv4"
+ "afi":"ipv4",
+ "active":true,
+ "recursive":true
},
{
- "flags":0,
- "ip":"192.168.6.2",
- "afi":"ipv4"
+ "flags":3,
+ "fib":true,
+ "ip":"192.168.2.3",
+ "afi":"ipv4",
+ "interfaceName":"tor1-eth1",
+ "active":true
}
]
}
@@ -88,29 +88,21 @@
"table":254,
"internalStatus":16,
"internalFlags":13,
- "internalNextHopNum":2,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"ip":"192.168.2.3",
"afi":"ipv4",
- "interfaceIndex":3,
"interfaceName":"tor1-eth1",
"active":true
- },
- {
- "flags":0,
- "ip":"192.168.6.2",
- "afi":"ipv4"
}
]
}
],
- "192.168.5.0\/24":[
+ "192.168.5.1\/32":[
{
- "prefix":"192.168.5.0\/24",
+ "prefix":"192.168.5.1\/32",
"protocol":"connected",
"selected":true,
"destSelected":true,
@@ -120,23 +112,20 @@
"table":254,
"internalStatus":16,
"internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"directlyConnected":true,
- "interfaceIndex":4,
- "interfaceName":"tor1-eth2",
+ "interfaceName":"lo",
"active":true
}
]
}
],
- "192.168.6.0\/24":[
+ "192.168.6.2\/32":[
{
- "prefix":"192.168.6.0\/24",
+ "prefix":"192.168.6.2\/32",
"protocol":"bgp",
"selected":true,
"destSelected":true,
@@ -146,21 +135,20 @@
"table":254,
"internalStatus":16,
"internalFlags":13,
- "internalNextHopNum":2,
- "internalNextHopActiveNum":1,
"nexthops":[
{
- "flags":0,
+ "flags":5,
"ip":"192.168.4.2",
- "afi":"ipv4"
+ "afi":"ipv4",
+ "active":true,
+ "recursive":true
},
{
"flags":3,
"fib":true,
- "ip":"192.168.5.4",
+ "ip":"192.168.2.3",
"afi":"ipv4",
- "interfaceIndex":4,
- "interfaceName":"tor1-eth2",
+ "interfaceName":"tor1-eth1",
"active":true
}
]
diff --git a/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf b/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf
index f2fa713507..25b4fcfd0f 100644
--- a/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf
+++ b/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf
@@ -8,5 +8,5 @@ int tor1-eth0
int tor1-eth1
ip addr 192.168.2.1/24
-int tor1-eth2
- ip addr 192.168.5.1/24
+int lo
+ ip addr 192.168.5.1/32
diff --git a/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf
index 5ef1de260e..b091c97ac3 100644
--- a/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf
+++ b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf
@@ -1,5 +1,4 @@
hostname tor2
router bgp 99
neighbor 192.168.4.3 remote-as internal
- neighbor 192.168.6.4 remote-as internal
redistribute connected
diff --git a/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref
index 5f041b8c62..d9e9290e61 100644
--- a/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref
+++ b/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref
@@ -3,23 +3,29 @@
{
"prefix":"192.168.1.0\/24",
"protocol":"bgp",
+ "selected":true,
+ "destSelected":true,
"distance":200,
"metric":0,
+ "installed":true,
"table":254,
- "internalStatus":0,
- "internalFlags":5,
- "internalNextHopNum":2,
- "internalNextHopActiveNum":0,
+ "internalStatus":16,
+ "internalFlags":13,
"nexthops":[
{
- "flags":0,
+ "flags":5,
"ip":"192.168.2.1",
- "afi":"ipv4"
+ "afi":"ipv4",
+ "active":true,
+ "recursive":true
},
{
- "flags":0,
- "ip":"192.168.5.1",
- "afi":"ipv4"
+ "flags":3,
+ "fib":true,
+ "ip":"192.168.4.3",
+ "afi":"ipv4",
+ "interfaceName":"tor2-eth1",
+ "active":true
}
]
}
@@ -36,22 +42,14 @@
"table":254,
"internalStatus":16,
"internalFlags":13,
- "internalNextHopNum":2,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"ip":"192.168.4.3",
"afi":"ipv4",
- "interfaceIndex":3,
"interfaceName":"tor2-eth1",
"active":true
- },
- {
- "flags":0,
- "ip":"192.168.5.1",
- "afi":"ipv4"
}
]
}
@@ -68,14 +66,11 @@
"table":254,
"internalStatus":16,
"internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"directlyConnected":true,
- "interfaceIndex":2,
"interfaceName":"tor2-eth0",
"active":true
}
@@ -94,23 +89,20 @@
"table":254,
"internalStatus":16,
"internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"directlyConnected":true,
- "interfaceIndex":3,
"interfaceName":"tor2-eth1",
"active":true
}
]
}
],
- "192.168.5.0\/24":[
+ "192.168.5.1\/32":[
{
- "prefix":"192.168.5.0\/24",
+ "prefix":"192.168.5.1\/32",
"protocol":"bgp",
"selected":true,
"destSelected":true,
@@ -120,29 +112,28 @@
"table":254,
"internalStatus":16,
"internalFlags":13,
- "internalNextHopNum":2,
- "internalNextHopActiveNum":1,
"nexthops":[
{
- "flags":0,
+ "flags":5,
"ip":"192.168.2.1",
- "afi":"ipv4"
+ "afi":"ipv4",
+ "active":true,
+ "recursive":true
},
{
"flags":3,
"fib":true,
- "ip":"192.168.6.4",
+ "ip":"192.168.4.3",
"afi":"ipv4",
- "interfaceIndex":4,
- "interfaceName":"tor2-eth2",
+ "interfaceName":"tor2-eth1",
"active":true
}
]
}
],
- "192.168.6.0\/24":[
+ "192.168.6.2\/32":[
{
- "prefix":"192.168.6.0\/24",
+ "prefix":"192.168.6.2\/32",
"protocol":"connected",
"selected":true,
"destSelected":true,
@@ -152,15 +143,12 @@
"table":254,
"internalStatus":16,
"internalFlags":8,
- "internalNextHopNum":1,
- "internalNextHopActiveNum":1,
"nexthops":[
{
"flags":3,
"fib":true,
"directlyConnected":true,
- "interfaceIndex":4,
- "interfaceName":"tor2-eth2",
+ "interfaceName":"lo",
"active":true
}
]
diff --git a/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf b/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf
index 3318cbb196..e1a06b14fc 100644
--- a/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf
+++ b/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf
@@ -9,5 +9,5 @@ int tor2-eth1
ip addr 192.168.4.2/24
-int tor2-eth2
- ip addr 192.168.6.2/24
+int lo
+ ip addr 192.168.6.2/32
diff --git a/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py b/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py
index 09e195e22d..387cb0b42f 100644
--- a/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py
+++ b/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py
@@ -113,7 +113,7 @@ def test_bgp_set_local_preference():
expected = {
'paths': [
{
- 'localpref': 50,
+ 'locPrf': 50,
'nexthops': [
{
'ip': '192.168.255.3'
@@ -121,7 +121,7 @@ def test_bgp_set_local_preference():
]
},
{
- 'localpref': 150,
+ 'locPrf': 150,
'nexthops': [
{
'ip': '192.168.255.2'
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/ldpd.conf b/tests/topotests/ldp-oc-acl-topo1/r1/ldpd.conf
new file mode 100644
index 0000000000..85bb970fdf
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/ldpd.conf
@@ -0,0 +1,25 @@
+hostname r1
+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 1.1.1.1
+ ordered-control
+ !
+ address-family ipv4
+ discovery transport-address 1.1.1.1
+ label local allocate host-routes
+ !
+ interface r1-eth0
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf
new file mode 100644
index 0000000000..6daf034d18
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf
@@ -0,0 +1,7 @@
+hostname r1
+log file ospfd.log
+!
+router ospf
+ router-id 1.1.1.1
+ network 0.0.0.0/0 area 0
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..2c493173f5
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_ospf_neighbor.json
@@ -0,0 +1,12 @@
+{
+ "neighbors":{
+ "2.2.2.2":[
+ {
+ "priority":1,
+ "state":"Full\/DR",
+ "address":"10.0.1.2",
+ "ifaceName":"r1-eth0:10.0.1.1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_route.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_route.ref
new file mode 100644
index 0000000000..d75b8f21db
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_route.ref
@@ -0,0 +1,171 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4/32":[
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24":[
+ {
+ "prefix":"10.0.1.0/24",
+ "protocol":"ospf",
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24":[
+ {
+ "prefix":"10.0.2.0/24",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24":[
+ {
+ "prefix":"10.0.3.0/24",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "123.0.1.0/24":[
+ {
+ "prefix":"123.0.1.0/24",
+ "protocol":"ospf",
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"123.0.1.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_all_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_all_binding.ref
new file mode 100644
index 0000000000..99a59668f8
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_all_binding.ref
@@ -0,0 +1,61 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"2.2.2.2",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_binding.ref
new file mode 100644
index 0000000000..ccc8413646
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_binding.ref
@@ -0,0 +1,55 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"2.2.2.2",
+ "localLabel":"-",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"2.2.2.2",
+ "localLabel":"-",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"2.2.2.2",
+ "localLabel":"-",
+ "inUse":1
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_discovery.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_discovery.ref
new file mode 100644
index 0000000000..b349f4418f
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_discovery.ref
@@ -0,0 +1,11 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"link",
+ "interface":"r1-eth0",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..4bff444a46
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_neighbor.ref
@@ -0,0 +1,10 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "state":"OPERATIONAL",
+ "transportAddress":"2.2.2.2"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/zebra.conf b/tests/topotests/ldp-oc-acl-topo1/r1/zebra.conf
new file mode 100644
index 0000000000..83aea46e64
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/zebra.conf
@@ -0,0 +1,17 @@
+log file zebra.log
+!
+hostname r1
+!
+interface lo
+ ip address 1.1.1.1/32
+!
+interface r1-eth0
+ description to sw0
+ ip address 10.0.1.1/24
+ ip address 123.0.1.1/24
+!
+ip forwarding
+!
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/ldpd.conf b/tests/topotests/ldp-oc-acl-topo1/r2/ldpd.conf
new file mode 100644
index 0000000000..e1a552c701
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/ldpd.conf
@@ -0,0 +1,28 @@
+hostname r2
+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 2.2.2.2
+ ordered-control
+ !
+ address-family ipv4
+ discovery transport-address 2.2.2.2
+ !
+ interface r2-eth0
+ !
+ interface r2-eth1
+ !
+ interface r2-eth2
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf
new file mode 100644
index 0000000000..8678813665
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf
@@ -0,0 +1,7 @@
+hostname r2
+log file ospfd.log
+!
+router ospf
+ router-id 2.2.2.2
+ network 0.0.0.0/0 area 0
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..55f12359e5
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_ospf_neighbor.json
@@ -0,0 +1,31 @@
+{
+ "neighbors":{
+ "1.1.1.1":[
+ {
+ "priority":1,
+ "state":"Full\/Backup",
+ "address":"10.0.1.1",
+ "ifaceName":"r2-eth0:10.0.1.2",
+ "retransmitCounter":0,
+ "requestCounter":0,
+ "dbSummaryCounter":0
+ }
+ ],
+ "3.3.3.3":[
+ {
+ "priority":1,
+ "state":"Full\/Backup",
+ "address":"10.0.2.3",
+ "ifaceName":"r2-eth1:10.0.2.2"
+ }
+ ],
+ "4.4.4.4":[
+ {
+ "priority":1,
+ "state":"Full\/DR",
+ "address":"10.0.2.4",
+ "ifaceName":"r2-eth1:10.0.2.2"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_route.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_route.ref
new file mode 100644
index 0000000000..060c0b429d
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_route.ref
@@ -0,0 +1,209 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r2-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4/32":[
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r2-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r2-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "123.0.1.0\/24":[
+ {
+ "prefix":"123.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r2-eth0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_all_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_all_binding.ref
new file mode 100644
index 0000000000..95fb847c1e
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_all_binding.ref
@@ -0,0 +1,63 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"1.1.1.1",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"1.1.1.1",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"3.3.3.3",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"1.1.1.1",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_binding.ref
new file mode 100644
index 0000000000..ea32de3eda
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_binding.ref
@@ -0,0 +1,63 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"1.1.1.1",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"3.3.3.3",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_discovery.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_discovery.ref
new file mode 100644
index 0000000000..8129570082
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_discovery.ref
@@ -0,0 +1,18 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "type":"link",
+ "interface":"r2-eth0",
+ "helloHoldtime":15
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "type":"link",
+ "interface":"r2-eth1",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..eed35289ea
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_neighbor.ref
@@ -0,0 +1,16 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "state":"OPERATIONAL",
+ "transportAddress":"1.1.1.1"
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "state":"OPERATIONAL",
+ "transportAddress":"3.3.3.3"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/zebra.conf b/tests/topotests/ldp-oc-acl-topo1/r2/zebra.conf
new file mode 100644
index 0000000000..1f1e3e391a
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/zebra.conf
@@ -0,0 +1,27 @@
+log file zebra.log
+!
+hostname r2
+!
+interface lo
+ ip address 2.2.2.2/32
+!
+interface r2-eth0
+ description to sw0
+ ip address 10.0.1.2/24
+! no link-detect
+!
+interface r2-eth1
+ description to sw1
+ ip address 10.0.2.2/24
+! no link-detect
+!
+interface r2-eths2
+ description to sw2
+ ip address 10.0.3.2/24
+! no link-detect
+!
+ip forwarding
+!
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/ldpd.conf b/tests/topotests/ldp-oc-acl-topo1/r3/ldpd.conf
new file mode 100644
index 0000000000..4e66b140ac
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/ldpd.conf
@@ -0,0 +1,24 @@
+hostname r3
+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 3.3.3.3
+ ordered-control
+ !
+ address-family ipv4
+ discovery transport-address 3.3.3.3
+ !
+ interface r3-eth0
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf
new file mode 100644
index 0000000000..202be238ec
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf
@@ -0,0 +1,8 @@
+hostname r3
+password 1
+log file ospfd.log
+!
+router ospf
+ router-id 3.3.3.3
+ network 0.0.0.0/0 area 0
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..24502ed813
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_ospf_neighbor.json
@@ -0,0 +1,20 @@
+{
+ "neighbors":{
+ "2.2.2.2":[
+ {
+ "priority":1,
+ "state":"Full\/DROther",
+ "address":"10.0.2.2",
+ "ifaceName":"r3-eth0:10.0.2.3"
+ }
+ ],
+ "4.4.4.4":[
+ {
+ "priority":1,
+ "state":"Full\/DR",
+ "address":"10.0.2.4",
+ "ifaceName":"r3-eth0:10.0.2.3"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_route.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_route.ref
new file mode 100644
index 0000000000..40800762ba
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_route.ref
@@ -0,0 +1,209 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4/32":[
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "123.0.1.0\/24":[
+ {
+ "prefix":"123.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_all_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_all_binding.ref
new file mode 100644
index 0000000000..100dd307ea
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_all_binding.ref
@@ -0,0 +1,61 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"2.2.2.2",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_binding.ref
new file mode 100644
index 0000000000..bb1b2b3023
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_binding.ref
@@ -0,0 +1,62 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"2.2.2.2",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_discovery.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_discovery.ref
new file mode 100644
index 0000000000..c3a07e7e38
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_discovery.ref
@@ -0,0 +1,11 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"link",
+ "interface":"r3-eth0",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..4bff444a46
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_neighbor.ref
@@ -0,0 +1,10 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "state":"OPERATIONAL",
+ "transportAddress":"2.2.2.2"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/zebra.conf b/tests/topotests/ldp-oc-acl-topo1/r3/zebra.conf
new file mode 100644
index 0000000000..234c215ddf
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname r3
+!
+interface lo
+ ip address 3.3.3.3/32
+!
+interface r3-eth0
+ description to sw1
+ ip address 10.0.2.3/24
+! no link-detect
+!
+interface r3-eth1
+ description to sw2
+ ip address 10.0.3.3/24
+! no link-detect
+!
+ip forwarding
+!
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/ldpd.conf b/tests/topotests/ldp-oc-acl-topo1/r4/ldpd.conf
new file mode 100644
index 0000000000..6b7d28f983
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/ldpd.conf
@@ -0,0 +1,24 @@
+hostname r4
+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 4.4.4.4
+ ordered-control
+ !
+ address-family ipv4
+ discovery transport-address 4.4.4.4
+ !
+ !interface r4-eth0
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf
new file mode 100644
index 0000000000..569dbc54e2
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf
@@ -0,0 +1,7 @@
+hostname r4
+log file ospfd.log
+!
+router ospf
+ router-id 4.4.4.4
+ network 0.0.0.0/0 area 0
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..794410522d
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_ospf_neighbor.json
@@ -0,0 +1,21 @@
+
+{
+ "neighbors":{
+ "2.2.2.2":[
+ {
+ "priority":1,
+ "state":"Full\/DROther",
+ "address":"10.0.2.2",
+ "ifaceName":"r4-eth0:10.0.2.4"
+ }
+ ],
+ "3.3.3.3":[
+ {
+ "priority":1,
+ "state":"Full\/Backup",
+ "address":"10.0.2.3",
+ "ifaceName":"r4-eth0:10.0.2.4"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_route.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_route.ref
new file mode 100644
index 0000000000..c9b83a1c73
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_route.ref
@@ -0,0 +1,196 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4/32":[
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "123.0.1.0\/24":[
+ {
+ "prefix":"123.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_all_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_all_binding.ref
new file mode 100644
index 0000000000..2a46c40346
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_all_binding.ref
@@ -0,0 +1,68 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_binding.ref
new file mode 100644
index 0000000000..2a46c40346
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_binding.ref
@@ -0,0 +1,68 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_discovery.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_discovery.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_discovery.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_neighbor.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/zebra.conf b/tests/topotests/ldp-oc-acl-topo1/r4/zebra.conf
new file mode 100644
index 0000000000..7e291053e5
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/zebra.conf
@@ -0,0 +1,17 @@
+log file zebra.log
+!
+hostname r4
+!
+interface lo
+ ip address 4.4.4.4/32
+!
+interface r4-eth0
+ description to sw1
+ ip address 10.0.2.4/24
+! no link-detect
+!
+ip forwarding
+!
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.dot b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.dot
new file mode 100644
index 0000000000..62058e3cb1
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.dot
@@ -0,0 +1,76 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="Test Topology - LDP-OC 1";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+
+ # Switches
+ s0 [
+ shape=oval,
+ label="10.0.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s1 [
+ shape=oval,
+ label="10.0.2.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="10.0.3.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+
+ r1 -- s0 [label="eth0"];
+ r2 -- s0 [label="eth0"];
+
+ r2 -- s1 [label="eth1"];
+ r3 -- s1 [label="eth0"];
+ r4 -- s1 [label="eth0"];
+
+ r2 -- s2 [label="eth2"];
+ r3 -- s2 [label="eth1"];
+}
diff --git a/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py
new file mode 100755
index 0000000000..9695c0d345
--- /dev/null
+++ b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py
@@ -0,0 +1,243 @@
+#!/usr/bin/env python
+
+#
+# test_ldp_oc_acl_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by Volta Networks
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_ldp_oc_acl_topo1.py: Simple FRR/Quagga LDP Test
+
+ +---------+
+ | r1 |
+ | 1.1.1.1 |
+ +----+----+
+ | .1 r1-eth0
+ |
+ ~~~~~~~~~~~~~
+ ~~ sw0 ~~
+ ~~ 10.0.1.0/24 ~~
+ ~~~~~~~~~~~~~
+ |10.0.1.0/24
+ |
+ | .2 r2-eth0
+ +----+----+
+ | r2 |
+ | 2.2.2.2 |
+ +--+---+--+
+ r2-eth2 .2 | | .2 r2-eth1
+ ______/ \______
+ / \
+ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~
+~~ sw2 ~~ ~~ sw1 ~~
+~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~
+ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~
+ | / |
+ \ _________/ |
+ \ / \
+r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0
+ +----+--+---+ +----+----+
+ | r3 | | r4 |
+ | 3.3.3.3 | | 4.4.4.4 |
+ +-----------+ +---------+
+"""
+
+import os
+import sys
+import pytest
+import json
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ #
+ # Define FRR Routers
+ #
+ for router in ['r1', 'r2', 'r3', 'r4']:
+ tgen.add_router(router)
+
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch('s0')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r2'])
+ 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):
+ "Sets up the pytest environment"
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ # Don't start ospfd and ldpd in the CE nodes
+ if router.name[0] == 'r':
+ router.load_config(
+ TopoRouter.RD_OSPF,
+ os.path.join(CWD, '{}/ospfd.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_LDP,
+ os.path.join(CWD, '{}/ldpd.conf'.format(rname))
+ )
+
+ tgen.start_router()
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def router_compare_json_output(rname, command, reference):
+ "Compare router JSON output"
+
+ logger.info('Comparing router "%s" "%s" output', rname, command)
+
+ tgen = get_topogen()
+ filename = '{}/{}/{}'.format(CWD, rname, reference)
+ expected = json.loads(open(filename).read())
+
+ # Run test function until we get an result. Wait at most 80 seconds.
+ test_func = partial(topotest.router_json_cmp,
+ tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=160, wait=0.5)
+
+ assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+def test_ospf_convergence():
+ logger.info("Test: check OSPF adjacencies")
+
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json")
+
+def test_rib():
+ logger.info("Test: verify RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show ip route json", "show_ip_route.ref")
+
+def test_ldp_adjacencies():
+ logger.info("Test: verify LDP adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show mpls ldp discovery json", "show_ldp_discovery.ref")
+
+def test_ldp_neighbors():
+ logger.info("Test: verify LDP neighbors")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show mpls ldp neighbor json", "show_ldp_neighbor.ref")
+
+def test_ldp_bindings():
+ logger.info("Test: verify LDP bindings")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show mpls ldp binding json", "show_ldp_binding.ref")
+
+def test_ldp_bindings_all_routes():
+ logger.info("Test: verify LDP bindings after host filter removed")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # remove ACL that blocks advertising everything but host routes */
+ cmd = 'vtysh -c \"configure terminal\" -c \"mpls ldp\" -c \"address-family ipv4\" -c \"no label local allocate host-routes\"'
+ tgen.net['r1'].cmd(cmd)
+ sleep(2)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show mpls ldp binding json", "show_ldp_all_binding.ref")
+
+# Memory leak test template
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ldp-oc-topo1/r1/ldpd.conf b/tests/topotests/ldp-oc-topo1/r1/ldpd.conf
new file mode 100644
index 0000000000..2a8e023832
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r1/ldpd.conf
@@ -0,0 +1,24 @@
+hostname r1
+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 1.1.1.1
+ ordered-control
+ !
+ address-family ipv4
+ discovery transport-address 1.1.1.1
+ !
+ interface r1-eth0
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-topo1/r1/ospfd.conf b/tests/topotests/ldp-oc-topo1/r1/ospfd.conf
new file mode 100644
index 0000000000..6daf034d18
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r1/ospfd.conf
@@ -0,0 +1,7 @@
+hostname r1
+log file ospfd.log
+!
+router ospf
+ router-id 1.1.1.1
+ network 0.0.0.0/0 area 0
+!
diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-topo1/r1/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..2c493173f5
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r1/show_ip_ospf_neighbor.json
@@ -0,0 +1,12 @@
+{
+ "neighbors":{
+ "2.2.2.2":[
+ {
+ "priority":1,
+ "state":"Full\/DR",
+ "address":"10.0.1.2",
+ "ifaceName":"r1-eth0:10.0.1.1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ip_route.ref b/tests/topotests/ldp-oc-topo1/r1/show_ip_route.ref
new file mode 100644
index 0000000000..d75b8f21db
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r1/show_ip_route.ref
@@ -0,0 +1,171 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4/32":[
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24":[
+ {
+ "prefix":"10.0.1.0/24",
+ "protocol":"ospf",
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24":[
+ {
+ "prefix":"10.0.2.0/24",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24":[
+ {
+ "prefix":"10.0.3.0/24",
+ "protocol":"ospf",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "123.0.1.0/24":[
+ {
+ "prefix":"123.0.1.0/24",
+ "protocol":"ospf",
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"123.0.1.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ldp_binding.ref b/tests/topotests/ldp-oc-topo1/r1/show_ldp_binding.ref
new file mode 100644
index 0000000000..99a59668f8
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r1/show_ldp_binding.ref
@@ -0,0 +1,61 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"2.2.2.2",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ldp_discovery.ref b/tests/topotests/ldp-oc-topo1/r1/show_ldp_discovery.ref
new file mode 100644
index 0000000000..b349f4418f
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r1/show_ldp_discovery.ref
@@ -0,0 +1,11 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"link",
+ "interface":"r1-eth0",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-topo1/r1/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..4bff444a46
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r1/show_ldp_neighbor.ref
@@ -0,0 +1,10 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "state":"OPERATIONAL",
+ "transportAddress":"2.2.2.2"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r1/zebra.conf b/tests/topotests/ldp-oc-topo1/r1/zebra.conf
new file mode 100644
index 0000000000..83aea46e64
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r1/zebra.conf
@@ -0,0 +1,17 @@
+log file zebra.log
+!
+hostname r1
+!
+interface lo
+ ip address 1.1.1.1/32
+!
+interface r1-eth0
+ description to sw0
+ ip address 10.0.1.1/24
+ ip address 123.0.1.1/24
+!
+ip forwarding
+!
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-topo1/r2/ldpd.conf b/tests/topotests/ldp-oc-topo1/r2/ldpd.conf
new file mode 100644
index 0000000000..e1a552c701
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r2/ldpd.conf
@@ -0,0 +1,28 @@
+hostname r2
+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 2.2.2.2
+ ordered-control
+ !
+ address-family ipv4
+ discovery transport-address 2.2.2.2
+ !
+ interface r2-eth0
+ !
+ interface r2-eth1
+ !
+ interface r2-eth2
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-topo1/r2/ospfd.conf b/tests/topotests/ldp-oc-topo1/r2/ospfd.conf
new file mode 100644
index 0000000000..8678813665
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r2/ospfd.conf
@@ -0,0 +1,7 @@
+hostname r2
+log file ospfd.log
+!
+router ospf
+ router-id 2.2.2.2
+ network 0.0.0.0/0 area 0
+!
diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-topo1/r2/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..55f12359e5
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r2/show_ip_ospf_neighbor.json
@@ -0,0 +1,31 @@
+{
+ "neighbors":{
+ "1.1.1.1":[
+ {
+ "priority":1,
+ "state":"Full\/Backup",
+ "address":"10.0.1.1",
+ "ifaceName":"r2-eth0:10.0.1.2",
+ "retransmitCounter":0,
+ "requestCounter":0,
+ "dbSummaryCounter":0
+ }
+ ],
+ "3.3.3.3":[
+ {
+ "priority":1,
+ "state":"Full\/Backup",
+ "address":"10.0.2.3",
+ "ifaceName":"r2-eth1:10.0.2.2"
+ }
+ ],
+ "4.4.4.4":[
+ {
+ "priority":1,
+ "state":"Full\/DR",
+ "address":"10.0.2.4",
+ "ifaceName":"r2-eth1:10.0.2.2"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ip_route.ref b/tests/topotests/ldp-oc-topo1/r2/show_ip_route.ref
new file mode 100644
index 0000000000..060c0b429d
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r2/show_ip_route.ref
@@ -0,0 +1,209 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r2-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4/32":[
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r2-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r2-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "123.0.1.0\/24":[
+ {
+ "prefix":"123.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r2-eth0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ldp_binding.ref b/tests/topotests/ldp-oc-topo1/r2/show_ldp_binding.ref
new file mode 100644
index 0000000000..95fb847c1e
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r2/show_ldp_binding.ref
@@ -0,0 +1,63 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"1.1.1.1",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"1.1.1.1",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"3.3.3.3",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"1.1.1.1",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ldp_discovery.ref b/tests/topotests/ldp-oc-topo1/r2/show_ldp_discovery.ref
new file mode 100644
index 0000000000..8129570082
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r2/show_ldp_discovery.ref
@@ -0,0 +1,18 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "type":"link",
+ "interface":"r2-eth0",
+ "helloHoldtime":15
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "type":"link",
+ "interface":"r2-eth1",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-topo1/r2/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..eed35289ea
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r2/show_ldp_neighbor.ref
@@ -0,0 +1,16 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "state":"OPERATIONAL",
+ "transportAddress":"1.1.1.1"
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "state":"OPERATIONAL",
+ "transportAddress":"3.3.3.3"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r2/zebra.conf b/tests/topotests/ldp-oc-topo1/r2/zebra.conf
new file mode 100644
index 0000000000..1f1e3e391a
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r2/zebra.conf
@@ -0,0 +1,27 @@
+log file zebra.log
+!
+hostname r2
+!
+interface lo
+ ip address 2.2.2.2/32
+!
+interface r2-eth0
+ description to sw0
+ ip address 10.0.1.2/24
+! no link-detect
+!
+interface r2-eth1
+ description to sw1
+ ip address 10.0.2.2/24
+! no link-detect
+!
+interface r2-eths2
+ description to sw2
+ ip address 10.0.3.2/24
+! no link-detect
+!
+ip forwarding
+!
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-topo1/r3/ldpd.conf b/tests/topotests/ldp-oc-topo1/r3/ldpd.conf
new file mode 100644
index 0000000000..4e66b140ac
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r3/ldpd.conf
@@ -0,0 +1,24 @@
+hostname r3
+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 3.3.3.3
+ ordered-control
+ !
+ address-family ipv4
+ discovery transport-address 3.3.3.3
+ !
+ interface r3-eth0
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-topo1/r3/ospfd.conf b/tests/topotests/ldp-oc-topo1/r3/ospfd.conf
new file mode 100644
index 0000000000..202be238ec
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r3/ospfd.conf
@@ -0,0 +1,8 @@
+hostname r3
+password 1
+log file ospfd.log
+!
+router ospf
+ router-id 3.3.3.3
+ network 0.0.0.0/0 area 0
+!
diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-topo1/r3/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..24502ed813
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r3/show_ip_ospf_neighbor.json
@@ -0,0 +1,20 @@
+{
+ "neighbors":{
+ "2.2.2.2":[
+ {
+ "priority":1,
+ "state":"Full\/DROther",
+ "address":"10.0.2.2",
+ "ifaceName":"r3-eth0:10.0.2.3"
+ }
+ ],
+ "4.4.4.4":[
+ {
+ "priority":1,
+ "state":"Full\/DR",
+ "address":"10.0.2.4",
+ "ifaceName":"r3-eth0:10.0.2.3"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ip_route.ref b/tests/topotests/ldp-oc-topo1/r3/show_ip_route.ref
new file mode 100644
index 0000000000..40800762ba
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r3/show_ip_route.ref
@@ -0,0 +1,209 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4/32":[
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "123.0.1.0\/24":[
+ {
+ "prefix":"123.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ldp_binding.ref b/tests/topotests/ldp-oc-topo1/r3/show_ldp_binding.ref
new file mode 100644
index 0000000000..100dd307ea
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r3/show_ldp_binding.ref
@@ -0,0 +1,61 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"2.2.2.2",
+ "localLabel":"imp-null",
+ "remoteLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"2.2.2.2",
+ "inUse":1
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ldp_discovery.ref b/tests/topotests/ldp-oc-topo1/r3/show_ldp_discovery.ref
new file mode 100644
index 0000000000..c3a07e7e38
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r3/show_ldp_discovery.ref
@@ -0,0 +1,11 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"link",
+ "interface":"r3-eth0",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-topo1/r3/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..4bff444a46
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r3/show_ldp_neighbor.ref
@@ -0,0 +1,10 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "state":"OPERATIONAL",
+ "transportAddress":"2.2.2.2"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r3/zebra.conf b/tests/topotests/ldp-oc-topo1/r3/zebra.conf
new file mode 100644
index 0000000000..234c215ddf
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r3/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname r3
+!
+interface lo
+ ip address 3.3.3.3/32
+!
+interface r3-eth0
+ description to sw1
+ ip address 10.0.2.3/24
+! no link-detect
+!
+interface r3-eth1
+ description to sw2
+ ip address 10.0.3.3/24
+! no link-detect
+!
+ip forwarding
+!
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-topo1/r4/ldpd.conf b/tests/topotests/ldp-oc-topo1/r4/ldpd.conf
new file mode 100644
index 0000000000..6b7d28f983
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r4/ldpd.conf
@@ -0,0 +1,24 @@
+hostname r4
+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 4.4.4.4
+ ordered-control
+ !
+ address-family ipv4
+ discovery transport-address 4.4.4.4
+ !
+ !interface r4-eth0
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-topo1/r4/ospfd.conf b/tests/topotests/ldp-oc-topo1/r4/ospfd.conf
new file mode 100644
index 0000000000..569dbc54e2
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r4/ospfd.conf
@@ -0,0 +1,7 @@
+hostname r4
+log file ospfd.log
+!
+router ospf
+ router-id 4.4.4.4
+ network 0.0.0.0/0 area 0
+!
diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-topo1/r4/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..794410522d
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r4/show_ip_ospf_neighbor.json
@@ -0,0 +1,21 @@
+
+{
+ "neighbors":{
+ "2.2.2.2":[
+ {
+ "priority":1,
+ "state":"Full\/DROther",
+ "address":"10.0.2.2",
+ "ifaceName":"r4-eth0:10.0.2.4"
+ }
+ ],
+ "3.3.3.3":[
+ {
+ "priority":1,
+ "state":"Full\/Backup",
+ "address":"10.0.2.3",
+ "ifaceName":"r4-eth0:10.0.2.4"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ip_route.ref b/tests/topotests/ldp-oc-topo1/r4/show_ip_route.ref
new file mode 100644
index 0000000000..c9b83a1c73
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r4/show_ip_route.ref
@@ -0,0 +1,196 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":10,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4/32":[
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"4.4.4.4/32",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "123.0.1.0\/24":[
+ {
+ "prefix":"123.0.1.0\/24",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "distance":110,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"r4-eth0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ldp_binding.ref b/tests/topotests/ldp-oc-topo1/r4/show_ldp_binding.ref
new file mode 100644
index 0000000000..2a46c40346
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r4/show_ldp_binding.ref
@@ -0,0 +1,68 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"4.4.4.4/32",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.2.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"10.0.3.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"123.0.1.0/24",
+ "neighborId":"0.0.0.0",
+ "localLabel":"imp-null",
+ "remoteLabel":"-",
+ "inUse":0
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ldp_discovery.ref b/tests/topotests/ldp-oc-topo1/r4/show_ldp_discovery.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r4/show_ldp_discovery.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-topo1/r4/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r4/show_ldp_neighbor.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/ldp-oc-topo1/r4/zebra.conf b/tests/topotests/ldp-oc-topo1/r4/zebra.conf
new file mode 100644
index 0000000000..7e291053e5
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/r4/zebra.conf
@@ -0,0 +1,17 @@
+log file zebra.log
+!
+hostname r4
+!
+interface lo
+ ip address 4.4.4.4/32
+!
+interface r4-eth0
+ description to sw1
+ ip address 10.0.2.4/24
+! no link-detect
+!
+ip forwarding
+!
+!
+line vty
+!
diff --git a/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.dot b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.dot
new file mode 100644
index 0000000000..62058e3cb1
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.dot
@@ -0,0 +1,76 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="Test Topology - LDP-OC 1";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+
+ # Switches
+ s0 [
+ shape=oval,
+ label="10.0.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s1 [
+ shape=oval,
+ label="10.0.2.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="10.0.3.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+
+ r1 -- s0 [label="eth0"];
+ r2 -- s0 [label="eth0"];
+
+ r2 -- s1 [label="eth1"];
+ r3 -- s1 [label="eth0"];
+ r4 -- s1 [label="eth0"];
+
+ r2 -- s2 [label="eth2"];
+ r3 -- s2 [label="eth1"];
+}
diff --git a/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py
new file mode 100755
index 0000000000..eda1b37e52
--- /dev/null
+++ b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py
@@ -0,0 +1,227 @@
+#!/usr/bin/env python
+
+#
+# test_ldp_oc_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by by Volta Networks
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_ldp_oc_topo1.py: Simple FRR/Quagga LDP Test
+
+ +---------+
+ | r1 |
+ | 1.1.1.1 |
+ +----+----+
+ | .1 r1-eth0
+ |
+ ~~~~~~~~~~~~~
+ ~~ sw0 ~~
+ ~~ 10.0.1.0/24 ~~
+ ~~~~~~~~~~~~~
+ |10.0.1.0/24
+ |
+ | .2 r2-eth0
+ +----+----+
+ | r2 |
+ | 2.2.2.2 |
+ +--+---+--+
+ r2-eth2 .2 | | .2 r2-eth1
+ ______/ \______
+ / \
+ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~
+~~ sw2 ~~ ~~ sw1 ~~
+~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~
+ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~
+ | / |
+ \ _________/ |
+ \ / \
+r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0
+ +----+--+---+ +----+----+
+ | r3 | | r4 |
+ | 3.3.3.3 | | 4.4.4.4 |
+ +-----------+ +---------+
+"""
+
+import os
+import sys
+import pytest
+import json
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ #
+ # Define FRR Routers
+ #
+ for router in ['r1', 'r2', 'r3', 'r4']:
+ tgen.add_router(router)
+
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch('s0')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r2'])
+ 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):
+ "Sets up the pytest environment"
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ # Don't start ospfd and ldpd in the CE nodes
+ if router.name[0] == 'r':
+ router.load_config(
+ TopoRouter.RD_OSPF,
+ os.path.join(CWD, '{}/ospfd.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_LDP,
+ os.path.join(CWD, '{}/ldpd.conf'.format(rname))
+ )
+
+ tgen.start_router()
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def router_compare_json_output(rname, command, reference):
+ "Compare router JSON output"
+
+ logger.info('Comparing router "%s" "%s" output', rname, command)
+
+ tgen = get_topogen()
+ filename = '{}/{}/{}'.format(CWD, rname, reference)
+ expected = json.loads(open(filename).read())
+
+ # Run test function until we get an result. Wait at most 80 seconds.
+ test_func = partial(topotest.router_json_cmp,
+ tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=160, wait=0.5)
+
+ assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+def test_ospf_convergence():
+ logger.info("Test: check OSPF adjacencies")
+
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json")
+
+def test_rib():
+ logger.info("Test: verify RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show ip route json", "show_ip_route.ref")
+
+def test_ldp_adjacencies():
+ logger.info("Test: verify LDP adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show mpls ldp discovery json", "show_ldp_discovery.ref")
+
+def test_ldp_neighbors():
+ logger.info("Test: verify LDP neighbors")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show mpls ldp neighbor json", "show_ldp_neighbor.ref")
+
+def test_ldp_bindings():
+ logger.info("Test: verify LDP bindings")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['r1', 'r2', 'r3', 'r4']:
+ router_compare_json_output(rname, "show mpls ldp binding json", "show_ldp_binding.ref")
+
+# Memory leak test template
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref
index f244122f1a..a13c1d459b 100644
--- a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref
+++ b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref
@@ -3,3 +3,4 @@ xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx
xx via inet 10.0.1.2 dev r1-eth0 proto xx
xx via inet 10.0.1.2 dev r1-eth0 proto xx
xx via inet 10.0.1.2 dev r1-eth0 proto xx
+
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 997b72d691..15f970ba75 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -1256,7 +1256,7 @@ def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name,
}
},
"set": {
- "localpref": 150,
+ "locPrf": 150,
"weight": 100
}
}],
@@ -1269,7 +1269,7 @@ def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name,
}
},
"set": {
- "med": 50
+ "metric": 50
}
}]
}
@@ -1406,7 +1406,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict,
}
}
}
- attribute = "localpref"
+ attribute = "locPrf"
result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, \
input_dict, attribute)
Returns
@@ -1443,14 +1443,14 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict,
attribute_dict[next_hop_ip] = route_attribute[attribute]
# AS_PATH attribute
- if attribute == "aspath":
+ if attribute == "path":
# Find next_hop for the route have minimum as_path
_next_hop = min(attribute_dict, key=lambda x: len(set(
attribute_dict[x])))
compare = "SHORTEST"
# LOCAL_PREF attribute
- elif attribute == "localpref":
+ elif attribute == "locPrf":
# Find next_hop for the route have highest local preference
_next_hop = max(attribute_dict, key=(lambda k:
attribute_dict[k]))
@@ -1473,7 +1473,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict,
compare = ""
# MED attribute
- elif attribute == "med":
+ elif attribute == "metric":
# Find next_hop for the route have LOWEST MED
_next_hop = min(attribute_dict, key=(lambda k:
attribute_dict[k]))
@@ -1548,7 +1548,7 @@ def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict,
{"network": "200.50.2.0/32", \
"admin_distance": 60, "next_hop": "10.0.0.18"}]
}}
- attribute = "localpref"
+ attribute = "locPrf"
result = verify_best_path_as_per_admin_distance(tgen, "ipv4", dut, \
input_dict, attribute):
Returns
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index fc7581b1f2..8a9d2d64c9 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -1101,9 +1101,9 @@ def create_route_maps(tgen, input_dict, build=False):
"tag": "tag_id"
},
"set": {
- "localpref": 150,
- "med": 30,
- "aspath": {
+ "locPrf": 150,
+ "metric": 30,
+ "path": {
"num": 20000,
"action": "prepend",
},
@@ -1199,10 +1199,10 @@ def create_route_maps(tgen, input_dict, build=False):
set_data = rmap_dict["set"]
ipv4_data = set_data.setdefault("ipv4", {})
ipv6_data = set_data.setdefault("ipv6", {})
- local_preference = set_data.setdefault("localpref",
+ local_preference = set_data.setdefault("locPrf",
None)
- metric = set_data.setdefault("med", None)
- as_path = set_data.setdefault("aspath", {})
+ metric = set_data.setdefault("metric", None)
+ as_path = set_data.setdefault("path", {})
weight = set_data.setdefault("weight", None)
community = set_data.setdefault("community", {})
large_community = set_data.setdefault(
diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini
index 62c825341f..ade5bfd501 100644
--- a/tests/topotests/pytest.ini
+++ b/tests/topotests/pytest.ini
@@ -1,6 +1,6 @@
# Skip pytests example directory
[pytest]
-norecursedirs = .git example-test example-topojson-test lib docker bgp_rr_ibgp
+norecursedirs = .git example-test example-topojson-test lib docker
[topogen]
# Default configuration values
diff --git a/tools/gcc-plugins/.gitignore b/tools/gcc-plugins/.gitignore
new file mode 100644
index 0000000000..dd8d0cb7ee
--- /dev/null
+++ b/tools/gcc-plugins/.gitignore
@@ -0,0 +1,7 @@
+*.so
+*.o
+debian/.debhelper
+debian/files
+debian/*.substvars
+debian/gcc-9-frr-plugin
+!gcc-retain-typeinfo.patch
diff --git a/tools/gcc-plugins/COPYING.GPLv3 b/tools/gcc-plugins/COPYING.GPLv3
new file mode 100644
index 0000000000..94a9ed024d
--- /dev/null
+++ b/tools/gcc-plugins/COPYING.GPLv3
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 3 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. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/tools/gcc-plugins/Makefile b/tools/gcc-plugins/Makefile
new file mode 100644
index 0000000000..d6edd745ce
--- /dev/null
+++ b/tools/gcc-plugins/Makefile
@@ -0,0 +1,19 @@
+all: frr-format.so
+
+CXX=g++-9
+
+PLUGBASE=`$(CXX) -print-file-name=plugin`
+CPPFLAGS=-I$(PLUGBASE)/include -I$(PLUGBASE)/include/c-family
+
+frr-format.so: frr-format.o
+ $(CXX) -g -shared -o $@ $^
+
+frr-format.o: frr-format.c gcc-common.h
+ $(CXX) -g $(CPPFLAGS) -fPIC -Wall -Wextra -Wno-unused-parameter -c -o $@ $<
+
+install:
+ install -d $(DESTDIR)$(PLUGBASE)
+ install frr-format.so $(DESTDIR)$(PLUGBASE)
+
+clean:
+ rm -f frr-format.so frr-format.o
diff --git a/tools/gcc-plugins/README.md b/tools/gcc-plugins/README.md
new file mode 100644
index 0000000000..94a9635e76
--- /dev/null
+++ b/tools/gcc-plugins/README.md
@@ -0,0 +1,99 @@
+frr-format GCC plugin
+=====================
+
+Context
+-------
+
+This plugin provides improved type checking for Linux kernel style printf
+extensions (i.e. `%pI4` printing `struct in_addr *` as `1.2.3.4`.)
+
+Other than additional warnings, (non-)usage of this plugin should not affect
+the build outcome. It is perfectly fine to build FRR without this plugin.
+
+
+Binary Debian packages
+----------------------
+
+Can be found at [https://deb.nox.tf/devel/].
+
+
+GCC requirements
+----------------
+
+To use this plugin, you need a **patched 9.3.0** version of GCC using the
+[gcc-retain-typeinfo.patch] provided in this repo. Without this patch, GCC
+strips type information too early during compilation, leaving to the plugin
+being unable to perform more meaningful type checks. (Specifically, all
+`typedef` types will be "cooked down" to their final type.)
+
+(@eqvinox has discussed this one-line diff with some GCC people on their
+IRC channel around mid 2019, the consensus was that the line is an "early
+optimization" and removing it should not be harmful. However, doing so is
+likely to break GCC's unit tests since warnings would print different types.)
+
+Other versions of gcc are not supported. gcc 8 previously did work but isn't
+actively tested/maintained. gcc 10 is not supported yet but may work.
+
+
+Usage
+-----
+
+First, all plugin-specific statements should be wrapped by an ifdef:
+
+```
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+...
+#endif
+```
+
+`_FRR_ATTRIBUTE_PRINTFRR` will be defined to the plugin's version (currently
+0x10000) whenever the plugin is loaded.
+
+Then, annotate extended printf functions with the `frr_format` attribute.
+This works exactly like the `format` attribute:
+
+```
+int printfn(const char *fmt, ...) __attribute__((frr_format("frr_printf", 1, 2)));
+```
+
+In the FRR codebase, use the `PRINTFRR` macro provided in
+[../../lib/compiler.h].
+
+Lastly, "declare" extensions with `#pragma FRR printfrr_ext`:
+```
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pI4" (struct in_addr *)
+#pragma FRR printfrr_ext "%pI4" (in_addr_t *)
+#endif
+```
+
+Note that you can use multiple such lines if a particular extended printer
+works for more than one type (as seen above.)
+
+The pragma type "parameter" looks like a C cast but unfortunately due to GCC
+not exporting a good interface to proper type parsing, it is "ghetto parsed",
+with only `struct`, `union`, `enum` being properly supported. `const` is
+ignored if it occurs as the first token. (The plugin always accepts `const`
+parameters for printf since printf shouldn't change the passed data it's
+printing.) The last token may be zero or more counts of `*`, note that
+qualifiers on the intermediate pointers (e.g. `const char * const *`) are not
+supported.
+
+
+TODOs and future direction
+--------------------------
+
+* support two-parameter extension printers that use the precision field
+ (e.g. `"%.*pI5" (int af, void *addr)` to print an IP address with the
+ address family in the "precision".
+
+* port to future GCC versions
+
+* get the one-liner patch upstreamed
+
+
+License
+-------
+
+This plugin is **derivative of GCC 9.x**. It was created by copying off
+`c-format.c`. It must therefore adhere to GCC's GPLv3+ license.
diff --git a/tools/gcc-plugins/debian/changelog b/tools/gcc-plugins/debian/changelog
new file mode 100644
index 0000000000..62bbbcd46f
--- /dev/null
+++ b/tools/gcc-plugins/debian/changelog
@@ -0,0 +1,5 @@
+gcc-frr-plugin (9.3.0d8+equi2) unstable; urgency=medium
+
+ * package created (+equi1 used during development, never released.)
+
+ -- David Lamparter <equinox-debian@diac24.net> Sun, 29 Mar 2020 08:32:24 +0200
diff --git a/tools/gcc-plugins/debian/compat b/tools/gcc-plugins/debian/compat
new file mode 100644
index 0000000000..48082f72f0
--- /dev/null
+++ b/tools/gcc-plugins/debian/compat
@@ -0,0 +1 @@
+12
diff --git a/tools/gcc-plugins/debian/control b/tools/gcc-plugins/debian/control
new file mode 100644
index 0000000000..6a9b886bef
--- /dev/null
+++ b/tools/gcc-plugins/debian/control
@@ -0,0 +1,19 @@
+Source: gcc-frr-plugin
+Section: devel
+Priority: optional
+Maintainer: David Lamparter <equinox-debian@diac24.net>
+Build-Depends:
+ gcc-9-plugin-dev (=9.3.0-8+equi1),
+ debhelper (>= 12)
+Standards-Version: 4.4.1
+Homepage: https://www.frrouting.org/
+Vcs-Browser: https://github.com/FRRouting/frr/
+Vcs-Git: https://github.com/FRRouting/frr.git
+
+Package: gcc-9-frr-plugin
+Architecture: linux-any
+Depends:
+ gcc-9 (=9.3.0-8+equi1),
+ ${misc:Depends},
+ ${shlibs:Depends}
+Description: GCC plugin for FRRouting
diff --git a/tools/gcc-plugins/debian/copyright b/tools/gcc-plugins/debian/copyright
new file mode 100644
index 0000000000..dcd9fa1770
--- /dev/null
+++ b/tools/gcc-plugins/debian/copyright
@@ -0,0 +1,9 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: FRR
+Upstream-Contact: maintainers@frrouting.org, security@frrouting.org
+Source: https://www.frrouting.org/
+
+Files: *
+Copyright:
+ 2019-2020 by David Lamparter
+ Code derived from GCC, please refer to gcc package copyright.
diff --git a/tools/gcc-plugins/debian/rules b/tools/gcc-plugins/debian/rules
new file mode 100755
index 0000000000..f8f42ad337
--- /dev/null
+++ b/tools/gcc-plugins/debian/rules
@@ -0,0 +1,11 @@
+#!/usr/bin/make -f
+
+# standard Debian options & profiles
+
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+%:
+ dh $@
+
+override_dh_auto_test:
+ true
diff --git a/tools/gcc-plugins/debian/source/format b/tools/gcc-plugins/debian/source/format
new file mode 100644
index 0000000000..af745b310b
--- /dev/null
+++ b/tools/gcc-plugins/debian/source/format
@@ -0,0 +1 @@
+3.0 (git)
diff --git a/tools/gcc-plugins/format-test.c b/tools/gcc-plugins/format-test.c
new file mode 100644
index 0000000000..b031ca5ece
--- /dev/null
+++ b/tools/gcc-plugins/format-test.c
@@ -0,0 +1,107 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+typedef unsigned long mytype;
+typedef size_t mysize;
+
+typedef unsigned int not_in_addr_t;
+typedef in_addr_t yes_in_addr_t;
+typedef struct in_addr in_addr_s;
+
+struct other {
+ int x;
+};
+
+int testfn(const char *fmt, ...) __attribute__((frr_format("frr_printf", 1, 2)));
+
+#ifndef _FRR_ATTRIBUTE_PRINTFRR
+#error please load the frr-format plugin
+#endif
+
+#pragma FRR printfrr_ext "%pI4" (struct in_addr *)
+#pragma FRR printfrr_ext "%pI4" (in_addr_t *)
+
+int test(unsigned long long ay)
+{
+ size_t v_size_t = 0;
+ long v_long = 0;
+ int v_int = 0;
+ uint64_t v_uint64_t = 0;
+ mytype v_mytype = 0;
+ mysize v_mysize = 0;
+ pid_t v_pid_t = 0;
+
+ testfn("%zu", v_size_t); // NOWARN
+ testfn("%zu", v_long); // WARN
+ testfn("%zu", v_int); // WARN
+ testfn("%zu", sizeof(v_int)); // NOWARN
+ testfn("%zu", v_mytype); // WARN
+ testfn("%zu", v_mysize); // NOWARN
+ testfn("%zu", v_uint64_t); // WARN
+ testfn("%zu", v_pid_t); // WARN
+
+ testfn("%lu", v_long); // NOWARN PEDANTIC
+ testfn("%lu", v_int); // WARN
+ testfn("%lu", v_size_t); // WARN
+ testfn("%lu", sizeof(v_int)); // NOWARN (integer constant)
+ testfn("%lu", v_uint64_t); // WARN
+ testfn("%lu", v_pid_t); // WARN
+
+ testfn("%ld", v_long); // NOWARN
+ testfn("%ld", v_int); // WARN
+ testfn("%ld", v_size_t); // WARN
+ testfn("%ld", sizeof(v_int)); // NOWARN (integer constant)
+ testfn("%ld", v_uint64_t); // WARN
+ testfn("%ld", v_pid_t); // WARN
+
+ testfn("%d", v_int); // NOWARN
+ testfn("%d", v_long); // WARN
+ testfn("%d", v_size_t); // WARN
+ testfn("%d", sizeof(v_int)); // WARN
+ testfn("%d", v_uint64_t); // WARN
+ testfn("%d", v_pid_t); // WARN
+
+ testfn("%Lu", v_size_t); // WARN
+ testfn("%Lu", v_long); // WARN
+ testfn("%Lu", v_int); // WARN
+ testfn("%Lu", sizeof(v_int)); // NOWARN (integer constant)
+ testfn("%Lu", v_mytype); // WARN
+ testfn("%Lu", v_mysize); // WARN
+ testfn("%Lu", v_pid_t); // WARN
+ testfn("%Lu", v_uint64_t); // NOWARN
+
+ testfn("%Ld", v_size_t); // WARN
+ testfn("%Ld", v_long); // WARN
+ testfn("%Ld", v_int); // WARN
+ testfn("%Ld", sizeof(v_int)); // NOWARN (integer constant)
+ testfn("%Ld", v_mytype); // WARN
+ testfn("%Ld", v_mysize); // WARN
+ testfn("%Ld", v_pid_t); // WARN
+ testfn("%Ld", v_uint64_t); // NOWARN
+
+ testfn("%pI4", &v_long); // WARN
+
+ in_addr_t v_in_addr_t;
+ yes_in_addr_t v_yes_in_addr_t;
+ not_in_addr_t v_not_in_addr_t;
+ void *v_voidp = &v_in_addr_t;
+
+ testfn("%pI4", &v_in_addr_t); // NOWARN
+ testfn("%pI4", &v_yes_in_addr_t); // NOWARN
+ testfn("%pI4", &v_not_in_addr_t); // WARN
+ testfn("%pI4", v_voidp); // WARN
+
+ struct in_addr v_in_addr;
+ in_addr_s v_in_addr_s;
+ struct other v_other;
+ const struct in_addr *v_in_addr_const = &v_in_addr;
+
+ testfn("%pI4", &v_in_addr); // NOWARN
+ testfn("%pI4", &v_in_addr_s); // NOWARN
+ testfn("%pI4", &v_other); // WARN
+ testfn("%pI4", v_in_addr_const); // NOWARN
+ return 0;
+}
diff --git a/tools/gcc-plugins/format-test.py b/tools/gcc-plugins/format-test.py
new file mode 100644
index 0000000000..cc6ca6100e
--- /dev/null
+++ b/tools/gcc-plugins/format-test.py
@@ -0,0 +1,57 @@
+import subprocess
+import sys
+import shlex
+import os
+import re
+
+os.environ['LC_ALL'] = 'C'
+os.environ['LANG'] = 'C'
+for k in list(os.environ.keys()):
+ if k.startswith('LC_'):
+ os.environ.pop(k)
+
+c_re = re.compile(r'//\s+(NO)?WARN')
+expect = {}
+lines = {}
+
+with open('format-test.c', 'r') as fd:
+ for lno, line in enumerate(fd.readlines(), 1):
+ lines[lno] = line.strip()
+ m = c_re.search(line)
+ if m is None:
+ continue
+ if m.group(1) is None:
+ expect[lno] = 'warn'
+ else:
+ expect[lno] = 'nowarn'
+
+cmd = shlex.split('gcc -Wall -Wextra -Wno-unused -fplugin=./frr-format.so -fno-diagnostics-show-caret -c -o format-test.o format-test.c')
+
+gcc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+sout, serr = gcc.communicate()
+gcc.wait()
+
+gcclines = serr.decode('UTF-8').splitlines()
+line_re = re.compile(r'^format-test\.c:(\d+):(.*)$')
+gcc_warns = {}
+
+for line in gcclines:
+ if line.find('In function') >= 0:
+ continue
+ m = line_re.match(line)
+ if m is None:
+ sys.stderr.write('cannot process GCC output: %s\n' % line)
+ continue
+
+ lno = int(m.group(1))
+ gcc_warns.setdefault(lno, []).append(line)
+
+for lno, val in expect.items():
+ if val == 'nowarn' and lno in gcc_warns:
+ sys.stderr.write('unexpected gcc warning on line %d:\n\t%s\n\t%s\n' % (lno, lines[lno], '\n\t'.join(gcc_warns[lno])))
+ if val == 'warn' and lno not in gcc_warns:
+ sys.stderr.write('expected warning on line %d but did not get one\n\t%s\n' % (lno, lines[lno]))
+
+leftover = set(gcc_warns.keys()) - set(expect.keys())
+for lno in sorted(leftover):
+ sys.stderr.write('unmarked gcc warning on line %d:\n\t%s\n\t%s\n' % (lno, lines[lno], '\n\t'.join(gcc_warns[lno])))
diff --git a/tools/gcc-plugins/frr-format.c b/tools/gcc-plugins/frr-format.c
new file mode 100644
index 0000000000..174f403d48
--- /dev/null
+++ b/tools/gcc-plugins/frr-format.c
@@ -0,0 +1,4457 @@
+/* Check calls to formatted I/O functions (-Wformat).
+ Copyright (C) 1992-2019 Free Software Foundation, Inc.
+
+ Extended for FRR's printfrr() with Linux kernel style extensions
+ Copyright (C) 2019-2020 David Lamparter, for NetDEF, Inc.
+
+This file is part of GCC.
+
+GCC 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 3, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING.GPLv3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "gcc-common.h"
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+//include "c-target.h"
+#include "c-common.h"
+#include "alloc-pool.h"
+#include "stringpool.h"
+#include "c-tree.h"
+#include "c-objc.h"
+#include "intl.h"
+#include "langhooks.h"
+#include "frr-format.h"
+#include "diagnostic.h"
+#include "substring-locations.h"
+#include "selftest.h"
+#include "selftest-diagnostic.h"
+#ifndef FIRST_PSEUDO_REGISTER
+#define FIRST_PSEUDO_REGISTER 0
+#endif
+#include "builtins.h"
+#include "attribs.h"
+#include "gcc-rich-location.h"
+#include "c-pretty-print.h"
+#include "c-pragma.h"
+
+extern struct cpp_reader *parse_in;
+
+#pragma GCC visibility push(hidden)
+
+/* Handle attributes associated with format checking. */
+
+/* This must be in the same order as format_types, except for
+ format_type_error. Target-specific format types do not have
+ matching enum values. */
+enum format_type { frr_printf_format_type,
+ format_type_error = -1};
+
+struct function_format_info
+{
+ int format_type; /* type of format (printf, scanf, etc.) */
+ unsigned HOST_WIDE_INT format_num; /* number of format argument */
+ unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */
+};
+
+static GTY(()) tree local_uint64_t_node;
+static GTY(()) tree local_int64_t_node;
+
+static GTY(()) tree local_size_t_node;
+static GTY(()) tree local_ssize_t_node;
+static GTY(()) tree local_atomic_size_t_node;
+static GTY(()) tree local_atomic_ssize_t_node;
+static GTY(()) tree local_ptrdiff_t_node;
+
+static GTY(()) tree local_pid_t_node;
+static GTY(()) tree local_uid_t_node;
+static GTY(()) tree local_gid_t_node;
+static GTY(()) tree local_time_t_node;
+
+static GTY(()) tree local_socklen_t_node;
+static GTY(()) tree local_in_addr_t_node;
+
+static struct type_special {
+ tree *match;
+ tree *replace;
+ tree *cousin;
+} special_types[] = {
+ { &local_atomic_size_t_node, &local_size_t_node, &local_ssize_t_node, },
+ { &local_atomic_ssize_t_node, &local_ssize_t_node, &local_size_t_node, },
+ { &local_size_t_node, NULL, &local_ssize_t_node, },
+ { &local_ssize_t_node, NULL, &local_size_t_node, },
+ { &local_uint64_t_node, NULL, &local_int64_t_node, },
+ { &local_int64_t_node, NULL, &local_uint64_t_node, },
+ { &local_pid_t_node, NULL, &local_pid_t_node, },
+ { &local_uid_t_node, NULL, &local_uid_t_node, },
+ { &local_gid_t_node, NULL, &local_gid_t_node, },
+ { &local_time_t_node, NULL, &local_time_t_node, },
+ { NULL, NULL, NULL, }
+};
+
+static bool decode_format_attr (tree, function_format_info *, int);
+static int decode_format_type (const char *);
+
+static bool check_format_string (tree argument,
+ unsigned HOST_WIDE_INT format_num,
+ int flags, bool *no_add_attrs,
+ int expected_format_type);
+static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
+ int validated_p);
+static const char *convert_format_name_to_system_name (const char *attr_name);
+
+static int first_target_format_type;
+static const char *format_name (int format_num);
+static int format_flags (int format_num);
+
+/* Emit a warning as per format_warning_va, but construct the substring_loc
+ for the character at offset (CHAR_IDX - 1) within a string constant
+ FORMAT_STRING_CST at FMT_STRING_LOC. */
+
+ATTRIBUTE_GCC_DIAG (5,6)
+static bool
+format_warning_at_char (location_t fmt_string_loc, tree format_string_cst,
+ int char_idx, int opt, const char *gmsgid, ...)
+{
+ va_list ap;
+ va_start (ap, gmsgid);
+ tree string_type = TREE_TYPE (format_string_cst);
+
+ /* The callers are of the form:
+ format_warning (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ where format_chars has already been incremented, so that
+ CHAR_IDX is one character beyond where the warning should
+ be emitted. Fix it. */
+ char_idx -= 1;
+
+ substring_loc fmt_loc (fmt_string_loc, string_type, char_idx, char_idx,
+ char_idx);
+#if BUILDING_GCC_VERSION >= 9000
+ format_string_diagnostic_t diag (fmt_loc, NULL, UNKNOWN_LOCATION, NULL,
+ NULL);
+ bool warned = diag.emit_warning_va (opt, gmsgid, &ap);
+#else
+ bool warned = format_warning_va (fmt_loc, UNKNOWN_LOCATION, NULL,
+ opt, gmsgid, &ap);
+#endif
+ va_end (ap);
+
+ return warned;
+}
+
+/* Check that we have a pointer to a string suitable for use as a format.
+ The default is to check for a char type.
+ For objective-c dialects, this is extended to include references to string
+ objects validated by objc_string_ref_type_p ().
+ Targets may also provide a string object type that can be used within c and
+ c++ and shared with their respective objective-c dialects. In this case the
+ reference to a format string is checked for validity via a hook.
+
+ The function returns true if strref points to any string type valid for the
+ language dialect and target. */
+
+static bool
+valid_stringptr_type_p (tree strref)
+{
+ return (strref != NULL
+ && TREE_CODE (strref) == POINTER_TYPE
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (strref)) == char_type_node
+ || objc_string_ref_type_p (strref)));
+// || (*targetcm.string_object_ref_type_p) ((const_tree) strref)));
+}
+
+/* Handle a "format_arg" attribute; arguments as in
+ struct attribute_spec.handler. */
+tree
+handle_frr_format_arg_attribute (tree *node, tree ARG_UNUSED (name),
+ tree args, int flags, bool *no_add_attrs)
+{
+ tree type = *node;
+ tree format_num_expr = TREE_VALUE (args);
+ unsigned HOST_WIDE_INT format_num = 0;
+
+ if (!get_constant (format_num_expr, &format_num, 0))
+ {
+ error ("format string has invalid operand number");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ if (prototype_p (type))
+ {
+ /* The format arg can be any string reference valid for the language and
+ target. We cannot be more specific in this case. */
+ if (!check_format_string (type, format_num, flags, no_add_attrs, -1))
+ return NULL_TREE;
+ }
+
+ if (!valid_stringptr_type_p (TREE_TYPE (type)))
+ {
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("function does not return string type");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ return NULL_TREE;
+}
+
+/* Verify that the format_num argument is actually a string reference suitable,
+ for the language dialect and target (in case the format attribute is in
+ error). When we know the specific reference type expected, this is also
+ checked. */
+static bool
+check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num,
+ int flags, bool *no_add_attrs, int expected_format_type)
+{
+ unsigned HOST_WIDE_INT i;
+ bool is_target_sref, is_char_ref;
+ tree ref;
+ int fmt_flags;
+ function_args_iterator iter;
+
+ i = 1;
+ FOREACH_FUNCTION_ARGS (fntype, ref, iter)
+ {
+ if (i == format_num)
+ break;
+ i++;
+ }
+
+ if (!ref
+ || !valid_stringptr_type_p (ref))
+ {
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("format string argument is not a string type");
+ *no_add_attrs = true;
+ return false;
+ }
+
+ /* We only know that we want a suitable string reference. */
+ if (expected_format_type < 0)
+ return true;
+
+ /* Now check that the arg matches the expected type. */
+ is_char_ref =
+ (TYPE_MAIN_VARIANT (TREE_TYPE (ref)) == char_type_node);
+
+ fmt_flags = format_flags (expected_format_type);
+ is_target_sref = false;
+
+ if (!(fmt_flags & FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL))
+ {
+ if (is_char_ref)
+ return true; /* OK, we expected a char and found one. */
+ else
+ {
+ error ("found a %qT but the format argument should be a string",
+ ref);
+ *no_add_attrs = true;
+ return false;
+ }
+ }
+
+ /* We expect a string object type as the format arg. */
+ if (is_char_ref)
+ {
+ error ("format argument should be a %qs reference but"
+ " a string was found", format_name (expected_format_type));
+ *no_add_attrs = true;
+ return false;
+ }
+
+ /* We will allow a target string ref to match only itself. */
+ if (first_target_format_type
+ && expected_format_type >= first_target_format_type
+ && is_target_sref)
+ return true;
+ else
+ {
+ error ("format argument should be a %qs reference",
+ format_name (expected_format_type));
+ *no_add_attrs = true;
+ return false;
+ }
+
+ gcc_unreachable ();
+}
+
+/* Verify EXPR is a constant, and store its value.
+ If validated_p is true there should be no errors.
+ Returns true on success, false otherwise. */
+static bool
+get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p)
+{
+ if (!tree_fits_uhwi_p (expr))
+ {
+ gcc_assert (!validated_p);
+ return false;
+ }
+
+ *value = TREE_INT_CST_LOW (expr);
+
+ return true;
+}
+
+/* Decode the arguments to a "format" attribute into a
+ function_format_info structure. It is already known that the list
+ is of the right length. If VALIDATED_P is true, then these
+ attributes have already been validated and must not be erroneous;
+ if false, it will give an error message. Returns true if the
+ attributes are successfully decoded, false otherwise. */
+
+static bool
+decode_format_attr (tree args, function_format_info *info, int validated_p)
+{
+ tree format_type_id = TREE_VALUE (args);
+ tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
+ tree first_arg_num_expr
+ = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
+
+ if (TREE_CODE (format_type_id) != STRING_CST)
+ {
+ gcc_assert (!validated_p);
+ error ("unrecognized format specifier");
+ return false;
+ }
+ else
+ {
+ const char *p = TREE_STRING_POINTER (format_type_id);
+
+ p = convert_format_name_to_system_name (p);
+
+ info->format_type = decode_format_type (p);
+
+ if (info->format_type == format_type_error)
+ {
+ gcc_assert (!validated_p);
+ warning (OPT_Wformat_, "%qE is an unrecognized format function type",
+ format_type_id);
+ return false;
+ }
+ }
+
+ if (!get_constant (format_num_expr, &info->format_num, validated_p))
+ {
+ error ("format string has invalid operand number");
+ return false;
+ }
+
+ if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p))
+ {
+ error ("%<...%> has invalid operand number");
+ return false;
+ }
+
+ if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num)
+ {
+ gcc_assert (!validated_p);
+ error ("format string argument follows the args to be formatted");
+ return false;
+ }
+
+ return true;
+}
+
+/* Check a call to a format function against a parameter list. */
+
+/* The C standard version C++ is treated as equivalent to
+ or inheriting from, for the purpose of format features supported. */
+#define CPLUSPLUS_STD_VER (cxx_dialect < cxx11 ? STD_C94 : STD_C99)
+/* The C standard version we are checking formats against when pedantic. */
+#define C_STD_VER ((int) (c_dialect_cxx () \
+ ? CPLUSPLUS_STD_VER \
+ : (flag_isoc99 \
+ ? STD_C99 \
+ : (flag_isoc94 ? STD_C94 : STD_C89))))
+/* The name to give to the standard version we are warning about when
+ pedantic. FEATURE_VER is the version in which the feature warned out
+ appeared, which is higher than C_STD_VER. */
+#define C_STD_NAME(FEATURE_VER) (c_dialect_cxx () \
+ ? (cxx_dialect < cxx11 ? "ISO C++98" \
+ : "ISO C++11") \
+ : ((FEATURE_VER) == STD_EXT \
+ ? "ISO C" \
+ : "ISO C90"))
+/* Adjust a C standard version, which may be STD_C9L, to account for
+ -Wno-long-long. Returns other standard versions unchanged. */
+#define ADJ_STD(VER) ((int) ((VER) == STD_C9L \
+ ? (warn_long_long ? STD_C99 : STD_C89) \
+ : (VER)))
+
+/* Enum describing the kind of specifiers present in the format and
+ requiring an argument. */
+enum format_specifier_kind {
+ CF_KIND_FORMAT,
+ CF_KIND_FIELD_WIDTH,
+ CF_KIND_FIELD_PRECISION
+};
+
+static const char *kind_descriptions[] = {
+ N_("format"),
+ N_("field width specifier"),
+ N_("field precision specifier")
+};
+
+/* Structure describing details of a type expected in format checking,
+ and the type to check against it. */
+struct format_wanted_type
+{
+ /* The type wanted. */
+ tree wanted_type;
+ /* The name of this type to use in diagnostics. */
+ const char *wanted_type_name;
+ /* Should be type checked just for scalar width identity. */
+ int scalar_identity_flag;
+ /* The level of indirection through pointers at which this type occurs. */
+ int pointer_count;
+ /* Whether, when pointer_count is 1, to allow any character type when
+ pedantic, rather than just the character or void type specified. */
+ int char_lenient_flag;
+ /* Whether the argument, dereferenced once, is written into and so the
+ argument must not be a pointer to a const-qualified type. */
+ int writing_in_flag;
+ /* Whether the argument, dereferenced once, is read from and so
+ must not be a NULL pointer. */
+ int reading_from_flag;
+ /* The kind of specifier that this type is used for. */
+ enum format_specifier_kind kind;
+ /* The starting character of the specifier. This never includes the
+ initial percent sign. */
+ const char *format_start;
+ /* The length of the specifier. */
+ int format_length;
+ /* The actual parameter to check against the wanted type. */
+ tree param;
+ /* The argument number of that parameter. */
+ int arg_num;
+ /* The offset location of this argument with respect to the format
+ string location. */
+ unsigned int offset_loc;
+ /* The next type to check for this format conversion, or NULL if none. */
+ struct format_wanted_type *next;
+};
+
+/* Convenience macro for format_length_info meaning unused. */
+#define NO_FMT NULL, FMT_LEN_none, STD_C89
+
+static const format_length_info printf_length_specs[] =
+{
+ { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 },
+ { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 },
+ { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 },
+ { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 },
+ { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 },
+ { "Z", FMT_LEN_z, STD_EXT, NO_FMT, 0 },
+ { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 },
+ { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 },
+ { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 },
+ { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 },
+ { NO_FMT, NO_FMT, 0 }
+};
+
+static const format_flag_spec printf_flag_specs[] =
+{
+ { ' ', 0, 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 },
+ { '+', 0, 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
+ { '#', 0, 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
+ { '0', 0, 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 },
+ { '-', 0, 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 },
+ { '\'', 0, 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT },
+ { 'I', 0, 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT },
+ { 'w', 0, 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
+ { 'p', 0, 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
+ { 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+ { 0, 0, 0, 0, NULL, NULL, STD_C89 }
+};
+
+
+static const format_flag_pair printf_flag_pairs[] =
+{
+ { ' ', '+', 1, 0 },
+ { '0', '-', 1, 0 },
+ { '0', 'p', 1, 'i' },
+ { 0, 0, 0, 0 }
+};
+
+#define ETAB_SZ 128
+static kernel_ext_fmt ext_p[ETAB_SZ] = {
+ { NULL }
+};
+static kernel_ext_fmt ext_d[ETAB_SZ] = {
+ { NULL }
+};
+
+static const format_char_info print_char_table[] =
+{
+ /* C89 conversion specifiers. */
+ /* none, hh, h, l, ll, L, z, t, j, H, D, DD */
+ { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_S64, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "-wp0 +'I", "i", NULL, ext_d },
+ { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_U64, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL, NULL },
+ { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_U64, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0'I", "i", NULL, NULL },
+ { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL, NULL },
+ { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#I", "", NULL, NULL },
+ { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL, NULL },
+ { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL, NULL },
+ { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "c", NULL, ext_p },
+ { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL, NULL },
+ /* C99 conversion specifiers. */
+ { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL, NULL },
+ { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL, NULL },
+ /* X/Open conversion specifiers. */
+ { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL, NULL },
+ { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL, NULL },
+ /* GNU conversion specifiers. */
+ { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL, NULL },
+ { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL, NULL }
+};
+
+/* This must be in the same order as enum format_type. */
+static const format_kind_info format_types_orig[] =
+{
+ { "frr_printf", printf_length_specs, print_char_table, " +#0-'I", NULL,
+ printf_flag_specs, printf_flag_pairs,
+ FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+ 'w', 0, 'p', 0, 'L', 0,
+ &integer_type_node, &integer_type_node
+ },
+};
+
+/* This layer of indirection allows GCC to reassign format_types with
+ new data if necessary, while still allowing the original data to be
+ const. */
+static const format_kind_info *format_types = format_types_orig;
+
+static int n_format_types = ARRAY_SIZE (format_types_orig);
+
+/* Structure detailing the results of checking a format function call
+ where the format expression may be a conditional expression with
+ many leaves resulting from nested conditional expressions. */
+struct format_check_results
+{
+ /* Number of leaves of the format argument that could not be checked
+ as they were not string literals. */
+ int number_non_literal;
+ /* Number of leaves of the format argument that were null pointers or
+ string literals, but had extra format arguments. */
+ int number_extra_args;
+ location_t extra_arg_loc;
+ /* Number of leaves of the format argument that were null pointers or
+ string literals, but had extra format arguments and used $ operand
+ numbers. */
+ int number_dollar_extra_args;
+ /* Number of leaves of the format argument that were wide string
+ literals. */
+ int number_wide;
+ /* Number of leaves of the format argument that are not array of "char". */
+ int number_non_char;
+ /* Number of leaves of the format argument that were empty strings. */
+ int number_empty;
+ /* Number of leaves of the format argument that were unterminated
+ strings. */
+ int number_unterminated;
+ /* Number of leaves of the format argument that were not counted above. */
+ int number_other;
+ /* Location of the format string. */
+ location_t format_string_loc;
+};
+
+struct format_check_context
+{
+ format_check_results *res;
+ function_format_info *info;
+ tree params;
+ vec<location_t> *arglocs;
+};
+
+/* Return the format name (as specified in the original table) for the format
+ type indicated by format_num. */
+static const char *
+format_name (int format_num)
+{
+ if (format_num >= 0 && format_num < n_format_types)
+ return format_types[format_num].name;
+ gcc_unreachable ();
+}
+
+/* Return the format flags (as specified in the original table) for the format
+ type indicated by format_num. */
+static int
+format_flags (int format_num)
+{
+ if (format_num >= 0 && format_num < n_format_types)
+ return format_types[format_num].flags;
+ gcc_unreachable ();
+}
+
+static void check_format_info (function_format_info *, tree,
+ vec<location_t> *);
+static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT);
+static void check_format_info_main (format_check_results *,
+ function_format_info *, const char *,
+ location_t, tree,
+ int, tree,
+ unsigned HOST_WIDE_INT,
+ object_allocator<format_wanted_type> &,
+ vec<location_t> *);
+
+static void init_dollar_format_checking (int, tree);
+static int maybe_read_dollar_number (const char **, int,
+ tree, tree *, const format_kind_info *);
+static bool avoid_dollar_number (const char *);
+static void finish_dollar_format_checking (format_check_results *, int);
+
+static const format_flag_spec *get_flag_spec (const format_flag_spec *,
+ int, const char *);
+
+static void check_format_types (const substring_loc &fmt_loc,
+ format_wanted_type *,
+ const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char,
+ vec<location_t> *arglocs);
+static void format_type_warning (const substring_loc &fmt_loc,
+ location_t param_loc,
+ format_wanted_type *, tree,
+ tree,
+ const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char,
+ const char *extra = NULL);
+
+static bool check_kef_type (const substring_loc &fmt_loc,
+ const struct kernel_ext_fmt *kef,
+ unsigned arg_num,
+ tree cur_param,
+ tree wanted_type,
+ const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char,
+ vec<location_t> *arglocs);
+
+/* Decode a format type from a string, returning the type, or
+ format_type_error if not valid, in which case the caller should print an
+ error message. */
+static int
+decode_format_type (const char *s)
+{
+ int i;
+ int slen;
+
+ s = convert_format_name_to_system_name (s);
+ slen = strlen (s);
+ for (i = 0; i < n_format_types; i++)
+ {
+ int alen;
+ if (!strcmp (s, format_types[i].name))
+ return i;
+ alen = strlen (format_types[i].name);
+ if (slen == alen + 4 && s[0] == '_' && s[1] == '_'
+ && s[slen - 1] == '_' && s[slen - 2] == '_'
+ && !strncmp (s + 2, format_types[i].name, alen))
+ return i;
+ }
+ return format_type_error;
+}
+
+
+/* Check the argument list of a call to printf, scanf, etc.
+ ATTRS are the attributes on the function type. There are NARGS argument
+ values in the array ARGARRAY.
+ Also, if -Wsuggest-attribute=format,
+ warn for calls to vprintf or vscanf in functions with no such format
+ attribute themselves. */
+
+void
+check_function_format (tree attrs, int nargs, tree *argarray,
+ vec<location_t> *arglocs)
+{
+ tree a;
+
+ /* See if this function has any format attributes. */
+ for (a = attrs; a; a = TREE_CHAIN (a))
+ {
+ if (is_attribute_p ("frr_format", TREE_PURPOSE (a)))
+ {
+ /* Yup; check it. */
+ function_format_info info;
+ decode_format_attr (TREE_VALUE (a), &info, /*validated=*/true);
+ if (warn_format)
+ {
+ /* FIXME: Rewrite all the internal functions in this file
+ to use the ARGARRAY directly instead of constructing this
+ temporary list. */
+ tree params = NULL_TREE;
+ int i;
+ for (i = nargs - 1; i >= 0; i--)
+ params = tree_cons (NULL_TREE, argarray[i], params);
+ check_format_info (&info, params, arglocs);
+ }
+
+ /* Attempt to detect whether the current function might benefit
+ from the format attribute if the called function is decorated
+ with it. Avoid using calls with string literal formats for
+ guidance since those are unlikely to be viable candidates. */
+ if (warn_suggest_attribute_format
+ && current_function_decl != NULL_TREE
+ && info.first_arg_num == 0
+ && (format_types[info.format_type].flags
+ & (int) FMT_FLAG_ARG_CONVERT)
+ /* c_strlen will fail for a function parameter but succeed
+ for a literal or constant array. */
+ && !c_strlen (argarray[info.format_num - 1], 1))
+ {
+ tree c;
+ for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
+ c;
+ c = TREE_CHAIN (c))
+ if (is_attribute_p ("frr_format", TREE_PURPOSE (c))
+ && (decode_format_type (IDENTIFIER_POINTER
+ (TREE_VALUE (TREE_VALUE (c))))
+ == info.format_type))
+ break;
+ if (c == NULL_TREE)
+ {
+ /* Check if the current function has a parameter to which
+ the format attribute could be attached; if not, it
+ can't be a candidate for a format attribute, despite
+ the vprintf-like or vscanf-like call. */
+ tree args;
+ for (args = DECL_ARGUMENTS (current_function_decl);
+ args != 0;
+ args = DECL_CHAIN (args))
+ {
+ if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args)))
+ == char_type_node))
+ break;
+ }
+ if (args != 0)
+ warning (OPT_Wsuggest_attribute_format, "function %qD "
+ "might be a candidate for %qs frr_format attribute",
+ current_function_decl,
+ format_types[info.format_type].name);
+ }
+ }
+ }
+ }
+}
+
+
+/* Variables used by the checking of $ operand number formats. */
+static char *dollar_arguments_used = NULL;
+static char *dollar_arguments_pointer_p = NULL;
+static int dollar_arguments_alloc = 0;
+static int dollar_arguments_count;
+static int dollar_first_arg_num;
+static int dollar_max_arg_used;
+static int dollar_format_warned;
+
+/* Initialize the checking for a format string that may contain $
+ parameter number specifications; we will need to keep track of whether
+ each parameter has been used. FIRST_ARG_NUM is the number of the first
+ argument that is a parameter to the format, or 0 for a vprintf-style
+ function; PARAMS is the list of arguments starting at this argument. */
+
+static void
+init_dollar_format_checking (int first_arg_num, tree params)
+{
+ tree oparams = params;
+
+ dollar_first_arg_num = first_arg_num;
+ dollar_arguments_count = 0;
+ dollar_max_arg_used = 0;
+ dollar_format_warned = 0;
+ if (first_arg_num > 0)
+ {
+ while (params)
+ {
+ dollar_arguments_count++;
+ params = TREE_CHAIN (params);
+ }
+ }
+ if (dollar_arguments_alloc < dollar_arguments_count)
+ {
+ free (dollar_arguments_used);
+ free (dollar_arguments_pointer_p);
+ dollar_arguments_alloc = dollar_arguments_count;
+ dollar_arguments_used = XNEWVEC (char, dollar_arguments_alloc);
+ dollar_arguments_pointer_p = XNEWVEC (char, dollar_arguments_alloc);
+ }
+ if (dollar_arguments_alloc)
+ {
+ memset (dollar_arguments_used, 0, dollar_arguments_alloc);
+ if (first_arg_num > 0)
+ {
+ int i = 0;
+ params = oparams;
+ while (params)
+ {
+ dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params)))
+ == POINTER_TYPE);
+ params = TREE_CHAIN (params);
+ i++;
+ }
+ }
+ }
+}
+
+
+/* Look for a decimal number followed by a $ in *FORMAT. If DOLLAR_NEEDED
+ is set, it is an error if one is not found; otherwise, it is OK. If
+ such a number is found, check whether it is within range and mark that
+ numbered operand as being used for later checking. Returns the operand
+ number if found and within range, zero if no such number was found and
+ this is OK, or -1 on error. PARAMS points to the first operand of the
+ format; PARAM_PTR is made to point to the parameter referred to. If
+ a $ format is found, *FORMAT is updated to point just after it. */
+
+static int
+maybe_read_dollar_number (const char **format,
+ int dollar_needed, tree params, tree *param_ptr,
+ const format_kind_info *fki)
+{
+ int argnum;
+ int overflow_flag;
+ const char *fcp = *format;
+ if (!ISDIGIT (*fcp))
+ {
+ if (dollar_needed)
+ {
+ warning (OPT_Wformat_, "missing $ operand number in format");
+ return -1;
+ }
+ else
+ return 0;
+ }
+ argnum = 0;
+ overflow_flag = 0;
+ while (ISDIGIT (*fcp))
+ {
+ int nargnum;
+ nargnum = 10 * argnum + (*fcp - '0');
+ if (nargnum < 0 || nargnum / 10 != argnum)
+ overflow_flag = 1;
+ argnum = nargnum;
+ fcp++;
+ }
+ if (*fcp != '$')
+ {
+ if (dollar_needed)
+ {
+ warning (OPT_Wformat_, "missing $ operand number in format");
+ return -1;
+ }
+ else
+ return 0;
+ }
+ *format = fcp + 1;
+ if (pedantic && !dollar_format_warned)
+ {
+ warning (OPT_Wformat_, "%s does not support %%n$ operand number formats",
+ C_STD_NAME (STD_EXT));
+ dollar_format_warned = 1;
+ }
+ if (overflow_flag || argnum == 0
+ || (dollar_first_arg_num && argnum > dollar_arguments_count))
+ {
+ warning (OPT_Wformat_, "operand number out of range in format");
+ return -1;
+ }
+ if (argnum > dollar_max_arg_used)
+ dollar_max_arg_used = argnum;
+ /* For vprintf-style functions we may need to allocate more memory to
+ track which arguments are used. */
+ while (dollar_arguments_alloc < dollar_max_arg_used)
+ {
+ int nalloc;
+ nalloc = 2 * dollar_arguments_alloc + 16;
+ dollar_arguments_used = XRESIZEVEC (char, dollar_arguments_used,
+ nalloc);
+ dollar_arguments_pointer_p = XRESIZEVEC (char, dollar_arguments_pointer_p,
+ nalloc);
+ memset (dollar_arguments_used + dollar_arguments_alloc, 0,
+ nalloc - dollar_arguments_alloc);
+ dollar_arguments_alloc = nalloc;
+ }
+ if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE)
+ && dollar_arguments_used[argnum - 1] == 1)
+ {
+ dollar_arguments_used[argnum - 1] = 2;
+ warning (OPT_Wformat_, "format argument %d used more than once in %s format",
+ argnum, fki->name);
+ }
+ else
+ dollar_arguments_used[argnum - 1] = 1;
+ if (dollar_first_arg_num)
+ {
+ int i;
+ *param_ptr = params;
+ for (i = 1; i < argnum && *param_ptr != 0; i++)
+ *param_ptr = TREE_CHAIN (*param_ptr);
+
+ /* This case shouldn't be caught here. */
+ gcc_assert (*param_ptr);
+ }
+ else
+ *param_ptr = 0;
+ return argnum;
+}
+
+/* Ensure that FORMAT does not start with a decimal number followed by
+ a $; give a diagnostic and return true if it does, false otherwise. */
+
+static bool
+avoid_dollar_number (const char *format)
+{
+ if (!ISDIGIT (*format))
+ return false;
+ while (ISDIGIT (*format))
+ format++;
+ if (*format == '$')
+ {
+ warning (OPT_Wformat_, "$ operand number used after format without operand number");
+ return true;
+ }
+ return false;
+}
+
+
+/* Finish the checking for a format string that used $ operand number formats
+ instead of non-$ formats. We check for unused operands before used ones
+ (a serious error, since the implementation of the format function
+ can't know what types to pass to va_arg to find the later arguments).
+ and for unused operands at the end of the format (if we know how many
+ arguments the format had, so not for vprintf). If there were operand
+ numbers out of range on a non-vprintf-style format, we won't have reached
+ here. If POINTER_GAP_OK, unused arguments are OK if all arguments are
+ pointers. */
+
+static void
+finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok)
+{
+ int i;
+ bool found_pointer_gap = false;
+ for (i = 0; i < dollar_max_arg_used; i++)
+ {
+ if (!dollar_arguments_used[i])
+ {
+ if (pointer_gap_ok && (dollar_first_arg_num == 0
+ || dollar_arguments_pointer_p[i]))
+ found_pointer_gap = true;
+ else
+ warning_at (res->format_string_loc, OPT_Wformat_,
+ "format argument %d unused before used argument %d in $-style format",
+ i + 1, dollar_max_arg_used);
+ }
+ }
+ if (found_pointer_gap
+ || (dollar_first_arg_num
+ && dollar_max_arg_used < dollar_arguments_count))
+ {
+ res->number_other--;
+ res->number_dollar_extra_args++;
+ }
+}
+
+
+/* Retrieve the specification for a format flag. SPEC contains the
+ specifications for format flags for the applicable kind of format.
+ FLAG is the flag in question. If PREDICATES is NULL, the basic
+ spec for that flag must be retrieved and must exist. If
+ PREDICATES is not NULL, it is a string listing possible predicates
+ for the spec entry; if an entry predicated on any of these is
+ found, it is returned, otherwise NULL is returned. */
+
+static const format_flag_spec *
+get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates)
+{
+ int i;
+ for (i = 0; spec[i].flag_char != 0; i++)
+ {
+ if (spec[i].flag_char != flag)
+ continue;
+ if (predicates != NULL)
+ {
+ if (spec[i].predicate != 0
+ && strchr (predicates, spec[i].predicate) != 0)
+ return &spec[i];
+ }
+ else if (spec[i].predicate == 0)
+ return &spec[i];
+ }
+ gcc_assert (predicates);
+ return NULL;
+}
+
+
+/* Check the argument list of a call to printf, scanf, etc.
+ INFO points to the function_format_info structure.
+ PARAMS is the list of argument values. */
+
+static void
+check_format_info (function_format_info *info, tree params,
+ vec<location_t> *arglocs)
+{
+ format_check_context format_ctx;
+ unsigned HOST_WIDE_INT arg_num;
+ tree format_tree;
+ format_check_results res;
+ /* Skip to format argument. If the argument isn't available, there's
+ no work for us to do; prototype checking will catch the problem. */
+ for (arg_num = 1; ; ++arg_num)
+ {
+ if (params == 0)
+ return;
+ if (arg_num == info->format_num)
+ break;
+ params = TREE_CHAIN (params);
+ }
+ format_tree = TREE_VALUE (params);
+ params = TREE_CHAIN (params);
+ if (format_tree == 0)
+ return;
+
+ res.number_non_literal = 0;
+ res.number_extra_args = 0;
+ res.extra_arg_loc = UNKNOWN_LOCATION;
+ res.number_dollar_extra_args = 0;
+ res.number_wide = 0;
+ res.number_non_char = 0;
+ res.number_empty = 0;
+ res.number_unterminated = 0;
+ res.number_other = 0;
+ res.format_string_loc = input_location;
+
+ format_ctx.res = &res;
+ format_ctx.info = info;
+ format_ctx.params = params;
+ format_ctx.arglocs = arglocs;
+
+ check_function_arguments_recurse (check_format_arg, &format_ctx,
+ format_tree, arg_num);
+
+ location_t loc = format_ctx.res->format_string_loc;
+
+ if (res.number_non_literal > 0)
+ {
+ /* Functions taking a va_list normally pass a non-literal format
+ string. These functions typically are declared with
+ first_arg_num == 0, so avoid warning in those cases. */
+ if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT))
+ {
+ /* For strftime-like formats, warn for not checking the format
+ string; but there are no arguments to check. */
+ warning_at (loc, OPT_Wformat_nonliteral,
+ "format not a string literal, format string not checked");
+ }
+ else if (info->first_arg_num != 0)
+ {
+ /* If there are no arguments for the format at all, we may have
+ printf (foo) which is likely to be a security hole. */
+ while (arg_num + 1 < info->first_arg_num)
+ {
+ if (params == 0)
+ break;
+ params = TREE_CHAIN (params);
+ ++arg_num;
+ }
+ if (params == 0 && warn_format_security)
+ warning_at (loc, OPT_Wformat_security,
+ "format not a string literal and no format arguments");
+ else if (params == 0 && warn_format_nonliteral)
+ warning_at (loc, OPT_Wformat_nonliteral,
+ "format not a string literal and no format arguments");
+ else
+ warning_at (loc, OPT_Wformat_nonliteral,
+ "format not a string literal, argument types not checked");
+ }
+ }
+
+ /* If there were extra arguments to the format, normally warn. However,
+ the standard does say extra arguments are ignored, so in the specific
+ case where we have multiple leaves (conditional expressions or
+ ngettext) allow extra arguments if at least one leaf didn't have extra
+ arguments, but was otherwise OK (either non-literal or checked OK).
+ If the format is an empty string, this should be counted similarly to the
+ case of extra format arguments. */
+ if (res.number_extra_args > 0 && res.number_non_literal == 0
+ && res.number_other == 0)
+ {
+ if (res.extra_arg_loc == UNKNOWN_LOCATION)
+ res.extra_arg_loc = loc;
+ warning_at (res.extra_arg_loc, OPT_Wformat_extra_args,
+ "too many arguments for format");
+ }
+ if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0
+ && res.number_other == 0)
+ warning_at (loc, OPT_Wformat_extra_args, "unused arguments in $-style format");
+ if (res.number_empty > 0 && res.number_non_literal == 0
+ && res.number_other == 0)
+ warning_at (loc, OPT_Wformat_zero_length, "zero-length %s format string",
+ format_types[info->format_type].name);
+
+ if (res.number_wide > 0)
+ warning_at (loc, OPT_Wformat_, "format is a wide character string");
+
+ if (res.number_non_char > 0)
+ warning_at (loc, OPT_Wformat_,
+ "format string is not an array of type %qs", "char");
+
+ if (res.number_unterminated > 0)
+ warning_at (loc, OPT_Wformat_, "unterminated format string");
+}
+
+/* Callback from check_function_arguments_recurse to check a
+ format string. FORMAT_TREE is the format parameter. ARG_NUM
+ is the number of the format argument. CTX points to a
+ format_check_context. */
+
+static void
+check_format_arg (void *ctx, tree format_tree,
+ unsigned HOST_WIDE_INT arg_num)
+{
+ format_check_context *format_ctx = (format_check_context *) ctx;
+ format_check_results *res = format_ctx->res;
+ function_format_info *info = format_ctx->info;
+ tree params = format_ctx->params;
+ vec<location_t> *arglocs = format_ctx->arglocs;
+
+ int format_length;
+ HOST_WIDE_INT offset;
+ const char *format_chars;
+ tree array_size = 0;
+ tree array_init;
+
+ location_t fmt_param_loc = EXPR_LOC_OR_LOC (format_tree, input_location);
+
+ /* Pull out a constant value if the front end didn't, and handle location
+ wrappers. */
+ format_tree = fold_for_warn (format_tree);
+ STRIP_NOPS (format_tree);
+
+ if (integer_zerop (format_tree))
+ {
+ /* Skip to first argument to check, so we can see if this format
+ has any arguments (it shouldn't). */
+ while (arg_num + 1 < info->first_arg_num)
+ {
+ if (params == 0)
+ return;
+ params = TREE_CHAIN (params);
+ ++arg_num;
+ }
+
+ if (params == 0)
+ res->number_other++;
+ else
+ {
+ if (res->number_extra_args == 0)
+ res->extra_arg_loc = EXPR_LOC_OR_LOC (TREE_VALUE (params),
+ input_location);
+ res->number_extra_args++;
+ }
+ return;
+ }
+
+ offset = 0;
+ if (TREE_CODE (format_tree) == POINTER_PLUS_EXPR)
+ {
+ tree arg0, arg1;
+
+ arg0 = TREE_OPERAND (format_tree, 0);
+ arg1 = TREE_OPERAND (format_tree, 1);
+ STRIP_NOPS (arg0);
+ STRIP_NOPS (arg1);
+ if (TREE_CODE (arg1) == INTEGER_CST)
+ format_tree = arg0;
+ else
+ {
+ res->number_non_literal++;
+ return;
+ }
+ /* POINTER_PLUS_EXPR offsets are to be interpreted signed. */
+ if (!cst_and_fits_in_hwi (arg1))
+ {
+ res->number_non_literal++;
+ return;
+ }
+ offset = int_cst_value (arg1);
+ }
+ if (TREE_CODE (format_tree) != ADDR_EXPR)
+ {
+ res->number_non_literal++;
+ return;
+ }
+ res->format_string_loc = EXPR_LOC_OR_LOC (format_tree, input_location);
+ format_tree = TREE_OPERAND (format_tree, 0);
+ if (format_types[info->format_type].flags
+ & (int) FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL)
+ {
+ /* We cannot examine this string here - but we can check that it is
+ a valid type. */
+ if (TREE_CODE (format_tree) != CONST_DECL)
+ {
+ res->number_non_literal++;
+ return;
+ }
+ /* Skip to first argument to check. */
+ while (arg_num + 1 < info->first_arg_num)
+ {
+ if (params == 0)
+ return;
+ params = TREE_CHAIN (params);
+ ++arg_num;
+ }
+ return;
+ }
+ if (TREE_CODE (format_tree) == ARRAY_REF
+ && tree_fits_shwi_p (TREE_OPERAND (format_tree, 1))
+ && (offset += tree_to_shwi (TREE_OPERAND (format_tree, 1))) >= 0)
+ format_tree = TREE_OPERAND (format_tree, 0);
+ if (offset < 0)
+ {
+ res->number_non_literal++;
+ return;
+ }
+ if (VAR_P (format_tree)
+ && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
+ && (array_init = decl_constant_value (format_tree)) != format_tree
+ && TREE_CODE (array_init) == STRING_CST)
+ {
+ /* Extract the string constant initializer. Note that this may include
+ a trailing NUL character that is not in the array (e.g.
+ const char a[3] = "foo";). */
+ array_size = DECL_SIZE_UNIT (format_tree);
+ format_tree = array_init;
+ }
+ if (TREE_CODE (format_tree) != STRING_CST)
+ {
+ res->number_non_literal++;
+ return;
+ }
+ tree underlying_type
+ = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree)));
+ if (underlying_type != char_type_node)
+ {
+ if (underlying_type == char16_type_node
+ || underlying_type == char32_type_node
+ || underlying_type == wchar_type_node)
+ res->number_wide++;
+ else
+ res->number_non_char++;
+ return;
+ }
+ format_chars = TREE_STRING_POINTER (format_tree);
+ format_length = TREE_STRING_LENGTH (format_tree);
+ if (array_size != 0)
+ {
+ /* Variable length arrays can't be initialized. */
+ gcc_assert (TREE_CODE (array_size) == INTEGER_CST);
+
+ if (tree_fits_shwi_p (array_size))
+ {
+ HOST_WIDE_INT array_size_value = tree_to_shwi (array_size);
+ if (array_size_value > 0
+ && array_size_value == (int) array_size_value
+ && format_length > array_size_value)
+ format_length = array_size_value;
+ }
+ }
+ if (offset)
+ {
+ if (offset >= format_length)
+ {
+ res->number_non_literal++;
+ return;
+ }
+ format_chars += offset;
+ format_length -= offset;
+ }
+ if (format_length < 1 || format_chars[--format_length] != 0)
+ {
+ res->number_unterminated++;
+ return;
+ }
+ if (format_length == 0)
+ {
+ res->number_empty++;
+ return;
+ }
+
+ /* Skip to first argument to check. */
+ while (arg_num + 1 < info->first_arg_num)
+ {
+ if (params == 0)
+ return;
+ params = TREE_CHAIN (params);
+ ++arg_num;
+ }
+ /* Provisionally increment res->number_other; check_format_info_main
+ will decrement it if it finds there are extra arguments, but this way
+ need not adjust it for every return. */
+ res->number_other++;
+ object_allocator <format_wanted_type> fwt_pool ("format_wanted_type pool");
+ check_format_info_main (res, info, format_chars, fmt_param_loc, format_tree,
+ format_length, params, arg_num, fwt_pool, arglocs);
+}
+
+/* Support class for argument_parser and check_format_info_main.
+ Tracks any flag characters that have been applied to the
+ current argument. */
+
+class flag_chars_t
+{
+ public:
+ flag_chars_t ();
+ bool has_char_p (char ch) const;
+ void add_char (char ch);
+ void validate (const format_kind_info *fki,
+ const format_char_info *fci,
+ const format_flag_spec *flag_specs,
+ const char * const format_chars,
+ tree format_string_cst,
+ location_t format_string_loc,
+ const char * const orig_format_chars,
+ char format_char,
+ bool quoted);
+ int get_alloc_flag (const format_kind_info *fki);
+ int assignment_suppression_p (const format_kind_info *fki);
+
+ private:
+ char m_flag_chars[256];
+};
+
+/* Support struct for argument_parser and check_format_info_main.
+ Encapsulates any length modifier applied to the current argument. */
+
+struct length_modifier
+{
+ length_modifier ()
+ : chars (NULL), val (FMT_LEN_none), std (STD_C89),
+ scalar_identity_flag (0)
+ {
+ }
+
+ length_modifier (const char *chars_,
+ enum format_lengths val_,
+ enum format_std_version std_,
+ int scalar_identity_flag_)
+ : chars (chars_), val (val_), std (std_),
+ scalar_identity_flag (scalar_identity_flag_)
+ {
+ }
+
+ const char *chars;
+ enum format_lengths val;
+ enum format_std_version std;
+ int scalar_identity_flag;
+};
+
+/* Parsing one argument within a format string. */
+
+class argument_parser
+{
+ public:
+ argument_parser (function_format_info *info, const char *&format_chars,
+ tree format_string_cst,
+ const char * const orig_format_chars,
+ location_t format_string_loc, flag_chars_t &flag_chars,
+ int &has_operand_number, tree first_fillin_param,
+ object_allocator <format_wanted_type> &fwt_pool_,
+ vec<location_t> *arglocs);
+
+ bool read_any_dollar ();
+
+ bool read_format_flags ();
+
+ bool
+ read_any_format_width (tree &params,
+ unsigned HOST_WIDE_INT &arg_num);
+
+ void
+ read_any_format_left_precision ();
+
+ bool
+ read_any_format_precision (tree &params,
+ unsigned HOST_WIDE_INT &arg_num);
+
+ void handle_alloc_chars ();
+
+ length_modifier read_any_length_modifier ();
+
+ void read_any_other_modifier ();
+
+ const format_char_info *find_format_char_info (char format_char);
+
+ void
+ validate_flag_pairs (const format_char_info *fci,
+ char format_char);
+
+ void
+ give_y2k_warnings (const format_char_info *fci,
+ char format_char);
+
+ void parse_any_scan_set (const format_char_info *fci);
+
+ bool handle_conversions (const format_char_info *fci,
+ const length_modifier &len_modifier,
+ tree &wanted_type,
+ const char *&wanted_type_name,
+ unsigned HOST_WIDE_INT &arg_num,
+ tree &params,
+ char format_char);
+
+ bool
+ check_argument_type (const format_char_info *fci,
+ const struct kernel_ext_fmt *kef,
+ const length_modifier &len_modifier,
+ tree &wanted_type,
+ const char *&wanted_type_name,
+ const bool suppressed,
+ unsigned HOST_WIDE_INT &arg_num,
+ tree &params,
+ const int alloc_flag,
+ const char * const format_start,
+ const char * const type_start,
+ location_t fmt_param_loc,
+ char conversion_char);
+
+ private:
+ const function_format_info *const info;
+ const format_kind_info * const fki;
+ const format_flag_spec * const flag_specs;
+ const char *start_of_this_format;
+ const char *&format_chars;
+ const tree format_string_cst;
+ const char * const orig_format_chars;
+ const location_t format_string_loc;
+ object_allocator <format_wanted_type> &fwt_pool;
+ flag_chars_t &flag_chars;
+ int main_arg_num;
+ tree main_arg_params;
+ int &has_operand_number;
+ const tree first_fillin_param;
+ format_wanted_type width_wanted_type;
+ format_wanted_type precision_wanted_type;
+ public:
+ format_wanted_type main_wanted_type;
+ private:
+ format_wanted_type *first_wanted_type;
+ format_wanted_type *last_wanted_type;
+ vec<location_t> *arglocs;
+};
+
+/* flag_chars_t's constructor. */
+
+flag_chars_t::flag_chars_t ()
+{
+ m_flag_chars[0] = 0;
+}
+
+/* Has CH been seen as a flag within the current argument? */
+
+bool
+flag_chars_t::has_char_p (char ch) const
+{
+ return strchr (m_flag_chars, ch) != 0;
+}
+
+/* Add CH to the flags seen within the current argument. */
+
+void
+flag_chars_t::add_char (char ch)
+{
+ int i = strlen (m_flag_chars);
+ m_flag_chars[i++] = ch;
+ m_flag_chars[i] = 0;
+}
+
+/* Validate the individual flags used, removing any that are invalid. */
+
+void
+flag_chars_t::validate (const format_kind_info *fki,
+ const format_char_info *fci,
+ const format_flag_spec *flag_specs,
+ const char * const format_chars,
+ tree format_string_cst,
+ location_t format_string_loc,
+ const char * const orig_format_chars,
+ char format_char,
+ bool quoted)
+{
+ int i;
+ int d = 0;
+ bool quotflag = false;
+
+ for (i = 0; m_flag_chars[i] != 0; i++)
+ {
+ const format_flag_spec *s = get_flag_spec (flag_specs,
+ m_flag_chars[i], NULL);
+ m_flag_chars[i - d] = m_flag_chars[i];
+ if (m_flag_chars[i] == fki->length_code_char)
+ continue;
+
+ /* Remember if a quoting flag is seen. */
+ quotflag |= s->quoting;
+
+ if (strchr (fci->flag_chars, m_flag_chars[i]) == 0)
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "%s used with %<%%%c%> %s format",
+ _(s->name), format_char, fki->name);
+ d++;
+ continue;
+ }
+ if (pedantic)
+ {
+ const format_flag_spec *t;
+ if (ADJ_STD (s->std) > C_STD_VER)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "%s does not support %s",
+ C_STD_NAME (s->std), _(s->long_name));
+ t = get_flag_spec (flag_specs, m_flag_chars[i], fci->flags2);
+ if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std))
+ {
+ const char *long_name = (t->long_name != NULL
+ ? t->long_name
+ : s->long_name);
+ if (ADJ_STD (t->std) > C_STD_VER)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "%s does not support %s with"
+ " the %<%%%c%> %s format",
+ C_STD_NAME (t->std), _(long_name),
+ format_char, fki->name);
+ }
+ }
+
+ /* Detect quoting directives used within a quoted sequence, such
+ as GCC's "%<...%qE". */
+ if (quoted && s->quoting)
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars - 1,
+ OPT_Wformat_,
+ "%s used within a quoted sequence",
+ _(s->name));
+ }
+ }
+ m_flag_chars[i - d] = 0;
+
+ if (!quoted
+ && !quotflag
+ && strchr (fci->flags2, '\''))
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "%qc conversion used unquoted",
+ format_char);
+ }
+}
+
+/* Determine if an assignment-allocation has been set, requiring
+ an extra char ** for writing back a dynamically-allocated char *.
+ This is for handling the optional 'm' character in scanf. */
+
+int
+flag_chars_t::get_alloc_flag (const format_kind_info *fki)
+{
+ if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
+ && has_char_p ('a'))
+ return 1;
+ if (fki->alloc_char && has_char_p (fki->alloc_char))
+ return 1;
+ return 0;
+}
+
+/* Determine if an assignment-suppression character was seen.
+ ('*' in scanf, for discarding the converted input). */
+
+int
+flag_chars_t::assignment_suppression_p (const format_kind_info *fki)
+{
+ if (fki->suppression_char
+ && has_char_p (fki->suppression_char))
+ return 1;
+ return 0;
+}
+
+/* Constructor for argument_parser. Initialize for parsing one
+ argument within a format string. */
+
+argument_parser::
+argument_parser (function_format_info *info_, const char *&format_chars_,
+ tree format_string_cst_,
+ const char * const orig_format_chars_,
+ location_t format_string_loc_,
+ flag_chars_t &flag_chars_,
+ int &has_operand_number_,
+ tree first_fillin_param_,
+ object_allocator <format_wanted_type> &fwt_pool_,
+ vec<location_t> *arglocs_)
+: info (info_),
+ fki (&format_types[info->format_type]),
+ flag_specs (fki->flag_specs),
+ start_of_this_format (format_chars_),
+ format_chars (format_chars_),
+ format_string_cst (format_string_cst_),
+ orig_format_chars (orig_format_chars_),
+ format_string_loc (format_string_loc_),
+ fwt_pool (fwt_pool_),
+ flag_chars (flag_chars_),
+ main_arg_num (0),
+ main_arg_params (NULL),
+ has_operand_number (has_operand_number_),
+ first_fillin_param (first_fillin_param_),
+ first_wanted_type (NULL),
+ last_wanted_type (NULL),
+ arglocs (arglocs_)
+{
+}
+
+/* Handle dollars at the start of format arguments, setting up main_arg_params
+ and main_arg_num.
+
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::read_any_dollar ()
+{
+ if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
+ {
+ /* Possibly read a $ operand number at the start of the format.
+ If one was previously used, one is required here. If one
+ is not used here, we can't immediately conclude this is a
+ format without them, since it could be printf %m or scanf %*. */
+ int opnum;
+ opnum = maybe_read_dollar_number (&format_chars, 0,
+ first_fillin_param,
+ &main_arg_params, fki);
+ if (opnum == -1)
+ return false;
+ else if (opnum > 0)
+ {
+ has_operand_number = 1;
+ main_arg_num = opnum + info->first_arg_num - 1;
+ }
+ }
+ else if (fki->flags & FMT_FLAG_USE_DOLLAR)
+ {
+ if (avoid_dollar_number (format_chars))
+ return false;
+ }
+ return true;
+}
+
+/* Read any format flags, but do not yet validate them beyond removing
+ duplicates, since in general validation depends on the rest of
+ the format.
+
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::read_format_flags ()
+{
+ while (*format_chars != 0
+ && strchr (fki->flag_chars, *format_chars) != 0)
+ {
+ const format_flag_spec *s = get_flag_spec (flag_specs,
+ *format_chars, NULL);
+ if (flag_chars.has_char_p (*format_chars))
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars + 1 - orig_format_chars,
+ OPT_Wformat_,
+ "repeated %s in format", _(s->name));
+ }
+ else
+ flag_chars.add_char (*format_chars);
+
+ if (s->skip_next_char)
+ {
+ ++format_chars;
+ if (*format_chars == 0)
+ {
+ warning_at (format_string_loc, OPT_Wformat_,
+ "missing fill character at end of strfmon format");
+ return false;
+ }
+ }
+ ++format_chars;
+ }
+
+ return true;
+}
+
+/* Read any format width, possibly * or *m$.
+
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::
+read_any_format_width (tree &params,
+ unsigned HOST_WIDE_INT &arg_num)
+{
+ if (!fki->width_char)
+ return true;
+
+ if (fki->width_type != NULL && *format_chars == '*')
+ {
+ flag_chars.add_char (fki->width_char);
+ /* "...a field width...may be indicated by an asterisk.
+ In this case, an int argument supplies the field width..." */
+ ++format_chars;
+ if (has_operand_number != 0)
+ {
+ int opnum;
+ opnum = maybe_read_dollar_number (&format_chars,
+ has_operand_number == 1,
+ first_fillin_param,
+ &params, fki);
+ if (opnum == -1)
+ return false;
+ else if (opnum > 0)
+ {
+ has_operand_number = 1;
+ arg_num = opnum + info->first_arg_num - 1;
+ }
+ else
+ has_operand_number = 0;
+ }
+ else
+ {
+ if (avoid_dollar_number (format_chars))
+ return false;
+ }
+ if (info->first_arg_num != 0)
+ {
+ tree cur_param;
+ if (params == 0)
+ cur_param = NULL;
+ else
+ {
+ cur_param = TREE_VALUE (params);
+ if (has_operand_number <= 0)
+ {
+ params = TREE_CHAIN (params);
+ ++arg_num;
+ }
+ }
+ width_wanted_type.wanted_type = *fki->width_type;
+ width_wanted_type.wanted_type_name = NULL;
+ width_wanted_type.pointer_count = 0;
+ width_wanted_type.char_lenient_flag = 0;
+ width_wanted_type.scalar_identity_flag = 0;
+ width_wanted_type.writing_in_flag = 0;
+ width_wanted_type.reading_from_flag = 0;
+ width_wanted_type.kind = CF_KIND_FIELD_WIDTH;
+ width_wanted_type.format_start = format_chars - 1;
+ width_wanted_type.format_length = 1;
+ width_wanted_type.param = cur_param;
+ width_wanted_type.arg_num = arg_num;
+ width_wanted_type.offset_loc =
+ format_chars - orig_format_chars;
+ width_wanted_type.next = NULL;
+ if (last_wanted_type != 0)
+ last_wanted_type->next = &width_wanted_type;
+ if (first_wanted_type == 0)
+ first_wanted_type = &width_wanted_type;
+ last_wanted_type = &width_wanted_type;
+ }
+ }
+ else
+ {
+ /* Possibly read a numeric width. If the width is zero,
+ we complain if appropriate. */
+ int non_zero_width_char = FALSE;
+ int found_width = FALSE;
+ while (ISDIGIT (*format_chars))
+ {
+ found_width = TRUE;
+ if (*format_chars != '0')
+ non_zero_width_char = TRUE;
+ ++format_chars;
+ }
+ if (found_width && !non_zero_width_char &&
+ (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
+ warning_at (format_string_loc, OPT_Wformat_,
+ "zero width in %s format", fki->name);
+ if (found_width)
+ flag_chars.add_char (fki->width_char);
+ }
+
+ return true;
+}
+
+/* Read any format left precision (must be a number, not *). */
+void
+argument_parser::read_any_format_left_precision ()
+{
+ if (fki->left_precision_char == 0)
+ return;
+ if (*format_chars != '#')
+ return;
+
+ ++format_chars;
+ flag_chars.add_char (fki->left_precision_char);
+ if (!ISDIGIT (*format_chars))
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "empty left precision in %s format", fki->name);
+ while (ISDIGIT (*format_chars))
+ ++format_chars;
+}
+
+/* Read any format precision, possibly * or *m$.
+
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::
+read_any_format_precision (tree &params,
+ unsigned HOST_WIDE_INT &arg_num)
+{
+ if (fki->precision_char == 0)
+ return true;
+ if (*format_chars != '.')
+ return true;
+
+ ++format_chars;
+ flag_chars.add_char (fki->precision_char);
+ if (fki->precision_type != NULL && *format_chars == '*')
+ {
+ /* "...a...precision...may be indicated by an asterisk.
+ In this case, an int argument supplies the...precision." */
+ ++format_chars;
+ if (has_operand_number != 0)
+ {
+ int opnum;
+ opnum = maybe_read_dollar_number (&format_chars,
+ has_operand_number == 1,
+ first_fillin_param,
+ &params, fki);
+ if (opnum == -1)
+ return false;
+ else if (opnum > 0)
+ {
+ has_operand_number = 1;
+ arg_num = opnum + info->first_arg_num - 1;
+ }
+ else
+ has_operand_number = 0;
+ }
+ else
+ {
+ if (avoid_dollar_number (format_chars))
+ return false;
+ }
+ if (info->first_arg_num != 0)
+ {
+ tree cur_param;
+ if (params == 0)
+ cur_param = NULL;
+ else
+ {
+ cur_param = TREE_VALUE (params);
+ if (has_operand_number <= 0)
+ {
+ params = TREE_CHAIN (params);
+ ++arg_num;
+ }
+ }
+ precision_wanted_type.wanted_type = *fki->precision_type;
+ precision_wanted_type.wanted_type_name = NULL;
+ precision_wanted_type.pointer_count = 0;
+ precision_wanted_type.char_lenient_flag = 0;
+ precision_wanted_type.scalar_identity_flag = 0;
+ precision_wanted_type.writing_in_flag = 0;
+ precision_wanted_type.reading_from_flag = 0;
+ precision_wanted_type.kind = CF_KIND_FIELD_PRECISION;
+ precision_wanted_type.param = cur_param;
+ precision_wanted_type.format_start = format_chars - 2;
+ precision_wanted_type.format_length = 2;
+ precision_wanted_type.arg_num = arg_num;
+ precision_wanted_type.offset_loc =
+ format_chars - orig_format_chars;
+ precision_wanted_type.next = NULL;
+ if (last_wanted_type != 0)
+ last_wanted_type->next = &precision_wanted_type;
+ if (first_wanted_type == 0)
+ first_wanted_type = &precision_wanted_type;
+ last_wanted_type = &precision_wanted_type;
+ }
+ }
+ else
+ {
+ if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK)
+ && !ISDIGIT (*format_chars))
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "empty precision in %s format", fki->name);
+ while (ISDIGIT (*format_chars))
+ ++format_chars;
+ }
+
+ return true;
+}
+
+/* Parse any assignment-allocation flags, which request an extra
+ char ** for writing back a dynamically-allocated char *.
+ This is for handling the optional 'm' character in scanf,
+ and, before C99, 'a' (for compatibility with a non-standard
+ GNU libc extension). */
+
+void
+argument_parser::handle_alloc_chars ()
+{
+ if (fki->alloc_char && fki->alloc_char == *format_chars)
+ {
+ flag_chars.add_char (fki->alloc_char);
+ format_chars++;
+ }
+
+ /* Handle the scanf allocation kludge. */
+ if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
+ {
+ if (*format_chars == 'a' && !flag_isoc99)
+ {
+ if (format_chars[1] == 's' || format_chars[1] == 'S'
+ || format_chars[1] == '[')
+ {
+ /* 'a' is used as a flag. */
+ flag_chars.add_char ('a');
+ format_chars++;
+ }
+ }
+ }
+}
+
+/* Look for length modifiers within the current format argument,
+ returning a length_modifier instance describing it (or the
+ default if one is not found).
+
+ Issue warnings about non-standard modifiers. */
+
+length_modifier
+argument_parser::read_any_length_modifier ()
+{
+ length_modifier result;
+
+ const format_length_info *fli = fki->length_char_specs;
+ if (!fli)
+ return result;
+
+ while (fli->name != 0
+ && strncmp (fli->name, format_chars, strlen (fli->name)))
+ fli++;
+ if (fli->name != 0)
+ {
+ format_chars += strlen (fli->name);
+ if (fli->double_name != 0 && fli->name[0] == *format_chars)
+ {
+ format_chars++;
+ result = length_modifier (fli->double_name, fli->double_index,
+ fli->double_std, 0);
+ }
+ else
+ {
+ result = length_modifier (fli->name, fli->index, fli->std,
+ fli->scalar_identity_flag);
+ }
+ flag_chars.add_char (fki->length_code_char);
+ }
+ if (pedantic)
+ {
+ /* Warn if the length modifier is non-standard. */
+ if (ADJ_STD (result.std) > C_STD_VER)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "%s does not support the %qs %s length modifier",
+ C_STD_NAME (result.std), result.chars,
+ fki->name);
+ }
+
+ return result;
+}
+
+/* Read any other modifier (strftime E/O). */
+
+void
+argument_parser::read_any_other_modifier ()
+{
+ if (fki->modifier_chars == NULL)
+ return;
+
+ while (*format_chars != 0
+ && strchr (fki->modifier_chars, *format_chars) != 0)
+ {
+ if (flag_chars.has_char_p (*format_chars))
+ {
+ const format_flag_spec *s = get_flag_spec (flag_specs,
+ *format_chars, NULL);
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "repeated %s in format", _(s->name));
+ }
+ else
+ flag_chars.add_char (*format_chars);
+ ++format_chars;
+ }
+}
+
+/* Return the format_char_info corresponding to FORMAT_CHAR,
+ potentially issuing a warning if the format char is
+ not supported in the C standard version we are checking
+ against.
+
+ Issue a warning and return NULL if it is not found.
+
+ Issue warnings about non-standard modifiers. */
+
+const format_char_info *
+argument_parser::find_format_char_info (char format_char)
+{
+ const format_char_info *fci = fki->conversion_specs;
+
+ while (fci->format_chars != 0
+ && strchr (fci->format_chars, format_char) == 0)
+ ++fci;
+ if (fci->format_chars == 0)
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "unknown conversion type character"
+ " %qc in format",
+ format_char);
+ return NULL;
+ }
+
+ if (pedantic)
+ {
+ if (ADJ_STD (fci->std) > C_STD_VER)
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "%s does not support the %<%%%c%> %s format",
+ C_STD_NAME (fci->std), format_char, fki->name);
+ }
+
+ return fci;
+}
+
+/* Validate the pairs of flags used.
+ Issue warnings about incompatible combinations of flags. */
+
+void
+argument_parser::validate_flag_pairs (const format_char_info *fci,
+ char format_char)
+{
+ const format_flag_pair * const bad_flag_pairs = fki->bad_flag_pairs;
+
+ for (int i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
+ {
+ const format_flag_spec *s, *t;
+ if (!flag_chars.has_char_p (bad_flag_pairs[i].flag_char1))
+ continue;
+ if (!flag_chars.has_char_p (bad_flag_pairs[i].flag_char2))
+ continue;
+ if (bad_flag_pairs[i].predicate != 0
+ && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0)
+ continue;
+ s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL);
+ t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL);
+ if (bad_flag_pairs[i].ignored)
+ {
+ if (bad_flag_pairs[i].predicate != 0)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "%s ignored with %s and %<%%%c%> %s format",
+ _(s->name), _(t->name), format_char,
+ fki->name);
+ else
+ warning_at (format_string_loc, OPT_Wformat_,
+ "%s ignored with %s in %s format",
+ _(s->name), _(t->name), fki->name);
+ }
+ else
+ {
+ if (bad_flag_pairs[i].predicate != 0)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "use of %s and %s together with %<%%%c%> %s format",
+ _(s->name), _(t->name), format_char,
+ fki->name);
+ else
+ warning_at (format_string_loc, OPT_Wformat_,
+ "use of %s and %s together in %s format",
+ _(s->name), _(t->name), fki->name);
+ }
+ }
+}
+
+/* Give Y2K warnings. */
+
+void
+argument_parser::give_y2k_warnings (const format_char_info *fci,
+ char format_char)
+{
+ if (!warn_format_y2k)
+ return;
+
+ int y2k_level = 0;
+ if (strchr (fci->flags2, '4') != 0)
+ if (flag_chars.has_char_p ('E'))
+ y2k_level = 3;
+ else
+ y2k_level = 2;
+ else if (strchr (fci->flags2, '3') != 0)
+ y2k_level = 3;
+ else if (strchr (fci->flags2, '2') != 0)
+ y2k_level = 2;
+ if (y2k_level == 3)
+ warning_at (format_string_loc, OPT_Wformat_y2k,
+ "%<%%%c%> yields only last 2 digits of "
+ "year in some locales", format_char);
+ else if (y2k_level == 2)
+ warning_at (format_string_loc, OPT_Wformat_y2k,
+ "%<%%%c%> yields only last 2 digits of year",
+ format_char);
+}
+
+/* Parse any "scan sets" enclosed in square brackets, e.g.
+ for scanf-style calls. */
+
+void
+argument_parser::parse_any_scan_set (const format_char_info *fci)
+{
+ if (strchr (fci->flags2, '[') == NULL)
+ return;
+
+ /* Skip over scan set, in case it happens to have '%' in it. */
+ if (*format_chars == '^')
+ ++format_chars;
+ /* Find closing bracket; if one is hit immediately, then
+ it's part of the scan set rather than a terminator. */
+ if (*format_chars == ']')
+ ++format_chars;
+ while (*format_chars && *format_chars != ']')
+ ++format_chars;
+ if (*format_chars != ']')
+ /* The end of the format string was reached. */
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "no closing %<]%> for %<%%[%> format");
+}
+
+/* Return true if this argument is to be continued to be parsed,
+ false to skip to next argument. */
+
+bool
+argument_parser::handle_conversions (const format_char_info *fci,
+ const length_modifier &len_modifier,
+ tree &wanted_type,
+ const char *&wanted_type_name,
+ unsigned HOST_WIDE_INT &arg_num,
+ tree &params,
+ char format_char)
+{
+ enum format_std_version wanted_type_std;
+
+ if (!(fki->flags & (int) FMT_FLAG_ARG_CONVERT))
+ return true;
+
+ wanted_type = (fci->types[len_modifier.val].type
+ ? *fci->types[len_modifier.val].type : 0);
+ wanted_type_name = fci->types[len_modifier.val].name;
+ wanted_type_std = fci->types[len_modifier.val].std;
+ if (wanted_type == 0)
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "use of %qs length modifier with %qc type"
+ " character has either no effect"
+ " or undefined behavior",
+ len_modifier.chars, format_char);
+ /* Heuristic: skip one argument when an invalid length/type
+ combination is encountered. */
+ arg_num++;
+ if (params != 0)
+ params = TREE_CHAIN (params);
+ return false;
+ }
+ else if (pedantic
+ /* Warn if non-standard, provided it is more non-standard
+ than the length and type characters that may already
+ have been warned for. */
+ && ADJ_STD (wanted_type_std) > ADJ_STD (len_modifier.std)
+ && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
+ {
+ if (ADJ_STD (wanted_type_std) > C_STD_VER)
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "%s does not support the %<%%%s%c%> %s format",
+ C_STD_NAME (wanted_type_std),
+ len_modifier.chars,
+ format_char, fki->name);
+ }
+
+ return true;
+}
+
+/* Check type of argument against desired type.
+
+ Return true if format parsing is to continue, false otherwise. */
+
+bool
+argument_parser::
+check_argument_type (const format_char_info *fci,
+ const struct kernel_ext_fmt *kef,
+ const length_modifier &len_modifier,
+ tree &wanted_type,
+ const char *&wanted_type_name,
+ const bool suppressed,
+ unsigned HOST_WIDE_INT &arg_num,
+ tree &params,
+ const int alloc_flag,
+ const char * const format_start,
+ const char * const type_start,
+ location_t fmt_param_loc,
+ char conversion_char)
+{
+ if (info->first_arg_num == 0)
+ return true;
+
+ if ((fci->pointer_count == 0 && wanted_type == void_type_node)
+ || suppressed)
+ {
+ if (main_arg_num != 0)
+ {
+ if (suppressed)
+ warning_at (format_string_loc, OPT_Wformat_,
+ "operand number specified with "
+ "suppressed assignment");
+ else
+ warning_at (format_string_loc, OPT_Wformat_,
+ "operand number specified for format "
+ "taking no argument");
+ }
+ }
+ else
+ {
+ format_wanted_type *wanted_type_ptr;
+
+ if (main_arg_num != 0)
+ {
+ arg_num = main_arg_num;
+ params = main_arg_params;
+ }
+ else
+ {
+ ++arg_num;
+ if (has_operand_number > 0)
+ {
+ warning_at (format_string_loc, OPT_Wformat_,
+ "missing $ operand number in format");
+ return false;
+ }
+ else
+ has_operand_number = 0;
+ }
+
+ wanted_type_ptr = &main_wanted_type;
+ while (fci)
+ {
+ tree cur_param;
+ if (params == 0)
+ cur_param = NULL;
+ else
+ {
+ cur_param = TREE_VALUE (params);
+ params = TREE_CHAIN (params);
+ }
+
+ wanted_type_ptr->wanted_type = wanted_type;
+ wanted_type_ptr->wanted_type_name = wanted_type_name;
+ wanted_type_ptr->pointer_count = fci->pointer_count + alloc_flag;
+ wanted_type_ptr->char_lenient_flag = 0;
+ if (strchr (fci->flags2, 'c') != 0)
+ wanted_type_ptr->char_lenient_flag = 1;
+ wanted_type_ptr->scalar_identity_flag = 0;
+ if (len_modifier.scalar_identity_flag)
+ wanted_type_ptr->scalar_identity_flag = 1;
+ wanted_type_ptr->writing_in_flag = 0;
+ wanted_type_ptr->reading_from_flag = 0;
+ if (alloc_flag)
+ wanted_type_ptr->writing_in_flag = 1;
+ else
+ {
+ if (strchr (fci->flags2, 'W') != 0)
+ wanted_type_ptr->writing_in_flag = 1;
+ if (strchr (fci->flags2, 'R') != 0)
+ wanted_type_ptr->reading_from_flag = 1;
+ }
+ wanted_type_ptr->kind = CF_KIND_FORMAT;
+ wanted_type_ptr->param = cur_param;
+ wanted_type_ptr->arg_num = arg_num;
+ wanted_type_ptr->format_start = format_start;
+ wanted_type_ptr->format_length = format_chars - format_start;
+ wanted_type_ptr->offset_loc = format_chars - orig_format_chars;
+ wanted_type_ptr->next = NULL;
+ if (last_wanted_type != 0)
+ last_wanted_type->next = wanted_type_ptr;
+ if (first_wanted_type == 0)
+ first_wanted_type = wanted_type_ptr;
+ last_wanted_type = wanted_type_ptr;
+
+ fci = fci->chain;
+ if (fci)
+ {
+ wanted_type_ptr = fwt_pool.allocate ();
+ arg_num++;
+ wanted_type = *fci->types[len_modifier.val].type;
+ wanted_type_name = fci->types[len_modifier.val].name;
+ }
+ }
+ }
+
+ if (first_wanted_type != 0)
+ {
+ ptrdiff_t offset_to_format_start = (start_of_this_format - 1) - orig_format_chars;
+ ptrdiff_t offset_to_format_end = (format_chars - 1) - orig_format_chars;
+ /* By default, use the end of the range for the caret location. */
+ substring_loc fmt_loc (fmt_param_loc, TREE_TYPE (format_string_cst),
+ offset_to_format_end,
+ offset_to_format_start, offset_to_format_end);
+ ptrdiff_t offset_to_type_start = type_start - orig_format_chars;
+ check_format_types (fmt_loc, first_wanted_type, fki,
+ offset_to_type_start,
+ conversion_char, arglocs);
+
+ /* note printf extension type checks are *additional* - %p must always
+ * be pointer compatible, %d always int compatible.
+ */
+ if (!kef)
+ return true;
+
+ const struct kernel_ext_fmt *kef_now;
+ bool success;
+
+ for (kef_now = kef; kef_now->suffix && !strcmp (kef->suffix, kef_now->suffix); kef_now++)
+ {
+ success = check_kef_type (fmt_loc, kef_now,
+ first_wanted_type->arg_num,
+ first_wanted_type->param,
+ kef_now->type, fki, offset_to_type_start, conversion_char, arglocs);
+
+ if (success)
+ return true;
+ }
+
+ location_t param_loc;
+
+ if (EXPR_HAS_LOCATION (first_wanted_type->param))
+ param_loc = EXPR_LOCATION (first_wanted_type->param);
+ else if (arglocs)
+ {
+ /* arg_num is 1-based. */
+ gcc_assert (first_wanted_type->arg_num > 0);
+ param_loc = (*arglocs)[first_wanted_type->arg_num - 1];
+ }
+
+ format_type_warning (fmt_loc, param_loc, first_wanted_type,
+ kef->type, TREE_TYPE (first_wanted_type->param),
+ fki, offset_to_type_start, conversion_char);
+ }
+
+ return true;
+}
+
+/* Do the main part of checking a call to a format function. FORMAT_CHARS
+ is the NUL-terminated format string (which at this point may contain
+ internal NUL characters); FORMAT_LENGTH is its length (excluding the
+ terminating NUL character). ARG_NUM is one less than the number of
+ the first format argument to check; PARAMS points to that format
+ argument in the list of arguments. */
+
+static void
+check_format_info_main (format_check_results *res,
+ function_format_info *info, const char *format_chars,
+ location_t fmt_param_loc, tree format_string_cst,
+ int format_length, tree params,
+ unsigned HOST_WIDE_INT arg_num,
+ object_allocator <format_wanted_type> &fwt_pool,
+ vec<location_t> *arglocs)
+{
+ const char * const orig_format_chars = format_chars;
+ const tree first_fillin_param = params;
+
+ const format_kind_info * const fki = &format_types[info->format_type];
+ const format_flag_spec * const flag_specs = fki->flag_specs;
+ const location_t format_string_loc = res->format_string_loc;
+
+ /* -1 if no conversions taking an operand have been found; 0 if one has
+ and it didn't use $; 1 if $ formats are in use. */
+ int has_operand_number = -1;
+
+ /* Vector of pointers to opening quoting directives (like GCC "%<"). */
+ auto_vec<const char*> quotdirs;
+
+ /* Pointers to the most recent color directives (like GCC's "%r or %R").
+ A starting color directive much be terminated before the end of
+ the format string. A terminating directive makes no sense without
+ a prior starting directive. */
+ const char *color_begin = NULL;
+ const char *color_end = NULL;
+
+ init_dollar_format_checking (info->first_arg_num, first_fillin_param);
+
+ while (*format_chars != 0)
+ {
+ if (*format_chars++ != '%')
+ continue;
+ if (*format_chars == 0)
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "spurious trailing %<%%%> in format");
+ continue;
+ }
+ if (*format_chars == '%')
+ {
+ ++format_chars;
+ continue;
+ }
+
+ flag_chars_t flag_chars;
+ argument_parser arg_parser (info, format_chars, format_string_cst,
+ orig_format_chars, format_string_loc,
+ flag_chars, has_operand_number,
+ first_fillin_param, fwt_pool, arglocs);
+
+ if (!arg_parser.read_any_dollar ())
+ return;
+
+ if (!arg_parser.read_format_flags ())
+ return;
+
+ /* Read any format width, possibly * or *m$. */
+ if (!arg_parser.read_any_format_width (params, arg_num))
+ return;
+
+ /* Read any format left precision (must be a number, not *). */
+ arg_parser.read_any_format_left_precision ();
+
+ /* Read any format precision, possibly * or *m$. */
+ if (!arg_parser.read_any_format_precision (params, arg_num))
+ return;
+
+ const char *format_start = format_chars;
+
+ arg_parser.handle_alloc_chars ();
+
+ /* The rest of the conversion specification is the length modifier
+ (if any), and the conversion specifier, so this is where the
+ type information starts. If we need to issue a suggestion
+ about a type mismatch, then we should preserve everything up
+ to here. */
+ const char *type_start = format_chars;
+
+ /* Read any length modifier, if this kind of format has them. */
+ const length_modifier len_modifier
+ = arg_parser.read_any_length_modifier ();
+
+ /* Read any modifier (strftime E/O). */
+ arg_parser.read_any_other_modifier ();
+
+ char format_char = *format_chars;
+ if (format_char == 0
+ || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
+ && format_char == '%'))
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "conversion lacks type at end of format");
+ continue;
+ }
+ format_chars++;
+
+ const format_char_info * const fci
+ = arg_parser.find_format_char_info (format_char);
+ if (!fci)
+ continue;
+
+ struct kernel_ext_fmt *etab = fci->kernel_ext;
+
+ if (etab && format_chars[0] >= 'A' && format_chars[0] <= 'Z')
+ {
+ struct kernel_ext_fmt *etab_end = etab + ETAB_SZ;
+
+ for (; etab < etab_end && etab->suffix; etab++)
+ {
+ if (!strncmp (etab->suffix, format_chars, strlen (etab->suffix)))
+ break;
+ }
+
+ if (!etab->suffix || etab == etab_end)
+ {
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars + 1,
+ OPT_Wformat_,
+ "unrecognized printf extension suffix");
+ etab = NULL;
+ }
+ else
+ {
+ format_chars += strlen (etab->suffix);
+ }
+ }
+ else
+ etab = NULL;
+
+ flag_chars.validate (fki, fci, flag_specs, format_chars,
+ format_string_cst,
+ format_string_loc, orig_format_chars, format_char,
+ quotdirs.length () > 0);
+
+ const int alloc_flag = flag_chars.get_alloc_flag (fki);
+ const bool suppressed = flag_chars.assignment_suppression_p (fki);
+
+ /* Diagnose nested or unmatched quoting directives such as GCC's
+ "%<...%<" and "%>...%>". */
+ bool quot_begin_p = strchr (fci->flags2, '<');
+ bool quot_end_p = strchr (fci->flags2, '>');
+
+ if (quot_begin_p && !quot_end_p)
+ {
+ if (quotdirs.length ())
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "nested quoting directive");
+ quotdirs.safe_push (format_chars);
+ }
+ else if (!quot_begin_p && quot_end_p)
+ {
+ if (quotdirs.length ())
+ quotdirs.pop ();
+ else
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "unmatched quoting directive");
+ }
+
+ bool color_begin_p = strchr (fci->flags2, '/');
+ if (color_begin_p)
+ {
+ color_begin = format_chars;
+ color_end = NULL;
+ }
+ else if (strchr (fci->flags2, '\\'))
+ {
+ if (color_end)
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "%qc directive redundant after prior "
+ "occurence of the same", format_char);
+ else if (!color_begin)
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "unmatched color reset directive");
+ color_end = format_chars;
+ }
+
+ /* Diagnose directives that shouldn't appear in a quoted sequence.
+ (They are denoted by a double quote in FLAGS2.) */
+ if (quotdirs.length ())
+ {
+ if (strchr (fci->flags2, '"'))
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars - orig_format_chars,
+ OPT_Wformat_,
+ "%qc conversion used within a quoted "
+ "sequence",
+ format_char);
+ }
+
+ /* Validate the pairs of flags used. */
+ arg_parser.validate_flag_pairs (fci, format_char);
+
+ arg_parser.give_y2k_warnings (fci, format_char);
+
+ arg_parser.parse_any_scan_set (fci);
+
+ tree wanted_type = NULL;
+ const char *wanted_type_name = NULL;
+
+ if (!arg_parser.handle_conversions (fci, len_modifier,
+ wanted_type, wanted_type_name,
+ arg_num,
+ params,
+ format_char))
+ continue;
+
+ arg_parser.main_wanted_type.next = NULL;
+
+ /* Finally. . .check type of argument against desired type! */
+ if (!arg_parser.check_argument_type (fci, etab, len_modifier,
+ wanted_type, wanted_type_name,
+ suppressed,
+ arg_num, params,
+ alloc_flag,
+ format_start, type_start,
+ fmt_param_loc,
+ format_char))
+ return;
+ }
+
+ if (format_chars - orig_format_chars != format_length)
+ format_warning_at_char (format_string_loc, format_string_cst,
+ format_chars + 1 - orig_format_chars,
+ OPT_Wformat_contains_nul,
+ "embedded %<\\0%> in format");
+ if (info->first_arg_num != 0 && params != 0
+ && has_operand_number <= 0)
+ {
+ res->number_other--;
+ res->number_extra_args++;
+ }
+ if (has_operand_number > 0)
+ finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK);
+
+ if (quotdirs.length ())
+ format_warning_at_char (format_string_loc, format_string_cst,
+ quotdirs.pop () - orig_format_chars,
+ OPT_Wformat_, "unterminated quoting directive");
+ if (color_begin && !color_end)
+ format_warning_at_char (format_string_loc, format_string_cst,
+ color_begin - orig_format_chars,
+ OPT_Wformat_, "unterminated color directive");
+}
+
+/* Check the argument types from a single format conversion (possibly
+ including width and precision arguments).
+
+ FMT_LOC is the location of the format conversion.
+
+ TYPES is a singly-linked list expressing the parts of the format
+ conversion that expect argument types, and the arguments they
+ correspond to.
+
+ OFFSET_TO_TYPE_START is the offset within the execution-charset encoded
+ format string to where type information begins for the conversion
+ (the length modifier and conversion specifier).
+
+ CONVERSION_CHAR is the user-provided conversion specifier.
+
+ For example, given:
+
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+
+ then FMT_LOC covers this range:
+
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^^^^^^^^^
+
+ and TYPES in this case is a three-entry singly-linked list consisting of:
+ (1) the check for the field width here:
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^ ^^^^
+ against arg3, and
+ (2) the check for the field precision here:
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^^ ^^^^
+ against arg4, and
+ (3) the check for the length modifier and conversion char here:
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^^^ ^^^^
+ against arg5.
+
+ OFFSET_TO_TYPE_START is 13, the offset to the "lld" within the
+ STRING_CST:
+
+ 0000000000111111111122
+ 0123456789012345678901
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^ ^
+ | ` CONVERSION_CHAR: 'd'
+ type starts here. */
+tree type_normalize (tree type, tree *cousin, tree target = NULL)
+{
+ while (1)
+ {
+ if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == POINTER_TYPE)
+ return type;
+ if (target)
+ /* Strip off any "const" etc. */
+ type = build_qualified_type (type, 0);
+ if (TREE_CODE (TYPE_NAME (type)) != TYPE_DECL)
+ return type;
+
+ if (target && (type == target || TYPE_NAME (type) == target))
+ return target;
+
+ struct type_special *t;
+ for (t = special_types; t->match; t++)
+ {
+ if (!*t->match)
+ continue;
+ if (TYPE_NAME (type) != *t->match)
+ continue;
+ if (t->cousin && *t->cousin)
+ *cousin = *t->cousin;
+ if (t->replace)
+ return *t->replace ? *t->replace : type;
+ return type;
+ }
+
+ tree orig = DECL_ORIGINAL_TYPE (TYPE_NAME (type));
+ if (!orig)
+ return type;
+
+ type = orig;
+ }
+ return type;
+}
+
+static void
+check_format_types (const substring_loc &fmt_loc,
+ format_wanted_type *types, const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char,
+ vec<location_t> *arglocs)
+{
+ for (; types != 0; types = types->next)
+ {
+ tree cur_param;
+ tree cur_type;
+ tree cur_type_cousin = NULL;
+ tree orig_cur_type;
+ tree wanted_type;
+ int arg_num;
+ int i;
+ int char_type_flag;
+
+ wanted_type = types->wanted_type;
+ arg_num = types->arg_num;
+
+ /* The following should not occur here. */
+ gcc_assert (wanted_type);
+ gcc_assert (wanted_type != void_type_node || types->pointer_count);
+
+ if (types->pointer_count == 0)
+ wanted_type = lang_hooks.types.type_promotes_to (wanted_type);
+
+ switch (TREE_CODE (wanted_type))
+ {
+ case IDENTIFIER_NODE:
+ break;
+ case TYPE_DECL:
+ wanted_type = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (wanted_type));
+ break;
+ default:
+ wanted_type = TYPE_MAIN_VARIANT (wanted_type);
+ break;
+ }
+
+ cur_param = types->param;
+ if (!cur_param)
+ {
+ format_type_warning (fmt_loc, UNKNOWN_LOCATION, types, wanted_type,
+ NULL, fki, offset_to_type_start,
+ conversion_char);
+ continue;
+ }
+
+ cur_type = TREE_TYPE (cur_param);
+ if (cur_type == error_mark_node)
+ continue;
+ orig_cur_type = cur_type;
+ char_type_flag = 0;
+
+ location_t param_loc = UNKNOWN_LOCATION;
+ if (EXPR_HAS_LOCATION (cur_param))
+ param_loc = EXPR_LOCATION (cur_param);
+ else if (arglocs)
+ {
+ /* arg_num is 1-based. */
+ gcc_assert (types->arg_num > 0);
+ param_loc = (*arglocs)[types->arg_num - 1];
+ }
+
+ STRIP_NOPS (cur_param);
+
+ /* Check the types of any additional pointer arguments
+ that precede the "real" argument. */
+ for (i = 0; i < types->pointer_count; ++i)
+ {
+ if (TREE_CODE (cur_type) == POINTER_TYPE)
+ {
+ cur_type = TREE_TYPE (cur_type);
+ if (cur_type == error_mark_node)
+ break;
+
+ /* Check for writing through a NULL pointer. */
+ if (types->writing_in_flag
+ && i == 0
+ && cur_param != 0
+ && integer_zerop (cur_param))
+ warning (OPT_Wformat_, "writing through null pointer "
+ "(argument %d)", arg_num);
+
+ /* Check for reading through a NULL pointer. */
+ if (types->reading_from_flag
+ && i == 0
+ && cur_param != 0
+ && integer_zerop (cur_param))
+ warning (OPT_Wformat_, "reading through null pointer "
+ "(argument %d)", arg_num);
+
+ if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
+ cur_param = TREE_OPERAND (cur_param, 0);
+ else
+ cur_param = 0;
+
+ /* See if this is an attempt to write into a const type with
+ scanf or with printf "%n". Note: the writing in happens
+ at the first indirection only, if for example
+ void * const * is passed to scanf %p; passing
+ const void ** is simply passing an incompatible type. */
+ if (types->writing_in_flag
+ && i == 0
+ && (TYPE_READONLY (cur_type)
+ || (cur_param != 0
+ && (CONSTANT_CLASS_P (cur_param)
+ || (DECL_P (cur_param)
+ && TREE_READONLY (cur_param))))))
+ warning (OPT_Wformat_, "writing into constant object "
+ "(argument %d)", arg_num);
+
+ /* If there are extra type qualifiers beyond the first
+ indirection, then this makes the types technically
+ incompatible. */
+ if (i > 0
+ && pedantic
+ && (TYPE_READONLY (cur_type)
+ || TYPE_VOLATILE (cur_type)
+ || TYPE_ATOMIC (cur_type)
+ || TYPE_RESTRICT (cur_type)))
+ warning (OPT_Wformat_, "extra type qualifiers in format "
+ "argument (argument %d)",
+ arg_num);
+
+ }
+ else
+ {
+ format_type_warning (fmt_loc, param_loc,
+ types, wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char);
+ break;
+ }
+ }
+
+ if (i < types->pointer_count)
+ continue;
+
+ cur_type = type_normalize (cur_type, &cur_type_cousin);
+
+ /* Check whether the argument type is a character type. This leniency
+ only applies to certain formats, flagged with 'c'. */
+ if (types->char_lenient_flag)
+ char_type_flag = (cur_type == char_type_node
+ || cur_type == signed_char_type_node
+ || cur_type == unsigned_char_type_node);
+
+ int compat = lang_hooks.types_compatible_p (wanted_type, cur_type);
+ /* Check the type of the "real" argument, if there's a type we want. */
+ if ((TREE_CODE (wanted_type) != INTEGER_TYPE || types->pointer_count)
+ && compat)
+ continue;
+ if (TREE_CODE (wanted_type) == INTEGER_TYPE && !types->pointer_count
+ && compat)
+ {
+compat_inner:
+ if (TREE_CODE (cur_param) == INTEGER_CST)
+ continue;
+
+ if (TREE_CODE (types->wanted_type) == TYPE_DECL
+ && TREE_CODE (cur_type) == TYPE_DECL)
+ {
+ if (types->wanted_type == cur_type)
+ continue;
+ format_type_warning (fmt_loc, param_loc, types,
+ wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char,
+ " (strict match required [A])");
+ continue;
+ }
+ else if (TREE_CODE (types->wanted_type) == TYPE_DECL)
+ {
+ if (types->wanted_type == TYPE_NAME(cur_type))
+ continue;
+ format_type_warning (fmt_loc, param_loc, types,
+ wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char,
+ " (strict match required [B])");
+ continue;
+ }
+ else if (wanted_type == cur_type)
+ continue;
+ else if (cur_type_cousin)
+ {
+ format_type_warning (fmt_loc, param_loc, types,
+ wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char,
+ " (strict match required [C])");
+ }
+
+ /*
+ format_type_warning (fmt_loc, param_loc, types,
+ wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char,
+ " (ultra-pedantic mode)");
+ */
+ continue;
+ }
+
+ /* If we want 'void *', allow any pointer type.
+ (Anything else would already have got a warning.)
+ With -Wpedantic, only allow pointers to void and to character
+ types. */
+ if (wanted_type == void_type_node
+ && (!pedantic || (i == 1 && char_type_flag)))
+ continue;
+ /* Don't warn about differences merely in signedness, unless
+ -Wpedantic. With -Wpedantic, warn if the type is a pointer
+ target and not a character type, and for character types at
+ a second level of indirection. */
+ if (TREE_CODE (wanted_type) == INTEGER_TYPE
+ && TREE_CODE (cur_type) == INTEGER_TYPE
+ && ((!pedantic && !warn_format_signedness)
+ || (i == 0 && !warn_format_signedness)
+ || (i == 1 && char_type_flag))
+ && (TYPE_UNSIGNED (wanted_type)
+ ? wanted_type == c_common_unsigned_type (cur_type)
+ : wanted_type == c_common_signed_type (cur_type)))
+ {
+ if (cur_type_cousin)
+ {
+ if (TREE_CODE (types->wanted_type) == TYPE_DECL
+ && TREE_CODE (cur_type_cousin) == TYPE_DECL)
+ {
+ if (types->wanted_type == cur_type_cousin)
+ continue;
+ format_type_warning (fmt_loc, param_loc, types,
+ wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char,
+ " (strict match required [X])");
+ continue;
+ }
+ else if (TREE_CODE (types->wanted_type) == TYPE_DECL)
+ {
+ if (types->wanted_type == TYPE_NAME(cur_type_cousin))
+ continue;
+ format_type_warning (fmt_loc, param_loc, types,
+ wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char,
+ " (strict match required [Y])");
+ continue;
+ }
+ else if (wanted_type == cur_type_cousin)
+ continue;
+ else
+ {
+ format_type_warning (fmt_loc, param_loc, types,
+ wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char,
+ " (strict match required [Z])");
+ }
+ }
+
+ goto compat_inner;
+ }
+ /* Don't warn about differences merely in signedness if we know
+ that the current type is integer-promoted and its original type
+ was unsigned such as that it is in the range of WANTED_TYPE. */
+ if (TREE_CODE (wanted_type) == INTEGER_TYPE
+ && TREE_CODE (cur_type) == INTEGER_TYPE
+ && warn_format_signedness
+ && TYPE_UNSIGNED (wanted_type)
+ && cur_param != NULL_TREE
+ && TREE_CODE (cur_param) == NOP_EXPR)
+ {
+ tree t = TREE_TYPE (TREE_OPERAND (cur_param, 0));
+ if (TYPE_UNSIGNED (t)
+ && cur_type == lang_hooks.types.type_promotes_to (t))
+ continue;
+ }
+ /* Likewise, "signed char", "unsigned char" and "char" are
+ equivalent but the above test won't consider them equivalent. */
+ if (wanted_type == char_type_node
+ && (!pedantic || i < 2)
+ && char_type_flag)
+ continue;
+ if (types->scalar_identity_flag
+ && (TREE_CODE (cur_type) == TREE_CODE (wanted_type)
+ || (INTEGRAL_TYPE_P (cur_type)
+ && INTEGRAL_TYPE_P (wanted_type)))
+ && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type))
+ continue;
+ /* Now we have a type mismatch. */
+ format_type_warning (fmt_loc, param_loc, types,
+ wanted_type, orig_cur_type, fki,
+ offset_to_type_start, conversion_char);
+ }
+}
+
+static bool
+check_kef_type (const substring_loc &fmt_loc,
+ const struct kernel_ext_fmt *kef,
+ unsigned arg_num,
+ tree cur_param,
+ tree wanted_type,
+ const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char,
+ vec<location_t> *arglocs)
+{
+ tree cur_type;
+ bool ok = true;
+ int i;
+
+ /* The following should not occur here. */
+ gcc_assert (wanted_type);
+ gcc_assert (wanted_type != void_type_node || kef->ptrlevel);
+
+ if (TREE_CODE (wanted_type) == TYPE_DECL)
+ wanted_type = DECL_ORIGINAL_TYPE (wanted_type);
+
+ if (!cur_param)
+ return false;
+
+ cur_type = TREE_TYPE (cur_param);
+ if (cur_type == error_mark_node)
+ return false;
+
+ location_t param_loc = UNKNOWN_LOCATION;
+ if (EXPR_HAS_LOCATION (cur_param))
+ param_loc = EXPR_LOCATION (cur_param);
+ else if (arglocs)
+ {
+ /* arg_num is 1-based. */
+ gcc_assert (arg_num > 0);
+ param_loc = (*arglocs)[arg_num - 1];
+ }
+ (void)param_loc;
+
+ STRIP_NOPS (cur_param);
+
+ /* Check the types of any additional pointer arguments
+ that precede the "real" argument. */
+ for (i = 0; i < kef->ptrlevel; ++i)
+ {
+ if (TREE_CODE (cur_type) == POINTER_TYPE)
+ {
+ cur_type = TREE_TYPE (cur_type);
+ if (cur_type == error_mark_node)
+ break;
+
+ if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
+ cur_param = TREE_OPERAND (cur_param, 0);
+ else
+ cur_param = 0;
+
+ /* If there are extra type qualifiers beyond the first
+ indirection, then this makes the types technically
+ incompatible. */
+ if (i > 0
+ && pedantic
+ && (TYPE_READONLY (cur_type)
+ || TYPE_VOLATILE (cur_type)
+ || TYPE_ATOMIC (cur_type)
+ || TYPE_RESTRICT (cur_type)))
+ warning (OPT_Wformat_, "extra type qualifiers in format "
+ "argument (argument %d)",
+ arg_num);
+
+ }
+ else
+ {
+ ok = false;
+ break;
+ }
+ }
+
+ if (i < kef->ptrlevel)
+ return ok;
+
+ int compat = lang_hooks.types_compatible_p (wanted_type, cur_type);
+
+ if (!compat)
+ return false;
+
+ tree cousin;
+ tree normal_type;
+
+ normal_type = type_normalize (cur_type, &cousin, wanted_type);
+
+ return normal_type == wanted_type;
+}
+
+
+/* Given type TYPE, attempt to dereference the type N times
+ (e.g. from ("int ***", 2) to "int *")
+
+ Return the derefenced type, with any qualifiers
+ such as "const" stripped from the result, or
+ NULL if unsuccessful (e.g. TYPE is not a pointer type). */
+
+static tree
+deref_n_times (tree type, int n)
+{
+ gcc_assert (type);
+
+ for (int i = n; i > 0; i--)
+ {
+ if (TREE_CODE (type) != POINTER_TYPE)
+ return NULL_TREE;
+ type = TREE_TYPE (type);
+ }
+ /* Strip off any "const" etc. */
+ return build_qualified_type (type, 0);
+}
+
+/* Lookup the format code for FORMAT_LEN within FLI,
+ returning the string code for expressing it, or NULL
+ if it is not found. */
+
+static const char *
+get_modifier_for_format_len (const format_length_info *fli,
+ enum format_lengths format_len)
+{
+ for (; fli->name; fli++)
+ {
+ if (fli->index == format_len)
+ return fli->name;
+ if (fli->double_index == format_len)
+ return fli->double_name;
+ }
+ return NULL;
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+static void
+test_get_modifier_for_format_len ()
+{
+ ASSERT_STREQ ("h",
+ get_modifier_for_format_len (printf_length_specs, FMT_LEN_h));
+ ASSERT_STREQ ("hh",
+ get_modifier_for_format_len (printf_length_specs, FMT_LEN_hh));
+ ASSERT_STREQ ("L",
+ get_modifier_for_format_len (printf_length_specs, FMT_LEN_L));
+ ASSERT_EQ (NULL,
+ get_modifier_for_format_len (printf_length_specs, FMT_LEN_none));
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
+/* Determine if SPEC_TYPE and ARG_TYPE are sufficiently similar for a
+ format_type_detail using SPEC_TYPE to be offered as a suggestion for
+ Wformat type errors where the argument has type ARG_TYPE. */
+
+static bool
+matching_type_p (tree spec_type, tree arg_type)
+{
+ gcc_assert (spec_type);
+ gcc_assert (arg_type);
+
+ /* If any of the types requires structural equality, we can't compare
+ their canonical types. */
+ if (TYPE_STRUCTURAL_EQUALITY_P (spec_type)
+ || TYPE_STRUCTURAL_EQUALITY_P (arg_type))
+ return false;
+
+ spec_type = TYPE_CANONICAL (spec_type);
+ arg_type = TYPE_CANONICAL (arg_type);
+
+ if (TREE_CODE (spec_type) == INTEGER_TYPE
+ && TREE_CODE (arg_type) == INTEGER_TYPE
+ && (TYPE_UNSIGNED (spec_type)
+ ? spec_type == c_common_unsigned_type (arg_type)
+ : spec_type == c_common_signed_type (arg_type)))
+ return true;
+
+ return spec_type == arg_type;
+}
+
+/* Subroutine of get_format_for_type.
+
+ Generate a string containing the length modifier and conversion specifier
+ that should be used to format arguments of type ARG_TYPE within FKI
+ (effectively the inverse of the checking code).
+
+ If CONVERSION_CHAR is not zero (the first pass), the resulting suggestion
+ is required to use it, for correcting bogus length modifiers.
+ If CONVERSION_CHAR is zero (the second pass), then allow any suggestion
+ that matches ARG_TYPE.
+
+ If successful, returns a non-NULL string which should be freed
+ by the caller.
+ Otherwise, returns NULL. */
+
+static char *
+get_format_for_type_1 (const format_kind_info *fki, tree arg_type,
+ char conversion_char)
+{
+ gcc_assert (arg_type);
+
+ const format_char_info *spec;
+ for (spec = &fki->conversion_specs[0];
+ spec->format_chars;
+ spec++)
+ {
+ if (conversion_char)
+ if (!strchr (spec->format_chars, conversion_char))
+ continue;
+
+ tree effective_arg_type = deref_n_times (arg_type,
+ spec->pointer_count);
+ if (!effective_arg_type)
+ continue;
+ for (int i = 0; i < FMT_LEN_MAX; i++)
+ {
+ const format_type_detail *ftd = &spec->types[i];
+ if (!ftd->type)
+ continue;
+ if (matching_type_p (*ftd->type, effective_arg_type))
+ {
+ const char *len_modifier
+ = get_modifier_for_format_len (fki->length_char_specs,
+ (enum format_lengths)i);
+ if (!len_modifier)
+ len_modifier = "";
+
+ if (conversion_char)
+ /* We found a match, using the given conversion char - the
+ length modifier was incorrect (or absent).
+ Provide a suggestion using the conversion char with the
+ correct length modifier for the type. */
+ return xasprintf ("%s%c", len_modifier, conversion_char);
+ else
+ /* 2nd pass: no match was possible using the user-provided
+ conversion char, but we do have a match without using it.
+ Provide a suggestion using the first conversion char
+ listed for the given type. */
+ return xasprintf ("%s%c", len_modifier, spec->format_chars[0]);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* Generate a string containing the length modifier and conversion specifier
+ that should be used to format arguments of type ARG_TYPE within FKI
+ (effectively the inverse of the checking code).
+
+ If successful, returns a non-NULL string which should be freed
+ by the caller.
+ Otherwise, returns NULL. */
+
+static char *
+get_format_for_type (const format_kind_info *fki, tree arg_type,
+ char conversion_char)
+{
+ gcc_assert (arg_type);
+ gcc_assert (conversion_char);
+
+ /* First pass: look for a format_char_info containing CONVERSION_CHAR
+ If we find one, then presumably the length modifier was incorrect
+ (or absent). */
+ char *result = get_format_for_type_1 (fki, arg_type, conversion_char);
+ if (result)
+ return result;
+
+ /* Second pass: we didn't find a match for CONVERSION_CHAR, so try
+ matching just on the type. */
+ return get_format_for_type_1 (fki, arg_type, '\0');
+}
+
+/* Attempt to get a string for use as a replacement fix-it hint for the
+ source range in FMT_LOC.
+
+ Preserve all of the text within the range of FMT_LOC up to
+ OFFSET_TO_TYPE_START, replacing the rest with an appropriate
+ length modifier and conversion specifier for ARG_TYPE, attempting
+ to keep the user-provided CONVERSION_CHAR if possible.
+
+ For example, given a long vs long long mismatch for arg5 here:
+
+ 000000000111111111122222222223333333333|
+ 123456789012345678901234567890123456789` column numbers
+ 0000000000111111111122|
+ 0123456789012345678901` string offsets
+ V~~~~~~~~ : range of FMT_LOC, from cols 23-31
+ sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
+ ^ ^
+ | ` CONVERSION_CHAR: 'd'
+ type starts here
+
+ where OFFSET_TO_TYPE_START is 13 (the offset to the "lld" within the
+ STRING_CST), where the user provided:
+ %-+*.*lld
+ the result (assuming "long" argument 5) should be:
+ %-+*.*ld
+
+ If successful, returns a non-NULL string which should be freed
+ by the caller.
+ Otherwise, returns NULL. */
+
+static char *
+get_corrected_substring (const substring_loc &fmt_loc,
+ format_wanted_type *type, tree arg_type,
+ const format_kind_info *fki,
+ int offset_to_type_start, char conversion_char)
+{
+ /* Attempt to provide hints for argument types, but not for field widths
+ and precisions. */
+ if (!arg_type)
+ return NULL;
+ if (type->kind != CF_KIND_FORMAT)
+ return NULL;
+
+ /* Locate the current code within the source range, rejecting
+ any awkward cases where the format string occupies more than
+ one line.
+ Lookup the place where the type starts (including any length
+ modifiers), getting it as the caret location. */
+ substring_loc type_loc (fmt_loc);
+ type_loc.set_caret_index (offset_to_type_start);
+
+ location_t fmt_substring_loc;
+ const char *err = type_loc.get_location (&fmt_substring_loc);
+ if (err)
+ return NULL;
+
+ source_range fmt_substring_range
+ = get_range_from_loc (line_table, fmt_substring_loc);
+
+ expanded_location caret
+ = expand_location_to_spelling_point (fmt_substring_loc);
+ expanded_location start
+ = expand_location_to_spelling_point (fmt_substring_range.m_start);
+ expanded_location finish
+ = expand_location_to_spelling_point (fmt_substring_range.m_finish);
+ if (caret.file != start.file)
+ return NULL;
+ if (start.file != finish.file)
+ return NULL;
+ if (caret.line != start.line)
+ return NULL;
+ if (start.line != finish.line)
+ return NULL;
+ if (start.column > caret.column)
+ return NULL;
+ if (start.column > finish.column)
+ return NULL;
+ if (caret.column > finish.column)
+ return NULL;
+
+#if BUILDING_GCC_VERSION >= 9000
+ char_span line = location_get_source_line (start.file, start.line);
+ if (!line)
+ return NULL;
+
+ /* If we got this far, then we have the line containing the
+ existing conversion specification.
+
+ Generate a trimmed copy, containing the prefix part of the conversion
+ specification, up to the (but not including) the length modifier.
+ In the above example, this would be "%-+*.*". */
+ int length_up_to_type = caret.column - start.column;
+ char_span prefix_span = line.subspan (start.column - 1, length_up_to_type);
+ char *prefix = prefix_span.xstrdup ();
+#else
+ char *prefix = NULL;
+#endif
+
+ /* Now attempt to generate a suggestion for the rest of the specification
+ (length modifier and conversion char), based on ARG_TYPE and
+ CONVERSION_CHAR.
+ In the above example, this would be "ld". */
+ char *format_for_type = get_format_for_type (fki, arg_type, conversion_char);
+ if (!format_for_type)
+ {
+ free (prefix);
+ return NULL;
+ }
+
+ /* Success. Generate the resulting suggestion for the whole range of
+ FMT_LOC by concatenating the two strings.
+ In the above example, this would be "%-+*.*ld". */
+ char *result = concat (prefix, format_for_type, NULL);
+ free (format_for_type);
+ free (prefix);
+ return result;
+}
+
+/* Helper class for adding zero or more trailing '*' to types.
+
+ The format type and name exclude any '*' for pointers, so those
+ must be formatted manually. For all the types we currently have,
+ this is adequate, but formats taking pointers to functions or
+ arrays would require the full type to be built up in order to
+ print it with %T. */
+
+class indirection_suffix
+{
+ public:
+ indirection_suffix (int pointer_count) : m_pointer_count (pointer_count) {}
+
+ /* Determine the size of the buffer (including NUL-terminator). */
+
+ size_t get_buffer_size () const
+ {
+ return m_pointer_count + 2;
+ }
+
+ /* Write the '*' to DST and add a NUL-terminator. */
+
+ void fill_buffer (char *dst) const
+ {
+ if (m_pointer_count == 0)
+ dst[0] = 0;
+ else if (c_dialect_cxx ())
+ {
+ memset (dst, '*', m_pointer_count);
+ dst[m_pointer_count] = 0;
+ }
+ else
+ {
+ dst[0] = ' ';
+ memset (dst + 1, '*', m_pointer_count);
+ dst[m_pointer_count + 1] = 0;
+ }
+ }
+
+ private:
+ int m_pointer_count;
+};
+
+#if BUILDING_GCC_VERSION >= 9000
+/* not exported by GCC... need a local copy :( */
+class frr_range_label_for_type_mismatch : public range_label
+{
+ public:
+ frr_range_label_for_type_mismatch (tree labelled_type, tree other_type)
+ : m_labelled_type (labelled_type), m_other_type (other_type)
+ {
+ }
+
+ label_text get_text (unsigned range_idx) const OVERRIDE;
+
+ protected:
+ tree m_labelled_type;
+ tree m_other_type;
+};
+
+/* Print T to CPP. */
+
+static void
+print_type (c_pretty_printer *cpp, tree t, bool *quoted)
+{
+ gcc_assert (TYPE_P (t));
+ struct obstack *ob = pp_buffer (cpp)->obstack;
+ char *p = (char *) obstack_base (ob);
+ /* Remember the end of the initial dump. */
+ int len = obstack_object_size (ob);
+
+ tree name = TYPE_NAME (t);
+ if (name && TREE_CODE (name) == TYPE_DECL && DECL_NAME (name))
+ pp_identifier (cpp, lang_hooks.decl_printable_name (name, 2));
+ else
+ cpp->type_id (t);
+
+ /* If we're printing a type that involves typedefs, also print the
+ stripped version. But sometimes the stripped version looks
+ exactly the same, so we don't want it after all. To avoid
+ printing it in that case, we play ugly obstack games. */
+ if (TYPE_CANONICAL (t) && t != TYPE_CANONICAL (t))
+ {
+ c_pretty_printer cpp2;
+ /* Print the stripped version into a temporary printer. */
+ cpp2.type_id (TYPE_CANONICAL (t));
+ struct obstack *ob2 = cpp2.buffer->obstack;
+ /* Get the stripped version from the temporary printer. */
+ const char *aka = (char *) obstack_base (ob2);
+ int aka_len = obstack_object_size (ob2);
+ int type1_len = obstack_object_size (ob) - len;
+
+ /* If they are identical, bail out. */
+ if (aka_len == type1_len && memcmp (p + len, aka, aka_len) == 0)
+ return;
+
+ /* They're not, print the stripped version now. */
+ if (*quoted)
+ pp_end_quote (cpp, pp_show_color (cpp));
+ pp_c_whitespace (cpp);
+ pp_left_brace (cpp);
+ pp_c_ws_string (cpp, _("aka"));
+ pp_c_whitespace (cpp);
+ if (*quoted)
+ pp_begin_quote (cpp, pp_show_color (cpp));
+ cpp->type_id (TYPE_CANONICAL (t));
+ if (*quoted)
+ pp_end_quote (cpp, pp_show_color (cpp));
+ pp_right_brace (cpp);
+ /* No further closing quotes are needed. */
+ *quoted = false;
+ }
+}
+
+/* C-specific implementation of range_label::get_text () vfunc for
+ range_label_for_type_mismatch. */
+
+label_text
+frr_range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const
+{
+ if (m_labelled_type == NULL_TREE)
+ return label_text (NULL, false);
+
+ c_pretty_printer cpp;
+ bool quoted = false;
+ print_type (&cpp, m_labelled_type, &quoted);
+ return label_text (xstrdup (pp_formatted_text (&cpp)), true);
+}
+
+#define range_label_for_type_mismatch frr_range_label_for_type_mismatch
+#endif
+
+/* Subclass of range_label for labelling the range in the format string
+ with the type in question, adding trailing '*' for pointer_count. */
+
+class range_label_for_format_type_mismatch
+ : public range_label_for_type_mismatch
+{
+ public:
+ range_label_for_format_type_mismatch (tree labelled_type, tree other_type,
+ int pointer_count)
+ : range_label_for_type_mismatch (labelled_type, other_type),
+ m_pointer_count (pointer_count)
+ {
+ }
+
+ label_text get_text (unsigned range_idx) const FINAL OVERRIDE
+ {
+ label_text text = range_label_for_type_mismatch::get_text (range_idx);
+ if (text.m_buffer == NULL)
+ return text;
+
+ indirection_suffix suffix (m_pointer_count);
+ char *p = (char *) alloca (suffix.get_buffer_size ());
+ suffix.fill_buffer (p);
+
+ char *result = concat (text.m_buffer, p, NULL);
+ text.maybe_free ();
+ return label_text (result, true);
+ }
+
+ private:
+ int m_pointer_count;
+};
+
+/* Give a warning about a format argument of different type from that expected.
+ The range of the diagnostic is taken from WHOLE_FMT_LOC; the caret location
+ is based on the location of the char at TYPE->offset_loc.
+ PARAM_LOC is the location of the relevant argument, or UNKNOWN_LOCATION
+ if this is unavailable.
+ WANTED_TYPE is the type the argument should have,
+ possibly stripped of pointer dereferences. The description (such as "field
+ precision"), the placement in the format string, a possibly more
+ friendly name of WANTED_TYPE, and the number of pointer dereferences
+ are taken from TYPE. ARG_TYPE is the type of the actual argument,
+ or NULL if it is missing.
+
+ OFFSET_TO_TYPE_START is the offset within the execution-charset encoded
+ format string to where type information begins for the conversion
+ (the length modifier and conversion specifier).
+ CONVERSION_CHAR is the user-provided conversion specifier.
+
+ For example, given a type mismatch for argument 5 here:
+
+ 00000000011111111112222222222333333333344444444445555555555|
+ 12345678901234567890123456789012345678901234567890123456789` column numbers
+ 0000000000111111111122|
+ 0123456789012345678901` offsets within STRING_CST
+ V~~~~~~~~ : range of WHOLE_FMT_LOC, from cols 23-31
+ sprintf (d, "before %-+*.*lld after", int_expr, int_expr, long_expr);
+ ^ ^ ^~~~~~~~~
+ | ` CONVERSION_CHAR: 'd' PARAM_LOC
+ type starts here
+
+ OFFSET_TO_TYPE_START is 13, the offset to the "lld" within the
+ STRING_CST. */
+
+static void
+format_type_warning (const substring_loc &whole_fmt_loc,
+ location_t param_loc,
+ format_wanted_type *type,
+ tree wanted_type, tree arg_type,
+ const format_kind_info *fki,
+ int offset_to_type_start,
+ char conversion_char,
+ const char *extra)
+{
+ enum format_specifier_kind kind = type->kind;
+ const char *wanted_type_name = type->wanted_type_name;
+ const char *format_start = type->format_start;
+ int format_length = type->format_length;
+ int pointer_count = type->pointer_count;
+ int arg_num = type->arg_num;
+
+ if (!extra)
+ extra = "";
+
+ /* If ARG_TYPE is a typedef with a misleading name (for example,
+ size_t but not the standard size_t expected by printf %zu), avoid
+ printing the typedef name. */
+ if (wanted_type_name
+ && arg_type
+ && TYPE_NAME (arg_type)
+ && TREE_CODE (TYPE_NAME (arg_type)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (arg_type))
+ && !strcmp (wanted_type_name,
+ lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2)))
+ arg_type = TYPE_MAIN_VARIANT (arg_type);
+
+ indirection_suffix suffix (pointer_count);
+ char *p = (char *) alloca (suffix.get_buffer_size ());
+ suffix.fill_buffer (p);
+
+ /* WHOLE_FMT_LOC has the caret at the end of the range.
+ Set the caret to be at the offset from TYPE. Subtract one
+ from the offset for the same reason as in format_warning_at_char. */
+ substring_loc fmt_loc (whole_fmt_loc);
+ fmt_loc.set_caret_index (type->offset_loc - 1);
+
+#if BUILDING_GCC_VERSION >= 9000
+ range_label_for_format_type_mismatch fmt_label (wanted_type, arg_type,
+ pointer_count);
+ range_label_for_type_mismatch param_label (arg_type, wanted_type);
+
+ /* Get a string for use as a replacement fix-it hint for the range in
+ fmt_loc, or NULL. */
+ char *corrected_substring
+ = get_corrected_substring (fmt_loc, type, arg_type, fki,
+ offset_to_type_start, conversion_char);
+ format_string_diagnostic_t diag (fmt_loc, &fmt_label, param_loc, &param_label,
+ corrected_substring);
+# define format_warning_at_substring(a,b,c,d,e,...) \
+ diag.emit_warning(__VA_ARGS__)
+#else
+# define format_warning_at_substring(a,b,c,d,...) \
+ format_warning_at_substring(a,c,__VA_ARGS__)
+ /* Get a string for use as a replacement fix-it hint for the range in
+ fmt_loc, or NULL. */
+ char *corrected_substring
+ = get_corrected_substring (fmt_loc, type, arg_type, fki,
+ offset_to_type_start, conversion_char);
+
+#endif
+
+ if (wanted_type_name)
+ {
+ if (arg_type)
+ format_warning_at_substring
+ (fmt_loc, &fmt_label, param_loc, &param_label,
+ corrected_substring, OPT_Wformat_,
+ "%s %<%s%.*s%> expects argument of type %<%s%s%>, "
+ "but argument %d has type %qT%s",
+ gettext (kind_descriptions[kind]),
+ (kind == CF_KIND_FORMAT ? "%" : ""),
+ format_length, format_start,
+ wanted_type_name, p, arg_num, arg_type, extra);
+ else
+ format_warning_at_substring
+ (fmt_loc, &fmt_label, param_loc, &param_label,
+ corrected_substring, OPT_Wformat_,
+ "%s %<%s%.*s%> expects a matching %<%s%s%> argument%s",
+ gettext (kind_descriptions[kind]),
+ (kind == CF_KIND_FORMAT ? "%" : ""),
+ format_length, format_start, wanted_type_name, p, extra);
+ }
+ else
+ {
+ if (arg_type)
+ format_warning_at_substring
+ (fmt_loc, &fmt_label, param_loc, &param_label,
+ corrected_substring, OPT_Wformat_,
+ "%s %<%s%.*s%> expects argument of type %<%T%s%>, "
+ "but argument %d has type %qT%s",
+ gettext (kind_descriptions[kind]),
+ (kind == CF_KIND_FORMAT ? "%" : ""),
+ format_length, format_start,
+ wanted_type, p, arg_num, arg_type, extra);
+ else
+ format_warning_at_substring
+ (fmt_loc, &fmt_label, param_loc, &param_label,
+ corrected_substring, OPT_Wformat_,
+ "%s %<%s%.*s%> expects a matching %<%T%s%> argument%s",
+ gettext (kind_descriptions[kind]),
+ (kind == CF_KIND_FORMAT ? "%" : ""),
+ format_length, format_start, wanted_type, p, extra);
+ }
+
+ free (corrected_substring);
+}
+
+
+#if 0
+/* Given a format_char_info array FCI, and a character C, this function
+ returns the index into the conversion_specs where that specifier's
+ data is located. The character must exist. */
+static unsigned int
+find_char_info_specifier_index (const format_char_info *fci, int c)
+{
+ unsigned i;
+
+ for (i = 0; fci->format_chars; i++, fci++)
+ if (strchr (fci->format_chars, c))
+ return i;
+
+ /* We shouldn't be looking for a non-existent specifier. */
+ gcc_unreachable ();
+}
+
+/* Given a format_length_info array FLI, and a character C, this
+ function returns the index into the conversion_specs where that
+ modifier's data is located. The character must exist. */
+static unsigned int
+find_length_info_modifier_index (const format_length_info *fli, int c)
+{
+ unsigned i;
+
+ for (i = 0; fli->name; i++, fli++)
+ if (strchr (fli->name, c))
+ return i;
+
+ /* We shouldn't be looking for a non-existent modifier. */
+ gcc_unreachable ();
+}
+#endif
+
+#ifdef TARGET_FORMAT_TYPES
+extern const format_kind_info TARGET_FORMAT_TYPES[];
+#endif
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+#ifdef TARGET_OVERRIDES_FORMAT_INIT
+ extern void TARGET_OVERRIDES_FORMAT_INIT (void);
+#endif
+
+/* Attributes such as "printf" are equivalent to those such as
+ "gnu_printf" unless this is overridden by a target. */
+static const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+ { NULL, NULL }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+ decode_format_attr. In attr_name the user specified argument is passed. It
+ returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+ or the attr_name passed to this function, if there is no matching entry. */
+static const char *
+convert_format_name_to_system_name (const char *attr_name)
+{
+ int i;
+
+ if (attr_name == NULL || *attr_name == 0
+ || strncmp (attr_name, "gcc_", 4) == 0)
+ return attr_name;
+#ifdef TARGET_OVERRIDES_FORMAT_INIT
+ TARGET_OVERRIDES_FORMAT_INIT ();
+#endif
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+ /* Check if format attribute is overridden by target. */
+ if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+ && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+ {
+ for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+ {
+ if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+ attr_name))
+ return attr_name;
+ if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+ attr_name))
+ return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+ }
+ }
+#endif
+ /* Otherwise default to gnu format. */
+ for (i = 0;
+ gnu_target_overrides_format_attributes[i].named_attr_src != NULL;
+ ++i)
+ {
+ if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+ attr_name))
+ return attr_name;
+ if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+ attr_name))
+ return gnu_target_overrides_format_attributes[i].named_attr_src;
+ }
+
+ return attr_name;
+}
+
+/* Handle a "format" attribute; arguments as in
+ struct attribute_spec.handler. */
+tree
+handle_frr_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+ int flags, bool *no_add_attrs)
+{
+ tree type = *node;
+ function_format_info info;
+
+ /* Canonicalize name of format function. */
+ if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
+ TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args));
+
+ if (!decode_format_attr (args, &info, 0))
+ {
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ if (prototype_p (type))
+ {
+ if (!check_format_string (type, info.format_num, flags,
+ no_add_attrs, info.format_type))
+ return NULL_TREE;
+
+ if (info.first_arg_num != 0)
+ {
+ unsigned HOST_WIDE_INT arg_num = 1;
+ function_args_iterator iter;
+ tree arg_type;
+
+ /* Verify that first_arg_num points to the last arg,
+ the ... */
+ FOREACH_FUNCTION_ARGS (type, arg_type, iter)
+ arg_num++;
+
+ if (arg_num != info.first_arg_num)
+ {
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("args to be formatted is not %<...%>");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ }
+ }
+
+ /* Check if this is a strftime variant. Just for this variant
+ FMT_FLAG_ARG_CONVERT is not set. */
+ if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0
+ && info.first_arg_num != 0)
+ {
+ error ("strftime formats cannot format arguments");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ return NULL_TREE;
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests of location handling. */
+
+/* Get the format_kind_info with the given name. */
+
+static const format_kind_info *
+get_info (const char *name)
+{
+ int idx = decode_format_type (name);
+ const format_kind_info *fki = &format_types[idx];
+ ASSERT_STREQ (fki->name, name);
+ return fki;
+}
+
+/* Verify that get_format_for_type (FKI, TYPE, CONVERSION_CHAR)
+ is EXPECTED_FORMAT. */
+
+static void
+assert_format_for_type_streq (const location &loc, const format_kind_info *fki,
+ const char *expected_format, tree type,
+ char conversion_char)
+{
+ gcc_assert (fki);
+ gcc_assert (expected_format);
+ gcc_assert (type);
+
+ char *actual_format = get_format_for_type (fki, type, conversion_char);
+ ASSERT_STREQ_AT (loc, expected_format, actual_format);
+ free (actual_format);
+}
+
+/* Selftests for get_format_for_type. */
+
+#define ASSERT_FORMAT_FOR_TYPE_STREQ(EXPECTED_FORMAT, TYPE, CONVERSION_CHAR) \
+ assert_format_for_type_streq (SELFTEST_LOCATION, (fki), (EXPECTED_FORMAT), \
+ (TYPE), (CONVERSION_CHAR))
+
+/* Selftest for get_format_for_type for "printf"-style functions. */
+
+static void
+test_get_format_for_type_printf ()
+{
+ const format_kind_info *fki = get_info ("gnu_printf");
+ ASSERT_NE (fki, NULL);
+
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'X');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'X');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("d", integer_type_node, 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("i", integer_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("o", integer_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("x", integer_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("X", integer_type_node, 'X');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("d", unsigned_type_node, 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("i", unsigned_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("o", unsigned_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("x", unsigned_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("X", unsigned_type_node, 'X');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("ld", long_integer_type_node, 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("li", long_integer_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lx", long_integer_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lo", long_unsigned_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lx", long_unsigned_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lld", long_long_integer_type_node, 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lli", long_long_integer_type_node, 'i');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("llo", long_long_unsigned_type_node, 'o');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("llx", long_long_unsigned_type_node, 'x');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("s", build_pointer_type (char_type_node), 'i');
+}
+
+/* Selftest for get_format_for_type for "scanf"-style functions. */
+
+static void
+test_get_format_for_type_scanf ()
+{
+ const format_kind_info *fki = get_info ("gnu_scanf");
+ ASSERT_NE (fki, NULL);
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("d", build_pointer_type (integer_type_node), 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("u", build_pointer_type (unsigned_type_node), 'u');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("ld",
+ build_pointer_type (long_integer_type_node), 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("lu",
+ build_pointer_type (long_unsigned_type_node), 'u');
+ ASSERT_FORMAT_FOR_TYPE_STREQ
+ ("lld", build_pointer_type (long_long_integer_type_node), 'd');
+ ASSERT_FORMAT_FOR_TYPE_STREQ
+ ("llu", build_pointer_type (long_long_unsigned_type_node), 'u');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("e", build_pointer_type (float_type_node), 'e');
+ ASSERT_FORMAT_FOR_TYPE_STREQ ("le", build_pointer_type (double_type_node), 'e');
+}
+
+#undef ASSERT_FORMAT_FOR_TYPE_STREQ
+
+/* Exercise the type-printing label code, to give some coverage
+ under "make selftest-valgrind" (in particular, to ensure that
+ the label-printing machinery doesn't leak). */
+
+static void
+test_type_mismatch_range_labels ()
+{
+ /* Create a tempfile and write some text to it.
+ ....................0000000001 11111111 12 22222222
+ ....................1234567890 12345678 90 12345678. */
+ const char *content = " printf (\"msg: %i\\n\", msg);\n";
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
+ line_table_test ltt;
+
+ linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
+
+ location_t c17 = linemap_position_for_column (line_table, 17);
+ ASSERT_EQ (LOCATION_COLUMN (c17), 17);
+ location_t c18 = linemap_position_for_column (line_table, 18);
+ location_t c24 = linemap_position_for_column (line_table, 24);
+ location_t c26 = linemap_position_for_column (line_table, 26);
+
+ /* Don't attempt to run the tests if column data might be unavailable. */
+ if (c26 > LINE_MAP_MAX_LOCATION_WITH_COLS)
+ return;
+
+ location_t fmt = make_location (c18, c17, c18);
+ ASSERT_EQ (LOCATION_COLUMN (fmt), 18);
+
+ location_t param = make_location (c24, c24, c26);
+ ASSERT_EQ (LOCATION_COLUMN (param), 24);
+
+ range_label_for_format_type_mismatch fmt_label (char_type_node,
+ integer_type_node, 1);
+ range_label_for_type_mismatch param_label (integer_type_node,
+ char_type_node);
+ gcc_rich_location richloc (fmt, &fmt_label);
+ richloc.add_range (param, SHOW_RANGE_WITHOUT_CARET, &param_label);
+
+ test_diagnostic_context dc;
+ diagnostic_show_locus (&dc, &richloc, DK_ERROR);
+ if (c_dialect_cxx ())
+ /* "char*", without a space. */
+ ASSERT_STREQ ("\n"
+ " printf (\"msg: %i\\n\", msg);\n"
+ " ~^ ~~~\n"
+ " | |\n"
+ " char* int\n",
+ pp_formatted_text (dc.printer));
+ else
+ /* "char *", with a space. */
+ ASSERT_STREQ ("\n"
+ " printf (\"msg: %i\\n\", msg);\n"
+ " ~^ ~~~\n"
+ " | |\n"
+ " | int\n"
+ " char *\n",
+ pp_formatted_text (dc.printer));
+}
+
+/* Run all of the selftests within this file. */
+
+void
+c_format_c_tests ()
+{
+ test_get_modifier_for_format_len ();
+ test_get_format_for_type_printf ();
+ test_get_format_for_type_scanf ();
+ test_type_mismatch_range_labels ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
+// include "gt-c-family-c-format.h"
+
+static const struct attribute_spec frr_format_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+ affects_type_identity, handler, exclude } */
+ { "frr_format", 3, 3, false, true, true, false,
+ handle_frr_format_attribute, NULL },
+ { "frr_format_arg", 1, 1, false, true, true, false,
+ handle_frr_format_arg_attribute, NULL },
+ { NULL, 0, 0, false, false, false, false, NULL, NULL }
+};
+
+static void
+register_attributes (void *event_data, void *data)
+{
+ // warning (0, G_("Callback to register attributes"));
+ register_attribute (frr_format_attribute_table);
+}
+
+tree
+cb_walk_tree_fn (tree * tp, int * walk_subtrees, void * data ATTRIBUTE_UNUSED)
+{
+ if (TREE_CODE (*tp) != CALL_EXPR)
+ return NULL_TREE;
+
+ tree call_expr = *tp;
+
+ int nargs = call_expr_nargs(call_expr);
+ tree fn = CALL_EXPR_FN(call_expr);
+
+ if (!fn || TREE_CODE (fn) != ADDR_EXPR)
+ return NULL_TREE;
+
+ tree fndecl = TREE_OPERAND (fn, 0);
+ if (TREE_CODE (fndecl) != FUNCTION_DECL)
+ return NULL_TREE;
+
+#if 0
+ warning (0, G_("function call to %s, %d args"),
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)),
+ nargs);
+#endif
+
+ tree *fargs = (tree *) alloca (nargs * sizeof (tree));
+
+ for (int j = 0; j < nargs; j++)
+ {
+ tree arg = CALL_EXPR_ARG(call_expr, j);
+
+ /* For -Wformat undo the implicit passing by hidden reference
+ done by convert_arg_to_ellipsis. */
+ if (TREE_CODE (arg) == ADDR_EXPR
+ && TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
+ fargs[j] = TREE_OPERAND (arg, 0);
+ else
+ fargs[j] = arg;
+ }
+
+ check_function_format (TYPE_ATTRIBUTES (TREE_TYPE (fndecl)), nargs, fargs, NULL);
+ return NULL_TREE;
+}
+
+static void
+setup_type (const char *name, tree *dst)
+{
+ tree tmp;
+
+ if (*dst && *dst != void_type_node)
+ return;
+
+ *dst = maybe_get_identifier (name);
+ if (!*dst)
+ return;
+
+ tmp = identifier_global_value (*dst);
+ if (tmp && TREE_CODE (tmp) != TYPE_DECL)
+ {
+ warning (0, "%<%s%> is not defined as a type", name);
+ *dst = NULL;
+ return;
+ }
+ if (tmp && TREE_CODE (tmp) == TYPE_DECL)
+ *dst = tmp;
+ else
+ *dst = NULL;
+}
+
+static void
+handle_finish_parse (void *event_data, void *data)
+{
+ tree fndecl = (tree) event_data;
+ gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
+
+ setup_type ("uint64_t", &local_uint64_t_node);
+ setup_type ("int64_t", &local_int64_t_node);
+
+ setup_type ("size_t", &local_size_t_node);
+ setup_type ("ssize_t", &local_ssize_t_node);
+ setup_type ("atomic_size_t", &local_atomic_size_t_node);
+ setup_type ("atomic_ssize_t", &local_atomic_ssize_t_node);
+ setup_type ("ptrdiff_t", &local_ptrdiff_t_node);
+
+ setup_type ("pid_t", &local_pid_t_node);
+ setup_type ("uid_t", &local_uid_t_node);
+ setup_type ("gid_t", &local_gid_t_node);
+ setup_type ("time_t", &local_time_t_node);
+
+ setup_type ("socklen_t", &local_socklen_t_node);
+ setup_type ("in_addr_t", &local_in_addr_t_node);
+
+ const format_char_info *fci;
+
+ for (fci = print_char_table; fci->format_chars; fci++)
+ {
+ if (!fci->kernel_ext)
+ continue;
+
+ struct kernel_ext_fmt *etab = fci->kernel_ext;
+ struct kernel_ext_fmt *etab_end = etab + ETAB_SZ;
+
+ for (; etab->suffix && etab < etab_end; etab++)
+ {
+ tree identifier, node;
+
+ if (etab->type && etab->type != void_type_node)
+ continue;
+
+ identifier = maybe_get_identifier (etab->type_str);
+
+ if (!identifier || identifier == error_mark_node)
+ continue;
+
+ if (etab->type_code)
+ {
+ node = identifier_global_tag (identifier);
+ if (!node)
+ continue;
+
+ if (node->base.code != etab->type_code)
+ {
+ if (!etab->warned)
+ {
+ warning (0, "%qs tag category (struct/union/enum) mismatch", etab->type_str);
+ etab->warned = true;
+ }
+ continue;
+ }
+ }
+ else
+ {
+ node = identifier_global_value (identifier);
+ if (!node)
+ continue;
+
+ if (TREE_CODE (node) != TYPE_DECL)
+ {
+ if (!etab->warned)
+ {
+ warning (0, "%qs is defined as a non-type", etab->type_str);
+ etab->warned = true;
+ }
+ continue;
+ }
+ node = TREE_TYPE (node);
+ }
+
+ etab->type = node;
+ }
+ }
+
+ walk_tree (&DECL_SAVED_TREE (fndecl), cb_walk_tree_fn, NULL, NULL);
+}
+
+static void
+handle_pragma_printfrr_ext (cpp_reader *dummy)
+{
+ tree token = 0;
+ location_t loc;
+ enum cpp_ttype ttype;
+
+ ttype = pragma_lex (&token, &loc);
+ if (ttype != CPP_STRING)
+ {
+ error_at (loc, "%<#pragma FRR printfrr_ext%> requires string argument");
+ return;
+ }
+
+ const char *s = TREE_STRING_POINTER (token);
+
+ if (s[0] != '%')
+ {
+ error_at (loc, "%<#pragma FRR printfrr_ext%>: invalid format string, needs to start with '%%'");
+ return;
+ }
+
+ switch (s[1])
+ {
+ case 'p':
+ case 'd':
+ case 'i':
+ break;
+ default:
+ error_at (loc, "%<#pragma FRR printfrr_ext%>: invalid format string, needs to be %%p, %%d or %%i");
+ return;
+ }
+
+ const format_char_info *fci;
+
+ for (fci = print_char_table; fci->format_chars; fci++)
+ if (strchr (fci->format_chars, s[1]))
+ break;
+
+ gcc_assert (fci->format_chars);
+ gcc_assert (fci->kernel_ext);
+
+ struct kernel_ext_fmt *etab = fci->kernel_ext;
+ struct kernel_ext_fmt *etab_end = etab + ETAB_SZ;
+
+ switch (s[2])
+ {
+ case 'A' ... 'Z':
+ break;
+
+ default:
+ error_at (loc, "%<#pragma FRR printfrr_ext%>: invalid format string, suffix must start with an uppercase letter");
+ return;
+ }
+
+ /* -2 -- need to keep the sentinel at the end */
+ if (etab[ETAB_SZ - 2].suffix)
+ {
+ error_at (loc, "%<#pragma FRR printfrr_ext%>: out of space for format suffixes");
+ return;
+ }
+
+ for (; etab->suffix && etab < etab_end; etab++)
+ {
+ if (!strcmp(s + 2, etab->suffix))
+ {
+ memmove (etab + 1, etab, (etab_end - etab - 1) * sizeof (*etab));
+
+ if (0)
+ {
+ warning_at (loc, OPT_Wformat_,
+ "%<#pragma FRR printfrr_ext%>: duplicate printf format suffix \"%s\"", s);
+ warning_at (etab->origin_loc, OPT_Wformat_,
+ "%<#pragma FRR printfrr_ext%>: previous definition was here");
+ return;
+ }
+
+ break;
+ }
+
+ if (!strncmp(s + 2, etab->suffix, MIN(strlen(s + 2), strlen(etab->suffix))))
+ {
+ warning_at (loc, OPT_Wformat_,
+ "%<#pragma FRR printfrr_ext%>: overlapping printf format suffix \"%s\"", s);
+ warning_at (etab->origin_loc, OPT_Wformat_,
+ "%<#pragma FRR printfrr_ext%>: previous definition for \"%%%c%s\" was here", s[1], etab->suffix);
+ return;
+ }
+ }
+
+ gcc_assert (etab < etab_end);
+
+ memset (etab, 0, sizeof (*etab));
+ etab->suffix = xstrdup(s + 2);
+ etab->origin_loc = loc;
+ etab->type = void_type_node;
+
+ ttype = pragma_lex (&token, &loc);
+ if (ttype != CPP_OPEN_PAREN)
+ {
+ error_at (loc, "%<#pragma FRR printfrr_ext%> expected %<(%>");
+ goto out_drop;
+ }
+
+ ttype = pragma_lex (&token, &loc);
+
+ /* qualifiers */
+ if (ttype == CPP_NAME && !strcmp (IDENTIFIER_POINTER (token), "const"))
+ {
+ etab->t_const = true;
+ ttype = pragma_lex (&token, &loc);
+ }
+
+ /* tagged types */
+ if (ttype == CPP_NAME && !strcmp (IDENTIFIER_POINTER (token), "struct"))
+ {
+ etab->type_code = RECORD_TYPE;
+ ttype = pragma_lex (&token, &loc);
+ }
+ else if (ttype == CPP_NAME && !strcmp (IDENTIFIER_POINTER (token), "union"))
+ {
+ etab->type_code = UNION_TYPE;
+ ttype = pragma_lex (&token, &loc);
+ }
+ else if (ttype == CPP_NAME && !strcmp (IDENTIFIER_POINTER (token), "enum"))
+ {
+ etab->type_code = ENUMERAL_TYPE;
+ ttype = pragma_lex (&token, &loc);
+ }
+
+ /* type name */
+ if (ttype != CPP_NAME)
+ {
+ error_at (loc, "%<#pragma FRR printfrr_ext%>: expected typename identifier");
+ goto out_drop;
+ }
+
+ etab->type_str = xstrdup (IDENTIFIER_POINTER (token));
+
+ while ((ttype = pragma_lex (&token, &loc)) != CPP_CLOSE_PAREN)
+ {
+ switch (ttype) {
+ case CPP_NAME:
+ error_at (loc, "%<#pragma FRR printfrr_ext%>: unexpected identifier. Note the only supported qualifier is \"const\".");
+ goto out_drop;
+
+ case CPP_MULT:
+ etab->ptrlevel++;
+ break;
+
+ case CPP_EOF:
+ error_at (loc, "%<#pragma FRR printfrr_ext%>: premature end of line, missing %<)%>");
+ goto out_drop;
+
+ default:
+ error_at (loc, "%<#pragma FRR printfrr_ext%>: unsupported token");
+ goto out_drop;
+ }
+ }
+
+ ttype = pragma_lex (&token, &loc);
+ if (ttype != CPP_EOF)
+ warning_at (loc, OPT_Wformat_,
+ "%<#pragma FRR printfrr_ext%>: garbage at end of line");
+
+ return;
+
+out_drop:
+ memset (etab, 0, sizeof (*etab));
+}
+
+static void
+register_pragma_printfrr_ext (void *event_data, void *data)
+{
+ c_register_pragma_with_expansion ("FRR", "printfrr_ext", handle_pragma_printfrr_ext);
+}
+
+static void
+define_vars (void *gcc_data, void *user_data)
+{
+ cpp_define (parse_in, "_FRR_ATTRIBUTE_PRINTFRR=0x10000");
+}
+
+#ifndef __visible
+#define __visible __attribute__((visibility("default")))
+#endif
+
+__visible int plugin_is_GPL_compatible;
+
+__visible int
+plugin_init (struct plugin_name_args *plugin_info,
+ struct plugin_gcc_version *version)
+{
+ const char *plugin_name = plugin_info->base_name;
+
+ if (!plugin_default_version_check(version, &gcc_version))
+ {
+ error(G_("incompatible gcc/plugin versions"));
+ return 1;
+ }
+
+ memset (ext_p, 0, sizeof (ext_p));
+ memset (ext_d, 0, sizeof (ext_d));
+
+ register_callback (plugin_name, PLUGIN_FINISH_PARSE_FUNCTION, handle_finish_parse, NULL);
+ register_callback (plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL);
+ register_callback (plugin_name, PLUGIN_START_UNIT, define_vars, NULL);
+ register_callback (plugin_name, PLUGIN_PRAGMAS, register_pragma_printfrr_ext, NULL);
+ return 0;
+}
diff --git a/tools/gcc-plugins/frr-format.h b/tools/gcc-plugins/frr-format.h
new file mode 100644
index 0000000000..87d2049ed4
--- /dev/null
+++ b/tools/gcc-plugins/frr-format.h
@@ -0,0 +1,364 @@
+/* Check calls to formatted I/O functions (-Wformat).
+ Copyright (C) 1992-2018 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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 3, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_C_FORMAT_H
+#define GCC_C_FORMAT_H
+
+/* The meaningfully distinct length modifiers for format checking recognized
+ by GCC. */
+enum format_lengths
+{
+ FMT_LEN_none,
+ FMT_LEN_hh,
+ FMT_LEN_h,
+ FMT_LEN_l,
+ FMT_LEN_ll,
+ FMT_LEN_L,
+ FMT_LEN_z,
+ FMT_LEN_t,
+ FMT_LEN_j,
+ FMT_LEN_H,
+ FMT_LEN_D,
+ FMT_LEN_DD,
+ FMT_LEN_MAX
+};
+
+
+/* The standard versions in which various format features appeared. */
+enum format_std_version
+{
+ STD_C89,
+ STD_C94,
+ STD_C9L, /* C99, but treat as C89 if -Wno-long-long. */
+ STD_C99,
+ STD_EXT
+};
+
+/* Flags that may apply to a particular kind of format checked by GCC. */
+enum
+{
+ /* This format converts arguments of types determined by the
+ format string. */
+ FMT_FLAG_ARG_CONVERT = 1,
+ /* The scanf allocation 'a' kludge applies to this format kind. */
+ FMT_FLAG_SCANF_A_KLUDGE = 2,
+ /* A % during parsing a specifier is allowed to be a modified % rather
+ that indicating the format is broken and we are out-of-sync. */
+ FMT_FLAG_FANCY_PERCENT_OK = 4,
+ /* With $ operand numbers, it is OK to reference the same argument more
+ than once. */
+ FMT_FLAG_DOLLAR_MULTIPLE = 8,
+ /* This format type uses $ operand numbers (strfmon doesn't). */
+ FMT_FLAG_USE_DOLLAR = 16,
+ /* Zero width is bad in this type of format (scanf). */
+ FMT_FLAG_ZERO_WIDTH_BAD = 32,
+ /* Empty precision specification is OK in this type of format (printf). */
+ FMT_FLAG_EMPTY_PREC_OK = 64,
+ /* Gaps are allowed in the arguments with $ operand numbers if all
+ arguments are pointers (scanf). */
+ FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128,
+ /* The format arg is an opaque object that will be parsed by an external
+ facility. */
+ FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL = 256
+ /* Not included here: details of whether width or precision may occur
+ (controlled by width_char and precision_char); details of whether
+ '*' can be used for these (width_type and precision_type); details
+ of whether length modifiers can occur (length_char_specs). */
+};
+
+/* Structure describing a length modifier supported in format checking, and
+ possibly a doubled version such as "hh". */
+struct format_length_info
+{
+ /* Name of the single-character length modifier. If prefixed by
+ a zero character, it describes a multi character length
+ modifier, like I64, I32, etc. */
+ const char *name;
+ /* Index into a format_char_info.types array. */
+ enum format_lengths index;
+ /* Standard version this length appears in. */
+ enum format_std_version std;
+ /* Same, if the modifier can be repeated, or NULL if it can't. */
+ const char *double_name;
+ enum format_lengths double_index;
+ enum format_std_version double_std;
+
+ /* If this flag is set, just scalar width identity is checked, and
+ not the type identity itself. */
+ int scalar_identity_flag;
+};
+
+
+struct kernel_ext_fmt
+{
+ const char *suffix;
+
+ /* RECORD_TYPE, UNION_TYPE, ENUMERAL_TYPE, or NULL for typedef */
+ tree_code type_code;
+ int ptrlevel;
+ bool t_const;
+ bool warned;
+
+ const char *type_str;
+ GTY(()) tree type;
+
+ location_t origin_loc;
+};
+
+
+/* Structure describing the combination of a conversion specifier
+ (or a set of specifiers which act identically) and a length modifier. */
+struct format_type_detail
+{
+ /* The standard version this combination of length and type appeared in.
+ This is only relevant if greater than those for length and type
+ individually; otherwise it is ignored. */
+ enum format_std_version std;
+ /* The name to use for the type, if different from that generated internally
+ (e.g., "signed size_t"). */
+ const char *name;
+ /* The type itself. */
+ tree *type;
+};
+
+
+/* Macros to fill out tables of these. */
+#define NOARGUMENTS { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }
+#define BADLEN { STD_C89, NULL, NULL }
+#define NOLENGTHS { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }
+
+
+/* Structure describing a format conversion specifier (or a set of specifiers
+ which act identically), and the length modifiers used with it. */
+struct format_char_info
+{
+ const char *format_chars;
+ int pointer_count;
+ enum format_std_version std;
+ /* Types accepted for each length modifier. */
+ format_type_detail types[FMT_LEN_MAX];
+ /* List of other modifier characters allowed with these specifiers.
+ This lists flags, and additionally "w" for width, "p" for precision
+ (right precision, for strfmon), "#" for left precision (strfmon),
+ "a" for scanf "a" allocation extension (not applicable in C99 mode),
+ "*" for scanf suppression, and "E" and "O" for those strftime
+ modifiers. */
+ const char *flag_chars;
+ /* List of additional flags describing these conversion specifiers.
+ "c" for generic character pointers being allowed, "2" for strftime
+ two digit year formats, "3" for strftime formats giving two digit
+ years in some locales, "4" for "2" which becomes "3" with an "E" modifier,
+ "o" if use of strftime "O" is a GNU extension beyond C99,
+ "W" if the argument is a pointer which is dereferenced and written into,
+ "R" if the argument is a pointer which is dereferenced and read from,
+ "i" for printf integer formats where the '0' flag is ignored with
+ precision, and "[" for the starting character of a scanf scanset,
+ "<" if the specifier introduces a quoted sequence (such as "%<"),
+ ">" if the specifier terminates a quoted sequence (such as "%>"),
+ "[" if the specifier introduces a color sequence (such as "%r"),
+ "]" if the specifier terminates a color sequence (such as "%R"),
+ "'" (single quote) if the specifier is expected to be quoted when
+ it appears outside a quoted sequence and unquoted otherwise (such
+ as the GCC internal printf format directive "%T"), and
+ "\"" (double quote) if the specifier is not expected to appear in
+ a quoted sequence (such as the GCC internal format directive "%K". */
+ const char *flags2;
+ /* If this format conversion character consumes more than one argument,
+ CHAIN points to information about the next argument. For later
+ arguments, only POINTER_COUNT, TYPES, and the "c", "R", and "W" flags
+ in FLAGS2 are used. */
+ const struct format_char_info *chain;
+
+ struct kernel_ext_fmt *kernel_ext;
+};
+
+
+/* Structure describing a flag accepted by some kind of format. */
+struct format_flag_spec
+{
+ /* The flag character in question (0 for end of array). */
+ int flag_char;
+ /* Zero if this entry describes the flag character in general, or a
+ nonzero character that may be found in flags2 if it describes the
+ flag when used with certain formats only. If the latter, only
+ the first such entry found that applies to the current conversion
+ specifier is used; the values of 'name' and 'long_name' it supplies
+ will be used, if non-NULL and the standard version is higher than
+ the unpredicated one, for any pedantic warning. For example, 'o'
+ for strftime formats (meaning 'O' is an extension over C99). */
+ int predicate;
+ /* Nonzero if the next character after this flag in the format should
+ be skipped ('=' in strfmon), zero otherwise. */
+ int skip_next_char;
+ /* True if the flag introduces quoting (as in GCC's %qE). */
+ bool quoting;
+ /* The name to use for this flag in diagnostic messages. For example,
+ N_("'0' flag"), N_("field width"). */
+ const char *name;
+ /* Long name for this flag in diagnostic messages; currently only used for
+ "ISO C does not support ...". For example, N_("the 'I' printf flag"). */
+ const char *long_name;
+ /* The standard version in which it appeared. */
+ enum format_std_version std;
+};
+
+
+/* Structure describing a combination of flags that is bad for some kind
+ of format. */
+struct format_flag_pair
+{
+ /* The first flag character in question (0 for end of array). */
+ int flag_char1;
+ /* The second flag character. */
+ int flag_char2;
+ /* Nonzero if the message should say that the first flag is ignored with
+ the second, zero if the combination should simply be objected to. */
+ int ignored;
+ /* Zero if this entry applies whenever this flag combination occurs,
+ a nonzero character from flags2 if it only applies in some
+ circumstances (e.g. 'i' for printf formats ignoring 0 with precision). */
+ int predicate;
+};
+
+
+/* Structure describing a particular kind of format processed by GCC. */
+struct format_kind_info
+{
+ /* The name of this kind of format, for use in diagnostics. Also
+ the name of the attribute (without preceding and following __). */
+ const char *name;
+ /* Specifications of the length modifiers accepted; possibly NULL. */
+ const format_length_info *length_char_specs;
+ /* Details of the conversion specification characters accepted. */
+ const format_char_info *conversion_specs;
+ /* String listing the flag characters that are accepted. */
+ const char *flag_chars;
+ /* String listing modifier characters (strftime) accepted. May be NULL. */
+ const char *modifier_chars;
+ /* Details of the flag characters, including pseudo-flags. */
+ const format_flag_spec *flag_specs;
+ /* Details of bad combinations of flags. */
+ const format_flag_pair *bad_flag_pairs;
+ /* Flags applicable to this kind of format. */
+ int flags;
+ /* Flag character to treat a width as, or 0 if width not used. */
+ int width_char;
+ /* Flag character to treat a left precision (strfmon) as,
+ or 0 if left precision not used. */
+ int left_precision_char;
+ /* Flag character to treat a precision (for strfmon, right precision) as,
+ or 0 if precision not used. */
+ int precision_char;
+ /* If a flag character has the effect of suppressing the conversion of
+ an argument ('*' in scanf), that flag character, otherwise 0. */
+ int suppression_char;
+ /* Flag character to treat a length modifier as (ignored if length
+ modifiers not used). Need not be placed in flag_chars for conversion
+ specifiers, but is used to check for bad combinations such as length
+ modifier with assignment suppression in scanf. */
+ int length_code_char;
+ /* Assignment-allocation flag character ('m' in scanf), otherwise 0. */
+ int alloc_char;
+ /* Pointer to type of argument expected if '*' is used for a width,
+ or NULL if '*' not used for widths. */
+ tree *width_type;
+ /* Pointer to type of argument expected if '*' is used for a precision,
+ or NULL if '*' not used for precisions. */
+ tree *precision_type;
+};
+
+#define T_I &integer_type_node
+#define T89_I { STD_C89, NULL, T_I }
+#define T_L &long_integer_type_node
+#define T89_L { STD_C89, NULL, T_L }
+#define T_LL &long_long_integer_type_node
+#define T9L_LL { STD_C9L, NULL, T_LL }
+#define TEX_LL { STD_EXT, NULL, T_LL }
+#define T_U64 &local_uint64_t_node
+#define TEX_U64 { STD_EXT, "uint64_t", T_U64 }
+#define T_S64 &local_int64_t_node
+#define TEX_S64 { STD_EXT, "int64_t", T_S64 }
+#define T_S &short_integer_type_node
+#define T89_S { STD_C89, NULL, T_S }
+#define T_UI &unsigned_type_node
+#define T89_UI { STD_C89, NULL, T_UI }
+#define T_UL &long_unsigned_type_node
+#define T89_UL { STD_C89, NULL, T_UL }
+#define T_ULL &long_long_unsigned_type_node
+#define T9L_ULL { STD_C9L, NULL, T_ULL }
+#define TEX_ULL { STD_EXT, NULL, T_ULL }
+#define T_US &short_unsigned_type_node
+#define T89_US { STD_C89, NULL, T_US }
+#define T_F &float_type_node
+#define T89_F { STD_C89, NULL, T_F }
+#define T99_F { STD_C99, NULL, T_F }
+#define T_D &double_type_node
+#define T89_D { STD_C89, NULL, T_D }
+#define T99_D { STD_C99, NULL, T_D }
+#define T_LD &long_double_type_node
+#define T89_LD { STD_C89, NULL, T_LD }
+#define T99_LD { STD_C99, NULL, T_LD }
+#define T_C &char_type_node
+#define T89_C { STD_C89, NULL, T_C }
+#define T_SC &signed_char_type_node
+#define T99_SC { STD_C99, NULL, T_SC }
+#define T_UC &unsigned_char_type_node
+#define T99_UC { STD_C99, NULL, T_UC }
+#define T_V &void_type_node
+#define T89_G { STD_C89, NULL, &local_gimple_ptr_node }
+#define T89_T { STD_C89, NULL, &local_tree_type_node }
+#define T89_V { STD_C89, NULL, T_V }
+#define T_W &wchar_type_node
+#define T94_W { STD_C94, "wchar_t", T_W }
+#define TEX_W { STD_EXT, "wchar_t", T_W }
+#define T_WI &wint_type_node
+#define T94_WI { STD_C94, "wint_t", T_WI }
+#define TEX_WI { STD_EXT, "wint_t", T_WI }
+#define T_ST &local_size_t_node
+#define T99_ST { STD_C99, "size_t", T_ST }
+#define T_SST &local_ssize_t_node
+#define T99_SST { STD_C99, "ssize_t", T_SST }
+#define T_PD &ptrdiff_type_node
+#define T99_PD { STD_C99, "ptrdiff_t", T_PD }
+#define T_UPD &unsigned_ptrdiff_type_node
+#define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD }
+#define T_IM &intmax_type_node
+#define T99_IM { STD_C99, "intmax_t", T_IM }
+#define T_UIM &uintmax_type_node
+#define T99_UIM { STD_C99, "uintmax_t", T_UIM }
+#define T_D32 &dfloat32_type_node
+#define TEX_D32 { STD_EXT, "_Decimal32", T_D32 }
+#define T_D64 &dfloat64_type_node
+#define TEX_D64 { STD_EXT, "_Decimal64", T_D64 }
+#define T_D128 &dfloat128_type_node
+#define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
+
+/* Structure describing how format attributes such as "printf" are
+ interpreted as "gnu_printf" or "ms_printf" on a particular system.
+ TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
+ defaults. */
+struct target_ovr_attr
+{
+ /* The name of the to be copied format attribute. */
+ const char *named_attr_src;
+ /* The name of the to be overridden format attribute. */
+ const char *named_attr_dst;
+};
+
+#endif /* GCC_C_FORMAT_H */
diff --git a/tools/gcc-plugins/gcc-common.h b/tools/gcc-plugins/gcc-common.h
new file mode 100644
index 0000000000..6b6c17231a
--- /dev/null
+++ b/tools/gcc-plugins/gcc-common.h
@@ -0,0 +1,981 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* FRR: imported from Linux kernel on 2019-07-29 */
+
+#ifndef GCC_COMMON_H_INCLUDED
+#define GCC_COMMON_H_INCLUDED
+
+#include "bversion.h"
+#if BUILDING_GCC_VERSION >= 6000
+#include "gcc-plugin.h"
+#else
+#include "plugin.h"
+#endif
+#include "plugin-version.h"
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "line-map.h"
+#include "input.h"
+#include "tree.h"
+
+#include "tree-inline.h"
+#include "version.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "flags.h"
+#include "hard-reg-set.h"
+#include "output.h"
+#include "except.h"
+#include "function.h"
+#include "toplev.h"
+#if BUILDING_GCC_VERSION >= 5000
+#include "expr.h"
+#endif
+#include "basic-block.h"
+#include "intl.h"
+#include "ggc.h"
+#include "timevar.h"
+
+#include "params.h"
+
+#if BUILDING_GCC_VERSION <= 4009
+#include "pointer-set.h"
+#else
+#include "hash-map.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 7000
+#include "memmodel.h"
+#endif
+#include "emit-rtl.h"
+#include "debug.h"
+#include "target.h"
+#include "langhooks.h"
+#include "cfgloop.h"
+#include "cgraph.h"
+#include "opts.h"
+
+#if BUILDING_GCC_VERSION == 4005
+#include <sys/mman.h>
+#endif
+
+#if BUILDING_GCC_VERSION >= 4007
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 4006
+/*
+ * The c-family headers were moved into a subdirectory in GCC version
+ * 4.7, but most plugin-building users of GCC 4.6 are using the Debian
+ * or Ubuntu package, which has an out-of-tree patch to move this to the
+ * same location as found in 4.7 and later:
+ * https://sources.debian.net/src/gcc-4.6/4.6.3-14/debian/patches/pr45078.diff/
+ */
+#include "c-family/c-common.h"
+#else
+#include "c-common.h"
+#endif
+
+#if BUILDING_GCC_VERSION <= 4008
+#include "tree-flow.h"
+#else
+#include "tree-cfgcleanup.h"
+#include "tree-ssa-operands.h"
+#include "tree-into-ssa.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 4008
+#include "is-a.h"
+#endif
+
+#include "diagnostic.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+#if BUILDING_GCC_VERSION >= 4009
+#include "pass_manager.h"
+#endif
+#include "predict.h"
+#include "ipa-utils.h"
+
+#if BUILDING_GCC_VERSION >= 8000
+#include "stringpool.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+#include "attribs.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "gimple-fold.h"
+#include "context.h"
+#include "tree-ssa-alias.h"
+#include "tree-ssa.h"
+#include "stringpool.h"
+#if BUILDING_GCC_VERSION >= 7000
+#include "tree-vrp.h"
+#endif
+#include "tree-ssanames.h"
+#include "print-tree.h"
+#include "tree-eh.h"
+#include "stmt.h"
+#include "gimplify.h"
+#endif
+
+#include "gimple.h"
+
+#if BUILDING_GCC_VERSION >= 4009
+#include "tree-ssa-operands.h"
+#include "tree-phinodes.h"
+#include "tree-cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "ssa-iterators.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 5000
+#include "builtins.h"
+#endif
+
+/* missing from basic_block.h... */
+void debug_dominance_info(enum cdi_direction dir);
+void debug_dominance_tree(enum cdi_direction dir, basic_block root);
+
+#if BUILDING_GCC_VERSION == 4006
+void debug_gimple_stmt(gimple);
+void debug_gimple_seq(gimple_seq);
+void print_gimple_seq(FILE *, gimple_seq, int, int);
+void print_gimple_stmt(FILE *, gimple, int, int);
+void print_gimple_expr(FILE *, gimple, int, int);
+void dump_gimple_stmt(pretty_printer *, gimple, int, int);
+#endif
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+#ifndef __visible
+#define __visible __attribute__((visibility("default")))
+#endif
+
+#define DECL_NAME_POINTER(node) IDENTIFIER_POINTER(DECL_NAME(node))
+#define DECL_NAME_LENGTH(node) IDENTIFIER_LENGTH(DECL_NAME(node))
+#define TYPE_NAME_POINTER(node) IDENTIFIER_POINTER(TYPE_NAME(node))
+#define TYPE_NAME_LENGTH(node) IDENTIFIER_LENGTH(TYPE_NAME(node))
+
+#if BUILDING_GCC_VERSION < 9000
+/* should come from c-tree.h if only it were installed for gcc 4.5... */
+#define C_TYPE_FIELDS_READONLY(TYPE) TREE_LANG_FLAG_1(TYPE)
+#endif
+
+static inline tree build_const_char_string(int len, const char *str)
+{
+ tree cstr, elem, index, type;
+
+ cstr = build_string(len, str);
+ elem = build_type_variant(char_type_node, 1, 0);
+ index = build_index_type(size_int(len - 1));
+ type = build_array_type(elem, index);
+ TREE_TYPE(cstr) = type;
+ TREE_CONSTANT(cstr) = 1;
+ TREE_READONLY(cstr) = 1;
+ TREE_STATIC(cstr) = 1;
+ return cstr;
+}
+
+#define PASS_INFO(NAME, REF, ID, POS) \
+struct register_pass_info NAME##_pass_info = { \
+ .pass = make_##NAME##_pass(), \
+ .reference_pass_name = REF, \
+ .ref_pass_instance_number = ID, \
+ .pos_op = POS, \
+}
+
+#if BUILDING_GCC_VERSION == 4005
+#define FOR_EACH_LOCAL_DECL(FUN, I, D) \
+ for (tree vars = (FUN)->local_decls, (I) = 0; \
+ vars && ((D) = TREE_VALUE(vars)); \
+ vars = TREE_CHAIN(vars), (I)++)
+#define DECL_CHAIN(NODE) (TREE_CHAIN(DECL_MINIMAL_CHECK(NODE)))
+#define FOR_EACH_VEC_ELT(T, V, I, P) \
+ for (I = 0; VEC_iterate(T, (V), (I), (P)); ++(I))
+#define TODO_rebuild_cgraph_edges 0
+#define SCOPE_FILE_SCOPE_P(EXP) (!(EXP))
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+typedef struct varpool_node *varpool_node_ptr;
+
+static inline bool gimple_call_builtin_p(gimple stmt, enum built_in_function code)
+{
+ tree fndecl;
+
+ if (!is_gimple_call(stmt))
+ return false;
+ fndecl = gimple_call_fndecl(stmt);
+ if (!fndecl || DECL_BUILT_IN_CLASS(fndecl) != BUILT_IN_NORMAL)
+ return false;
+ return DECL_FUNCTION_CODE(fndecl) == code;
+}
+
+static inline bool is_simple_builtin(tree decl)
+{
+ if (decl && DECL_BUILT_IN_CLASS(decl) != BUILT_IN_NORMAL)
+ return false;
+
+ switch (DECL_FUNCTION_CODE(decl)) {
+ /* Builtins that expand to constants. */
+ case BUILT_IN_CONSTANT_P:
+ case BUILT_IN_EXPECT:
+ case BUILT_IN_OBJECT_SIZE:
+ case BUILT_IN_UNREACHABLE:
+ /* Simple register moves or loads from stack. */
+ case BUILT_IN_RETURN_ADDRESS:
+ case BUILT_IN_EXTRACT_RETURN_ADDR:
+ case BUILT_IN_FROB_RETURN_ADDR:
+ case BUILT_IN_RETURN:
+ case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
+ case BUILT_IN_FRAME_ADDRESS:
+ case BUILT_IN_VA_END:
+ case BUILT_IN_STACK_SAVE:
+ case BUILT_IN_STACK_RESTORE:
+ /* Exception state returns or moves registers around. */
+ case BUILT_IN_EH_FILTER:
+ case BUILT_IN_EH_POINTER:
+ case BUILT_IN_EH_COPY_VALUES:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static inline void add_local_decl(struct function *fun, tree d)
+{
+ gcc_assert(TREE_CODE(d) == VAR_DECL);
+ fun->local_decls = tree_cons(NULL_TREE, d, fun->local_decls);
+}
+#endif
+
+#if BUILDING_GCC_VERSION <= 4006
+#define ANY_RETURN_P(rtx) (GET_CODE(rtx) == RETURN)
+#define C_DECL_REGISTER(EXP) DECL_LANG_FLAG_4(EXP)
+#define EDGE_PRESERVE 0ULL
+#define HOST_WIDE_INT_PRINT_HEX_PURE "%" HOST_WIDE_INT_PRINT "x"
+#define flag_fat_lto_objects true
+
+#define get_random_seed(noinit) ({ \
+ unsigned HOST_WIDE_INT seed; \
+ sscanf(get_random_seed(noinit), "%" HOST_WIDE_INT_PRINT "x", &seed); \
+ seed * seed; })
+
+#define int_const_binop(code, arg1, arg2) \
+ int_const_binop((code), (arg1), (arg2), 0)
+
+static inline bool gimple_clobber_p(gimple s __unused)
+{
+ return false;
+}
+
+static inline bool gimple_asm_clobbers_memory_p(const_gimple stmt)
+{
+ unsigned i;
+
+ for (i = 0; i < gimple_asm_nclobbers(stmt); i++) {
+ tree op = gimple_asm_clobber_op(stmt, i);
+
+ if (!strcmp(TREE_STRING_POINTER(TREE_VALUE(op)), "memory"))
+ return true;
+ }
+
+ return false;
+}
+
+static inline tree builtin_decl_implicit(enum built_in_function fncode)
+{
+ return implicit_built_in_decls[fncode];
+}
+
+static inline int ipa_reverse_postorder(struct cgraph_node **order)
+{
+ return cgraph_postorder(order);
+}
+
+static inline struct cgraph_node *cgraph_create_node(tree decl)
+{
+ return cgraph_node(decl);
+}
+
+static inline struct cgraph_node *cgraph_get_create_node(tree decl)
+{
+ struct cgraph_node *node = cgraph_get_node(decl);
+
+ return node ? node : cgraph_node(decl);
+}
+
+static inline bool cgraph_function_with_gimple_body_p(struct cgraph_node *node)
+{
+ return node->analyzed && !node->thunk.thunk_p && !node->alias;
+}
+
+static inline struct cgraph_node *cgraph_first_function_with_gimple_body(void)
+{
+ struct cgraph_node *node;
+
+ for (node = cgraph_nodes; node; node = node->next)
+ if (cgraph_function_with_gimple_body_p(node))
+ return node;
+ return NULL;
+}
+
+static inline struct cgraph_node *cgraph_next_function_with_gimple_body(struct cgraph_node *node)
+{
+ for (node = node->next; node; node = node->next)
+ if (cgraph_function_with_gimple_body_p(node))
+ return node;
+ return NULL;
+}
+
+static inline bool cgraph_for_node_and_aliases(cgraph_node_ptr node, bool (*callback)(cgraph_node_ptr, void *), void *data, bool include_overwritable)
+{
+ cgraph_node_ptr alias;
+
+ if (callback(node, data))
+ return true;
+
+ for (alias = node->same_body; alias; alias = alias->next) {
+ if (include_overwritable || cgraph_function_body_availability(alias) > AVAIL_OVERWRITABLE)
+ if (cgraph_for_node_and_aliases(alias, callback, data, include_overwritable))
+ return true;
+ }
+
+ return false;
+}
+
+#define FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) \
+ for ((node) = cgraph_first_function_with_gimple_body(); (node); \
+ (node) = cgraph_next_function_with_gimple_body(node))
+
+static inline void varpool_add_new_variable(tree decl)
+{
+ varpool_finalize_decl(decl);
+}
+#endif
+
+#if BUILDING_GCC_VERSION <= 4007
+#define FOR_EACH_FUNCTION(node) \
+ for (node = cgraph_nodes; node; node = node->next)
+#define FOR_EACH_VARIABLE(node) \
+ for (node = varpool_nodes; node; node = node->next)
+#define PROP_loops 0
+#define NODE_SYMBOL(node) (node)
+#define NODE_DECL(node) (node)->decl
+#define INSN_LOCATION(INSN) RTL_LOCATION(INSN)
+#define vNULL NULL
+
+static inline int bb_loop_depth(const_basic_block bb)
+{
+ return bb->loop_father ? loop_depth(bb->loop_father) : 0;
+}
+
+static inline bool gimple_store_p(gimple gs)
+{
+ tree lhs = gimple_get_lhs(gs);
+
+ return lhs && !is_gimple_reg(lhs);
+}
+
+static inline void gimple_init_singleton(gimple g __unused)
+{
+}
+#endif
+
+#if BUILDING_GCC_VERSION == 4007 || BUILDING_GCC_VERSION == 4008
+static inline struct cgraph_node *cgraph_alias_target(struct cgraph_node *n)
+{
+ return cgraph_alias_aliased_node(n);
+}
+#endif
+
+#if BUILDING_GCC_VERSION <= 4008
+#define ENTRY_BLOCK_PTR_FOR_FN(FN) ENTRY_BLOCK_PTR_FOR_FUNCTION(FN)
+#define EXIT_BLOCK_PTR_FOR_FN(FN) EXIT_BLOCK_PTR_FOR_FUNCTION(FN)
+#define basic_block_info_for_fn(FN) ((FN)->cfg->x_basic_block_info)
+#define n_basic_blocks_for_fn(FN) ((FN)->cfg->x_n_basic_blocks)
+#define n_edges_for_fn(FN) ((FN)->cfg->x_n_edges)
+#define last_basic_block_for_fn(FN) ((FN)->cfg->x_last_basic_block)
+#define label_to_block_map_for_fn(FN) ((FN)->cfg->x_label_to_block_map)
+#define profile_status_for_fn(FN) ((FN)->cfg->x_profile_status)
+#define BASIC_BLOCK_FOR_FN(FN, N) BASIC_BLOCK_FOR_FUNCTION((FN), (N))
+#define NODE_IMPLICIT_ALIAS(node) (node)->same_body_alias
+#define VAR_P(NODE) (TREE_CODE(NODE) == VAR_DECL)
+
+static inline bool tree_fits_shwi_p(const_tree t)
+{
+ if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST)
+ return false;
+
+ if (TREE_INT_CST_HIGH(t) == 0 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) >= 0)
+ return true;
+
+ if (TREE_INT_CST_HIGH(t) == -1 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) < 0 && !TYPE_UNSIGNED(TREE_TYPE(t)))
+ return true;
+
+ return false;
+}
+
+static inline bool tree_fits_uhwi_p(const_tree t)
+{
+ if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST)
+ return false;
+
+ return TREE_INT_CST_HIGH(t) == 0;
+}
+
+static inline HOST_WIDE_INT tree_to_shwi(const_tree t)
+{
+ gcc_assert(tree_fits_shwi_p(t));
+ return TREE_INT_CST_LOW(t);
+}
+
+static inline unsigned HOST_WIDE_INT tree_to_uhwi(const_tree t)
+{
+ gcc_assert(tree_fits_uhwi_p(t));
+ return TREE_INT_CST_LOW(t);
+}
+
+static inline const char *get_tree_code_name(enum tree_code code)
+{
+ gcc_assert(code < MAX_TREE_CODES);
+ return tree_code_name[code];
+}
+
+#define ipa_remove_stmt_references(cnode, stmt)
+
+typedef union gimple_statement_d gasm;
+typedef union gimple_statement_d gassign;
+typedef union gimple_statement_d gcall;
+typedef union gimple_statement_d gcond;
+typedef union gimple_statement_d gdebug;
+typedef union gimple_statement_d ggoto;
+typedef union gimple_statement_d gphi;
+typedef union gimple_statement_d greturn;
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gassign *as_a_const_gassign(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gcond *as_a_gcond(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gcond *as_a_const_gcond(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gdebug *as_a_gdebug(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gdebug *as_a_const_gdebug(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline ggoto *as_a_ggoto(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const ggoto *as_a_const_ggoto(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gphi *as_a_gphi(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gphi *as_a_const_gphi(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline greturn *as_a_greturn(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const greturn *as_a_const_greturn(const_gimple stmt)
+{
+ return stmt;
+}
+#endif
+
+#if BUILDING_GCC_VERSION == 4008
+#define NODE_SYMBOL(node) (&(node)->symbol)
+#define NODE_DECL(node) (node)->symbol.decl
+#endif
+
+#if BUILDING_GCC_VERSION >= 4008
+#define add_referenced_var(var)
+#define mark_sym_for_renaming(var)
+#define varpool_mark_needed_node(node)
+#define create_var_ann(var)
+#define TODO_dump_func 0
+#define TODO_dump_cgraph 0
+#endif
+
+#if BUILDING_GCC_VERSION <= 4009
+#define TODO_verify_il 0
+#define AVAIL_INTERPOSABLE AVAIL_OVERWRITABLE
+
+#define section_name_prefix LTO_SECTION_NAME_PREFIX
+#define fatal_error(loc, gmsgid, ...) fatal_error((gmsgid), __VA_ARGS__)
+
+rtx emit_move_insn(rtx x, rtx y);
+
+typedef struct rtx_def rtx_insn;
+
+static inline const char *get_decl_section_name(const_tree decl)
+{
+ if (DECL_SECTION_NAME(decl) == NULL_TREE)
+ return NULL;
+
+ return TREE_STRING_POINTER(DECL_SECTION_NAME(decl));
+}
+
+static inline void set_decl_section_name(tree node, const char *value)
+{
+ if (value)
+ DECL_SECTION_NAME(node) = build_string(strlen(value) + 1, value);
+ else
+ DECL_SECTION_NAME(node) = NULL;
+}
+#endif
+
+#if BUILDING_GCC_VERSION == 4009
+typedef struct gimple_statement_asm gasm;
+typedef struct gimple_statement_base gassign;
+typedef struct gimple_statement_call gcall;
+typedef struct gimple_statement_base gcond;
+typedef struct gimple_statement_base gdebug;
+typedef struct gimple_statement_base ggoto;
+typedef struct gimple_statement_phi gphi;
+typedef struct gimple_statement_base greturn;
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
+ return as_a<gasm>(stmt);
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
+ return as_a<const gasm>(stmt);
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gassign *as_a_const_gassign(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
+ return as_a<gcall>(stmt);
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
+ return as_a<const gcall>(stmt);
+}
+
+static inline gcond *as_a_gcond(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gcond *as_a_const_gcond(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gdebug *as_a_gdebug(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gdebug *as_a_const_gdebug(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline ggoto *as_a_ggoto(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const ggoto *as_a_const_ggoto(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gphi *as_a_gphi(gimple stmt)
+{
+ return as_a<gphi>(stmt);
+}
+
+static inline const gphi *as_a_const_gphi(const_gimple stmt)
+{
+ return as_a<const gphi>(stmt);
+}
+
+static inline greturn *as_a_greturn(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const greturn *as_a_const_greturn(const_gimple stmt)
+{
+ return stmt;
+}
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+#define TODO_ggc_collect 0
+#define NODE_SYMBOL(node) (node)
+#define NODE_DECL(node) (node)->decl
+#define cgraph_node_name(node) (node)->name()
+#define NODE_IMPLICIT_ALIAS(node) (node)->cpp_implicit_alias
+
+static inline opt_pass *get_pass_for_id(int id)
+{
+ return g->get_passes()->get_pass_for_id(id);
+}
+#endif
+
+#if BUILDING_GCC_VERSION >= 5000 && BUILDING_GCC_VERSION < 6000
+/* gimple related */
+template <>
+template <>
+inline bool is_a_helper<const gassign *>::test(const_gimple gs)
+{
+ return gs->code == GIMPLE_ASSIGN;
+}
+#endif
+
+#if BUILDING_GCC_VERSION >= 5000
+#define TODO_verify_ssa TODO_verify_il
+#define TODO_verify_flow TODO_verify_il
+#define TODO_verify_stmts TODO_verify_il
+#define TODO_verify_rtl_sharing TODO_verify_il
+
+#define INSN_DELETED_P(insn) (insn)->deleted()
+
+static inline const char *get_decl_section_name(const_tree decl)
+{
+ return DECL_SECTION_NAME(decl);
+}
+
+/* symtab/cgraph related */
+#define debug_cgraph_node(node) (node)->debug()
+#define cgraph_get_node(decl) cgraph_node::get(decl)
+#define cgraph_get_create_node(decl) cgraph_node::get_create(decl)
+#define cgraph_create_node(decl) cgraph_node::create(decl)
+#define cgraph_n_nodes symtab->cgraph_count
+#define cgraph_max_uid symtab->cgraph_max_uid
+#define varpool_get_node(decl) varpool_node::get(decl)
+#define dump_varpool_node(file, node) (node)->dump(file)
+
+#if BUILDING_GCC_VERSION >= 8000
+#define cgraph_create_edge(caller, callee, call_stmt, count, freq) \
+ (caller)->create_edge((callee), (call_stmt), (count))
+
+#define cgraph_create_edge_including_clones(caller, callee, \
+ old_call_stmt, call_stmt, count, freq, reason) \
+ (caller)->create_edge_including_clones((callee), \
+ (old_call_stmt), (call_stmt), (count), (reason))
+#else
+#define cgraph_create_edge(caller, callee, call_stmt, count, freq) \
+ (caller)->create_edge((callee), (call_stmt), (count), (freq))
+
+#define cgraph_create_edge_including_clones(caller, callee, \
+ old_call_stmt, call_stmt, count, freq, reason) \
+ (caller)->create_edge_including_clones((callee), \
+ (old_call_stmt), (call_stmt), (count), (freq), (reason))
+#endif
+
+typedef struct cgraph_node *cgraph_node_ptr;
+typedef struct cgraph_edge *cgraph_edge_p;
+typedef struct varpool_node *varpool_node_ptr;
+
+static inline void change_decl_assembler_name(tree decl, tree name)
+{
+ symtab->change_decl_assembler_name(decl, name);
+}
+
+static inline void varpool_finalize_decl(tree decl)
+{
+ varpool_node::finalize_decl(decl);
+}
+
+static inline void varpool_add_new_variable(tree decl)
+{
+ varpool_node::add(decl);
+}
+
+static inline unsigned int rebuild_cgraph_edges(void)
+{
+ return cgraph_edge::rebuild_edges();
+}
+
+static inline cgraph_node_ptr cgraph_function_node(cgraph_node_ptr node, enum availability *availability)
+{
+ return node->function_symbol(availability);
+}
+
+static inline cgraph_node_ptr cgraph_function_or_thunk_node(cgraph_node_ptr node, enum availability *availability = NULL)
+{
+ return node->ultimate_alias_target(availability);
+}
+
+static inline bool cgraph_only_called_directly_p(cgraph_node_ptr node)
+{
+ return node->only_called_directly_p();
+}
+
+static inline enum availability cgraph_function_body_availability(cgraph_node_ptr node)
+{
+ return node->get_availability();
+}
+
+static inline cgraph_node_ptr cgraph_alias_target(cgraph_node_ptr node)
+{
+ return node->get_alias_target();
+}
+
+static inline bool cgraph_for_node_and_aliases(cgraph_node_ptr node, bool (*callback)(cgraph_node_ptr, void *), void *data, bool include_overwritable)
+{
+ return node->call_for_symbol_thunks_and_aliases(callback, data, include_overwritable);
+}
+
+static inline struct cgraph_node_hook_list *cgraph_add_function_insertion_hook(cgraph_node_hook hook, void *data)
+{
+ return symtab->add_cgraph_insertion_hook(hook, data);
+}
+
+static inline void cgraph_remove_function_insertion_hook(struct cgraph_node_hook_list *entry)
+{
+ symtab->remove_cgraph_insertion_hook(entry);
+}
+
+static inline struct cgraph_node_hook_list *cgraph_add_node_removal_hook(cgraph_node_hook hook, void *data)
+{
+ return symtab->add_cgraph_removal_hook(hook, data);
+}
+
+static inline void cgraph_remove_node_removal_hook(struct cgraph_node_hook_list *entry)
+{
+ symtab->remove_cgraph_removal_hook(entry);
+}
+
+static inline struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook(cgraph_2node_hook hook, void *data)
+{
+ return symtab->add_cgraph_duplication_hook(hook, data);
+}
+
+static inline void cgraph_remove_node_duplication_hook(struct cgraph_2node_hook_list *entry)
+{
+ symtab->remove_cgraph_duplication_hook(entry);
+}
+
+static inline void cgraph_call_node_duplication_hooks(cgraph_node_ptr node, cgraph_node_ptr node2)
+{
+ symtab->call_cgraph_duplication_hooks(node, node2);
+}
+
+static inline void cgraph_call_edge_duplication_hooks(cgraph_edge *cs1, cgraph_edge *cs2)
+{
+ symtab->call_edge_duplication_hooks(cs1, cs2);
+}
+
+#if BUILDING_GCC_VERSION >= 6000
+typedef gimple *gimple_ptr;
+typedef const gimple *const_gimple_ptr;
+#define gimple gimple_ptr
+#define const_gimple const_gimple_ptr
+#undef CONST_CAST_GIMPLE
+#define CONST_CAST_GIMPLE(X) CONST_CAST(gimple, (X))
+#endif
+
+/* gimple related */
+static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree lhs, tree op1, tree op2 MEM_STAT_DECL)
+{
+ return gimple_build_assign(lhs, subcode, op1, op2 PASS_MEM_STAT);
+}
+
+template <>
+template <>
+inline bool is_a_helper<const ggoto *>::test(const_gimple gs)
+{
+ return gs->code == GIMPLE_GOTO;
+}
+
+template <>
+template <>
+inline bool is_a_helper<const greturn *>::test(const_gimple gs)
+{
+ return gs->code == GIMPLE_RETURN;
+}
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
+ return as_a<gasm *>(stmt);
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
+ return as_a<const gasm *>(stmt);
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
+{
+ return as_a<gassign *>(stmt);
+}
+
+static inline const gassign *as_a_const_gassign(const_gimple stmt)
+{
+ return as_a<const gassign *>(stmt);
+}
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
+ return as_a<gcall *>(stmt);
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
+ return as_a<const gcall *>(stmt);
+}
+
+static inline ggoto *as_a_ggoto(gimple stmt)
+{
+ return as_a<ggoto *>(stmt);
+}
+
+static inline const ggoto *as_a_const_ggoto(const_gimple stmt)
+{
+ return as_a<const ggoto *>(stmt);
+}
+
+static inline gphi *as_a_gphi(gimple stmt)
+{
+ return as_a<gphi *>(stmt);
+}
+
+static inline const gphi *as_a_const_gphi(const_gimple stmt)
+{
+ return as_a<const gphi *>(stmt);
+}
+
+static inline greturn *as_a_greturn(gimple stmt)
+{
+ return as_a<greturn *>(stmt);
+}
+
+static inline const greturn *as_a_const_greturn(const_gimple stmt)
+{
+ return as_a<const greturn *>(stmt);
+}
+
+/* IPA/LTO related */
+#define ipa_ref_list_referring_iterate(L, I, P) \
+ (L)->referring.iterate((I), &(P))
+#define ipa_ref_list_reference_iterate(L, I, P) \
+ (L)->reference.iterate((I), &(P))
+
+static inline cgraph_node_ptr ipa_ref_referring_node(struct ipa_ref *ref)
+{
+ return dyn_cast<cgraph_node_ptr>(ref->referring);
+}
+
+static inline void ipa_remove_stmt_references(symtab_node *referring_node, gimple stmt)
+{
+ referring_node->remove_stmt_references(stmt);
+}
+#endif
+
+#if BUILDING_GCC_VERSION < 6000
+#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \
+ get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, pvolatilep, keep_aligning)
+#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET(VOIDmode, (ARG0), (ARG1))
+#endif
+
+#if BUILDING_GCC_VERSION >= 6000
+#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET((ARG0), (ARG1))
+#endif
+
+#ifdef __cplusplus
+static inline void debug_tree(const_tree t)
+{
+ debug_tree(CONST_CAST_TREE(t));
+}
+
+static inline void debug_gimple_stmt(const_gimple s)
+{
+ debug_gimple_stmt(CONST_CAST_GIMPLE(s));
+}
+#else
+#define debug_tree(t) debug_tree(CONST_CAST_TREE(t))
+#define debug_gimple_stmt(s) debug_gimple_stmt(CONST_CAST_GIMPLE(s))
+#endif
+
+#if BUILDING_GCC_VERSION >= 7000
+#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \
+ get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep)
+#endif
+
+#if BUILDING_GCC_VERSION < 7000
+#define SET_DECL_ALIGN(decl, align) DECL_ALIGN(decl) = (align)
+#define SET_DECL_MODE(decl, mode) DECL_MODE(decl) = (mode)
+#endif
+
+#endif
diff --git a/tools/gcc-plugins/gcc-retain-typeinfo.patch b/tools/gcc-plugins/gcc-retain-typeinfo.patch
new file mode 100644
index 0000000000..ec51f0be6f
--- /dev/null
+++ b/tools/gcc-plugins/gcc-retain-typeinfo.patch
@@ -0,0 +1,11 @@
+--- a/src/gcc/c/c-typeck.c
++++ b/src/gcc/c/c-typeck.c
+@@ -5716,8 +5716,6 @@ build_c_cast (location_t loc, tree type, tree expr)
+ if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr)))
+ return build1 (NOP_EXPR, type, expr);
+
+- type = TYPE_MAIN_VARIANT (type);
+-
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ error_at (loc, "cast specifies array type");
diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c
index ed9616963d..05e6651229 100644
--- a/watchfrr/watchfrr.c
+++ b/watchfrr/watchfrr.c
@@ -318,9 +318,8 @@ static pid_t run_background(char *shell_cmd)
}
default:
/* Parent process: we will reap the child later. */
- flog_err_sys(EC_LIB_SYSTEM_CALL,
- "Forked background command [pid %d]: %s",
- (int)child, shell_cmd);
+ zlog_info("Forked background command [pid %d]: %s", (int)child,
+ shell_cmd);
return child;
}
}
@@ -559,9 +558,9 @@ static int wakeup_init(struct thread *t_wakeup)
dmn->t_wakeup = NULL;
if (try_connect(dmn) < 0) {
- flog_err(EC_WATCHFRR_CONNECTION,
- "%s state -> down : initial connection attempt failed",
- dmn->name);
+ zlog_info(
+ "%s state -> down : initial connection attempt failed",
+ dmn->name);
dmn->state = DAEMON_DOWN;
}
phase_check();
diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang
index f9ac2e43b0..b870bfd0c8 100644
--- a/yang/frr-bfdd.yang
+++ b/yang/frr-bfdd.yang
@@ -16,7 +16,7 @@ module frr-bfdd {
prefix frr-route-types;
}
- organization "Free Range Routing";
+ organization "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang
index 0c62954570..e02f888b0e 100644
--- a/yang/frr-eigrpd.yang
+++ b/yang/frr-eigrpd.yang
@@ -16,7 +16,7 @@ module frr-eigrpd {
prefix frr-route-types;
}
- organization "Free Range Routing";
+ organization "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang
index e79ede87b7..61ffa51552 100644
--- a/yang/frr-filter.yang
+++ b/yang/frr-filter.yang
@@ -10,7 +10,7 @@ module frr-filter {
prefix yang;
}
- organization "Free Range Routing";
+ organization "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang
index 4f7f3beebd..1f3eebb2ab 100644
--- a/yang/frr-interface.yang
+++ b/yang/frr-interface.yang
@@ -4,7 +4,7 @@ module frr-interface {
prefix frr-interface;
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index faab1e55b2..8dcc0f97a3 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -20,7 +20,7 @@ module frr-isisd {
}
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-module-translator.yang b/yang/frr-module-translator.yang
index 3d64ec5399..6713eae76e 100644
--- a/yang/frr-module-translator.yang
+++ b/yang/frr-module-translator.yang
@@ -4,7 +4,7 @@ module frr-module-translator {
prefix frr-module-translator;
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-nexthop.yang b/yang/frr-nexthop.yang
index 7d8ce1b8ed..3657ecbd75 100644
--- a/yang/frr-nexthop.yang
+++ b/yang/frr-nexthop.yang
@@ -15,7 +15,7 @@ module frr-nexthop {
}
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang
index 94a9ebf3e1..7318eb18d7 100644
--- a/yang/frr-ripd.yang
+++ b/yang/frr-ripd.yang
@@ -17,7 +17,7 @@ module frr-ripd {
}
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang
index 831758af86..732f32ea50 100644
--- a/yang/frr-ripngd.yang
+++ b/yang/frr-ripngd.yang
@@ -17,7 +17,7 @@ module frr-ripngd {
}
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang
index 34a7e28a77..eea29733a3 100644
--- a/yang/frr-route-map.yang
+++ b/yang/frr-route-map.yang
@@ -13,7 +13,7 @@ module frr-route-map {
prefix frr-interface;
}
- organization "Free Range Routing";
+ organization "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
@@ -179,17 +179,27 @@ module frr-route-map {
description "Match a route tag";
value 10;
}
-
- /*
- * Protocol YANG models should augment the parent node to
- * contain the routing protocol specific value. The protocol
- * must also augment `condition-value` to include its specific
- * values or expand the `when` statement on the existing cases.
- */
- enum routing-protocol-specific {
- description "Match a routing protocol specific type";
+ /* zebra specific conditions. */
+ enum ipv4-prefix-length {
+ description "Match IPv4 prefix length";
value 100;
}
+ enum ipv6-prefix-length {
+ description "Match IPv6 prefix length";
+ value 101;
+ }
+ enum ipv4-next-hop-prefix-length {
+ description "Match next-hop prefix length";
+ value 102;
+ }
+ enum source-protocol {
+ description "Match source protocol";
+ value 103;
+ }
+ enum source-instance {
+ description "Match source protocol instance";
+ value 104;
+ }
}
}
@@ -291,15 +301,9 @@ module frr-route-map {
description "Set tag";
value 3;
}
-
- /*
- * Protocol YANG models should augment the parent node to
- * contain the routing protocol specific value. The protocol
- * must also augment `action-value` to include its specific
- * values or expand the `when` statement on the existing cases.
- */
- enum routing-protocol-specific {
- description "Set a routing protocol specific action";
+ /* zebra specific conditions. */
+ enum source {
+ description "Set source address for route";
value 100;
}
}
diff --git a/yang/frr-route-types.yang b/yang/frr-route-types.yang
index f22c5ef890..8fdd10121e 100644
--- a/yang/frr-route-types.yang
+++ b/yang/frr-route-types.yang
@@ -4,7 +4,7 @@ module frr-route-types {
prefix frr-route-types;
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
@@ -106,4 +106,12 @@ module frr-route-types {
}
}
}
+
+ typedef frr-route-types {
+ description "Route types as enumerated in `lib/route_types.txt`";
+ type union {
+ type frr-route-types-v4;
+ type frr-route-types-v6;
+ }
+ }
}
diff --git a/yang/frr-vrrpd.yang b/yang/frr-vrrpd.yang
index 3d3a4138fa..145387c4b4 100644
--- a/yang/frr-vrrpd.yang
+++ b/yang/frr-vrrpd.yang
@@ -16,7 +16,7 @@ module frr-vrrpd {
}
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
index 74922a22f7..736bbc2c81 100644
--- a/yang/frr-zebra.yang
+++ b/yang/frr-zebra.yang
@@ -11,6 +11,10 @@ module frr-zebra {
prefix inet;
}
+ import frr-route-map {
+ prefix frr-route-map;
+ }
+
import frr-route-types {
prefix frr-route-types;
}
@@ -28,7 +32,7 @@ module frr-zebra {
}
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
@@ -1985,4 +1989,63 @@ module frr-zebra {
}
// End interface model augmentation
+
+ augment "/frr-route-map:lib"
+ + "/frr-route-map:route-map"
+ + "/frr-route-map:entry"
+ + "/frr-route-map:match-condition"
+ + "/frr-route-map:condition-value" {
+ case ipv4-prefix-length {
+ when "./condition = 'ipv4-prefix-length' or
+ ./condition = 'ipv4-next-hop-prefix-length'";
+ leaf ipv4-prefix-length {
+ type uint8 {
+ range "0..32";
+ }
+ }
+ }
+ case ipv6-prefix-length {
+ when "./condition = 'ipv6-prefix-length'";
+ leaf ipv6-prefix-length {
+ type uint8 {
+ range "0..128";
+ }
+ }
+ }
+ case source-protocol {
+ when "./condition = 'source-protocol'";
+ leaf source-protocol {
+ type frr-route-types:frr-route-types;
+ }
+ }
+ case source-instance {
+ when "./condition = 'source-instance'";
+ leaf source-instance {
+ type uint8 {
+ range "0..255";
+ }
+ }
+ }
+ }
+
+ augment "/frr-route-map:lib"
+ + "/frr-route-map:route-map"
+ + "/frr-route-map:entry"
+ + "/frr-route-map:set-action"
+ + "/frr-route-map:action-value" {
+ case source-v4 {
+ when "./action = 'source'";
+ leaf source-v4 {
+ description "IPv4 address";
+ type inet:ipv4-address;
+ }
+ }
+ case source-v6 {
+ when "./action = 'source'";
+ leaf source-v6 {
+ description "IPv6 address";
+ type inet:ipv6-address;
+ }
+ }
+ }
}
diff --git a/yang/ietf/frr-deviations-ietf-interfaces.yang b/yang/ietf/frr-deviations-ietf-interfaces.yang
index 6528d66d22..704839fb60 100644
--- a/yang/ietf/frr-deviations-ietf-interfaces.yang
+++ b/yang/ietf/frr-deviations-ietf-interfaces.yang
@@ -8,7 +8,7 @@ module frr-deviations-ietf-interfaces {
}
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
diff --git a/yang/ietf/frr-deviations-ietf-rip.yang b/yang/ietf/frr-deviations-ietf-rip.yang
index 42ed8e3c09..39a1d7e71d 100644
--- a/yang/ietf/frr-deviations-ietf-rip.yang
+++ b/yang/ietf/frr-deviations-ietf-rip.yang
@@ -12,7 +12,7 @@ module frr-deviations-ietf-rip {
}
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
diff --git a/yang/ietf/frr-deviations-ietf-routing.yang b/yang/ietf/frr-deviations-ietf-routing.yang
index 62787e782c..15ceb6b929 100644
--- a/yang/ietf/frr-deviations-ietf-routing.yang
+++ b/yang/ietf/frr-deviations-ietf-routing.yang
@@ -8,7 +8,7 @@ module frr-deviations-ietf-routing {
}
organization
- "Free Range Routing";
+ "FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
diff --git a/yang/subdir.am b/yang/subdir.am
index c1297dafd5..0e124c5ab0 100644
--- a/yang/subdir.am
+++ b/yang/subdir.am
@@ -21,10 +21,12 @@ EXTRA_DIST += yang/embedmodel.py
dist_yangmodels_DATA += yang/frr-filter.yang
dist_yangmodels_DATA += yang/frr-module-translator.yang
+dist_yangmodels_DATA += yang/frr-nexthop.yang
dist_yangmodels_DATA += yang/frr-test-module.yang
dist_yangmodels_DATA += yang/frr-interface.yang
dist_yangmodels_DATA += yang/frr-route-map.yang
dist_yangmodels_DATA += yang/frr-route-types.yang
+dist_yangmodels_DATA += yang/frr-zebra.yang
dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang
if BFDD
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 5ab5210664..950690b943 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -1393,7 +1393,7 @@ static int kernel_read(struct thread *thread)
*/
if (rtm->rtm_msglen != nbytes) {
zlog_debug(
- "kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n",
+ "kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d",
rtm->rtm_msglen, nbytes, rtm->rtm_type);
return -1;
}
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index caebdc0f08..0825fb55ca 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -4,7 +4,7 @@
* Copyright (C) 2017 by Bingen Eguzkitza,
* Volta Networks Inc.
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/zebra/label_manager.h b/zebra/label_manager.h
index 74e283e85e..4fee34d301 100644
--- a/zebra/label_manager.h
+++ b/zebra/label_manager.h
@@ -4,7 +4,7 @@
* Copyright (C) 2017 by Bingen Eguzkitza,
* Volta Networks Inc.
*
- * This file is part of FreeRangeRouting (FRR)
+ * 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
diff --git a/zebra/main.c b/zebra/main.c
index dab1449194..306372ccdb 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -174,6 +174,7 @@ static void sigint(void)
work_queue_free_and_null(&zrouter.lsp_process_q);
vrf_terminate();
+ rtadv_terminate();
ns_walk_func(zebra_ns_early_shutdown);
zebra_ns_notify_close();
@@ -245,6 +246,7 @@ struct quagga_signal_t zebra_signals[] = {
static const struct frr_yang_module_info *const zebra_yang_modules[] = {
&frr_interface_info,
&frr_route_map_info,
+ &frr_zebra_info,
};
FRR_DAEMON_INFO(
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 80cc18a57d..115a69f2c8 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -268,7 +268,7 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
/* Add DISTANCE_INFINITY check. */
if (old_re && (old_re->distance == DISTANCE_INFINITY)) {
if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("\tSkipping due to Infinite Distance");
+ zlog_debug(" Skipping due to Infinite Distance");
return;
}
@@ -291,6 +291,10 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
}
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
if (new_re) {
/* Skip this client if it will receive an update for the
* 'new' re
@@ -472,6 +476,12 @@ void zebra_interface_up_update(struct interface *ifp)
if (ifp->ptm_status || !ifp->ptm_enable) {
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode,
client)) {
+ /* Do not send unsolicited messages to synchronous
+ * clients.
+ */
+ if (client->synchronous)
+ continue;
+
zsend_interface_update(ZEBRA_INTERFACE_UP,
client, ifp);
zsend_interface_link_params(client, ifp);
@@ -490,6 +500,10 @@ void zebra_interface_down_update(struct interface *ifp)
ifp->name, ifp->vrf_id);
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp);
}
}
@@ -505,6 +519,10 @@ void zebra_interface_add_update(struct interface *ifp)
ifp->vrf_id);
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
client->ifadd_cnt++;
zsend_interface_add(client, ifp);
zsend_interface_link_params(client, ifp);
@@ -521,6 +539,10 @@ void zebra_interface_delete_update(struct interface *ifp)
ifp->name, ifp->vrf_id);
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
client->ifdel_cnt++;
zsend_interface_delete(client, ifp);
}
@@ -552,12 +574,17 @@ void zebra_interface_address_add_update(struct interface *ifp,
router_id_add_address(ifc);
- for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) {
client->connected_rt_add_cnt++;
zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_ADD,
client, ifp, ifc);
}
+ }
}
/* Interface address deletion. */
@@ -581,12 +608,17 @@ void zebra_interface_address_delete_update(struct interface *ifp,
router_id_del_address(ifc);
- for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) {
client->connected_rt_del_cnt++;
zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_DELETE,
client, ifp, ifc);
}
+ }
}
/* Interface VRF change. May need to delete from clients not interested in
@@ -603,6 +635,10 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id)
ifp->name, ifp->vrf_id, new_vrf_id);
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
/* Need to delete if the client is not interested in the new
* VRF. */
zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp);
@@ -626,6 +662,10 @@ void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id)
ifp->name, old_vrf_id, ifp->vrf_id);
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
/* Need to add if the client is interested in the new VRF. */
client->ifadd_cnt++;
zsend_interface_add(client, ifp);
@@ -913,6 +953,11 @@ void zebra_interface_parameters_update(struct interface *ifp)
zlog_debug("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s(%u)",
ifp->name, ifp->vrf_id);
- for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
zsend_interface_link_params(client, ifp);
+ }
}
diff --git a/zebra/rib.h b/zebra/rib.h
index 931c97638e..3717a12814 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -107,7 +107,7 @@ struct route_entry {
/* Uptime. */
time_t uptime;
- /* Type fo this route. */
+ /* Type of this route. */
int type;
/* VRF identifier. */
@@ -347,10 +347,16 @@ extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
uint32_t nhe_id, uint32_t table_id, uint32_t metric,
uint32_t mtu, uint8_t distance, route_tag_t tag);
-
+/*
+ * Multipath route apis.
+ */
extern int 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);
+extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
+ struct prefix_ipv6 *src_p,
+ struct route_entry *re,
+ struct nhg_hash_entry *nhe);
extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, int flags, struct prefix *p,
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 2cc520bbce..84c9bd098e 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1111,7 +1111,8 @@ static int build_label_stack(struct mpls_label_stack *nh_label,
* @param nlmsg: nlmsghdr structure to fill in.
* @param req_size: The size allocated for the message.
*/
-static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
+static void _netlink_route_build_singlepath(const struct prefix *p,
+ const char *routedesc, int bytelen,
const struct nexthop *nexthop,
struct nlmsghdr *nlmsg,
struct rtmsg *rtmsg,
@@ -1176,9 +1177,8 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- " 5549: _netlink_route_build_singlepath() (%s): "
- "nexthop via %s %s if %u(%u)",
- routedesc, ipv4_ll_buf, label_buf,
+ " 5549: _netlink_route_build_singlepath() (%s): %pFX nexthop via %s %s if %u(%u)",
+ routedesc, p, ipv4_ll_buf, label_buf,
nexthop->ifindex, nexthop->vrf_id);
return;
}
@@ -1202,9 +1202,8 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "netlink_route_multipath() (%s): "
- "nexthop via %s %s if %u(%u)",
- routedesc, inet_ntoa(nexthop->gate.ipv4),
+ "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u(%u)",
+ routedesc, p, inet_ntoa(nexthop->gate.ipv4),
label_buf, nexthop->ifindex, nexthop->vrf_id);
}
@@ -1225,9 +1224,8 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "netlink_route_multipath() (%s): "
- "nexthop via %s %s if %u(%u)",
- routedesc, inet6_ntoa(nexthop->gate.ipv6),
+ "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u(%u)",
+ routedesc, p, inet6_ntoa(nexthop->gate.ipv6),
label_buf, nexthop->ifindex, nexthop->vrf_id);
}
@@ -1251,9 +1249,9 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "netlink_route_multipath() (%s): "
- "nexthop via if %u(%u)",
- routedesc, nexthop->ifindex, nexthop->vrf_id);
+ "netlink_route_multipath() (%s): %pFX nexthop via if %u(%u)",
+ routedesc, p, nexthop->ifindex,
+ nexthop->vrf_id);
}
}
@@ -1273,12 +1271,11 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
* @param src: pointer pointing to a location where
* the prefsrc should be stored.
*/
-static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
- const struct nexthop *nexthop,
- struct rtattr *rta,
- struct rtnexthop *rtnh,
- struct rtmsg *rtmsg,
- const union g_addr **src)
+static void
+_netlink_route_build_multipath(const struct prefix *p, const char *routedesc,
+ int bytelen, const struct nexthop *nexthop,
+ struct rtattr *rta, struct rtnexthop *rtnh,
+ struct rtmsg *rtmsg, const union g_addr **src)
{
mpls_lse_t out_lse[MPLS_MAX_LABELS];
char label_buf[256];
@@ -1350,9 +1347,8 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- " 5549: netlink_route_build_multipath() (%s): "
- "nexthop via %s %s if %u",
- routedesc, ipv4_ll_buf, label_buf,
+ " 5549: netlink_route_build_multipath() (%s): %pFX nexthop via %s %s if %u",
+ routedesc, p, ipv4_ll_buf, label_buf,
nexthop->ifindex);
return;
}
@@ -1369,9 +1365,8 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "netlink_route_multipath() (%s): "
- "nexthop via %s %s if %u",
- routedesc, inet_ntoa(nexthop->gate.ipv4),
+ "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u",
+ routedesc, p, inet_ntoa(nexthop->gate.ipv4),
label_buf, nexthop->ifindex);
}
if (nexthop->type == NEXTHOP_TYPE_IPV6
@@ -1387,9 +1382,8 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "netlink_route_multipath() (%s): "
- "nexthop via %s %s if %u",
- routedesc, inet6_ntoa(nexthop->gate.ipv6),
+ "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u",
+ routedesc, p, inet6_ntoa(nexthop->gate.ipv6),
label_buf, nexthop->ifindex);
}
@@ -1410,16 +1404,16 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "netlink_route_multipath() (%s): "
- "nexthop via if %u",
- routedesc, nexthop->ifindex);
+ "netlink_route_multipath() (%s): %pFX nexthop via if %u",
+ routedesc, p, nexthop->ifindex);
}
if (nexthop->weight)
rtnh->rtnh_hops = nexthop->weight - 1;
}
-static inline void _netlink_mpls_build_singlepath(const char *routedesc,
+static inline void _netlink_mpls_build_singlepath(const struct prefix *p,
+ const char *routedesc,
const zebra_nhlfe_t *nhlfe,
struct nlmsghdr *nlmsg,
struct rtmsg *rtmsg,
@@ -1430,23 +1424,24 @@ static inline void _netlink_mpls_build_singlepath(const char *routedesc,
family = NHLFE_FAMILY(nhlfe);
bytelen = (family == AF_INET ? 4 : 16);
- _netlink_route_build_singlepath(routedesc, bytelen, nhlfe->nexthop,
+ _netlink_route_build_singlepath(p, routedesc, bytelen, nhlfe->nexthop,
nlmsg, rtmsg, req_size, cmd);
}
static inline void
-_netlink_mpls_build_multipath(const char *routedesc, const zebra_nhlfe_t *nhlfe,
- struct rtattr *rta, struct rtnexthop *rtnh,
- struct rtmsg *rtmsg, const union g_addr **src)
+_netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc,
+ const zebra_nhlfe_t *nhlfe, struct rtattr *rta,
+ struct rtnexthop *rtnh, struct rtmsg *rtmsg,
+ const union g_addr **src)
{
int bytelen;
uint8_t family;
family = NHLFE_FAMILY(nhlfe);
bytelen = (family == AF_INET ? 4 : 16);
- _netlink_route_build_multipath(routedesc, bytelen, nhlfe->nexthop, rta,
- rtnh, rtmsg, src);
+ _netlink_route_build_multipath(p, routedesc, bytelen, nhlfe->nexthop,
+ rta, rtnh, rtmsg, src);
}
@@ -1520,6 +1515,30 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
0);
}
+static bool nexthop_set_src(const struct nexthop *nexthop, int family,
+ union g_addr *src)
+{
+ if (family == AF_INET) {
+ if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) {
+ src->ipv4 = nexthop->rmap_src.ipv4;
+ return true;
+ } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) {
+ src->ipv4 = nexthop->src.ipv4;
+ return true;
+ }
+ } else if (family == AF_INET6) {
+ if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) {
+ src->ipv6 = nexthop->rmap_src.ipv6;
+ return true;
+ } else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) {
+ src->ipv6 = nexthop->src.ipv6;
+ return true;
+ }
+ }
+
+ return false;
+}
+
/*
* Routing table change via netlink interface, using a dataplane context object
*/
@@ -1530,7 +1549,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
unsigned int nexthop_num;
int family;
const char *routedesc;
- int setsrc = 0;
+ bool setsrc = false;
union g_addr src;
const struct prefix *p, *src_p;
uint32_t table_id;
@@ -1647,8 +1666,29 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
if (kernel_nexthops_supported()) {
/* Kernel supports nexthop objects */
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "netlink_route_multipath(): %pFX nhg_id is %u",
+ p, dplane_ctx_get_nhe_id(ctx));
addattr32(&req.n, sizeof(req), RTA_NH_ID,
dplane_ctx_get_nhe_id(ctx));
+
+ /* Have to determine src still */
+ for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
+ if (setsrc)
+ break;
+
+ setsrc = nexthop_set_src(nexthop, family, &src);
+ }
+
+ if (setsrc) {
+ if (family == AF_INET)
+ addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
+ &src.ipv4, bytelen);
+ else if (family == AF_INET6)
+ addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
+ &src.ipv6, bytelen);
+ }
goto skip;
}
@@ -1696,32 +1736,8 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
if (setsrc)
continue;
- if (family == AF_INET) {
- if (nexthop->rmap_src.ipv4.s_addr
- != 0) {
- src.ipv4 =
- nexthop->rmap_src.ipv4;
- setsrc = 1;
- } else if (nexthop->src.ipv4.s_addr
- != 0) {
- src.ipv4 =
- nexthop->src.ipv4;
- setsrc = 1;
- }
- } else if (family == AF_INET6) {
- if (!IN6_IS_ADDR_UNSPECIFIED(
- &nexthop->rmap_src.ipv6)) {
- src.ipv6 =
- nexthop->rmap_src.ipv6;
- setsrc = 1;
- } else if (
- !IN6_IS_ADDR_UNSPECIFIED(
- &nexthop->src.ipv6)) {
- src.ipv6 =
- nexthop->src.ipv6;
- setsrc = 1;
- }
- }
+ setsrc = nexthop_set_src(nexthop, family, &src);
+
continue;
}
@@ -1732,13 +1748,13 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
: "single-path";
_netlink_route_build_singlepath(
- routedesc, bytelen, nexthop, &req.n,
+ p, routedesc, bytelen, nexthop, &req.n,
&req.r, sizeof(req), cmd);
nexthop_num++;
break;
}
}
- if (setsrc && (cmd == RTM_NEWROUTE)) {
+ if (setsrc) {
if (family == AF_INET)
addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
&src.ipv4, bytelen);
@@ -1764,32 +1780,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
if (setsrc)
continue;
- if (family == AF_INET) {
- if (nexthop->rmap_src.ipv4.s_addr
- != 0) {
- src.ipv4 =
- nexthop->rmap_src.ipv4;
- setsrc = 1;
- } else if (nexthop->src.ipv4.s_addr
- != 0) {
- src.ipv4 =
- nexthop->src.ipv4;
- setsrc = 1;
- }
- } else if (family == AF_INET6) {
- if (!IN6_IS_ADDR_UNSPECIFIED(
- &nexthop->rmap_src.ipv6)) {
- src.ipv6 =
- nexthop->rmap_src.ipv6;
- setsrc = 1;
- } else if (
- !IN6_IS_ADDR_UNSPECIFIED(
- &nexthop->src.ipv6)) {
- src.ipv6 =
- nexthop->src.ipv6;
- setsrc = 1;
- }
- }
+ setsrc = nexthop_set_src(nexthop, family, &src);
continue;
}
@@ -1802,8 +1793,8 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
nexthop_num++;
_netlink_route_build_multipath(
- routedesc, bytelen, nexthop, rta, rtnh,
- &req.r, &src1);
+ p, routedesc, bytelen, nexthop, rta,
+ rtnh, &req.r, &src1);
rtnh = RTNH_NEXT(rtnh);
if (!setsrc && src1) {
@@ -1816,7 +1807,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
}
}
}
- if (setsrc && (cmd == RTM_NEWROUTE)) {
+ if (setsrc) {
if (family == AF_INET)
addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
&src.ipv4, bytelen);
@@ -1991,6 +1982,12 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
addattr32(&req.n, req_size, NHA_ID, id);
if (cmd == RTM_NEWNEXTHOP) {
+ /*
+ * We distinguish between a "group", which is a collection
+ * of ids, and a singleton nexthop with an id. The
+ * group is installed as an id that just refers to a list of
+ * other ids.
+ */
if (dplane_ctx_get_nhe_nh_grp_count(ctx))
_netlink_nexthop_build_group(
&req.n, req_size, id,
@@ -2077,14 +2074,13 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
}
}
- nexthop_done:
- if (IS_ZEBRA_DEBUG_KERNEL) {
- char buf[NEXTHOP_STRLEN];
+nexthop_done:
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: ID (%u): %pNHv (%u) %s ",
+ __func__, id, nh, nh->vrf_id,
+ label_buf);
- snprintfrr(buf, sizeof(buf), "%pNHv", nh);
- zlog_debug("%s: ID (%u): %s (%u) %s ", __func__,
- id, buf, nh->vrf_id, label_buf);
- }
}
req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx));
@@ -2112,43 +2108,19 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
*/
enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
{
+ enum dplane_op_e op;
int cmd = 0;
int ret = 0;
- switch (dplane_ctx_get_op(ctx)) {
- case DPLANE_OP_NH_DELETE:
- cmd = RTM_DELNEXTHOP;
- break;
- case DPLANE_OP_NH_INSTALL:
- case DPLANE_OP_NH_UPDATE:
+ op = dplane_ctx_get_op(ctx);
+ if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE)
cmd = RTM_NEWNEXTHOP;
- break;
- case DPLANE_OP_ROUTE_INSTALL:
- case DPLANE_OP_ROUTE_UPDATE:
- case DPLANE_OP_ROUTE_DELETE:
- case DPLANE_OP_ROUTE_NOTIFY:
- case DPLANE_OP_LSP_INSTALL:
- case DPLANE_OP_LSP_UPDATE:
- case DPLANE_OP_LSP_DELETE:
- case DPLANE_OP_LSP_NOTIFY:
- case DPLANE_OP_PW_INSTALL:
- case DPLANE_OP_PW_UNINSTALL:
- case DPLANE_OP_SYS_ROUTE_ADD:
- case DPLANE_OP_SYS_ROUTE_DELETE:
- case DPLANE_OP_ADDR_INSTALL:
- case DPLANE_OP_ADDR_UNINSTALL:
- case DPLANE_OP_MAC_INSTALL:
- case DPLANE_OP_MAC_DELETE:
- case DPLANE_OP_NEIGH_INSTALL:
- case DPLANE_OP_NEIGH_UPDATE:
- case DPLANE_OP_NEIGH_DELETE:
- case DPLANE_OP_VTEP_ADD:
- case DPLANE_OP_VTEP_DELETE:
- case DPLANE_OP_NONE:
- flog_err(
- EC_ZEBRA_NHG_FIB_UPDATE,
- "Context received for kernel nexthop update with incorrect OP code (%u)",
- dplane_ctx_get_op(ctx));
+ else if (op == DPLANE_OP_NH_DELETE)
+ cmd = RTM_DELNEXTHOP;
+ else {
+ flog_err(EC_ZEBRA_NHG_FIB_UPDATE,
+ "Context received for kernel nexthop update with incorrect OP code (%u)",
+ op);
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
@@ -2677,7 +2649,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
if (filter_vlan && vid != filter_vlan) {
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("\tFiltered due to filter vlan: %d",
+ zlog_debug(" Filtered due to filter vlan: %d",
filter_vlan);
return 0;
}
@@ -2691,8 +2663,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
/* Drop "permanent" entries. */
if (ndm->ndm_state & NUD_PERMANENT) {
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("\tDropping entry because of NUD_PERMANENT");
- return 0;
+ zlog_debug(
+ " Dropping entry because of NUD_PERMANENT");
+ return 0;
}
if (IS_ZEBRA_IF_VXLAN(ifp))
@@ -3466,6 +3439,7 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
unsigned int nexthop_num;
const char *routedesc;
int route_type;
+ struct prefix p = {0};
struct {
struct nlmsghdr n;
@@ -3552,8 +3526,7 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
NEXTHOP_FLAG_FIB)))) {
/* Add the gateway */
_netlink_mpls_build_singlepath(
- routedesc, nhlfe,
- &req.n, &req.r,
+ &p, routedesc, nhlfe, &req.n, &req.r,
sizeof(req), cmd);
nexthop_num++;
@@ -3593,9 +3566,9 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
nexthop_num++;
/* Build the multipath */
- _netlink_mpls_build_multipath(routedesc, nhlfe,
- rta, rtnh, &req.r,
- &src1);
+ _netlink_mpls_build_multipath(&p, routedesc,
+ nhlfe, rta, rtnh,
+ &req.r, &src1);
rtnh = RTNH_NEXT(rtnh);
}
}
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 60ac471b5a..a22e39dc48 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -204,9 +204,12 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
}
/* Logging of packet. */
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("%s(%u): Tx RA, socket %u", ifp->name, ifp->ifindex,
- sock);
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug("%s(%s:%u): Tx RA, socket %u", ifp->name,
+ VRF_LOGNAME(vrf), ifp->ifindex, sock);
+ }
/* Fill in sockaddr_in6. */
memset(&addr, 0, sizeof(struct sockaddr_in6));
@@ -333,16 +336,6 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
IPV6_ADDR_COPY(&pinfo->nd_opt_pi_prefix,
&rprefix->prefix.prefix);
-#ifdef DEBUG
- {
- uint8_t buf[INET6_ADDRSTRLEN];
-
- zlog_debug("DEBUG %s",
- inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
- buf, INET6_ADDRSTRLEN));
- }
-#endif /* DEBUG */
-
len += sizeof(struct nd_opt_prefix_info);
}
@@ -388,9 +381,11 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr);
if (len + opt_len > max_len) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
zlog_warn(
- "%s(%u): Tx RA: RDNSS option would exceed MTU, omitting it",
- ifp->name, ifp->ifindex);
+ "%s(%s:%u): Tx RA: RDNSS option would exceed MTU, omitting it",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex);
goto no_more_opts;
}
struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len);
@@ -510,10 +505,17 @@ static int rtadv_timer(struct thread *thread)
<= 0)
zif->rtadv.inFastRexmit = 0;
- if (IS_ZEBRA_DEBUG_SEND)
+ if (IS_ZEBRA_DEBUG_SEND) {
+ struct vrf *vrf =
+ vrf_lookup_by_id(
+ ifp->vrf_id);
+
zlog_debug(
- "Fast RA Rexmit on interface %s",
- ifp->name);
+ "Fast RA Rexmit on interface %s(%s:%u)",
+ ifp->name,
+ VRF_LOGNAME(vrf),
+ ifp->ifindex);
+ }
rtadv_send_packet(rtadv_get_socket(zvrf),
ifp, RA_ENABLE);
@@ -612,9 +614,14 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
if (len < sizeof(struct nd_router_advert)) {
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("%s(%u): Rx RA with invalid length %d from %s",
- ifp->name, ifp->ifindex, len, addr_str);
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug(
+ "%s(%s:%u): Rx RA with invalid length %d from %s",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, len,
+ addr_str);
+ }
return;
}
@@ -622,9 +629,14 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
rtadv_process_optional(msg + sizeof(struct nd_router_advert),
len - sizeof(struct nd_router_advert),
ifp, addr);
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("%s(%u): Rx RA with non-linklocal source address from %s",
- ifp->name, ifp->ifindex, addr_str);
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug(
+ "%s(%s:%u): Rx RA with non-linklocal source address from %s",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex,
+ addr_str);
+ }
return;
}
@@ -703,9 +715,12 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len,
return;
}
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("%s(%u): Rx RA/RS len %d from %s", ifp->name,
- ifp->ifindex, len, addr_str);
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug("%s(%s:%u): Rx RA/RS len %d from %s", ifp->name,
+ VRF_LOGNAME(vrf), ifp->ifindex, len, addr_str);
+ }
if (if_is_loopback(ifp)
|| CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))
@@ -718,8 +733,11 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len,
/* ICMP message length check. */
if (len < sizeof(struct icmp6_hdr)) {
- zlog_debug("%s(%u): Rx RA with Invalid ICMPV6 packet length %d",
- ifp->name, ifp->ifindex, len);
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug(
+ "%s(%s:%u): Rx RA with Invalid ICMPV6 packet length %d",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, len);
return;
}
@@ -728,15 +746,20 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len,
/* ICMP message type check. */
if (icmph->icmp6_type != ND_ROUTER_SOLICIT
&& icmph->icmp6_type != ND_ROUTER_ADVERT) {
- zlog_debug("%s(%u): Rx RA - Unwanted ICMPV6 message type %d",
- ifp->name, ifp->ifindex, icmph->icmp6_type);
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug("%s(%s:%u): Rx RA - Unwanted ICMPV6 message type %d",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex,
+ icmph->icmp6_type);
return;
}
/* Hoplimit check. */
if (hoplimit >= 0 && hoplimit != 255) {
- zlog_debug("%s(%u): Rx RA - Invalid hoplimit %d", ifp->name,
- ifp->ifindex, hoplimit);
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug("%s(%s:%u): Rx RA - Invalid hoplimit %d", ifp->name,
+ VRF_LOGNAME(vrf), ifp->ifindex, hoplimit);
return;
}
@@ -1055,25 +1078,34 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
unsigned int ra_interval = ra_interval_rxd;
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%u: IF %u RA %s from client %s, interval %ums",
- zvrf_id(zvrf), ifindex,
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s:%u: IF %u RA %s from client %s, interval %ums",
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
enable ? "enable" : "disable",
zebra_route_string(client->proto), ra_interval);
+ }
/* Locate interface and check VRF match. */
ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
if (!ifp) {
+ struct vrf *vrf = zvrf->vrf;
+
flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
- "%u: IF %u RA %s client %s - interface unknown",
- zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
+ "%s:%u: IF %u RA %s client %s - interface unknown",
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
+ enable ? "enable" : "disable",
zebra_route_string(client->proto));
return;
}
if (ifp->vrf_id != zvrf_id(zvrf)) {
+ struct vrf *vrf = zvrf->vrf;
+
zlog_debug(
- "%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
- zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
+ "%s:%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
+ enable ? "enable" : "disable",
zebra_route_string(client->proto), ifp->vrf_id);
return;
}
@@ -2329,6 +2361,13 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
{
struct rtadv *rtadv = &zvrf->rtadv;
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s(%s) with event: %d and val: %d", __func__,
+ VRF_LOGNAME(vrf), event, val);
+ }
+
switch (event) {
case RTADV_START:
thread_add_read(zrouter.master, rtadv_read, zvrf, val,
@@ -2371,20 +2410,26 @@ void rtadv_init(struct zebra_vrf *zvrf)
}
}
-void rtadv_terminate(struct zebra_vrf *zvrf)
+void rtadv_vrf_terminate(struct zebra_vrf *zvrf)
{
rtadv_event(zvrf, RTADV_STOP, 0);
if (zvrf->rtadv.sock >= 0) {
close(zvrf->rtadv.sock);
zvrf->rtadv.sock = -1;
- } else if (zrouter.rtadv_sock >= 0) {
- close(zrouter.rtadv_sock);
- zrouter.rtadv_sock = -1;
}
+
zvrf->rtadv.adv_if_count = 0;
zvrf->rtadv.adv_msec_if_count = 0;
}
+void rtadv_terminate(void)
+{
+ if (zrouter.rtadv_sock >= 0) {
+ close(zrouter.rtadv_sock);
+ zrouter.rtadv_sock = -1;
+ }
+}
+
void rtadv_cmd_init(void)
{
hook_register(zebra_if_extra_info, nd_dump_vty);
@@ -2445,10 +2490,13 @@ static int if_join_all_router(int sock, struct interface *ifp)
ifp->name, ifp->ifindex, sock,
safe_strerror(errno));
- if (IS_ZEBRA_DEBUG_EVENT)
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
zlog_debug(
- "%s(%u): Join All-Routers multicast group, socket %u",
- ifp->name, ifp->ifindex, sock);
+ "%s(%s:%u): Join All-Routers multicast group, socket %u",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock);
+ }
return 0;
}
@@ -2465,17 +2513,22 @@ static int if_leave_all_router(int sock, struct interface *ifp)
ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq,
sizeof(mreq));
- if (ret < 0)
+ if (ret < 0) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
flog_err_sys(
EC_LIB_SOCKET,
- "%s(%u): Failed to leave group, socket %u error %s",
- ifp->name, ifp->ifindex, sock, safe_strerror(errno));
+ "%s(%s:%u): Failed to leave group, socket %u error %s",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock,
+ safe_strerror(errno));
+ }
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug(
- "%s(%u): Leave All-Routers multicast group, socket %u",
- ifp->name, ifp->ifindex, sock);
-
+ "%s(%s:%u): Leave All-Routers multicast group, socket %u",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock);
+ }
return 0;
}
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 64b28cbfd6..68a5bbcdbe 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -153,7 +153,8 @@ typedef enum {
} ipv6_nd_suppress_ra_status;
extern void rtadv_init(struct zebra_vrf *zvrf);
-extern void rtadv_terminate(struct zebra_vrf *zvrf);
+extern void rtadv_vrf_terminate(struct zebra_vrf *zvrf);
+extern void rtadv_terminate(void);
extern void rtadv_stop_ra(struct interface *ifp);
extern void rtadv_stop_ra_all(void);
extern void rtadv_cmd_init(void);
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 1d49de5410..f281afce94 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -75,6 +75,7 @@ zebra_zebra_SOURCES = \
zebra/zebra_mlag.c \
zebra/zebra_mlag_vty.c \
zebra/zebra_l2.c \
+ zebra/zebra_northbound.c \
zebra/zebra_memory.c \
zebra/zebra_dplane.c \
zebra/zebra_mpls.c \
@@ -191,5 +192,10 @@ zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_dt.c
endif
endif
+nodist_zebra_zebra_SOURCES = \
+ yang/frr-nexthop.yang.c \
+ yang/frr-zebra.yang.c \
+ # end
+
zebra_zebra_cumulus_mlag_la_SOURCES = zebra/zebra_mlag_private.c
zebra_zebra_cumulus_mlag_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index f1c181438e..aabe533ee6 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -383,9 +383,14 @@ static void zebra_interface_nbr_address_add_update(struct interface *ifp,
p->prefixlen, ifc->ifp->name);
}
- for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_ADD,
client, ifp, ifc);
+ }
}
/* Interface address deletion. */
@@ -407,9 +412,14 @@ static void zebra_interface_nbr_address_delete_update(struct interface *ifp,
p->prefixlen, ifc->ifp->name);
}
- for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_DELETE,
client, ifp, ifc);
+ }
}
/* Send addresses on interface to client */
@@ -1063,7 +1073,7 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
if (IS_ZEBRA_DEBUG_NHT)
zlog_debug(
- "rnh_register msg from client %s: hdr->length=%d, type=%s vrf=%u\n",
+ "rnh_register msg from client %s: hdr->length=%d, type=%s vrf=%u",
zebra_route_string(client->proto), hdr->length,
(type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route",
zvrf->vrf->vrf_id);
@@ -1152,7 +1162,7 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS)
if (IS_ZEBRA_DEBUG_NHT)
zlog_debug(
- "rnh_unregister msg from client %s: hdr->length=%d vrf: %u\n",
+ "rnh_unregister msg from client %s: hdr->length=%d vrf: %u",
zebra_route_string(client->proto), hdr->length,
zvrf->vrf->vrf_id);
@@ -1403,6 +1413,132 @@ void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
}
}
+/*
+ * Create a new nexthop based on a zapi nexthop.
+ */
+static struct nexthop *nexthop_from_zapi(struct route_entry *re,
+ const struct zapi_nexthop *api_nh,
+ const struct zapi_route *api)
+{
+ struct nexthop *nexthop = NULL;
+ struct ipaddr vtep_ip;
+ struct interface *ifp;
+ char nhbuf[INET6_ADDRSTRLEN] = "";
+
+ switch (api_nh->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ nexthop = nexthop_from_ifindex(api_nh->ifindex, api_nh->vrf_id);
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
+ sizeof(nhbuf));
+ zlog_debug("%s: nh=%s, vrf_id=%d", __func__,
+ nhbuf, api_nh->vrf_id);
+ }
+ nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4, NULL,
+ api_nh->vrf_id);
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
+ sizeof(nhbuf));
+ zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d",
+ __func__, nhbuf, api_nh->vrf_id,
+ api_nh->ifindex);
+ }
+
+ nexthop = nexthop_from_ipv4_ifindex(
+ &api_nh->gate.ipv4, NULL, api_nh->ifindex,
+ api_nh->vrf_id);
+
+ ifp = if_lookup_by_index(api_nh->ifindex, api_nh->vrf_id);
+ if (ifp && connected_is_unnumbered(ifp))
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
+
+ /* Special handling for IPv4 routes sourced from EVPN:
+ * the nexthop and associated MAC need to be installed.
+ */
+ if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+ memset(&vtep_ip, 0, sizeof(struct ipaddr));
+ vtep_ip.ipa_type = IPADDR_V4;
+ memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4),
+ sizeof(struct in_addr));
+ zebra_vxlan_evpn_vrf_route_add(
+ api_nh->vrf_id, &api_nh->rmac,
+ &vtep_ip, &api->prefix);
+ }
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf,
+ sizeof(nhbuf));
+ zlog_debug("%s: nh=%s, vrf_id=%d", __func__,
+ nhbuf, api_nh->vrf_id);
+ }
+ nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6, api_nh->vrf_id);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf,
+ sizeof(nhbuf));
+ zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d",
+ __func__, nhbuf, api_nh->vrf_id,
+ api_nh->ifindex);
+ }
+ nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6,
+ api_nh->ifindex,
+ api_nh->vrf_id);
+
+ /* Special handling for IPv6 routes sourced from EVPN:
+ * the nexthop and associated MAC need to be installed.
+ */
+ if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+ memset(&vtep_ip, 0, sizeof(struct ipaddr));
+ vtep_ip.ipa_type = IPADDR_V6;
+ memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
+ sizeof(struct in6_addr));
+ zebra_vxlan_evpn_vrf_route_add(
+ api_nh->vrf_id, &api_nh->rmac,
+ &vtep_ip, &api->prefix);
+ }
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: nh blackhole %d",
+ __func__, api_nh->bh_type);
+
+ nexthop = nexthop_from_blackhole(api_nh->bh_type);
+ break;
+ }
+
+ /* Return early if we couldn't process the zapi nexthop */
+ if (nexthop == NULL) {
+ goto done;
+ }
+
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK))
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
+
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT))
+ nexthop->weight = api_nh->weight;
+
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
+ if (api_nh->backup_idx < api->backup_nexthop_num) {
+ /* Capture backup info */
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ nexthop->backup_idx = api_nh->backup_idx;
+ } else {
+ /* Warn about invalid backup index */
+ if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: invalid backup nh idx %d",
+ __func__, api_nh->backup_idx);
+ }
+ }
+done:
+ return nexthop;
+}
+
static void zread_route_add(ZAPI_HANDLER_ARGS)
{
struct stream *s;
@@ -1411,12 +1547,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
afi_t afi;
struct prefix_ipv6 *src_p = NULL;
struct route_entry *re;
- struct nexthop *nexthop = NULL;
+ struct nexthop *nexthop = NULL, *last_nh;
struct nexthop_group *ng = NULL;
+ struct nhg_backup_info *bnhg = NULL;
int i, ret;
vrf_id_t vrf_id;
- struct ipaddr vtep_ip;
- struct interface *ifp;
+ struct nhg_hash_entry nhe;
+ enum lsp_types_t label_type;
+ char nhbuf[NEXTHOP_STRLEN];
+ char labelbuf[MPLS_LABEL_STRLEN];
s = msg;
if (zapi_route_decode(s, &api) < 0) {
@@ -1430,8 +1569,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
char buf_prefix[PREFIX_STRLEN];
prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
- zlog_debug("%s: p=%s, flags=0x%x",
- __func__, buf_prefix, api.flags);
+ zlog_debug("%s: p=%s, msg flags=0x%x, flags=0x%x",
+ __func__, buf_prefix, (int)api.message, api.flags);
}
/* Allocate new route. */
@@ -1459,6 +1598,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
return;
}
+ /* Report misuse of the backup flag */
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS) &&
+ api.backup_nexthop_num == 0) {
+ if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: client %s: BACKUP flag set but no backup nexthops, prefix %pFX",
+ __func__,
+ zebra_route_string(client->proto), &api.prefix);
+ }
+
/* Use temporary list of nexthops */
ng = nexthop_group_new();
@@ -1469,130 +1617,138 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
*/
for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i];
- ifindex_t ifindex = 0;
- nexthop = NULL;
+ /* Convert zapi nexthop */
+ nexthop = nexthop_from_zapi(re, api_nh, &api);
+ if (!nexthop) {
+ flog_warn(
+ EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Nexthops Specified: %d but we failed to properly create one",
+ __func__, api.nexthop_num);
+ nexthop_group_delete(&ng);
+ XFREE(MTYPE_RE, re);
+ return;
+ }
- if (IS_ZEBRA_DEBUG_RECV)
- zlog_debug("nh type %d", api_nh->type);
+ /* MPLS labels for BGP-LU or Segment Routing */
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
+ && api_nh->type != NEXTHOP_TYPE_IFINDEX
+ && api_nh->type != NEXTHOP_TYPE_BLACKHOLE
+ && api_nh->label_num > 0) {
- switch (api_nh->type) {
- case NEXTHOP_TYPE_IFINDEX:
- nexthop = nexthop_from_ifindex(api_nh->ifindex,
- api_nh->vrf_id);
- break;
- case NEXTHOP_TYPE_IPV4:
- if (IS_ZEBRA_DEBUG_RECV) {
- char nhbuf[INET6_ADDRSTRLEN] = {0};
+ label_type = lsp_type_from_re_type(client->proto);
+ nexthop_add_labels(nexthop, label_type,
+ api_nh->label_num,
+ &api_nh->labels[0]);
+ }
- inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
- INET6_ADDRSTRLEN);
- zlog_debug("%s: nh=%s, vrf_id=%d", __func__,
- nhbuf, api_nh->vrf_id);
- }
- nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4,
- NULL, api_nh->vrf_id);
- break;
- case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ labelbuf[0] = '\0';
+ nhbuf[0] = '\0';
- memset(&vtep_ip, 0, sizeof(struct ipaddr));
- ifindex = api_nh->ifindex;
- if (IS_ZEBRA_DEBUG_RECV) {
- char nhbuf[INET6_ADDRSTRLEN] = {0};
+ nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
- inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
- INET6_ADDRSTRLEN);
- zlog_debug(
- "%s: nh=%s, vrf_id=%d (re->vrf_id=%d), ifindex=%d",
- __func__, nhbuf, api_nh->vrf_id,
- re->vrf_id, ifindex);
+ if (nexthop->nh_label &&
+ nexthop->nh_label->num_labels > 0) {
+ mpls_label2str(nexthop->nh_label->num_labels,
+ nexthop->nh_label->label,
+ labelbuf, sizeof(labelbuf),
+ false);
}
- nexthop = nexthop_from_ipv4_ifindex(
- &api_nh->gate.ipv4, NULL, ifindex,
- api_nh->vrf_id);
-
- ifp = if_lookup_by_index(ifindex, api_nh->vrf_id);
- if (ifp && connected_is_unnumbered(ifp))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
- /* Special handling for IPv4 routes sourced from EVPN:
- * the nexthop and associated MAC need to be installed.
- */
- if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
- vtep_ip.ipa_type = IPADDR_V4;
- memcpy(&(vtep_ip.ipaddr_v4),
- &(api_nh->gate.ipv4),
- sizeof(struct in_addr));
- zebra_vxlan_evpn_vrf_route_add(
- api_nh->vrf_id, &api_nh->rmac,
- &vtep_ip, &api.prefix);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6,
- api_nh->vrf_id);
- break;
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- memset(&vtep_ip, 0, sizeof(struct ipaddr));
- ifindex = api_nh->ifindex;
- nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6,
- ifindex,
- api_nh->vrf_id);
-
- /* Special handling for IPv6 routes sourced from EVPN:
- * the nexthop and associated MAC need to be installed.
- */
- if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
- vtep_ip.ipa_type = IPADDR_V6;
- memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
- sizeof(struct in6_addr));
- zebra_vxlan_evpn_vrf_route_add(
- api_nh->vrf_id, &api_nh->rmac,
- &vtep_ip, &api.prefix);
- }
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- nexthop = nexthop_from_blackhole(api_nh->bh_type);
- break;
+
+ zlog_debug("%s: nh=%s, vrf_id=%d %s",
+ __func__, nhbuf, api_nh->vrf_id, labelbuf);
}
+ /* Add new nexthop to temporary list. This list is
+ * canonicalized - sorted - so that it can be hashed later
+ * in route processing. We expect that the sender has sent
+ * the list sorted, and the zapi client api attempts to enforce
+ * that, so this should be inexpensive - but it is necessary
+ * to support shared nexthop-groups.
+ */
+ nexthop_group_add_sorted(ng, nexthop);
+ }
+
+ /* Allocate temporary list of backup nexthops, if necessary */
+ if (api.backup_nexthop_num > 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: adding %d backup nexthops",
+ __func__, api.backup_nexthop_num);
+
+ bnhg = zebra_nhg_backup_alloc();
+ nexthop = NULL;
+ last_nh = NULL;
+ }
+
+ /* Copy backup nexthops also, if present */
+ for (i = 0; i < api.backup_nexthop_num; i++) {
+ api_nh = &api.backup_nexthops[i];
+
+ /* Convert zapi backup nexthop */
+ nexthop = nexthop_from_zapi(re, api_nh, &api);
if (!nexthop) {
flog_warn(
EC_ZEBRA_NEXTHOP_CREATION_FAILED,
- "%s: Nexthops Specified: %d but we failed to properly create one",
- __func__, api.nexthop_num);
+ "%s: Backup Nexthops Specified: %d but we failed to properly create one",
+ __func__, api.backup_nexthop_num);
nexthop_group_delete(&ng);
+ zebra_nhg_backup_free(&bnhg);
XFREE(MTYPE_RE, re);
return;
}
- if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
-
- if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT))
- nexthop->weight = api_nh->weight;
+ /* Backup nexthops can't have backups; that's not valid. */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ if (IS_ZEBRA_DEBUG_RECV) {
+ nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
+ zlog_debug("%s: backup nh %s with BACKUP flag!",
+ __func__, nhbuf);
+ }
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ nexthop->backup_idx = 0;
+ }
/* MPLS labels for BGP-LU or Segment Routing */
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
&& api_nh->type != NEXTHOP_TYPE_IFINDEX
- && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) {
- enum lsp_types_t label_type;
+ && api_nh->type != NEXTHOP_TYPE_BLACKHOLE
+ && api_nh->label_num > 0) {
label_type = lsp_type_from_re_type(client->proto);
-
- if (IS_ZEBRA_DEBUG_RECV) {
- zlog_debug(
- "%s: adding %d labels of type %d (1st=%u)",
- __func__, api_nh->label_num, label_type,
- api_nh->labels[0]);
- }
-
nexthop_add_labels(nexthop, label_type,
api_nh->label_num,
&api_nh->labels[0]);
}
- /* Add new nexthop to temporary list */
- nexthop_group_add_sorted(ng, nexthop);
+ if (IS_ZEBRA_DEBUG_RECV) {
+ labelbuf[0] = '\0';
+ nhbuf[0] = '\0';
+
+ nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
+
+ if (nexthop->nh_label &&
+ nexthop->nh_label->num_labels > 0) {
+ mpls_label2str(nexthop->nh_label->num_labels,
+ nexthop->nh_label->label,
+ labelbuf, sizeof(labelbuf),
+ false);
+ }
+
+ zlog_debug("%s: backup nh=%s, vrf_id=%d %s",
+ __func__, nhbuf, api_nh->vrf_id, labelbuf);
+ }
+
+ /* Note that the order of the backup nexthops is significant,
+ * so we don't sort this list as we do the primary nexthops,
+ * we just append.
+ */
+ if (last_nh)
+ NEXTHOP_APPEND(last_nh, nexthop);
+ else
+ bnhg->nhe->nhg.nexthop = nexthop;
+
+ last_nh = nexthop;
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
@@ -1610,6 +1766,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
"%s: Received SRC Prefix but afi is not v6",
__func__);
nexthop_group_delete(&ng);
+ zebra_nhg_backup_free(&bnhg);
XFREE(MTYPE_RE, re);
return;
}
@@ -1621,10 +1778,28 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
"%s: Received safi: %d but we can only accept UNICAST or MULTICAST",
__func__, api.safi);
nexthop_group_delete(&ng);
+ zebra_nhg_backup_free(&bnhg);
XFREE(MTYPE_RE, re);
return;
}
- ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re, ng);
+
+ /* Include backup info with the route. We use a temporary nhe here;
+ * if this is a new/unknown nhe, a new copy will be allocated
+ * and stored.
+ */
+ zebra_nhe_init(&nhe, afi, ng->nexthop);
+ nhe.nhg.nexthop = ng->nexthop;
+ nhe.backup_info = bnhg;
+ ret = rib_add_multipath_nhe(afi, api.safi, &api.prefix, src_p,
+ re, &nhe);
+
+ /* At this point, these allocations are not needed: 're' has been
+ * retained or freed, and if 're' still exists, it is using
+ * a reference to a shared group object.
+ */
+ nexthop_group_delete(&ng);
+ if (bnhg)
+ zebra_nhg_backup_free(&bnhg);
/* Stats */
switch (api.prefix.family) {
@@ -1740,6 +1915,10 @@ void zsend_capabilities_all_clients(void)
zvrf = vrf_info_lookup(VRF_DEFAULT);
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
zsend_capabilities(client, zvrf);
}
}
@@ -1751,13 +1930,18 @@ static void zread_hello(ZAPI_HANDLER_ARGS)
uint8_t proto;
unsigned short instance;
uint8_t notify;
+ uint8_t synchronous;
STREAM_GETC(msg, proto);
STREAM_GETW(msg, instance);
STREAM_GETC(msg, notify);
+ STREAM_GETC(msg, synchronous);
if (notify)
client->notify_owner = true;
+ if (synchronous)
+ client->synchronous = true;
+
/* accept only dynamic routing protocols */
if ((proto < ZEBRA_ROUTE_MAX) && (proto > ZEBRA_ROUTE_CONNECT)) {
zlog_notice(
@@ -1774,8 +1958,10 @@ static void zread_hello(ZAPI_HANDLER_ARGS)
zebra_gr_client_reconnect(client);
}
- zsend_capabilities(client, zvrf);
- zebra_vrf_update_all(client);
+ if (!client->synchronous) {
+ zsend_capabilities(client, zvrf);
+ zebra_vrf_update_all(client);
+ }
stream_failure:
return;
}
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 459d2bc620..a2365ee76b 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -113,10 +113,15 @@ struct dplane_route_info {
struct dplane_nexthop_info nhe;
/* Nexthops */
+ uint32_t zd_nhg_id;
struct nexthop_group zd_ng;
+ /* Backup nexthops (if present) */
+ struct nexthop_group backup_ng;
+
/* "Previous" nexthops, used only in route updates without netlink */
struct nexthop_group zd_old_ng;
+ struct nexthop_group old_backup_ng;
/* TODO -- use fixed array of nexthops, to avoid mallocs? */
@@ -472,6 +477,14 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
(*pctx)->u.rinfo.zd_ng.nexthop = NULL;
}
+ /* Free backup info also (if present) */
+ if ((*pctx)->u.rinfo.backup_ng.nexthop) {
+ /* This deals with recursive nexthops too */
+ nexthops_free((*pctx)->u.rinfo.backup_ng.nexthop);
+
+ (*pctx)->u.rinfo.backup_ng.nexthop = NULL;
+ }
+
if ((*pctx)->u.rinfo.zd_old_ng.nexthop) {
/* This deals with recursive nexthops too */
nexthops_free((*pctx)->u.rinfo.zd_old_ng.nexthop);
@@ -479,6 +492,13 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
(*pctx)->u.rinfo.zd_old_ng.nexthop = NULL;
}
+ if ((*pctx)->u.rinfo.old_backup_ng.nexthop) {
+ /* This deals with recursive nexthops too */
+ nexthops_free((*pctx)->u.rinfo.old_backup_ng.nexthop);
+
+ (*pctx)->u.rinfo.old_backup_ng.nexthop = NULL;
+ }
+
break;
case DPLANE_OP_NH_INSTALL:
@@ -1038,6 +1058,12 @@ void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
nexthop_group_copy_nh_sorted(&(ctx->u.rinfo.zd_ng), nh);
}
+uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.zd_nhg_id;
+}
+
const struct nexthop_group *dplane_ctx_get_ng(
const struct zebra_dplane_ctx *ctx)
{
@@ -1046,14 +1072,30 @@ const struct nexthop_group *dplane_ctx_get_ng(
return &(ctx->u.rinfo.zd_ng);
}
-const struct nexthop_group *dplane_ctx_get_old_ng(
- const struct zebra_dplane_ctx *ctx)
+const struct nexthop_group *
+dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rinfo.backup_ng);
+}
+
+const struct nexthop_group *
+dplane_ctx_get_old_ng(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
return &(ctx->u.rinfo.zd_old_ng);
}
+const struct nexthop_group *
+dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rinfo.old_backup_ng);
+}
+
const struct zebra_dplane_info *dplane_ctx_get_ns(
const struct zebra_dplane_ctx *ctx)
{
@@ -1514,6 +1556,13 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
/* Copy nexthops; recursive info is included too */
copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop),
re->nhe->nhg.nexthop, NULL);
+ ctx->u.rinfo.zd_nhg_id = re->nhe->id;
+
+ /* Copy backup nexthop info, if present */
+ if (re->nhe->backup_info && re->nhe->backup_info->nhe) {
+ copy_nexthops(&(ctx->u.rinfo.backup_ng.nexthop),
+ re->nhe->backup_info->nhe->nhg.nexthop, NULL);
+ }
/* Ensure that the dplane nexthops' flags are clear. */
for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop))
@@ -1532,9 +1581,8 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
#ifdef HAVE_NETLINK
- if (re->nhe_id) {
- struct nhg_hash_entry *nhe =
- zebra_nhg_resolve(zebra_nhg_lookup_id(re->nhe_id));
+ if (re->nhe) {
+ struct nhg_hash_entry *nhe = zebra_nhg_resolve(re->nhe);
ctx->u.rinfo.nhe.id = nhe->id;
/*
@@ -1581,7 +1629,6 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx,
{
struct zebra_vrf *zvrf = NULL;
struct zebra_ns *zns = NULL;
-
int ret = EINVAL;
if (!ctx || !nhe)
@@ -1850,6 +1897,17 @@ dplane_route_update_internal(struct route_node *rn,
*/
copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
old_re->nhe->nhg.nexthop, NULL);
+
+ if (zebra_nhg_get_backup_nhg(old_re->nhe) != NULL) {
+ struct nexthop_group *nhg;
+ struct nexthop **nh;
+
+ nhg = zebra_nhg_get_backup_nhg(old_re->nhe);
+ nh = &(ctx->u.rinfo.old_backup_ng.nexthop);
+
+ if (nhg->nexthop)
+ copy_nexthops(nh, nhg->nexthop, NULL);
+ }
#endif /* !HAVE_NETLINK */
}
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index c0b04e71b0..9ce4df197c 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -270,11 +270,19 @@ 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);
void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh);
+
+uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx);
const struct nexthop_group *dplane_ctx_get_ng(
const struct zebra_dplane_ctx *ctx);
const struct nexthop_group *dplane_ctx_get_old_ng(
const struct zebra_dplane_ctx *ctx);
+/* Backup nexthop information (list of nexthops) if present. */
+const struct nexthop_group *
+dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx);
+const struct nexthop_group *
+dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx);
+
/* Accessors for nexthop information */
uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx);
afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx);
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index d373fdf370..999e91486d 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -98,14 +98,14 @@ static void lsp_free(struct hash *lsp_table, zebra_lsp_t **plsp);
static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size);
static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
- enum nexthop_types_t gtype, union g_addr *gate,
- ifindex_t ifindex);
+ enum nexthop_types_t gtype,
+ const union g_addr *gate, ifindex_t ifindex);
static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
- enum nexthop_types_t gtype, union g_addr *gate,
- ifindex_t ifindex, uint8_t num_labels,
- mpls_label_t *labels);
+ enum nexthop_types_t gtype,
+ const union g_addr *gate, ifindex_t ifindex,
+ uint8_t num_labels, mpls_label_t *labels);
static int nhlfe_del(zebra_nhlfe_t *snhlfe);
static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
struct mpls_label_stack *nh_label);
@@ -117,13 +117,13 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty);
static void lsp_print(zebra_lsp_t *lsp, void *ctxt);
static void *slsp_alloc(void *p);
static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex,
+ const union g_addr *gate, ifindex_t ifindex,
mpls_label_t out_label);
static int snhlfe_del(zebra_snhlfe_t *snhlfe);
static int snhlfe_del_all(zebra_slsp_t *slsp);
@@ -960,7 +960,7 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
/* We leave the INSTALLED flag set here
- * so we know an update in in-flight.
+ * so we know an update is in-flight.
*/
/*
@@ -1149,7 +1149,7 @@ static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size)
* Check if NHLFE matches with search info passed.
*/
static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
struct nexthop *nhop;
int cmp = 1;
@@ -1191,8 +1191,8 @@ static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
* Locate NHLFE that matches with passed info.
*/
static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
- enum nexthop_types_t gtype, union g_addr *gate,
- ifindex_t ifindex)
+ enum nexthop_types_t gtype,
+ const union g_addr *gate, ifindex_t ifindex)
{
zebra_nhlfe_t *nhlfe;
@@ -1214,9 +1214,9 @@ static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
* check done.
*/
static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
- enum nexthop_types_t gtype, union g_addr *gate,
- ifindex_t ifindex, uint8_t num_labels,
- mpls_label_t labels[])
+ enum nexthop_types_t gtype,
+ const union g_addr *gate, ifindex_t ifindex,
+ uint8_t num_labels, mpls_label_t labels[])
{
zebra_nhlfe_t *nhlfe;
struct nexthop *nexthop;
@@ -1520,7 +1520,7 @@ static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
/*
* Compare two LSPs based on their label values.
*/
-static int lsp_cmp(zebra_lsp_t *lsp1, zebra_lsp_t *lsp2)
+static int lsp_cmp(const zebra_lsp_t *lsp1, const zebra_lsp_t *lsp2)
{
if (lsp1->ile.in_label < lsp2->ile.in_label)
return -1;
@@ -1547,7 +1547,7 @@ static void *slsp_alloc(void *p)
/*
* Compare two static LSPs based on their label values.
*/
-static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
+static int slsp_cmp(const zebra_slsp_t *slsp1, const zebra_slsp_t *slsp2)
{
if (slsp1->ile.in_label < slsp2->ile.in_label)
return -1;
@@ -1562,7 +1562,7 @@ static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
* Check if static NHLFE matches with search info passed.
*/
static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
int cmp = 1;
@@ -1593,7 +1593,7 @@ static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
*/
static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
zebra_snhlfe_t *snhlfe;
@@ -1615,7 +1615,7 @@ static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
*/
static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex,
+ const union g_addr *gate, ifindex_t ifindex,
mpls_label_t out_label)
{
zebra_snhlfe_t *snhlfe;
@@ -2746,7 +2746,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, uint8_t num_out_labels,
mpls_label_t out_labels[], enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
struct hash *lsp_table;
zebra_ile_t tmp_ile;
@@ -2759,11 +2759,12 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
if (!lsp_table)
return -1;
- /* If entry is present, exit. */
+ /* Find or create LSP object */
tmp_ile.in_label = in_label;
lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
if (!lsp)
return -1;
+
nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
if (nhlfe) {
struct nexthop *nh = nhlfe->nexthop;
@@ -2780,8 +2781,8 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
return 0;
if (IS_ZEBRA_DEBUG_MPLS) {
- char buf2[BUFSIZ];
- char buf3[BUFSIZ];
+ char buf2[MPLS_LABEL_STRLEN];
+ char buf3[MPLS_LABEL_STRLEN];
nhlfe2str(nhlfe, buf, BUFSIZ);
mpls_label2str(num_out_labels, out_labels, buf2,
@@ -2842,7 +2843,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
*/
int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
struct hash *lsp_table;
zebra_ile_t tmp_ile;
@@ -3056,11 +3057,12 @@ int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
if (!slsp_table)
return -1;
- /* If entry is present, exit. */
+ /* Find or create LSP. */
tmp_ile.in_label = in_label;
slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc);
if (!slsp)
return -1;
+
snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
if (snhlfe) {
if (snhlfe->out_label == out_label)
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index 2489e8e510..33cb614346 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -288,7 +288,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, uint8_t num_out_labels,
mpls_label_t out_labels[], enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
/*
* Uninstall a particular NHLFE in the forwarding table. If this is
@@ -296,7 +296,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
*/
int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
/*
* Uninstall all NHLFEs for a particular LSP forwarding entry.
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index f0d43756b5..fceddcb745 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -63,6 +63,9 @@ static struct nhg_hash_entry *
depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
static void depends_decrement_free(struct nhg_connected_tree_head *head);
+static struct nhg_backup_info *
+nhg_backup_copy(const struct nhg_backup_info *orig);
+
static void nhg_connected_free(struct nhg_connected *dep)
{
@@ -295,7 +298,7 @@ static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
static void
zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
- struct nhg_connected_tree_head nhg_depends)
+ struct nhg_connected_tree_head *nhg_depends)
{
struct nhg_connected *rb_node_dep = NULL;
@@ -304,31 +307,58 @@ zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
* for now. Otherwise, their might be a time trade-off for repeated
* alloc/frees as startup.
*/
- nhe->nhg_depends = nhg_depends;
+ nhe->nhg_depends = *nhg_depends;
/* Attach backpointer to anything that it depends on */
zebra_nhg_dependents_init(nhe);
if (!zebra_nhg_depends_is_empty(nhe)) {
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u), dep %p (%u)",
+ __func__, nhe, nhe->id,
+ rb_node_dep->nhe,
+ rb_node_dep->nhe->id);
+
zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
}
}
+}
- /* Add the ifp now if its not a group or recursive and has ifindex */
- if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg.nexthop
- && nhe->nhg.nexthop->ifindex) {
- struct interface *ifp = NULL;
+/* Init an nhe, for use in a hash lookup for example */
+void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
+ const struct nexthop *nh)
+{
+ memset(nhe, 0, sizeof(struct nhg_hash_entry));
+ nhe->vrf_id = VRF_DEFAULT;
+ nhe->type = ZEBRA_ROUTE_NHG;
+ nhe->afi = AFI_UNSPEC;
- ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex,
- nhe->nhg.nexthop->vrf_id);
- if (ifp)
- zebra_nhg_set_if(nhe, ifp);
- else
- flog_err(
- EC_ZEBRA_IF_LOOKUP_FAILED,
- "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
- nhe->nhg.nexthop->ifindex,
- nhe->nhg.nexthop->vrf_id, nhe->id);
+ /* There are some special rules that apply to groups representing
+ * a single nexthop.
+ */
+ if (nh && (nh->next == NULL)) {
+ switch (nh->type) {
+ case (NEXTHOP_TYPE_IFINDEX):
+ case (NEXTHOP_TYPE_BLACKHOLE):
+ /*
+ * This switch case handles setting the afi different
+ * for ipv4/v6 routes. Ifindex/blackhole nexthop
+ * objects cannot be ambiguous, they must be Address
+ * Family specific. If we get here, we will either use
+ * the AF of the route, or the one we got passed from
+ * here from the kernel.
+ */
+ nhe->afi = afi;
+ break;
+ case (NEXTHOP_TYPE_IPV4_IFINDEX):
+ case (NEXTHOP_TYPE_IPV4):
+ nhe->afi = AFI_IP;
+ break;
+ case (NEXTHOP_TYPE_IPV6_IFINDEX):
+ case (NEXTHOP_TYPE_IPV6):
+ nhe->afi = AFI_IP6;
+ break;
+ }
}
}
@@ -341,7 +371,7 @@ struct nhg_hash_entry *zebra_nhg_alloc(void)
return nhe;
}
-static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *copy,
+static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *orig,
uint32_t id)
{
struct nhg_hash_entry *nhe;
@@ -350,14 +380,18 @@ static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *copy,
nhe->id = id;
- nexthop_group_copy(&(nhe->nhg), &(copy->nhg));
+ nexthop_group_copy(&(nhe->nhg), &(orig->nhg));
- nhe->vrf_id = copy->vrf_id;
- nhe->afi = copy->afi;
- nhe->type = copy->type ? copy->type : ZEBRA_ROUTE_NHG;
+ nhe->vrf_id = orig->vrf_id;
+ nhe->afi = orig->afi;
+ nhe->type = orig->type ? orig->type : ZEBRA_ROUTE_NHG;
nhe->refcnt = 0;
nhe->dplane_ref = zebra_router_get_next_sequence();
+ /* Copy backup info also, if present */
+ if (orig->backup_info)
+ nhe->backup_info = nhg_backup_copy(orig->backup_info);
+
return nhe;
}
@@ -372,7 +406,25 @@ static void *zebra_nhg_hash_alloc(void *arg)
/* Mark duplicate nexthops in a group at creation time. */
nexthop_group_mark_duplicates(&(nhe->nhg));
- zebra_nhg_connect_depends(nhe, copy->nhg_depends);
+ zebra_nhg_connect_depends(nhe, &(copy->nhg_depends));
+
+ /* Add the ifp now if it's not a group or recursive and has ifindex */
+ if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg.nexthop
+ && nhe->nhg.nexthop->ifindex) {
+ struct interface *ifp = NULL;
+
+ ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex,
+ nhe->nhg.nexthop->vrf_id);
+ if (ifp)
+ zebra_nhg_set_if(nhe, ifp);
+ else
+ flog_err(
+ EC_ZEBRA_IF_LOOKUP_FAILED,
+ "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
+ nhe->nhg.nexthop->ifindex,
+ nhe->nhg.nexthop->vrf_id, nhe->id);
+ }
+
zebra_nhg_insert_id(nhe);
return nhe;
@@ -381,12 +433,17 @@ static void *zebra_nhg_hash_alloc(void *arg)
uint32_t zebra_nhg_hash_key(const void *arg)
{
const struct nhg_hash_entry *nhe = arg;
+ uint32_t val, key = 0x5a351234;
+
+ val = nexthop_group_hash(&(nhe->nhg));
+ if (nhe->backup_info) {
+ val = jhash_2words(val,
+ nexthop_group_hash(
+ &(nhe->backup_info->nhe->nhg)),
+ key);
+ }
- uint32_t key = 0x5a351234;
-
- key = jhash_3words(nhe->vrf_id, nhe->afi,
- nexthop_group_hash(&(nhe->nhg)),
- key);
+ key = jhash_3words(nhe->vrf_id, nhe->afi, val, key);
return key;
}
@@ -398,6 +455,50 @@ uint32_t zebra_nhg_id_key(const void *arg)
return nhe->id;
}
+/* Helper with common nhg/nhe nexthop comparison logic */
+static bool nhg_compare_nexthops(const struct nexthop *nh1,
+ const struct nexthop *nh2)
+{
+ if (nh1 && !nh2)
+ return false;
+
+ if (!nh1 && nh2)
+ return false;
+
+ /*
+ * We have to check the active flag of each individual one,
+ * not just the overall active_num. This solves the special case
+ * issue of a route with a nexthop group with one nexthop
+ * resolving to itself and thus marking it inactive. If we
+ * have two different routes each wanting to mark a different
+ * nexthop inactive, they need to hash to two different groups.
+ *
+ * If we just hashed on num_active, they would hash the same
+ * which is incorrect.
+ *
+ * ex)
+ * 1.1.1.0/24
+ * -> 1.1.1.1 dummy1 (inactive)
+ * -> 1.1.2.1 dummy2
+ *
+ * 1.1.2.0/24
+ * -> 1.1.1.1 dummy1
+ * -> 1.1.2.1 dummy2 (inactive)
+ *
+ * Without checking each individual one, they would hash to
+ * the same group and both have 1.1.1.1 dummy1 marked inactive.
+ *
+ */
+ if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_ACTIVE)
+ != CHECK_FLAG(nh2->flags, NEXTHOP_FLAG_ACTIVE))
+ return false;
+
+ if (!nexthop_same(nh1, nh2))
+ return false;
+
+ return true;
+}
+
bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
{
const struct nhg_hash_entry *nhe1 = arg1;
@@ -415,45 +516,44 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
if (nhe1->afi != nhe2->afi)
return false;
- /* Nexthops should be sorted */
+ /* Nexthops should be in-order, so we simply compare them in-place */
for (nexthop1 = nhe1->nhg.nexthop, nexthop2 = nhe2->nhg.nexthop;
nexthop1 || nexthop2;
nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
- if (nexthop1 && !nexthop2)
- return false;
- if (!nexthop1 && nexthop2)
+ if (!nhg_compare_nexthops(nexthop1, nexthop2))
return false;
+ }
- /*
- * We have to check the active flag of each individual one,
- * not just the overall active_num. This solves the special case
- * issue of a route with a nexthop group with one nexthop
- * resolving to itself and thus marking it inactive. If we
- * have two different routes each wanting to mark a different
- * nexthop inactive, they need to hash to two different groups.
- *
- * If we just hashed on num_active, they would hash the same
- * which is incorrect.
- *
- * ex)
- * 1.1.1.0/24
- * -> 1.1.1.1 dummy1 (inactive)
- * -> 1.1.2.1 dummy2
- *
- * 1.1.2.0/24
- * -> 1.1.1.1 dummy1
- * -> 1.1.2.1 dummy2 (inactive)
- *
- * Without checking each individual one, they would hash to
- * the same group and both have 1.1.1.1 dummy1 marked inactive.
- *
- */
- if (CHECK_FLAG(nexthop1->flags, NEXTHOP_FLAG_ACTIVE)
- != CHECK_FLAG(nexthop2->flags, NEXTHOP_FLAG_ACTIVE))
- return false;
+ /* If there's no backup info, comparison is done. */
+ if ((nhe1->backup_info == NULL) && (nhe2->backup_info == NULL))
+ return true;
- if (!nexthop_same(nexthop1, nexthop2))
+ /* Compare backup info also - test the easy things first */
+ if (nhe1->backup_info && (nhe2->backup_info == NULL))
+ return false;
+ if (nhe2->backup_info && (nhe1->backup_info == NULL))
+ return false;
+
+ /* Compare number of backups before actually comparing any */
+ for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
+ nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
+ nexthop1 && nexthop2;
+ nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
+ ;
+ }
+
+ /* Did we find the end of one list before the other? */
+ if (nexthop1 || nexthop2)
+ return false;
+
+ /* Have to compare the backup nexthops */
+ for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
+ nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
+ nexthop1 || nexthop2;
+ nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
+
+ if (!nhg_compare_nexthops(nexthop1, nexthop2))
return false;
}
@@ -512,29 +612,185 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
resolved_ng.nexthop = nh;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: head %p, nh %pNHv",
+ __func__, nhg_depends, nh);
+
depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv => %p (%u)",
+ __func__, nh, depend,
+ depend ? depend->id : 0);
+
if (depend)
depends_add(nhg_depends, depend);
}
+/*
+ * Lookup an nhe in the global hash, using data from another nhe. If 'lookup'
+ * has an id value, that's used. Create a new global/shared nhe if not found.
+ */
+static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
+ struct nhg_hash_entry *lookup,
+ struct nhg_connected_tree_head *nhg_depends,
+ afi_t afi)
+{
+ bool created = false;
+ bool recursive = false;
+ struct nhg_hash_entry *newnhe, *backup_nhe;
+ struct nexthop *nh = NULL;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: id %u, lookup %p, vrf %d, type %d, depends %p",
+ __func__, lookup->id, lookup,
+ lookup->vrf_id, lookup->type,
+ nhg_depends);
+
+ if (lookup->id)
+ (*nhe) = zebra_nhg_lookup_id(lookup->id);
+ else
+ (*nhe) = hash_lookup(zrouter.nhgs, lookup);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: lookup => %p (%u)",
+ __func__, (*nhe),
+ (*nhe) ? (*nhe)->id : 0);
+
+ /* If we found an existing object, we're done */
+ if (*nhe)
+ goto done;
+
+ /* We're going to create/insert a new nhe:
+ * assign the next global id value if necessary.
+ */
+ if (lookup->id == 0)
+ lookup->id = ++id_counter;
+ newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
+ created = true;
+
+ /* Mail back the new object */
+ *nhe = newnhe;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: => created %p (%u)", __func__, newnhe,
+ newnhe->id);
+
+ /* Only hash/lookup the depends if the first lookup
+ * fails to find something. This should hopefully save a
+ * lot of cycles for larger ecmp sizes.
+ */
+ if (nhg_depends) {
+ /* If you don't want to hash on each nexthop in the
+ * nexthop group struct you can pass the depends
+ * directly. Kernel-side we do this since it just looks
+ * them up via IDs.
+ */
+ zebra_nhg_connect_depends(newnhe, nhg_depends);
+ goto done;
+ }
+
+ /* Prepare dependency relationships if this is not a
+ * singleton nexthop. There are two cases: a single
+ * recursive nexthop, where we need a relationship to the
+ * resolving nexthop; or a group of nexthops, where we need
+ * relationships with the corresponding singletons.
+ */
+ zebra_nhg_depends_init(lookup);
+
+ nh = newnhe->nhg.nexthop;
+
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE))
+ SET_FLAG(newnhe->flags, NEXTHOP_GROUP_VALID);
+
+ if (nh->next == NULL) {
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
+ /* Single recursive nexthop */
+ handle_recursive_depend(&newnhe->nhg_depends,
+ nh->resolved, afi);
+ recursive = true;
+ }
+ } else {
+ /* List of nexthops */
+ for (nh = newnhe->nhg.nexthop; nh; nh = nh->next) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: depends NH %pNHv %s",
+ __func__, nh,
+ CHECK_FLAG(nh->flags,
+ NEXTHOP_FLAG_RECURSIVE) ?
+ "(R)" : "");
+
+ depends_find_add(&newnhe->nhg_depends, nh, afi);
+ }
+ }
+
+ if (recursive)
+ SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
+
+ if (zebra_nhg_get_backup_nhg(newnhe) == NULL ||
+ zebra_nhg_get_backup_nhg(newnhe)->nexthop == NULL)
+ goto done;
+
+ /* If there are backup nexthops, add them to the backup
+ * depends tree. The rules here are a little different.
+ */
+ recursive = false;
+ backup_nhe = newnhe->backup_info->nhe;
+
+ nh = backup_nhe->nhg.nexthop;
+
+ /* Singleton recursive NH */
+ if (nh->next == NULL &&
+ CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: backup depend NH %pNHv (R)",
+ __func__, nh);
+
+ /* Single recursive nexthop */
+ handle_recursive_depend(&backup_nhe->nhg_depends,
+ nh->resolved, afi);
+ recursive = true;
+ } else {
+ /* One or more backup NHs */
+ for (; nh; nh = nh->next) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: backup depend NH %pNHv %s",
+ __func__, nh,
+ CHECK_FLAG(nh->flags,
+ NEXTHOP_FLAG_RECURSIVE) ?
+ "(R)" : "");
+
+ depends_find_add(&backup_nhe->nhg_depends,
+ nh, afi);
+ }
+ }
+
+ if (recursive)
+ SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE);
+
+done:
+
+ return created;
+}
+
+/*
+ * Lookup or create an nhe, based on an nhg or an nhe id.
+ */
static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
struct nexthop_group *nhg,
struct nhg_connected_tree_head *nhg_depends,
vrf_id_t vrf_id, afi_t afi, int type)
{
struct nhg_hash_entry lookup = {};
-
- uint32_t old_id_counter = id_counter;
-
bool created = false;
- bool recursive = false;
- /*
- * If it has an id at this point, we must have gotten it from the kernel
- */
- lookup.id = id ? id : ++id_counter;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p",
+ __func__, id, nhg, vrf_id, type,
+ nhg_depends);
+ /* Use a temporary nhe and call into the superset/common code */
+ lookup.id = id;
lookup.type = type ? type : ZEBRA_ROUTE_NHG;
lookup.nhg = *nhg;
@@ -567,53 +823,8 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
}
}
- if (id)
- (*nhe) = zebra_nhg_lookup_id(id);
- else
- (*nhe) = hash_lookup(zrouter.nhgs, &lookup);
-
- /* If it found an nhe in our tables, this new ID is unused */
- if (*nhe)
- id_counter = old_id_counter;
-
- if (!(*nhe)) {
- /* Only hash/lookup the depends if the first lookup
- * fails to find something. This should hopefully save a
- * lot of cycles for larger ecmp sizes.
- */
- if (nhg_depends)
- /* If you don't want to hash on each nexthop in the
- * nexthop group struct you can pass the depends
- * directly. Kernel-side we do this since it just looks
- * them up via IDs.
- */
- lookup.nhg_depends = *nhg_depends;
- else {
- if (nhg->nexthop->next) {
- zebra_nhg_depends_init(&lookup);
-
- /* If its a group, create a dependency tree */
- struct nexthop *nh = NULL;
-
- for (nh = nhg->nexthop; nh; nh = nh->next)
- depends_find_add(&lookup.nhg_depends,
- nh, afi);
- } else if (CHECK_FLAG(nhg->nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE)) {
- zebra_nhg_depends_init(&lookup);
- handle_recursive_depend(&lookup.nhg_depends,
- nhg->nexthop->resolved,
- afi);
- recursive = true;
- }
- }
-
- (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_hash_alloc);
- created = true;
+ created = zebra_nhe_find(nhe, &lookup, nhg_depends, afi);
- if (recursive)
- SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
- }
return created;
}
@@ -629,6 +840,10 @@ zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv => %p (%u)",
+ __func__, nh, nhe, nhe ? nhe->id : 0);
+
return nhe;
}
@@ -807,6 +1022,9 @@ done:
static void zebra_nhg_release(struct nhg_hash_entry *nhe)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u)", __func__, nhe, nhe->id);
+
/* Remove it from any lists it may be on */
zebra_nhg_depends_release(nhe);
zebra_nhg_dependents_release(nhe);
@@ -872,6 +1090,10 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
lookup = zebra_nhg_lookup_id(id);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: id %u, count %d, lookup => %p",
+ __func__, id, count, lookup);
+
if (lookup) {
/* This is already present in our table, hence an update
* that we did not initate.
@@ -919,6 +1141,11 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
*/
kernel_nhe = zebra_nhg_copy(nhe, id);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: copying kernel nhe (%u), dup of %u",
+ __func__, id, nhe->id);
+
zebra_nhg_insert_id(kernel_nhe);
zebra_nhg_set_unhashable(kernel_nhe);
} else if (zebra_nhg_contains_unhashable(nhe)) {
@@ -926,10 +1153,18 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
* depend, so lets mark this group as unhashable as well
* and release it from the non-ID hash.
*/
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u) unhashable",
+ __func__, nhe, nhe->id);
+
hash_release(zrouter.nhgs, nhe);
zebra_nhg_set_unhashable(nhe);
} else {
/* It actually created a new nhe */
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u) is new",
+ __func__, nhe, nhe->id);
+
SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
}
@@ -1038,6 +1273,10 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
{
struct nhg_ctx *ctx = NULL;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv, id %u, count %d",
+ __func__, nh, id, (int)count);
+
if (id > id_counter)
/* Increase our counter so we don't try to create
* an ID that already exists
@@ -1111,12 +1350,17 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
/* The copy may have allocated labels; free them if necessary. */
nexthop_del_labels(&lookup);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv => %p (%u)",
+ __func__, nh, nhe, nhe ? nhe->id : 0);
+
return nhe;
}
static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
{
struct nhg_hash_entry *nhe = NULL;
+ char rbuf[10];
if (!nh)
goto done;
@@ -1124,10 +1368,18 @@ static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
/* We are separating these functions out to increase handling speed
* in the non-recursive case (by not alloc/freeing)
*/
- if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
nhe = depends_find_recursive(nh, afi);
- else
+ strlcpy(rbuf, "(R)", sizeof(rbuf));
+ } else {
nhe = depends_find_singleton(nh, afi);
+ rbuf[0] = '\0';
+ }
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv %s => %p (%u)",
+ __func__, nh, rbuf,
+ nhe, nhe ? nhe->id : 0);
done:
return nhe;
@@ -1136,6 +1388,10 @@ done:
static void depends_add(struct nhg_connected_tree_head *head,
struct nhg_hash_entry *depend)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: head %p nh %pNHv",
+ __func__, head, depend->nhg.nexthop);
+
/* If NULL is returned, it was successfully added and
* needs to have its refcnt incremented.
*
@@ -1154,6 +1410,10 @@ depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
depend = depends_find(nh, afi);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv => %p",
+ __func__, nh, depend);
+
if (depend)
depends_add(head, depend);
@@ -1179,7 +1439,7 @@ static void depends_decrement_free(struct nhg_connected_tree_head *head)
nhg_connected_tree_free(head);
}
-/* Rib-side, you get a nexthop group struct */
+/* Find an nhe based on a list of nexthops */
struct nhg_hash_entry *
zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
{
@@ -1195,13 +1455,107 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: => nhe %p (%u)",
+ __func__, nhe, nhe ? nhe->id : 0);
+
+ return nhe;
+}
+
+/* Find an nhe based on a route's nhe */
+struct nhg_hash_entry *
+zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi)
+{
+ struct nhg_hash_entry *nhe = NULL;
+
+ if (!(rt_nhe && rt_nhe->nhg.nexthop)) {
+ flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
+ "No nexthop passed to %s", __func__);
+ return NULL;
+ }
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: rt_nhe %p (%u)",
+ __func__, rt_nhe,
+ rt_nhe ? rt_nhe->id : 0);
+
+ zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: => nhe %p (%u)",
+ __func__, nhe, nhe ? nhe->id : 0);
+
return nhe;
}
+/*
+ * Allocate backup nexthop info object. Typically these are embedded in
+ * nhg_hash_entry objects.
+ */
+struct nhg_backup_info *zebra_nhg_backup_alloc(void)
+{
+ struct nhg_backup_info *p;
+
+ p = XCALLOC(MTYPE_NHG, sizeof(struct nhg_backup_info));
+
+ p->nhe = zebra_nhg_alloc();
+
+ /* Identify the embedded group used to hold the list of backups */
+ SET_FLAG(p->nhe->flags, NEXTHOP_GROUP_BACKUP);
+
+ return p;
+}
+
+/*
+ * Free backup nexthop info object, deal with any embedded allocations
+ */
+void zebra_nhg_backup_free(struct nhg_backup_info **p)
+{
+ if (p && *p) {
+ if ((*p)->nhe)
+ zebra_nhg_free((*p)->nhe);
+
+ XFREE(MTYPE_NHG, (*p));
+ }
+}
+
+/* Accessor for backup nexthop group */
+struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe)
+{
+ struct nexthop_group *p = NULL;
+
+ if (nhe) {
+ if (nhe->backup_info && nhe->backup_info->nhe)
+ p = &(nhe->backup_info->nhe->nhg);
+ }
+
+ return p;
+}
+
+/*
+ * Helper to return a copy of a backup_info - note that this is a shallow
+ * copy, meant to be used when creating a new nhe from info passed in with
+ * a route e.g.
+ */
+static struct nhg_backup_info *
+nhg_backup_copy(const struct nhg_backup_info *orig)
+{
+ struct nhg_backup_info *b;
+
+ b = zebra_nhg_backup_alloc();
+
+ /* Copy list of nexthops */
+ nexthop_group_copy(&(b->nhe->nhg), &(orig->nhe->nhg));
+
+ return b;
+}
+
static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
{
nexthops_free(nhe->nhg.nexthop);
+ zebra_nhg_backup_free(&nhe->backup_info);
+
/* Decrement to remove connection ref */
nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
nhg_connected_tree_free(&nhe->nhg_depends);
@@ -1210,6 +1564,21 @@ static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
void zebra_nhg_free(struct nhg_hash_entry *nhe)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
+ /* Group or singleton? */
+ if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
+ zlog_debug("%s: nhe %p (%u), refcnt %d",
+ __func__, nhe,
+ (nhe ? nhe->id : 0),
+ (nhe ? nhe->refcnt : 0));
+ else
+ zlog_debug("%s: nhe %p (%u), refcnt %d, NH %pNHv",
+ __func__, nhe,
+ (nhe ? nhe->id : 0),
+ (nhe ? nhe->refcnt : 0),
+ nhe->nhg.nexthop);
+ }
+
if (nhe->refcnt)
zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
@@ -1225,6 +1594,11 @@ void zebra_nhg_hash_free(void *p)
void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u) %d => %d",
+ __func__, nhe, nhe->id, nhe->refcnt,
+ nhe->refcnt - 1);
+
nhe->refcnt--;
if (!zebra_nhg_depends_is_empty(nhe))
@@ -1236,6 +1610,11 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u) %d => %d",
+ __func__, nhe, nhe->id, nhe->refcnt,
+ nhe->refcnt + 1);
+
nhe->refcnt++;
if (!zebra_nhg_depends_is_empty(nhe))
@@ -1385,6 +1764,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
nexthop->resolved = NULL;
re->nexthop_mtu = 0;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p, nexthop %pNHv",
+ __func__, re, nexthop);
+
/*
* If the kernel has sent us a NEW route, then
* by golly gee whiz it's a good route.
@@ -1411,7 +1794,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (!ifp) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "\t%s: Onlink and interface: %u[%u] does not exist",
+ " %s: Onlink and interface: %u[%u] does not exist",
__func__, nexthop->ifindex,
nexthop->vrf_id);
return 0;
@@ -1422,14 +1805,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "\t%s: Onlink and interface %s is not operative",
+ " %s: Onlink and interface %s is not operative",
__func__, ifp->name);
return 0;
}
if (!if_is_operative(ifp)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "\t%s: Interface %s is not unnumbered",
+ " %s: Interface %s is not unnumbered",
__func__, ifp->name);
return 0;
}
@@ -1441,7 +1824,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
&& memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "\t:%s: Attempting to install a max prefixlength route through itself",
+ " :%s: Attempting to install a max prefixlength route through itself",
__func__);
return 0;
}
@@ -1469,7 +1852,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
if (!table || !zvrf) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("\t%s: Table not found", __func__);
+ zlog_debug(" %s: Table not found", __func__);
return 0;
}
@@ -1487,7 +1870,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|| ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "\t%s: Matched against ourself and prefix length is not max bit length",
+ " %s: Matched against ourself and prefix length is not max bit length",
__func__);
return 0;
}
@@ -1500,7 +1883,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
&& !rnh_resolve_via_default(zvrf, p.family)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "\t:%s: Resolved against default route",
+ " :%s: Resolved against default route",
__func__);
return 0;
}
@@ -1533,6 +1916,12 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|| nexthop->type == NEXTHOP_TYPE_IPV6)
nexthop->ifindex = newhop->ifindex;
}
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: CONNECT match %p (%u), newhop %pNHv",
+ __func__, match,
+ match->nhe->id, newhop);
+
return 1;
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
resolved = 0;
@@ -1543,6 +1932,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (!nexthop_valid_resolve(nexthop, newhop))
continue;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: RECURSIVE match %p (%u), newhop %pNHv",
+ __func__, match,
+ match->nhe->id, newhop);
+
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE);
nexthop_set_resolved(afi, newhop, nexthop);
@@ -1552,8 +1946,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
re->nexthop_mtu = match->mtu;
if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("\t%s: Recursion failed to find",
- __func__);
+ zlog_debug(
+ " %s: Recursion failed to find",
+ __func__);
return resolved;
} else if (re->type == ZEBRA_ROUTE_STATIC) {
resolved = 0;
@@ -1564,6 +1959,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (!nexthop_valid_resolve(nexthop, newhop))
continue;
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("%s: STATIC match %p (%u), newhop %pNHv",
+ __func__, match,
+ match->nhe->id, newhop);
+
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE);
nexthop_set_resolved(afi, newhop, nexthop);
@@ -1574,24 +1974,25 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "\t%s: Static route unable to resolve",
+ " %s: Static route unable to resolve",
__func__);
return resolved;
} else {
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
zlog_debug(
- "\t%s: Route Type %s has not turned on recursion",
+ " %s: Route Type %s has not turned on recursion",
__func__, zebra_route_string(re->type));
if (re->type == ZEBRA_ROUTE_BGP
&& !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
zlog_debug(
- "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
+ " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
}
return 0;
}
}
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("\t%s: Nexthop did not lookup in table", __func__);
+ zlog_debug(" %s: Nexthop did not lookup in table",
+ __func__);
return 0;
}
@@ -1681,9 +2082,10 @@ static unsigned nexthop_active_check(struct route_node *rn,
default:
break;
}
+
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("\t%s: Unable to find a active nexthop",
+ zlog_debug(" %s: Unable to find active nexthop",
__func__);
return 0;
}
@@ -1713,7 +2115,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
if (!zvrf) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("\t%s: zvrf is NULL", __func__);
+ zlog_debug(" %s: zvrf is NULL", __func__);
return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
@@ -1734,46 +2136,68 @@ static unsigned nexthop_active_check(struct route_node *rn,
return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
+/* Helper function called after resolution to walk nhg rb trees
+ * and toggle the NEXTHOP_GROUP_VALID flag if the nexthop
+ * is active on singleton NHEs.
+ */
+static bool zebra_nhg_set_valid_if_active(struct nhg_hash_entry *nhe)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+ bool valid = false;
+
+ if (!zebra_nhg_depends_is_empty(nhe)) {
+ /* Is at least one depend valid? */
+ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
+ if (zebra_nhg_set_valid_if_active(rb_node_dep->nhe))
+ valid = true;
+ }
+
+ goto done;
+ }
+
+ /* should be fully resolved singleton at this point */
+ if (CHECK_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ valid = true;
+
+done:
+ if (valid)
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+
+ return valid;
+}
+
/*
- * Iterate over all nexthops of the given RIB entry and refresh their
- * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
- * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
- *
- * Return value is the new number of active nexthops.
+ * Process a list of nexthops, given the head of the list, determining
+ * whether each one is ACTIVE/installable at this time.
*/
-int nexthop_active_update(struct route_node *rn, struct route_entry *re)
+static uint32_t nexthop_list_active_update(struct route_node *rn,
+ struct route_entry *re,
+ struct nexthop *nexthop)
{
- struct nexthop_group new_grp = {};
- struct nexthop *nexthop;
union g_addr prev_src;
unsigned int prev_active, new_active;
ifindex_t prev_index;
- uint8_t curr_active = 0;
+ uint32_t counter = 0;
- afi_t rt_afi = family2afi(rn->p.family);
-
- UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
-
- /* Copy over the nexthops in current state */
- nexthop_group_copy(&new_grp, &(re->nhe->nhg));
-
- for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) {
+ /* Process nexthops one-by-one */
+ for ( ; nexthop; nexthop = nexthop->next) {
/* No protocol daemon provides src and so we're skipping
- * tracking it */
+ * tracking it
+ */
prev_src = nexthop->rmap_src;
prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
prev_index = nexthop->ifindex;
/*
* We need to respect the multipath_num here
* as that what we should be able to install from
- * a multipath perpsective should not be a data plane
+ * a multipath perspective should not be a data plane
* decision point.
*/
new_active =
nexthop_active_check(rn, re, nexthop);
- if (new_active && curr_active >= zrouter.multipath_num) {
+ if (new_active && counter >= zrouter.multipath_num) {
struct nexthop *nh;
/* Set it and its resolved nexthop as inactive. */
@@ -1784,7 +2208,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
}
if (new_active)
- curr_active++;
+ counter++;
/* Don't allow src setting on IPv6 addr for now */
if (prev_active != new_active || prev_index != nexthop->ifindex
@@ -1800,48 +2224,122 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
}
+ return counter;
+}
+
+/*
+ * Iterate over all nexthops of the given RIB entry and refresh their
+ * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
+ * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
+ *
+ * Return value is the new number of active nexthops.
+ */
+int nexthop_active_update(struct route_node *rn, struct route_entry *re)
+{
+ struct nhg_hash_entry *curr_nhe;
+ uint32_t curr_active = 0, backup_active = 0;
+
+ afi_t rt_afi = family2afi(rn->p.family);
+
+ UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
+
+ /* Make a local copy of the existing nhe, so we don't work on/modify
+ * the shared nhe.
+ */
+ curr_nhe = zebra_nhg_copy(re->nhe, re->nhe->id);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p nhe %p (%u), curr_nhe %p",
+ __func__, re, re->nhe, re->nhe->id,
+ curr_nhe);
+
+ /* Clear the existing id, if any: this will avoid any confusion
+ * if the id exists, and will also force the creation
+ * of a new nhe reflecting the changes we may make in this local copy.
+ */
+ curr_nhe->id = 0;
+
+ /* Process nexthops */
+ curr_active = nexthop_list_active_update(rn, re, curr_nhe->nhg.nexthop);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p curr_active %u", __func__, re,
+ curr_active);
+
+ /* If there are no backup nexthops, we are done */
+ if (zebra_nhg_get_backup_nhg(curr_nhe) == NULL)
+ goto backups_done;
+
+ backup_active = nexthop_list_active_update(
+ rn, re, zebra_nhg_get_backup_nhg(curr_nhe)->nexthop);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p backup_active %u", __func__, re,
+ backup_active);
+
+backups_done:
+
+ /*
+ * Ref or create an nhe that matches the current state of the
+ * nexthop(s).
+ */
if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
struct nhg_hash_entry *new_nhe = NULL;
- new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi);
+ new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p CHANGED: nhe %p (%u) => new_nhe %p (%u)",
+ __func__, re, re->nhe,
+ re->nhe->id, new_nhe, new_nhe->id);
route_entry_update_nhe(re, new_nhe);
}
- if (curr_active) {
- struct nhg_hash_entry *nhe = NULL;
-
- nhe = zebra_nhg_lookup_id(re->nhe_id);
- if (nhe)
- SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
- else
- flog_err(
- EC_ZEBRA_TABLE_LOOKUP_FAILED,
- "Active update on NHE id=%u that we do not have in our tables",
- re->nhe_id);
- }
+ /* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID
+ * flag where appropriate.
+ */
+ if (curr_active)
+ zebra_nhg_set_valid_if_active(re->nhe);
/*
- * Do not need these nexthops anymore since they
- * were either copied over into an nhe or not
+ * Do not need the old / copied nhe anymore since it
+ * was either copied over into a new nhe or not
* used at all.
*/
- nexthops_free(new_grp.nexthop);
+ zebra_nhg_free(curr_nhe);
return curr_active;
}
-/* Convert a nhe into a group array */
-uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
- int max_num)
+/* Recursively construct a grp array of fully resolved IDs.
+ *
+ * This function allows us to account for groups within groups,
+ * by converting them into a flat array of IDs.
+ *
+ * nh_grp is modified at every level of recursion to append
+ * to it the next unique, fully resolved ID from the entire tree.
+ *
+ *
+ * Note:
+ * I'm pretty sure we only allow ONE level of group within group currently.
+ * But making this recursive just in case that ever changes.
+ */
+static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp,
+ uint8_t curr_index,
+ struct nhg_hash_entry *nhe,
+ int max_num)
{
struct nhg_connected *rb_node_dep = NULL;
struct nhg_hash_entry *depend = NULL;
- uint8_t i = 0;
+ uint8_t i = curr_index;
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
bool duplicate = false;
+ if (i >= max_num)
+ goto done;
+
depend = rb_node_dep->nhe;
/*
@@ -1858,27 +2356,78 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
}
}
- /* Check for duplicate IDs, kernel doesn't like that */
- for (int j = 0; j < i; j++) {
- if (depend->id == grp[j].id)
- duplicate = true;
- }
+ if (!zebra_nhg_depends_is_empty(depend)) {
+ /* This is a group within a group */
+ i = zebra_nhg_nhe2grp_internal(grp, i, depend, max_num);
+ } else {
+ if (!CHECK_FLAG(depend->flags, NEXTHOP_GROUP_VALID)) {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED
+ || IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: Nexthop ID (%u) not valid, not appending to dataplane install group",
+ __func__, depend->id);
+ continue;
+ }
+
+ /* If the nexthop not installed/queued for install don't
+ * put in the ID array.
+ */
+ if (!(CHECK_FLAG(depend->flags, NEXTHOP_GROUP_INSTALLED)
+ || CHECK_FLAG(depend->flags,
+ NEXTHOP_GROUP_QUEUED))) {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED
+ || IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: Nexthop ID (%u) not installed or queued for install, not appending to dataplane install group",
+ __func__, depend->id);
+ continue;
+ }
+
+ /* Check for duplicate IDs, ignore if found. */
+ for (int j = 0; j < i; j++) {
+ if (depend->id == grp[j].id) {
+ duplicate = true;
+ break;
+ }
+ }
+
+ if (duplicate) {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED
+ || IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: Nexthop ID (%u) is duplicate, not appending to dataplane install group",
+ __func__, depend->id);
+ continue;
+ }
- if (!duplicate) {
grp[i].id = depend->id;
- /* We aren't using weights for anything right now */
grp[i].weight = depend->nhg.nexthop->weight;
i++;
}
-
- if (i >= max_num)
- goto done;
}
+ if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL)
+ goto done;
+
+ /* TODO -- For now, we are not trying to use or install any
+ * backup info in this nexthop-id path: we aren't prepared
+ * to use the backups here yet. We're just debugging what we find.
+ */
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: skipping backup nhe", __func__);
+
done:
return i;
}
+/* Convert a nhe into a group array */
+uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
+ int max_num)
+{
+ /* Call into the recursive function */
+ return zebra_nhg_nhe2grp_internal(grp, 0, nhe, max_num);
+}
+
void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
{
struct nhg_connected *rb_node_dep = NULL;
@@ -1891,7 +2440,8 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
zebra_nhg_install_kernel(rb_node_dep->nhe);
}
- if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)
+ && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
&& !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
/* Change its type to us since we are installing it */
nhe->type = ZEBRA_ROUTE_NHG;
@@ -1952,7 +2502,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
id = dplane_ctx_get_nhe_id(ctx);
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug(
"Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
ctx, dplane_op2str(op), id, dplane_res2str(status));
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index dc3a47c020..0a9e97ab48 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -50,6 +50,9 @@ struct nhg_hash_entry {
struct nexthop_group nhg;
+ /* If supported, a mapping of backup nexthops. */
+ struct nhg_backup_info *backup_info;
+
/* If this is not a group, it
* will be a single nexthop
* and must have an interface
@@ -72,6 +75,7 @@ struct nhg_hash_entry {
* faster with ID's.
*/
struct nhg_connected_tree_head nhg_depends, nhg_dependents;
+
/*
* Is this nexthop group valid, ie all nexthops are fully resolved.
* What is fully resolved? It's a nexthop that is either self contained
@@ -102,11 +106,25 @@ struct nhg_hash_entry {
* from the kernel. Therefore, it is unhashable.
*/
#define NEXTHOP_GROUP_UNHASHABLE (1 << 4)
+
+/*
+ * Backup nexthop support - identify groups that are backups for
+ * another group.
+ */
+#define NEXTHOP_GROUP_BACKUP (1 << 5)
+
};
/* Was this one we created, either this session or previously? */
#define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG)
+/*
+ * Backup nexthops: this is a group object itself, so
+ * that the backup nexthops can use the same code as a normal object.
+ */
+struct nhg_backup_info {
+ struct nhg_hash_entry *nhe;
+};
enum nhg_ctx_op_e {
NHG_CTX_OP_NONE = 0,
@@ -162,13 +180,26 @@ bool zebra_nhg_kernel_nexthops_enabled(void);
/**
* NHE abstracted tree functions.
- * Use these where possible instead of the direct ones access ones.
+ * Use these where possible instead of direct access.
*/
struct nhg_hash_entry *zebra_nhg_alloc(void);
void zebra_nhg_free(struct nhg_hash_entry *nhe);
/* In order to clear a generic hash, we need a generic api, sigh. */
void zebra_nhg_hash_free(void *p);
+/* Init an nhe, for use in a hash lookup for example. There's some fuzziness
+ * if the nhe represents only a single nexthop, so we try to capture that
+ * variant also.
+ */
+void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
+ const struct nexthop *nh);
+
+/* Allocate, free backup nexthop info objects */
+struct nhg_backup_info *zebra_nhg_backup_alloc(void);
+void zebra_nhg_backup_free(struct nhg_backup_info **p);
+
+struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe);
+
extern struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe);
extern unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe);
@@ -203,10 +234,14 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
/* Del via kernel */
extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
-/* Find via route creation */
+/* Find an nhe based on a nexthop_group */
extern struct nhg_hash_entry *
zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi);
+/* Find an nhe based on a route's nhe, used during route creation */
+struct nhg_hash_entry *
+zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi);
+
/* Reference counter functions */
extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe);
extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe);
diff --git a/zebra/zebra_northbound.c b/zebra/zebra_northbound.c
new file mode 100644
index 0000000000..9f6514e12f
--- /dev/null
+++ b/zebra/zebra_northbound.c
@@ -0,0 +1,2212 @@
+/*
+ * Zebra northbound implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/command.h"
+#include "lib/log.h"
+#include "lib/northbound.h"
+#include "lib/routemap.h"
+
+#include "zebra/rib.h"
+
+/*
+ * XPath: /frr-zebra:zebra/mcast-rpf-lookup
+ */
+static int zebra_mcast_rpf_lookup_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/ip-forwarding
+ */
+static int zebra_ip_forwarding_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_ip_forwarding_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/ipv6-forwarding
+ */
+static int zebra_ipv6_forwarding_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_ipv6_forwarding_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/workqueue-hold-timer
+ */
+static int zebra_workqueue_hold_timer_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/zapi-packets
+ */
+static int zebra_zapi_packets_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/import-kernel-table/table-id
+ */
+static int
+zebra_import_kernel_table_table_id_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+zebra_import_kernel_table_table_id_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/import-kernel-table/distance
+ */
+static int
+zebra_import_kernel_table_distance_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/import-kernel-table/route-map
+ */
+static int
+zebra_import_kernel_table_route_map_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+zebra_import_kernel_table_route_map_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/allow-external-route-update
+ */
+static int
+zebra_allow_external_route_update_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+zebra_allow_external_route_update_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/dplane-queue-limit
+ */
+static int zebra_dplane_queue_limit_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/vrf-vni-mapping
+ */
+static int zebra_vrf_vni_mapping_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_vrf_vni_mapping_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/vrf-vni-mapping/vni-id
+ */
+static int zebra_vrf_vni_mapping_vni_id_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_vrf_vni_mapping_vni_id_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/vrf-vni-mapping/prefix-only
+ */
+static int
+zebra_vrf_vni_mapping_prefix_only_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+zebra_vrf_vni_mapping_prefix_only_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-events
+ */
+static int zebra_debugs_debug_events_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_events_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-zapi-send
+ */
+static int zebra_debugs_debug_zapi_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_zapi_send_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-zapi-recv
+ */
+static int zebra_debugs_debug_zapi_recv_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_zapi_recv_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-zapi-detail
+ */
+static int zebra_debugs_debug_zapi_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_zapi_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-kernel
+ */
+static int zebra_debugs_debug_kernel_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_kernel_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-kernel-msg-send
+ */
+static int
+zebra_debugs_debug_kernel_msg_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+zebra_debugs_debug_kernel_msg_send_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-kernel-msg-recv
+ */
+static int
+zebra_debugs_debug_kernel_msg_recv_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+zebra_debugs_debug_kernel_msg_recv_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-rib
+ */
+static int zebra_debugs_debug_rib_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_rib_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-rib-detail
+ */
+static int zebra_debugs_debug_rib_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_rib_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-fpm
+ */
+static int zebra_debugs_debug_fpm_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_fpm_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-nht
+ */
+static int zebra_debugs_debug_nht_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_nht_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-nht-detail
+ */
+static int zebra_debugs_debug_nht_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_nht_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-mpls
+ */
+static int zebra_debugs_debug_mpls_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_mpls_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-vxlan
+ */
+static int zebra_debugs_debug_vxlan_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_vxlan_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-pw
+ */
+static int zebra_debugs_debug_pw_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_pw_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-dplane
+ */
+static int zebra_debugs_debug_dplane_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_dplane_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-dplane-detail
+ */
+static int zebra_debugs_debug_dplane_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+zebra_debugs_debug_dplane_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-mlag
+ */
+static int zebra_debugs_debug_mlag_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int zebra_debugs_debug_mlag_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-route-information
+ */
+static int get_route_information_rpc(const char *xpath,
+ const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-v6-mroute-info
+ */
+static int get_v6_mroute_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-vrf-info
+ */
+static int get_vrf_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-vrf-vni-info
+ */
+static int get_vrf_vni_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-info
+ */
+static int get_evpn_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-vni-info
+ */
+static int get_vni_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-vni-rmac
+ */
+static int get_evpn_vni_rmac_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-vni-nexthops
+ */
+static int get_evpn_vni_nexthops_rpc(const char *xpath,
+ const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:clear-evpn-dup-addr
+ */
+static int clear_evpn_dup_addr_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-macs
+ */
+static int get_evpn_macs_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-arp-cache
+ */
+static int get_evpn_arp_cache_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-pbr-ipset
+ */
+static int get_pbr_ipset_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-pbr-iptable
+ */
+static int get_pbr_iptable_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-debugs
+ */
+static int get_debugs_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list
+ */
+static int
+lib_interface_zebra_ip4_addr_list_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+lib_interface_zebra_ip4_addr_list_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list/ip4-peer
+ */
+static int
+lib_interface_zebra_ip4_addr_list_ip4_peer_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+lib_interface_zebra_ip4_addr_list_ip4_peer_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list/label
+ */
+static int
+lib_interface_zebra_ip4_addr_list_label_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+lib_interface_zebra_ip4_addr_list_label_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip6-addr-list
+ */
+static int
+lib_interface_zebra_ip6_addr_list_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+lib_interface_zebra_ip6_addr_list_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip6-addr-list/label
+ */
+static int
+lib_interface_zebra_ip6_addr_list_label_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int
+lib_interface_zebra_ip6_addr_list_label_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/multicast
+ */
+static int lib_interface_zebra_multicast_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int lib_interface_zebra_multicast_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-detect
+ */
+static int lib_interface_zebra_link_detect_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int lib_interface_zebra_link_detect_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/shutdown
+ */
+static int lib_interface_zebra_shutdown_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int lib_interface_zebra_shutdown_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/bandwidth
+ */
+static int lib_interface_zebra_bandwidth_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+static int lib_interface_zebra_bandwidth_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv4-prefix-length
+ */
+static int lib_route_map_entry_match_condition_ipv4_prefix_length_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *length;
+ int condition, rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ length = yang_dnode_get_string(dnode, NULL);
+ condition = yang_dnode_get_enum(dnode, "../frr-route-map:condition");
+
+ /* Set destroy information. */
+ switch (condition) {
+ case 100: /* ipv4-prefix-length */
+ rhc->rhc_rule = "ip address prefix-len";
+ break;
+
+ case 102: /* ipv4-next-hop-prefix-length */
+ rhc->rhc_rule = "ip next-hop prefix-len";
+ break;
+ }
+ rhc->rhc_mhook = generic_match_delete;
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = generic_match_add(NULL, rhc->rhc_rmi, rhc->rhc_rule, length,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_ipv4_prefix_length_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv6-prefix-length
+ */
+static int lib_route_map_entry_match_condition_ipv6_prefix_length_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *length;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ length = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = generic_match_delete;
+ rhc->rhc_rule = "ipv6 address prefix-len";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = generic_match_add(NULL, rhc->rhc_rmi, "ipv6 address prefix-len",
+ length, RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_ipv6_prefix_length_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-protocol
+ */
+static int lib_route_map_entry_match_condition_source_protocol_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ type = yang_dnode_get_string(dnode, NULL);
+ if (proto_name2num(type) == -1) {
+ zlog_warn("%s: invalid protocol: %s", __func__, type);
+ return NB_ERR_VALIDATION;
+ }
+ return NB_OK;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ return NB_OK;
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = generic_match_delete;
+ rhc->rhc_rule = "source-protocol";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = generic_match_add(NULL, rhc->rhc_rmi, "source-protocol", type,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_source_protocol_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-instance
+ */
+static int lib_route_map_entry_match_condition_source_instance_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = generic_match_delete;
+ rhc->rhc_rule = "source-instance";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = generic_match_add(NULL, rhc->rhc_rmi, "source-instance", type,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_source_instance_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v4
+ */
+static int
+lib_route_map_entry_set_action_source_v4_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ struct interface *pif = NULL;
+ const char *source;
+ struct vrf *vrf;
+ struct prefix p;
+ int rv;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ memset(&p, 0, sizeof(p));
+ yang_dnode_get_ipv4p(&p, dnode, NULL);
+ if (zebra_check_addr(&p) == 0) {
+ zlog_warn("%s: invalid IPv4 address: %s", __func__,
+ yang_dnode_get_string(dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
+ RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) {
+ pif = if_lookup_exact_address(&p.u.prefix4, AF_INET,
+ vrf->vrf_id);
+ if (pif != NULL)
+ break;
+ }
+ if (pif == NULL) {
+ zlog_warn("%s: is not a local adddress: %s", __func__,
+ yang_dnode_get_string(dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+ return NB_OK;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ return NB_OK;
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ source = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = generic_set_delete;
+ rhc->rhc_rule = "src";
+
+ rv = generic_set_add(NULL, rhc->rhc_rmi, "src", source);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int
+lib_route_map_entry_set_action_source_v4_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v6
+ */
+static int
+lib_route_map_entry_set_action_source_v6_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ struct interface *pif = NULL;
+ const char *source;
+ struct vrf *vrf;
+ struct prefix p;
+ int rv;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ memset(&p, 0, sizeof(p));
+ yang_dnode_get_ipv6p(&p, dnode, NULL);
+ if (zebra_check_addr(&p) == 0) {
+ zlog_warn("%s: invalid IPv6 address: %s", __func__,
+ yang_dnode_get_string(dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
+ RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) {
+ pif = if_lookup_exact_address(&p.u.prefix6, AF_INET6,
+ vrf->vrf_id);
+ if (pif != NULL)
+ break;
+ }
+ if (pif == NULL) {
+ zlog_warn("%s: is not a local adddress: %s", __func__,
+ yang_dnode_get_string(dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+ return NB_OK;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ return NB_OK;
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ source = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = generic_set_delete;
+ rhc->rhc_rule = "src";
+
+ rv = generic_set_add(NULL, rhc->rhc_rmi, "src", source);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+static int
+lib_route_map_entry_set_action_source_v6_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/* clang-format off */
+const struct frr_yang_module_info frr_zebra_info = {
+ .name = "frr-zebra",
+ .nodes = {
+ {
+ .xpath = "/frr-zebra:zebra/mcast-rpf-lookup",
+ .cbs = {
+ .modify = zebra_mcast_rpf_lookup_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/ip-forwarding",
+ .cbs = {
+ .modify = zebra_ip_forwarding_modify,
+ .destroy = zebra_ip_forwarding_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/ipv6-forwarding",
+ .cbs = {
+ .modify = zebra_ipv6_forwarding_modify,
+ .destroy = zebra_ipv6_forwarding_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/workqueue-hold-timer",
+ .cbs = {
+ .modify = zebra_workqueue_hold_timer_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/zapi-packets",
+ .cbs = {
+ .modify = zebra_zapi_packets_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/import-kernel-table/table-id",
+ .cbs = {
+ .modify = zebra_import_kernel_table_table_id_modify,
+ .destroy = zebra_import_kernel_table_table_id_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/import-kernel-table/distance",
+ .cbs = {
+ .modify = zebra_import_kernel_table_distance_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/import-kernel-table/route-map",
+ .cbs = {
+ .modify = zebra_import_kernel_table_route_map_modify,
+ .destroy = zebra_import_kernel_table_route_map_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/allow-external-route-update",
+ .cbs = {
+ .create = zebra_allow_external_route_update_create,
+ .destroy = zebra_allow_external_route_update_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/dplane-queue-limit",
+ .cbs = {
+ .modify = zebra_dplane_queue_limit_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/vrf-vni-mapping",
+ .cbs = {
+ .create = zebra_vrf_vni_mapping_create,
+ .destroy = zebra_vrf_vni_mapping_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/vrf-vni-mapping/vni-id",
+ .cbs = {
+ .modify = zebra_vrf_vni_mapping_vni_id_modify,
+ .destroy = zebra_vrf_vni_mapping_vni_id_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/vrf-vni-mapping/prefix-only",
+ .cbs = {
+ .create = zebra_vrf_vni_mapping_prefix_only_create,
+ .destroy = zebra_vrf_vni_mapping_prefix_only_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-events",
+ .cbs = {
+ .modify = zebra_debugs_debug_events_modify,
+ .destroy = zebra_debugs_debug_events_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-zapi-send",
+ .cbs = {
+ .modify = zebra_debugs_debug_zapi_send_modify,
+ .destroy = zebra_debugs_debug_zapi_send_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-zapi-recv",
+ .cbs = {
+ .modify = zebra_debugs_debug_zapi_recv_modify,
+ .destroy = zebra_debugs_debug_zapi_recv_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-zapi-detail",
+ .cbs = {
+ .modify = zebra_debugs_debug_zapi_detail_modify,
+ .destroy = zebra_debugs_debug_zapi_detail_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-kernel",
+ .cbs = {
+ .modify = zebra_debugs_debug_kernel_modify,
+ .destroy = zebra_debugs_debug_kernel_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-kernel-msg-send",
+ .cbs = {
+ .modify = zebra_debugs_debug_kernel_msg_send_modify,
+ .destroy = zebra_debugs_debug_kernel_msg_send_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-kernel-msg-recv",
+ .cbs = {
+ .modify = zebra_debugs_debug_kernel_msg_recv_modify,
+ .destroy = zebra_debugs_debug_kernel_msg_recv_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-rib",
+ .cbs = {
+ .modify = zebra_debugs_debug_rib_modify,
+ .destroy = zebra_debugs_debug_rib_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-rib-detail",
+ .cbs = {
+ .modify = zebra_debugs_debug_rib_detail_modify,
+ .destroy = zebra_debugs_debug_rib_detail_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-fpm",
+ .cbs = {
+ .modify = zebra_debugs_debug_fpm_modify,
+ .destroy = zebra_debugs_debug_fpm_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-nht",
+ .cbs = {
+ .modify = zebra_debugs_debug_nht_modify,
+ .destroy = zebra_debugs_debug_nht_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-nht-detail",
+ .cbs = {
+ .modify = zebra_debugs_debug_nht_detail_modify,
+ .destroy = zebra_debugs_debug_nht_detail_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-mpls",
+ .cbs = {
+ .modify = zebra_debugs_debug_mpls_modify,
+ .destroy = zebra_debugs_debug_mpls_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-vxlan",
+ .cbs = {
+ .modify = zebra_debugs_debug_vxlan_modify,
+ .destroy = zebra_debugs_debug_vxlan_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-pw",
+ .cbs = {
+ .modify = zebra_debugs_debug_pw_modify,
+ .destroy = zebra_debugs_debug_pw_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-dplane",
+ .cbs = {
+ .modify = zebra_debugs_debug_dplane_modify,
+ .destroy = zebra_debugs_debug_dplane_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-dplane-detail",
+ .cbs = {
+ .modify = zebra_debugs_debug_dplane_detail_modify,
+ .destroy = zebra_debugs_debug_dplane_detail_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-mlag",
+ .cbs = {
+ .modify = zebra_debugs_debug_mlag_modify,
+ .destroy = zebra_debugs_debug_mlag_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-route-information",
+ .cbs = {
+ .rpc = get_route_information_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-v6-mroute-info",
+ .cbs = {
+ .rpc = get_v6_mroute_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-vrf-info",
+ .cbs = {
+ .rpc = get_vrf_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-vrf-vni-info",
+ .cbs = {
+ .rpc = get_vrf_vni_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-info",
+ .cbs = {
+ .rpc = get_evpn_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-vni-info",
+ .cbs = {
+ .rpc = get_vni_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-vni-rmac",
+ .cbs = {
+ .rpc = get_evpn_vni_rmac_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-vni-nexthops",
+ .cbs = {
+ .rpc = get_evpn_vni_nexthops_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:clear-evpn-dup-addr",
+ .cbs = {
+ .rpc = clear_evpn_dup_addr_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-macs",
+ .cbs = {
+ .rpc = get_evpn_macs_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-arp-cache",
+ .cbs = {
+ .rpc = get_evpn_arp_cache_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-pbr-ipset",
+ .cbs = {
+ .rpc = get_pbr_ipset_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-pbr-iptable",
+ .cbs = {
+ .rpc = get_pbr_iptable_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-debugs",
+ .cbs = {
+ .rpc = get_debugs_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list",
+ .cbs = {
+ .create = lib_interface_zebra_ip4_addr_list_create,
+ .destroy = lib_interface_zebra_ip4_addr_list_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list/ip4-peer",
+ .cbs = {
+ .modify = lib_interface_zebra_ip4_addr_list_ip4_peer_modify,
+ .destroy = lib_interface_zebra_ip4_addr_list_ip4_peer_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list/label",
+ .cbs = {
+ .modify = lib_interface_zebra_ip4_addr_list_label_modify,
+ .destroy = lib_interface_zebra_ip4_addr_list_label_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip6-addr-list",
+ .cbs = {
+ .create = lib_interface_zebra_ip6_addr_list_create,
+ .destroy = lib_interface_zebra_ip6_addr_list_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip6-addr-list/label",
+ .cbs = {
+ .modify = lib_interface_zebra_ip6_addr_list_label_modify,
+ .destroy = lib_interface_zebra_ip6_addr_list_label_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/multicast",
+ .cbs = {
+ .modify = lib_interface_zebra_multicast_modify,
+ .destroy = lib_interface_zebra_multicast_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-detect",
+ .cbs = {
+ .modify = lib_interface_zebra_link_detect_modify,
+ .destroy = lib_interface_zebra_link_detect_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/shutdown",
+ .cbs = {
+ .modify = lib_interface_zebra_shutdown_modify,
+ .destroy = lib_interface_zebra_shutdown_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/bandwidth",
+ .cbs = {
+ .modify = lib_interface_zebra_bandwidth_modify,
+ .destroy = lib_interface_zebra_bandwidth_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv4-prefix-length",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_ipv4_prefix_length_modify,
+ .destroy = lib_route_map_entry_match_condition_ipv4_prefix_length_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv6-prefix-length",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_ipv6_prefix_length_modify,
+ .destroy = lib_route_map_entry_match_condition_ipv6_prefix_length_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-protocol",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_source_protocol_modify,
+ .destroy = lib_route_map_entry_match_condition_source_protocol_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-instance",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_source_instance_modify,
+ .destroy = lib_route_map_entry_match_condition_source_instance_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v4",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_source_v4_modify,
+ .destroy = lib_route_map_entry_set_action_source_v4_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v6",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_source_v6_modify,
+ .destroy = lib_route_map_entry_set_action_source_v6_destroy,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 29d59b515f..58967de778 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -112,7 +112,7 @@ static const struct {
/* no entry/default: 150 */
};
-static void __attribute__((format(printf, 5, 6)))
+static void PRINTFRR(5, 6)
_rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
int priority, const char *msgfmt, ...)
{
@@ -213,7 +213,7 @@ static void route_entry_attach_ref(struct route_entry *re,
int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new)
{
- struct nhg_hash_entry *old = NULL;
+ struct nhg_hash_entry *old;
int ret = 0;
if (new == NULL) {
@@ -223,7 +223,7 @@ int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new)
goto done;
}
- if (re->nhe_id != new->id) {
+ if ((re->nhe_id != 0) && (re->nhe_id != new->id)) {
old = re->nhe;
route_entry_attach_ref(re, new);
@@ -2338,7 +2338,6 @@ static void rib_addnode(struct route_node *rn,
void rib_unlink(struct route_node *rn, struct route_entry *re)
{
rib_dest_t *dest;
- struct nhg_hash_entry *nhe = NULL;
assert(rn && re);
@@ -2353,11 +2352,10 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
if (dest->selected_fib == re)
dest->selected_fib = NULL;
- if (re->nhe_id) {
- nhe = zebra_nhg_lookup_id(re->nhe_id);
- if (nhe)
- zebra_nhg_decrement_ref(nhe);
- } else if (re->nhe->nhg.nexthop)
+ if (re->nhe && re->nhe_id) {
+ assert(re->nhe->id == re->nhe_id);
+ zebra_nhg_decrement_ref(re->nhe);
+ } else if (re->nhe && re->nhe->nhg.nexthop)
nexthops_free(re->nhe->nhg.nexthop);
nexthops_free(re->fib_ng.nexthop);
@@ -2396,11 +2394,75 @@ void rib_delnode(struct route_node *rn, struct route_entry *re)
}
}
+/*
+ * Helper that debugs a single nexthop within a route-entry
+ */
+static void _route_entry_dump_nh(const struct route_entry *re,
+ const char *straddr,
+ const struct nexthop *nexthop)
+{
+ char nhname[PREFIX_STRLEN];
+ char backup_str[50];
+ char wgt_str[50];
+ struct interface *ifp;
+ struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ sprintf(nhname, "Blackhole");
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
+ sprintf(nhname, "%s", ifp ? ifp->name : "Unknown");
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ /* fallthrough */
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ inet_ntop(AF_INET, &nexthop->gate, nhname, INET6_ADDRSTRLEN);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ inet_ntop(AF_INET6, &nexthop->gate, nhname, INET6_ADDRSTRLEN);
+ break;
+ }
+
+ backup_str[0] = '\0';
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ snprintf(backup_str, sizeof(backup_str), "backup %d,",
+ (int)nexthop->backup_idx);
+ }
+
+ wgt_str[0] = '\0';
+ if (nexthop->weight)
+ snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight);
+
+ zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s",
+ straddr, (nexthop->rparent ? " NH" : "NH"), nhname,
+ nexthop->ifindex, vrf ? vrf->name : "Unknown",
+ nexthop->vrf_id,
+ wgt_str, backup_str,
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
+ ? "ACTIVE "
+ : ""),
+ (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
+ ? "FIB "
+ : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
+ ? "RECURSIVE "
+ : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)
+ ? "ONLINK "
+ : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)
+ ? "DUPLICATE "
+ : ""));
+
+}
+
/* This function dumps the contents of a given RE entry into
* standard debug log. Calling function name and IP prefix in
* question are passed as 1st and 2nd arguments.
*/
-
void _route_entry_dump(const char *func, union prefixconstptr pp,
union prefixconstptr src_pp,
const struct route_entry *re)
@@ -2409,9 +2471,9 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
bool is_srcdst = src_p && src_p->prefixlen;
char straddr[PREFIX_STRLEN];
char srcaddr[PREFIX_STRLEN];
- char nhname[PREFIX_STRLEN];
struct nexthop *nexthop;
struct vrf *vrf = vrf_lookup_by_id(re->vrf_id);
+ struct nexthop_group *nhg;
zlog_debug("%s: dumping RE entry %p for %s%s%s vrf %s(%u)", func,
(const void *)re, prefix2str(pp, straddr, sizeof(straddr)),
@@ -2422,65 +2484,32 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d",
straddr, (unsigned long)re->uptime, re->type, re->instance,
re->table);
- zlog_debug(
- "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
- straddr, re->metric, re->mtu, re->distance, re->flags, re->status);
+ zlog_debug("%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
+ straddr, re->metric, re->mtu, re->distance, re->flags,
+ re->status);
zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr,
nexthop_group_nexthop_num(&(re->nhe->nhg)),
nexthop_group_active_nexthop_num(&(re->nhe->nhg)));
- for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
- struct interface *ifp;
- struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+ /* Dump nexthops */
+ for (ALL_NEXTHOPS(re->nhe->nhg, nexthop))
+ _route_entry_dump_nh(re, straddr, nexthop);
- switch (nexthop->type) {
- case NEXTHOP_TYPE_BLACKHOLE:
- sprintf(nhname, "Blackhole");
- break;
- case NEXTHOP_TYPE_IFINDEX:
- ifp = if_lookup_by_index(nexthop->ifindex,
- nexthop->vrf_id);
- sprintf(nhname, "%s", ifp ? ifp->name : "Unknown");
- break;
- case NEXTHOP_TYPE_IPV4:
- /* fallthrough */
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- inet_ntop(AF_INET, &nexthop->gate, nhname,
- INET6_ADDRSTRLEN);
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- inet_ntop(AF_INET6, &nexthop->gate, nhname,
- INET6_ADDRSTRLEN);
- break;
- }
- zlog_debug("%s: %s %s[%u] vrf %s(%u) with flags %s%s%s%s%s",
- straddr, (nexthop->rparent ? " NH" : "NH"), nhname,
- nexthop->ifindex, vrf ? vrf->name : "Unknown",
- nexthop->vrf_id,
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
- ? "ACTIVE "
- : ""),
- (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
- ? "FIB "
- : ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
- ? "RECURSIVE "
- : ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)
- ? "ONLINK "
- : ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)
- ? "DUPLICATE "
- : ""));
+ if (zebra_nhg_get_backup_nhg(re->nhe)) {
+ zlog_debug("%s: backup nexthops:", straddr);
+
+ nhg = zebra_nhg_get_backup_nhg(re->nhe);
+ for (ALL_NEXTHOPS_PTR(nhg, nexthop))
+ _route_entry_dump_nh(re, straddr, nexthop);
}
+
zlog_debug("%s: dump complete", straddr);
}
-/* This is an exported helper to rtm_read() to dump the strange
+/*
+ * This is an exported helper to rtm_read() to dump the strange
* RE entry found by rib_lookup_ipv4_route()
*/
-
void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id)
{
struct route_table *table;
@@ -2574,9 +2603,16 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
}
}
-int 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)
+/*
+ * Internal route-add implementation; there are a couple of different public
+ * signatures. Callers in this path are responsible for the memory they
+ * allocate: if they allocate a nexthop_group or backup nexthop info, they
+ * must free those objects. If this returns < 0, an error has occurred and the
+ * route_entry 're' has not been captured; the caller should free that also.
+ */
+int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
+ struct prefix_ipv6 *src_p, struct route_entry *re,
+ struct nhg_hash_entry *re_nhe)
{
struct nhg_hash_entry *nhe = NULL;
struct route_table *table;
@@ -2584,41 +2620,31 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
struct route_entry *same = NULL;
int ret = 0;
- if (!re)
- return 0;
+ if (!re || !re_nhe)
+ return -1;
assert(!src_p || !src_p->prefixlen || afi == AFI_IP6);
/* Lookup table. */
table = zebra_vrf_get_table_with_table_id(afi, safi, re->vrf_id,
re->table);
- if (!table) {
- if (ng)
- nexthop_group_delete(&ng);
- XFREE(MTYPE_RE, re);
- return 0;
- }
+ if (!table)
+ return -1;
- if (re->nhe_id) {
- nhe = zebra_nhg_lookup_id(re->nhe_id);
+ if (re_nhe->id > 0) {
+ nhe = zebra_nhg_lookup_id(re_nhe->id);
if (!nhe) {
flog_err(
EC_ZEBRA_TABLE_LOOKUP_FAILED,
"Zebra failed to find the nexthop hash entry for id=%u in a route entry",
- re->nhe_id);
- XFREE(MTYPE_RE, re);
+ re_nhe->id);
+
return -1;
}
} else {
- nhe = zebra_nhg_rib_find(0, ng, afi);
-
- /*
- * The nexthops got copied over into an nhe,
- * so free them now.
- */
- nexthop_group_delete(&ng);
-
+ /* Lookup nhe from route information */
+ nhe = zebra_nhg_rib_find_nhe(re_nhe, afi);
if (!nhe) {
char buf[PREFIX_STRLEN] = "";
char buf2[PREFIX_STRLEN] = "";
@@ -2631,7 +2657,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
src_p ? prefix2str(src_p, buf2, sizeof(buf2))
: "");
- XFREE(MTYPE_RE, re);
return -1;
}
}
@@ -2709,15 +2734,51 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
ret = 1;
/* Free implicit route.*/
- if (same) {
+ if (same)
rib_delnode(rn, same);
- ret = -1;
- }
route_unlock_node(rn);
return ret;
}
+/*
+ * Add a single route.
+ */
+int 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 ret;
+ struct nhg_hash_entry nhe;
+
+ if (!re)
+ return -1;
+
+ /* We either need nexthop(s) or an existing nexthop id */
+ if (ng == NULL && re->nhe_id == 0)
+ return -1;
+
+ /*
+ * Use a temporary nhe to convey info to the common/main api.
+ */
+ zebra_nhe_init(&nhe, afi, (ng ? ng->nexthop : NULL));
+ if (ng)
+ nhe.nhg.nexthop = ng->nexthop;
+ else if (re->nhe_id > 0)
+ nhe.id = re->nhe_id;
+
+ ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, &nhe);
+
+ /* In this path, the callers expect memory to be freed. */
+ nexthop_group_delete(&ng);
+
+ /* In error cases, free the route also */
+ if (ret < 0)
+ XFREE(MTYPE_RE, re);
+
+ return ret;
+}
+
void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, int flags, struct prefix *p,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
@@ -3188,6 +3249,9 @@ void rib_sweep_table(struct route_table *table)
if (!table)
return;
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s: starting", __func__);
+
for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
RNODE_FOREACH_RE_SAFE (rn, re, next) {
@@ -3234,6 +3298,9 @@ void rib_sweep_table(struct route_table *table)
rib_delnode(rn, re);
}
}
+
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s: ends", __func__);
}
/* Sweep all RIB tables. */
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index c758e25839..f9c74c7462 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -471,7 +471,7 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
*prn = rn;
if (!re && IS_ZEBRA_DEBUG_NHT_DETAILED)
- zlog_debug("\tRejected due to removed or is a bgp route");
+ zlog_debug(" Rejected due to removed or is a bgp route");
return re;
}
@@ -656,7 +656,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
&& !rnh_resolve_via_default(zvrf, rn->p.family)) {
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug(
- "\tNot allowed to resolve through default prefix");
+ " Not allowed to resolve through default prefix");
return NULL;
}
@@ -665,7 +665,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug(
- "\tRoute Entry %s removed",
+ " Route Entry %s removed",
zebra_route_string(re->type));
continue;
}
@@ -673,7 +673,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
!CHECK_FLAG(re->flags, ZEBRA_FLAG_FIB_OVERRIDE)) {
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug(
- "\tRoute Entry %s !selected",
+ " Route Entry %s !selected",
zebra_route_string(re->type));
continue;
}
@@ -681,7 +681,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) {
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug(
- "\tRoute Entry %s queued",
+ " Route Entry %s queued",
zebra_route_string(re->type));
continue;
}
@@ -697,7 +697,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
if (nexthop == NULL) {
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug(
- "\tRoute Entry %s no nexthops",
+ " Route Entry %s no nexthops",
zebra_route_string(re->type));
continue;
}
@@ -732,7 +732,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
else {
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug(
- "\tNexthop must be connected, cannot recurse up");
+ " Nexthop must be connected, cannot recurse up");
return NULL;
}
}
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 500c2c84a1..2b3b3afbb5 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -30,6 +30,8 @@
#include "filter.h"
#include "plist.h"
#include "nexthop.h"
+#include "northbound_cli.h"
+#include "route_types.h"
#include "vrf.h"
#include "frrstr.h"
@@ -58,82 +60,6 @@ struct nh_rmap_obj {
static void zebra_route_map_set_delay_timer(uint32_t value);
-
-/* Add zebra route map rule */
-static int zebra_route_match_add(struct vty *vty, const char *command,
- const char *arg, route_map_event_t type)
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- enum rmap_compile_rets ret;
- int retval = CMD_SUCCESS;
-
- ret = route_map_add_match(index, command, arg, type);
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Zebra Can't find rule.\n");
- retval = CMD_WARNING_CONFIG_FAILED;
- break;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% Zebra Argument is malformed.\n");
- retval = CMD_WARNING_CONFIG_FAILED;
- break;
- case RMAP_COMPILE_SUCCESS:
- /*
- * Nothing to do here
- */
- break;
- }
-
- return retval;
-}
-
-/* Delete zebra route map rule. */
-static int zebra_route_match_delete(struct vty *vty, const char *command,
- const char *arg, route_map_event_t type)
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- enum rmap_compile_rets ret;
- int retval = CMD_SUCCESS;
- char *dep_name = NULL;
- const char *tmpstr;
- char *rmap_name = NULL;
-
- if (type != RMAP_EVENT_MATCH_DELETED) {
- /* ignore the mundane, the types without any dependency */
- if (arg == NULL) {
- if ((tmpstr = route_map_get_match_arg(index, command))
- != NULL)
- dep_name =
- XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
- } else {
- dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
- }
- rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
- }
-
- ret = route_map_delete_match(index, command, arg, type);
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Zebra Can't find rule.\n");
- retval = CMD_WARNING_CONFIG_FAILED;
- break;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% Zebra Argument is malformed.\n");
- retval = CMD_WARNING_CONFIG_FAILED;
- break;
- case RMAP_COMPILE_SUCCESS:
- /*
- * Nothing to do here
- */
- break;
- }
-
- XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
- XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
-
- return retval;
-}
-
/* 'match tag TAG'
* Match function return 1 if match is success else return 0
*/
@@ -425,246 +351,227 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype,
return CMD_SUCCESS;
}
-DEFUN (match_ip_address_prefix_len,
- match_ip_address_prefix_len_cmd,
- "match ip address prefix-len (0-32)",
- MATCH_STR
- IP_STR
- "Match prefix length of ip address\n"
- "Match prefix length of ip address\n"
- "Prefix length\n")
+DEFPY(
+ match_ip_address_prefix_len, match_ip_address_prefix_len_cmd,
+ "match ip address prefix-len (0-32)$length",
+ MATCH_STR
+ IP_STR
+ "Match prefix length of IP address\n"
+ "Match prefix length of IP address\n"
+ "Prefix length\n")
{
- return zebra_route_match_add(vty, "ip address prefix-len", argv[4]->arg,
- RMAP_EVENT_MATCH_ADDED);
+ const char *xpath = "./match-condition[condition='ipv4-prefix-length']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:ipv4-prefix-length", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_match_ip_address_prefix_len,
- no_match_ip_address_prefix_len_cmd,
- "no match ip address prefix-len [(0-32)]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match prefix length of ip address\n"
- "Match prefix length of ip address\n"
- "Prefix length\n")
+DEFPY(
+ no_match_ip_address_prefix_len, no_match_ip_address_prefix_len_cmd,
+ "no match ip address prefix-len [(0-32)]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefix length of IP address\n"
+ "Match prefix length of IP address\n"
+ "Prefix length\n")
{
- char *plen = (argc == 6) ? argv[5]->arg : NULL;
- return zebra_route_match_delete(vty, "ip address prefix-len", plen,
- RMAP_EVENT_MATCH_DELETED);
+ const char *xpath = "./match-condition[condition='ipv4-prefix-length']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (match_ipv6_address_prefix_len,
- match_ipv6_address_prefix_len_cmd,
- "match ipv6 address prefix-len (0-128)",
- MATCH_STR
- IPV6_STR
- "Match prefix length of ipv6 address\n"
- "Match prefix length of ipv6 address\n"
- "Prefix length\n")
+DEFPY(
+ match_ipv6_address_prefix_len, match_ipv6_address_prefix_len_cmd,
+ "match ipv6 address prefix-len (0-128)$length",
+ MATCH_STR
+ IPV6_STR
+ "Match prefix length of IPv6 address\n"
+ "Match prefix length of IPv6 address\n"
+ "Prefix length\n")
{
- return zebra_route_match_add(vty, "ipv6 address prefix-len",
- argv[4]->arg, RMAP_EVENT_MATCH_ADDED);
+ const char *xpath = "./match-condition[condition='ipv6-prefix-length']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:ipv6-prefix-length", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_match_ipv6_address_prefix_len,
- no_match_ipv6_address_prefix_len_cmd,
- "no match ipv6 address prefix-len [(0-128)]",
- NO_STR
- MATCH_STR
- IPV6_STR
- "Match prefix length of ip address\n"
- "Match prefix length of ip address\n"
- "Prefix length\n")
+DEFPY(
+ no_match_ipv6_address_prefix_len, no_match_ipv6_address_prefix_len_cmd,
+ "no match ipv6 address prefix-len [(0-128)]",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match prefix length of IPv6 address\n"
+ "Match prefix length of IPv6 address\n"
+ "Prefix length\n")
{
- char *plen = (argc == 6) ? argv[5]->arg : NULL;
- return zebra_route_match_delete(vty, "ipv6 address prefix-len", plen,
- RMAP_EVENT_MATCH_DELETED);
+ const char *xpath = "./match-condition[condition='ipv6-prefix-length']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (match_ip_nexthop_prefix_len,
- match_ip_nexthop_prefix_len_cmd,
- "match ip next-hop prefix-len (0-32)",
- MATCH_STR
- IP_STR
- "Match prefixlen of nexthop ip address\n"
- "Match prefixlen of given nexthop\n"
- "Prefix length\n")
+DEFPY(
+ match_ip_nexthop_prefix_len, match_ip_nexthop_prefix_len_cmd,
+ "match ip next-hop prefix-len (0-32)$length",
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of nexthop IP address\n"
+ "Match prefixlen of given nexthop\n"
+ "Prefix length\n")
{
- return zebra_route_match_add(vty, "ip next-hop prefix-len",
- argv[4]->arg, RMAP_EVENT_MATCH_ADDED);
+ const char *xpath =
+ "./match-condition[condition='ipv4-next-hop-prefix-length']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:ipv4-prefix-length", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_match_ip_nexthop_prefix_len,
- no_match_ip_nexthop_prefix_len_cmd,
- "no match ip next-hop prefix-len [(0-32)]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match prefixlen of nexthop ip address\n"
- "Match prefix length of nexthop\n"
- "Prefix length\n")
-{
- char *plen = (argc == 6) ? argv[5]->arg : NULL;
- return zebra_route_match_delete(vty, "ip next-hop prefix-len", plen,
- RMAP_EVENT_MATCH_DELETED);
-}
-
-DEFUN (match_source_protocol,
- match_source_protocol_cmd,
- "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>",
- MATCH_STR
- "Match protocol via which the route was learnt\n"
- "BGP protocol\n"
- "OSPF protocol\n"
- "RIP protocol\n"
- "RIPNG protocol\n"
- "ISIS protocol\n"
- "OSPF6 protocol\n"
- "PIM protocol\n"
- "NHRP protocol\n"
- "EIGRP protocol\n"
- "BABEL protocol\n"
- "Routes from directly connected peer\n"
- "Routes from system configuration\n"
- "Routes from kernel\n"
- "Statically configured routes\n"
- "SHARP process\n")
-{
- char *proto = argv[2]->text;
- int i;
+DEFPY(
+ no_match_ip_nexthop_prefix_len, no_match_ip_nexthop_prefix_len_cmd,
+ "no match ip next-hop prefix-len [(0-32)]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of nexthop IP address\n"
+ "Match prefix length of nexthop\n"
+ "Prefix length\n")
+{
+ const char *xpath =
+ "./match-condition[condition='ipv4-next-hop-prefix-length']";
- i = proto_name2num(proto);
- if (i < 0) {
- vty_out(vty, "invalid protocol name \"%s\"\n", proto);
- return CMD_WARNING_CONFIG_FAILED;
- }
- return zebra_route_match_add(vty, "source-protocol", proto,
- RMAP_EVENT_MATCH_ADDED);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_match_source_protocol,
- no_match_source_protocol_cmd,
- "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>]",
- NO_STR
- MATCH_STR
- "No match protocol via which the route was learnt\n"
- "BGP protocol\n"
- "OSPF protocol\n"
- "RIP protocol\n"
- "RIPNG protocol\n"
- "ISIS protocol\n"
- "OSPF6 protocol\n"
- "PIM protocol\n"
- "NHRP protocol\n"
- "EIGRP protocol\n"
- "BABEL protocol\n"
- "Routes from directly connected peer\n"
- "Routes from system configuration\n"
- "Routes from kernel\n"
- "Statically configured routes\n"
- "SHARP process\n")
-{
- char *proto = (argc == 4) ? argv[3]->text : NULL;
- return zebra_route_match_delete(vty, "source-protocol", proto,
- RMAP_EVENT_MATCH_DELETED);
-}
-
-DEFUN (match_source_instance,
- match_source_instance_cmd,
- "match source-instance (0-255)",
- MATCH_STR
- "Match the protocol's instance number\n"
- "The instance number\n")
-{
- char *instance = argv[2]->arg;
-
- return zebra_route_match_add(vty, "source-instance", instance,
- RMAP_EVENT_MATCH_ADDED);
-}
-
-DEFUN (no_match_source_instance,
- no_match_source_instance_cmd,
- "no match source-instance [(0-255)]",
- NO_STR MATCH_STR
- "Match the protocol's instance number\n"
- "The instance number\n")
-{
- char *instance = (argc == 4) ? argv[3]->arg : NULL;
-
- return zebra_route_match_delete(vty, "source-instance", instance,
- RMAP_EVENT_MATCH_ADDED);
+DEFPY(
+ match_source_protocol, match_source_protocol_cmd,
+ "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto",
+ MATCH_STR
+ "Match protocol via which the route was learnt\n"
+ FRR_REDIST_HELP_STR_ZEBRA)
+{
+ const char *xpath = "./match-condition[condition='source-protocol']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:source-protocol", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-/* set functions */
+DEFPY(
+ no_match_source_protocol, no_match_source_protocol_cmd,
+ "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]",
+ NO_STR
+ MATCH_STR
+ "Match protocol via which the route was learnt\n"
+ FRR_REDIST_HELP_STR_ZEBRA)
+{
+ const char *xpath = "./match-condition[condition='source-protocol']";
-DEFUN (set_src,
- set_src_cmd,
- "set src <A.B.C.D|X:X::X:X>",
- SET_STR
- "src address for route\n"
- "IPv4 src address\n"
- "IPv6 src address\n")
-{
- int idx_ip = 2;
- union g_addr src;
- struct interface *pif = NULL;
- int family;
- struct prefix p;
- struct vrf *vrf;
-
- if (inet_pton(AF_INET, argv[idx_ip]->arg, &src.ipv4) != 1) {
- if (inet_pton(AF_INET6, argv[idx_ip]->arg, &src.ipv6) != 1) {
- vty_out(vty, "%% not a valid IPv4/v6 address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- p.family = family = AF_INET6;
- p.u.prefix6 = src.ipv6;
- p.prefixlen = IPV6_MAX_BITLEN;
- } else {
- p.family = family = AF_INET;
- p.u.prefix4 = src.ipv4;
- p.prefixlen = IPV4_MAX_BITLEN;
- }
+ return nb_cli_apply_changes(vty, NULL);
+}
- if (!zebra_check_addr(&p)) {
- vty_out(vty, "%% not a valid source IPv4/v6 address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+DEFPY(
+ match_source_instance, match_source_instance_cmd,
+ "match source-instance (0-255)$instance",
+ MATCH_STR
+ "Match the protocol's instance number\n"
+ "The instance number\n")
+{
+ const char *xpath = "./match-condition[condition='source-instance']";
+ char xpath_value[XPATH_MAXLEN];
- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
- if (family == AF_INET)
- pif = if_lookup_exact_address((void *)&src.ipv4,
- AF_INET, vrf->vrf_id);
- else if (family == AF_INET6)
- pif = if_lookup_exact_address((void *)&src.ipv6,
- AF_INET6, vrf->vrf_id);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:source-instance", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str);
- if (pif != NULL)
- break;
- }
+ return nb_cli_apply_changes(vty, NULL);
+}
- if (!pif) {
- vty_out(vty, "%% not a local address\n");
- return CMD_WARNING_CONFIG_FAILED;
+DEFPY(
+ no_match_source_instance, no_match_source_instance_cmd,
+ "no match source-instance [(0-255)]",
+ NO_STR MATCH_STR
+ "Match the protocol's instance number\n"
+ "The instance number\n")
+{
+ const char *xpath = "./match-condition[condition='source-instance']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+/* set functions */
+
+DEFPY(
+ set_src, set_src_cmd,
+ "set src <A.B.C.D$addrv4|X:X::X:X$addrv6>",
+ SET_STR
+ "src address for route\n"
+ "IPv4 src address\n"
+ "IPv6 src address\n")
+{
+ const char *xpath = "./set-action[action='source']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (addrv4_str) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:source-v4", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+ addrv4_str);
+ } else {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:source-v6", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+ addrv6_str);
}
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- return generic_set_add(vty, index, "src", argv[idx_ip]->arg);
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_set_src,
- no_set_src_cmd,
- "no set src [<A.B.C.D|X:X::X:X>]",
- NO_STR
- SET_STR
- "Source address for route\n"
- "IPv4 address\n"
- "IPv6 address\n")
-{
- char *ip = (argc == 4) ? argv[3]->arg : NULL;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- return generic_set_delete(vty, index, "src", ip);
+DEFPY(
+ no_set_src, no_set_src_cmd,
+ "no set src [<A.B.C.D|X:X::X:X>]",
+ NO_STR
+ SET_STR
+ "Source address for route\n"
+ "IPv4 address\n"
+ "IPv6 address\n")
+{
+ const char *xpath = "./set-action[action='source']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
DEFUN (zebra_route_map_timer,
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index a891ffb76a..ea2b6752b3 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -223,10 +223,11 @@ void zebra_router_terminate(void)
zebra_vxlan_disable();
zebra_mlag_terminate();
- hash_clean(zrouter.nhgs, zebra_nhg_hash_free);
- hash_free(zrouter.nhgs);
- hash_clean(zrouter.nhgs_id, NULL);
+ /* Free NHE in ID table only since it has unhashable entries as well */
+ hash_clean(zrouter.nhgs_id, zebra_nhg_hash_free);
hash_free(zrouter.nhgs_id);
+ hash_clean(zrouter.nhgs, NULL);
+ hash_free(zrouter.nhgs);
hash_clean(zrouter.rules_hash, zebra_pbr_rules_free);
hash_free(zrouter.rules_hash);
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index 59bd0e55f0..773e5a6415 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -218,6 +218,9 @@ extern void multicast_mode_ipv4_set(enum multicast_mode mode);
extern enum multicast_mode multicast_mode_ipv4_get(void);
+/* zebra_northbound.c */
+extern const struct frr_yang_module_info frr_zebra_info;
+
#ifdef __cplusplus
}
#endif
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index c392303760..ee1e251a69 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -60,8 +60,13 @@ static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf));
- for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
zsend_vrf_add(client, zvrf);
+ }
}
static void zebra_vrf_delete_update(struct zebra_vrf *zvrf)
@@ -72,8 +77,13 @@ static void zebra_vrf_delete_update(struct zebra_vrf *zvrf)
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf));
- for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ /* Do not send unsolicited messages to synchronous clients. */
+ if (client->synchronous)
+ continue;
+
zsend_vrf_delete(client, zvrf);
+ }
}
void zebra_vrf_update_all(struct zserv *client)
@@ -168,7 +178,7 @@ static int zebra_vrf_disable(struct vrf *vrf)
zebra_vxlan_vrf_disable(zvrf);
#if defined(HAVE_RTADV)
- rtadv_terminate(zvrf);
+ rtadv_vrf_terminate(zvrf);
#endif
/* Inform clients that the VRF is now inactive. This is a
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index ccc6e9e46b..590ec57087 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -164,7 +164,8 @@ DEFUN (show_ip_rpf_addr,
return CMD_SUCCESS;
}
-static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
+static char re_status_output_char(const struct route_entry *re,
+ const struct nexthop *nhop)
{
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) &&
@@ -187,6 +188,152 @@ static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
return ' ';
}
+/*
+ * TODO -- Show backup nexthop info
+ */
+static void show_nh_backup_helper(struct vty *vty,
+ const struct nhg_hash_entry *nhe,
+ const struct nexthop *nexthop)
+{
+ /* Double-check that there _is_ a backup */
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return;
+
+ /* Locate the backup nexthop */
+
+ /* Format the backup (indented) */
+
+}
+
+/*
+ * Helper api to format output for a nexthop, used in the 'detailed'
+ * output path.
+ */
+static void show_nexthop_detail_helper(struct vty *vty,
+ const struct route_entry *re,
+ const struct nexthop *nexthop)
+{
+ char addrstr[32];
+ char buf[MPLS_LABEL_STRLEN];
+
+ vty_out(vty, " %c%s",
+ re_status_output_char(re, nexthop),
+ nexthop->rparent ? " " : "");
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out(vty, " %s",
+ inet_ntoa(nexthop->gate.ipv4));
+ if (nexthop->ifindex)
+ vty_out(vty, ", via %s",
+ ifindex2ifname(
+ nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ vty_out(vty, " %s",
+ inet_ntop(AF_INET6, &nexthop->gate.ipv6,
+ buf, sizeof(buf)));
+ if (nexthop->ifindex)
+ vty_out(vty, ", via %s",
+ ifindex2ifname(
+ nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out(vty, " directly connected, %s",
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ vty_out(vty, " unreachable");
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ vty_out(vty, " (ICMP unreachable)");
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ vty_out(vty,
+ " (ICMP admin-prohibited)");
+ break;
+ case BLACKHOLE_NULL:
+ vty_out(vty, " (blackhole)");
+ break;
+ case BLACKHOLE_UNSPEC:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ((re->vrf_id != nexthop->vrf_id)
+ && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
+ struct vrf *vrf =
+ vrf_lookup_by_id(nexthop->vrf_id);
+
+ if (vrf)
+ vty_out(vty, "(vrf %s)", vrf->name);
+ else
+ vty_out(vty, "(vrf UNKNOWN)");
+ }
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
+ vty_out(vty, " (duplicate nexthop removed)");
+
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out(vty, " inactive");
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
+ vty_out(vty, " onlink");
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ vty_out(vty, " (recursive)");
+
+ /* Source specified? */
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (nexthop->src.ipv4.s_addr) {
+ if (inet_ntop(AF_INET, &nexthop->src.ipv4,
+ addrstr, sizeof(addrstr)))
+ vty_out(vty, ", src %s",
+ addrstr);
+ }
+ break;
+
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
+ &in6addr_any)) {
+ if (inet_ntop(AF_INET6, &nexthop->src.ipv6,
+ addrstr, sizeof(addrstr)))
+ vty_out(vty, ", src %s",
+ addrstr);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (re->nexthop_mtu)
+ vty_out(vty, ", mtu %u", re->nexthop_mtu);
+
+ /* Label information */
+ if (nexthop->nh_label && nexthop->nh_label->num_labels) {
+ vty_out(vty, ", label %s",
+ mpls_label2str(nexthop->nh_label->num_labels,
+ nexthop->nh_label->label, buf,
+ sizeof(buf), 1 /*pretty*/));
+ }
+
+ if (nexthop->weight)
+ vty_out(vty, ", weight %u", nexthop->weight);
+}
+
/* New RIB. Detailed information for IPv4 route. */
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
int mcast, bool use_fib, bool show_ng)
@@ -253,129 +400,122 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id);
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
- char addrstr[32];
-
- vty_out(vty, " %c%s",
- re_status_output_char(re, nexthop),
- nexthop->rparent ? " " : "");
-
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " %s",
- inet_ntoa(nexthop->gate.ipv4));
- if (nexthop->ifindex)
- vty_out(vty, ", via %s",
- ifindex2ifname(
- nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6,
- buf, sizeof(buf)));
- if (nexthop->ifindex)
- vty_out(vty, ", via %s",
- ifindex2ifname(
- nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " directly connected, %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " unreachable");
- switch (nexthop->bh_type) {
- case BLACKHOLE_REJECT:
- vty_out(vty, " (ICMP unreachable)");
- break;
- case BLACKHOLE_ADMINPROHIB:
- vty_out(vty,
- " (ICMP admin-prohibited)");
- break;
- case BLACKHOLE_NULL:
- vty_out(vty, " (blackhole)");
- break;
- case BLACKHOLE_UNSPEC:
- break;
- }
- break;
- default:
- break;
- }
-
- if ((re->vrf_id != nexthop->vrf_id)
- && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
- struct vrf *vrf =
- vrf_lookup_by_id(nexthop->vrf_id);
-
- if (vrf)
- vty_out(vty, "(vrf %s)", vrf->name);
- else
- vty_out(vty, "(vrf UNKNOWN)");
- }
+ /* Use helper to format each nexthop */
+ show_nexthop_detail_helper(vty, re, nexthop);
+ vty_out(vty, "\n");
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
- vty_out(vty, " (duplicate nexthop removed)");
+ /* Include backup info, if present */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ show_nh_backup_helper(vty, re->nhe, nexthop);
+ }
+ vty_out(vty, "\n");
+ }
+}
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- vty_out(vty, " inactive");
+/*
+ * Helper for nexthop output, used in the 'show ip route' path
+ */
+static void show_route_nexthop_helper(struct vty *vty,
+ const struct route_entry *re,
+ const struct nexthop *nexthop)
+{
+ char buf[MPLS_LABEL_STRLEN];
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
+ if (nexthop->ifindex)
+ vty_out(vty, ", %s",
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ vty_out(vty, " via %s",
+ inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
+ sizeof(buf)));
+ if (nexthop->ifindex)
+ vty_out(vty, ", %s",
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
- vty_out(vty, " onlink");
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out(vty, " is directly connected, %s",
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ vty_out(vty, " unreachable");
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ vty_out(vty, " (ICMP unreachable)");
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ vty_out(vty, " (ICMP admin-prohibited)");
+ break;
+ case BLACKHOLE_NULL:
+ vty_out(vty, " (blackhole)");
+ break;
+ case BLACKHOLE_UNSPEC:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " (recursive)");
+ if ((re == NULL || (nexthop->vrf_id != re->vrf_id)) &&
+ (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
+ struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->src.ipv4.s_addr) {
- if (inet_ntop(AF_INET,
- &nexthop->src.ipv4,
- addrstr, sizeof(addrstr)))
- vty_out(vty, ", src %s",
- addrstr);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
- &in6addr_any)) {
- if (inet_ntop(AF_INET6,
- &nexthop->src.ipv6,
- addrstr, sizeof(addrstr)))
- vty_out(vty, ", src %s",
- addrstr);
- }
- break;
- default:
- break;
- }
+ if (vrf)
+ vty_out(vty, " (vrf %s)", vrf->name);
+ else
+ vty_out(vty, " (vrf UNKNOWN)");
+ }
- if (re->nexthop_mtu)
- vty_out(vty, ", mtu %u", re->nexthop_mtu);
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out(vty, " inactive");
- /* Label information */
- if (nexthop->nh_label
- && nexthop->nh_label->num_labels) {
- vty_out(vty, ", label %s",
- mpls_label2str(
- nexthop->nh_label->num_labels,
- nexthop->nh_label->label, buf,
- sizeof(buf), 1));
- }
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
+ vty_out(vty, " onlink");
- if (nexthop->weight)
- vty_out(vty, ", weight %u", nexthop->weight);
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ vty_out(vty, " (recursive)");
- vty_out(vty, "\n");
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (nexthop->src.ipv4.s_addr) {
+ if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
+ sizeof(buf)))
+ vty_out(vty, ", src %s", buf);
}
- vty_out(vty, "\n");
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
+ if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
+ sizeof(buf)))
+ vty_out(vty, ", src %s", buf);
+ }
+ break;
+ default:
+ break;
}
+
+ /* Label information */
+ if (nexthop->nh_label && nexthop->nh_label->num_labels) {
+ vty_out(vty, ", label %s",
+ mpls_label2str(nexthop->nh_label->num_labels,
+ nexthop->nh_label->label, buf,
+ sizeof(buf), 1));
+ }
+
+ if ((re == NULL) && nexthop->weight)
+ vty_out(vty, ", weight %u", nexthop->weight);
}
static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
@@ -660,105 +800,43 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
len - 3 + (2 * nexthop_level(nexthop)), ' ');
}
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " via %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
- sizeof(buf)));
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
-
- case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " is directly connected, %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " unreachable");
- switch (nexthop->bh_type) {
- case BLACKHOLE_REJECT:
- vty_out(vty, " (ICMP unreachable)");
- break;
- case BLACKHOLE_ADMINPROHIB:
- vty_out(vty, " (ICMP admin-prohibited)");
- break;
- case BLACKHOLE_NULL:
- vty_out(vty, " (blackhole)");
- break;
- case BLACKHOLE_UNSPEC:
- break;
- }
- break;
- default:
- break;
- }
-
- if ((nexthop->vrf_id != re->vrf_id)
- && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
- struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+ show_route_nexthop_helper(vty, re, nexthop);
- if (vrf)
- vty_out(vty, "(vrf %s)", vrf->name);
- else
- vty_out(vty, "(vrf UNKNOWN)");
- }
-
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- vty_out(vty, " inactive");
+ vty_out(vty, ", %s\n", up_str);
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
- vty_out(vty, " onlink");
+ /* Check for backup info */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ struct nexthop *backup;
+ int i;
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " (recursive)");
+ if (re->nhe->backup_info == NULL ||
+ re->nhe->backup_info->nhe == NULL)
+ continue;
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->src.ipv4.s_addr) {
- if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
- if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
+ i = 0;
+ for (ALL_NEXTHOPS(re->nhe->backup_info->nhe->nhg,
+ backup)) {
+ if (i == nexthop->backup_idx)
+ break;
+ i++;
}
- break;
- default:
- break;
- }
- /* Label information */
- if (nexthop->nh_label && nexthop->nh_label->num_labels) {
- vty_out(vty, ", label %s",
- mpls_label2str(nexthop->nh_label->num_labels,
- nexthop->nh_label->label, buf,
- sizeof(buf), 1));
+ /* Print useful backup info */
+ if (backup) {
+ /* TODO -- install state is not accurate */
+ vty_out(vty, " %*c [backup %d]",
+ /*re_status_output_char(re, backup),*/
+ len - 3 + (2 * nexthop_level(nexthop)),
+ ' ', nexthop->backup_idx);
+ show_route_nexthop_helper(vty, re, backup);
+ vty_out(vty, "\n");
+ }
}
-
- vty_out(vty, ", %s\n", up_str);
}
}
static void vty_show_ip_route_detail_json(struct vty *vty,
- struct route_node *rn, bool use_fib)
+ struct route_node *rn, bool use_fib)
{
json_object *json = NULL;
json_object *json_prefix = NULL;
@@ -1028,9 +1106,8 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
{
struct nexthop *nexthop = NULL;
struct nhg_connected *rb_node_dep = NULL;
- char buf[SRCDEST2STR_BUFFER];
-
struct vrf *nhe_vrf = vrf_lookup_by_id(nhe->vrf_id);
+ struct nexthop_group *backup_nhg;
vty_out(vty, "ID: %u\n", nhe->id);
vty_out(vty, " RefCnt: %d\n", nhe->refcnt);
@@ -1062,6 +1139,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
vty_out(vty, "\n");
}
+ /* Output nexthops */
for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
vty_out(vty, " ");
@@ -1069,100 +1147,56 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
/* Make recursive nexthops a bit more clear */
vty_out(vty, " ");
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " %s", inet_ntoa(nexthop->gate.ipv4));
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
- sizeof(buf)));
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
+ show_route_nexthop_helper(vty, NULL, nexthop);
- case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " directly connected %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " unreachable");
- switch (nexthop->bh_type) {
- case BLACKHOLE_REJECT:
- vty_out(vty, " (ICMP unreachable)");
- break;
- case BLACKHOLE_ADMINPROHIB:
- vty_out(vty, " (ICMP admin-prohibited)");
- break;
- case BLACKHOLE_NULL:
- vty_out(vty, " (blackhole)");
- break;
- case BLACKHOLE_UNSPEC:
- break;
- }
- break;
- default:
- break;
+ 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);
+
+ vty_out(vty, "\n");
+ continue;
}
- struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+ /* TODO -- print more useful backup info */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ struct nexthop *backup;
+ int i;
- if (vrf)
- vty_out(vty, " (vrf %s)", vrf->name);
- else
- vty_out(vty, " (vrf UNKNOWN)");
+ i = 0;
+ for (ALL_NEXTHOPS(nhe->backup_info->nhe->nhg, backup)) {
+ if (i == nexthop->backup_idx)
+ break;
+ i++;
+ }
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- vty_out(vty, " inactive");
+ /* TODO */
+ if (backup)
+ vty_out(vty, " [backup %d]",
+ nexthop->backup_idx);
+ else
+ vty_out(vty, " [backup INVALID]");
+ }
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
- vty_out(vty, " onlink");
+ vty_out(vty, "\n");
+ }
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " (recursive)");
+ /* Output backup nexthops (if any) */
+ backup_nhg = zebra_nhg_get_backup_nhg(nhe);
+ if (backup_nhg) {
+ vty_out(vty, " Backups:\n");
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->src.ipv4.s_addr) {
- if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
- if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
- }
- break;
- default:
- break;
- }
+ 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, " ");
- /* Label information */
- if (nexthop->nh_label && nexthop->nh_label->num_labels) {
- vty_out(vty, ", label %s",
- mpls_label2str(nexthop->nh_label->num_labels,
- nexthop->nh_label->label, buf,
- sizeof(buf), 1));
+ show_route_nexthop_helper(vty, NULL, nexthop);
+ vty_out(vty, "\n");
}
-
- if (nexthop->weight)
- vty_out(vty, ", weight %u", nexthop->weight);
-
- vty_out(vty, "\n");
}
if (!zebra_nhg_dependents_is_empty(nhe)) {
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 61865e5baf..aa2e5c91c9 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -121,11 +121,11 @@ static struct interface *zvni_map_to_macvlan(struct interface *br_if,
/* l3-vni next-hop neigh related APIs */
static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
- struct ipaddr *ip);
+ const struct ipaddr *ip);
static void *zl3vni_nh_alloc(void *p);
static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
- struct ipaddr *vtep_ip,
- struct ethaddr *rmac);
+ const struct ipaddr *vtep_ip,
+ const struct ethaddr *rmac);
static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
@@ -133,10 +133,10 @@ static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
/* l3-vni rmac related APIs */
static void zl3vni_print_rmac_hash(struct hash_bucket *, void *);
static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
- struct ethaddr *rmac);
+ const struct ethaddr *rmac);
static void *zl3vni_rmac_alloc(void *p);
static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
- struct ethaddr *rmac);
+ const struct ethaddr *rmac);
static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
@@ -3059,7 +3059,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
if (!zvrf) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("\tUnable to find vrf for: %d",
+ zlog_debug(" Unable to find vrf for: %d",
zvni->vxlan_if->vrf_id);
return -1;
}
@@ -3094,7 +3094,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
if (!mac_different && is_router == cur_is_router) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "\tIgnoring entry mac is the same and is_router == cur_is_router");
+ " Ignoring entry mac is the same and is_router == cur_is_router");
n->ifindex = ifp->ifindex;
return 0;
}
@@ -3126,7 +3126,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
else {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "\tNeighbor active and frozen");
+ " Neighbor active and frozen");
}
return 0;
}
@@ -3271,7 +3271,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
n->flags, n->loc_seq);
} else {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("\tNeighbor on hold not sending");
+ zlog_debug(" Neighbor on hold not sending");
}
return 0;
}
@@ -4434,7 +4434,7 @@ static void zl3vni_cleanup_all(struct hash_bucket *bucket, void *args)
}
static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe,
- struct prefix *host)
+ const struct prefix *host)
{
struct host_rb_entry lookup;
struct host_rb_entry *hle;
@@ -4473,7 +4473,7 @@ static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host)
* Look up MAC hash entry.
*/
static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
- struct ethaddr *rmac)
+ const struct ethaddr *rmac)
{
zebra_mac_t tmp;
zebra_mac_t *pmac;
@@ -4502,7 +4502,8 @@ static void *zl3vni_rmac_alloc(void *p)
/*
* Add RMAC entry to l3-vni
*/
-static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac)
+static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
+ const struct ethaddr *rmac)
{
zebra_mac_t tmp_rmac;
zebra_mac_t *zrmac = NULL;
@@ -4632,9 +4633,10 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
}
/* handle rmac add */
-static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac,
- struct ipaddr *vtep_ip,
- struct prefix *host_prefix)
+static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni,
+ const struct ethaddr *rmac,
+ const struct ipaddr *vtep_ip,
+ const struct prefix *host_prefix)
{
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
@@ -4709,7 +4711,8 @@ static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac,
/*
* Look up nh hash entry on a l3-vni.
*/
-static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, struct ipaddr *ip)
+static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
+ const struct ipaddr *ip)
{
zebra_neigh_t tmp;
zebra_neigh_t *n;
@@ -4739,8 +4742,9 @@ static void *zl3vni_nh_alloc(void *p)
/*
* Add neighbor entry.
*/
-static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip,
- struct ethaddr *mac)
+static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
+ const struct ipaddr *ip,
+ const struct ethaddr *mac)
{
zebra_neigh_t tmp_n;
zebra_neigh_t *n = NULL;
@@ -4822,9 +4826,10 @@ static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
}
/* add remote vtep as a neigh entry */
-static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip,
- struct ethaddr *rmac,
- struct prefix *host_prefix)
+static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni,
+ const struct ipaddr *vtep_ip,
+ const struct ethaddr *rmac,
+ const struct prefix *host_prefix)
{
char buf[ETHER_ADDR_STRLEN];
char buf1[ETHER_ADDR_STRLEN];
@@ -5960,9 +5965,9 @@ int is_l3vni_for_prefix_routes_only(vni_t vni)
}
/* handle evpn route in vrf table */
-void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac,
- struct ipaddr *vtep_ip,
- struct prefix *host_prefix)
+void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac,
+ const struct ipaddr *vtep_ip,
+ const struct prefix *host_prefix)
{
zebra_l3vni_t *zl3vni = NULL;
struct ipaddr ipv4_vtep;
@@ -8034,7 +8039,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
if (!zvni) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "\tAdd/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
+ " Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf, sizeof(buf)),
ifp->name, ifp->ifindex, vid);
@@ -8044,7 +8049,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
if (!zvni->vxlan_if) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "\tVNI %u hash %p doesn't have intf upon local MAC ADD",
+ " VNI %u hash %p doesn't have intf upon local MAC ADD",
zvni->vni, zvni);
return -1;
}
@@ -8052,7 +8057,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
if (!zvrf) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("\tNo Vrf found for vrf_id: %d",
+ zlog_debug(" No Vrf found for vrf_id: %d",
zvni->vxlan_if->vrf_id);
return -1;
}
@@ -8105,7 +8110,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
&& mac->fwd_info.local.vid == vid) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "\tAdd/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, "
+ " Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, "
"entry exists and has not changed ",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf,
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
index 6ca93f6cb6..a5c13a59e3 100644
--- a/zebra/zebra_vxlan.h
+++ b/zebra/zebra_vxlan.h
@@ -199,9 +199,9 @@ extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *);
extern void zebra_vxlan_init(void);
extern void zebra_vxlan_disable(void);
extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id,
- struct ethaddr *rmac,
- struct ipaddr *ip,
- struct prefix *host_prefix);
+ const struct ethaddr *rmac,
+ const struct ipaddr *ip,
+ const struct prefix *host_prefix);
extern void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
struct ipaddr *vtep_ip,
struct prefix *host_prefix);
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 6ab7fbd918..08df664d56 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -131,6 +131,9 @@ struct zserv {
bool notify_owner;
+ /* Indicates if client is synchronous. */
+ bool synchronous;
+
/* client's protocol */
uint8_t proto;
uint16_t instance;