summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--alpine/APKBUILD.in23
-rw-r--r--babeld/babel_interface.c47
-rw-r--r--babeld/babel_interface.h5
-rw-r--r--babeld/babel_main.c2
-rw-r--r--babeld/babel_zebra.c4
-rw-r--r--bfdd/bfd.c59
-rw-r--r--bfdd/bfd.h8
-rw-r--r--bfdd/bfd_packet.c3
-rw-r--r--bfdd/bfdd_northbound.c26
-rw-r--r--bfdd/bfdd_vty.c12
-rw-r--r--bfdd/ptm_adapter.c50
-rw-r--r--bgpd/bgp_aspath.c85
-rw-r--r--bgpd/bgp_aspath.h8
-rw-r--r--bgpd/bgp_attr.c12
-rw-r--r--bgpd/bgp_attr.h3
-rw-r--r--bgpd/bgp_bmp.c12
-rw-r--r--bgpd/bgp_community.c89
-rw-r--r--bgpd/bgp_community.h8
-rw-r--r--bgpd/bgp_ecommunity.c86
-rw-r--r--bgpd/bgp_ecommunity.h9
-rw-r--r--bgpd/bgp_evpn.c181
-rw-r--r--bgpd/bgp_evpn.h1
-rw-r--r--bgpd/bgp_evpn_vty.c338
-rw-r--r--bgpd/bgp_filter.c61
-rw-r--r--bgpd/bgp_flowspec_vty.c2
-rw-r--r--bgpd/bgp_io.c107
-rw-r--r--bgpd/bgp_io.h2
-rw-r--r--bgpd/bgp_lcommunity.c88
-rw-r--r--bgpd/bgp_lcommunity.h10
-rw-r--r--bgpd/bgp_main.c12
-rw-r--r--bgpd/bgp_mpath.c2
-rw-r--r--bgpd/bgp_mplsvpn.c2
-rw-r--r--bgpd/bgp_network.c25
-rw-r--r--bgpd/bgp_pbr.c2
-rw-r--r--bgpd/bgp_route.c2102
-rw-r--r--bgpd/bgp_routemap.c65
-rw-r--r--bgpd/bgp_rpki.c3
-rw-r--r--bgpd/bgp_snmp.c2
-rw-r--r--bgpd/bgp_updgrp.c6
-rw-r--r--bgpd/bgp_updgrp_adv.c5
-rw-r--r--bgpd/bgp_updgrp_packet.c47
-rw-r--r--bgpd/bgp_vpn.c75
-rw-r--r--bgpd/bgp_vty.c545
-rw-r--r--bgpd/bgp_zebra.c98
-rw-r--r--bgpd/bgpd.c24
-rw-r--r--bgpd/bgpd.h14
-rw-r--r--bgpd/rfapi/rfapi.c18
-rw-r--r--bgpd/rfapi/rfapi_import.c225
-rw-r--r--bgpd/rfapi/rfapi_rib.c5
-rw-r--r--bgpd/rfapi/rfapi_vty.c173
-rw-r--r--bgpd/rfapi/vnc_import_bgp.c49
-rwxr-xr-xconfigure.ac32
-rw-r--r--doc/developer/frr-release-procedure.rst181
-rw-r--r--doc/developer/maintainer-release-build.rst89
-rw-r--r--doc/developer/memtypes.rst8
-rw-r--r--doc/developer/packaging.rst8
-rw-r--r--doc/developer/release-announcement-template.md40
-rw-r--r--doc/developer/subdir.am3
-rw-r--r--doc/developer/topotests-jsontopo.rst609
-rw-r--r--doc/developer/topotests.rst7
-rw-r--r--doc/developer/workflow.rst32
-rw-r--r--doc/manpages/bgpd.rst42
-rw-r--r--doc/user/basic.rst3
-rw-r--r--doc/user/bfd.rst8
-rw-r--r--doc/user/bgp.rst246
-rw-r--r--doc/user/filter.rst22
-rw-r--r--doc/user/installation.rst17
-rw-r--r--doc/user/overview.rst2
-rw-r--r--doc/user/pim.rst7
-rw-r--r--doc/user/routemap.rst5
-rw-r--r--doc/user/vrrp.rst23
-rw-r--r--doc/user/zebra.rst52
-rw-r--r--docker/alpine/Dockerfile5
-rw-r--r--docker/debian/Dockerfile17
-rw-r--r--eigrpd/eigrp_interface.c92
-rw-r--r--eigrpd/eigrp_interface.h1
-rw-r--r--eigrpd/eigrp_network.c5
-rw-r--r--eigrpd/eigrp_zebra.c147
-rw-r--r--include/linux/fib_rules.h20
-rw-r--r--include/linux/if_addr.h3
-rw-r--r--include/linux/if_bridge.h10
-rw-r--r--include/linux/if_link.h92
-rw-r--r--include/linux/lwtunnel.h7
-rw-r--r--include/linux/mpls_iptunnel.h7
-rw-r--r--include/linux/neighbour.h3
-rw-r--r--include/linux/net_namespace.h7
-rw-r--r--include/linux/netlink.h15
-rw-r--r--include/linux/nexthop.h58
-rw-r--r--include/linux/rtnetlink.h57
-rw-r--r--include/linux/socket.h7
-rw-r--r--include/subdir.am1
-rw-r--r--isisd/isis_adjacency.c1
-rw-r--r--isisd/isis_circuit.c49
-rw-r--r--isisd/isis_circuit.h9
-rw-r--r--isisd/isis_cli.c111
-rw-r--r--isisd/isis_main.c2
-rw-r--r--isisd/isis_northbound.c534
-rw-r--r--isisd/isis_pdu.c35
-rw-r--r--isisd/isis_te.c3
-rw-r--r--isisd/isis_zebra.c79
-rw-r--r--isisd/isis_zebra.h2
-rw-r--r--isisd/isisd.c3
-rw-r--r--isisd/isisd.h3
-rw-r--r--ldpd/ldp_zebra.c49
-rw-r--r--lib/agentx.c16
-rw-r--r--lib/command.c22
-rw-r--r--lib/command.h2
-rw-r--r--lib/command_match.c14
-rw-r--r--lib/filter.c5
-rw-r--r--lib/frrcu.c7
-rw-r--r--lib/if.c223
-rw-r--r--lib/if.h30
-rw-r--r--lib/json.c17
-rw-r--r--lib/json.h17
-rw-r--r--lib/libfrr.c25
-rw-r--r--lib/memory.h16
-rw-r--r--lib/nexthop.c62
-rw-r--r--lib/nexthop.h12
-rw-r--r--lib/nexthop_group.c138
-rw-r--r--lib/nexthop_group.h17
-rw-r--r--lib/northbound.c327
-rw-r--r--lib/northbound.h27
-rw-r--r--lib/northbound_cli.c213
-rw-r--r--lib/northbound_cli.h2
-rw-r--r--lib/northbound_confd.c6
-rw-r--r--lib/northbound_grpc.cpp29
-rw-r--r--lib/northbound_sysrepo.c6
-rw-r--r--lib/pbr.h2
-rw-r--r--lib/prefix.c61
-rw-r--r--lib/prefix.h2
-rw-r--r--lib/printf/glue.c6
-rw-r--r--lib/printf/printf-pos.c6
-rw-r--r--lib/route_types.txt2
-rw-r--r--lib/sockopt.c15
-rw-r--r--lib/sockopt.h1
-rw-r--r--lib/subdir.am1
-rw-r--r--lib/systemd.c9
-rw-r--r--lib/systemd.h5
-rw-r--r--lib/thread.c20
-rw-r--r--lib/typesafe.c2
-rw-r--r--lib/vrf.c8
-rw-r--r--lib/vty.c24
-rw-r--r--lib/vty.h3
-rw-r--r--lib/yang.c16
-rw-r--r--lib/yang.h8
-rw-r--r--lib/yang_wrappers.c60
-rw-r--r--lib/yang_wrappers.h10
-rw-r--r--lib/zclient.c78
-rw-r--r--lib/zclient.h9
-rw-r--r--lib/zebra.h5
-rw-r--r--nhrpd/list.h9
-rw-r--r--nhrpd/nhrp_interface.c38
-rw-r--r--nhrpd/nhrp_main.c2
-rw-r--r--nhrpd/nhrp_route.c4
-rw-r--r--nhrpd/nhrp_vty.c5
-rw-r--r--nhrpd/nhrpd.h7
-rw-r--r--ospf6d/ospf6_interface.c109
-rw-r--r--ospf6d/ospf6_interface.h1
-rw-r--r--ospf6d/ospf6_lsdb.c15
-rw-r--r--ospf6d/ospf6_message.c44
-rw-r--r--ospf6d/ospf6_neighbor.c33
-rw-r--r--ospf6d/ospf6_snmp.c4
-rw-r--r--ospf6d/ospf6_top.c5
-rw-r--r--ospf6d/ospf6_top.h3
-rw-r--r--ospf6d/ospf6_zebra.c55
-rw-r--r--ospfd/ospf_ase.c4
-rw-r--r--ospfd/ospf_interface.c131
-rw-r--r--ospfd/ospf_interface.h5
-rw-r--r--ospfd/ospf_lsa.c2
-rw-r--r--ospfd/ospf_vty.c2
-rw-r--r--ospfd/ospf_zebra.c172
-rw-r--r--ospfd/ospf_zebra.h3
-rw-r--r--ospfd/ospfd.c1
-rw-r--r--pbrd/pbr_main.c2
-rw-r--r--pbrd/pbr_nht.c18
-rw-r--r--pbrd/pbr_vty.c12
-rw-r--r--pbrd/pbr_zebra.c46
-rw-r--r--pbrd/pbr_zebra.h6
-rw-r--r--pimd/pim_bsm.c15
-rw-r--r--pimd/pim_cmd.c6
-rw-r--r--pimd/pim_hello.c2
-rw-r--r--pimd/pim_iface.c168
-rw-r--r--pimd/pim_iface.h6
-rw-r--r--pimd/pim_join.c27
-rw-r--r--pimd/pim_main.c2
-rw-r--r--pimd/pim_mroute.c29
-rw-r--r--pimd/pim_pim.c1
-rw-r--r--pimd/pim_rp.c5
-rw-r--r--pimd/pim_sock.c6
-rw-r--r--pimd/pim_zebra.c277
-rw-r--r--pimd/pim_zebra.h3
-rw-r--r--ripd/rip_interface.c49
-rw-r--r--ripd/rip_snmp.c2
-rw-r--r--ripd/rip_zebra.c4
-rw-r--r--ripd/ripd.c18
-rw-r--r--ripngd/ripng_interface.c54
-rw-r--r--ripngd/ripng_zebra.c4
-rw-r--r--ripngd/ripngd.c20
-rw-r--r--sharpd/sharp_vty.c42
-rw-r--r--sharpd/sharp_zebra.c127
-rw-r--r--staticd/static_routes.c4
-rw-r--r--staticd/static_vrf.c4
-rw-r--r--staticd/static_zebra.c92
-rw-r--r--staticd/static_zebra.h3
-rw-r--r--tests/bgpd/test_aspath.c2
-rw-r--r--tests/bgpd/test_capability.c2
-rw-r--r--tests/bgpd/test_mp_attr.c3
-rw-r--r--tests/bgpd/test_mpath.c3
-rw-r--r--tests/bgpd/test_packet.c3
-rw-r--r--tests/bgpd/test_peer_attr.c3
-rw-r--r--tests/lib/test_typelist.h2
-rw-r--r--tests/topotests/Dockerfile20
-rw-r--r--tests/topotests/bfd-topo2/r1/ipv6_routes.json1
-rw-r--r--tests/topotests/bfd-topo2/r2/ipv4_routes.json1
-rw-r--r--tests/topotests/bfd-topo2/r2/ipv6_routes.json1
-rw-r--r--tests/topotests/bfd-topo2/r3/ipv4_routes.json1
-rw-r--r--tests/topotests/bfd-topo2/r4/ipv6_routes.json1
-rwxr-xr-xtests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json234
-rwxr-xr-xtests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json234
-rw-r--r--tests/topotests/bgp-route-map/bgp_route_map_topo1.json187
-rwxr-xr-xtests/topotests/bgp-route-map/bgp_route_map_topo2.json316
-rwxr-xr-xtests/topotests/bgp-route-map/test_route_map_topo1.py1361
-rwxr-xr-xtests/topotests/bgp-route-map/test_route_map_topo2.py3916
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py11
-rw-r--r--tests/topotests/bgp_large_community/__init__.py0
-rw-r--r--tests/topotests/bgp_large_community/bgp_large_community_topo_1.json262
-rw-r--r--tests/topotests/bgp_large_community/bgp_large_community_topo_2.json344
-rwxr-xr-xtests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py1281
-rwxr-xr-xtests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py2408
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py3
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf8
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref162
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine1/staticd.conf1
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine1/zebra.conf9
-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.py245
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf5
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref169
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor1/staticd.conf1
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor1/zebra.conf12
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf5
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref169
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor2/staticd.conf1
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor2/zebra.conf13
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json1
-rwxr-xr-xtests/topotests/conftest.py6
-rw-r--r--tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref31
-rw-r--r--tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh18
-rw-r--r--tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist14
-rw-r--r--tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref30
-rw-r--r--tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh18
-rw-r--r--tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist14
-rw-r--r--tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref30
-rw-r--r--tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh18
-rw-r--r--tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist14
-rwxr-xr-xtests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py27
-rw-r--r--tests/topotests/lib/bgp.py207
-rw-r--r--tests/topotests/lib/common_config.py589
-rw-r--r--tests/topotests/lib/topojson.py2
-rw-r--r--tests/topotests/pytest.ini2
-rw-r--r--vrrpd/vrrp.c36
-rw-r--r--vrrpd/vrrp_vty.c13
-rw-r--r--vrrpd/vrrp_zebra.c70
-rw-r--r--vrrpd/vrrp_zebra.h5
-rw-r--r--vtysh/vtysh.c67
-rw-r--r--vtysh/vtysh_config.c4
-rw-r--r--watchfrr/watchfrr.c12
-rw-r--r--yang/frr-isisd.yang682
-rw-r--r--yang/frr-nexthop.yang209
-rw-r--r--yang/frr-zebra.yang1988
-rw-r--r--yang/ietf/ietf-routing-types.yang751
-rw-r--r--yang/libyang_plugins/frr_user_types.c17
-rw-r--r--yang/subdir.am1
-rw-r--r--zebra/connected.c14
-rw-r--r--zebra/if_netlink.c75
-rw-r--r--zebra/interface.c131
-rw-r--r--zebra/interface.h18
-rw-r--r--zebra/irdp.h10
-rw-r--r--zebra/kernel_netlink.c33
-rw-r--r--zebra/kernel_socket.c13
-rw-r--r--zebra/main.c4
-rw-r--r--zebra/redistribute.c109
-rw-r--r--zebra/redistribute.h18
-rw-r--r--zebra/rib.h49
-rw-r--r--zebra/rt.h10
-rw-r--r--zebra/rt_netlink.c1106
-rw-r--r--zebra/rt_netlink.h4
-rw-r--r--zebra/rt_socket.c7
-rw-r--r--zebra/rtadv.c4
-rw-r--r--zebra/rtread_getmsg.c2
-rw-r--r--zebra/rule_netlink.c24
-rw-r--r--zebra/subdir.am1
-rw-r--r--zebra/zapi_msg.c58
-rw-r--r--zebra/zapi_msg.h3
-rw-r--r--zebra/zebra_dplane.c307
-rw-r--r--zebra/zebra_dplane.h28
-rw-r--r--zebra/zebra_errors.c51
-rw-r--r--zebra/zebra_errors.h6
-rw-r--r--zebra/zebra_fpm.c5
-rw-r--r--zebra/zebra_fpm_dt.c2
-rw-r--r--zebra/zebra_fpm_netlink.c2
-rw-r--r--zebra/zebra_fpm_protobuf.c2
-rw-r--r--zebra/zebra_mpls.c67
-rw-r--r--zebra/zebra_nhg.c1416
-rw-r--r--zebra/zebra_nhg.h199
-rw-r--r--zebra/zebra_nhg_private.h62
-rw-r--r--zebra/zebra_pbr.c27
-rw-r--r--zebra/zebra_pbr.h2
-rw-r--r--zebra/zebra_pw.c2
-rw-r--r--zebra/zebra_rib.c734
-rw-r--r--zebra/zebra_rnh.c27
-rw-r--r--zebra/zebra_router.c19
-rw-r--r--zebra/zebra_router.h10
-rw-r--r--zebra/zebra_snmp.c12
-rw-r--r--zebra/zebra_vrf.c8
-rw-r--r--zebra/zebra_vty.c349
-rw-r--r--zebra/zebra_vxlan.c24
-rw-r--r--zebra/zserv.c2
322 files changed, 26077 insertions, 6440 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in
index e0b00f978..1c579a8e7 100644
--- a/alpine/APKBUILD.in
+++ b/alpine/APKBUILD.in
@@ -8,18 +8,17 @@ arch="x86_64"
license="GPL-2.0"
depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash"
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
- acct autoconf automake bash
- binutils bison bsd-compat-headers build-base
- c-ares c-ares-dev ca-certificates cryptsetup-libs curl
- device-mapper-libs expat fakeroot flex fortify-headers gdbm
- git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
- libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
- libgomp libisoburn libisofs libltdl libressl libssh2
- libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1
- mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
- patch pax-utils pcre perl pkgconf python2 python2-dev readline
- readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
- py-sphinx rtrlib rtrlib-dev"
+ acct autoconf automake bash binutils bison bsd-compat-headers build-base
+ c-ares c-ares-dev ca-certificates cryptsetup-libs curl device-mapper-libs
+ expat fakeroot flex fortify-headers gdbm git gmp isl json-c-dev kmod
+ lddtree libacl libatomic libattr libblkid libburn libbz2 libc-dev
+ libcap-dev libcurl libedit libffi libgcc libgomp libisoburn libisofs
+ libltdl libressl libssh2 libstdc++ libtool libuuid libyang-dev
+ linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr4 mtools musl-dev
+ ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre
+ perl pkgconf python2 python2-dev readline readline-dev sqlite-libs
+ squashfs-tools sudo tar texinfo xorriso xz-libs py-pip py-sphinx rtrlib
+ rtrlib-dev"
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c
index 0eeb9b2bb..7f9a13c27 100644
--- a/babeld/babel_interface.c
+++ b/babeld/babel_interface.c
@@ -86,16 +86,10 @@ babel_interface_up (ZAPI_CALLBACK_ARGS)
}
int
-babel_interface_down (ZAPI_CALLBACK_ARGS)
+babel_ifp_down(struct interface *ifp)
{
- struct stream *s = NULL;
- struct interface *ifp = NULL;
-
debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
- s = zclient->ibuf;
- ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */
-
if (ifp == NULL) {
return 0;
}
@@ -104,45 +98,23 @@ babel_interface_down (ZAPI_CALLBACK_ARGS)
return 0;
}
-int
-babel_interface_add (ZAPI_CALLBACK_ARGS)
+int babel_ifp_create (struct interface *ifp)
{
- struct interface *ifp = NULL;
-
debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
- /* read and add the interface in the iflist. */
- ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
-
- if (ifp == NULL) {
- return 0;
- }
-
interface_recalculate(ifp);
- return 0;
-}
+
+ return 0;
+ }
int
-babel_interface_delete (ZAPI_CALLBACK_ARGS)
+babel_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
- struct stream *s;
-
debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
- s = zclient->ibuf;
- ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */
-
- if (ifp == NULL)
- return 0;
-
if (IS_ENABLE(ifp))
interface_reset(ifp);
- /* To support pseudo interface do not free interface structure. */
- /* if_delete(ifp); */
- if_set_index(ifp, IFINDEX_INTERNAL);
-
return 0;
}
@@ -1095,7 +1067,7 @@ DEFUN (show_babel_route_prefix,
vty_out (vty, "%% Malformed address\n");
return CMD_WARNING;
}
-
+
routes = route_stream(0);
if(routes) {
while(1) {
@@ -1260,6 +1232,11 @@ DEFUN (show_babel_parameters,
return CMD_SUCCESS;
}
+int babel_ifp_up(struct interface *ifp)
+{
+ return 0;
+}
+
void
babel_if_init(void)
{
diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h
index d9e274582..983382792 100644
--- a/babeld/babel_interface.h
+++ b/babeld/babel_interface.h
@@ -121,6 +121,11 @@ int babel_interface_delete (int, struct zclient *, zebra_size_t, vrf_id_t);
int babel_interface_address_add (int, struct zclient *, zebra_size_t, vrf_id_t);
int babel_interface_address_delete (int, struct zclient *, zebra_size_t, vrf_id_t);
+int babel_ifp_create(struct interface *ifp);
+int babel_ifp_up(struct interface *ifp);
+int babel_ifp_down(struct interface *ifp);
+int babel_ifp_destroy(struct interface *ifp);
+
unsigned jitter(babel_interface_nfo *, int);
unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent);
/* return "true" if "address" is one of our ipv6 addresses */
diff --git a/babeld/babel_main.c b/babeld/babel_main.c
index a3f2b4e7d..4bb840815 100644
--- a/babeld/babel_main.c
+++ b/babeld/babel_main.c
@@ -202,6 +202,8 @@ main(int argc, char **argv)
babel_replace_by_null(STDIN_FILENO);
/* init some quagga's dependencies, and babeld's commands */
+ if_zapi_callbacks(babel_ifp_create, babel_ifp_up,
+ babel_ifp_down, babel_ifp_destroy);
babeld_quagga_init();
/* init zebra client's structure and it's commands */
/* this replace kernel_setup && kernel_setup_socket */
diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c
index d70823544..5a336df7b 100644
--- a/babeld/babel_zebra.c
+++ b/babeld/babel_zebra.c
@@ -240,10 +240,6 @@ void babelz_zebra_init(void)
zclient_init(zclient, ZEBRA_ROUTE_BABEL, 0, &babeld_privs);
zclient->zebra_connected = babel_zebra_connected;
- zclient->interface_add = babel_interface_add;
- zclient->interface_delete = babel_interface_delete;
- zclient->interface_up = babel_interface_up;
- zclient->interface_down = babel_interface_down;
zclient->interface_address_add = babel_interface_address_add;
zclient->interface_address_delete = babel_interface_address_delete;
zclient->redistribute_route_add = babel_zebra_read_route;
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index 50c46fbd3..6e956aa92 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -161,6 +161,7 @@ int bfd_session_enable(struct bfd_session *bs)
bs->vrf = vrf;
if (bs->vrf == NULL)
bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ assert(bs->vrf);
if (bs->key.ifname[0]
&& BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
@@ -215,9 +216,13 @@ void bfd_session_disable(struct bfd_session *bs)
/* Disable all timers. */
bfd_recvtimer_delete(bs);
- bfd_echo_recvtimer_delete(bs);
bfd_xmttimer_delete(bs);
- bfd_echo_xmttimer_delete(bs);
+ ptm_bfd_echo_stop(bs);
+ bs->vrf = NULL;
+ bs->ifp = NULL;
+
+ /* Set session down so it doesn't report UP and disabled. */
+ ptm_bfd_sess_dn(bs, BD_PATH_DOWN);
}
static uint32_t ptm_bfd_gen_ID(void)
@@ -330,7 +335,14 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
bfd->demand_mode = 0;
monotime(&bfd->downtime);
- ptm_bfd_snd(bfd, 0);
+ /*
+ * Only attempt to send if we have a valid socket:
+ * this function might be called by session disablers and in
+ * this case we won't have a valid socket (i.e. interface was
+ * removed or VRF doesn't exist anymore).
+ */
+ if (bfd->sock != -1)
+ ptm_bfd_snd(bfd, 0);
/* Slow down the control packets, the connection is down. */
bs_set_slow_timers(bfd);
@@ -1244,19 +1256,10 @@ int bs_observer_add(struct bfd_session *bs)
struct bfd_session_observer *bso;
bso = XCALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
- bso->bso_isaddress = false;
bso->bso_bs = bs;
- bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
- if (bso->bso_isinterface)
- strlcpy(bso->bso_entryname, bs->key.ifname,
- sizeof(bso->bso_entryname));
- /* Handle socket binding failures caused by missing local addresses. */
- if (bs->sock == -1) {
- bso->bso_isaddress = true;
- bso->bso_addr.family = bs->key.family;
- memcpy(&bso->bso_addr.u.prefix, &bs->key.local,
- sizeof(bs->key.local));
- }
+ bso->bso_addr.family = bs->key.family;
+ memcpy(&bso->bso_addr.u.prefix, &bs->key.local,
+ sizeof(bs->key.local));
TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
@@ -1470,7 +1473,7 @@ struct bfd_session *bfd_key_lookup(struct bfd_key key)
if (ctx.result) {
bsp = ctx.result;
log_debug(" peer %s found, but ifp"
- " and/or loc-addr params ignored");
+ " and/or loc-addr params ignored", peer_buf);
}
return bsp;
}
@@ -1746,6 +1749,15 @@ static int bfd_vrf_disable(struct vrf *vrf)
}
log_debug("VRF disable %s id %d", vrf->name, vrf->vrf_id);
+
+ /* Disable read/write poll triggering. */
+ THREAD_OFF(bvrf->bg_ev[0]);
+ THREAD_OFF(bvrf->bg_ev[1]);
+ THREAD_OFF(bvrf->bg_ev[2]);
+ THREAD_OFF(bvrf->bg_ev[3]);
+ THREAD_OFF(bvrf->bg_ev[4]);
+ THREAD_OFF(bvrf->bg_ev[5]);
+
/* Close all descriptors. */
socket_close(&bvrf->bg_echo);
socket_close(&bvrf->bg_shop);
@@ -1829,16 +1841,11 @@ void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf)
snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']/vrf",
bs->key.vrfname);
- pthread_rwlock_wrlock(&running_config->lock);
- {
- bfd_dnode = yang_dnode_get(
- running_config->dnode,
- xpath, bs->key.vrfname);
- if (bfd_dnode) {
- yang_dnode_change_leaf(bfd_dnode, vrf->name);
- running_config->version++;
- }
- pthread_rwlock_unlock(&running_config->lock);
+ bfd_dnode = yang_dnode_get(running_config->dnode, xpath,
+ bs->key.vrfname);
+ if (bfd_dnode) {
+ yang_dnode_change_leaf(bfd_dnode, vrf->name);
+ running_config->version++;
}
}
memset(bs->key.vrfname, 0, sizeof(bs->key.vrfname));
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index 89f97d2e3..815b0aec2 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -274,12 +274,8 @@ struct bfd_state_str_list {
struct bfd_session_observer {
struct bfd_session *bso_bs;
- bool bso_isinterface;
- bool bso_isaddress;
- union {
- char bso_entryname[MAXNAMELEN];
- struct prefix bso_addr;
- };
+ char bso_entryname[MAXNAMELEN];
+ struct prefix bso_addr;
TAILQ_ENTRY(bfd_session_observer) bso_entry;
};
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 7fbe6db16..ed36bb742 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -529,8 +529,7 @@ int bfd_recv_cb(struct thread *t)
uint8_t msgbuf[1516];
struct bfd_vrf_global *bvrf = THREAD_ARG(t);
- if (bvrf)
- vrfid = bvrf->vrf->vrf_id;
+ vrfid = bvrf->vrf->vrf_id;
/* Schedule next read. */
bfd_sd_reschedule(bvrf, sd);
diff --git a/bfdd/bfdd_northbound.c b/bfdd/bfdd_northbound.c
index b8a7e9555..edbd40691 100644
--- a/bfdd/bfdd_northbound.c
+++ b/bfdd/bfdd_northbound.c
@@ -58,10 +58,36 @@ static int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
union nb_resource *resource, bool mhop)
{
struct bfd_session *bs;
+ const char *ifname;
struct bfd_key bk;
+ struct prefix p;
switch (event) {
case NB_EV_VALIDATE:
+ /*
+ * When `dest-addr` is IPv6 and link-local we must
+ * require interface name, otherwise we can't figure
+ * which interface to use to send the packets.
+ */
+ yang_dnode_get_prefix(&p, dnode, "./dest-addr");
+
+ /*
+ * To support old FRR versions we must allow empty
+ * interface to be specified, however that should
+ * change in the future.
+ */
+ if (yang_dnode_exists(dnode, "./interface"))
+ ifname = yang_dnode_get_string(dnode, "./interface");
+ else
+ ifname = "";
+
+ if (p.family == AF_INET6
+ && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)
+ && strlen(ifname) == 0) {
+ zlog_warn("%s: when using link-local you must specify "
+ "an interface.", __func__);
+ return NB_ERR_VALIDATION;
+ }
break;
case NB_EV_PREPARE:
diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c
index 5663ce54c..c98ae5c7b 100644
--- a/bfdd/bfdd_vty.c
+++ b/bfdd/bfdd_vty.c
@@ -498,7 +498,7 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
/*
* Show commands.
*/
-DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]",
+DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf NAME] peers [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
VRF_CMD_HELP_STR
@@ -516,7 +516,7 @@ DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]",
}
DEFPY(bfd_show_peer, bfd_show_peer_cmd,
- "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]",
+ "show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
VRF_CMD_HELP_STR
@@ -528,7 +528,7 @@ DEFPY(bfd_show_peer, bfd_show_peer_cmd,
/* Look up the BFD peer. */
bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str,
- ifname, vrfname);
+ ifname, vrf_name);
if (bs == NULL)
return CMD_WARNING_CONFIG_FAILED;
@@ -543,7 +543,7 @@ DEFPY(bfd_show_peer, bfd_show_peer_cmd,
}
DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
- "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]",
+ "show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
VRF_CMD_HELP_STR
@@ -564,7 +564,7 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
/* Look up the BFD peer. */
bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str,
- ifname, vrfname);
+ ifname, vrf_name);
if (bs == NULL)
return CMD_WARNING_CONFIG_FAILED;
@@ -577,7 +577,7 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
}
DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd,
- "show bfd [vrf <NAME>] peers counters [json]",
+ "show bfd [vrf NAME] peers counters [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
VRF_CMD_HELP_STR
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c
index 2677eb31f..dcca70b79 100644
--- a/bfdd/ptm_adapter.c
+++ b/bfdd/ptm_adapter.c
@@ -586,8 +586,6 @@ static void bfdd_sessions_enable_interface(struct interface *ifp)
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
bs = bso->bso_bs;
- if (bso->bso_isinterface == false)
- continue;
/* Interface name mismatch. */
if (strcmp(ifp->name, bs->key.ifname))
continue;
@@ -612,10 +610,6 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
struct bfd_session *bs;
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
- if (bso->bso_isinterface == false)
- continue;
-
- /* Interface name mismatch. */
bs = bso->bso_bs;
if (strcmp(ifp->name, bs->key.ifname))
continue;
@@ -623,7 +617,6 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
if (bs->sock == -1)
continue;
- /* Try to enable it. */
bfd_session_disable(bs);
}
@@ -665,8 +658,6 @@ void bfdd_sessions_disable_vrf(struct vrf *vrf)
struct bfd_session *bs;
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
- if (bso->bso_isinterface)
- continue;
bs = bso->bso_bs;
if (bs->key.vrfname[0] &&
strcmp(vrf->name, bs->key.vrfname))
@@ -675,38 +666,14 @@ void bfdd_sessions_disable_vrf(struct vrf *vrf)
if (bs->sock == -1)
continue;
- /* Try to enable it. */
bfd_session_disable(bs);
}
}
-static int bfdd_interface_update(ZAPI_CALLBACK_ARGS)
+static int bfd_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
-
- /*
- * `zebra_interface_add_read` will handle the interface creation
- * on `lib/if.c`. We'll use that data structure instead of
- * rolling our own.
- */
- if (cmd == ZEBRA_INTERFACE_ADD) {
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
- if (ifp == NULL)
- return 0;
-
- bfdd_sessions_enable_interface(ifp);
- return 0;
- }
-
- /* Update interface information. */
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- if (ifp == NULL)
- return 0;
-
bfdd_sessions_disable_interface(ifp);
- if_set_index(ifp, IFINDEX_INTERNAL);
-
return 0;
}
@@ -731,9 +698,6 @@ static void bfdd_sessions_enable_address(struct connected *ifc)
struct prefix prefix;
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
- if (bso->bso_isaddress == false)
- continue;
-
/* Skip enabled sessions. */
bs = bso->bso_bs;
if (bs->sock != -1)
@@ -763,8 +727,16 @@ static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS)
return 0;
}
+static int bfd_ifp_create(struct interface *ifp)
+{
+ bfdd_sessions_enable_interface(ifp);
+
+ return 0;
+}
+
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
{
+ if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy);
zclient = zclient_new(master, &zclient_options_default);
assert(zclient != NULL);
zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv);
@@ -779,10 +751,6 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
/* Send replay request on zebra connect. */
zclient->zebra_connected = bfdd_zebra_connected;
- /* Learn interfaces from zebra instead of the OS. */
- zclient->interface_add = bfdd_interface_update;
- zclient->interface_delete = bfdd_interface_update;
-
/* Learn about interface VRF. */
zclient->interface_vrf_update = bfdd_interface_vrf_update;
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index f5652b07c..4257b601f 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -576,7 +576,7 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
if (make_json)
json_object_array_add(
jseg_list,
- json_object_new_int(seg->as[i]));
+ json_object_new_int64(seg->as[i]));
len += snprintf(str_buf + len, str_size - len, "%u",
seg->as[i]);
@@ -2114,15 +2114,12 @@ static void *bgp_aggr_aspath_hash_alloc(void *p)
static void bgp_aggr_aspath_prepare(struct hash_backet *hb, void *arg)
{
- struct aspath *asmerge = NULL;
struct aspath *hb_aspath = hb->data;
struct aspath **aggr_aspath = arg;
- if (*aggr_aspath) {
- asmerge = aspath_aggregate(*aggr_aspath, hb_aspath);
- aspath_free(*aggr_aspath);
- *aggr_aspath = asmerge;
- } else
+ if (*aggr_aspath)
+ *aggr_aspath = aspath_aggregate(*aggr_aspath, hb_aspath);
+ else
*aggr_aspath = aspath_dup(hb_aspath);
}
@@ -2136,6 +2133,15 @@ void bgp_aggr_aspath_remove(void *arg)
void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate,
struct aspath *aspath)
{
+ bgp_compute_aggregate_aspath_hash(aggregate, aspath);
+
+ bgp_compute_aggregate_aspath_val(aggregate);
+
+}
+
+void bgp_compute_aggregate_aspath_hash(struct bgp_aggregate *aggregate,
+ struct aspath *aspath)
+{
struct aspath *aggr_aspath = NULL;
if ((aggregate == NULL) || (aspath == NULL))
@@ -2154,17 +2160,29 @@ void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate,
*/
aggr_aspath = hash_get(aggregate->aspath_hash, aspath,
bgp_aggr_aspath_hash_alloc);
+ }
- /* Compute aggregate's as-path.
- */
+ /* Increment reference counter.
+ */
+ aggr_aspath->refcnt++;
+}
+
+void bgp_compute_aggregate_aspath_val(struct bgp_aggregate *aggregate)
+{
+ if (aggregate == NULL)
+ return;
+ /* Re-compute aggregate's as-path.
+ */
+ if (aggregate->aspath) {
+ aspath_free(aggregate->aspath);
+ aggregate->aspath = NULL;
+ }
+ if (aggregate->aspath_hash
+ && aggregate->aspath_hash->count) {
hash_iterate(aggregate->aspath_hash,
bgp_aggr_aspath_prepare,
&aggregate->aspath);
}
-
- /* Increment refernce counter.
- */
- aggr_aspath->refcnt++;
}
void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate,
@@ -2173,10 +2191,9 @@ void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate,
struct aspath *aggr_aspath = NULL;
struct aspath *ret_aspath = NULL;
- if ((aggregate == NULL) || (aspath == NULL))
- return;
-
- if (aggregate->aspath_hash == NULL)
+ if ((!aggregate)
+ || (!aggregate->aspath_hash)
+ || (!aspath))
return;
/* Look-up the aspath in the hash.
@@ -2189,17 +2206,41 @@ void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate,
ret_aspath = hash_release(aggregate->aspath_hash,
aggr_aspath);
aspath_free(ret_aspath);
+ ret_aspath = NULL;
/* Remove aggregate's old as-path.
*/
aspath_free(aggregate->aspath);
aggregate->aspath = NULL;
- /* Compute aggregate's as-path.
- */
- hash_iterate(aggregate->aspath_hash,
- bgp_aggr_aspath_prepare,
- &aggregate->aspath);
+ bgp_compute_aggregate_aspath_val(aggregate);
}
}
}
+
+void bgp_remove_aspath_from_aggregate_hash(struct bgp_aggregate *aggregate,
+ struct aspath *aspath)
+{
+ struct aspath *aggr_aspath = NULL;
+ struct aspath *ret_aspath = NULL;
+
+ if ((!aggregate)
+ || (!aggregate->aspath_hash)
+ || (!aspath))
+ return;
+
+ /* Look-up the aspath in the hash.
+ */
+ aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath);
+ if (aggr_aspath) {
+ aggr_aspath->refcnt--;
+
+ if (aggr_aspath->refcnt == 0) {
+ ret_aspath = hash_release(aggregate->aspath_hash,
+ aggr_aspath);
+ aspath_free(ret_aspath);
+ ret_aspath = NULL;
+ }
+ }
+}
+
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index f84b3740c..10f6ee282 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -134,8 +134,16 @@ extern uint8_t *aspath_snmp_pathseg(struct aspath *, size_t *);
extern void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate,
struct aspath *aspath);
+
+extern void bgp_compute_aggregate_aspath_hash(struct bgp_aggregate *aggregate,
+ struct aspath *aspath);
+extern void bgp_compute_aggregate_aspath_val(struct bgp_aggregate *aggregate);
extern void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate,
struct aspath *aspath);
+extern void bgp_remove_aspath_from_aggregate_hash(
+ struct bgp_aggregate *aggregate,
+ struct aspath *aspath);
+
extern void bgp_aggr_aspath_remove(void *arg);
#endif /* _QUAGGA_BGP_ASPATH_H */
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 248bbca8c..10e78cbc9 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -520,6 +520,7 @@ unsigned int attrhash_key_make(const void *p)
key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key);
key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance);
+ MIX(attr->rmap_table_id);
return key;
}
@@ -546,6 +547,7 @@ bool attrhash_cmp(const void *p1, const void *p2)
&& attr1->lcommunity == attr2->lcommunity
&& attr1->cluster == attr2->cluster
&& attr1->transit == attr2->transit
+ && attr1->rmap_table_id == attr2->rmap_table_id
&& (attr1->encap_tunneltype == attr2->encap_tunneltype)
&& encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
#if ENABLE_BGP_VNC
@@ -1305,14 +1307,20 @@ bgp_attr_nexthop_valid(struct peer *peer, struct attr *attr)
if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h)
|| IPV4_CLASS_DE(nexthop_h))
&& !BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) {
+ uint8_t data[7]; /* type(2) + length(1) + nhop(4) */
char buf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &attr->nexthop.s_addr, buf,
INET_ADDRSTRLEN);
flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s",
buf);
- bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP);
+ data[0] = BGP_ATTR_FLAG_TRANS;
+ data[1] = BGP_ATTR_NEXT_HOP;
+ data[2] = BGP_ATTR_NHLEN_IPV4;
+ memcpy(&data[3], &attr->nexthop.s_addr, BGP_ATTR_NHLEN_IPV4);
+ bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
+ data, 7);
return BGP_ATTR_PARSE_ERROR;
}
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index cfa428a79..eacd37b65 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -209,6 +209,9 @@ struct attr {
/* Distance as applied by Route map */
uint8_t distance;
+
+ /* rmap set table */
+ uint32_t rmap_table_id;
};
/* rmap_change_flags definition */
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 3af373b56..9f1fe6481 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -1307,8 +1307,12 @@ static struct bmp *bmp_open(struct bmp_targets *bt, int bmp_sock)
}
bt->cnt_accept++;
- setsockopt(bmp_sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
- setsockopt(bmp_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
+ if (setsockopt(bmp_sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0)
+ flog_err(EC_LIB_SOCKET, "bmp: %d can't setsockopt SO_KEEPALIVE: %s(%d)",
+ bmp_sock, safe_strerror(errno), errno);
+ if (setsockopt(bmp_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
+ flog_err(EC_LIB_SOCKET, "bmp: %d can't setsockopt TCP_NODELAY: %s(%d)",
+ bmp_sock, safe_strerror(errno), errno);
zlog_info("bmp[%s] connection established", buf);
@@ -1632,7 +1636,7 @@ static void bmp_active_connect(struct bmp_active *ba)
ba->hostname);
continue;
}
-
+
set_nonblocking(ba->socket);
res = sockunion_connect(ba->socket, &ba->addrs[ba->addrpos],
htons(ba->port), 0);
@@ -1767,7 +1771,7 @@ static struct cmd_node bmp_node = {BMP_NODE, "%s(config-bgp-bmp)# "};
#define BMP_STR "BGP Monitoring Protocol\n"
#ifndef VTYSH_EXTRACT_PL
-#include "bgp_bmp_clippy.c"
+#include "bgpd/bgp_bmp_clippy.c"
#endif
DEFPY_NOSH(bmp_targets_main,
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index 22d61f702..432c922ea 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -910,15 +910,13 @@ static void *bgp_aggr_communty_hash_alloc(void *p)
static void bgp_aggr_community_prepare(struct hash_backet *hb, void *arg)
{
- struct community *commerge = NULL;
struct community *hb_community = hb->data;
struct community **aggr_community = arg;
- if (*aggr_community) {
- commerge = community_merge(*aggr_community, hb_community);
- *aggr_community = community_uniq_sort(commerge);
- community_free(&commerge);
- } else
+ if (*aggr_community)
+ *aggr_community = community_merge(*aggr_community,
+ hb_community);
+ else
*aggr_community = community_dup(hb_community);
}
@@ -932,6 +930,14 @@ void bgp_aggr_community_remove(void *arg)
void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate,
struct community *community)
{
+ bgp_compute_aggregate_community_hash(aggregate, community);
+ bgp_compute_aggregate_community_val(aggregate);
+}
+
+
+void bgp_compute_aggregate_community_hash(struct bgp_aggregate *aggregate,
+ struct community *community)
+{
struct community *aggr_community = NULL;
if ((aggregate == NULL) || (community == NULL))
@@ -951,32 +957,47 @@ void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate,
*/
aggr_community = hash_get(aggregate->community_hash, community,
bgp_aggr_communty_hash_alloc);
+ }
- /* Re-compute aggregate's community.
- */
- if (aggregate->community)
- community_free(&aggregate->community);
+ /* Increment reference counter.
+ */
+ aggr_community->refcnt++;
+}
+void bgp_compute_aggregate_community_val(struct bgp_aggregate *aggregate)
+{
+ struct community *commerge = NULL;
+
+ if (aggregate == NULL)
+ return;
+
+ /* Re-compute aggregate's community.
+ */
+ if (aggregate->community)
+ community_free(&aggregate->community);
+ if (aggregate->community_hash &&
+ aggregate->community_hash->count) {
hash_iterate(aggregate->community_hash,
bgp_aggr_community_prepare,
&aggregate->community);
+ commerge = aggregate->community;
+ aggregate->community = community_uniq_sort(commerge);
+ if (commerge)
+ community_free(&commerge);
}
-
- /* Increment refernce counter.
- */
- aggr_community->refcnt++;
}
+
+
void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate,
struct community *community)
{
struct community *aggr_community = NULL;
struct community *ret_comm = NULL;
- if ((aggregate == NULL) || (community == NULL))
- return;
-
- if (aggregate->community_hash == NULL)
+ if ((!aggregate)
+ || (!aggregate->community_hash)
+ || (!community))
return;
/* Look-up the community in the hash.
@@ -990,13 +1011,33 @@ void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate,
aggr_community);
community_free(&ret_comm);
- community_free(&aggregate->community);
+ bgp_compute_aggregate_community_val(aggregate);
+ }
+ }
+}
+
+void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate *aggregate,
+ struct community *community)
+{
+
+ struct community *aggr_community = NULL;
+ struct community *ret_comm = NULL;
- /* Compute aggregate's community.
- */
- hash_iterate(aggregate->community_hash,
- bgp_aggr_community_prepare,
- &aggregate->community);
+ if ((!aggregate)
+ || (!aggregate->community_hash)
+ || (!community))
+ return;
+
+ /* Look-up the community in the hash.
+ */
+ aggr_community = bgp_aggr_community_lookup(aggregate, community);
+ if (aggr_community) {
+ aggr_community->refcnt--;
+
+ if (aggr_community->refcnt == 0) {
+ ret_comm = hash_release(aggregate->community_hash,
+ aggr_community);
+ community_free(&ret_comm);
}
}
}
diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h
index f761a8f5e..74a3a6b50 100644
--- a/bgpd/bgp_community.h
+++ b/bgpd/bgp_community.h
@@ -92,8 +92,16 @@ extern struct hash *community_hash(void);
extern uint32_t community_val_get(struct community *com, int i);
extern void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate,
struct community *community);
+
+extern void bgp_compute_aggregate_community_val(
+ struct bgp_aggregate *aggregate);
+extern void bgp_compute_aggregate_community_hash(
+ struct bgp_aggregate *aggregate,
+ struct community *community);
extern void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate,
struct community *community);
+extern void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate *aggregate,
+ struct community *community);
extern void bgp_aggr_community_remove(void *arg);
#endif /* _QUAGGA_BGP_COMMUNITY_H */
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 850b85aa6..11f5a326d 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -1042,15 +1042,13 @@ static void *bgp_aggr_ecommunty_hash_alloc(void *p)
static void bgp_aggr_ecommunity_prepare(struct hash_backet *hb, void *arg)
{
- struct ecommunity *ecommerge = NULL;
struct ecommunity *hb_ecommunity = hb->data;
struct ecommunity **aggr_ecommunity = arg;
- if (*aggr_ecommunity) {
- ecommerge = ecommunity_merge(*aggr_ecommunity, hb_ecommunity);
- *aggr_ecommunity = ecommunity_uniq_sort(ecommerge);
- ecommunity_free(&ecommerge);
- } else
+ if (*aggr_ecommunity)
+ *aggr_ecommunity = ecommunity_merge(*aggr_ecommunity,
+ hb_ecommunity);
+ else
*aggr_ecommunity = ecommunity_dup(hb_ecommunity);
}
@@ -1064,6 +1062,14 @@ void bgp_aggr_ecommunity_remove(void *arg)
void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate,
struct ecommunity *ecommunity)
{
+ bgp_compute_aggregate_ecommunity_hash(aggregate, ecommunity);
+ bgp_compute_aggregate_ecommunity_val(aggregate);
+}
+
+
+void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate *aggregate,
+ struct ecommunity *ecommunity)
+{
struct ecommunity *aggr_ecommunity = NULL;
if ((aggregate == NULL) || (ecommunity == NULL))
@@ -1083,20 +1089,34 @@ void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate,
aggr_ecommunity = hash_get(aggregate->ecommunity_hash,
ecommunity,
bgp_aggr_ecommunty_hash_alloc);
+ }
- /* Re-compute aggregate's ecommunity.
- */
- if (aggregate->ecommunity)
- ecommunity_free(&aggregate->ecommunity);
+ /* Increment reference counter.
+ */
+ aggr_ecommunity->refcnt++;
+}
+void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate *aggregate)
+{
+ struct ecommunity *ecommerge = NULL;
+
+ if (aggregate == NULL)
+ return;
+
+ /* Re-compute aggregate's ecommunity.
+ */
+ if (aggregate->ecommunity)
+ ecommunity_free(&aggregate->ecommunity);
+ if (aggregate->ecommunity_hash
+ && aggregate->ecommunity_hash->count) {
hash_iterate(aggregate->ecommunity_hash,
bgp_aggr_ecommunity_prepare,
&aggregate->ecommunity);
+ ecommerge = aggregate->ecommunity;
+ aggregate->ecommunity = ecommunity_uniq_sort(ecommerge);
+ if (ecommerge)
+ ecommunity_free(&ecommerge);
}
-
- /* Increment refernce counter.
- */
- aggr_ecommunity->refcnt++;
}
void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate,
@@ -1105,10 +1125,9 @@ void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate,
struct ecommunity *aggr_ecommunity = NULL;
struct ecommunity *ret_ecomm = NULL;
- if ((aggregate == NULL) || (ecommunity == NULL))
- return;
-
- if (aggregate->ecommunity_hash == NULL)
+ if ((!aggregate)
+ || (!aggregate->ecommunity_hash)
+ || (!ecommunity))
return;
/* Look-up the ecommunity in the hash.
@@ -1121,14 +1140,33 @@ void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate,
ret_ecomm = hash_release(aggregate->ecommunity_hash,
aggr_ecommunity);
ecommunity_free(&ret_ecomm);
+ bgp_compute_aggregate_ecommunity_val(aggregate);
+ }
+ }
+}
+
+void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
+ struct ecommunity *ecommunity)
+{
+
+ struct ecommunity *aggr_ecommunity = NULL;
+ struct ecommunity *ret_ecomm = NULL;
- ecommunity_free(&aggregate->ecommunity);
+ if ((!aggregate)
+ || (!aggregate->ecommunity_hash)
+ || (!ecommunity))
+ return;
- /* Compute aggregate's ecommunity.
- */
- hash_iterate(aggregate->ecommunity_hash,
- bgp_aggr_ecommunity_prepare,
- &aggregate->ecommunity);
+ /* Look-up the ecommunity in the hash.
+ */
+ aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
+ if (aggr_ecommunity) {
+ aggr_ecommunity->refcnt--;
+
+ if (aggr_ecommunity->refcnt == 0) {
+ ret_ecomm = hash_release(aggregate->ecommunity_hash,
+ aggr_ecommunity);
+ ecommunity_free(&ret_ecomm);
}
}
}
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 79be4ee42..249e5bf7d 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -190,9 +190,18 @@ extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
extern void bgp_compute_aggregate_ecommunity(
struct bgp_aggregate *aggregate,
struct ecommunity *ecommunity);
+
+extern void bgp_compute_aggregate_ecommunity_hash(
+ struct bgp_aggregate *aggregate,
+ struct ecommunity *ecommunity);
+extern void bgp_compute_aggregate_ecommunity_val(
+ struct bgp_aggregate *aggregate);
extern void bgp_remove_ecommunity_from_aggregate(
struct bgp_aggregate *aggregate,
struct ecommunity *ecommunity);
+extern void bgp_remove_ecomm_from_aggregate_hash(
+ struct bgp_aggregate *aggregate,
+ struct ecommunity *ecommunity);
extern void bgp_aggr_ecommunity_remove(void *arg);
#endif /* _QUAGGA_BGP_ECOMMUNITY_H */
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 50fef00a9..07d3f7b31 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -2394,6 +2394,33 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
return 0;
}
+static struct bgp_path_info *
+bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi,
+ struct bgp_node *rn)
+{
+ struct attr *attr_new;
+ struct bgp_path_info *pi;
+
+ /* Add (or update) attribute to hash. */
+ attr_new = bgp_attr_intern(parent_pi->attr);
+
+ /* Create new route with its attribute. */
+ pi = info_make(parent_pi->type, BGP_ROUTE_IMPORTED, 0, parent_pi->peer,
+ attr_new, rn);
+ SET_FLAG(pi->flags, BGP_PATH_VALID);
+ bgp_path_info_extra_get(pi);
+ pi->extra->parent = bgp_path_info_lock(parent_pi);
+ bgp_lock_node((struct bgp_node *)parent_pi->net);
+ if (parent_pi->extra) {
+ memcpy(&pi->extra->label, &parent_pi->extra->label,
+ sizeof(pi->extra->label));
+ pi->extra->num_labels = parent_pi->extra->num_labels;
+ }
+ bgp_path_info_add(rn, pi);
+
+ return 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,
@@ -2424,7 +2451,8 @@ static int install_evpn_route_entry_in_es(struct bgp *bgp, struct evpnes *es,
parent_pi->peer, attr_new, rn);
SET_FLAG(pi->flags, BGP_PATH_VALID);
bgp_path_info_extra_get(pi);
- pi->extra->parent = parent_pi;
+ pi->extra->parent = bgp_path_info_lock(parent_pi);
+ bgp_lock_node((struct bgp_node *)parent_pi->net);
bgp_path_info_add(rn, pi);
} else {
if (attrhash_cmp(pi->attr, parent_pi->attr)
@@ -2516,24 +2544,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
&& (struct bgp_path_info *)pi->extra->parent == parent_pi)
break;
- if (!pi) {
- /* Add (or update) attribute to hash. */
- attr_new = bgp_attr_intern(&attr);
-
- /* Create new route with its attribute. */
- pi = info_make(parent_pi->type, BGP_ROUTE_IMPORTED, 0,
- parent_pi->peer, attr_new, rn);
- SET_FLAG(pi->flags, BGP_PATH_VALID);
- bgp_path_info_extra_get(pi);
- pi->extra->parent = bgp_path_info_lock(parent_pi);
- bgp_lock_node((struct bgp_node *)parent_pi->net);
- if (parent_pi->extra) {
- memcpy(&pi->extra->label, &parent_pi->extra->label,
- sizeof(pi->extra->label));
- pi->extra->num_labels = parent_pi->extra->num_labels;
- }
- bgp_path_info_add(rn, pi);
- } else {
+ if (!pi)
+ pi = bgp_create_evpn_bgp_path_info(parent_pi, rn);
+ else {
if (attrhash_cmp(pi->attr, &attr)
&& !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
bgp_unlock_node(rn);
@@ -2596,22 +2609,8 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
break;
if (!pi) {
- /* Add (or update) attribute to hash. */
- attr_new = bgp_attr_intern(parent_pi->attr);
-
- /* Create new route with its attribute. */
- pi = info_make(parent_pi->type, BGP_ROUTE_IMPORTED, 0,
- parent_pi->peer, attr_new, rn);
- SET_FLAG(pi->flags, BGP_PATH_VALID);
- bgp_path_info_extra_get(pi);
- pi->extra->parent = bgp_path_info_lock(parent_pi);
- bgp_lock_node((struct bgp_node *)parent_pi->net);
- if (parent_pi->extra) {
- memcpy(&pi->extra->label, &parent_pi->extra->label,
- sizeof(pi->extra->label));
- pi->extra->num_labels = parent_pi->extra->num_labels;
- }
- bgp_path_info_add(rn, pi);
+ /* Create an info */
+ (void)bgp_create_evpn_bgp_path_info(parent_pi, rn);
} else {
if (attrhash_cmp(pi->attr, parent_pi->attr)
&& !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
@@ -3025,8 +3024,7 @@ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
* SVI comes up with MAC and stored in hash, triggers
* bgp_mac_rescan_all_evpn_tables.
*/
- if (pi->attr &&
- memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) {
+ if (memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) {
if (bgp_debug_update(pi->peer, NULL, NULL, 1)) {
char buf1[PREFIX_STRLEN];
char attr_str[BUFSIZ] = {0};
@@ -4700,59 +4698,60 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
{
char buf1[ETHER_ADDR_STRLEN];
char buf2[PREFIX2STR_BUFFER];
+ uint8_t family;
+ uint8_t prefixlen;
if (!json)
return;
- if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
- json_object_int_add(json, "routeType", p->prefix.route_type);
+ json_object_int_add(json, "routeType", p->prefix.route_type);
+
+ switch (p->prefix.route_type) {
+ case BGP_EVPN_MAC_IP_ROUTE:
json_object_int_add(json, "ethTag",
- p->prefix.imet_addr.eth_tag);
- json_object_int_add(json, "ipLen",
- is_evpn_prefix_ipaddr_v4(p)
- ? IPV4_MAX_BITLEN
- : IPV6_MAX_BITLEN);
- json_object_string_add(json, "ip",
- inet_ntoa(p->prefix.imet_addr.ip.ipaddr_v4));
- } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
- if (is_evpn_prefix_ipaddr_none(p)) {
- json_object_int_add(json, "routeType",
- p->prefix.route_type);
- json_object_int_add(json, "ethTag",
- p->prefix.macip_addr.eth_tag);
- json_object_int_add(json, "macLen", 8 * ETH_ALEN);
- json_object_string_add(json, "mac",
- prefix_mac2str(&p->prefix.macip_addr.mac,
- buf1,
- sizeof(buf1)));
- } else {
- uint8_t family;
+ p->prefix.macip_addr.eth_tag);
+ json_object_int_add(json, "macLen", 8 * ETH_ALEN);
+ json_object_string_add(json, "mac",
+ prefix_mac2str(&p->prefix.macip_addr.mac, buf1,
+ sizeof(buf1)));
+
+ if (!is_evpn_prefix_ipaddr_none(p)) {
+ family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET :
+ AF_INET6;
+ prefixlen = (family == AF_INET) ?
+ IPV4_MAX_BITLEN : IPV6_MAX_BITLEN;
+ inet_ntop(family, &p->prefix.macip_addr.ip.ip.addr,
+ buf2, PREFIX2STR_BUFFER);
+ json_object_int_add(json, "ipLen", prefixlen);
+ json_object_string_add(json, "ip", buf2);
+ }
+ break;
- family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET
- : AF_INET6;
+ case BGP_EVPN_IMET_ROUTE:
+ json_object_int_add(json, "ethTag",
+ p->prefix.imet_addr.eth_tag);
+ family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6;
+ prefixlen = (family == AF_INET) ? IPV4_MAX_BITLEN :
+ IPV6_MAX_BITLEN;
+ inet_ntop(family, &p->prefix.imet_addr.ip.ip.addr, buf2,
+ PREFIX2STR_BUFFER);
+ json_object_int_add(json, "ipLen", prefixlen);
+ json_object_string_add(json, "ip", buf2);
+ break;
- json_object_int_add(json, "routeType",
- p->prefix.route_type);
- json_object_int_add(json, "ethTag",
- p->prefix.macip_addr.eth_tag);
- json_object_int_add(json, "macLen", 8 * ETH_ALEN);
- json_object_string_add(json, "mac",
- prefix_mac2str(&p->prefix.macip_addr.mac,
- buf1,
- sizeof(buf1)));
- json_object_int_add(json, "ipLen",
- is_evpn_prefix_ipaddr_v4(p)
- ? IPV4_MAX_BITLEN
- : IPV6_MAX_BITLEN);
- json_object_string_add(
- json, "ip",
- inet_ntop(family,
- &p->prefix.macip_addr.ip.ip.addr,
- buf2,
- PREFIX2STR_BUFFER));
- }
- } else {
- /* Currently, this is to cater to other AF_ETHERNET code. */
+ case BGP_EVPN_IP_PREFIX_ROUTE:
+ json_object_int_add(json, "ethTag",
+ p->prefix.prefix_addr.eth_tag);
+ family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6;
+ inet_ntop(family, &p->prefix.prefix_addr.ip.ip.addr,
+ buf2, sizeof(buf2));
+ json_object_int_add(json, "ipLen",
+ p->prefix.prefix_addr.ip_prefix_length);
+ json_object_string_add(json, "ip", buf2);
+ break;
+
+ default:
+ break;
}
}
@@ -6011,3 +6010,19 @@ void bgp_evpn_vrf_delete(struct bgp *bgp_vrf)
{
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
}
+
+/*
+ * Get the prefixlen of the ip prefix carried within the type5 evpn route.
+ */
+int bgp_evpn_get_type5_prefixlen(struct prefix *pfx)
+{
+ struct prefix_evpn *evp = (struct prefix_evpn *)pfx;
+
+ if (!pfx || pfx->family != AF_EVPN)
+ return 0;
+
+ if (evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE)
+ return 0;
+
+ return evp->prefix.prefix_addr.ip_prefix_length;
+}
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
index 4ad8e95be..6d1e8cd31 100644
--- a/bgpd/bgp_evpn.h
+++ b/bgpd/bgp_evpn.h
@@ -190,5 +190,6 @@ 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);
#endif /* _QUAGGA_BGP_EVPN_H */
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 30380f6ad..55f85eeb8 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -37,6 +37,8 @@
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
+#include "bgpd/bgp_community.h"
#define SHOW_DISPLAY_STANDARD 0
#define SHOW_DISPLAY_TAGS 1
@@ -273,42 +275,61 @@ static void show_import_rt_entry(struct hash_bucket *bucket, void *args[])
static void bgp_evpn_show_route_rd_header(struct vty *vty,
struct bgp_node *rd_rn,
- json_object *json)
+ json_object *json,
+ char *rd_str, int len)
{
uint16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
uint8_t *pnt;
- char rd_str[RD_ADDRSTRLEN];
pnt = rd_rn->p.u.val;
/* Decode RD type. */
type = decode_rd_type(pnt);
- if (json)
- return;
-
- vty_out(vty, "Route Distinguisher: ");
+ if (!json)
+ vty_out(vty, "Route Distinguisher: ");
switch (type) {
case RD_TYPE_AS:
decode_rd_as(pnt + 2, &rd_as);
- snprintf(rd_str, RD_ADDRSTRLEN, "%u:%d", rd_as.as, rd_as.val);
+ snprintf(rd_str, len, "%u:%d", rd_as.as, rd_as.val);
+ if (json)
+ json_object_string_add(json, "rd", rd_str);
+ else
+ vty_out(vty, "as2 %s\n", rd_str);
+ break;
+
+ case RD_TYPE_AS4:
+ decode_rd_as4(pnt + 2, &rd_as);
+ snprintf(rd_str, len, "%u:%d", rd_as.as, rd_as.val);
+ if (json)
+ json_object_string_add(json, "rd", rd_str);
+ else
+ vty_out(vty, "as4 %s\n", rd_str);
break;
case RD_TYPE_IP:
decode_rd_ip(pnt + 2, &rd_ip);
- snprintf(rd_str, RD_ADDRSTRLEN, "%s:%d", inet_ntoa(rd_ip.ip),
+ snprintf(rd_str, len, "%s:%d", inet_ntoa(rd_ip.ip),
rd_ip.val);
+ if (json)
+ json_object_string_add(json, "rd", rd_str);
+ else
+ vty_out(vty, "ip %s\n", rd_str);
break;
default:
- snprintf(rd_str, RD_ADDRSTRLEN, "Unknown RD type");
+ if (json) {
+ snprintf(rd_str, len, "Unknown");
+ json_object_string_add(json, "rd", rd_str);
+ } else {
+ snprintf(rd_str, len, "Unknown RD type");
+ vty_out(vty, "ip %s\n", rd_str);
+ }
break;
}
-
- vty_out(vty, "%s\n", rd_str);
}
static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
@@ -358,6 +379,9 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
json_object_string_add(json, "originatorIp",
inet_ntoa(bgp_vrf->originator_ip));
json_object_string_add(json, "advertiseGatewayMacip", "n/a");
+ json_object_string_add(json, "advertiseSviMacip", "n/a");
+ json_object_to_json_string_ext(json,
+ JSON_C_TO_STRING_NOSLASHESCAPE);
} else {
vty_out(vty, "VNI: %d", bgp_vrf->l3vni);
vty_out(vty, " (known to the kernel)");
@@ -371,6 +395,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
vty_out(vty, " Originator IP: %s\n",
inet_ntoa(bgp_vrf->originator_ip));
vty_out(vty, " Advertise-gw-macip : %s\n", "n/a");
+ vty_out(vty, " Advertise-svi-macip : %s\n", "n/a");
}
if (!json)
@@ -460,6 +485,9 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
struct ecommunity *ecom;
json_object *json_import_rtl = NULL;
json_object *json_export_rtl = NULL;
+ struct bgp *bgp_evpn;
+
+ bgp_evpn = bgp_get_evpn();
if (json) {
json_import_rtl = json_object_new_array();
@@ -475,8 +503,30 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
inet_ntoa(vpn->originator_ip));
json_object_string_add(json, "mcastGroup",
inet_ntoa(vpn->mcast_grp));
- json_object_string_add(json, "advertiseGatewayMacip",
- vpn->advertise_gw_macip ? "Yes" : "No");
+ /* per vni knob is enabled -- Enabled
+ * Global knob is enabled -- Active
+ * default -- Disabled
+ */
+ if (!vpn->advertise_gw_macip &&
+ bgp_evpn && bgp_evpn->advertise_gw_macip)
+ json_object_string_add(json, "advertiseGatewayMacip",
+ "Active");
+ else if (vpn->advertise_gw_macip)
+ json_object_string_add(json, "advertiseGatewayMacip",
+ "Enabled");
+ else
+ json_object_string_add(json, "advertiseGatewayMacip",
+ "Disabled");
+ if (!vpn->advertise_svi_macip && bgp_evpn &&
+ bgp_evpn->evpn_info->advertise_svi_macip)
+ json_object_string_add(json, "advertiseSviMacip",
+ "Active");
+ else if (vpn->advertise_svi_macip)
+ json_object_string_add(json, "advertiseSviMacip",
+ "Enabled");
+ else
+ json_object_string_add(json, "advertiseSviMacip",
+ "Disabled");
} else {
vty_out(vty, "VNI: %d", vpn->vni);
if (is_vni_live(vpn))
@@ -492,10 +542,26 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
inet_ntoa(vpn->originator_ip));
vty_out(vty, " Mcast group: %s\n",
inet_ntoa(vpn->mcast_grp));
- vty_out(vty, " Advertise-gw-macip : %s\n",
- vpn->advertise_gw_macip ? "Yes" : "No");
- vty_out(vty, " Advertise-svi-macip : %s\n",
- vpn->advertise_svi_macip ? "Yes" : "No");
+ if (!vpn->advertise_gw_macip &&
+ bgp_evpn && bgp_evpn->advertise_gw_macip)
+ vty_out(vty, " Advertise-gw-macip : %s\n",
+ "Active");
+ else if (vpn->advertise_gw_macip)
+ vty_out(vty, " Advertise-gw-macip : %s\n",
+ "Enabled");
+ else
+ vty_out(vty, " Advertise-gw-macip : %s\n",
+ "Disabled");
+ if (!vpn->advertise_svi_macip && bgp_evpn &&
+ bgp_evpn->evpn_info->advertise_svi_macip)
+ vty_out(vty, " Advertise-svi-macip : %s\n",
+ "Active");
+ else if (vpn->advertise_svi_macip)
+ vty_out(vty, " Advertise-svi-macip : %s\n",
+ "Enabled");
+ else
+ vty_out(vty, " Advertise-svi-macip : %s\n",
+ "Disabled");
}
if (!json)
@@ -1010,17 +1076,17 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
struct bgp_path_info *pi;
int rd_header;
int header = 1;
- char rd_str[BUFSIZ];
+ char rd_str[RD_ADDRSTRLEN];
char buf[BUFSIZ];
+ int no_display;
unsigned long output_count = 0;
unsigned long total_count = 0;
json_object *json = NULL;
- json_object *json_nroute = NULL;
json_object *json_array = NULL;
json_object *json_prefix_info = NULL;
- memset(rd_str, 0, BUFSIZ);
+ memset(rd_str, 0, RD_ADDRSTRLEN);
bgp = bgp_get_evpn();
if (bgp == NULL) {
@@ -1037,6 +1103,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
for (rn = bgp_table_top(bgp->rib[afi][SAFI_EVPN]); rn;
rn = bgp_route_next(rn)) {
uint64_t tbl_ver;
+ json_object *json_nroute = NULL;
if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
continue;
@@ -1049,24 +1116,12 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
tbl_ver = table->version;
for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) {
- if (use_json) {
- json_array = json_object_new_array();
- 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_int_add(json_prefix_info,
- "prefixLen", rm->p.prefixlen);
-
- if (rd_header)
- json_nroute = json_object_new_object();
- }
+ pi = bgp_node_get_bgp_path_info(rm);
+ if (pi == NULL)
+ continue;
- for (pi = bgp_node_get_bgp_path_info(rm); pi;
- pi = pi->next) {
+ no_display = 0;
+ for (; pi; pi = pi->next) {
total_count++;
if (type == bgp_show_type_neighbor) {
struct peer *peer = output_arg;
@@ -1074,6 +1129,38 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
if (peer_cmp(peer, pi->peer) != 0)
continue;
}
+ if (type == bgp_show_type_lcommunity_exact) {
+ struct lcommunity *lcom = output_arg;
+
+ if (!pi->attr->lcommunity ||
+ !lcommunity_cmp(
+ pi->attr->lcommunity, lcom))
+ continue;
+ }
+ if (type == bgp_show_type_lcommunity) {
+ struct lcommunity *lcom = output_arg;
+
+ if (!pi->attr->lcommunity ||
+ !lcommunity_match(
+ pi->attr->lcommunity, lcom))
+ continue;
+ }
+ if (type == bgp_show_type_community) {
+ struct community *com = output_arg;
+
+ if (!pi->attr->community ||
+ !community_match(
+ pi->attr->community, com))
+ continue;
+ }
+ if (type == bgp_show_type_community_exact) {
+ struct community *com = output_arg;
+
+ if (!pi->attr->community ||
+ !community_cmp(
+ pi->attr->community, com))
+ continue;
+ }
if (header) {
if (use_json) {
json_object_int_add(
@@ -1101,98 +1188,61 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
vty_out(vty,
V4_HEADER_OVERLAY);
else {
- vty_out(vty,
- "BGP table version is %" PRIu64 ", local router ID is %s\n",
- tbl_ver,
- inet_ntoa(
- bgp->router_id));
- vty_out(vty,
- "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n");
- vty_out(vty,
- "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n");
- vty_out(vty, V4_HEADER);
+ bgp_evpn_show_route_header(vty, bgp, tbl_ver, NULL);
}
}
header = 0;
}
if (rd_header) {
- uint16_t type;
- struct rd_as rd_as;
- struct rd_ip rd_ip;
- uint8_t *pnt;
-
- pnt = rn->p.u.val;
-
- /* Decode RD type. */
- type = decode_rd_type(pnt);
- /* Decode RD value. */
- if (type == RD_TYPE_AS)
- decode_rd_as(pnt + 2, &rd_as);
- else if (type == RD_TYPE_AS4)
- decode_rd_as4(pnt + 2, &rd_as);
- else if (type == RD_TYPE_IP)
- decode_rd_ip(pnt + 2, &rd_ip);
- if (use_json) {
- if (type == RD_TYPE_AS
- || type == RD_TYPE_AS4)
- sprintf(rd_str, "%u:%d",
- rd_as.as,
- rd_as.val);
- else if (type == RD_TYPE_IP)
- sprintf(rd_str, "%s:%d",
- inet_ntoa(
- rd_ip.ip),
- rd_ip.val);
- json_object_string_add(
- json_nroute,
- "rd",
- rd_str);
-
- } else {
- vty_out(vty,
- "Route Distinguisher: ");
- if (type == RD_TYPE_AS)
- vty_out(vty,
- "as2 %u:%d",
- rd_as.as,
- rd_as.val);
- else if (type == RD_TYPE_AS4)
- vty_out(vty,
- "as4 %u:%d",
- rd_as.as,
- rd_as.val);
- else if (type == RD_TYPE_IP)
- vty_out(vty, "ip %s:%d",
- inet_ntoa(
- rd_ip.ip),
- rd_ip.val);
- vty_out(vty, "\n\n");
- }
+ if (use_json)
+ json_nroute =
+ json_object_new_object();
+ bgp_evpn_show_route_rd_header(vty, rn,
+ json_nroute, rd_str,
+ RD_ADDRSTRLEN);
rd_header = 0;
}
+ if (use_json && !json_array)
+ json_array = json_object_new_array();
if (option == SHOW_DISPLAY_TAGS)
- route_vty_out_tag(vty, &rm->p, pi, 0,
- SAFI_EVPN,
+ route_vty_out_tag(vty, &rm->p, pi,
+ no_display, SAFI_EVPN,
json_array);
else if (option == SHOW_DISPLAY_OVERLAY)
route_vty_out_overlay(vty, &rm->p, pi,
- 0, json_array);
+ no_display,
+ json_array);
else
- route_vty_out(vty, &rm->p, pi, 0,
- SAFI_EVPN, json_array);
- output_count++;
+ route_vty_out(vty, &rm->p, pi,
+ no_display, SAFI_EVPN,
+ json_array);
+ no_display = 1;
}
- rd_header = 0;
- if (use_json) {
+
+ if (no_display)
+ output_count++;
+
+ if (use_json && json_array) {
+ 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_int_add(json_prefix_info,
+ "prefixLen", rm->p.prefixlen);
+
json_object_object_add(json_prefix_info,
"paths", json_array);
json_object_object_add(json_nroute, buf,
json_prefix_info);
+ json_array = NULL;
}
}
- if (use_json)
+ if (use_json && json_nroute)
json_object_object_add(json, rd_str, json_nroute);
}
@@ -1653,6 +1703,71 @@ DEFUN(show_ip_bgp_evpn_rd_overlay,
use_json(argc, argv));
}
+DEFUN(show_bgp_l2vpn_evpn_com,
+ show_bgp_l2vpn_evpn_com_cmd,
+ "show bgp l2vpn evpn \
+ <community AA:NN|large-community AA:BB:CC> \
+ [exact-match] [json]",
+ SHOW_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display routes matching the community\n"
+ "Community number where AA and NN are (0-65535)\n"
+ "Display routes matching the large-community\n"
+ "List of large-community numbers\n"
+ "Exact match of the communities\n"
+ JSON_STR)
+{
+ int idx = 0;
+ int ret = 0;
+ const char *clist_number_or_name;
+ int show_type = bgp_show_type_normal;
+ struct community *com;
+ struct lcommunity *lcom;
+
+ if (argv_find(argv, argc, "large-community", &idx)) {
+ clist_number_or_name = argv[++idx]->arg;
+ show_type = bgp_show_type_lcommunity;
+
+ if (++idx < argc && strmatch(argv[idx]->text, "exact-match"))
+ show_type = bgp_show_type_lcommunity_exact;
+
+ lcom = lcommunity_str2com(clist_number_or_name);
+ if (!lcom) {
+ vty_out(vty, "%% Large-community malformed\n");
+ return CMD_WARNING;
+ }
+
+ ret = bgp_show_ethernet_vpn(vty, NULL, show_type, lcom,
+ SHOW_DISPLAY_STANDARD,
+ use_json(argc, argv));
+
+ lcommunity_free(&lcom);
+ } else if (argv_find(argv, argc, "community", &idx)) {
+ clist_number_or_name = argv[++idx]->arg;
+ show_type = bgp_show_type_community;
+
+ if (++idx < argc && strmatch(argv[idx]->text, "exact-match"))
+ show_type = bgp_show_type_community_exact;
+
+ com = community_str2com(clist_number_or_name);
+
+ if (!com) {
+ vty_out(vty, "%% Community malformed: %s\n",
+ clist_number_or_name);
+ return CMD_WARNING;
+ }
+
+ ret = bgp_show_ethernet_vpn(vty, NULL, show_type, com,
+ SHOW_DISPLAY_STANDARD,
+ use_json(argc, argv));
+ community_free(&com);
+ }
+
+ return ret;
+}
+
/* For testing purpose, static route of EVPN RT-5. */
DEFUN(evpnrt5_network,
evpnrt5_network_cmd,
@@ -2544,7 +2659,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
/* RD header - per RD. */
if (rd_header) {
bgp_evpn_show_route_rd_header(
- vty, rd_rn, json);
+ vty, rd_rn, NULL, rd_str,
+ RD_ADDRSTRLEN);
rd_header = 0;
}
@@ -3587,6 +3703,9 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
bgp_evpn->advertise_gw_macip
? "Enabled"
: "Disabled");
+ json_object_string_add(json, "advertiseSviMacip",
+ bgp_evpn->evpn_info->advertise_svi_macip
+ ? "Enabled" : "Disabled");
json_object_string_add(json, "advertiseAllVnis",
is_evpn_enabled() ? "Enabled"
: "Disabled");
@@ -5443,6 +5562,7 @@ void bgp_ethernetvpn_init(void)
install_element(VIEW_NODE, &show_bgp_evpn_route_vni_all_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_import_rt_cmd);
install_element(VIEW_NODE, &show_bgp_vrf_l3vni_info_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_com_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_vni_cmd);
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
index 30a964a22..f08f9b2fb 100644
--- a/bgpd/bgp_filter.c
+++ b/bgpd/bgp_filter.c
@@ -416,13 +416,6 @@ DEFUN(as_path, bgp_as_path_cmd,
regex_t *regex;
char *regstr;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command\n");
- vty_out(vty, "'bgp as-path access-list WORD <deny|permit> LINE'\n");
- zlog_warn("Deprecated option: 'ip as-path access-list WORD <deny|permit> LINE' being used");
- }
-
/* Retrieve access list name */
argv_find(argv, argc, "WORD", &idx);
char *alname = argv[idx]->arg;
@@ -464,19 +457,6 @@ DEFUN(as_path, bgp_as_path_cmd,
return CMD_SUCCESS;
}
-#if CONFDATE > 20191005
-CPP_NOTICE("bgpd: remove deprecated 'ip as-path access-list WORD <deny|permit> LINE' command")
-#endif
-ALIAS(as_path, ip_as_path_cmd,
- "ip as-path access-list WORD <deny|permit> LINE...",
- IP_STR
- "BGP autonomous system path filter\n"
- "Specify an access list name\n"
- "Regular expression access list name\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
-
DEFUN(no_as_path, no_bgp_as_path_cmd,
"no bgp as-path access-list WORD <deny|permit> LINE...",
NO_STR
@@ -495,12 +475,6 @@ DEFUN(no_as_path, no_bgp_as_path_cmd,
char *regstr;
regex_t *regex;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command\n");
- vty_out(vty, "'no bgp as-path access-list WORD <deny|permit> LINE'\n");
- zlog_warn("Deprecated option: 'no ip as-path access-list WORD <deny|permit> LINE' being used");
- }
char *aslistname =
argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
@@ -555,16 +529,6 @@ DEFUN(no_as_path, no_bgp_as_path_cmd,
return CMD_SUCCESS;
}
-ALIAS(no_as_path, no_ip_as_path_cmd,
- "no ip as-path access-list WORD <deny|permit> LINE...",
- NO_STR IP_STR
- "BGP autonomous system path filter\n"
- "Specify an access list name\n"
- "Regular expression access list name\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
-
DEFUN (no_as_path_all,
no_bgp_as_path_all_cmd,
"no bgp as-path access-list WORD",
@@ -576,14 +540,6 @@ DEFUN (no_as_path_all,
{
int idx_word = 4;
struct as_list *aslist;
- int idx = 0;
-
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command\n");
- vty_out(vty, "'no bgp as-path access-list WORD'\n");
- zlog_warn("Deprecated option: `no ip as-path access-list WORD` being used");
- }
aslist = as_list_lookup(argv[idx_word]->arg);
if (aslist == NULL) {
@@ -660,14 +616,7 @@ DEFUN (show_as_path_access_list,
{
int idx_word = 3;
struct as_list *aslist;
- int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command\n");
- vty_out(vty, "'show bgp as-path-access-list WORD'\n");
- zlog_warn("Deprecated option: 'show ip as-path-access-list WORD' being used");
- }
aslist = as_list_lookup(argv[idx_word]->arg);
if (aslist)
as_list_show(vty, aslist);
@@ -690,14 +639,6 @@ DEFUN (show_as_path_access_list_all,
BGP_STR
"List AS path access lists\n")
{
- int idx = 0;
-
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command\n");
- vty_out(vty, "'show bgp as-path-access-list'\n");
- zlog_warn("Deprecated option: 'show ip as-path-access-list' being used");
- }
as_list_show_all(vty);
return CMD_SUCCESS;
}
@@ -743,9 +684,7 @@ void bgp_filter_init(void)
install_node(&as_list_node, config_write_as_list);
install_element(CONFIG_NODE, &bgp_as_path_cmd);
- install_element(CONFIG_NODE, &ip_as_path_cmd);
install_element(CONFIG_NODE, &no_bgp_as_path_cmd);
- install_element(CONFIG_NODE, &no_ip_as_path_cmd);
install_element(CONFIG_NODE, &no_bgp_as_path_all_cmd);
install_element(CONFIG_NODE, &no_ip_as_path_all_cmd);
diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c
index 2d6523ed3..80384c12c 100644
--- a/bgpd/bgp_flowspec_vty.c
+++ b/bgpd/bgp_flowspec_vty.c
@@ -294,7 +294,7 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p,
}
if (!path)
return;
- if (path->attr && path->attr->ecommunity) {
+ if (path->attr->ecommunity) {
/* Print attribute */
attr = path->attr;
s = ecommunity_ecom2str(attr->ecommunity,
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index c2d06a4b5..9e1c89b71 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -22,6 +22,7 @@
/* clang-format off */
#include <zebra.h>
#include <pthread.h> // for pthread_mutex_unlock, pthread_mutex_lock
+#include <sys/uio.h> // for writev
#include "frr_pthread.h"
#include "linklist.h" // for list_delete, list_delete_all_node, lis...
@@ -242,13 +243,13 @@ static int bgp_process_reads(struct thread *thread)
break;
}
- assert(ringbuf_space(peer->ibuf_work) >= BGP_MAX_PACKET_SIZE);
-
/* handle invalid header */
if (fatal) {
/* wipe buffer just in case someone screwed up */
ringbuf_wipe(peer->ibuf_work);
} else {
+ assert(ringbuf_space(peer->ibuf_work) >= BGP_MAX_PACKET_SIZE);
+
thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
&peer->t_read);
if (added_pkt)
@@ -275,35 +276,96 @@ static uint16_t bgp_write(struct peer *peer)
{
uint8_t type;
struct stream *s;
- int num;
int update_last_write = 0;
- unsigned int count = 0;
+ unsigned int count;
uint32_t uo = 0;
uint16_t status = 0;
uint32_t wpkt_quanta_old;
+ int writenum = 0;
+ int num;
+ unsigned int iovsz;
+ unsigned int strmsz;
+ unsigned int total_written;
+
wpkt_quanta_old = atomic_load_explicit(&peer->bgp->wpkt_quanta,
memory_order_relaxed);
+ struct stream *ostreams[wpkt_quanta_old];
+ struct stream **streams = ostreams;
+ struct iovec iov[wpkt_quanta_old];
+
+ s = stream_fifo_head(peer->obuf);
+
+ if (!s)
+ goto done;
+
+ count = iovsz = 0;
+ while (count < wpkt_quanta_old && iovsz < array_size(iov) && s) {
+ ostreams[iovsz] = s;
+ iov[iovsz].iov_base = stream_pnt(s);
+ iov[iovsz].iov_len = STREAM_READABLE(s);
+ writenum += STREAM_READABLE(s);
+ s = s->next;
+ ++iovsz;
+ ++count;
+ }
- while (count < wpkt_quanta_old && (s = stream_fifo_head(peer->obuf))) {
- int writenum;
- do {
- writenum = stream_get_endp(s) - stream_get_getp(s);
- num = write(peer->fd, stream_pnt(s), writenum);
+ strmsz = iovsz;
+ total_written = 0;
- if (num < 0) {
- if (!ERRNO_IO_RETRY(errno)) {
- BGP_EVENT_ADD(peer, TCP_fatal_error);
- SET_FLAG(status, BGP_IO_FATAL_ERR);
- } else {
- SET_FLAG(status, BGP_IO_TRANS_ERR);
- }
+ do {
+ num = writev(peer->fd, iov, iovsz);
- goto done;
- } else if (num != writenum)
- stream_forward_getp(s, num);
+ if (num < 0) {
+ if (!ERRNO_IO_RETRY(errno)) {
+ BGP_EVENT_ADD(peer, TCP_fatal_error);
+ SET_FLAG(status, BGP_IO_FATAL_ERR);
+ } else {
+ SET_FLAG(status, BGP_IO_TRANS_ERR);
+ }
+
+ break;
+ } else if (num != writenum) {
+ unsigned int msg_written = 0;
+ unsigned int ic = iovsz;
- } while (num != writenum);
+ for (unsigned int i = 0; i < ic; i++) {
+ size_t ss = iov[i].iov_len;
+
+ if (ss > (unsigned int) num)
+ break;
+
+ msg_written++;
+ iovsz--;
+ writenum -= ss;
+ num -= ss;
+ }
+
+ total_written += msg_written;
+
+ assert(total_written < count);
+
+ memmove(&iov, &iov[msg_written],
+ sizeof(iov[0]) * iovsz);
+ streams = &streams[msg_written];
+ stream_forward_getp(streams[0], num);
+ iov[0].iov_base = stream_pnt(streams[0]);
+ iov[0].iov_len = STREAM_READABLE(streams[0]);
+
+ writenum -= num;
+ num = 0;
+ assert(writenum > 0);
+ } else {
+ total_written = strmsz;
+ }
+
+ } while (num != writenum);
+
+ /* Handle statistics */
+ for (unsigned int i = 0; i < total_written; i++) {
+ s = stream_fifo_pop(peer->obuf);
+
+ assert(s == ostreams[i]);
/* Retrieve BGP packet type. */
stream_set_getp(s, BGP_MARKER_SIZE + 2);
@@ -351,9 +413,8 @@ static uint16_t bgp_write(struct peer *peer)
break;
}
- count++;
-
- stream_free(stream_fifo_pop(peer->obuf));
+ stream_free(s);
+ ostreams[i] = NULL;
update_last_write = 1;
}
diff --git a/bgpd/bgp_io.h b/bgpd/bgp_io.h
index 14a12d370..75d014f38 100644
--- a/bgpd/bgp_io.h
+++ b/bgpd/bgp_io.h
@@ -22,7 +22,7 @@
#ifndef _FRR_BGP_IO_H
#define _FRR_BGP_IO_H
-#define BGP_WRITE_PACKET_MAX 10U
+#define BGP_WRITE_PACKET_MAX 64U
#define BGP_READ_PACKET_MAX 10U
#include "bgpd/bgpd.h"
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
index aeb290719..3243ce96b 100644
--- a/bgpd/bgp_lcommunity.c
+++ b/bgpd/bgp_lcommunity.c
@@ -555,15 +555,13 @@ static void *bgp_aggr_lcommunty_hash_alloc(void *p)
static void bgp_aggr_lcommunity_prepare(struct hash_backet *hb, void *arg)
{
- struct lcommunity *lcommerge = NULL;
struct lcommunity *hb_lcommunity = hb->data;
struct lcommunity **aggr_lcommunity = arg;
- if (*aggr_lcommunity) {
- lcommerge = lcommunity_merge(*aggr_lcommunity, hb_lcommunity);
- *aggr_lcommunity = lcommunity_uniq_sort(lcommerge);
- lcommunity_free(&lcommerge);
- } else
+ if (*aggr_lcommunity)
+ *aggr_lcommunity = lcommunity_merge(*aggr_lcommunity,
+ hb_lcommunity);
+ else
*aggr_lcommunity = lcommunity_dup(hb_lcommunity);
}
@@ -577,6 +575,15 @@ void bgp_aggr_lcommunity_remove(void *arg)
void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate,
struct lcommunity *lcommunity)
{
+
+ bgp_compute_aggregate_lcommunity_hash(aggregate, lcommunity);
+ bgp_compute_aggregate_lcommunity_val(aggregate);
+}
+
+void bgp_compute_aggregate_lcommunity_hash(struct bgp_aggregate *aggregate,
+ struct lcommunity *lcommunity)
+{
+
struct lcommunity *aggr_lcommunity = NULL;
if ((aggregate == NULL) || (lcommunity == NULL))
@@ -596,20 +603,34 @@ void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate,
aggr_lcommunity = hash_get(aggregate->lcommunity_hash,
lcommunity,
bgp_aggr_lcommunty_hash_alloc);
+ }
- /* Re-compute aggregate's lcommunity.
- */
- if (aggregate->lcommunity)
- lcommunity_free(&aggregate->lcommunity);
+ /* Increment reference counter.
+ */
+ aggr_lcommunity->refcnt++;
+}
+
+void bgp_compute_aggregate_lcommunity_val(struct bgp_aggregate *aggregate)
+{
+ struct lcommunity *lcommerge = NULL;
+
+ if (aggregate == NULL)
+ return;
+ /* Re-compute aggregate's lcommunity.
+ */
+ if (aggregate->lcommunity)
+ lcommunity_free(&aggregate->lcommunity);
+ if (aggregate->lcommunity_hash &&
+ aggregate->lcommunity_hash->count) {
hash_iterate(aggregate->lcommunity_hash,
bgp_aggr_lcommunity_prepare,
&aggregate->lcommunity);
+ lcommerge = aggregate->lcommunity;
+ aggregate->lcommunity = lcommunity_uniq_sort(lcommerge);
+ if (lcommerge)
+ lcommunity_free(&lcommerge);
}
-
- /* Increment refernce counter.
- */
- aggr_lcommunity->refcnt++;
}
void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate,
@@ -618,10 +639,9 @@ void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate,
struct lcommunity *aggr_lcommunity = NULL;
struct lcommunity *ret_lcomm = NULL;
- if ((aggregate == NULL) || (lcommunity == NULL))
- return;
-
- if (aggregate->lcommunity_hash == NULL)
+ if ((!aggregate)
+ || (!aggregate->lcommunity_hash)
+ || (!lcommunity))
return;
/* Look-up the lcommunity in the hash.
@@ -635,13 +655,33 @@ void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate,
aggr_lcommunity);
lcommunity_free(&ret_lcomm);
- lcommunity_free(&aggregate->lcommunity);
+ bgp_compute_aggregate_lcommunity_val(aggregate);
+
+ }
+ }
+}
+
+void bgp_remove_lcomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
+ struct lcommunity *lcommunity)
+{
+ struct lcommunity *aggr_lcommunity = NULL;
+ struct lcommunity *ret_lcomm = NULL;
- /* Compute aggregate's lcommunity.
- */
- hash_iterate(aggregate->lcommunity_hash,
- bgp_aggr_lcommunity_prepare,
- &aggregate->lcommunity);
+ if ((!aggregate)
+ || (!aggregate->lcommunity_hash)
+ || (!lcommunity))
+ return;
+
+ /* Look-up the lcommunity in the hash.
+ */
+ aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
+ if (aggr_lcommunity) {
+ aggr_lcommunity->refcnt--;
+
+ if (aggr_lcommunity->refcnt == 0) {
+ ret_lcomm = hash_release(aggregate->lcommunity_hash,
+ aggr_lcommunity);
+ lcommunity_free(&ret_lcomm);
}
}
}
diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h
index a51239549..7d63f4d26 100644
--- a/bgpd/bgp_lcommunity.h
+++ b/bgpd/bgp_lcommunity.h
@@ -75,9 +75,19 @@ extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr);
extern void bgp_compute_aggregate_lcommunity(
struct bgp_aggregate *aggregate,
struct lcommunity *lcommunity);
+
+extern void bgp_compute_aggregate_lcommunity_hash(
+ struct bgp_aggregate *aggregate,
+ struct lcommunity *lcommunity);
+extern void bgp_compute_aggregate_lcommunity_val(
+ struct bgp_aggregate *aggregate);
+
extern void bgp_remove_lcommunity_from_aggregate(
struct bgp_aggregate *aggregate,
struct lcommunity *lcommunity);
+extern void bgp_remove_lcomm_from_aggregate_hash(
+ struct bgp_aggregate *aggregate,
+ struct lcommunity *lcommunity);
extern void bgp_aggr_lcommunity_remove(void *arg);
#endif /* _QUAGGA_BGP_LCOMMUNITY_H */
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index ef73b47ff..6b91a2cf1 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -75,6 +75,7 @@ static const struct option longopts[] = {
{"ecmp", required_argument, NULL, 'e'},
{"int_num", required_argument, NULL, 'I'},
{"no_zebra", no_argument, NULL, 'Z'},
+ {"socket_size", required_argument, NULL, 's'},
{0}};
/* signal definitions */
@@ -386,17 +387,19 @@ int main(int argc, char **argv)
int no_zebra_flag = 0;
int skip_runas = 0;
int instance = 0;
+ int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
frr_preinit(&bgpd_di, argc, argv);
frr_opt_add(
- "p:l:SnZe:I:" DEPRECATED_OPTIONS, longopts,
+ "p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts,
" -p, --bgp_port Set BGP listen port number (0 means do not listen).\n"
" -l, --listenon Listen on specified address (implies -n)\n"
" -n, --no_kernel Do not install route to kernel.\n"
" -Z, --no_zebra Do not communicate with Zebra.\n"
" -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n"
" -e, --ecmp Specify ECMP to use.\n"
- " -I, --int_num Set instance number (label-manager)\n");
+ " -I, --int_num Set instance number (label-manager)\n"
+ " -s, --socket_size Set BGP peer socket send buffer size\n");
/* Command line argument treatment. */
while (1) {
@@ -452,6 +455,9 @@ int main(int argc, char **argv)
zlog_err("Instance %i out of range (0..%u)",
instance, (unsigned short)-1);
break;
+ case 's':
+ buffer_size = atoi(optarg);
+ break;
default:
frr_help_exit(1);
break;
@@ -461,7 +467,7 @@ int main(int argc, char **argv)
memset(&bgpd_privs, 0, sizeof(bgpd_privs));
/* BGP master init. */
- bgp_master_init(frr_init());
+ bgp_master_init(frr_init(), buffer_size);
bm->port = bgp_port;
if (bgp_port == 0)
bgp_option_set(BGP_OPT_NO_LISTEN);
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 648c3be47..d37bf5473 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -614,8 +614,6 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
if ((mpath_count < maxpaths) && (new_mpath != new_best)
&& bgp_path_info_nexthop_cmp(prev_mpath,
new_mpath)) {
- if (new_mpath == next_mpath)
- bgp_path_info_mpath_next(new_mpath);
bgp_path_info_mpath_dequeue(new_mpath);
bgp_path_info_mpath_enqueue(prev_mpath,
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index c81abd643..1d1536141 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -109,7 +109,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
uint16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
- struct prefix_rd prd;
+ struct prefix_rd prd = {0};
mpls_label_t label = {0};
afi_t afi;
safi_t safi;
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 887caee95..4031d2dfd 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -320,6 +320,14 @@ static int bgp_get_instance_for_inc_conn(int sock, struct bgp **bgp_inst)
#endif
}
+static void bgp_socket_set_buffer_size(const int fd)
+{
+ if (getsockopt_so_sendbuf(fd) < (int)bm->socket_buffer)
+ setsockopt_so_sendbuf(fd, bm->socket_buffer);
+ if (getsockopt_so_recvbuf(fd) < (int)bm->socket_buffer)
+ setsockopt_so_recvbuf(fd, bm->socket_buffer);
+}
+
/* Accept bgp connection. */
static int bgp_accept(struct thread *thread)
{
@@ -371,8 +379,7 @@ static int bgp_accept(struct thread *thread)
return -1;
}
- /* Set socket send buffer size */
- setsockopt_so_sendbuf(bgp_sock, BGP_SOCKET_SNDBUF_SIZE);
+ bgp_socket_set_buffer_size(bgp_sock);
/* Check remote IP address */
peer1 = peer_lookup(bgp, &su);
@@ -438,12 +445,15 @@ static int bgp_accept(struct thread *thread)
return -1;
}
- /* Check whether max prefix restart timer is set for the peer */
- if (peer1->t_pmax_restart) {
+ /* Do not try to reconnect if the peer reached maximum
+ * prefixes, restart timer is still running or the peer
+ * is shutdown.
+ */
+ if (BGP_PEER_START_SUPPRESSED(peer1)) {
if (bgp_debug_neighbor_events(peer1))
zlog_debug(
- "%s - incoming conn rejected - "
- "peer max prefix timer is active",
+ "[Event] Incoming BGP connection rejected from %s "
+ "due to maximum-prefix or shutdown",
peer1->host);
close(bgp_sock);
return -1;
@@ -618,8 +628,7 @@ int bgp_connect(struct peer *peer)
set_nonblocking(peer->fd);
- /* Set socket send buffer size */
- setsockopt_so_sendbuf(peer->fd, BGP_SOCKET_SNDBUF_SIZE);
+ bgp_socket_set_buffer_size(peer->fd);
if (bgp_set_socket_ttl(peer, peer->fd) < 0)
return -1;
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 2d50d1c9e..83194e010 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -706,7 +706,7 @@ int bgp_pbr_build_and_validate_entry(struct prefix *p,
if (ret < 0)
return -1;
/* extract actiosn from flowspec ecom list */
- if (path && path->attr && path->attr->ecommunity) {
+ if (path && path->attr->ecommunity) {
ecom = path->attr->ecommunity;
for (i = 0; i < ecom->size; i++) {
ecom_eval = (struct ecommunity_val *)
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 05974bb2b..77428bbb0 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -249,8 +249,7 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi)
/* Free bgp route information. */
static void bgp_path_info_free(struct bgp_path_info *path)
{
- if (path->attr)
- bgp_attr_unintern(&path->attr);
+ bgp_attr_unintern(&path->attr);
bgp_unlink_nexthop(path);
bgp_path_info_extra_free(&path->extra);
@@ -1752,18 +1751,22 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
* if
* the peer (group) is configured to receive link-local nexthop
* unchanged
- * and it is available in the prefix OR we're not reflecting the route
- * and
+ * and it is available in the prefix OR we're not reflecting the route,
+ * link-local nexthop address is valid and
* the peer (group) to whom we're going to announce is on a shared
* network
* and this is either a self-originated route or the peer is EBGP.
+ * By checking if nexthop LL address is valid we are sure that
+ * we do not announce LL address as `::`.
*/
if (NEXTHOP_IS_V6) {
attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
if ((CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)
&& IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local))
- || (!reflect && peer->shared_network
+ || (!reflect
+ && IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local)
+ && peer->shared_network
&& (from == bgp->peer_self
|| peer->sort == BGP_PEER_EBGP))) {
attr->mp_nexthop_len =
@@ -1785,9 +1788,9 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
/* Route map & unsuppress-map apply. */
if (ROUTE_MAP_OUT_NAME(filter) || (pi->extra && pi->extra->suppress)) {
- struct bgp_path_info rmap_path;
- struct bgp_path_info_extra dummy_rmap_path_extra;
- struct attr dummy_attr;
+ struct bgp_path_info rmap_path = {0};
+ struct bgp_path_info_extra dummy_rmap_path_extra = {0};
+ struct attr dummy_attr = {0};
memset(&rmap_path, 0, sizeof(struct bgp_path_info));
rmap_path.peer = peer;
@@ -2748,8 +2751,8 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
return 0;
zlog_info(
- "%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, "
- "limit %ld",
+ "%%MAXPFXEXCEED: No. of %s prefix received from %s %" PRIu32
+ " exceed, limit %" PRIu32,
get_afi_safi_str(afi, safi, false), peer->host,
peer->pcount[afi][safi], peer->pmax[afi][safi]);
SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT);
@@ -2810,7 +2813,8 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
return 0;
zlog_info(
- "%%MAXPFX: No. of %s prefix received from %s reaches %ld, max %ld",
+ "%%MAXPFX: No. of %s prefix received from %s reaches %" PRIu32
+ ", max %" PRIu32,
get_afi_safi_str(afi, safi, false), peer->host,
peer->pcount[afi][safi], peer->pmax[afi][safi]);
SET_FLAG(peer->af_sflags[afi][safi],
@@ -2938,17 +2942,9 @@ static bool overlay_index_equal(afi_t afi, struct bgp_path_info *path,
if (afi != AFI_L2VPN)
return true;
- if (!path->attr) {
- memset(&temp, 0, sizeof(temp));
- path_eth_s_id = &temp.esi;
- path_gw_ip = &temp.ip;
- if (eth_s_id == NULL && gw_ip == NULL)
- return true;
- } else {
- path_eth_s_id = &(path->attr->evpn_overlay.eth_s_id);
- path_gw_ip = &(path->attr->evpn_overlay.gw_ip);
- }
+ path_eth_s_id = &(path->attr->evpn_overlay.eth_s_id);
+ path_gw_ip = &(path->attr->evpn_overlay.gw_ip);
if (gw_ip == NULL) {
memset(&temp, 0, sizeof(temp));
@@ -3164,6 +3160,12 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
goto filtered;
}
+ if (pi && pi->attr->rmap_table_id != new_attr.rmap_table_id) {
+ if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
+ /* remove from RIB previous entry */
+ bgp_zebra_withdraw(p, pi, bgp, safi);
+ }
+
if (peer->sort == BGP_PEER_EBGP) {
/* If we receive the graceful-shutdown community from an eBGP
@@ -3926,12 +3928,16 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
if (ain->peer != peer)
continue;
- struct bgp_path_info *pi =
- bgp_node_get_bgp_path_info(rn);
+ struct bgp_path_info *pi;
uint32_t num_labels = 0;
mpls_label_t *label_pnt = NULL;
struct bgp_route_evpn evpn;
+ for (pi = bgp_node_get_bgp_path_info(rn); pi;
+ pi = pi->next)
+ if (pi->peer == peer)
+ break;
+
if (pi && pi->extra)
num_labels = pi->extra->num_labels;
if (num_labels)
@@ -5927,33 +5933,41 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
*/
/* Compute aggregate route's as-path.
*/
- bgp_compute_aggregate_aspath(aggregate,
- pi->attr->aspath);
+ bgp_compute_aggregate_aspath_hash(aggregate,
+ pi->attr->aspath);
/* Compute aggregate route's community.
*/
if (pi->attr->community)
- bgp_compute_aggregate_community(
+ bgp_compute_aggregate_community_hash(
aggregate,
pi->attr->community);
/* Compute aggregate route's extended community.
*/
if (pi->attr->ecommunity)
- bgp_compute_aggregate_ecommunity(
+ bgp_compute_aggregate_ecommunity_hash(
aggregate,
pi->attr->ecommunity);
/* Compute aggregate route's large community.
*/
if (pi->attr->lcommunity)
- bgp_compute_aggregate_lcommunity(
+ bgp_compute_aggregate_lcommunity_hash(
aggregate,
pi->attr->lcommunity);
}
if (match)
bgp_process(bgp, rn, afi, safi);
}
+ if (aggregate->as_set) {
+ bgp_compute_aggregate_aspath_val(aggregate);
+ bgp_compute_aggregate_community_val(aggregate);
+ bgp_compute_aggregate_ecommunity_val(aggregate);
+ bgp_compute_aggregate_lcommunity_val(aggregate);
+ }
+
+
bgp_unlock_node(top);
@@ -6034,28 +6048,28 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
if (aggregate->as_set) {
/* Remove as-path from aggregate.
*/
- bgp_remove_aspath_from_aggregate(
+ bgp_remove_aspath_from_aggregate_hash(
aggregate,
pi->attr->aspath);
if (pi->attr->community)
/* Remove community from aggregate.
*/
- bgp_remove_community_from_aggregate(
+ bgp_remove_comm_from_aggregate_hash(
aggregate,
pi->attr->community);
if (pi->attr->ecommunity)
/* Remove ecommunity from aggregate.
*/
- bgp_remove_ecommunity_from_aggregate(
+ bgp_remove_ecomm_from_aggregate_hash(
aggregate,
pi->attr->ecommunity);
if (pi->attr->lcommunity)
/* Remove lcommunity from aggregate.
*/
- bgp_remove_lcommunity_from_aggregate(
+ bgp_remove_lcomm_from_aggregate_hash(
aggregate,
pi->attr->lcommunity);
}
@@ -6066,6 +6080,17 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
if (match)
bgp_process(bgp, rn, afi, safi);
}
+ if (aggregate->as_set) {
+ aspath_free(aggregate->aspath);
+ aggregate->aspath = NULL;
+ if (aggregate->community)
+ community_free(&aggregate->community);
+ if (aggregate->ecommunity)
+ ecommunity_free(&aggregate->ecommunity);
+ if (aggregate->lcommunity)
+ lcommunity_free(&aggregate->lcommunity);
+ }
+
bgp_unlock_node(top);
}
@@ -6543,6 +6568,7 @@ DEFUN (aggregate_address_mask,
argv_find(argv, argc, "A.B.C.D", &idx);
char *prefix = argv[idx]->arg;
char *mask = argv[idx + 1]->arg;
+ bool rmap_found;
char *rmap = NULL;
int as_set =
argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
@@ -6551,8 +6577,8 @@ DEFUN (aggregate_address_mask,
? AGGREGATE_SUMMARY_ONLY
: 0;
- argv_find(argv, argc, "WORD", &idx);
- if (idx)
+ rmap_found = argv_find(argv, argc, "WORD", &idx);
+ if (rmap_found)
rmap = argv[idx]->arg;
char prefix_str[BUFSIZ];
@@ -6569,14 +6595,16 @@ DEFUN (aggregate_address_mask,
DEFUN (no_aggregate_address,
no_aggregate_address_cmd,
- "no aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>]",
+ "no aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
NO_STR
"Configure BGP aggregate entries\n"
"Aggregate prefix\n"
"Generate AS set path information\n"
"Filter more specific routes from updates\n"
"Filter more specific routes from updates\n"
- "Generate AS set path information\n")
+ "Generate AS set path information\n"
+ "Apply route map to aggregate network\n"
+ "Name of route map\n")
{
int idx = 0;
argv_find(argv, argc, "A.B.C.D/M", &idx);
@@ -6586,7 +6614,7 @@ DEFUN (no_aggregate_address,
DEFUN (no_aggregate_address_mask,
no_aggregate_address_mask_cmd,
- "no aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>]",
+ "no aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
NO_STR
"Configure BGP aggregate entries\n"
"Aggregate address\n"
@@ -6594,7 +6622,9 @@ DEFUN (no_aggregate_address_mask,
"Generate AS set path information\n"
"Filter more specific routes from updates\n"
"Filter more specific routes from updates\n"
- "Generate AS set path information\n")
+ "Generate AS set path information\n"
+ "Apply route map to aggregate network\n"
+ "Name of route map\n")
{
int idx = 0;
argv_find(argv, argc, "A.B.C.D", &idx);
@@ -6628,6 +6658,7 @@ DEFUN (ipv6_aggregate_address,
argv_find(argv, argc, "X:X::X:X/M", &idx);
char *prefix = argv[idx]->arg;
char *rmap = NULL;
+ bool rmap_found;
int as_set =
argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
@@ -6636,8 +6667,8 @@ DEFUN (ipv6_aggregate_address,
? AGGREGATE_SUMMARY_ONLY
: 0;
- argv_find(argv, argc, "WORD", &idx);
- if (idx)
+ rmap_found = argv_find(argv, argc, "WORD", &idx);
+ if (rmap_found)
rmap = argv[idx]->arg;
return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap,
@@ -6646,14 +6677,16 @@ DEFUN (ipv6_aggregate_address,
DEFUN (no_ipv6_aggregate_address,
no_ipv6_aggregate_address_cmd,
- "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]",
+ "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
NO_STR
"Configure BGP aggregate entries\n"
"Aggregate prefix\n"
"Generate AS set path information\n"
"Filter more specific routes from updates\n"
"Filter more specific routes from updates\n"
- "Generate AS set path information\n")
+ "Generate AS set path information\n"
+ "Apply route map to aggregate network\n"
+ "Name of route map\n")
{
int idx = 0;
argv_find(argv, argc, "X:X::X:X/M", &idx);
@@ -6680,6 +6713,10 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
/* Make default attribute. */
bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
+ /*
+ * This must not be NULL to satisfy Coverity SA
+ */
+ assert(attr.aspath);
switch (nhtype) {
case NEXTHOP_TYPE_IFINDEX:
@@ -7082,14 +7119,6 @@ void route_vty_out(struct vty *vty, struct prefix *p,
/* Print attribute */
attr = path->attr;
- if (!attr) {
- if (json_paths)
- json_object_array_add(json_paths, json_path);
- else
- vty_out(vty, "\n");
-
- return;
- }
/*
* If vrf id of nexthop is different from that of prefix,
@@ -7216,21 +7245,11 @@ void route_vty_out(struct vty *vty, struct prefix *p,
if (json_paths) {
json_nexthop_global = json_object_new_object();
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
- json_object_string_add(
- json_nexthop_global,
- nexthop_fqdn ? "fqdn" : "ip",
- nexthop_fqdn
- ? nexthop_fqdn
- : inet_ntoa(
- attr->mp_nexthop_global_in));
- else
- json_object_string_add(
- json_nexthop_global,
- nexthop_fqdn ? "fqdn" : "ip",
- nexthop_fqdn
- ? nexthop_fqdn
- : inet_ntoa(attr->nexthop));
+ json_object_string_add(json_nexthop_global,
+ nexthop_fqdn ? "fqdn" : "ip",
+ nexthop_fqdn
+ ? nexthop_fqdn
+ : inet_ntoa(attr->nexthop));
json_object_string_add(json_nexthop_global, "afi",
"ipv4");
@@ -7490,7 +7509,7 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
json_object *json_status = NULL;
json_object *json_net = NULL;
char buff[BUFSIZ];
- char buf2[BUFSIZ];
+
/* Route status display. */
if (use_json) {
json_status = json_object_new_object();
@@ -7503,12 +7522,18 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
/* print prefix and mask */
if (use_json) {
- json_object_string_add(
- json_net, "addrPrefix",
- inet_ntop(p->family, &p->u.prefix, buff, BUFSIZ));
- json_object_int_add(json_net, "prefixLen", p->prefixlen);
- prefix2str(p, buf2, PREFIX_STRLEN);
- json_object_string_add(json_net, "network", buf2);
+ if (safi == SAFI_EVPN)
+ bgp_evpn_route2json((struct prefix_evpn *)p, json_net);
+ else if (p->family == AF_INET || p->family == AF_INET6) {
+ json_object_string_add(
+ json_net, "addrPrefix",
+ inet_ntop(p->family, &p->u.prefix, buff,
+ BUFSIZ));
+ json_object_int_add(json_net, "prefixLen",
+ p->prefixlen);
+ prefix2str(p, buff, PREFIX_STRLEN);
+ json_object_string_add(json_net, "network", buff);
+ }
} else
route_vty_out_route(p, vty, NULL);
@@ -7517,10 +7542,8 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
if (use_json) {
if (p->family == AF_INET
&& (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
- || safi == SAFI_EVPN
|| !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
- || safi == SAFI_EVPN)
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
json_object_string_add(
json_net, "nextHop",
inet_ntoa(
@@ -7538,7 +7561,11 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
inet_ntop(AF_INET6,
&attr->mp_nexthop_global, buf,
BUFSIZ));
- }
+ } else if (p->family == AF_EVPN &&
+ !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+ json_object_string_add(json_net,
+ "nextHop", inet_ntoa(
+ attr->mp_nexthop_global_in));
if (attr->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
@@ -7632,10 +7659,9 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
json_object_boolean_true_add(json_status, ">");
json_object_object_add(json_net, "appliedStatusSymbols",
json_status);
- char buf_cut[BUFSIZ];
- prefix2str(p, buf_cut, PREFIX_STRLEN);
- json_object_object_add(json_ar, buf_cut, json_net);
+ prefix2str(p, buff, PREFIX_STRLEN);
+ json_object_object_add(json_ar, buff, json_net);
} else
vty_out(vty, "\n");
}
@@ -7667,64 +7693,56 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
/* Print attribute */
attr = path->attr;
- if (attr) {
- if (((p->family == AF_INET)
- && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
- || (safi == SAFI_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
- || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
- || safi == SAFI_EVPN) {
- if (json)
- json_object_string_add(
- json_out, "mpNexthopGlobalIn",
- inet_ntoa(
- attr->mp_nexthop_global_in));
- else
- vty_out(vty, "%-16s",
- inet_ntoa(
- attr->mp_nexthop_global_in));
- } else {
- if (json)
- json_object_string_add(
- json_out, "nexthop",
- inet_ntoa(attr->nexthop));
- else
- vty_out(vty, "%-16s",
- inet_ntoa(attr->nexthop));
- }
- } else if (((p->family == AF_INET6)
- && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
- || (safi == SAFI_EVPN
- && BGP_ATTR_NEXTHOP_AFI_IP6(attr))
- || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
- char buf_a[512];
- if (attr->mp_nexthop_len
- == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
- if (json)
- json_object_string_add(
- json_out, "mpNexthopGlobalIn",
- inet_ntop(
- AF_INET6,
- &attr->mp_nexthop_global,
- buf_a, sizeof(buf_a)));
- else
- vty_out(vty, "%s",
- inet_ntop(
- AF_INET6,
- &attr->mp_nexthop_global,
- buf_a, sizeof(buf_a)));
- } else if (attr->mp_nexthop_len
- == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
- snprintfrr(buf_a, sizeof(buf_a), "%pI6(%pI6)",
- &attr->mp_nexthop_global,
- &attr->mp_nexthop_local);
- if (json)
- json_object_string_add(
- json_out,
- "mpNexthopGlobalLocal", buf_a);
- else
- vty_out(vty, "%s", buf_a);
- }
+ if (((p->family == AF_INET)
+ && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
+ || (safi == SAFI_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+ || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
+ || safi == SAFI_EVPN) {
+ if (json)
+ json_object_string_add(
+ json_out, "mpNexthopGlobalIn",
+ inet_ntoa(attr->mp_nexthop_global_in));
+ else
+ vty_out(vty, "%-16s",
+ inet_ntoa(attr->mp_nexthop_global_in));
+ } else {
+ if (json)
+ json_object_string_add(
+ json_out, "nexthop",
+ inet_ntoa(attr->nexthop));
+ else
+ vty_out(vty, "%-16s", inet_ntoa(attr->nexthop));
+ }
+ } else if (((p->family == AF_INET6)
+ && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
+ || (safi == SAFI_EVPN && BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+ || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
+ char buf_a[512];
+
+ if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
+ if (json)
+ json_object_string_add(
+ json_out, "mpNexthopGlobalIn",
+ inet_ntop(AF_INET6,
+ &attr->mp_nexthop_global,
+ buf_a, sizeof(buf_a)));
+ else
+ vty_out(vty, "%s",
+ inet_ntop(AF_INET6,
+ &attr->mp_nexthop_global,
+ buf_a, sizeof(buf_a)));
+ } else if (attr->mp_nexthop_len
+ == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
+ snprintfrr(buf_a, sizeof(buf_a), "%pI6(%pI6)",
+ &attr->mp_nexthop_global,
+ &attr->mp_nexthop_local);
+ if (json)
+ json_object_string_add(json_out,
+ "mpNexthopGlobalLocal",
+ buf_a);
+ else
+ vty_out(vty, "%s", buf_a);
}
}
@@ -7771,101 +7789,96 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p,
/* Print attribute */
attr = path->attr;
- if (attr) {
- char buf1[BUFSIZ];
- int af = NEXTHOP_FAMILY(attr->mp_nexthop_len);
+ char buf1[BUFSIZ];
+ int af = NEXTHOP_FAMILY(attr->mp_nexthop_len);
- switch (af) {
- case AF_INET:
- inet_ntop(af, &attr->mp_nexthop_global_in, buf, BUFSIZ);
- if (!json_path) {
- vty_out(vty, "%-16s", buf);
- } else {
- json_object_string_add(json_nexthop, "ip", buf);
+ switch (af) {
+ case AF_INET:
+ inet_ntop(af, &attr->mp_nexthop_global_in, buf, BUFSIZ);
+ if (!json_path) {
+ vty_out(vty, "%-16s", buf);
+ } else {
+ json_object_string_add(json_nexthop, "ip", buf);
- json_object_string_add(json_nexthop, "afi",
- "ipv4");
+ json_object_string_add(json_nexthop, "afi", "ipv4");
- json_object_object_add(json_path, "nexthop",
- json_nexthop);
- }
- break;
- case AF_INET6:
- inet_ntop(af, &attr->mp_nexthop_global, buf, BUFSIZ);
- inet_ntop(af, &attr->mp_nexthop_local, buf1, BUFSIZ);
- if (!json_path) {
- vty_out(vty, "%s(%s)", buf, buf1);
- } else {
- json_object_string_add(json_nexthop,
- "ipv6Global", buf);
+ json_object_object_add(json_path, "nexthop",
+ json_nexthop);
+ }
+ break;
+ case AF_INET6:
+ inet_ntop(af, &attr->mp_nexthop_global, buf, BUFSIZ);
+ inet_ntop(af, &attr->mp_nexthop_local, buf1, BUFSIZ);
+ if (!json_path) {
+ vty_out(vty, "%s(%s)", buf, buf1);
+ } else {
+ json_object_string_add(json_nexthop, "ipv6Global", buf);
- json_object_string_add(json_nexthop,
- "ipv6LinkLocal", buf1);
+ json_object_string_add(json_nexthop, "ipv6LinkLocal",
+ buf1);
- json_object_string_add(json_nexthop, "afi",
- "ipv6");
+ json_object_string_add(json_nexthop, "afi", "ipv6");
- json_object_object_add(json_path, "nexthop",
- json_nexthop);
- }
- break;
- default:
- if (!json_path) {
- vty_out(vty, "?");
- } else {
- json_object_string_add(json_nexthop, "Error",
- "Unsupported address-family");
- }
+ json_object_object_add(json_path, "nexthop",
+ json_nexthop);
+ }
+ break;
+ default:
+ if (!json_path) {
+ vty_out(vty, "?");
+ } else {
+ json_object_string_add(json_nexthop, "Error",
+ "Unsupported address-family");
}
+ }
- char *str = esi2str(&(attr->evpn_overlay.eth_s_id));
+ char *str = esi2str(&(attr->evpn_overlay.eth_s_id));
- if (!json_path)
- vty_out(vty, "%s", str);
- else
- json_object_string_add(json_overlay, "esi", str);
+ if (!json_path)
+ vty_out(vty, "%s", str);
+ else
+ json_object_string_add(json_overlay, "esi", str);
- XFREE(MTYPE_TMP, str);
+ XFREE(MTYPE_TMP, str);
- if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) {
- inet_ntop(AF_INET, &(attr->evpn_overlay.gw_ip.ipv4),
- buf, BUFSIZ);
- } else if (is_evpn_prefix_ipaddr_v6((struct prefix_evpn *)p)) {
- inet_ntop(AF_INET6, &(attr->evpn_overlay.gw_ip.ipv6),
- buf, BUFSIZ);
- }
+ if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) {
+ inet_ntop(AF_INET, &(attr->evpn_overlay.gw_ip.ipv4), buf,
+ BUFSIZ);
+ } else if (is_evpn_prefix_ipaddr_v6((struct prefix_evpn *)p)) {
+ inet_ntop(AF_INET6, &(attr->evpn_overlay.gw_ip.ipv6), buf,
+ BUFSIZ);
+ }
- if (!json_path)
- vty_out(vty, "/%s", buf);
- else
- json_object_string_add(json_overlay, "gw", buf);
-
- if (attr->ecommunity) {
- char *mac = NULL;
- struct ecommunity_val *routermac = ecommunity_lookup(
- attr->ecommunity, ECOMMUNITY_ENCODE_EVPN,
- ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC);
- if (routermac)
- mac = ecom_mac2str((char *)routermac->val);
- if (mac) {
- if (!json_path) {
- vty_out(vty, "/%s", (char *)mac);
- } else {
- json_object_string_add(json_overlay,
- "rmac", mac);
- }
- XFREE(MTYPE_TMP, mac);
+ if (!json_path)
+ vty_out(vty, "/%s", buf);
+ else
+ json_object_string_add(json_overlay, "gw", buf);
+
+ if (attr->ecommunity) {
+ char *mac = NULL;
+ struct ecommunity_val *routermac = ecommunity_lookup(
+ attr->ecommunity, ECOMMUNITY_ENCODE_EVPN,
+ ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC);
+
+ if (routermac)
+ mac = ecom_mac2str((char *)routermac->val);
+ if (mac) {
+ if (!json_path) {
+ vty_out(vty, "/%s", (char *)mac);
+ } else {
+ json_object_string_add(json_overlay, "rmac",
+ mac);
}
+ XFREE(MTYPE_TMP, mac);
}
+ }
- if (!json_path) {
- vty_out(vty, "\n");
- } else {
- json_object_object_add(json_path, "overlay",
- json_overlay);
+ if (!json_path) {
+ vty_out(vty, "\n");
+ } else {
+ json_object_object_add(json_path, "overlay", json_overlay);
- json_object_array_add(json_paths, json_path);
- }
+ json_object_array_add(json_paths, json_path);
}
}
@@ -7912,23 +7925,23 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p,
/* Print attribute */
attr = path->attr;
- if (attr) {
- /* Print aspath */
- if (attr->aspath) {
- if (use_json)
- json_object_string_add(json, "asPath",
- attr->aspath->str);
- else
- aspath_print_vty(vty, "%s", attr->aspath, " ");
- }
- /* Print origin */
+ /* Print aspath */
+ if (attr->aspath) {
if (use_json)
- json_object_string_add(json, "origin",
- bgp_origin_str[attr->origin]);
+ json_object_string_add(json, "asPath",
+ attr->aspath->str);
else
- vty_out(vty, "%s", bgp_origin_str[attr->origin]);
+ aspath_print_vty(vty, "%s", attr->aspath, " ");
}
+
+ /* Print origin */
+ if (use_json)
+ json_object_string_add(json, "origin",
+ bgp_origin_str[attr->origin]);
+ else
+ vty_out(vty, "%s", bgp_origin_str[attr->origin]);
+
if (!use_json)
vty_out(vty, "\n");
}
@@ -8007,23 +8020,23 @@ static void flap_route_vty_out(struct vty *vty, struct prefix *p,
/* Print attribute */
attr = path->attr;
- if (attr) {
- /* Print aspath */
- if (attr->aspath) {
- if (use_json)
- json_object_string_add(json, "asPath",
- attr->aspath->str);
- else
- aspath_print_vty(vty, "%s", attr->aspath, " ");
- }
- /* Print origin */
+ /* Print aspath */
+ if (attr->aspath) {
if (use_json)
- json_object_string_add(json, "origin",
- bgp_origin_str[attr->origin]);
+ json_object_string_add(json, "asPath",
+ attr->aspath->str);
else
- vty_out(vty, "%s", bgp_origin_str[attr->origin]);
+ aspath_print_vty(vty, "%s", attr->aspath, " ");
}
+
+ /* Print origin */
+ if (use_json)
+ json_object_string_add(json, "origin",
+ bgp_origin_str[attr->origin]);
+ else
+ vty_out(vty, "%s", bgp_origin_str[attr->origin]);
+
if (!use_json)
vty_out(vty, "\n");
}
@@ -8208,7 +8221,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
json_nexthop_global = json_object_new_object();
}
- if (!json_paths && path->extra) {
+ if (path->extra) {
char tag_buf[30];
buf2[0] = '\0';
@@ -8219,15 +8232,21 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
sizeof(tag_buf));
}
if (safi == SAFI_EVPN) {
- bgp_evpn_route2str((struct prefix_evpn *)&bn->p,
- buf2, sizeof(buf2));
- vty_out(vty, " Route %s", buf2);
- if (tag_buf[0] != '\0')
- vty_out(vty, " VNI %s", tag_buf);
- vty_out(vty, "\n");
+ if (!json_paths) {
+ bgp_evpn_route2str((struct prefix_evpn *)&bn->p,
+ buf2, sizeof(buf2));
+ vty_out(vty, " Route %s", buf2);
+ if (tag_buf[0] != '\0')
+ vty_out(vty, " VNI %s", tag_buf);
+ vty_out(vty, "\n");
+ } else {
+ if (tag_buf[0])
+ json_object_string_add(json_path, "VNI",
+ tag_buf);
+ }
}
- if (path->extra && path->extra->parent) {
+ if (path->extra && path->extra->parent && !json_paths) {
struct bgp_path_info *parent_ri;
struct bgp_node *rn, *prn;
@@ -8249,819 +8268,739 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
attr = path->attr;
- if (attr) {
- /* Line1 display AS-path, Aggregator */
- if (attr->aspath) {
- if (json_paths) {
- if (!attr->aspath->json)
- aspath_str_update(attr->aspath, true);
- json_object_lock(attr->aspath->json);
- json_object_object_add(json_path, "aspath",
- attr->aspath->json);
- } else {
- if (attr->aspath->segments)
- aspath_print_vty(vty, " %s",
- attr->aspath, "");
- else
- vty_out(vty, " Local");
- }
- }
-
- if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED)) {
- if (json_paths)
- json_object_boolean_true_add(json_path,
- "removed");
+ /* Line1 display AS-path, Aggregator */
+ if (attr->aspath) {
+ if (json_paths) {
+ if (!attr->aspath->json)
+ aspath_str_update(attr->aspath, true);
+ json_object_lock(attr->aspath->json);
+ json_object_object_add(json_path, "aspath",
+ attr->aspath->json);
+ } else {
+ if (attr->aspath->segments)
+ aspath_print_vty(vty, " %s", attr->aspath, "");
else
- vty_out(vty, ", (removed)");
+ vty_out(vty, " Local");
}
+ }
- if (CHECK_FLAG(path->flags, BGP_PATH_STALE)) {
- if (json_paths)
- json_object_boolean_true_add(json_path,
- "stale");
- else
- vty_out(vty, ", (stale)");
- }
+ if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED)) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path, "removed");
+ else
+ vty_out(vty, ", (removed)");
+ }
- if (CHECK_FLAG(attr->flag,
- ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
- if (json_paths) {
- json_object_int_add(json_path, "aggregatorAs",
- attr->aggregator_as);
- json_object_string_add(
- json_path, "aggregatorId",
- inet_ntoa(attr->aggregator_addr));
- } else {
- vty_out(vty, ", (aggregated by %u %s)",
- attr->aggregator_as,
- inet_ntoa(attr->aggregator_addr));
- }
- }
+ if (CHECK_FLAG(path->flags, BGP_PATH_STALE)) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path, "stale");
+ else
+ vty_out(vty, ", (stale)");
+ }
- if (CHECK_FLAG(path->peer->af_flags[afi][safi],
- PEER_FLAG_REFLECTOR_CLIENT)) {
- if (json_paths)
- json_object_boolean_true_add(
- json_path, "rxedFromRrClient");
- else
- vty_out(vty, ", (Received from a RR-client)");
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
+ if (json_paths) {
+ json_object_int_add(json_path, "aggregatorAs",
+ attr->aggregator_as);
+ json_object_string_add(
+ json_path, "aggregatorId",
+ inet_ntoa(attr->aggregator_addr));
+ } else {
+ vty_out(vty, ", (aggregated by %u %s)",
+ attr->aggregator_as,
+ inet_ntoa(attr->aggregator_addr));
}
+ }
- if (CHECK_FLAG(path->peer->af_flags[afi][safi],
- PEER_FLAG_RSERVER_CLIENT)) {
- if (json_paths)
- json_object_boolean_true_add(
- json_path, "rxedFromRsClient");
- else
- vty_out(vty, ", (Received from a RS-client)");
- }
+ if (CHECK_FLAG(path->peer->af_flags[afi][safi],
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path,
+ "rxedFromRrClient");
+ else
+ vty_out(vty, ", (Received from a RR-client)");
+ }
- if (CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) {
- if (json_paths)
- json_object_boolean_true_add(
- json_path, "dampeningHistoryEntry");
- else
- vty_out(vty, ", (history entry)");
- } else if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) {
- if (json_paths)
- json_object_boolean_true_add(
- json_path, "dampeningSuppressed");
- else
- vty_out(vty, ", (suppressed due to dampening)");
- }
+ if (CHECK_FLAG(path->peer->af_flags[afi][safi],
+ PEER_FLAG_RSERVER_CLIENT)) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path,
+ "rxedFromRsClient");
+ else
+ vty_out(vty, ", (Received from a RS-client)");
+ }
- if (!json_paths)
- vty_out(vty, "\n");
+ if (CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path,
+ "dampeningHistoryEntry");
+ else
+ vty_out(vty, ", (history entry)");
+ } else if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path,
+ "dampeningSuppressed");
+ else
+ vty_out(vty, ", (suppressed due to dampening)");
+ }
- /* 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)
- && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
- || safi == SAFI_EVPN
- || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
- || safi == SAFI_EVPN) {
- if (json_paths)
- json_object_string_add(
- json_nexthop_global,
- nexthop_fqdn ? "fqdn" : "ip",
- nexthop_fqdn
- ? nexthop_fqdn
- : inet_ntoa(
- attr->mp_nexthop_global_in));
- else
- vty_out(vty, " %s",
- nexthop_fqdn
- ? nexthop_fqdn
- : inet_ntoa(
- attr->mp_nexthop_global_in));
- } else {
- if (json_paths)
- json_object_string_add(
- json_nexthop_global,
- nexthop_fqdn ? "fqdn" : "ip",
- nexthop_fqdn
- ? nexthop_fqdn
- : inet_ntoa(
- attr->nexthop));
- else
- vty_out(vty, " %s",
- nexthop_fqdn
- ? nexthop_fqdn
- : inet_ntoa(
- attr->nexthop));
- }
+ if (!json_paths)
+ vty_out(vty, "\n");
+ /* 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)
+ && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN
+ || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
+ || safi == SAFI_EVPN) {
if (json_paths)
- json_object_string_add(json_nexthop_global,
- "afi", "ipv4");
+ json_object_string_add(
+ json_nexthop_global,
+ nexthop_fqdn ? "fqdn" : "ip",
+ nexthop_fqdn
+ ? nexthop_fqdn
+ : inet_ntoa(
+ attr->mp_nexthop_global_in));
+ else
+ vty_out(vty, " %s",
+ nexthop_fqdn
+ ? nexthop_fqdn
+ : inet_ntoa(
+ attr->mp_nexthop_global_in));
} else {
- if (json_paths) {
+ if (json_paths)
json_object_string_add(
json_nexthop_global,
nexthop_fqdn ? "fqdn" : "ip",
nexthop_fqdn
? nexthop_fqdn
- : inet_ntop(
- AF_INET6,
- &attr->mp_nexthop_global,
- buf,
- INET6_ADDRSTRLEN));
- json_object_string_add(json_nexthop_global,
- "afi", "ipv6");
- json_object_string_add(json_nexthop_global,
- "scope", "global");
- } else {
+ : inet_ntoa(attr->nexthop));
+ else
vty_out(vty, " %s",
nexthop_fqdn
? nexthop_fqdn
- : inet_ntop(
- AF_INET6,
- &attr->mp_nexthop_global,
- buf,
- INET6_ADDRSTRLEN));
- }
+ : inet_ntoa(attr->nexthop));
}
- /* Display the IGP cost or 'inaccessible' */
- if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) {
- if (json_paths)
- json_object_boolean_false_add(
- json_nexthop_global, "accessible");
- else
- vty_out(vty, " (inaccessible)");
+ if (json_paths)
+ json_object_string_add(json_nexthop_global, "afi",
+ "ipv4");
+ } else {
+ if (json_paths) {
+ json_object_string_add(
+ json_nexthop_global,
+ nexthop_fqdn ? "fqdn" : "ip",
+ nexthop_fqdn
+ ? nexthop_fqdn
+ : inet_ntop(AF_INET6,
+ &attr->mp_nexthop_global,
+ buf, INET6_ADDRSTRLEN));
+ json_object_string_add(json_nexthop_global, "afi",
+ "ipv6");
+ json_object_string_add(json_nexthop_global, "scope",
+ "global");
} else {
- if (path->extra && path->extra->igpmetric) {
- if (json_paths)
- json_object_int_add(
- json_nexthop_global, "metric",
- path->extra->igpmetric);
- else
- vty_out(vty, " (metric %u)",
- path->extra->igpmetric);
- }
+ vty_out(vty, " %s",
+ nexthop_fqdn
+ ? nexthop_fqdn
+ : inet_ntop(AF_INET6,
+ &attr->mp_nexthop_global,
+ buf, INET6_ADDRSTRLEN));
+ }
+ }
- /* IGP cost is 0, display this only for json */
- else {
- if (json_paths)
- json_object_int_add(json_nexthop_global,
- "metric", 0);
- }
+ /* Display the IGP cost or 'inaccessible' */
+ if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) {
+ if (json_paths)
+ json_object_boolean_false_add(json_nexthop_global,
+ "accessible");
+ else
+ vty_out(vty, " (inaccessible)");
+ } else {
+ if (path->extra && path->extra->igpmetric) {
+ if (json_paths)
+ json_object_int_add(json_nexthop_global,
+ "metric",
+ path->extra->igpmetric);
+ else
+ vty_out(vty, " (metric %u)",
+ path->extra->igpmetric);
+ }
+ /* IGP cost is 0, display this only for json */
+ else {
if (json_paths)
- json_object_boolean_true_add(
- json_nexthop_global, "accessible");
+ json_object_int_add(json_nexthop_global,
+ "metric", 0);
}
- /* Display peer "from" output */
- /* This path was originated locally */
- if (path->peer == bgp->peer_self) {
+ if (json_paths)
+ json_object_boolean_true_add(json_nexthop_global,
+ "accessible");
+ }
- if (safi == SAFI_EVPN
- || (bn->p.family == AF_INET
- && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
- if (json_paths)
- json_object_string_add(
- json_peer, "peerId", "0.0.0.0");
- else
- vty_out(vty, " from 0.0.0.0 ");
- } else {
- if (json_paths)
- json_object_string_add(json_peer,
- "peerId", "::");
- else
- vty_out(vty, " from :: ");
- }
+ /* Display peer "from" output */
+ /* This path was originated locally */
+ if (path->peer == bgp->peer_self) {
+ if (safi == SAFI_EVPN
+ || (bn->p.family == AF_INET
+ && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
if (json_paths)
- json_object_string_add(
- json_peer, "routerId",
- inet_ntoa(bgp->router_id));
+ json_object_string_add(json_peer, "peerId",
+ "0.0.0.0");
+ else
+ vty_out(vty, " from 0.0.0.0 ");
+ } else {
+ if (json_paths)
+ json_object_string_add(json_peer, "peerId",
+ "::");
else
- vty_out(vty, "(%s)", inet_ntoa(bgp->router_id));
+ vty_out(vty, " from :: ");
}
- /* We RXed this path from one of our peers */
- else {
-
- if (json_paths) {
- json_object_string_add(
- json_peer, "peerId",
- sockunion2str(&path->peer->su, buf,
- SU_ADDRSTRLEN));
- json_object_string_add(
- json_peer, "routerId",
- inet_ntop(AF_INET,
- &path->peer->remote_id, buf1,
- sizeof(buf1)));
-
- if (path->peer->hostname)
- json_object_string_add(
- json_peer, "hostname",
- path->peer->hostname);
+ if (json_paths)
+ json_object_string_add(json_peer, "routerId",
+ inet_ntoa(bgp->router_id));
+ else
+ vty_out(vty, "(%s)", inet_ntoa(bgp->router_id));
+ }
- if (path->peer->domainname)
- json_object_string_add(
- json_peer, "domainname",
- path->peer->domainname);
+ /* We RXed this path from one of our peers */
+ else {
- if (path->peer->conf_if)
- json_object_string_add(
- json_peer, "interface",
+ if (json_paths) {
+ json_object_string_add(json_peer, "peerId",
+ sockunion2str(&path->peer->su,
+ buf,
+ SU_ADDRSTRLEN));
+ json_object_string_add(json_peer, "routerId",
+ inet_ntop(AF_INET,
+ &path->peer->remote_id,
+ buf1, sizeof(buf1)));
+
+ if (path->peer->hostname)
+ json_object_string_add(json_peer, "hostname",
+ path->peer->hostname);
+
+ if (path->peer->domainname)
+ json_object_string_add(json_peer, "domainname",
+ path->peer->domainname);
+
+ if (path->peer->conf_if)
+ json_object_string_add(json_peer, "interface",
+ path->peer->conf_if);
+ } else {
+ if (path->peer->conf_if) {
+ if (path->peer->hostname
+ && bgp_flag_check(path->peer->bgp,
+ BGP_FLAG_SHOW_HOSTNAME))
+ vty_out(vty, " from %s(%s)",
+ path->peer->hostname,
+ path->peer->conf_if);
+ else
+ vty_out(vty, " from %s",
path->peer->conf_if);
} else {
- if (path->peer->conf_if) {
- if (path->peer->hostname
- && bgp_flag_check(
- path->peer->bgp,
- BGP_FLAG_SHOW_HOSTNAME))
- vty_out(vty, " from %s(%s)",
- path->peer->hostname,
- path->peer->conf_if);
- else
- vty_out(vty, " from %s",
- path->peer->conf_if);
- } else {
- if (path->peer->hostname
- && bgp_flag_check(
- path->peer->bgp,
- BGP_FLAG_SHOW_HOSTNAME))
- vty_out(vty, " from %s(%s)",
- path->peer->hostname,
- path->peer->host);
- else
- vty_out(vty, " from %s",
- sockunion2str(
- &path->peer->su,
- buf,
- SU_ADDRSTRLEN));
- }
-
- if (attr->flag
- & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- vty_out(vty, " (%s)",
- inet_ntoa(attr->originator_id));
+ if (path->peer->hostname
+ && bgp_flag_check(path->peer->bgp,
+ BGP_FLAG_SHOW_HOSTNAME))
+ vty_out(vty, " from %s(%s)",
+ path->peer->hostname,
+ path->peer->host);
else
- vty_out(vty, " (%s)",
- inet_ntop(
- AF_INET,
- &path->peer->remote_id,
- buf1, sizeof(buf1)));
+ vty_out(vty, " from %s",
+ sockunion2str(&path->peer->su,
+ buf,
+ SU_ADDRSTRLEN));
}
- }
- /*
- * Note when vrfid of nexthop is different from that of prefix
- */
- if (path->extra && path->extra->bgp_orig) {
- vrf_id_t nexthop_vrfid = path->extra->bgp_orig->vrf_id;
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+ vty_out(vty, " (%s)",
+ inet_ntoa(attr->originator_id));
+ else
+ vty_out(vty, " (%s)",
+ inet_ntop(AF_INET,
+ &path->peer->remote_id, buf1,
+ sizeof(buf1)));
+ }
+ }
- if (json_paths) {
- const char *vn;
+ /*
+ * Note when vrfid of nexthop is different from that of prefix
+ */
+ if (path->extra && path->extra->bgp_orig) {
+ vrf_id_t nexthop_vrfid = path->extra->bgp_orig->vrf_id;
- if (path->extra->bgp_orig->inst_type
- == BGP_INSTANCE_TYPE_DEFAULT)
+ if (json_paths) {
+ const char *vn;
- vn = VRF_DEFAULT_NAME;
- else
- vn = path->extra->bgp_orig->name;
+ if (path->extra->bgp_orig->inst_type
+ == BGP_INSTANCE_TYPE_DEFAULT)
+ vn = VRF_DEFAULT_NAME;
+ else
+ vn = path->extra->bgp_orig->name;
- json_object_string_add(json_path, "nhVrfName",
- vn);
+ json_object_string_add(json_path, "nhVrfName", vn);
- if (nexthop_vrfid == VRF_UNKNOWN) {
- json_object_int_add(json_path,
- "nhVrfId", -1);
- } else {
- json_object_int_add(json_path,
- "nhVrfId", (int)nexthop_vrfid);
- }
+ if (nexthop_vrfid == VRF_UNKNOWN) {
+ json_object_int_add(json_path, "nhVrfId", -1);
} else {
- if (nexthop_vrfid == VRF_UNKNOWN)
- vty_out(vty, " vrf ?");
- else
- vty_out(vty, " vrf %u", nexthop_vrfid);
+ json_object_int_add(json_path, "nhVrfId",
+ (int)nexthop_vrfid);
}
+ } else {
+ if (nexthop_vrfid == VRF_UNKNOWN)
+ vty_out(vty, " vrf ?");
+ else
+ vty_out(vty, " vrf %u", nexthop_vrfid);
}
+ }
- if (nexthop_self) {
- if (json_paths) {
- json_object_boolean_true_add(json_path,
- "announceNexthopSelf");
- } else {
- vty_out(vty, " announce-nh-self");
- }
+ if (nexthop_self) {
+ if (json_paths) {
+ json_object_boolean_true_add(json_path,
+ "announceNexthopSelf");
+ } else {
+ vty_out(vty, " announce-nh-self");
}
+ }
- if (!json_paths)
- vty_out(vty, "\n");
+ if (!json_paths)
+ vty_out(vty, "\n");
- /* display the link-local nexthop */
- if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
- if (json_paths) {
- json_nexthop_ll = json_object_new_object();
- json_object_string_add(
- json_nexthop_ll,
- nexthop_fqdn ? "fqdn" : "ip",
- nexthop_fqdn
- ? nexthop_fqdn
- : inet_ntop(
- AF_INET6,
- &attr->mp_nexthop_local,
- buf,
- INET6_ADDRSTRLEN));
- json_object_string_add(json_nexthop_ll, "afi",
- "ipv6");
- json_object_string_add(json_nexthop_ll, "scope",
- "link-local");
+ /* display the link-local nexthop */
+ if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
+ if (json_paths) {
+ json_nexthop_ll = json_object_new_object();
+ json_object_string_add(
+ json_nexthop_ll, nexthop_fqdn ? "fqdn" : "ip",
+ nexthop_fqdn
+ ? nexthop_fqdn
+ : inet_ntop(AF_INET6,
+ &attr->mp_nexthop_local,
+ buf, INET6_ADDRSTRLEN));
+ json_object_string_add(json_nexthop_ll, "afi", "ipv6");
+ json_object_string_add(json_nexthop_ll, "scope",
+ "link-local");
+
+ json_object_boolean_true_add(json_nexthop_ll,
+ "accessible");
+ if (!attr->mp_nexthop_prefer_global)
json_object_boolean_true_add(json_nexthop_ll,
- "accessible");
+ "used");
+ else
+ json_object_boolean_true_add(
+ json_nexthop_global, "used");
+ } else {
+ vty_out(vty, " (%s) %s\n",
+ inet_ntop(AF_INET6, &attr->mp_nexthop_local,
+ buf, INET6_ADDRSTRLEN),
+ attr->mp_nexthop_prefer_global
+ ? "(prefer-global)"
+ : "(used)");
+ }
+ }
+ /* If we do not have a link-local nexthop then we must flag the
+ global as "used" */
+ else {
+ if (json_paths)
+ json_object_boolean_true_add(json_nexthop_global,
+ "used");
+ }
- if (!attr->mp_nexthop_prefer_global)
- json_object_boolean_true_add(
- json_nexthop_ll, "used");
+ /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid,
+ * Int/Ext/Local, Atomic, best */
+ if (json_paths)
+ json_object_string_add(json_path, "origin",
+ bgp_origin_long_str[attr->origin]);
+ else
+ vty_out(vty, " Origin %s",
+ 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);
+ json_object_int_add(json_path, "metric", attr->med);
+ } 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",
+ attr->local_pref);
+ else
+ vty_out(vty, ", localpref %u", attr->local_pref);
+ }
+
+ if (attr->weight != 0) {
+ if (json_paths)
+ json_object_int_add(json_path, "weight", attr->weight);
+ else
+ vty_out(vty, ", weight %u", attr->weight);
+ }
+
+ if (attr->tag != 0) {
+ if (json_paths)
+ json_object_int_add(json_path, "tag", attr->tag);
+ else
+ vty_out(vty, ", tag %" ROUTE_TAG_PRI, attr->tag);
+ }
+
+ if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) {
+ if (json_paths)
+ json_object_boolean_false_add(json_path, "valid");
+ else
+ vty_out(vty, ", invalid");
+ } else if (!CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path, "valid");
+ else
+ vty_out(vty, ", valid");
+ }
+
+ if (path->peer != bgp->peer_self) {
+ if (path->peer->as == path->peer->local_as) {
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
+ if (json_paths)
+ json_object_string_add(
+ json_peer, "type",
+ "confed-internal");
else
- json_object_boolean_true_add(
- json_nexthop_global, "used");
+ vty_out(vty, ", confed-internal");
} else {
- vty_out(vty, " (%s) %s\n",
- inet_ntop(AF_INET6,
- &attr->mp_nexthop_local, buf,
- INET6_ADDRSTRLEN),
- attr->mp_nexthop_prefer_global
- ? "(prefer-global)"
- : "(used)");
+ if (json_paths)
+ json_object_string_add(
+ json_peer, "type", "internal");
+ else
+ vty_out(vty, ", internal");
+ }
+ } else {
+ if (bgp_confederation_peers_check(bgp,
+ path->peer->as)) {
+ if (json_paths)
+ json_object_string_add(
+ json_peer, "type",
+ "confed-external");
+ else
+ vty_out(vty, ", confed-external");
+ } else {
+ if (json_paths)
+ json_object_string_add(
+ json_peer, "type", "external");
+ else
+ vty_out(vty, ", external");
}
}
- /* If we do not have a link-local nexthop then we must flag the
- global as "used" */
- else {
- if (json_paths)
- json_object_boolean_true_add(
- json_nexthop_global, "used");
+ } else if (path->sub_type == BGP_ROUTE_AGGREGATE) {
+ if (json_paths) {
+ json_object_boolean_true_add(json_path, "aggregated");
+ json_object_boolean_true_add(json_path, "local");
+ } else {
+ vty_out(vty, ", aggregated, local");
+ }
+ } else if (path->type != ZEBRA_ROUTE_BGP) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path, "sourced");
+ else
+ vty_out(vty, ", sourced");
+ } else {
+ if (json_paths) {
+ json_object_boolean_true_add(json_path, "sourced");
+ json_object_boolean_true_add(json_path, "local");
+ } else {
+ vty_out(vty, ", sourced, local");
}
+ }
- /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid,
- * Int/Ext/Local, Atomic, best */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
if (json_paths)
- json_object_string_add(
- json_path, "origin",
- bgp_origin_long_str[attr->origin]);
+ json_object_boolean_true_add(json_path,
+ "atomicAggregate");
else
- vty_out(vty, " Origin %s",
- bgp_origin_long_str[attr->origin]);
+ vty_out(vty, ", atomic-aggregate");
+ }
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) {
- if (json_paths) {
+ if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH)
+ || (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)
+ && bgp_path_info_mpath_count(path))) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path, "multipath");
+ else
+ vty_out(vty, ", multipath");
+ }
- /*
- * Adding "metric" field to match with
- * corresponding CLI. "med" will be
- * deprecated in future.
- */
- json_object_int_add(json_path, "med",
- attr->med);
- json_object_int_add(json_path, "metric",
- attr->med);
- } else
- vty_out(vty, ", metric %u", attr->med);
- }
+ // Mark the bestpath(s)
+ if (CHECK_FLAG(path->flags, BGP_PATH_DMED_SELECTED)) {
+ first_as = aspath_get_first_as(attr->aspath);
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
- if (json_paths)
- json_object_int_add(json_path, "localpref",
- attr->local_pref);
+ if (json_paths) {
+ if (!json_bestpath)
+ json_bestpath = json_object_new_object();
+ json_object_int_add(json_bestpath, "bestpathFromAs",
+ first_as);
+ } else {
+ if (first_as)
+ vty_out(vty, ", bestpath-from-AS %u", first_as);
else
- vty_out(vty, ", localpref %u",
- attr->local_pref);
+ vty_out(vty, ", bestpath-from-AS Local");
}
+ }
- if (attr->weight != 0) {
- if (json_paths)
- json_object_int_add(json_path, "weight",
- attr->weight);
- else
- vty_out(vty, ", weight %u", attr->weight);
+ if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) {
+ if (json_paths) {
+ if (!json_bestpath)
+ json_bestpath = json_object_new_object();
+ json_object_boolean_true_add(json_bestpath, "overall");
+ json_object_string_add(
+ json_bestpath, "selectionReason",
+ bgp_path_selection_reason2str(bn->reason));
+ } else {
+ vty_out(vty, ", best");
+ vty_out(vty, " (%s)",
+ bgp_path_selection_reason2str(bn->reason));
}
+ }
- if (attr->tag != 0) {
- if (json_paths)
- json_object_int_add(json_path, "tag",
- attr->tag);
- else
- vty_out(vty, ", tag %" ROUTE_TAG_PRI,
- attr->tag);
- }
+ if (json_bestpath)
+ json_object_object_add(json_path, "bestpath", json_bestpath);
- if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) {
- if (json_paths)
- json_object_boolean_false_add(json_path,
- "valid");
- else
- vty_out(vty, ", invalid");
- } else if (!CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) {
- if (json_paths)
- json_object_boolean_true_add(json_path,
- "valid");
- else
- vty_out(vty, ", valid");
+ if (!json_paths)
+ vty_out(vty, "\n");
+
+ /* Line 4 display Community */
+ if (attr->community) {
+ if (json_paths) {
+ if (!attr->community->json)
+ community_str(attr->community, true);
+ json_object_lock(attr->community->json);
+ json_object_object_add(json_path, "community",
+ attr->community->json);
+ } else {
+ vty_out(vty, " Community: %s\n",
+ attr->community->str);
}
+ }
- if (path->peer != bgp->peer_self) {
- if (path->peer->as == path->peer->local_as) {
- if (CHECK_FLAG(bgp->config,
- BGP_CONFIG_CONFEDERATION)) {
- if (json_paths)
- json_object_string_add(
- json_peer, "type",
- "confed-internal");
- else
- vty_out(vty,
- ", confed-internal");
- } else {
- if (json_paths)
- json_object_string_add(
- json_peer, "type",
- "internal");
- else
- vty_out(vty, ", internal");
- }
- } else {
- if (bgp_confederation_peers_check(
- bgp, path->peer->as)) {
- if (json_paths)
- json_object_string_add(
- json_peer, "type",
- "confed-external");
- else
- vty_out(vty,
- ", confed-external");
- } else {
- if (json_paths)
- json_object_string_add(
- json_peer, "type",
- "external");
- else
- vty_out(vty, ", external");
- }
- }
- } else if (path->sub_type == BGP_ROUTE_AGGREGATE) {
- if (json_paths) {
- json_object_boolean_true_add(json_path,
- "aggregated");
- json_object_boolean_true_add(json_path,
- "local");
- } else {
- vty_out(vty, ", aggregated, local");
- }
- } else if (path->type != ZEBRA_ROUTE_BGP) {
- if (json_paths)
- json_object_boolean_true_add(json_path,
- "sourced");
- else
- vty_out(vty, ", sourced");
+ /* Line 5 display Extended-community */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) {
+ if (json_paths) {
+ json_ext_community = json_object_new_object();
+ json_object_string_add(json_ext_community, "string",
+ attr->ecommunity->str);
+ json_object_object_add(json_path, "extendedCommunity",
+ json_ext_community);
} else {
- if (json_paths) {
- json_object_boolean_true_add(json_path,
- "sourced");
- json_object_boolean_true_add(json_path,
- "local");
- } else {
- vty_out(vty, ", sourced, local");
- }
+ vty_out(vty, " Extended Community: %s\n",
+ attr->ecommunity->str);
}
+ }
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
- if (json_paths)
- json_object_boolean_true_add(json_path,
- "atomicAggregate");
- else
- vty_out(vty, ", atomic-aggregate");
+ /* Line 6 display Large community */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
+ if (json_paths) {
+ if (!attr->lcommunity->json)
+ lcommunity_str(attr->lcommunity, true);
+ json_object_lock(attr->lcommunity->json);
+ json_object_object_add(json_path, "largeCommunity",
+ attr->lcommunity->json);
+ } else {
+ vty_out(vty, " Large Community: %s\n",
+ attr->lcommunity->str);
}
+ }
- if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH)
- || (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)
- && bgp_path_info_mpath_count(path))) {
+ /* Line 7 display Originator, Cluster-id */
+ if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+ || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) {
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) {
if (json_paths)
- json_object_boolean_true_add(json_path,
- "multipath");
+ json_object_string_add(
+ json_path, "originatorId",
+ inet_ntoa(attr->originator_id));
else
- vty_out(vty, ", multipath");
+ vty_out(vty, " Originator: %s",
+ inet_ntoa(attr->originator_id));
}
- // Mark the bestpath(s)
- if (CHECK_FLAG(path->flags, BGP_PATH_DMED_SELECTED)) {
- first_as = aspath_get_first_as(attr->aspath);
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) {
+ int i;
if (json_paths) {
- if (!json_bestpath)
- json_bestpath =
- json_object_new_object();
- json_object_int_add(json_bestpath,
- "bestpathFromAs", first_as);
- } else {
- if (first_as)
- vty_out(vty, ", bestpath-from-AS %u",
- first_as);
- else
- vty_out(vty,
- ", bestpath-from-AS Local");
- }
- }
+ json_cluster_list = json_object_new_object();
+ json_cluster_list_list =
+ json_object_new_array();
+
+ for (i = 0; i < attr->cluster->length / 4;
+ i++) {
+ json_string = json_object_new_string(
+ inet_ntoa(attr->cluster
+ ->list[i]));
+ json_object_array_add(
+ json_cluster_list_list,
+ json_string);
+ }
- if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) {
- if (json_paths) {
- if (!json_bestpath)
- json_bestpath =
- json_object_new_object();
- json_object_boolean_true_add(json_bestpath,
- "overall");
- json_object_string_add(json_bestpath,
- "selectionReason",
- bgp_path_selection_reason2str(bn->reason));
+ /*
+ * struct cluster_list does not have
+ * "str" variable like aspath and community
+ * do. Add this someday if someone asks
+ * for it.
+ * json_object_string_add(json_cluster_list,
+ * "string", attr->cluster->str);
+ */
+ json_object_object_add(json_cluster_list,
+ "list",
+ json_cluster_list_list);
+ json_object_object_add(json_path, "clusterList",
+ json_cluster_list);
} else {
- vty_out(vty, ", best");
- vty_out(vty, " (%s)",
- bgp_path_selection_reason2str(bn->reason));
+ vty_out(vty, ", Cluster list: ");
+
+ for (i = 0; i < attr->cluster->length / 4;
+ i++) {
+ vty_out(vty, "%s ",
+ inet_ntoa(attr->cluster
+ ->list[i]));
+ }
}
}
- if (json_bestpath)
- json_object_object_add(json_path, "bestpath",
- json_bestpath);
-
if (!json_paths)
vty_out(vty, "\n");
+ }
- /* Line 4 display Community */
- if (attr->community) {
- if (json_paths) {
- if (!attr->community->json)
- community_str(attr->community, true);
- json_object_lock(attr->community->json);
- json_object_object_add(json_path, "community",
- attr->community->json);
- } else {
- vty_out(vty, " Community: %s\n",
- attr->community->str);
- }
- }
-
- /* Line 5 display Extended-community */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) {
- if (json_paths) {
- json_ext_community = json_object_new_object();
- json_object_string_add(json_ext_community,
- "string",
- attr->ecommunity->str);
- json_object_object_add(json_path,
- "extendedCommunity",
- json_ext_community);
- } else {
- vty_out(vty, " Extended Community: %s\n",
- attr->ecommunity->str);
- }
- }
-
- /* Line 6 display Large community */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
- if (json_paths) {
- if (!attr->lcommunity->json)
- lcommunity_str(attr->lcommunity, true);
- json_object_lock(attr->lcommunity->json);
- json_object_object_add(json_path,
- "largeCommunity",
- attr->lcommunity->json);
- } else {
- vty_out(vty, " Large Community: %s\n",
- attr->lcommunity->str);
- }
- }
+ if (path->extra && path->extra->damp_info)
+ bgp_damp_info_vty(vty, path, json_path);
- /* Line 7 display Originator, Cluster-id */
- if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) {
- if (attr->flag
- & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) {
- if (json_paths)
- json_object_string_add(
- json_path, "originatorId",
- inet_ntoa(attr->originator_id));
- else
- vty_out(vty, " Originator: %s",
- inet_ntoa(attr->originator_id));
- }
+ /* Remote Label */
+ if (path->extra && bgp_is_valid_label(&path->extra->label[0])
+ && (safi != SAFI_EVPN && !is_route_parent_evpn(path))) {
+ mpls_label_t label = label_pton(&path->extra->label[0]);
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) {
- int i;
+ if (json_paths)
+ json_object_int_add(json_path, "remoteLabel", label);
+ else
+ vty_out(vty, " Remote label: %d\n", label);
+ }
- if (json_paths) {
- json_cluster_list =
- json_object_new_object();
- json_cluster_list_list =
- json_object_new_array();
+ /* Label Index */
+ if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
+ if (json_paths)
+ json_object_int_add(json_path, "labelIndex",
+ attr->label_index);
+ else
+ vty_out(vty, " Label Index: %d\n",
+ attr->label_index);
+ }
- for (i = 0;
- i < attr->cluster->length / 4;
- i++) {
- json_string = json_object_new_string(
- inet_ntoa(
- attr->cluster->list
- [i]));
- json_object_array_add(
- json_cluster_list_list,
- json_string);
- }
+ /* Line 8 display Addpath IDs */
+ if (path->addpath_rx_id
+ || bgp_addpath_info_has_ids(&path->tx_addpath)) {
+ if (json_paths) {
+ json_object_int_add(json_path, "addpathRxId",
+ path->addpath_rx_id);
- /* struct cluster_list does not have
- "str" variable like
- * aspath and community do. Add this
- someday if someone
- * asks for it.
- json_object_string_add(json_cluster_list,
- "string", attr->cluster->str);
- */
- json_object_object_add(
- json_cluster_list, "list",
- json_cluster_list_list);
- json_object_object_add(
- json_path, "clusterList",
- json_cluster_list);
- } else {
- vty_out(vty, ", Cluster list: ");
+ /* Keep backwards compatibility with the old API
+ * by putting TX All's ID in the old field
+ */
+ json_object_int_add(
+ json_path, "addpathTxId",
+ path->tx_addpath
+ .addpath_tx_id[BGP_ADDPATH_ALL]);
- for (i = 0;
- i < attr->cluster->length / 4;
- i++) {
- vty_out(vty, "%s ",
- inet_ntoa(
- attr->cluster->list
- [i]));
- }
- }
+ /* ... but create a specific field for each
+ * strategy
+ */
+ for (i = 0; i < BGP_ADDPATH_MAX; i++) {
+ json_object_int_add(
+ json_path,
+ bgp_addpath_names(i)->id_json_name,
+ path->tx_addpath.addpath_tx_id[i]);
}
+ } else {
+ vty_out(vty, " AddPath ID: RX %u, ",
+ path->addpath_rx_id);
- if (!json_paths)
- vty_out(vty, "\n");
- }
-
- if (path->extra && path->extra->damp_info)
- bgp_damp_info_vty(vty, path, json_path);
-
- /* Remote Label */
- if (path->extra && bgp_is_valid_label(&path->extra->label[0])
- && safi != SAFI_EVPN) {
- mpls_label_t label = label_pton(&path->extra->label[0]);
-
- if (json_paths)
- json_object_int_add(json_path, "remoteLabel",
- label);
- else
- vty_out(vty, " Remote label: %d\n", label);
- }
-
- /* Label Index */
- if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
- if (json_paths)
- json_object_int_add(json_path, "labelIndex",
- attr->label_index);
- else
- vty_out(vty, " Label Index: %d\n",
- attr->label_index);
+ route_vty_out_tx_ids(vty, &path->tx_addpath);
}
+ }
- /* Line 8 display Addpath IDs */
- if (path->addpath_rx_id
- || bgp_addpath_info_has_ids(&path->tx_addpath)) {
- if (json_paths) {
- json_object_int_add(json_path, "addpathRxId",
- path->addpath_rx_id);
-
- /* Keep backwards compatibility with the old API
- * by putting TX All's ID in the old field
- */
- json_object_int_add(
- json_path, "addpathTxId",
- path->tx_addpath.addpath_tx_id
- [BGP_ADDPATH_ALL]);
+ /* If we used addpath to TX a non-bestpath we need to display
+ * "Advertised to" on a path-by-path basis
+ */
+ if (bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
+ first = 1;
- /* ... but create a specific field for each
- * strategy
- */
- for (i = 0; i < BGP_ADDPATH_MAX; i++) {
- json_object_int_add(
- json_path,
- bgp_addpath_names(i)
- ->id_json_name,
- path->tx_addpath
- .addpath_tx_id[i]);
- }
- } else {
- vty_out(vty, " AddPath ID: RX %u, ",
- path->addpath_rx_id);
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ addpath_capable =
+ bgp_addpath_encode_tx(peer, afi, safi);
+ has_adj = bgp_adj_out_lookup(
+ peer, path->net,
+ bgp_addpath_id_for_peer(peer, afi, safi,
+ &path->tx_addpath));
+
+ if ((addpath_capable && has_adj)
+ || (!addpath_capable && has_adj
+ && CHECK_FLAG(path->flags,
+ BGP_PATH_SELECTED))) {
+ if (json_path && !json_adv_to)
+ json_adv_to = json_object_new_object();
- route_vty_out_tx_ids(vty, &path->tx_addpath);
+ route_vty_out_advertised_to(
+ vty, peer, &first,
+ " Advertised to:", json_adv_to);
}
}
- /* If we used addpath to TX a non-bestpath we need to display
- * "Advertised to" on a path-by-path basis
- */
- if (bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
- first = 1;
-
- for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- addpath_capable =
- bgp_addpath_encode_tx(peer, afi, safi);
- has_adj = bgp_adj_out_lookup(
- peer, path->net,
- bgp_addpath_id_for_peer(
- peer, afi, safi,
- &path->tx_addpath));
-
- if ((addpath_capable && has_adj)
- || (!addpath_capable && has_adj
- && CHECK_FLAG(path->flags,
- BGP_PATH_SELECTED))) {
- if (json_path && !json_adv_to)
- json_adv_to =
- json_object_new_object();
-
- route_vty_out_advertised_to(
- vty, peer, &first,
- " Advertised to:",
- json_adv_to);
- }
+ if (json_path) {
+ if (json_adv_to) {
+ json_object_object_add(
+ json_path, "advertisedTo", json_adv_to);
}
-
- if (json_path) {
- if (json_adv_to) {
- json_object_object_add(json_path,
- "advertisedTo",
- json_adv_to);
- }
- } else {
- if (!first) {
- vty_out(vty, "\n");
- }
+ } else {
+ if (!first) {
+ vty_out(vty, "\n");
}
}
+ }
- /* Line 9 display Uptime */
- tbuf = time(NULL) - (bgp_clock() - path->uptime);
- if (json_paths) {
- json_last_update = json_object_new_object();
- json_object_int_add(json_last_update, "epoch", tbuf);
- json_object_string_add(json_last_update, "string",
- ctime(&tbuf));
- json_object_object_add(json_path, "lastUpdate",
- json_last_update);
- } else
- vty_out(vty, " Last update: %s", ctime(&tbuf));
-
- /* Line 10 display PMSI tunnel attribute, if present */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
- const char *str = lookup_msg(bgp_pmsi_tnltype_str,
- attr->pmsi_tnl_type,
- PMSI_TNLTYPE_STR_DEFAULT);
+ /* Line 9 display Uptime */
+ tbuf = time(NULL) - (bgp_clock() - path->uptime);
+ if (json_paths) {
+ json_last_update = json_object_new_object();
+ json_object_int_add(json_last_update, "epoch", tbuf);
+ json_object_string_add(json_last_update, "string",
+ ctime(&tbuf));
+ json_object_object_add(json_path, "lastUpdate",
+ json_last_update);
+ } else
+ vty_out(vty, " Last update: %s", ctime(&tbuf));
- if (json_paths) {
- json_pmsi = json_object_new_object();
- json_object_string_add(json_pmsi,
- "tunnelType", str);
- json_object_int_add(json_pmsi,
- "label",
- label2vni(&attr->label));
- json_object_object_add(json_path, "pmsi",
- json_pmsi);
- } else
- vty_out(vty,
- " PMSI Tunnel Type: %s, label: %d\n",
- str, label2vni(&attr->label));
- }
+ /* Line 10 display PMSI tunnel attribute, if present */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
+ const char *str =
+ lookup_msg(bgp_pmsi_tnltype_str, attr->pmsi_tnl_type,
+ PMSI_TNLTYPE_STR_DEFAULT);
+ if (json_paths) {
+ json_pmsi = json_object_new_object();
+ json_object_string_add(json_pmsi, "tunnelType", str);
+ json_object_int_add(json_pmsi, "label",
+ label2vni(&attr->label));
+ json_object_object_add(json_path, "pmsi", json_pmsi);
+ } else
+ vty_out(vty, " PMSI Tunnel Type: %s, label: %d\n",
+ str, label2vni(&attr->label));
}
/* We've constructed the json object for this path, add it to the json
@@ -9085,8 +9024,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
json_object_object_add(json_path, "peer", json_peer);
json_object_array_add(json_paths, json_path);
- } else
- vty_out(vty, "\n");
+ }
}
#define BGP_SHOW_HEADER_CSV "Flags, Network, Next Hop, Metric, LocPrf, Weight, Path"
@@ -9603,37 +9541,47 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
if (has_valid_label)
label = label_pton(&rn->local_label);
- if (json) {
- if (has_valid_label)
- json_object_int_add(json, "localLabel", label);
+ if (safi == SAFI_EVPN) {
- json_object_string_add(
- json, "prefix",
- prefix2str(p, prefix_str, sizeof(prefix_str)));
- } else {
- if (safi == SAFI_EVPN)
+ if (!json) {
vty_out(vty, "BGP routing table entry for %s%s%s\n",
prd ? prefix_rd2str(prd, buf1, sizeof(buf1))
- : "",
- prd ? ":" : "",
+ : "", prd ? ":" : "",
bgp_evpn_route2str((struct prefix_evpn *)p,
- buf3, sizeof(buf3)));
- else
+ buf3, sizeof(buf3)));
+ } else {
+ json_object_string_add(json, "rd",
+ prd ? prefix_rd2str(prd, buf1, sizeof(buf1)) :
+ "");
+ bgp_evpn_route2json((struct prefix_evpn *)p, json);
+ }
+ } else {
+ if (!json) {
vty_out(vty, "BGP routing table entry for %s%s%s/%d\n",
((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
- ? prefix_rd2str(prd, buf1,
- sizeof(buf1))
- : ""),
+ ? prefix_rd2str(prd, buf1,
+ sizeof(buf1))
+ : ""),
safi == SAFI_MPLS_VPN ? ":" : "",
inet_ntop(p->family, &p->u.prefix, buf2,
- INET6_ADDRSTRLEN),
+ INET6_ADDRSTRLEN),
p->prefixlen);
- if (has_valid_label)
+ } else
+ json_object_string_add(json, "prefix",
+ prefix2str(p, prefix_str, sizeof(prefix_str)));
+ }
+
+ if (has_valid_label) {
+ if (json)
+ json_object_int_add(json, "localLabel", label);
+ else
vty_out(vty, "Local label: %d\n", label);
+ }
+
+ if (!json)
if (bgp_labeled_safi(safi) && safi != SAFI_EVPN)
vty_out(vty, "not allocated\n");
- }
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
count++;
@@ -9765,6 +9713,58 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
}
}
+static void bgp_show_path_info(struct prefix_rd *pfx_rd,
+ struct bgp_node *bgp_node, struct vty *vty,
+ struct bgp *bgp, afi_t afi,
+ safi_t safi, json_object *json,
+ enum bgp_path_type pathtype, int *display)
+{
+ struct bgp_path_info *pi;
+ int header = 1;
+ char rdbuf[RD_ADDRSTRLEN];
+ json_object *json_header = NULL;
+ json_object *json_paths = NULL;
+
+ for (pi = bgp_node_get_bgp_path_info(bgp_node); pi;
+ pi = pi->next) {
+
+ if (json && !json_paths) {
+ /* Instantiate json_paths only if path is valid */
+ json_paths = json_object_new_array();
+ if (pfx_rd) {
+ prefix_rd2str(pfx_rd, rdbuf, sizeof(rdbuf));
+ json_header = json_object_new_object();
+ } else
+ json_header = json;
+ }
+
+ if (header) {
+ route_vty_out_detail_header(
+ vty, bgp, bgp_node, pfx_rd,
+ AFI_IP, safi, json_header);
+ header = 0;
+ }
+ (*display)++;
+
+ if (pathtype == BGP_PATH_SHOW_ALL
+ || (pathtype == BGP_PATH_SHOW_BESTPATH
+ && CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
+ || (pathtype == BGP_PATH_SHOW_MULTIPATH
+ && (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH)
+ || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))))
+ route_vty_out_detail(vty, bgp, bgp_node,
+ pi, AFI_IP, safi,
+ json_paths);
+ }
+
+ if (json && json_paths) {
+ json_object_object_add(json_header, "paths", json_paths);
+
+ if (pfx_rd)
+ json_object_object_add(json, rdbuf, json_header);
+ }
+}
+
/* Display specified route of BGP table. */
static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
struct bgp_table *rib, const char *ip_str,
@@ -9773,12 +9773,10 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
enum bgp_path_type pathtype, bool use_json)
{
int ret;
- int header;
int display = 0;
struct prefix match;
struct bgp_node *rn;
struct bgp_node *rm;
- struct bgp_path_info *pi;
struct bgp_table *table;
json_object *json = NULL;
json_object *json_paths = NULL;
@@ -9792,12 +9790,10 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
match.family = afi2family(afi);
- if (use_json) {
+ if (use_json)
json = json_object_new_object();
- json_paths = json_object_new_array();
- }
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) {
+ 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)
continue;
@@ -9805,8 +9801,6 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
if (!table)
continue;
- header = 1;
-
if ((rm = bgp_node_match(table, &match)) == NULL)
continue;
@@ -9816,73 +9810,83 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
continue;
}
- for (pi = bgp_node_get_bgp_path_info(rm); pi;
- pi = pi->next) {
- if (header) {
- route_vty_out_detail_header(
- vty, bgp, rm,
- (struct prefix_rd *)&rn->p,
- AFI_IP, safi, json);
- header = 0;
+ bgp_show_path_info((struct prefix_rd *)&rn->p, rm,
+ vty, bgp, afi, safi, json,
+ pathtype, &display);
+
+ bgp_unlock_node(rm);
+ }
+ } else if (safi == SAFI_EVPN) {
+ struct bgp_node *longest_pfx;
+ 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)
+ continue;
+ table = bgp_node_get_bgp_table_info(rn);
+ if (!table)
+ continue;
+
+ longest_pfx = NULL;
+ is_exact_pfxlen_match = FALSE;
+ /*
+ * Search through all the prefixes for a match. The
+ * pfx's are enumerated in ascending order of pfxlens.
+ * So, the last pfx match is the longest match. Set
+ * is_exact_pfxlen_match when we get exact pfxlen match
+ */
+ for (rm = bgp_table_top(table); rm;
+ rm = bgp_route_next(rm)) {
+ /*
+ * Get prefixlen of the ip-prefix within type5
+ * evpn route
+ */
+ if (evpn_type5_prefix_match(&rm->p,
+ &match) && rm->info) {
+ longest_pfx = rm;
+ int type5_pfxlen =
+ bgp_evpn_get_type5_prefixlen(&rm->p);
+ if (type5_pfxlen == match.prefixlen) {
+ is_exact_pfxlen_match = TRUE;
+ bgp_unlock_node(rm);
+ break;
+ }
}
- display++;
-
- if (pathtype == BGP_PATH_SHOW_ALL
- || (pathtype == BGP_PATH_SHOW_BESTPATH
- && CHECK_FLAG(pi->flags,
- BGP_PATH_SELECTED))
- || (pathtype == BGP_PATH_SHOW_MULTIPATH
- && (CHECK_FLAG(pi->flags,
- BGP_PATH_MULTIPATH)
- || CHECK_FLAG(pi->flags,
- BGP_PATH_SELECTED))))
- route_vty_out_detail(vty, bgp, rm,
- pi, AFI_IP, safi,
- json_paths);
}
+ if (!longest_pfx)
+ continue;
+
+ if (prefix_check && !is_exact_pfxlen_match)
+ continue;
+
+ 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_unlock_node(rm);
}
} else if (safi == SAFI_FLOWSPEC) {
+ if (use_json)
+ json_paths = json_object_new_array();
+
display = bgp_flowspec_display_match_per_ip(afi, rib,
&match, prefix_check,
vty,
use_json,
json_paths);
+ if (use_json && display)
+ json_object_object_add(json, "paths", json_paths);
} else {
- header = 1;
-
if ((rn = bgp_node_match(rib, &match)) != NULL) {
if (!prefix_check
|| rn->p.prefixlen == match.prefixlen) {
- for (pi = bgp_node_get_bgp_path_info(rn); pi;
- pi = pi->next) {
- if (header) {
- route_vty_out_detail_header(
- vty, bgp, rn, NULL, afi,
- safi, json);
- header = 0;
- }
- display++;
-
- if (pathtype == BGP_PATH_SHOW_ALL
- || (pathtype
- == BGP_PATH_SHOW_BESTPATH
- && CHECK_FLAG(
- pi->flags,
- BGP_PATH_SELECTED))
- || (pathtype
- == BGP_PATH_SHOW_MULTIPATH
- && (CHECK_FLAG(
- pi->flags,
- BGP_PATH_MULTIPATH)
- || CHECK_FLAG(
- pi->flags,
- BGP_PATH_SELECTED))))
- route_vty_out_detail(
- vty, bgp, rn, pi,
- afi, safi, json_paths);
- }
+ bgp_show_path_info(NULL, rn, vty, bgp, afi,
+ safi, json,
+ pathtype, &display);
}
bgp_unlock_node(rn);
@@ -9890,11 +9894,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
}
if (use_json) {
- if (display)
- json_object_object_add(json, "paths", json_paths);
-
vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
+ json, JSON_C_TO_STRING_PRETTY |
+ JSON_C_TO_STRING_NOSLASHESCAPE));
json_object_free(json);
} else {
if (!display) {
@@ -10647,13 +10649,12 @@ static void bgp_table_stats_rn(struct bgp_node *rn, struct bgp_node *top,
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
ts->counts[BGP_STATS_RIB]++;
- if (pi->attr
- && (CHECK_FLAG(pi->attr->flag,
- ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))))
+ if (CHECK_FLAG(pi->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)))
ts->counts[BGP_STATS_AGGREGATES]++;
/* as-path stats */
- if (pi->attr && pi->attr->aspath) {
+ if (pi->attr->aspath) {
unsigned int hops = aspath_count_hops(pi->attr->aspath);
unsigned int size = aspath_size(pi->attr->aspath);
as_t highest = aspath_highest(pi->attr->aspath);
@@ -10970,7 +10971,7 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi,
get_afi_safi_str(afi, safi, false));
}
- vty_out(vty, "PfxCt: %ld\n", peer->pcount[afi][safi]);
+ vty_out(vty, "PfxCt: %" PRIu32 "\n", peer->pcount[afi][safi]);
vty_out(vty, "\nCounts from RIB table walk:\n\n");
for (i = 0; i < PCOUNT_MAX; i++)
@@ -11088,32 +11089,37 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix,
}
#endif /* KEEP_OLD_VPN_COMMANDS */
-DEFUN (show_ip_bgp_l2vpn_evpn_all_route_prefix,
- show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd,
- "show [ip] bgp l2vpn evpn all <A.B.C.D|A.B.C.D/M> [json]",
+DEFUN (show_bgp_l2vpn_evpn_route_prefix,
+ show_bgp_l2vpn_evpn_route_prefix_cmd,
+ "show bgp l2vpn evpn <A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [json]",
SHOW_STR
- IP_STR
BGP_STR
L2VPN_HELP_STR
EVPN_HELP_STR
- "Display information about all EVPN NLRIs\n"
+ "Network in the BGP routing table to display\n"
+ "Network in the BGP routing table to display\n"
"Network in the BGP routing table to display\n"
"Network in the BGP routing table to display\n"
JSON_STR)
{
int idx = 0;
char *network = NULL;
+ int prefix_check = 0;
- if (argv_find(argv, argc, "A.B.C.D", &idx))
+ if (argv_find(argv, argc, "A.B.C.D", &idx) ||
+ argv_find(argv, argc, "X:X::X:X", &idx))
network = argv[idx]->arg;
- else if (argv_find(argv, argc, "A.B.C.D/M", &idx))
+ else if (argv_find(argv, argc, "A.B.C.D/M", &idx) ||
+ argv_find(argv, argc, "A.B.C.D/M", &idx)) {
network = argv[idx]->arg;
- else {
+ prefix_check = 1;
+ } else {
vty_out(vty, "Unable to figure out Network\n");
return CMD_WARNING;
}
- return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, 0,
- BGP_PATH_SHOW_ALL, use_json(argc, argv));
+ return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL,
+ prefix_check, BGP_PATH_SHOW_ALL,
+ use_json(argc, argv));
}
static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
@@ -11224,7 +11230,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
if (type == bgp_show_adj_route_received
|| type == bgp_show_adj_route_filtered) {
for (ain = rn->adj_in; ain; ain = ain->next) {
- if (ain->peer != peer || !ain->attr)
+ if (ain->peer != peer)
continue;
if (header1) {
@@ -12610,7 +12616,7 @@ void bgp_route_init(void)
#endif /* KEEP_OLD_VPN_COMMANDS */
install_element(VIEW_NODE, &show_bgp_afi_vpn_rd_route_cmd);
install_element(VIEW_NODE,
- &show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd);
+ &show_bgp_l2vpn_evpn_route_prefix_cmd);
/* BGP dampening clear commands */
install_element(ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index a5286cea6..d0cea547e 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -114,6 +114,7 @@ o Cisco route-map
origin : Done
tag : Done
weight : Done
+ table : Done
o Local extensions
@@ -699,7 +700,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
if (type == RMAP_BGP && prefix->family == AF_INET) {
path = (struct bgp_path_info *)object;
- if (!path || !path->attr)
+ if (!path)
return RMAP_NOMATCH;
/* If nexthop interface's index can't be resolved and nexthop is
@@ -867,8 +868,7 @@ route_match_vni(void *rule, const struct prefix *prefix,
* For any other tunnel type, return noop to ignore
* this check.
*/
- if (path->attr && path->attr->encap_tunneltype !=
- BGP_ENCAP_TYPE_VXLAN)
+ if (path->attr->encap_tunneltype != BGP_ENCAP_TYPE_VXLAN)
return RMAP_NOOP;
/*
@@ -1469,7 +1469,7 @@ route_match_interface(void *rule, const struct prefix *prefix,
if (type == RMAP_BGP) {
path = object;
- if (!path || !path->attr)
+ if (!path)
return RMAP_NOMATCH;
ifp = if_lookup_by_name_all_vrf((char *)rule);
@@ -1754,6 +1754,32 @@ struct route_map_rule_cmd route_set_metric_cmd = {
"metric", route_set_metric, route_value_compile, route_value_free,
};
+/* `set table (1-4294967295)' */
+
+static enum route_map_cmd_result_t route_set_table_id(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
+{
+ struct rmap_value *rv;
+ struct bgp_path_info *path;
+
+ if (type == RMAP_BGP) {
+ /* Fetch routemap's rule information. */
+ rv = rule;
+ path = object;
+
+ path->attr->rmap_table_id = rv->value;
+ }
+ return RMAP_OKAY;
+}
+
+/* Set table_id rule structure. */
+static struct route_map_rule_cmd route_set_table_id_cmd = {
+ "table", route_set_table_id,
+ route_value_compile, route_value_free
+};
+
/* `set as-path prepend ASPATH' */
/* For AS path prepend mechanism. */
@@ -2663,7 +2689,7 @@ route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
if (type == RMAP_BGP && prefix->family == AF_INET6) {
path = (struct bgp_path_info *)object;
- if (!path || !path->attr)
+ if (!path)
return RMAP_NOMATCH;
if (IPV6_ADDR_SAME(&path->attr->mp_nexthop_global, addr)
@@ -4058,6 +4084,32 @@ DEFUN (no_match_origin,
RMAP_EVENT_MATCH_DELETED);
}
+DEFUN (set_table_id,
+ set_table_id_cmd,
+ "set table (1-4294967295)",
+ SET_STR
+ "export route to non-main kernel table\n"
+ "Kernel routing table id\n")
+{
+ int idx_id = 2;
+
+ VTY_DECLVAR_CONTEXT(route_map_index, index);
+
+ return generic_set_add(vty, index, "table", argv[idx_id]->arg);
+}
+
+DEFUN (no_set_table_id,
+ no_set_table_id_cmd,
+ "no set table",
+ NO_STR
+ SET_STR
+ "export route to non-main kernel table\n")
+{
+ VTY_DECLVAR_CONTEXT(route_map_index, index);
+
+ return generic_set_delete(vty, index, "table", NULL);
+}
+
DEFUN (set_ip_nexthop_peer,
set_ip_nexthop_peer_cmd,
"[no] set ip next-hop peer-address",
@@ -5167,6 +5219,7 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_evpn_default_route_cmd);
route_map_install_match(&route_match_vrl_source_vrf_cmd);
+ route_map_install_set(&route_set_table_id_cmd);
route_map_install_set(&route_set_ip_nexthop_cmd);
route_map_install_set(&route_set_local_pref_cmd);
route_map_install_set(&route_set_weight_cmd);
@@ -5223,6 +5276,8 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &match_probability_cmd);
install_element(RMAP_NODE, &no_match_probability_cmd);
+ install_element(RMAP_NODE, &no_set_table_id_cmd);
+ install_element(RMAP_NODE, &set_table_id_cmd);
install_element(RMAP_NODE, &set_ip_nexthop_peer_cmd);
install_element(RMAP_NODE, &set_ip_nexthop_unchanged_cmd);
install_element(RMAP_NODE, &set_local_pref_cmd);
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 352e3b87e..1267e3509 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -1234,7 +1234,8 @@ DEFPY (show_rpki_prefix,
const struct pfx_record *record = &matches[i];
if (record->max_len >= prefix->prefixlen
- && ((asn != 0 && asn == record->asn) || asn == 0)) {
+ && ((asn != 0 && (uint32_t)asn == record->asn)
+ || asn == 0)) {
print_record(&matches[i], vty);
}
}
diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c
index c26644089..f31f8cd31 100644
--- a/bgpd/bgp_snmp.c
+++ b/bgpd/bgp_snmp.c
@@ -46,7 +46,7 @@
/* BGP TRAP. */
#define BGPESTABLISHED 1
-#define BGPBACKWARDTRANSITION 2
+#define BGPBACKWARDTRANSITION 2
/* BGP MIB bgpVersion. */
#define BGPVERSION 0
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index de7b05bdd..4b6af935e 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -570,8 +570,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime));
filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi];
if (filter->map[RMAP_OUT].name)
- vty_out(vty, " Outgoing route map: %s%s\n",
- filter->map[RMAP_OUT].map ? "X" : "",
+ vty_out(vty, " Outgoing route map: %s\n",
filter->map[RMAP_OUT].name);
vty_out(vty, " MRAI value (seconds): %d\n", updgrp->conf->v_routeadv);
if (updgrp->conf->change_local_as)
@@ -613,6 +612,9 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
subgrp->peer_refreshes_combined);
vty_out(vty, " Merge checks triggered: %u\n",
subgrp->merge_checks_triggered);
+ vty_out(vty, " Coalesce Time: %u%s\n",
+ (UPDGRP_INST(subgrp->update_group))->coalesce_time,
+ subgrp->t_coalesce ? "(Running)" : "");
vty_out(vty, " Version: %" PRIu64 "\n", subgrp->version);
vty_out(vty, " Packet queue length: %d\n",
bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 21f1dff60..5c1483a76 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -324,8 +324,9 @@ static int subgroup_coalesce_timer(struct thread *thread)
subgrp = THREAD_ARG(thread);
if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
zlog_debug("u%" PRIu64 ":s%" PRIu64
- " announcing routes upon coalesce timer expiry",
- (SUBGRP_UPDGRP(subgrp))->id, subgrp->id);
+ " announcing routes upon coalesce timer expiry(%u ms)",
+ (SUBGRP_UPDGRP(subgrp))->id, subgrp->id,
+ subgrp->v_coalesce),
subgrp->t_coalesce = NULL;
subgrp->v_coalesce = 0;
subgroup_announce_route(subgrp);
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 688abae0e..9329c8d89 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -391,6 +391,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
struct peer *peer;
char buf[BUFSIZ];
char buf2[BUFSIZ];
+ struct bgp_filter *filter;
s = stream_dup(pkt->buffer);
peer = PAF_PEER(paf);
@@ -401,6 +402,8 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
afi_t nhafi;
int route_map_sets_nh;
nhlen = stream_getc_from(s, vec->offset);
+ filter = &peer->filter[paf->afi][paf->safi];
+
if (peer_cap_enhe(peer, paf->afi, paf->safi))
nhafi = AFI_IP6;
else
@@ -439,25 +442,25 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
mod_v4nh = &v4nh;
/*
- * If route-map has set the nexthop, that is always
- * used; if it is
- * specified as peer-address, the peering address is
- * picked up.
- * Otherwise, if NH is unavailable from attribute, the
- * peering addr
- * is picked up; the "NH unavailable" case also covers
- * next-hop-self
- * and some other scenarios -- see
- * subgroup_announce_check(). In
- * all other cases, use the nexthop carried in the
- * attribute unless
- * it is EBGP non-multiaccess and there is no
- * next-hop-unchanged setting.
+ * If route-map has set the nexthop, that is normally
+ * used; if it is specified as peer-address, the peering
+ * address is picked up. Otherwise, if NH is unavailable
+ * from attribute, the peering addr is picked up; the
+ * "NH unavailable" case also covers next-hop-self and
+ * some other scenarios - see subgroup_announce_check().
+ * In all other cases, use the nexthop carried in the
+ * attribute unless it is EBGP non-multiaccess and there
+ * is no next-hop-unchanged setting or the peer is EBGP
+ * and the route-map that changed the next-hop value
+ * was applied inbound rather than outbound. Updates to
+ * an EBGP peer should only modify the next-hop if it
+ * was set in an outbound route-map to that peer.
* Note: It is assumed route-map cannot set the nexthop
- * to an
- * invalid value.
+ * to an invalid value.
*/
- if (route_map_sets_nh) {
+ if (route_map_sets_nh
+ && ((peer->sort != BGP_PEER_EBGP)
+ || ROUTE_MAP_OUT(filter))) {
if (CHECK_FLAG(
vec->flags,
BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) {
@@ -543,7 +546,15 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
stream_get_from(&v6nhglobal, s, offset_nhglobal,
IPV6_MAX_BYTELEN);
- if (route_map_sets_nh) {
+
+ /*
+ * Updates to an EBGP peer should only modify the
+ * next-hop if it was set in an outbound route-map
+ * to that peer.
+ */
+ if (route_map_sets_nh
+ && ((peer->sort != BGP_PEER_EBGP)
+ || ROUTE_MAP_OUT(filter))) {
if (CHECK_FLAG(
vec->flags,
BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) {
diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c
index 09b1cb429..e48eda723 100644
--- a/bgpd/bgp_vpn.c
+++ b/bgpd/bgp_vpn.c
@@ -29,6 +29,7 @@
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_vpn.h"
+#include "bgpd/bgp_updgrp.h"
int show_adj_route_vpn(struct vty *vty, struct peer *peer,
struct prefix_rd *prd, afi_t afi, safi_t safi,
@@ -38,14 +39,15 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
struct bgp_table *table;
struct bgp_node *rn;
struct bgp_node *rm;
- struct bgp_path_info *path;
int rd_header;
int header = 1;
json_object *json = NULL;
json_object *json_scode = NULL;
json_object *json_ocode = NULL;
+ json_object *json_adv = NULL;
json_object *json_routes = NULL;
- json_object *json_array = NULL;
+ char rd_str[BUFSIZ];
+ unsigned long output_count = 0;
bgp = bgp_get_default();
if (bgp == NULL) {
@@ -59,8 +61,8 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
if (use_json) {
json_scode = json_object_new_object();
json_ocode = json_object_new_object();
- json_routes = json_object_new_object();
json = json_object_new_object();
+ json_adv = json_object_new_object();
json_object_string_add(json_scode, "suppressed", "s");
json_object_string_add(json_scode, "damped", "d");
@@ -83,16 +85,25 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
if (table == NULL)
continue;
- if (use_json)
- json_array = json_object_new_array();
- else
- json_array = NULL;
rd_header = 1;
+ memset(rd_str, 0, sizeof(rd_str));
for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) {
- path = bgp_node_get_bgp_path_info(rm);
- if (path == NULL)
+ struct bgp_adj_out *adj = NULL;
+ struct attr *attr = NULL;
+ struct peer_af *paf = NULL;
+
+ RB_FOREACH (adj, bgp_adj_out_rb, &rm->adj_out)
+ SUBGRP_FOREACH_PEER (adj->subgroup, paf) {
+ if (paf->peer != peer || !adj->attr)
+ continue;
+
+ attr = adj->attr;
+ break;
+ }
+
+ if (bgp_node_get_bgp_path_info(rm) == NULL)
continue;
if (header) {
@@ -102,6 +113,13 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
json_object_string_add(
json, "bgpLocalRouterId",
inet_ntoa(bgp->router_id));
+ json_object_int_add(
+ json,
+ "defaultLocPrf",
+ bgp->default_local_pref);
+ json_object_int_add(
+ json, "localAS",
+ bgp->as);
json_object_object_add(json,
"bgpStatusCodes",
json_scode);
@@ -112,6 +130,9 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
vty_out(vty,
"BGP table version is 0, local router ID is %s\n",
inet_ntoa(bgp->router_id));
+ vty_out(vty, "Default local pref %u, ",
+ bgp->default_local_pref);
+ vty_out(vty, "local AS %u\n", bgp->as);
vty_out(vty,
"Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n");
vty_out(vty,
@@ -146,18 +167,19 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
decode_rd_vnc_eth(pnt, &rd_vnc_eth);
#endif
if (use_json) {
- char buffer[BUFSIZ];
+ json_routes = json_object_new_object();
+
if (type == RD_TYPE_AS
|| type == RD_TYPE_AS4)
- sprintf(buffer, "%u:%d",
+ sprintf(rd_str, "%u:%d",
rd_as.as, rd_as.val);
else if (type == RD_TYPE_IP)
- sprintf(buffer, "%s:%d",
+ sprintf(rd_str, "%s:%d",
inet_ntoa(rd_ip.ip),
rd_ip.val);
json_object_string_add(
json_routes,
- "routeDistinguisher", buffer);
+ "rd", rd_str);
} else {
vty_out(vty, "Route Distinguisher: ");
@@ -192,24 +214,25 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
}
rd_header = 0;
}
- if (use_json) {
- char buf[BUFSIZ];
-
- prefix2str(&rm->p, buf, sizeof(buf));
- json_object_object_add(json_routes, buf,
- json_array);
- } else {
- route_vty_out_tmp(vty, &rm->p, path->attr,
- safi, use_json,
- json_array);
- }
+ route_vty_out_tmp(vty, &rm->p, attr,
+ safi, use_json,
+ json_routes);
+ output_count++;
}
+
+ if (use_json)
+ json_object_object_add(json_adv, rd_str, json_routes);
}
+
if (use_json) {
- json_object_object_add(json, "routes", json_routes);
+ json_object_object_add(json, "advertisedRoutes", json_adv);
+ json_object_int_add(json,
+ "totalPrefixCounter", output_count);
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
- }
+ } else
+ vty_out(vty, "\nTotal number of prefixes %ld\n", output_count);
+
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 17bc83ed2..9e81831ac 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -159,10 +159,8 @@ static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi)
return "IPv6 Flowspec";
else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
return "L2VPN EVPN";
- else {
- flog_err(EC_LIB_DEVELOPMENT, "New afi/safi that needs to be taken care of?");
+ else
return "Unknown";
- }
}
/*
@@ -199,10 +197,8 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
return "ipv6Flowspec";
else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
return "l2VpnEvpn";
- else {
- flog_err(EC_LIB_DEVELOPMENT, "New afi/safi that needs to be taken care of?");
+ else
return "Unknown";
- }
}
/* Utility function to get address family from current node. */
@@ -1586,36 +1582,24 @@ DEFUN (no_bgp_update_delay,
}
-static int bgp_wpkt_quanta_config_vty(struct vty *vty, const char *num,
- char set)
+static int bgp_wpkt_quanta_config_vty(struct vty *vty, uint32_t quanta,
+ bool set)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (set) {
- uint32_t quanta = strtoul(num, NULL, 10);
- atomic_store_explicit(&bgp->wpkt_quanta, quanta,
- memory_order_relaxed);
- } else {
- atomic_store_explicit(&bgp->wpkt_quanta, BGP_WRITE_PACKET_MAX,
- memory_order_relaxed);
- }
+ quanta = set ? quanta : BGP_WRITE_PACKET_MAX;
+ atomic_store_explicit(&bgp->wpkt_quanta, quanta, memory_order_relaxed);
return CMD_SUCCESS;
}
-static int bgp_rpkt_quanta_config_vty(struct vty *vty, const char *num,
- char set)
+static int bgp_rpkt_quanta_config_vty(struct vty *vty, uint32_t quanta,
+ bool set)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- if (set) {
- uint32_t quanta = strtoul(num, NULL, 10);
- atomic_store_explicit(&bgp->rpkt_quanta, quanta,
- memory_order_relaxed);
- } else {
- atomic_store_explicit(&bgp->rpkt_quanta, BGP_READ_PACKET_MAX,
- memory_order_relaxed);
- }
+ quanta = set ? quanta : BGP_READ_PACKET_MAX;
+ atomic_store_explicit(&bgp->rpkt_quanta, quanta, memory_order_relaxed);
return CMD_SUCCESS;
}
@@ -1636,47 +1620,32 @@ void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp)
vty_out(vty, " read-quanta %d\n", quanta);
}
-/* Packet quanta configuration */
-DEFUN (bgp_wpkt_quanta,
+/* Packet quanta configuration
+ *
+ * XXX: The value set here controls the size of a stack buffer in the IO
+ * thread. When changing these limits be careful to prevent stack overflow.
+ *
+ * Furthermore, the maximums used here should correspond to
+ * BGP_WRITE_PACKET_MAX and BGP_READ_PACKET_MAX.
+ */
+DEFPY (bgp_wpkt_quanta,
bgp_wpkt_quanta_cmd,
- "write-quanta (1-10)",
- "How many packets to write to peer socket per run\n"
- "Number of packets\n")
-{
- int idx_number = 1;
- return bgp_wpkt_quanta_config_vty(vty, argv[idx_number]->arg, 1);
-}
-
-DEFUN (no_bgp_wpkt_quanta,
- no_bgp_wpkt_quanta_cmd,
- "no write-quanta (1-10)",
+ "[no] write-quanta (1-64)$quanta",
NO_STR
- "How many packets to write to peer socket per I/O cycle\n"
+ "How many packets to write to peer socket per run\n"
"Number of packets\n")
{
- int idx_number = 2;
- return bgp_wpkt_quanta_config_vty(vty, argv[idx_number]->arg, 0);
+ return bgp_wpkt_quanta_config_vty(vty, quanta, !no);
}
-DEFUN (bgp_rpkt_quanta,
+DEFPY (bgp_rpkt_quanta,
bgp_rpkt_quanta_cmd,
- "read-quanta (1-10)",
- "How many packets to read from peer socket per I/O cycle\n"
- "Number of packets\n")
-{
- int idx_number = 1;
- return bgp_rpkt_quanta_config_vty(vty, argv[idx_number]->arg, 1);
-}
-
-DEFUN (no_bgp_rpkt_quanta,
- no_bgp_rpkt_quanta_cmd,
- "no read-quanta (1-10)",
+ "[no] read-quanta (1-10)$quanta",
NO_STR
"How many packets to read from peer socket per I/O cycle\n"
"Number of packets\n")
{
- int idx_number = 2;
- return bgp_rpkt_quanta_config_vty(vty, argv[idx_number]->arg, 0);
+ return bgp_rpkt_quanta_config_vty(vty, quanta, !no);
}
void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp)
@@ -7918,7 +7887,7 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
msg_str);
}
- }
+ }
json_object_string_add(json_peer, "lastResetDueTo",
peer_down_str[(int)peer->last_reset]);
json_object_int_add(json_peer, "lastResetCode",
@@ -8003,7 +7972,7 @@ static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp,
false);
}
}
-
+
/* Show BGP peer's summary information. */
static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
@@ -8049,7 +8018,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
if (peer_dynamic_neighbor(peer))
dn_count++;
}
-
+
} else {
/* Loop over all neighbors that will be displayed to determine
* how many
@@ -8078,7 +8047,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
if (len > max_neighbor_width)
max_neighbor_width = len;
-
+
/* See if we have at least a single failed peer */
if (bgp_has_peer_failed(peer, afi, safi))
failed_count++;
@@ -8097,7 +8066,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
if (use_json) {
json_object_int_add(json, "failedPeersCount", 0);
json_object_int_add(json, "dynamicPeers", dn_count);
- json_object_int_add(json, "totalPeers", count);
+ json_object_int_add(json, "totalPeers", count);
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
@@ -8108,7 +8077,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
}
return CMD_SUCCESS;
}
-
+
count = 0; /* Reset the value as its used again */
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
@@ -8447,9 +8416,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
if (peer->status == Established)
if (peer->afc_recv[afi][safi])
- vty_out(vty, " %12ld",
- peer->pcount[afi]
- [pfx_rcd_safi]);
+ vty_out(vty, " %12" PRIu32,
+ peer->pcount
+ [afi]
+ [pfx_rcd_safi]);
else
vty_out(vty, " NoNeg");
else {
@@ -9345,11 +9315,13 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
filter->usmap.name);
/* Receive prefix count */
- vty_out(vty, " %ld accepted prefixes\n", p->pcount[afi][safi]);
+ vty_out(vty, " %" PRIu32 " accepted prefixes\n",
+ p->pcount[afi][safi]);
/* Maximum prefix */
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) {
- vty_out(vty, " Maximum prefixes allowed %ld%s\n",
+ vty_out(vty,
+ " Maximum prefixes allowed %" PRIu32 "%s\n",
p->pmax[afi][safi],
CHECK_FLAG(p->af_flags[afi][safi],
PEER_FLAG_MAX_PREFIX_WARNING)
@@ -13069,9 +13041,7 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_update_delay_establish_wait_cmd);
install_element(BGP_NODE, &bgp_wpkt_quanta_cmd);
- install_element(BGP_NODE, &no_bgp_wpkt_quanta_cmd);
install_element(BGP_NODE, &bgp_rpkt_quanta_cmd);
- install_element(BGP_NODE, &no_bgp_rpkt_quanta_cmd);
install_element(BGP_NODE, &bgp_coalesce_time_cmd);
install_element(BGP_NODE, &no_bgp_coalesce_time_cmd);
@@ -14279,16 +14249,8 @@ DEFUN (community_list_standard,
char *cl_name_or_number = NULL;
int direct = 0;
int style = COMMUNITY_LIST_STANDARD;
-
int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'bgp community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> AA:NN'\n");
- zlog_warn("Deprecated option: 'ip community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> AA:NN' being used");
- }
-
argv_find(argv, argc, "(1-99)", &idx);
argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg;
@@ -14311,21 +14273,6 @@ DEFUN (community_list_standard,
return CMD_SUCCESS;
}
-#if CONFDATE > 20191005
-CPP_NOTICE("bgpd: remove deprecated 'ip community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> AA:NN' command")
-#endif
-ALIAS (community_list_standard,
- ip_community_list_standard_cmd,
- "ip community-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
- IP_STR
- COMMUNITY_LIST_STR
- "Community list number (standard)\n"
- "Add an standard community-list entry\n"
- "Community list name\n"
- "Specify community to reject\n"
- "Specify community to accept\n"
- COMMUNITY_VAL_STR)
-
DEFUN (no_community_list_standard_all,
no_bgp_community_list_standard_all_cmd,
"no bgp community-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
@@ -14346,13 +14293,6 @@ DEFUN (no_community_list_standard_all,
int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'no bgp community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> AA:NN'\n");
- zlog_warn("Deprecated option: 'no ip community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> |AA:NN' being used");
- }
-
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
@@ -14383,18 +14323,6 @@ DEFUN (no_community_list_standard_all,
return CMD_SUCCESS;
}
-ALIAS (no_community_list_standard_all,
- no_ip_community_list_standard_all_cmd,
- "no ip community-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
- NO_STR
- IP_STR
- COMMUNITY_LIST_STR
- "Community list number (standard)\n"
- "Add an standard community-list entry\n"
- "Community list name\n"
- "Specify community to reject\n"
- "Specify community to accept\n"
- COMMUNITY_VAL_STR)
ALIAS(no_community_list_standard_all, no_bgp_community_list_standard_all_list_cmd,
"no bgp community-list <(1-99)|standard WORD>",
@@ -14403,13 +14331,6 @@ ALIAS(no_community_list_standard_all, no_bgp_community_list_standard_all_list_cm
"Add an standard community-list entry\n"
"Community list name\n")
-ALIAS(no_community_list_standard_all, no_ip_community_list_standard_all_list_cmd,
- "no ip community-list <(1-99)|standard WORD>",
- NO_STR BGP_STR COMMUNITY_LIST_STR
- "Community list number (standard)\n"
- "Add an standard community-list entry\n"
- "Community list name\n")
-
/*community-list expanded */
DEFUN (community_list_expanded_all,
bgp_community_list_expanded_all_cmd,
@@ -14428,12 +14349,7 @@ DEFUN (community_list_expanded_all,
int style = COMMUNITY_LIST_EXPANDED;
int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'bgp community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> AA:NN'\n");
- zlog_warn("Deprecated option: 'ip community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> AA:NN' being used");
- }
+
argv_find(argv, argc, "(100-500)", &idx);
argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg;
@@ -14456,18 +14372,6 @@ DEFUN (community_list_expanded_all,
return CMD_SUCCESS;
}
-ALIAS (community_list_expanded_all,
- ip_community_list_expanded_all_cmd,
- "ip community-list <(100-500)|expanded WORD> <deny|permit> AA:NN...",
- IP_STR
- COMMUNITY_LIST_STR
- "Community list number (expanded)\n"
- "Add an expanded community-list entry\n"
- "Community list name\n"
- "Specify community to reject\n"
- "Specify community to accept\n"
- COMMUNITY_VAL_STR)
-
DEFUN (no_community_list_expanded_all,
no_bgp_community_list_expanded_all_cmd,
"no bgp community-list <(100-500)|expanded WORD> <deny|permit> AA:NN...",
@@ -14487,14 +14391,7 @@ DEFUN (no_community_list_expanded_all,
int style = COMMUNITY_LIST_EXPANDED;
int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'no bgp community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> AA:NN'\n");
- zlog_warn("Deprecated option: 'no ip community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> AA:NN' being used");
- }
- idx = 0;
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
@@ -14526,19 +14423,6 @@ DEFUN (no_community_list_expanded_all,
return CMD_SUCCESS;
}
-ALIAS (no_community_list_expanded_all,
- no_ip_community_list_expanded_all_cmd,
- "no ip community-list <(100-500)|expanded WORD> <deny|permit> AA:NN...",
- NO_STR
- IP_STR
- COMMUNITY_LIST_STR
- "Community list number (expanded)\n"
- "Add an expanded community-list entry\n"
- "Community list name\n"
- "Specify community to reject\n"
- "Specify community to accept\n"
- COMMUNITY_VAL_STR)
-
ALIAS(no_community_list_expanded_all, no_bgp_community_list_expanded_all_list_cmd,
"no bgp community-list <(100-500)|expanded WORD>",
NO_STR IP_STR COMMUNITY_LIST_STR
@@ -14546,13 +14430,6 @@ ALIAS(no_community_list_expanded_all, no_bgp_community_list_expanded_all_list_cm
"Add an expanded community-list entry\n"
"Community list name\n")
-ALIAS(no_community_list_expanded_all, no_ip_community_list_expanded_all_list_cmd,
- "no ip community-list <(100-500)|expanded WORD>",
- NO_STR IP_STR COMMUNITY_LIST_STR
- "Community list number (expanded)\n"
- "Add an expanded community-list entry\n"
- "Community list name\n")
-
/* Return configuration string of community-list entry. */
static const char *community_list_config_str(struct community_entry *entry)
{
@@ -14610,13 +14487,6 @@ DEFUN (show_community_list,
struct community_list *list;
struct community_list_master *cm;
- int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'show bgp community-list <(1-500)|WORD>'\n");
- zlog_warn("Deprecated option: 'ip show community-list <(1-500)|WORD>' being used");
- }
cm = community_list_master_lookup(bgp_clist, COMMUNITY_LIST_MASTER);
if (!cm)
return CMD_SUCCESS;
@@ -14630,13 +14500,6 @@ DEFUN (show_community_list,
return CMD_SUCCESS;
}
-ALIAS (show_community_list,
- show_ip_community_list_cmd,
- "show ip community-list",
- SHOW_STR
- IP_STR
- "List community-list\n")
-
DEFUN (show_community_list_arg,
show_bgp_community_list_arg_cmd,
"show bgp community-list <(1-500)|WORD> detail",
@@ -14650,13 +14513,6 @@ DEFUN (show_community_list_arg,
int idx_comm_list = 3;
struct community_list *list;
- int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'show bgp community-list <(1-500)|WORD> detail'\n");
- zlog_warn("Deprecated option: 'show ip community-list <(1-500)|WORD>' being used");
- }
list = community_list_lookup(bgp_clist, argv[idx_comm_list]->arg, 0,
COMMUNITY_LIST_MASTER);
if (!list) {
@@ -14669,15 +14525,6 @@ DEFUN (show_community_list_arg,
return CMD_SUCCESS;
}
-ALIAS (show_community_list_arg,
- show_ip_community_list_arg_cmd,
- "show ip community-list <(1-500)|WORD>",
- SHOW_STR
- IP_STR
- "List community-list\n"
- "Community-list number\n"
- "Community-list name\n")
-
/*
* Large Community code.
*/
@@ -14691,12 +14538,6 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc,
int idx = 0;
char *cl_name;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'bgp large-community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:BB:CC>'\n");
- zlog_warn("Deprecated option: 'large-community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:BB:CC>' being used");
- }
direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
: COMMUNITY_DENY;
@@ -14741,12 +14582,6 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
char *str = NULL;
int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'no bgp large-community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:BB:CC>'\n");
- zlog_warn("Deprecated option: 'no ip large-community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:BB:CC>' being used");
- }
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
@@ -14789,9 +14624,6 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
#define LCOMMUNITY_LIST_STR "Add a large community list entry\n"
#define LCOMMUNITY_VAL_STR "large community in 'aa:bb:cc' format\n"
-#if CONFDATE > 20191005
-CPP_NOTICE("bgpd: remove deprecated 'ip large-community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:BB:CC>' command")
-#endif
DEFUN (lcommunity_list_standard,
bgp_lcommunity_list_standard_cmd,
"bgp large-community-list (1-99) <deny|permit> AA:BB:CC...",
@@ -14806,16 +14638,6 @@ DEFUN (lcommunity_list_standard,
LARGE_COMMUNITY_LIST_STANDARD, 0);
}
-ALIAS (lcommunity_list_standard,
- ip_lcommunity_list_standard_cmd,
- "ip large-community-list (1-99) <deny|permit> AA:BB:CC...",
- IP_STR
- LCOMMUNITY_LIST_STR
- "Large Community list number (standard)\n"
- "Specify large community to reject\n"
- "Specify large community to accept\n"
- LCOMMUNITY_VAL_STR)
-
DEFUN (lcommunity_list_expanded,
bgp_lcommunity_list_expanded_cmd,
"bgp large-community-list (100-500) <deny|permit> LINE...",
@@ -14830,16 +14652,6 @@ DEFUN (lcommunity_list_expanded,
LARGE_COMMUNITY_LIST_EXPANDED, 0);
}
-ALIAS (lcommunity_list_expanded,
- ip_lcommunity_list_expanded_cmd,
- "ip large-community-list (100-500) <deny|permit> LINE...",
- IP_STR
- LCOMMUNITY_LIST_STR
- "Large Community list number (expanded)\n"
- "Specify large community to reject\n"
- "Specify large community to accept\n"
- "An ordered list as a regular-expression\n")
-
DEFUN (lcommunity_list_name_standard,
bgp_lcommunity_list_name_standard_cmd,
"bgp large-community-list standard WORD <deny|permit> AA:BB:CC...",
@@ -14855,17 +14667,6 @@ DEFUN (lcommunity_list_name_standard,
LARGE_COMMUNITY_LIST_STANDARD, 1);
}
-ALIAS (lcommunity_list_name_standard,
- ip_lcommunity_list_name_standard_cmd,
- "ip large-community-list standard WORD <deny|permit> AA:BB:CC...",
- IP_STR
- LCOMMUNITY_LIST_STR
- "Specify standard large-community-list\n"
- "Large Community list name\n"
- "Specify large community to reject\n"
- "Specify large community to accept\n"
- LCOMMUNITY_VAL_STR)
-
DEFUN (lcommunity_list_name_expanded,
bgp_lcommunity_list_name_expanded_cmd,
"bgp large-community-list expanded WORD <deny|permit> LINE...",
@@ -14881,17 +14682,6 @@ DEFUN (lcommunity_list_name_expanded,
LARGE_COMMUNITY_LIST_EXPANDED, 1);
}
-ALIAS (lcommunity_list_name_expanded,
- ip_lcommunity_list_name_expanded_cmd,
- "ip large-community-list expanded WORD <deny|permit> LINE...",
- IP_STR
- LCOMMUNITY_LIST_STR
- "Specify expanded large-community-list\n"
- "Large Community list name\n"
- "Specify large community to reject\n"
- "Specify large community to accept\n"
- "An ordered list as a regular-expression\n")
-
DEFUN (no_lcommunity_list_standard_all,
no_bgp_lcommunity_list_standard_all_cmd,
"no bgp large-community-list <(1-99)|(100-500)|WORD>",
@@ -14906,16 +14696,6 @@ DEFUN (no_lcommunity_list_standard_all,
LARGE_COMMUNITY_LIST_STANDARD);
}
-ALIAS (no_lcommunity_list_standard_all,
- no_ip_lcommunity_list_standard_all_cmd,
- "no ip large-community-list <(1-99)|(100-500)|WORD>",
- NO_STR
- IP_STR
- LCOMMUNITY_LIST_STR
- "Large Community list number (standard)\n"
- "Large Community list number (expanded)\n"
- "Large Community list name\n")
-
DEFUN (no_lcommunity_list_name_expanded_all,
no_bgp_lcommunity_list_name_expanded_all_cmd,
"no bgp large-community-list expanded WORD",
@@ -14929,15 +14709,6 @@ DEFUN (no_lcommunity_list_name_expanded_all,
LARGE_COMMUNITY_LIST_EXPANDED);
}
-ALIAS (no_lcommunity_list_name_expanded_all,
- no_ip_lcommunity_list_name_expanded_all_cmd,
- "no ip large-community-list expanded WORD",
- NO_STR
- IP_STR
- LCOMMUNITY_LIST_STR
- "Specify expanded large-community-list\n"
- "Large Community list name\n")
-
DEFUN (no_lcommunity_list_standard,
no_bgp_lcommunity_list_standard_cmd,
"no bgp large-community-list (1-99) <deny|permit> AA:AA:NN...",
@@ -14953,17 +14724,6 @@ DEFUN (no_lcommunity_list_standard,
LARGE_COMMUNITY_LIST_STANDARD);
}
-ALIAS (no_lcommunity_list_standard,
- no_ip_lcommunity_list_standard_cmd,
- "no ip large-community-list (1-99) <deny|permit> AA:AA:NN...",
- NO_STR
- IP_STR
- LCOMMUNITY_LIST_STR
- "Large Community list number (standard)\n"
- "Specify large community to reject\n"
- "Specify large community to accept\n"
- LCOMMUNITY_VAL_STR)
-
DEFUN (no_lcommunity_list_expanded,
no_bgp_lcommunity_list_expanded_cmd,
"no bgp large-community-list (100-500) <deny|permit> LINE...",
@@ -14979,17 +14739,6 @@ DEFUN (no_lcommunity_list_expanded,
LARGE_COMMUNITY_LIST_EXPANDED);
}
-ALIAS (no_lcommunity_list_expanded,
- no_ip_lcommunity_list_expanded_cmd,
- "no ip large-community-list (100-500) <deny|permit> LINE...",
- NO_STR
- IP_STR
- LCOMMUNITY_LIST_STR
- "Large Community list number (expanded)\n"
- "Specify large community to reject\n"
- "Specify large community to accept\n"
- "An ordered list as a regular-expression\n")
-
DEFUN (no_lcommunity_list_name_standard,
no_bgp_lcommunity_list_name_standard_cmd,
"no bgp large-community-list standard WORD <deny|permit> AA:AA:NN...",
@@ -15006,18 +14755,6 @@ DEFUN (no_lcommunity_list_name_standard,
LARGE_COMMUNITY_LIST_STANDARD);
}
-ALIAS (no_lcommunity_list_name_standard,
- no_ip_lcommunity_list_name_standard_cmd,
- "no ip large-community-list standard WORD <deny|permit> AA:AA:NN...",
- NO_STR
- IP_STR
- LCOMMUNITY_LIST_STR
- "Specify standard large-community-list\n"
- "Large Community list name\n"
- "Specify large community to reject\n"
- "Specify large community to accept\n"
- LCOMMUNITY_VAL_STR)
-
DEFUN (no_lcommunity_list_name_expanded,
no_bgp_lcommunity_list_name_expanded_cmd,
"no bgp large-community-list expanded WORD <deny|permit> LINE...",
@@ -15034,18 +14771,6 @@ DEFUN (no_lcommunity_list_name_expanded,
LARGE_COMMUNITY_LIST_EXPANDED);
}
-ALIAS (no_lcommunity_list_name_expanded,
- no_ip_lcommunity_list_name_expanded_cmd,
- "no ip large-community-list expanded WORD <deny|permit> LINE...",
- NO_STR
- IP_STR
- LCOMMUNITY_LIST_STR
- "Specify expanded large-community-list\n"
- "Large community list name\n"
- "Specify large community to reject\n"
- "Specify large community to accept\n"
- "An ordered list as a regular-expression\n")
-
static void lcommunity_list_show(struct vty *vty, struct community_list *list)
{
struct community_entry *entry;
@@ -15087,14 +14812,6 @@ DEFUN (show_lcommunity_list,
{
struct community_list *list;
struct community_list_master *cm;
- int idx = 0;
-
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'show bgp large-community-list <(1-500)|WORD>'\n");
- zlog_warn("Deprecated option: 'ip show large-community-list <(1-500)|WORD>' being used");
- }
cm = community_list_master_lookup(bgp_clist,
LARGE_COMMUNITY_LIST_MASTER);
@@ -15110,13 +14827,6 @@ DEFUN (show_lcommunity_list,
return CMD_SUCCESS;
}
-ALIAS (show_lcommunity_list,
- show_ip_lcommunity_list_cmd,
- "show ip large-community-list",
- SHOW_STR
- IP_STR
- "List large-community list\n")
-
DEFUN (show_lcommunity_list_arg,
show_bgp_lcommunity_list_arg_cmd,
"show bgp large-community-list <(1-500)|WORD> detail",
@@ -15128,14 +14838,6 @@ DEFUN (show_lcommunity_list_arg,
"Detailed information on large-community-list\n")
{
struct community_list *list;
- int idx = 0;
-
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'show bgp large-community-list <(1-500)|WORD> detail'\n");
- zlog_warn("Deprecated option: 'show ip large-community-list <(1-500)|WORD>' being used");
- }
list = community_list_lookup(bgp_clist, argv[3]->arg, 0,
LARGE_COMMUNITY_LIST_MASTER);
@@ -15149,15 +14851,6 @@ DEFUN (show_lcommunity_list_arg,
return CMD_SUCCESS;
}
-ALIAS (show_lcommunity_list_arg,
- show_ip_lcommunity_list_arg_cmd,
- "show ip large-community-list <(1-500)|WORD>",
- SHOW_STR
- IP_STR
- "List large-community list\n"
- "large-community-list number\n"
- "large-community-list name\n")
-
/* "extcommunity-list" keyword help string. */
#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"
#define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n"
@@ -15179,12 +14872,7 @@ DEFUN (extcommunity_list_standard,
char *cl_number_or_name = NULL;
int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'bgp extcommunity-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:NN>'\n");
- zlog_warn("Deprecated option: 'ip extcommunity-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:NN>' being used");
- }
+
argv_find(argv, argc, "(1-99)", &idx);
argv_find(argv, argc, "WORD", &idx);
cl_number_or_name = argv[idx]->arg;
@@ -15206,21 +14894,6 @@ DEFUN (extcommunity_list_standard,
return CMD_SUCCESS;
}
-#if CONFDATE > 20191005
-CPP_NOTICE("bgpd: remove deprecated 'ip extcommunity-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:NN>' command")
-#endif
-ALIAS (extcommunity_list_standard,
- ip_extcommunity_list_standard_cmd,
- "ip extcommunity-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
- IP_STR
- EXTCOMMUNITY_LIST_STR
- "Extended Community list number (standard)\n"
- "Specify standard extcommunity-list\n"
- "Community list name\n"
- "Specify community to reject\n"
- "Specify community to accept\n"
- EXTCOMMUNITY_VAL_STR)
-
DEFUN (extcommunity_list_name_expanded,
bgp_extcommunity_list_name_expanded_cmd,
"bgp extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...",
@@ -15236,14 +14909,7 @@ DEFUN (extcommunity_list_name_expanded,
int style = EXTCOMMUNITY_LIST_EXPANDED;
int direct = 0;
char *cl_number_or_name = NULL;
-
int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'extcommunity-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:NN>'\n");
- zlog_warn("Deprecated option: ‘ip extcommunity-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:NN>' being used");
- }
argv_find(argv, argc, "(100-500)", &idx);
argv_find(argv, argc, "WORD", &idx);
@@ -15266,18 +14932,6 @@ DEFUN (extcommunity_list_name_expanded,
return CMD_SUCCESS;
}
-ALIAS (extcommunity_list_name_expanded,
- ip_extcommunity_list_name_expanded_cmd,
- "ip extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...",
- IP_STR
- EXTCOMMUNITY_LIST_STR
- "Extended Community list number (expanded)\n"
- "Specify expanded extcommunity-list\n"
- "Extended Community list name\n"
- "Specify community to reject\n"
- "Specify community to accept\n"
- "An ordered list as a regular-expression\n")
-
DEFUN (no_extcommunity_list_standard_all,
no_bgp_extcommunity_list_standard_all_cmd,
"no bgp extcommunity-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
@@ -15295,16 +14949,8 @@ DEFUN (no_extcommunity_list_standard_all,
int direct = 0;
char *cl_number_or_name = NULL;
char *str = NULL;
-
int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'no bgp extcommunity-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:NN>'\n");
- zlog_warn("Deprecated option: ‘no ip extcommunity-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:NN>' being used");
- }
- idx = 0;
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
@@ -15336,19 +14982,6 @@ DEFUN (no_extcommunity_list_standard_all,
return CMD_SUCCESS;
}
-ALIAS (no_extcommunity_list_standard_all,
- no_ip_extcommunity_list_standard_all_cmd,
- "no ip extcommunity-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
- NO_STR
- IP_STR
- EXTCOMMUNITY_LIST_STR
- "Extended Community list number (standard)\n"
- "Specify standard extcommunity-list\n"
- "Community list name\n"
- "Specify community to reject\n"
- "Specify community to accept\n"
- EXTCOMMUNITY_VAL_STR)
-
ALIAS(no_extcommunity_list_standard_all,
no_bgp_extcommunity_list_standard_all_list_cmd,
"no bgp extcommunity-list <(1-99)|standard WORD>",
@@ -15357,14 +14990,6 @@ ALIAS(no_extcommunity_list_standard_all,
"Specify standard extcommunity-list\n"
"Community list name\n")
-ALIAS(no_extcommunity_list_standard_all,
- no_ip_extcommunity_list_standard_all_list_cmd,
- "no ip extcommunity-list <(1-99)|standard WORD>",
- NO_STR IP_STR EXTCOMMUNITY_LIST_STR
- "Extended Community list number (standard)\n"
- "Specify standard extcommunity-list\n"
- "Community list name\n")
-
DEFUN (no_extcommunity_list_expanded_all,
no_bgp_extcommunity_list_expanded_all_cmd,
"no bgp extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...",
@@ -15382,16 +15007,8 @@ DEFUN (no_extcommunity_list_expanded_all,
int direct = 0;
char *cl_number_or_name = NULL;
char *str = NULL;
-
int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'no bgp extcommunity-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:NN>'\n");
- zlog_warn("Deprecated option: ‘no ip extcommunity-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:NN>' being used");
- }
- idx = 0;
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
@@ -15423,27 +15040,6 @@ DEFUN (no_extcommunity_list_expanded_all,
return CMD_SUCCESS;
}
-ALIAS (no_extcommunity_list_expanded_all,
- no_ip_extcommunity_list_expanded_all_cmd,
- "no ip extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...",
- NO_STR
- IP_STR
- EXTCOMMUNITY_LIST_STR
- "Extended Community list number (expanded)\n"
- "Specify expanded extcommunity-list\n"
- "Extended Community list name\n"
- "Specify community to reject\n"
- "Specify community to accept\n"
- "An ordered list as a regular-expression\n")
-
-ALIAS(no_extcommunity_list_expanded_all,
- no_ip_extcommunity_list_expanded_all_list_cmd,
- "no ip extcommunity-list <(100-500)|expanded WORD>",
- NO_STR IP_STR EXTCOMMUNITY_LIST_STR
- "Extended Community list number (expanded)\n"
- "Specify expanded extcommunity-list\n"
- "Extended Community list name\n")
-
ALIAS(no_extcommunity_list_expanded_all,
no_bgp_extcommunity_list_expanded_all_list_cmd,
"no bgp extcommunity-list <(100-500)|expanded WORD>",
@@ -15491,14 +15087,7 @@ DEFUN (show_extcommunity_list,
{
struct community_list *list;
struct community_list_master *cm;
- int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'show bgp extcommunity-list <(1-500)|WORD>'\n");
- zlog_warn("Deprecated option: 'ip show extcommunity-list <(1-500)|WORD>' being used");
- }
cm = community_list_master_lookup(bgp_clist, EXTCOMMUNITY_LIST_MASTER);
if (!cm)
return CMD_SUCCESS;
@@ -15512,13 +15101,6 @@ DEFUN (show_extcommunity_list,
return CMD_SUCCESS;
}
-ALIAS (show_extcommunity_list,
- show_ip_extcommunity_list_cmd,
- "show ip extcommunity-list",
- SHOW_STR
- IP_STR
- "List extended-community list\n")
-
DEFUN (show_extcommunity_list_arg,
show_bgp_extcommunity_list_arg_cmd,
"show bgp extcommunity-list <(1-500)|WORD> detail",
@@ -15531,14 +15113,7 @@ DEFUN (show_extcommunity_list_arg,
{
int idx_comm_list = 3;
struct community_list *list;
- int idx = 0;
- if (argv_find(argv, argc, "ip", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please migrate to the below command.\n");
- vty_out(vty, "'show bgp extcommunity-list <(1-500)|WORD> detail'\n");
- zlog_warn("Deprecated option: 'show ip extcommunity-list <(1-500)|WORD>' being used");
- }
list = community_list_lookup(bgp_clist, argv[idx_comm_list]->arg, 0,
EXTCOMMUNITY_LIST_MASTER);
if (!list) {
@@ -15551,15 +15126,6 @@ DEFUN (show_extcommunity_list_arg,
return CMD_SUCCESS;
}
-ALIAS (show_extcommunity_list_arg,
- show_ip_extcommunity_list_arg_cmd,
- "show ip extcommunity-list <(1-500)|WORD>",
- SHOW_STR
- IP_STR
- "List extended-community list\n"
- "Extcommunity-list number\n"
- "Extcommunity-list name\n")
-
/* Display community-list and extcommunity-list configuration. */
static int community_list_config_write(struct vty *vty)
{
@@ -15653,14 +15219,6 @@ static void community_list_vty(void)
install_element(CONFIG_NODE, &no_bgp_community_list_expanded_all_list_cmd);
install_element(VIEW_NODE, &show_bgp_community_list_cmd);
install_element(VIEW_NODE, &show_bgp_community_list_arg_cmd);
- install_element(CONFIG_NODE, &ip_community_list_standard_cmd);
- install_element(CONFIG_NODE, &ip_community_list_expanded_all_cmd);
- install_element(CONFIG_NODE, &no_ip_community_list_standard_all_cmd);
- install_element(CONFIG_NODE, &no_ip_community_list_standard_all_list_cmd);
- install_element(CONFIG_NODE, &no_ip_community_list_expanded_all_cmd);
- install_element(CONFIG_NODE, &no_ip_community_list_expanded_all_list_cmd);
- install_element(VIEW_NODE, &show_ip_community_list_cmd);
- install_element(VIEW_NODE, &show_ip_community_list_arg_cmd);
/* Extcommunity-list. */
install_element(CONFIG_NODE, &bgp_extcommunity_list_standard_cmd);
@@ -15673,14 +15231,6 @@ static void community_list_vty(void)
&no_bgp_extcommunity_list_expanded_all_list_cmd);
install_element(VIEW_NODE, &show_bgp_extcommunity_list_cmd);
install_element(VIEW_NODE, &show_bgp_extcommunity_list_arg_cmd);
- install_element(CONFIG_NODE, &ip_extcommunity_list_standard_cmd);
- install_element(CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd);
- install_element(CONFIG_NODE, &no_ip_extcommunity_list_standard_all_cmd);
- install_element(CONFIG_NODE, &no_ip_extcommunity_list_standard_all_list_cmd);
- install_element(CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd);
- install_element(CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_list_cmd);
- install_element(VIEW_NODE, &show_ip_extcommunity_list_cmd);
- install_element(VIEW_NODE, &show_ip_extcommunity_list_arg_cmd);
/* Large Community List */
install_element(CONFIG_NODE, &bgp_lcommunity_list_standard_cmd);
@@ -15696,17 +15246,4 @@ static void community_list_vty(void)
install_element(CONFIG_NODE, &no_bgp_lcommunity_list_name_expanded_cmd);
install_element(VIEW_NODE, &show_bgp_lcommunity_list_cmd);
install_element(VIEW_NODE, &show_bgp_lcommunity_list_arg_cmd);
- install_element(CONFIG_NODE, &ip_lcommunity_list_standard_cmd);
- install_element(CONFIG_NODE, &ip_lcommunity_list_expanded_cmd);
- install_element(CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd);
- install_element(CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd);
- install_element(CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd);
- install_element(CONFIG_NODE,
- &no_ip_lcommunity_list_name_expanded_all_cmd);
- install_element(CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd);
- install_element(CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd);
- install_element(CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd);
- install_element(CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd);
- install_element(VIEW_NODE, &show_ip_lcommunity_list_cmd);
- install_element(VIEW_NODE, &show_ip_lcommunity_list_arg_cmd);
}
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 71f7f6d0e..7923f076c 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -202,75 +202,36 @@ static void bgp_nbr_connected_delete(struct bgp *bgp, struct nbr_connected *ifc,
}
}
-/* Inteface addition message from zebra. */
-static int bgp_interface_add(ZAPI_CALLBACK_ARGS)
+static int bgp_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
struct bgp *bgp;
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
- if (!ifp) // unexpected
- return 0;
-
- if (BGP_DEBUG(zebra, ZEBRA) && ifp)
- zlog_debug("Rx Intf add VRF %u IF %s", vrf_id, ifp->name);
-
- bgp = bgp_lookup_by_vrf_id(vrf_id);
- if (!bgp)
- return 0;
-
- bgp_mac_add_mac_entry(ifp);
-
- bgp_update_interface_nbrs(bgp, ifp, ifp);
- return 0;
-}
-
-static int bgp_interface_delete(ZAPI_CALLBACK_ARGS)
-{
- struct stream *s;
- struct interface *ifp;
- struct bgp *bgp;
-
- bgp = bgp_lookup_by_vrf_id(vrf_id);
-
- s = zclient->ibuf;
- ifp = zebra_interface_state_read(s, vrf_id);
- if (!ifp) /* This may happen if we've just unregistered for a VRF. */
- return 0;
+ bgp = bgp_lookup_by_vrf_id(ifp->vrf_id);
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("Rx Intf del VRF %u IF %s", vrf_id, ifp->name);
+ zlog_debug("Rx Intf del VRF %u IF %s", ifp->vrf_id, ifp->name);
if (bgp)
bgp_update_interface_nbrs(bgp, ifp, NULL);
bgp_mac_del_mac_entry(ifp);
- if_set_index(ifp, IFINDEX_INTERNAL);
return 0;
}
-static int bgp_interface_up(ZAPI_CALLBACK_ARGS)
+static int bgp_ifp_up(struct interface *ifp)
{
- struct stream *s;
- struct interface *ifp;
struct connected *c;
struct nbr_connected *nc;
struct listnode *node, *nnode;
struct bgp *bgp;
- bgp = bgp_lookup_by_vrf_id(vrf_id);
-
- s = zclient->ibuf;
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (!ifp)
- return 0;
+ bgp = bgp_lookup_by_vrf_id(ifp->vrf_id);
bgp_mac_add_mac_entry(ifp);
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("Rx Intf up VRF %u IF %s", vrf_id, ifp->name);
+ zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf_id, ifp->name);
if (!bgp)
return 0;
@@ -284,27 +245,20 @@ static int bgp_interface_up(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int bgp_interface_down(ZAPI_CALLBACK_ARGS)
+static int bgp_ifp_down(struct interface *ifp)
{
- struct stream *s;
- struct interface *ifp;
struct connected *c;
struct nbr_connected *nc;
struct listnode *node, *nnode;
struct bgp *bgp;
struct peer *peer;
- bgp = bgp_lookup_by_vrf_id(vrf_id);
-
- s = zclient->ibuf;
- ifp = zebra_interface_state_read(s, vrf_id);
- if (!ifp)
- return 0;
+ bgp = bgp_lookup_by_vrf_id(ifp->vrf_id);
bgp_mac_del_mac_entry(ifp);
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("Rx Intf down VRF %u IF %s", vrf_id, ifp->name);
+ zlog_debug("Rx Intf down VRF %u IF %s", ifp->vrf_id, ifp->name);
if (!bgp)
return 0;
@@ -1274,6 +1228,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
+ if (info->attr->rmap_table_id) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
+ api.tableid = info->attr->rmap_table_id;
+ }
+
/* Metric is currently based on the best-path only */
metric = info->attr->med;
for (mpinfo = info; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
@@ -1540,6 +1499,11 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_path_info *info,
api.safi = safi;
api.prefix = *p;
+ if (info->attr->rmap_table_id) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
+ api.tableid = info->attr->rmap_table_id;
+ }
+
/* If the route's source is EVPN, flag as such. */
if (is_route_parent_evpn(info))
SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
@@ -2721,17 +2685,35 @@ stream_failure: /* for STREAM_GETX */
extern struct zebra_privs_t bgpd_privs;
+static int bgp_ifp_create(struct interface *ifp)
+{
+ struct bgp *bgp;
+
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("Rx Intf add VRF %u IF %s", ifp->vrf_id, ifp->name);
+
+ bgp = bgp_lookup_by_vrf_id(ifp->vrf_id);
+ if (!bgp)
+ return 0;
+
+ bgp_mac_add_mac_entry(ifp);
+
+ bgp_update_interface_nbrs(bgp, ifp, ifp);
+ return 0;
+}
+
void bgp_zebra_init(struct thread_master *master, unsigned short instance)
{
zclient_num_connects = 0;
+ if_zapi_callbacks(bgp_ifp_create, bgp_ifp_up,
+ bgp_ifp_down, bgp_ifp_destroy);
+
/* Set default values. */
zclient = zclient_new(master, &zclient_options_default);
zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs);
zclient->zebra_connected = bgp_zebra_connected;
zclient->router_id_update = bgp_router_id_update;
- zclient->interface_add = bgp_interface_add;
- zclient->interface_delete = bgp_interface_delete;
zclient->interface_address_add = bgp_interface_address_add;
zclient->interface_address_delete = bgp_interface_address_delete;
zclient->interface_nbr_address_add = bgp_interface_nbr_address_add;
@@ -2740,8 +2722,6 @@ void bgp_zebra_init(struct thread_master *master, unsigned short instance)
zclient->interface_vrf_update = bgp_interface_vrf_update;
zclient->redistribute_route_add = zebra_read_route;
zclient->redistribute_route_del = zebra_read_route;
- zclient->interface_up = bgp_interface_up;
- zclient->interface_down = bgp_interface_down;
zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update;
zclient->fec_update = bgp_read_fec_update;
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index e815334bf..a2d4c0101 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1593,7 +1593,7 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
peer->readtime = peer->resettime = bgp_clock();
/* Default TTL set. */
- peer->ttl = (peer->sort == BGP_PEER_IBGP) ? MAXTTL : 1;
+ peer->ttl = (peer->sort == BGP_PEER_IBGP) ? MAXTTL : BGP_DEFAULT_TTL;
SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
@@ -1680,7 +1680,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
if (peer_sort(peer) == BGP_PEER_IBGP)
peer->ttl = MAXTTL;
else if (type == BGP_PEER_IBGP)
- peer->ttl = 1;
+ peer->ttl = BGP_DEFAULT_TTL;
/* reflector-client reset */
if (peer_sort(peer) != BGP_PEER_IBGP) {
@@ -2444,7 +2444,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name)
group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name);
group->conf->group = group;
group->conf->as = 0;
- group->conf->ttl = 1;
+ group->conf->ttl = BGP_DEFAULT_TTL;
group->conf->gtsm_hops = 0;
group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
SET_FLAG(group->conf->sflags, PEER_STATUS_GROUP);
@@ -2469,8 +2469,9 @@ static void peer_group2peer_config_copy(struct peer_group *group,
if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_LOCAL_AS))
peer->change_local_as = conf->change_local_as;
- /* TTL */
- peer->ttl = conf->ttl;
+ /* If peer-group has configured TTL then override it */
+ if (conf->ttl != BGP_DEFAULT_TTL)
+ peer->ttl = conf->ttl;
/* GTSM hops */
peer->gtsm_hops = conf->gtsm_hops;
@@ -4379,7 +4380,7 @@ int peer_ebgp_multihop_unset(struct peer *peer)
if (peer_group_active(peer))
peer->ttl = peer->group->conf->ttl;
else
- peer->ttl = 1;
+ peer->ttl = BGP_DEFAULT_TTL;
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
@@ -4393,7 +4394,7 @@ int peer_ebgp_multihop_unset(struct peer *peer)
if (peer->sort == BGP_PEER_IBGP)
continue;
- peer->ttl = 1;
+ peer->ttl = BGP_DEFAULT_TTL;
if (peer->fd >= 0) {
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
@@ -7348,7 +7349,7 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
/* maximum-prefix. */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX)) {
- vty_out(vty, " neighbor %s maximum-prefix %lu", addr,
+ vty_out(vty, " neighbor %s maximum-prefix %" PRIu32, addr,
peer->pmax[afi][safi]);
if (peer->pmax_threshold[afi][safi]
@@ -7529,7 +7530,6 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
int bgp_config_write(struct vty *vty)
{
- int write = 0;
struct bgp *bgp;
struct peer_group *group;
struct peer *peer;
@@ -7540,9 +7540,6 @@ int bgp_config_write(struct vty *vty)
vty_out(vty, "bgp route-map delay-timer %u\n",
bm->rmap_update_timer);
- if (write)
- vty_out(vty, "!\n");
-
/* BGP configuration. */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
@@ -7823,7 +7820,7 @@ int bgp_config_write(struct vty *vty)
return 0;
}
-void bgp_master_init(struct thread_master *master)
+void bgp_master_init(struct thread_master *master, const int buffer_size)
{
qobj_init();
@@ -7838,6 +7835,7 @@ void bgp_master_init(struct thread_master *master)
bm->t_rmap_update = NULL;
bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
bm->terminating = false;
+ bm->socket_buffer = buffer_size;
bgp_process_queue_init();
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 9d45d9698..9f6148488 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -156,6 +156,9 @@ struct bgp_master {
/* BGP-EVPN VRF ID. Defaults to default VRF (if any) */
struct bgp* bgp_evpn;
+ /* How big should we set the socket buffer size */
+ uint32_t socket_buffer;
+
bool terminating; /* global flag that sigint terminate seen */
QOBJ_FIELDS
};
@@ -632,6 +635,8 @@ struct bgp_nexthop {
#define RMAP_OUT 1
#define RMAP_MAX 2
+#define BGP_DEFAULT_TTL 1
+
#include "filter.h"
/* BGP filter structure. */
@@ -1152,10 +1157,10 @@ struct peer {
int rcvd_attr_printed;
/* Prefix count. */
- unsigned long pcount[AFI_MAX][SAFI_MAX];
+ uint32_t pcount[AFI_MAX][SAFI_MAX];
/* Max prefix count. */
- unsigned long pmax[AFI_MAX][SAFI_MAX];
+ uint32_t pmax[AFI_MAX][SAFI_MAX];
uint8_t pmax_threshold[AFI_MAX][SAFI_MAX];
uint16_t pmax_restart[AFI_MAX][SAFI_MAX];
#define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75
@@ -1202,7 +1207,7 @@ struct peer {
uint8_t last_reset_cause[BGP_MAX_PACKET_SIZE];
/* The kind of route-map Flags.*/
- uint8_t rmap_type;
+ uint16_t rmap_type;
#define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */
#define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */
#define PEER_RMAP_TYPE_NETWORK (1 << 2) /* network route-map */
@@ -1575,7 +1580,8 @@ extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
extern int bgp_config_write(struct vty *);
-extern void bgp_master_init(struct thread_master *master);
+extern void bgp_master_init(struct thread_master *master,
+ const int buffer_size);
extern void bgp_init(unsigned short instance);
extern void bgp_pthreads_run(void);
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 0aa102fea..7c4f8eaa0 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -388,15 +388,13 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
bpi = bpi->next) {
vnc_zlog_debug_verbose(
- "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%u",
+ "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%" PRIu64,
__func__, bpi, bpi->peer, bpi->type, bpi->sub_type,
(bpi->extra ? bpi->extra->vnc.export.rfapi_handle
: NULL),
- ((bpi->attr
- && CHECK_FLAG(bpi->attr->flag,
- ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))
- ? bpi->attr->local_pref
- : 0));
+ CHECK_FLAG(bpi->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)
+ ? bpi->attr->local_pref : 0));
if (bpi->peer == peer && bpi->type == type
&& bpi->sub_type == sub_type && bpi->extra
@@ -3192,12 +3190,8 @@ DEFUN (debug_rfapi_register_vn_un_l2o,
return CMD_WARNING_CONFIG_FAILED;
}
optary[opt_next].type = RFAPI_VN_OPTION_TYPE_L2ADDR;
- if (opt_next) {
- optary[opt_next - 1].next = optary + opt_next;
- } else {
- opt = optary;
- }
- ++opt_next;
+ opt = optary;
+
/* L2 option parsing END */
/* TBD fixme */
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 87a05a4f8..fe8e87444 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -484,8 +484,7 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr,
new = info_make(type, sub_type, 0, peer, attr, NULL);
- if (attr)
- new->attr = bgp_attr_intern(attr);
+ new->attr = bgp_attr_intern(attr);
bgp_path_info_extra_get(new);
if (prd) {
@@ -516,9 +515,8 @@ static void rfapiBgpInfoFree(struct bgp_path_info *goner)
peer_unlock(goner->peer);
}
- if (goner->attr) {
- bgp_attr_unintern(&goner->attr);
- }
+ bgp_attr_unintern(&goner->attr);
+
if (goner->extra)
bgp_path_info_extra_free(&goner->extra);
XFREE(MTYPE_BGP_ROUTE, goner);
@@ -1113,9 +1111,6 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
if (!bpi1 || !bpi2)
return 0;
- if (!bpi1->attr || !bpi2->attr)
- return 0;
-
/*
* VN address comparisons
*/
@@ -1299,13 +1294,10 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
memcpy(&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet,
ETH_ALEN);
/* only low 3 bytes of this are significant */
- if (bpi->attr) {
- (void)rfapiEcommunityGetLNI(
- bpi->attr->ecommunity,
- &vo->v.l2addr.logical_net_id);
- (void)rfapiEcommunityGetEthernetTag(
- bpi->attr->ecommunity, &vo->v.l2addr.tag_id);
- }
+ (void)rfapiEcommunityGetLNI(bpi->attr->ecommunity,
+ &vo->v.l2addr.logical_net_id);
+ (void)rfapiEcommunityGetEthernetTag(bpi->attr->ecommunity,
+ &vo->v.l2addr.tag_id);
/* local_nve_id comes from lower byte of RD type */
vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1];
@@ -1325,129 +1317,117 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
}
}
- if (bpi->attr) {
- bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS; /*Default*/
- new->prefix.cost = rfapiRfpCost(bpi->attr);
+ bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS; /*Default*/
+ new->prefix.cost = rfapiRfpCost(bpi->attr);
- struct bgp_attr_encap_subtlv *pEncap;
-
- switch (BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len)) {
- case AF_INET:
- new->vn_address.addr_family = AF_INET;
- new->vn_address.addr.v4 =
- bpi->attr->mp_nexthop_global_in;
- break;
+ struct bgp_attr_encap_subtlv *pEncap;
- case AF_INET6:
- new->vn_address.addr_family = AF_INET6;
- new->vn_address.addr.v6 = bpi->attr->mp_nexthop_global;
- break;
+ switch (BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len)) {
+ case AF_INET:
+ new->vn_address.addr_family = AF_INET;
+ new->vn_address.addr.v4 = bpi->attr->mp_nexthop_global_in;
+ break;
- default:
- zlog_warn("%s: invalid vpn nexthop length: %d",
- __func__, bpi->attr->mp_nexthop_len);
- rfapi_free_next_hop_list(new);
- return NULL;
- }
+ case AF_INET6:
+ new->vn_address.addr_family = AF_INET6;
+ new->vn_address.addr.v6 = bpi->attr->mp_nexthop_global;
+ break;
- for (pEncap = bpi->attr->vnc_subtlvs; pEncap;
- pEncap = pEncap->next) {
- switch (pEncap->type) {
- case BGP_VNC_SUBTLV_TYPE_LIFETIME:
- /* use configured lifetime, not attr lifetime */
- break;
+ default:
+ zlog_warn("%s: invalid vpn nexthop length: %d", __func__,
+ bpi->attr->mp_nexthop_len);
+ rfapi_free_next_hop_list(new);
+ return NULL;
+ }
- default:
- zlog_warn("%s: unknown VNC option type %d",
- __func__, pEncap->type);
+ for (pEncap = bpi->attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) {
+ switch (pEncap->type) {
+ case BGP_VNC_SUBTLV_TYPE_LIFETIME:
+ /* use configured lifetime, not attr lifetime */
+ break;
+ default:
+ zlog_warn("%s: unknown VNC option type %d", __func__,
+ pEncap->type);
- break;
- }
+ break;
}
+ }
- bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type);
- if (tun_type == BGP_ENCAP_TYPE_MPLS) {
- struct prefix p;
- /* MPLS carries UN address in next hop */
- rfapiNexthop2Prefix(bpi->attr, &p);
- if (p.family != 0) {
- rfapiQprefix2Raddr(&p, &new->un_address);
- have_vnc_tunnel_un = 1;
- }
+ bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type);
+ if (tun_type == BGP_ENCAP_TYPE_MPLS) {
+ struct prefix p;
+ /* MPLS carries UN address in next hop */
+ rfapiNexthop2Prefix(bpi->attr, &p);
+ if (p.family != 0) {
+ rfapiQprefix2Raddr(&p, &new->un_address);
+ have_vnc_tunnel_un = 1;
}
+ }
- for (pEncap = bpi->attr->encap_subtlvs; pEncap;
- pEncap = pEncap->next) {
- switch (pEncap->type) {
- case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT:
- /*
- * Overrides ENCAP UN address, if any
- */
- switch (pEncap->length) {
-
- case 8:
- new->un_address.addr_family = AF_INET;
- memcpy(&new->un_address.addr.v4,
- pEncap->value, 4);
- have_vnc_tunnel_un = 1;
- break;
+ for (pEncap = bpi->attr->encap_subtlvs; pEncap; pEncap = pEncap->next) {
+ switch (pEncap->type) {
+ case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT:
+ /*
+ * Overrides ENCAP UN address, if any
+ */
+ switch (pEncap->length) {
- case 20:
- new->un_address.addr_family = AF_INET6;
- memcpy(&new->un_address.addr.v6,
- pEncap->value, 16);
- have_vnc_tunnel_un = 1;
- break;
+ case 8:
+ new->un_address.addr_family = AF_INET;
+ memcpy(&new->un_address.addr.v4, pEncap->value,
+ 4);
+ have_vnc_tunnel_un = 1;
+ break;
- default:
- zlog_warn(
- "%s: invalid tunnel subtlv UN addr length (%d) for bpi %p",
- __func__, pEncap->length, bpi);
- }
+ case 20:
+ new->un_address.addr_family = AF_INET6;
+ memcpy(&new->un_address.addr.v6, pEncap->value,
+ 16);
+ have_vnc_tunnel_un = 1;
break;
default:
zlog_warn(
- "%s: unknown Encap Attribute option type %d",
- __func__, pEncap->type);
-
-
- break;
+ "%s: invalid tunnel subtlv UN addr length (%d) for bpi %p",
+ __func__, pEncap->length, bpi);
}
+ break;
+
+ default:
+ zlog_warn("%s: unknown Encap Attribute option type %d",
+ __func__, pEncap->type);
+ break;
}
+ }
- new->un_options = rfapi_encap_tlv_to_un_option(bpi->attr);
+ new->un_options = rfapi_encap_tlv_to_un_option(bpi->attr);
#if DEBUG_ENCAP_MONITOR
- vnc_zlog_debug_verbose("%s: line %d: have_vnc_tunnel_un=%d",
- __func__, __LINE__, have_vnc_tunnel_un);
+ vnc_zlog_debug_verbose("%s: line %d: have_vnc_tunnel_un=%d", __func__,
+ __LINE__, have_vnc_tunnel_un);
#endif
- if (!have_vnc_tunnel_un && bpi->extra) {
- /*
- * use cached UN address from ENCAP route
- */
- new->un_address.addr_family =
- bpi->extra->vnc.import.un_family;
- switch (new->un_address.addr_family) {
- case AF_INET:
- new->un_address.addr.v4 =
- bpi->extra->vnc.import.un.addr4;
- break;
- case AF_INET6:
- new->un_address.addr.v6 =
- bpi->extra->vnc.import.un.addr6;
- break;
- default:
- zlog_warn(
- "%s: invalid UN addr family (%d) for bpi %p",
- __func__, new->un_address.addr_family,
- bpi);
- rfapi_free_next_hop_list(new);
- return NULL;
- break;
- }
+ if (!have_vnc_tunnel_un && bpi->extra) {
+ /*
+ * use cached UN address from ENCAP route
+ */
+ new->un_address.addr_family = bpi->extra->vnc.import.un_family;
+ switch (new->un_address.addr_family) {
+ case AF_INET:
+ new->un_address.addr.v4 =
+ bpi->extra->vnc.import.un.addr4;
+ break;
+ case AF_INET6:
+ new->un_address.addr.v6 =
+ bpi->extra->vnc.import.un.addr6;
+ break;
+ default:
+ zlog_warn("%s: invalid UN addr family (%d) for bpi %p",
+ __func__, new->un_address.addr_family, bpi);
+ rfapi_free_next_hop_list(new);
+ return NULL;
+ break;
}
}
@@ -2179,8 +2159,8 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
{
struct skiplist *sl;
int rc;
- struct bgp_path_info bpi_fake;
- struct bgp_path_info_extra bpi_extra;
+ struct bgp_path_info bpi_fake = {0};
+ struct bgp_path_info_extra bpi_extra = {0};
struct bgp_path_info *bpi_result;
sl = RFAPI_RDINDEX(rn);
@@ -2607,12 +2587,6 @@ static int rfapiAttrNexthopAddrDifferent(struct prefix *p1, struct prefix *p2)
static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi,
struct bgp_path_info *vpn_bpi)
{
- if (!encap_bpi->attr) {
- zlog_warn("%s: no encap bpi attr/extra, can't copy UN address",
- __func__);
- return;
- }
-
if (!vpn_bpi || !vpn_bpi->extra) {
zlog_warn("%s: no vpn bpi attr/extra, can't copy UN address",
__func__);
@@ -4510,10 +4484,9 @@ static void rfapiDeleteRemotePrefixesIt(
vnc_zlog_debug_verbose("%s: examining bpi %p",
__func__, bpi);
- if (bpi->attr) {
- if (!rfapiGetNexthop(bpi->attr, &qpt))
- qpt_valid = 1;
- }
+ if (!rfapiGetNexthop(bpi->attr, &qpt))
+ qpt_valid = 1;
+
if (vn) {
if (!qpt_valid
|| !prefix_match(vn, &qpt)) {
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index 8e8acbfb9..39d4b3ee2 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -1647,11 +1647,6 @@ void rfapiRibUpdatePendingNode(
struct rfapi_info *ri;
struct prefix pfx_nh;
- if (!bpi->attr) {
- /* shouldn't happen */
- /* TBD increment error stats counter */
- continue;
- }
if (!bpi->extra) {
/* shouldn't happen */
/* TBD increment error stats counter */
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 46161b4f3..4fa64075c 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -418,7 +418,7 @@ void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p,
}
}
- if (bpi->attr && bpi->attr->ecommunity) {
+ if (bpi->attr->ecommunity) {
s = ecommunity_ecom2str(bpi->attr->ecommunity,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " EC{%s}", s);
@@ -538,82 +538,78 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi)
* RFP option sizes (they are opaque values)
* extended communities (RTs)
*/
- if (bpi->attr) {
- uint32_t lifetime;
- int printed_1st_gol = 0;
- struct bgp_attr_encap_subtlv *pEncap;
- struct prefix pfx_un;
- int af = BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len);
-
- /* Nexthop */
- if (af == AF_INET) {
- r = snprintf(p, REMAIN, "%s",
- inet_ntop(AF_INET,
- &bpi->attr->mp_nexthop_global_in,
- buf, BUFSIZ));
- INCP;
- } else if (af == AF_INET6) {
- r = snprintf(p, REMAIN, "%s",
- inet_ntop(AF_INET6,
- &bpi->attr->mp_nexthop_global,
- buf, BUFSIZ));
- INCP;
- } else {
- r = snprintf(p, REMAIN, "?");
- INCP;
- }
+ uint32_t lifetime;
+ int printed_1st_gol = 0;
+ struct bgp_attr_encap_subtlv *pEncap;
+ struct prefix pfx_un;
+ int af = BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len);
+
+ /* Nexthop */
+ if (af == AF_INET) {
+ r = snprintf(p, REMAIN, "%s",
+ inet_ntop(AF_INET,
+ &bpi->attr->mp_nexthop_global_in, buf,
+ BUFSIZ));
+ INCP;
+ } else if (af == AF_INET6) {
+ r = snprintf(p, REMAIN, "%s",
+ inet_ntop(AF_INET6, &bpi->attr->mp_nexthop_global,
+ buf, BUFSIZ));
+ INCP;
+ } else {
+ r = snprintf(p, REMAIN, "?");
+ INCP;
+ }
- /*
- * VNC tunnel subtlv, if present, contains UN address
- */
- if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) {
- r = snprintf(p, REMAIN, " un=%s",
- inet_ntop(pfx_un.family, pfx_un.u.val, buf,
- BUFSIZ));
- INCP;
- }
+ /*
+ * VNC tunnel subtlv, if present, contains UN address
+ */
+ if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) {
+ r = snprintf(
+ p, REMAIN, " un=%s",
+ inet_ntop(pfx_un.family, pfx_un.u.val, buf, BUFSIZ));
+ INCP;
+ }
- /* Lifetime */
- if (rfapiGetVncLifetime(bpi->attr, &lifetime)) {
- r = snprintf(p, REMAIN, " nolife");
- INCP;
- } else {
- if (lifetime == 0xffffffff)
- r = snprintf(p, REMAIN, " %6s", "infini");
- else
- r = snprintf(p, REMAIN, " %6u", lifetime);
- INCP;
- }
+ /* Lifetime */
+ if (rfapiGetVncLifetime(bpi->attr, &lifetime)) {
+ r = snprintf(p, REMAIN, " nolife");
+ INCP;
+ } else {
+ if (lifetime == 0xffffffff)
+ r = snprintf(p, REMAIN, " %6s", "infini");
+ else
+ r = snprintf(p, REMAIN, " %6u", lifetime);
+ INCP;
+ }
- /* RFP option lengths */
- for (pEncap = bpi->attr->vnc_subtlvs; pEncap;
- pEncap = pEncap->next) {
+ /* RFP option lengths */
+ for (pEncap = bpi->attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) {
- if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) {
- if (printed_1st_gol) {
- r = snprintf(p, REMAIN, ",");
- INCP;
- } else {
- r = snprintf(p, REMAIN,
- " "); /* leading space */
- INCP;
- }
- r = snprintf(p, REMAIN, "%d", pEncap->length);
+ if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) {
+ if (printed_1st_gol) {
+ r = snprintf(p, REMAIN, ",");
+ INCP;
+ } else {
+ r = snprintf(p, REMAIN,
+ " "); /* leading space */
INCP;
- printed_1st_gol = 1;
}
- }
-
- /* RT list */
- if (bpi->attr->ecommunity) {
- s = ecommunity_ecom2str(bpi->attr->ecommunity,
- ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- r = snprintf(p, REMAIN, " %s", s);
+ r = snprintf(p, REMAIN, "%d", pEncap->length);
INCP;
- XFREE(MTYPE_ECOMMUNITY_STR, s);
+ printed_1st_gol = 1;
}
}
+ /* RT list */
+ if (bpi->attr->ecommunity) {
+ s = ecommunity_ecom2str(bpi->attr->ecommunity,
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ r = snprintf(p, REMAIN, " %s", s);
+ INCP;
+ XFREE(MTYPE_ECOMMUNITY_STR, s);
+ }
+
r = snprintf(p, REMAIN, " bpi@%p", bpi);
INCP;
@@ -628,21 +624,17 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi)
INCP;
}
- if (bpi->attr) {
-
- if (bpi->attr->weight) {
- r = snprintf(p, REMAIN, " W=%d", bpi->attr->weight);
- INCP;
- }
+ if (bpi->attr->weight) {
+ r = snprintf(p, REMAIN, " W=%d", bpi->attr->weight);
+ INCP;
+ }
- if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
- r = snprintf(p, REMAIN, " LP=%d",
- bpi->attr->local_pref);
- INCP;
- } else {
- r = snprintf(p, REMAIN, " LP=unset");
- INCP;
- }
+ if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
+ r = snprintf(p, REMAIN, " LP=%d", bpi->attr->local_pref);
+ INCP;
+ } else {
+ r = snprintf(p, REMAIN, " LP=unset");
+ INCP;
}
r = snprintf(p, REMAIN, " %c:%u", zebra_route_char(bpi->type),
@@ -1087,16 +1079,13 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
* See rfapi_import.c'rfapiRouteInfo2NextHopEntry() for conversion
* back to cost.
*/
- if (bpi->attr) {
- uint32_t local_pref;
- if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
- local_pref = bpi->attr->local_pref;
- else
- local_pref = 0;
- cost = (local_pref > 255) ? 0 : 255 - local_pref;
- } else {
- cost = 0;
- }
+ uint32_t local_pref;
+
+ if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
+ local_pref = bpi->attr->local_pref;
+ else
+ local_pref = 0;
+ cost = (local_pref > 255) ? 0 : 255 - local_pref;
fp(out, "%-20s ", buf_pfx);
fp(out, "%-15s ", buf_vn);
@@ -4719,8 +4708,6 @@ static int vnc_add_vrf_prefix(struct vty *vty, const char *arg_vrf,
rfapiQprefix2Rprefix(&pfx, &rpfx);
memset(optary, 0, sizeof(optary));
if (arg_rd) {
- if (opt != NULL)
- opt->next = &optary[cur_opt];
opt = &optary[cur_opt++];
opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
if (!str2prefix_rd(arg_rd, &opt->v.internal_rd)) {
diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c
index eb2d0fd88..df0610553 100644
--- a/bgpd/rfapi/vnc_import_bgp.c
+++ b/bgpd/rfapi/vnc_import_bgp.c
@@ -476,25 +476,19 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi(
plifetime = &lifetime;
}
- if (bpi->attr) {
- encaptlvs = bpi->attr->vnc_subtlvs;
- if (bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_RESERVED
- && bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_MPLS) {
- if (opt != NULL)
- opt->next = &optary[cur_opt];
- opt = &optary[cur_opt++];
- memset(opt, 0, sizeof(struct rfapi_un_option));
- opt->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE;
- opt->v.tunnel.type = bpi->attr->encap_tunneltype;
- /* TBD parse bpi->attr->extra->encap_subtlvs */
- }
- } else {
- encaptlvs = NULL;
+ encaptlvs = bpi->attr->vnc_subtlvs;
+ if (bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_RESERVED
+ && bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_MPLS) {
+ opt = &optary[cur_opt++];
+ memset(opt, 0, sizeof(struct rfapi_un_option));
+ opt->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE;
+ opt->v.tunnel.type = bpi->attr->encap_tunneltype;
+ /* TBD parse bpi->attr->extra->encap_subtlvs */
}
struct ecommunity *new_ecom = ecommunity_dup(ecom);
- if (bpi->attr && bpi->attr->ecommunity)
+ if (bpi->attr->ecommunity)
ecommunity_merge(new_ecom, bpi->attr->ecommunity);
if (bpi->extra)
@@ -635,12 +629,8 @@ static void vnc_import_bgp_add_route_mode_resolve_nve(
}
local_pref = calc_local_pref(info->attr, info->peer);
- if (info->attr
- && (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) {
-
+ if (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
med = &info->attr->med;
- }
-
/*
* At this point, we have allocated:
@@ -1103,7 +1093,7 @@ static void vnc_import_bgp_del_route_mode_plain(struct bgp *bgp,
* Compute VN address
*/
- if (info && info->attr) {
+ if (info) {
rfapiUnicastNexthop2Prefix(afi, info->attr, &vn_pfx_space);
} else {
vnc_zlog_debug_verbose("%s: no attr, can't delete route",
@@ -1489,12 +1479,9 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
}
local_pref = calc_local_pref(pb->ubpi->attr, pb->ubpi->peer);
- if (pb->ubpi->attr
- && (pb->ubpi->attr->flag
- & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) {
-
+ if (pb->ubpi->attr->flag
+ & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
med = &pb->ubpi->attr->med;
- }
/*
* Sanity check
@@ -1729,11 +1716,6 @@ static void vnc_import_bgp_exterior_add_route_it(
return;
}
- if (!info->attr) {
- vnc_zlog_debug_verbose("%s: no info, skipping", __func__);
- return;
- }
-
/*
* Extract nexthop from exterior route
*
@@ -1920,11 +1902,6 @@ void vnc_import_bgp_exterior_del_route(
return;
}
- if (!info->attr) {
- vnc_zlog_debug_verbose("%s: no info, skipping", __func__);
- return;
- }
-
/*
* Extract nexthop from exterior route
*
diff --git a/configure.ac b/configure.ac
index 6c1b35b5f..6147ebf0d 100755
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@
##
AC_PREREQ([2.60])
-AC_INIT([frr], [7.2-dev], [https://github.com/frrouting/frr/issues])
+AC_INIT([frr], [7.3-dev], [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/"
AC_SUBST([PACKAGE_URL])
PACKAGE_FULLNAME="FRRouting"
@@ -328,8 +328,8 @@ if test "$enable_thread_sanitizer" = "yes"; then
])
fi
if test "$enable_memory_sanitizer" = "yes"; then
- AC_C_FLAG([-fsanitize=thread -fPIE -pie], [
- AC_MSG_ERROR([$CC does not support Thread Sanitizer.])
+ AC_C_FLAG([-fsanitize=memory -fPIE -pie], [
+ AC_MSG_ERROR([$CC does not support Memory Sanitizer.])
], [
SAN_FLAGS="-fsanitize=memory -fPIE -pie"
])
@@ -536,6 +536,8 @@ AC_ARG_ENABLE([backtrace],
AS_HELP_STRING([--disable-backtrace,], [disable crash backtraces (default autodetect)]))
AC_ARG_ENABLE([time-check],
AS_HELP_STRING([--disable-time-check], [disable slow thread warning messages]))
+AC_ARG_ENABLE([cpu-time],
+ AS_HELP_STRING([--disable-cpu-time], [disable cpu usage data gathering]))
AC_ARG_ENABLE([pcreposix],
AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions]))
AC_ARG_ENABLE([fpm],
@@ -614,6 +616,14 @@ if test x"${enable_time_check}" != x"no" ; then
fi
fi
+case "${enable_cpu_time}" in
+ "no")
+ AC_DEFINE([EXCLUDE_CPU_TIME], [1], [Exclude getrusage data gathering])
+ ;;
+ "*")
+ ;;
+esac
+
case "${enable_systemd}" in
"no") ;;
"yes")
@@ -1452,6 +1462,12 @@ if test "x$enable_pcreposix" = "xyes"; then
fi
AC_SUBST([HAVE_LIBPCREPOSIX])
+dnl ##########################################################################
+dnl test "${enable_clippy_only}" != "yes"
+fi
+dnl END OF LARGE if block
+dnl ##########################################################################
+
dnl ------------------
dnl check C-Ares library
dnl ------------------
@@ -1462,12 +1478,6 @@ PKG_CHECK_MODULES([CARES], [libcares], [
])
AM_CONDITIONAL([CARES], [$c_ares_found])
-dnl ##########################################################################
-dnl test "${enable_clippy_only}" != "yes"
-fi
-dnl END OF LARGE if block
-dnl ##########################################################################
-
dnl ----------------------------------------------------------------------------
dnl figure out if domainname is available in the utsname struct (GNU extension).
@@ -1535,9 +1545,11 @@ case "$host_os" in
no)
;;
yes)
+ if test "${enable_clippy_only}" != "yes"; then
if test "$c_ares_found" != "true" ; then
AC_MSG_ERROR([nhrpd requires libcares. Please install c-ares and its -dev headers.])
fi
+ fi
NHRPD="nhrpd"
;;
*)
@@ -2041,9 +2053,11 @@ if test "${enable_capabilities}" != "no"; then
case "$host_os" in
linux*)
+ if test "${enable_clippy_only}" != "yes"; then
if test "$frr_ac_lcaps" != "yes"; then
AC_MSG_ERROR([libcap and/or its headers were not found. Running FRR without libcap support built in causes a huge performance penalty.])
fi
+ fi
;;
esac
else
diff --git a/doc/developer/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst
new file mode 100644
index 000000000..ff95aa04a
--- /dev/null
+++ b/doc/developer/frr-release-procedure.rst
@@ -0,0 +1,181 @@
+.. _frr-release-procedure:
+
+FRR Release Procedure
+=====================
+
+``<version>`` - version to be released, e.g. 7.3
+``origin`` - FRR upstream repository
+
+1. Checkout ``dev/<version>``.
+
+ .. code-block:: console
+
+ git checkout dev/<version>
+
+2. Create and push a new branch called ``stable/<version>`` based on the
+ ``dev/<version>`` branch.
+
+ .. code-block:: console
+
+ git checkout -b stable/<version>
+ git push origin stable/<version>:refs/heads/stable/<version>
+
+3. Update Changelog for Red Hat Packages:
+
+ Edit :file:`redhat/frr.spec.in` and look for the ``%changelog`` section:
+
+ - Change last (top of list) entry from ``%{version}`` to the **last**
+ released version number. For example, if ``<version>`` is ``7.3`` and the
+ last public release was ``7.2``, you would use ``7.2``, changing the file
+ like so::
+
+ * Tue Nov 7 2017 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+
+ to::
+
+ * Tue Nov 7 2017 Martin Winter <mwinter@opensourcerouting.org> - 7.2
+
+ - Add new entry to the top of the list with ``%{version}`` tag. Make sure
+ to watch the format, i.e. the day is always 2 characters, with the 1st
+ character being a space if the day is one digit.
+
+ - Add the changelog text below this entry.
+
+4. Update Changelog for Debian Packages:
+
+ Edit :file:`changelog-auto.in`:
+
+ - Change last (top of list) entry from ``@VERSION@`` to the **last**
+ released version number. For example, if ``<version>`` is ``7.3`` and the
+ last public release was ``7.2``, you would use ``7.2``, changing the file
+ like so::
+
+ frr (@VERSION@) RELEASED; urgency=medium
+
+ to::
+
+ frr (7.2) RELEASED; urgency=medium
+
+ - Add a new entry to the top of the list with a ``@VERSION@`` tag. Make sure
+ to watch the format.
+
+ - Add the changelog text below this entry.
+
+ - Verify the changelog format using ``dpkg-parsechangelog``. In the
+ repository root:
+
+ .. code-block:: console
+
+ dpkg-parsechangelog
+
+ You should see output like this::
+
+ vagrant@local ~/frr> dpkg-parsechangelog
+ Source: frr
+ Version: 7.3-dev-0
+ Distribution: UNRELEASED
+ Urgency: medium
+ Maintainer: FRRouting-Dev <dev@lists.frrouting.org>
+ Timestamp: 1540478210
+ Date: Thu, 25 Oct 2018 16:36:50 +0200
+ Changes:
+ frr (7.3-dev-0) RELEASED; urgency=medium
+ .
+ * Your Changes Here
+
+5. Change main version number:
+
+ - Edit :file:`configure.ac` and change version in the ``AC_INIT`` command
+ to ``<version>``
+
+6. Commit the changes, adding the changelog to the commit message. Follow all
+ existing commit guidelines.
+
+7. Create and submit a GitHub pull request, with the ``HEAD`` set to
+ ``stable/<version>`` and the base set to the upstream ``master`` branch.
+ Allow NetDef CI to complete its run and verify that all package builds were
+ successful.
+
+8. Create a git tag for the version:
+
+ .. code-block:: console
+
+ git tag -a frr-<version> -m "FRRouting Release <version>"
+
+9. Push the commit and new tag.
+
+ .. code-block:: console
+
+ git push origin stable/<version>:refs/head/stable/<version>
+ git push origin frr-<version>
+
+10. Kick off the Release build plan on the CI system for the correct release.
+ Contact Martin Winter for this step. Ensure all release packages build
+ successfully.
+
+11. Kick off the Snapcraft build plan for the release.
+
+12. Acquire the release RPM binary packages from Martin Winter.
+
+13. On GitHub, go to the <https://github.com/FRRouting/frr/releases>_ and click
+ "Draft a new release". Write a release announcement. The release
+ announcement should follow the template in
+ ``release-announcement-template.md``, located next to this document. Check
+ for spelling errors, and optionally (but preferably) have other maintainers
+ proofread the announcement text.
+
+ Attach **only** the binary RPM packages to the GitHub release using
+ GitHub's attachment functionality. Do not attach Debian packages. Do not
+ attach source tarballs - these will be generated and attached by GitHub
+ automatically. Do not publish the release yet.
+
+14. Contact the current Debian maintainer for FRR to get new Debian packages
+ built and published on our APT repository at https://deb.frrouting.net/.
+ Ensure the webpage text is updated. Verify that new packages install
+ successfully on a vanilla Debian installation using the instructions on the
+ webpage.
+
+15. Deploy Snapcraft release (after CI system finishes the tests for snapcraft
+ testplan).
+
+16. Update the Read The Docs instance to being publishing documentation built
+ off the ``stable/<version>`` branch. Contact Quentin Young for this step.
+
+17. Publish the GitHub release.
+
+18. Clone the ``frr-www`` repository:
+
+ .. code-block:: console
+
+ git clone https://github.com/FRRouting/frr-www.git
+
+19. Add a new release announcement, using a previous announcement as template:
+
+ .. code-block:: console
+
+ cp <old-version>-launch.md <version>-launch.md
+
+ Paste the GitHub release announcement text into this document, and **remove
+ line breaks**. In other words, this::
+
+ This is one continuous
+ sentence that should be
+ rendered on one line
+
+ Needs to be changed to this::
+
+ This is one continuous sentence that should be rendered on one line
+
+ This is very important otherwise the announcement will be unreadable on the
+ website.
+
+ Make sure to add a link to the GitHub releases page at the top.
+
+ Once finished, manually add a new entry into ``index.html`` to link to this
+ new announcement. Look at past commits to see how to do this.
+
+20. Deploy the updated ``frr-www`` on the frrouting.org web server and verify
+ that the announcement text is visible.
+
+21. Send an email to ``announce@lists.frrouting.org``. The text of this email
+ should include the text from the GitHub release.
diff --git a/doc/developer/maintainer-release-build.rst b/doc/developer/maintainer-release-build.rst
deleted file mode 100644
index 779217303..000000000
--- a/doc/developer/maintainer-release-build.rst
+++ /dev/null
@@ -1,89 +0,0 @@
-Release Build Procedure for FRR Maintainers
-===========================================
-
-1. Rename branch (if needed)
-
-.. code-block:: shell
-
- git clone git@github.com:FRRouting/frr.git
- cd frr
- git checkout dev/5.0
- git push origin :refs/heads/dev/5.0
- git push origin dev/5.0:refs/heads/stable/5.0
-
-2. Checkout the new stable branch:
-
-.. code-block:: shell
-
- git checkout stable/5.0
-
-3. Update Changelog for RedHat Package:
-
- Edit :file:`redhat/frr.spec.in` and look for the ``%changelog`` section:
-
- - Change last (top of list) entry from ``%{version}`` to previous fixed
- version number, i.e.::
-
- * Tue Nov 7 2017 Martin Winter <mwinter@opensourcerouting.org> - %{version}
-
- to::
-
- * Tue Nov 7 2017 Martin Winter <mwinter@opensourcerouting.org> - 3.0.2
-
- - Add new entry to the top of the list with ``%{version}`` tag and changelog
- for version.
- Make sure to watch the format, i.e. the day is always 2 characters, with
- the 1st character being a space if the day is one digit.
-
-4. Update Changelog for Debian Packages:
-
- Edit :file:`debian/changelog-auto.in`:
-
- - Change last (top of list) entry from ``@VERSION@`` to previous fixed
- version number, i.e.::
-
- frr (@VERSION@) RELEASED; urgency=medium
-
- to::
-
- frr (3.0.2) RELEASED; urgency=medium
-
- - Add a new entry to the top of the list with a ``@VERSION@`` tag and
- changelog for version.
-
-5. Change main version number:
-
- - Edit :file:`configure.ac` and change version in the ``AC_INIT`` command
- - Create a new entry with the version as ``%{version}`` tag
-
-6. Test building at least a Red Hat and Ubuntu package (or create a PR to have
- the CI system test them)
-
-7. Commit the changes, adding the changelog to the commit message
-
-8. Create a git tag for the version:
-
- .. code-block:: shell
-
- git tag -a frr-5.0 -m "FRRouting Release 5.0"
-
-9. Push the commit and tag(s) and watch for errors on CI:
-
- .. code-block:: shell
-
- git push
- git push --tags
-
-10. Kick off the Release build plan on the CI system for the correct release
-
-11. Send a Release Announcement with changes to
- ``announce@lists.frrouting.org``
-
-12. Kick off the Snapcraft build plan for the correct release
-
-13. After CI plans succeed, release on GitHub by going to
- https://github.com/FRRouting/frr/releases and selecting "Draft a new
- release".
-
-14. Deploy Snapcraft release (after CI system finishes the tests for snapcraft
- testplan)
diff --git a/doc/developer/memtypes.rst b/doc/developer/memtypes.rst
index 13f6b43bb..e04049001 100644
--- a/doc/developer/memtypes.rst
+++ b/doc/developer/memtypes.rst
@@ -48,10 +48,16 @@ Definition
should be used to create these, but in some cases it is useful to pass a
``struct memtype *`` pointer to some helper function.
- The ``MTYPE_name`` created by the macros is declared as an array, i.e.
+ The ``MTYPE_name`` created by the macros is declared as a pointer, i.e.
a function taking a ``struct memtype *`` argument can be called with an
``MTYPE_name`` argument (as opposed to ``&MTYPE_name``.)
+ .. note::
+
+ As ``MTYPE_name`` is a variable assigned from ``&_mt_name`` and not a
+ constant expression, it cannot be used as initializer for static
+ variables. In the case please fall back to ``&_mt_name``.
+
.. c:macro:: DECLARE_MGROUP(name)
This macro forward-declares a memory group and should be placed in a
diff --git a/doc/developer/packaging.rst b/doc/developer/packaging.rst
index b174a9660..0c072e4d1 100644
--- a/doc/developer/packaging.rst
+++ b/doc/developer/packaging.rst
@@ -1,10 +1,10 @@
-*********
-Packaging
-*********
+********************
+Releases & Packaging
+********************
.. toctree::
:maxdepth: 2
- maintainer-release-build
+ frr-release-procedure
packaging-debian
packaging-redhat
diff --git a/doc/developer/release-announcement-template.md b/doc/developer/release-announcement-template.md
new file mode 100644
index 000000000..658b87ead
--- /dev/null
+++ b/doc/developer/release-announcement-template.md
@@ -0,0 +1,40 @@
+<!---
+name: release-announcement-template
+about: Template to use when drafing a new release announcement. DELETE THIS
+ BLOCK BEFORE PUBLISHING.
+--->
+
+We are pleased to announce FRR <version>.
+
+<!-- Add a brief summary of major changes here -->
+
+Thank you to all contributors!
+
+Changelog
+---------
+
+<!-- List **only** user-visible changes in this section. When listing changes to individual daemons, alphabetize the list by daemon name. -->
+
+**All daemons:**
+- <!-- List changes to all daemons -->
+
+<!-- If a new daemon was added, list it at the top here -->
+**New daemon: <new>**
+- Adds support for <protocol/feature>
+
+**daemon 1**
+- <!-- List changes -->
+
+**daemon 2**
+- <!-- List changes -->
+
+**daemon N**
+- <!-- List changes -->
+
+### Internal improvements
+
+- <!-- List **only** user-invisible changes here -->
+
+### Packaging changes
+
+- <!-- List any new or removed packages here -->
diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am
index 557a41c51..2c49d6b87 100644
--- a/doc/developer/subdir.am
+++ b/doc/developer/subdir.am
@@ -26,6 +26,7 @@ dev_RSTFILES = \
doc/developer/building.rst \
doc/developer/cli.rst \
doc/developer/conf.py \
+ doc/developer/frr-release-procedure.rst \
doc/developer/hooks.rst \
doc/developer/include-compile.rst \
doc/developer/index.rst \
@@ -33,7 +34,6 @@ dev_RSTFILES = \
doc/developer/lists.rst \
doc/developer/locking.rst \
doc/developer/logging.rst \
- doc/developer/maintainer-release-build.rst \
doc/developer/memtypes.rst \
doc/developer/modules.rst \
doc/developer/next-hop-tracking.rst \
@@ -55,6 +55,7 @@ EXTRA_DIST += \
$(dev_RSTFILES) \
doc/developer/draft-zebra-00.ms \
doc/developer/ldpd-basic-test-setup.md \
+ doc/developer/release-announcement-template.md \
# end
DEVBUILD = doc/developer/_build
diff --git a/doc/developer/topotests-jsontopo.rst b/doc/developer/topotests-jsontopo.rst
index 65bdcbe9c..130f072b6 100644
--- a/doc/developer/topotests-jsontopo.rst
+++ b/doc/developer/topotests-jsontopo.rst
@@ -6,54 +6,54 @@ FRRouting Topology Tests with Mininet
*************************************
Overview
-########
+========
On top of current topotests framework following enhancements are done:
-#.
- Creating the topology and assigning IPs to router' interfaces dynamically.\ :raw-html-m2r:`<br>`
+#. Creating the topology and assigning IPs to router' interfaces dynamically.\ :raw-html-m2r:`<br>`
It is achieved by using json file, in which user specify the number of routers,
links to each router, interfaces for the routers and protocol configurations for
all routers.
-#.
- Creating the configurations dynamically. It is achieved by using
+#. Creating the configurations dynamically. It is achieved by using
/usr/lib/frr/frr-reload.py utility, which takes running configuration and the
newly created configuration for any particular router and creates a delta
file(diff file) and loads it to router.
Logging of test case executions
-###############################
+===============================
#. User can enable logging of testcases execution messages into log file by
adding "frrtest_log_dir = /tmp/topotests/" in pytest.ini file
-#. Router's current configuration can be displyed on console or sent to logs by
+#.Router's current configuration can be displyed on console or sent to logs by
adding "show_router_config = True" in pytest.ini file
Log file name will be displayed when we start execution:
-root@test:~/topotests/example-topojson-test/test_topo_json_single_link# python
-test_topo_json_single_link.py Logs will be sent to logfile:
-/tmp/topotests/test_topo_json_single_link_11:57:01.353797
+
+.. code-block:: console
+
+ root@test:~/topotests/example-topojson-test/test_topo_json_single_link# python
+ test_topo_json_single_link.py Logs will be sent to logfile:
+ /tmp/topotests/test_topo_json_single_link_11:57:01.353797
Note: directory "/tmp/topotests/" is created by topotests by default, making
use of same directory to save execution logs.
Guidelines
-##########
+==========
Writing New Tests
-=================
-
+-----------------
-This section will guide you in all recommended steps to produce a standard topology test.
+This section will guide you in all recommended steps to produce a standard
+topology test.
This is the recommended test writing routine:
-
* Create a json file , which will have routers and protocol configurations
* Create topology from json
* Create configuration from json
@@ -61,7 +61,7 @@ This is the recommended test writing routine:
* Create a Pull Request
File Hierarchy
-==============
+--------------
Before starting to write any tests one must know the file hierarchy. The
repository hierarchy looks like this:
@@ -85,292 +85,289 @@ repository hierarchy looks like this:
./lib/bgp.py # library to create only bgp configurations
Defining the Topology and initial configuration in JSON file
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The first step to write a new test is to define the topology and initial
configuration. User has to define topology and initial configuration in JSON
-file. Here is an example of JSON file.
-
-.. code-block::
-
- BGP neihghborship with single phy-link, sample JSON file:
- {
- "ipv4base": "192.168.0.0",
- "ipv4mask": 30,
- "ipv6base": "fd00::",
- "ipv6mask": 64,
- "link_ip_start": {"ipv4": "192.168.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
- "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:DB8:F::", "v6mask": 128},
- "routers": {
- "r1": {
- "links": {
- "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
- "r2": {"ipv4": "auto", "ipv6": "auto"},
- "r3": {"ipv4": "auto", "ipv6": "auto"}
- },
- "bgp": {
- "local_as": "64512",
- "address_family": {
- "ipv4": {
- "unicast": {
- "neighbor": {
- "r2": {
- "dest_link": {
- "r1": {}
- }
- },
- "r3": {
- "dest_link": {
- "r1": {}
- }
- }
- }
- }
- }
- }
- }
- },
- "r2": {
- "links": {
- "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
- "r1": {"ipv4": "auto", "ipv6": "auto"},
- "r3": {"ipv4": "auto", "ipv6": "auto"}
- },
- "bgp": {
- "local_as": "64512",
- "address_family": {
- "ipv4": {
- "unicast": {
- "redistribute": [
- {
- "redist_type": "static"
- }
- ],
- "neighbor": {
- "r1": {
- "dest_link": {
- "r2": {}
- }
- },
- "r3": {
- "dest_link": {
- "r2": {}
- }
- }
- }
- }
- }
- }
- }
- }
- ...
-
-
- BGP neighboship with loopback interface, sample JSON file:
- {
- "ipv4base": "192.168.0.0",
- "ipv4mask": 30,
- "ipv6base": "fd00::",
- "ipv6mask": 64,
- "link_ip_start": {"ipv4": "192.168.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
- "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:DB8:F::", "v6mask": 128},
- "routers": {
- "r1": {
- "links": {
- "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback",
- "add_static_route":"yes"},
- "r2": {"ipv4": "auto", "ipv6": "auto"}
- },
- "bgp": {
- "local_as": "64512",
- "address_family": {
- "ipv4": {
- "unicast": {
- "neighbor": {
- "r2": {
- "dest_link": {
- "lo": {
- "source_link": "lo"
- }
- }
- }
- }
- }
- }
- }
- },
- "static_routes": [
- {
- "network": "1.0.2.17/32",
- "next_hop": "192.168.0.1
- }
- ]
- },
- "r2": {
- "links": {
- "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback",
- "add_static_route":"yes"},
- "r1": {"ipv4": "auto", "ipv6": "auto"},
- "r3": {"ipv4": "auto", "ipv6": "auto"}
- },
- "bgp": {
- "local_as": "64512",
- "address_family": {
- "ipv4": {
- "unicast": {
- "redistribute": [
- {
- "redist_type": "static"
- }
- ],
- "neighbor": {
- "r1": {
- "dest_link": {
- "lo": {
- "source_link": "lo"
- }
- }
- },
- "r3": {
- "dest_link": {
- "lo": {
- "source_link": "lo"
- }
- }
- }
- }
- }
- }
- }
- },
- "static_routes": [
- {
- "network": "192.0.20.1/32",
- "no_of_ip": 9,
- "admin_distance": 100,
- "next_hop": "192.168.0.1",
- "tag": 4001
- }
- ],
- }
- ...
-
- BGP neighborship with Multiple phy-links, sample JSON file:
- {
- "ipv4base": "192.168.0.0",
- "ipv4mask": 30,
- "ipv6base": "fd00::",
- "ipv6mask": 64,
- "link_ip_start": {"ipv4": "192.168.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
- "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:DB8:F::", "v6mask": 128},
- "routers": {
- "r1": {
- "links": {
- "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
- "r2-link1": {"ipv4": "auto", "ipv6": "auto"},
- "r2-link2": {"ipv4": "auto", "ipv6": "auto"}
- },
- "bgp": {
- "local_as": "64512",
- "address_family": {
- "ipv4": {
- "unicast": {
- "neighbor": {
- "r2": {
- "dest_link": {
- "r1-link1": {}
- }
- }
- }
- }
- }
- }
- }
- },
- "r2": {
- "links": {
- "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
- "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
- "r1-link2": {"ipv4": "auto", "ipv6": "auto"},
- "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
- "r3-link2": {"ipv4": "auto", "ipv6": "auto"}
- },
- "bgp": {
- "local_as": "64512",
- "address_family": {
- "ipv4": {
- "unicast": {
- "redistribute": [
- {
- "redist_type": "static"
- }
- ],
- "neighbor": {
- "r1": {
- "dest_link": {
- "r2-link1": {}
- }
- },
- "r3": {
- "dest_link": {
- "r2-link1": {}
- }
- }
- }
- }
- }
- }
- }
- }
- ...
-
-
-JSON file explained
+file. Here is an example of JSON file::
+
+ BGP neihghborship with single phy-link, sample JSON file:
+ {
+ "ipv4base": "192.168.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {"ipv4": "192.168.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:DB8:F::", "v6mask": 128},
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "64512",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "64512",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static"
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ...
+
+
+BGP neighboship with loopback interface, sample JSON file::
+
+ {
+ "ipv4base": "192.168.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {"ipv4": "192.168.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:DB8:F::", "v6mask": 128},
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback",
+ "add_static_route":"yes"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "64512",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "lo": {
+ "source_link": "lo"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "static_routes": [
+ {
+ "network": "1.0.2.17/32",
+ "next_hop": "192.168.0.1
+ }
+ ]
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback",
+ "add_static_route":"yes"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "64512",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static"
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "lo": {
+ "source_link": "lo"
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "lo": {
+ "source_link": "lo"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "static_routes": [
+ {
+ "network": "192.0.20.1/32",
+ "no_of_ip": 9,
+ "admin_distance": 100,
+ "next_hop": "192.168.0.1",
+ "tag": 4001
+ }
+ ],
+ }
+ ...
+
+BGP neighborship with Multiple phy-links, sample JSON file::
+
+ {
+ "ipv4base": "192.168.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {"ipv4": "192.168.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:DB8:F::", "v6mask": 128},
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "64512",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "64512",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static"
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ...
+
+
+JSON File Explained
"""""""""""""""""""
Mandatory keywords/options in JSON:
-
-* "ipv4base" : base ipv4 address to generate ips, ex - 192.168.0.0
-* "ipv4mask" : mask for ipv4 address, ex - 30
-* "ipv6base" : base ipv6 address to generate ips, ex - fd00:
-* "ipv6mask" : mask for ipv6 address, ex - 64
-* "link_ip_start" : physical interface base ipv4 and ipv6 address
-* "lo_prefix" : loopback interface base ipv4 and ipv6 address
-* "routers" : user can add number of routers as per topology, router's name
+* ``ipv4base`` : base ipv4 address to generate ips, ex - 192.168.0.0
+* ``ipv4mask`` : mask for ipv4 address, ex - 30
+* ``ipv6base`` : base ipv6 address to generate ips, ex - fd00:
+* ``ipv6mask`` : mask for ipv6 address, ex - 64
+* ``link_ip_start`` : physical interface base ipv4 and ipv6 address
+* ``lo_prefix`` : loopback interface base ipv4 and ipv6 address
+* ``routers`` : user can add number of routers as per topology, router's name
can be any logical name, ex- r1 or a0.
-* "r1" : name of the router
-* "lo" : loopback interface dict, ipv4 and/or ipv6 addresses generated automatically
-* "type" : type of interface, to identify loopback interface
-* "links" : physical interfaces dict, ipv4 and/or ipv6 addresses generated
+* ``r1`` : name of the router
+* ``lo`` : loopback interface dict, ipv4 and/or ipv6 addresses generated automatically
+* ``type`` : type of interface, to identify loopback interface
+* ``links`` : physical interfaces dict, ipv4 and/or ipv6 addresses generated
automatically
-* "r2-link1" : it will be used when routers have multiple links. 'r2' is router
+* ``r2-link1`` : it will be used when routers have multiple links. 'r2' is router
name, 'link' is any logical name, '1' is to identify link number,
- router name and link must be seperated by hyphen ("-"), ex- a0-peer1
+ router name and link must be seperated by hyphen (``-``), ex- a0-peer1
Optional keywords/options in JSON:
-* "bgp" : bgp configuration
-* "local_as" : Local AS number
-* "unicast" : All SAFI configuration
-* "neighbor": All neighbor details
-* "dest_link" : Destination link to which router will connect
-* "router_id" : bgp router-id
-* "source_link" : if user wants to establish bgp neighborship with loopback
- interface, add "source_link": "lo"
-* "keepalivetimer" : Keep alive timer for BGP neighbor
-* "holddowntimer" : Hold down timer for BGP neighbor
-* "static_routes" : create static routes for routers
-* "redistribute" : redistribute static and/or connected routes
-* "prefix_lists" : create Prefix-lists for routers
+* ``bgp`` : bgp configuration
+* ``local_as`` : Local AS number
+* ``unicast`` : All SAFI configuration
+* ``neighbor``: All neighbor details
+* ``dest_link`` : Destination link to which router will connect
+* ``router_id`` : bgp router-id
+* ``source_link`` : if user wants to establish bgp neighborship with loopback
+ interface, add ``source_link``: ``lo``
+* ``keepalivetimer`` : Keep alive timer for BGP neighbor
+* ``holddowntimer`` : Hold down timer for BGP neighbor
+* ``static_routes`` : create static routes for routers
+* ``redistribute`` : redistribute static and/or connected routes
+* ``prefix_lists`` : create Prefix-lists for routers
Building topology and configurations
""""""""""""""""""""""""""""""""""""
Topology and initial configuration will be created in setup_module(). Following
-is the sample code:
-
-.. code-block::
+is the sample code::
class TemplateTopo(Topo):
def build(self, *_args, **_opts):
@@ -438,38 +435,38 @@ to be used to reference the routers configuration file location
Example:
-* The topology class that inherits from Mininet Topo class
+* The topology class that inherits from Mininet Topo class;
-.. code-block::
-
- class TemplateTopo(Topo):
- def build(self, *_args, **_opts):
- tgen = get_topogen(self)
- # topology build code
+ .. code-block:: python
+ class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+ # topology build code
-* pytest setup_module() and teardown_module() to start the topology
-.. code-block::
+* pytest setup_module() and teardown_module() to start the topology:
- def setup_module(_m):
- tgen = Topogen(TemplateTopo)
+ .. code-block:: python
- # Starting topology, create tmp files which are loaded to routers
- # to start deamons and then start routers
- start_topology(tgen, CWD)
+ def setup_module(_m):
+ tgen = Topogen(TemplateTopo)
- def teardown_module(_m):
- tgen = get_topogen()
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, CWD)
- # Stop toplogy and Remove tmp files
- stop_topology(tgen, CWD)
+ def teardown_module(_m):
+ tgen = get_topogen()
+ # Stop toplogy and Remove tmp files
+ stop_topology(tgen, CWD)
-* __main__ initialization code (to support running the script directly)
-.. code-block::
+* ``__main__`` initialization code (to support running the script directly)
- if **name** == '\ **main**\ ':
- sys.exit(pytest.main(["-s"]))
+ .. code-block:: python
+
+ if **name** == '\ **main**\ ':
+ sys.exit(pytest.main(["-s"]))
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index a0a574a79..c2e72e2ec 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -189,11 +189,8 @@ for ``master`` branch:
git clone https://github.com/FRRouting/frr.git
cd frr
./bootstrap.sh
- export CC=gcc
- export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer"
- export LD=gcc
- export LDFLAGS="-g -fsanitize=address -ldl"
- ./configure --enable-shared=no \
+ ./configure \
+ --enable-address-sanitizer \
--prefix=/usr/lib/frr --sysconfdir=/etc/frr \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr --bindir=/usr/lib/frr \
diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst
index 3c6887fba..c2e3724df 100644
--- a/doc/developer/workflow.rst
+++ b/doc/developer/workflow.rst
@@ -113,6 +113,9 @@ Security fixes are backported to all releases less than or equal to at least one
year old. Security fixes may also be backported to older releases depending on
severity.
+For detailed instructions on how to produce an FRR release, refer to
+:ref:`frr-release-procedure`.
+
Long term support branches ( LTS )
-----------------------------------------
@@ -499,8 +502,11 @@ your new claim at the end of the list.
Code Formatting
---------------
-FRR uses Linux kernel style except where noted below. Code which does not
-comply with these style guidelines will not be accepted.
+C Code
+^^^^^^
+
+For C code, FRR uses Linux kernel style except where noted below. Code which
+does not comply with these style guidelines will not be accepted.
The project provides multiple tools to allow you to correctly style your code
as painlessly as possible, primarily built around ``clang-format``.
@@ -707,6 +713,28 @@ BSD coding style applies to:
- ``ldpd/``
+YANG
+^^^^
+
+FRR uses YANG to define data models for its northbound interface. YANG models
+should follow conventions used by the IETF standard models. From a practical
+standpoint, this corresponds to the output produced by the ``yanglint`` tool
+included in the ``libyang`` project, which is used by FRR to parse and validate
+YANG models. You should run the following command on all YANG documents you
+write:
+
+.. code-block:: console
+
+ yanglint -f yang <model>
+
+The output of this command should be identical to the input file. The sole
+exception to this is comments. ``yanglint`` does not support comments and will
+strip them from its output. You may include comments in your YANG documents,
+but they should be indented appropriately (use spaces). Where possible,
+comments should be eschewed in favor of a suitable ``description`` statement.
+
+In short, a diff between your input file and the output of ``yanglint`` should
+either be empty or contain only comments.
Specific Exceptions
^^^^^^^^^^^^^^^^^^^
diff --git a/doc/manpages/bgpd.rst b/doc/manpages/bgpd.rst
index f1736ffd0..079aad8c4 100644
--- a/doc/manpages/bgpd.rst
+++ b/doc/manpages/bgpd.rst
@@ -21,6 +21,48 @@ OPTIONS available for the |DAEMON| command:
.. include:: common-options.rst
+.. option:: -p, --bgp_port <port>
+
+ Set the bgp protocol's port number. When port number is 0, that means do not
+ listen bgp port.
+
+.. option:: -l, --listenon
+
+ Specify a specific IP address for bgpd to listen on, rather than its default
+ of ``0.0.0.0`` / ``::``. This can be useful to constrain bgpd to an internal
+ address, or to run multiple bgpd processes on one host.
+
+.. option:: -n, --no_kernel
+
+ Do not install learned routes into the linux kernel. This option is useful
+ for a route-reflector environment or if you are running multiple bgp
+ processes in the same namespace. This option is different than the --no_zebra
+ option in that a ZAPI connection is made.
+
+.. option:: -S, --skip_runas
+
+ Skip the normal process of checking capabilities and changing user and group
+ information.
+
+.. option:: -e, --ecmp
+
+ Run BGP with a limited ecmp capability, that is different than what BGP
+ was compiled with. The value specified must be greater than 0 and less
+ than or equal to the MULTIPATH_NUM specified on compilation.
+
+.. option:: -Z, --no_zebra
+
+ Do not communicate with zebra at all. This is different than the --no_kernel
+ option in that we do not even open a ZAPI connection to the zebra process.
+
+.. option:: -s, --socket_size
+
+ When opening tcp connections to our peers, set the socket send buffer
+ size that the kernel will use for the peers socket. This option
+ is only really useful at a very large scale. Experimentation should
+ be done to see if this is helping or not at the scale you are running
+ at.
+
LABEL MANAGER
-------------
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 5509fd5f0..c7d722164 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -451,7 +451,8 @@ Terminal Mode Commands
This command displays system run statistics for all the different event
types. If no options is specified all different run types are displayed
together. Additionally you can ask to look at (r)ead, (w)rite, (t)imer,
- (e)vent and e(x)ecute thread event types.
+ (e)vent and e(x)ecute thread event types. If you have compiled with
+ disable-cpu-time then this command will not show up.
.. index:: show thread poll
.. clicmd:: show thread poll
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 32ca5707d..525a31d48 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -79,8 +79,8 @@ BFDd Commands
`vrf` selects which domain we want to use.
-.. index:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]
-.. clicmd:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]
+.. index:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}]
+.. clicmd:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}]
Stops and removes the selected peer.
@@ -89,8 +89,8 @@ BFDd Commands
Show all configured BFD peers information and current status.
-.. index:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
-.. clicmd:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
+.. index:: show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
+.. clicmd:: show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
Show status for a specific BFD peer.
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 7b3cdf2c4..b916fcf41 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -35,6 +35,44 @@ be specified (:ref:`common-invocation-options`).
of ``0.0.0.0`` / ``::``. This can be useful to constrain bgpd to an internal
address, or to run multiple bgpd processes on one host.
+.. option:: -n, --no_kernel
+
+ Do not install learned routes into the linux kernel. This option is useful
+ for a route-reflector environment or if you are running multiple bgp
+ processes in the same namespace. This option is different than the --no_zebra
+ option in that a ZAPI connection is made.
+
+.. option:: -S, --skip_runas
+
+ Skip the normal process of checking capabilities and changing user and group
+ information.
+
+.. option:: -e, --ecmp
+
+ Run BGP with a limited ecmp capability, that is different than what BGP
+ was compiled with. The value specified must be greater than 0 and less
+ than or equal to the MULTIPATH_NUM specified on compilation.
+
+.. option:: -Z, --no_zebra
+
+ Do not communicate with zebra at all. This is different than the --no_kernel
+ option in that we do not even open a ZAPI connection to the zebra process.
+
+.. option:: -s, --socket_size
+
+ When opening tcp connections to our peers, set the socket send buffer
+ size that the kernel will use for the peers socket. This option
+ is only really useful at a very large scale. Experimentation should
+ be done to see if this is helping or not at the scale you are running
+ at.
+
+LABEL MANAGER
+-------------
+
+.. option:: -I, --int_num
+
+ Set zclient id. This is required when using Zebra label manager in proxy mode.
+
.. _bgp-basic-concepts:
Basic Concepts
@@ -1063,6 +1101,13 @@ Configuring Peers
on by default or not. This command defaults to on and is not displayed.
The `no bgp default ipv4-unicast` form of the command is displayed.
+.. index:: [no] neighbor PEER advertisement-interval (0-600)
+.. clicmd:: [no] neighbor PEER advertisement-interval (0-600)
+
+ Setup the minimum route advertisement interval(mrai) for the
+ peer in question. This number is between 0 and 600 seconds,
+ with the default advertisement interval being 0.
+
.. _bgp-peer-filtering:
Peer Filtering
@@ -1140,11 +1185,8 @@ Capability Negotiation
Negotiation. Please use *dont-capability-negotiate* command to disable the
feature.
-.. index:: neighbor PEER dont-capability-negotiate
-.. clicmd:: neighbor PEER dont-capability-negotiate
-
-.. index:: no neighbor PEER dont-capability-negotiate
-.. clicmd:: no neighbor PEER dont-capability-negotiate
+.. index:: [no] neighbor PEER dont-capability-negotiate
+.. clicmd:: [no] neighbor PEER dont-capability-negotiate
Suppress sending Capability Negotiation as OPEN message optional parameter
to the peer. This command only affects the peer is configured other than
@@ -1159,6 +1201,11 @@ Capability Negotiation
configured by *override-capability*, *bgpd* ignores received capabilities
then override negotiated capabilities with configured values.
+ Additionally the operator should be reminded that this feature fundamentally
+ disables the ability to use widely deployed BGP features. BGP unnumbered,
+ hostname support, AS4, Addpath, Route Refresh, ORF, Dynamic Capabilities,
+ and graceful restart.
+
.. index:: neighbor PEER override-capability
.. clicmd:: neighbor PEER override-capability
@@ -1175,16 +1222,16 @@ AS Path Access Lists
AS path access list is user defined AS path.
-.. index:: ip as-path access-list WORD permit|deny LINE
-.. clicmd:: ip as-path access-list WORD permit|deny LINE
+.. index:: bgp as-path access-list WORD permit|deny LINE
+.. clicmd:: bgp as-path access-list WORD permit|deny LINE
This command defines a new AS path access list.
-.. index:: no ip as-path access-list WORD
-.. clicmd:: no ip as-path access-list WORD
+.. index:: no bgp as-path access-list WORD
+.. clicmd:: no bgp as-path access-list WORD
-.. index:: no ip as-path access-list WORD permit|deny LINE
-.. clicmd:: no ip as-path access-list WORD permit|deny LINE
+.. index:: no bgp as-path access-list WORD permit|deny LINE
+.. clicmd:: no bgp as-path access-list WORD permit|deny LINE
.. _bgp-using-as-path-in-route-map:
@@ -1351,8 +1398,8 @@ expanded
interpreted on each use expanded community lists are slower than standard
lists.
-.. index:: ip community-list standard NAME permit|deny COMMUNITY
-.. clicmd:: ip community-list standard NAME permit|deny COMMUNITY
+.. index:: bgp community-list standard NAME permit|deny COMMUNITY
+.. clicmd:: bgp community-list standard NAME permit|deny COMMUNITY
This command defines a new standard community list. ``COMMUNITY`` is
communities value. The ``COMMUNITY`` is compiled into community structure.
@@ -1362,8 +1409,8 @@ expanded
community list definition. When there is no matched entry, deny will be
returned. When ``COMMUNITY`` is empty it matches to any routes.
-.. index:: ip community-list expanded NAME permit|deny COMMUNITY
-.. clicmd:: ip community-list expanded NAME permit|deny COMMUNITY
+.. index:: bgp community-list expanded NAME permit|deny COMMUNITY
+.. clicmd:: bgp community-list expanded NAME permit|deny COMMUNITY
This command defines a new expanded community list. ``COMMUNITY`` is a
string expression of communities attribute. ``COMMUNITY`` can be a regular
@@ -1374,8 +1421,8 @@ expanded
.. deprecated:: 5.0
It is recommended to use the more explicit versions of this command.
-.. index:: ip community-list NAME permit|deny COMMUNITY
-.. clicmd:: ip community-list NAME permit|deny COMMUNITY
+.. index:: bgp community-list NAME permit|deny COMMUNITY
+.. clicmd:: bgp community-list NAME permit|deny COMMUNITY
When the community list type is not specified, the community list type is
automatically detected. If ``COMMUNITY`` can be compiled into communities
@@ -1384,29 +1431,29 @@ expanded
for backward compatibility. Use of this feature is not recommended.
-.. index:: no ip community-list [standard|expanded] NAME
-.. clicmd:: no ip community-list [standard|expanded] NAME
+.. index:: no bgp community-list [standard|expanded] NAME
+.. clicmd:: no bgp community-list [standard|expanded] NAME
Deletes the community list specified by ``NAME``. All community lists share
the same namespace, so it's not necessary to specify ``standard`` or
``expanded``; these modifiers are purely aesthetic.
-.. index:: show ip community-list [NAME]
-.. clicmd:: show ip community-list [NAME]
+.. index:: show bgp community-list [NAME]
+.. clicmd:: show bgp community-list [NAME]
Displays community list information. When ``NAME`` is specified the
specified community list's information is shown.
::
- # show ip community-list
+ # show bgp community-list
Named Community standard list CLIST
permit 7675:80 7675:100 no-export
deny internet
Named Community expanded list EXPAND
permit :
- # show ip community-list CLIST
+ # show bgp community-list CLIST
Named Community standard list CLIST
permit 7675:80 7675:100 no-export
deny internet
@@ -1424,14 +1471,14 @@ to 199 is expanded community list. These community lists are called
as numbered community lists. On the other hand normal community lists
is called as named community lists.
-.. index:: ip community-list (1-99) permit|deny COMMUNITY
-.. clicmd:: ip community-list (1-99) permit|deny COMMUNITY
+.. index:: bgp community-list (1-99) permit|deny COMMUNITY
+.. clicmd:: bgp community-list (1-99) permit|deny COMMUNITY
This command defines a new community list. The argument to (1-99) defines
the list identifier.
-.. index:: ip community-list (100-199) permit|deny COMMUNITY
-.. clicmd:: ip community-list (100-199) permit|deny COMMUNITY
+.. index:: bgp community-list (100-199) permit|deny COMMUNITY
+.. clicmd:: bgp community-list (100-199) permit|deny COMMUNITY
This command defines a new expanded community list. The argument to
(100-199) defines the list identifier.
@@ -1497,12 +1544,12 @@ setting BGP communities attribute to the updates.
neighbor 192.168.0.1 route-map RMAP in
exit-address-family
!
- ip community-list 70 permit 7675:70
- ip community-list 70 deny
- ip community-list 80 permit 7675:80
- ip community-list 80 deny
- ip community-list 90 permit 7675:90
- ip community-list 90 deny
+ bgp community-list 70 permit 7675:70
+ bgp community-list 70 deny
+ bgp community-list 80 permit 7675:80
+ bgp community-list 80 deny
+ bgp community-list 90 permit 7675:90
+ bgp community-list 90 deny
!
route-map RMAP permit 10
match community 70
@@ -1551,7 +1598,7 @@ announcements into the internal network.
neighbor 192.168.0.1 route-map RMAP in
exit-address-family
!
- ip community-list 1 permit 0:80 0:90
+ bgp community-list 1 permit 0:80 0:90
!
route-map RMAP permit in
match community 1
@@ -1570,8 +1617,8 @@ community-list.
neighbor 192.168.0.1 route-map RMAP in
exit-address-family
!
- ip community-list standard FILTER deny 1:1
- ip community-list standard FILTER permit
+ bgp community-list standard FILTER deny 1:1
+ bgp community-list standard FILTER permit
!
route-map RMAP permit 10
match community FILTER
@@ -1584,8 +1631,8 @@ if the route does not have communities attribute at all. So community list
.. code-block:: frr
- ip community-list standard INTERNET deny 1:1
- ip community-list standard INTERNET permit internet
+ bgp community-list standard INTERNET deny 1:1
+ bgp community-list standard INTERNET permit internet
The following configuration is an example of communities value deletion. With
@@ -1601,7 +1648,7 @@ community-list is used. ``deny`` community-list is ignored.
neighbor 192.168.0.1 route-map RMAP in
exit-address-family
!
- ip community-list standard DEL permit 100:1 100:2
+ bgp community-list standard DEL permit 100:1 100:2
!
route-map RMAP permit 10
set comm-list DEL delete
@@ -1646,8 +1693,8 @@ the other is IP address based format.
Extended Community Lists
^^^^^^^^^^^^^^^^^^^^^^^^
-.. index:: ip extcommunity-list standard NAME permit|deny EXTCOMMUNITY
-.. clicmd:: ip extcommunity-list standard NAME permit|deny EXTCOMMUNITY
+.. index:: bgp extcommunity-list standard NAME permit|deny EXTCOMMUNITY
+.. clicmd:: bgp extcommunity-list standard NAME permit|deny EXTCOMMUNITY
This command defines a new standard extcommunity-list. `extcommunity` is
extended communities value. The `extcommunity` is compiled into extended
@@ -1658,37 +1705,37 @@ Extended Community Lists
there is no matched entry, deny will be returned. When `extcommunity` is
empty it matches to any routes.
-.. index:: ip extcommunity-list expanded NAME permit|deny LINE
-.. clicmd:: ip extcommunity-list expanded NAME permit|deny LINE
+.. index:: bgp extcommunity-list expanded NAME permit|deny LINE
+.. clicmd:: bgp extcommunity-list expanded NAME permit|deny LINE
This command defines a new expanded extcommunity-list. `line` is a string
expression of extended communities attribute. `line` can be a regular
expression (:ref:`bgp-regular-expressions`) to match an extended communities
attribute in BGP updates.
-.. index:: no ip extcommunity-list NAME
-.. clicmd:: no ip extcommunity-list NAME
+.. index:: no bgp extcommunity-list NAME
+.. clicmd:: no bgp extcommunity-list NAME
-.. index:: no ip extcommunity-list standard NAME
-.. clicmd:: no ip extcommunity-list standard NAME
+.. index:: no bgp extcommunity-list standard NAME
+.. clicmd:: no bgp extcommunity-list standard NAME
-.. index:: no ip extcommunity-list expanded NAME
-.. clicmd:: no ip extcommunity-list expanded NAME
+.. index:: no bgp extcommunity-list expanded NAME
+.. clicmd:: no bgp extcommunity-list expanded NAME
These commands delete extended community lists specified by `name`. All of
extended community lists shares a single name space. So extended community
lists can be removed simply specifying the name.
-.. index:: show ip extcommunity-list
-.. clicmd:: show ip extcommunity-list
+.. index:: show bgp extcommunity-list
+.. clicmd:: show bgp extcommunity-list
-.. index:: show ip extcommunity-list NAME
-.. clicmd:: show ip extcommunity-list NAME
+.. index:: show bgp extcommunity-list NAME
+.. clicmd:: show bgp extcommunity-list NAME
This command displays current extcommunity-list information. When `name` is
specified the community list's information is shown.::
- # show ip extcommunity-list
+ # show bgp extcommunity-list
.. _bgp-extended-communities-in-route-map:
@@ -1749,8 +1796,8 @@ Large Community Lists
Two types of large community lists are supported, namely `standard` and
`expanded`.
-.. index:: ip large-community-list standard NAME permit|deny LARGE-COMMUNITY
-.. clicmd:: ip large-community-list standard NAME permit|deny LARGE-COMMUNITY
+.. index:: bgp large-community-list standard NAME permit|deny LARGE-COMMUNITY
+.. clicmd:: bgp large-community-list standard NAME permit|deny LARGE-COMMUNITY
This command defines a new standard large-community-list. `large-community`
is the Large Community value. We can add multiple large communities under
@@ -1760,8 +1807,8 @@ Two types of large community lists are supported, namely `standard` and
definition. When there is no matched entry, a deny will be returned. When
`large-community` is empty it matches any routes.
-.. index:: ip large-community-list expanded NAME permit|deny LINE
-.. clicmd:: ip large-community-list expanded NAME permit|deny LINE
+.. index:: bgp large-community-list expanded NAME permit|deny LINE
+.. clicmd:: bgp large-community-list expanded NAME permit|deny LINE
This command defines a new expanded large-community-list. Where `line` is a
string matching expression, it will be compared to the entire Large
@@ -1769,24 +1816,24 @@ Two types of large community lists are supported, namely `standard` and
lowest to highest. `line` can also be a regular expression which matches
this Large Community attribute.
-.. index:: no ip large-community-list NAME
-.. clicmd:: no ip large-community-list NAME
+.. index:: no bgp large-community-list NAME
+.. clicmd:: no bgp large-community-list NAME
-.. index:: no ip large-community-list standard NAME
-.. clicmd:: no ip large-community-list standard NAME
+.. index:: no bgp large-community-list standard NAME
+.. clicmd:: no bgp large-community-list standard NAME
-.. index:: no ip large-community-list expanded NAME
-.. clicmd:: no ip large-community-list expanded NAME
+.. index:: no bgp large-community-list expanded NAME
+.. clicmd:: no bgp large-community-list expanded NAME
These commands delete Large Community lists specified by `name`. All Large
Community lists share a single namespace. This means Large Community lists
can be removed by simply specifying the name.
-.. index:: show ip large-community-list
-.. clicmd:: show ip large-community-list
+.. index:: show bgp large-community-list
+.. clicmd:: show bgp large-community-list
-.. index:: show ip large-community-list NAME
-.. clicmd:: show ip large-community-list NAME
+.. index:: show bgp large-community-list NAME
+.. clicmd:: show bgp large-community-list NAME
This command display current large-community-list information. When
`name` is specified the community list information is shown.
@@ -2165,6 +2212,8 @@ Dumping Messages and Routing Tables
Other BGP Commands
------------------
+The following are available in the top level *enable* mode:
+
.. index:: clear bgp \*
.. clicmd:: clear bgp \*
@@ -2200,6 +2249,24 @@ Other BGP Commands
Clear peer using soft reconfiguration in this address-family and sub-address-family.
+The following are available in the ``router bgp`` mode:
+
+.. index:: write-quanta (1-64)
+.. clicmd:: write-quanta (1-64)
+
+ BGP message Tx I/O is vectored. This means that multiple packets are written
+ to the peer socket at the same time each I/O cycle, in order to minimize
+ system call overhead. This value controls how many are written at a time.
+ Under certain load conditions, reducing this value could make peer traffic
+ less 'bursty'. In practice, leave this settings on the default (64) unless
+ you truly know what you are doing.
+
+.. index:: read-quanta (1-10)
+.. clicmd:: read-quanta (1-10)
+
+ Unlike Tx, BGP Rx traffic is not vectored. Packets are read off the wire one
+ at a time in a loop. This setting controls how many iterations the loop runs
+ for. As with write-quanta, it is best to leave this setting on the default.
.. _bgp-displaying-bgp-information:
@@ -2396,6 +2463,23 @@ Displaying Routes by AS Path
Print a summary of neighbor connections for the specified AFI/SAFI combination.
+Displaying Update Group Information
+-----------------------------------
+
+..index:: show bgp update-groups SUBGROUP-ID [advertise-queue|advertised-routes|packet-queue]
+..clicmd:: show bgp update-groups [advertise-queue|advertised-routes|packet-queue]
+
+ Display Information about each individual update-group being used.
+ If SUBGROUP-ID is specified only display about that particular group. If
+ advertise-queue is specified the list of routes that need to be sent
+ to the peers in the update-group is displayed, advertised-routes means
+ the list of routes we have sent to the peers in the update-group and
+ packet-queue specifies the list of packets in the queue to be sent.
+
+..index:: show bgp update-groups statistics
+..clicmd:: show bgp update-groups statistics
+
+ Display Information about update-group events in FRR.
.. _bgp-route-reflector:
@@ -2598,26 +2682,26 @@ certainly contains silly mistakes, if not serious flaws.
! 2X00 - set local_preference to X00
!
! blackhole the prefix of the route
- ip community-list standard cm-blackhole permit 64512:100
+ bgp community-list standard cm-blackhole permit 64512:100
!
! set no-export community before advertising
- ip community-list standard cm-set-no-export permit 64512:200
+ bgp community-list standard cm-set-no-export permit 64512:200
!
! advertise only to other customers
- ip community-list standard cm-cust-only permit 64512:300
+ bgp community-list standard cm-cust-only permit 64512:300
!
! advertise only to upstreams
- ip community-list standard cm-upstream-only permit 64512:400
+ bgp community-list standard cm-upstream-only permit 64512:400
!
! advertise to upstreams with no-export
- ip community-list standard cm-upstream-noexport permit 64512:500
+ bgp community-list standard cm-upstream-noexport permit 64512:500
!
! set local-pref to least significant 3 digits of the community
- ip community-list standard cm-prefmod-100 permit 64512:2100
- ip community-list standard cm-prefmod-200 permit 64512:2200
- ip community-list standard cm-prefmod-300 permit 64512:2300
- ip community-list standard cm-prefmod-400 permit 64512:2400
- ip community-list expanded cme-prefmod-range permit 64512:2...
+ bgp community-list standard cm-prefmod-100 permit 64512:2100
+ bgp community-list standard cm-prefmod-200 permit 64512:2200
+ bgp community-list standard cm-prefmod-300 permit 64512:2300
+ bgp community-list standard cm-prefmod-400 permit 64512:2400
+ bgp community-list expanded cme-prefmod-range permit 64512:2...
!
! Informational communities
!
@@ -2625,9 +2709,9 @@ certainly contains silly mistakes, if not serious flaws.
! 3100 - learned from customer
! 3200 - learned from peer
!
- ip community-list standard cm-learnt-upstream permit 64512:3000
- ip community-list standard cm-learnt-cust permit 64512:3100
- ip community-list standard cm-learnt-peer permit 64512:3200
+ bgp community-list standard cm-learnt-upstream permit 64512:3000
+ bgp community-list standard cm-learnt-cust permit 64512:3100
+ bgp community-list standard cm-learnt-peer permit 64512:3200
!
! ###################################################################
! Utility route-maps
diff --git a/doc/user/filter.rst b/doc/user/filter.rst
index 8c86d0608..98b768412 100644
--- a/doc/user/filter.rst
+++ b/doc/user/filter.rst
@@ -9,11 +9,24 @@ defined, it can be applied in any direction.
IP Access List
==============
-.. index:: access-list NAME permit IPV4-NETWORK
-.. clicmd:: access-list NAME permit IPV4-NETWORK
+.. index:: access-list NAME [seq (1-4294967295)] permit IPV4-NETWORK
+.. clicmd:: access-list NAME [seq (1-4294967295)] permit IPV4-NETWORK
-.. index:: access-list NAME deny IPV4-NETWORK
-.. clicmd:: access-list NAME deny IPV4-NETWORK
+.. index:: access-list NAME [seq (1-4294967295)] deny IPV4-NETWORK
+.. clicmd:: access-list NAME [seq (1-4294967295)] deny IPV4-NETWORK
+
+ seq
+ seq `number` can be set either automatically or manually. In the
+ case that sequential numbers are set manually, the user may pick any
+ number less than 4294967295. In the case that sequential number are set
+ automatically, the sequential number will increase by a unit of five (5)
+ per list. If a list with no specified sequential number is created
+ after a list with a specified sequential number, the list will
+ automatically pick the next multiple of five (5) as the list number.
+ For example, if a list with number 2 already exists and a new list with
+ no specified number is created, the next list will be numbered 5. If
+ lists 2 and 7 already exist and a new list with no specified number is
+ created, the new list will be numbered 10.
Basic filtering is done by `access-list` as shown in the
following example.
@@ -22,6 +35,7 @@ IP Access List
access-list filter deny 10.0.0.0/9
access-list filter permit 10.0.0.0/8
+ access-list filter seq 13 permit 10.0.0.0/7
IP Prefix List
diff --git a/doc/user/installation.rst b/doc/user/installation.rst
index 45549dcca..392a2dd78 100644
--- a/doc/user/installation.rst
+++ b/doc/user/installation.rst
@@ -302,6 +302,23 @@ options from the list below.
Build the Sysrepo northbound plugin.
+.. option:: --enable-time-check XXX
+
+ When this is enabled with a XXX value in microseconds, any thread that
+ runs for over this value will cause a warning to be issued to the log.
+ If you do not specify any value or don't include this option then
+ the default time is 5 seconds. If --disable-time-check is specified
+ then no warning is issued for any thread run length.
+
+.. option:: --disable-cpu-time
+
+ Disable cpu process accounting, this command also disables the `show thread cpu`
+ command. If this option is disabled, --enable-time-check is ignored. This
+ disabling of cpu time effectively means that the getrusage call is skipped.
+ Since this is a process switch into the kernel, systems with high FRR
+ load might see improvement in behavior. Be aware that `show thread cpu`
+ is considered a good data gathering tool from the perspective of developers.
+
You may specify any combination of the above options to the configure
script. By default, the executables are placed in :file:`/usr/local/sbin`
and the configuration files in :file:`/usr/local/etc`. The :file:`/usr/local/`
diff --git a/doc/user/overview.rst b/doc/user/overview.rst
index 5f9a7b937..24d9ece93 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -230,6 +230,8 @@ features with system dependencies are included here.
+-----------------------------------+----------------+--------------+------------+------------+------------+
| EVPN BUM Forwarding | :mark:`≥5.0` | :mark:`N` | :mark:`N` | :mark:`N` | :mark:`N` |
+-----------------------------------+----------------+--------------+------------+------------+------------+
+| `vrrpd` (VRRP) | :mark:`≥5.1` | :mark:`N` | :mark:`N` | :mark:`N` | :mark:`N` |
++-----------------------------------+----------------+--------------+------------+------------+------------+
The indicators have the following semantics:
diff --git a/doc/user/pim.rst b/doc/user/pim.rst
index 805d6264a..4f9c573a2 100644
--- a/doc/user/pim.rst
+++ b/doc/user/pim.rst
@@ -201,14 +201,15 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
.. clicmd:: ip pim sm
Tell pim that we would like to use this interface to form pim neighbors
- over. Please note we will *not* accept igmp reports over this interface with
- this command.
+ over. Please note that this command does not enable the reception of IGMP
+ reports on the interface. Refer to the next `ip igmp` command for IGMP
+ management.
.. index:: ip igmp
.. clicmd:: ip igmp
Tell pim to receive IGMP reports and Query on this interface. The default
- version is v3. This command is useful on the LHR.
+ version is v3. This command is useful on a LHR.
.. index:: ip igmp join A.B.C.D A.B.C.D
.. clicmd:: ip igmp join A.B.C.D A.B.C.D
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index e36783d17..5c2b41b63 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -306,6 +306,11 @@ Route Map Set Command
Set BGP route origin.
+.. index:: set table (1-4294967295)
+.. clicmd:: set table (1-4294967295)
+
+ Set the BGP table to a given table identifier
+
.. _route-map-call-command:
Route Map Call Command
diff --git a/doc/user/vrrp.rst b/doc/user/vrrp.rst
index a2dd95098..435580131 100644
--- a/doc/user/vrrp.rst
+++ b/doc/user/vrrp.rst
@@ -108,19 +108,18 @@ Suppose you have an interface ``eth0`` with the following configuration:
.. code-block:: console
- $ ip link show eth0
+ $ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 02:17:45:00:aa:aa brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic eth0
valid_lft 72532sec preferred_lft 72532sec
- inet 10.0.2.16/24 brd 10.0.2.255 scope global dynamic eth0
- valid_lft 72532sec preferred_lft 72532sec
inet6 fe80::17:45ff:fe00:aaaa/64 scope link
valid_lft forever preferred_lft forever
-Suppose the address you want to back up is ``10.0.2.16``, and will be managed
-by the virtual router with id ``5``. A macvlan device with the appropriate MAC
-address must be created before VRRP can begin to operate.
+Suppose that the IPv4 and IPv6 addresses you want to back up are ``10.0.2.16``
+and ``2001:db8::370:7334``, and that they will be managed by the virtual router
+with id ``5``. A macvlan device with the appropriate MAC address must be created
+before VRRP can begin to operate.
If you are using ``ifupdown2``, the configuration is as follows:
@@ -171,6 +170,8 @@ Using ``vrrp4-2-1`` as an example, a few things to note about this interface:
egress via ``eth0``
- Its MAC address is set to the VRRP IPv4 virtual MAC specified by the RFC for
:abbr:`VRID (Virtual Router ID)` ``5``
+- The :abbr:`VIP (Virtual IP)` address ``10.0.2.16`` must not be present on
+ the parent interface ``eth0``.
- The link local address on the interface is not derived from the interface
MAC
@@ -426,10 +427,11 @@ Show commands, global defaults and debugging configuration commands.
VRID will only show routers with that VRID. Specifying ``json`` will dump
each router state in a JSON array.
-.. index:: debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}]
-.. clicmd:: debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}]
+.. index:: [no] debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}]
+.. clicmd:: [no] debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}]
- Toggle debugging logs for some or all components of VRRP.
+ Toggle debugging logs for VRRP components.
+ If no component is specified, debugging for all components are turned on/off.
protocol
Logs state changes, election protocol decisions, and interface status
@@ -482,7 +484,8 @@ execute the following command:
.. clicmd:: [no] vrrp autoconfigure [version (2-3)]
Generates VRRP configuration based on the interface configuration on the
- base system. Any existing interfaces that are configured properly for VRRP -
+ base system. If the protocol version is not specified, the default is VRRPv3.
+ Any existing interfaces that are configured properly for VRRP -
i.e. have the correct MAC address, link local address (when required), IPv4
and IPv6 addresses - are used to create a VRRP router on their parent
interfaces, with VRRP IPvX addresses taken from the addresses assigned to
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index b7283d83d..2099dfdd6 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -663,19 +663,30 @@ kernel.
.. clicmd:: ip protocol PROTOCOL route-map ROUTEMAP
Apply a route-map filter to routes for the specified protocol. PROTOCOL can
- be **any** or one of
+ be:
- - system,
- - kernel,
+ - any,
+ - babel,
+ - bgp,
- connected,
- - static,
- - rip,
- - ripng,
+ - eigrp,
+ - isis,
+ - kernel,
+ - nhrp,
+ - openfabric,
- ospf,
- ospf6,
- - isis,
- - bgp,
- - hsls.
+ - rip,
+ - sharp,
+ - static,
+ - ripng,
+ - table,
+ - vnc.
+
+ If you choose any as the option that will cause all protocols that are sending
+ routes to zebra. You can specify a :dfn:`ip protocol PROTOCOL route-map ROUTEMAP`
+ on a per vrf basis, by entering this command under vrf mode for the vrf you
+ want to apply the route-map against.
.. index:: set src ADDRESS
.. clicmd:: set src ADDRESS
@@ -828,8 +839,22 @@ zebra Terminal Mode Commands
.. index:: show ipv6 route
.. clicmd:: show ipv6 route
-.. index:: show interface
-.. clicmd:: show interface
+.. index:: show [ip|ipv6] route [PREFIX] [nexthop-group]
+.. clicmd:: show [ip|ipv6] route [PREFIX] [nexthop-group]
+
+ Display detailed information about a route. If [nexthop-group] is
+ included, it will display the nexthop group ID the route is using as well.
+
+.. index:: show interface [NAME] [{vrf VRF|brief}] [nexthop-group]
+.. clicmd:: show interface [NAME] [{vrf VRF|brief}] [nexthop-group]
+
+.. index:: show interface [NAME] [{vrf all|brief}] [nexthop-group]
+.. clicmd:: show interface [NAME] [{vrf all|brief}] [nexthop-group]
+
+ Display interface information. If no extra information is added, it will
+ dump information on all interfaces. If [NAME] is specified, it will display
+ detailed information about that single interface. If [nexthop-group] is
+ specified, it will display nexthop groups pointing out that interface.
.. index:: show ip prefix-list [NAME]
.. clicmd:: show ip prefix-list [NAME]
@@ -886,3 +911,8 @@ zebra Terminal Mode Commands
Reset statistics related to the zebra code that interacts with the
optional Forwarding Plane Manager (FPM) component.
+.. index:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]
+.. clicmd:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]
+
+ Display nexthop groups created by zebra.
+
diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile
index 815983a39..88c8f88f8 100644
--- a/docker/alpine/Dockerfile
+++ b/docker/alpine/Dockerfile
@@ -9,7 +9,8 @@ RUN source /src/alpine/APKBUILD.in \
--no-cache \
--update-cache \
$makedepends \
- gzip
+ gzip \
+ && pip install pytest
COPY . /src
ARG PKGVER
@@ -29,6 +30,8 @@ RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/reposit
abuild \
alpine-conf \
alpine-sdk \
+ py-pip \
+ && pip install pytest \
&& setup-apkcache /var/cache/apk \
&& mkdir -p /pkgs/apk \
&& echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile
index 6ffdd0ccb..3f830348b 100644
--- a/docker/debian/Dockerfile
+++ b/docker/debian/Dockerfile
@@ -1,13 +1,20 @@
FROM debian:buster
MAINTAINER Rob Gil (rob@rem5.com)
+
ENV DEBIAN_FRONTEND noninteractive
ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
-RUN apt-get update
-RUN apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \
- libc-ares2 libjson-c3 vim systemd procps libreadline7 gnupg2 lsb-release apt-utils
+
+RUN apt-get update && \
+ apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \
+ libc-ares2 libjson-c3 vim procps libreadline7 gnupg2 lsb-release apt-utils && \
+ rm -rf /var/lib/apt/lists/*
+
RUN curl -s https://deb.frrouting.org/frr/keys.asc | apt-key add -
RUN echo deb https://deb.frrouting.org/frr $(lsb_release -s -c) frr-stable | tee -a /etc/apt/sources.list.d/frr.list
-RUN apt-get update
-RUN apt-get install -y frr frr-pythontools
+
+RUN apt-get update && \
+ apt-get install -y frr frr-pythontools && \
+ rm -rf /var/lib/apt/lists/*
+
ADD docker-start /usr/sbin/docker-start
ENTRYPOINT ["/usr/sbin/docker-start"]
diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c
index fd1d3f5cb..6294c0dd0 100644
--- a/eigrpd/eigrp_interface.c
+++ b/eigrpd/eigrp_interface.c
@@ -54,6 +54,7 @@
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_dump.h"
struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp,
struct prefix *p)
@@ -122,10 +123,101 @@ int eigrp_if_delete_hook(struct interface *ifp)
return 0;
}
+static int eigrp_ifp_create(struct interface *ifp)
+{
+ struct eigrp_interface *ei = ifp->info;
+
+ if (!ei)
+ return 0;
+
+ ei->params.type = eigrp_default_iftype(ifp);
+
+ eigrp_if_update(ifp);
+
+ return 0;
+}
+
+static int eigrp_ifp_up(struct interface *ifp)
+{
+ /* Interface is already up. */
+ if (if_is_operative(ifp)) {
+ /* Temporarily keep ifp values. */
+ struct interface if_tmp;
+ memcpy(&if_tmp, ifp, sizeof(struct interface));
+
+ if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
+ zlog_debug("Zebra: Interface[%s] state update.",
+ ifp->name);
+
+ if (if_tmp.bandwidth != ifp->bandwidth) {
+ if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
+ zlog_debug(
+ "Zebra: Interface[%s] bandwidth change %d -> %d.",
+ ifp->name, if_tmp.bandwidth,
+ ifp->bandwidth);
+
+ // eigrp_if_recalculate_output_cost (ifp);
+ }
+
+ if (if_tmp.mtu != ifp->mtu) {
+ if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
+ zlog_debug(
+ "Zebra: Interface[%s] MTU change %u -> %u.",
+ ifp->name, if_tmp.mtu, ifp->mtu);
+
+ /* Must reset the interface (simulate down/up) when MTU
+ * changes. */
+ eigrp_if_reset(ifp);
+ }
+ return 0;
+ }
+
+ if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
+ zlog_debug("Zebra: Interface[%s] state change to up.",
+ ifp->name);
+
+ if (ifp->info)
+ eigrp_if_up(ifp->info);
+
+ return 0;
+}
+
+static int eigrp_ifp_down(struct interface *ifp)
+{
+ if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
+ zlog_debug("Zebra: Interface[%s] state change to down.",
+ ifp->name);
+
+ if (ifp->info)
+ eigrp_if_down(ifp->info);
+
+ return 0;
+}
+
+static int eigrp_ifp_destroy(struct interface *ifp)
+{
+ if (if_is_up(ifp))
+ zlog_warn("Zebra: got delete of %s, but interface is still up",
+ ifp->name);
+
+ if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
+ zlog_debug(
+ "Zebra: interface delete %s index %d flags %llx metric %d mtu %d",
+ ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
+ ifp->metric, ifp->mtu);
+
+ if (ifp->info)
+ eigrp_if_free(ifp->info, INTERFACE_DOWN_BY_ZEBRA);
+
+ return 0;
+}
+
struct list *eigrp_iflist;
void eigrp_if_init(void)
{
+ if_zapi_callbacks(eigrp_ifp_create, eigrp_ifp_up,
+ eigrp_ifp_down, eigrp_ifp_destroy);
/* Initialize Zebra interface data structure. */
// hook_register_prio(if_add, 0, eigrp_if_new);
hook_register_prio(if_del, 0, eigrp_if_delete_hook);
diff --git a/eigrpd/eigrp_interface.h b/eigrpd/eigrp_interface.h
index a18b0b701..1e66dafde 100644
--- a/eigrpd/eigrp_interface.h
+++ b/eigrpd/eigrp_interface.h
@@ -63,5 +63,4 @@ extern uint32_t eigrp_scaled_to_bandwidth(uint32_t);
extern uint32_t eigrp_delay_to_scaled(uint32_t);
extern uint32_t eigrp_scaled_to_delay(uint32_t);
-
#endif /* ZEBRA_EIGRP_INTERFACE_H_ */
diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c
index c7ffbf9f0..3e09ec41b 100644
--- a/eigrpd/eigrp_network.c
+++ b/eigrpd/eigrp_network.c
@@ -55,12 +55,15 @@ static void eigrp_network_run_interface(struct eigrp *, struct prefix *,
int eigrp_sock_init(struct vrf *vrf)
{
- int eigrp_sock;
+ int eigrp_sock = -1;
int ret;
#ifdef IP_HDRINCL
int hincl = 1;
#endif
+ if (!vrf)
+ return eigrp_sock;
+
frr_with_privs(&eigrpd_privs) {
eigrp_sock = vrf_socket(
AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP, vrf->vrf_id,
diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c
index 63cbe84ef..9a0fdda0f 100644
--- a/eigrpd/eigrp_zebra.c
+++ b/eigrpd/eigrp_zebra.c
@@ -53,14 +53,8 @@
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
-static int eigrp_interface_add(ZAPI_CALLBACK_ARGS);
-static int eigrp_interface_delete(ZAPI_CALLBACK_ARGS);
static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS);
static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS);
-static int eigrp_interface_state_up(ZAPI_CALLBACK_ARGS);
-static int eigrp_interface_state_down(ZAPI_CALLBACK_ARGS);
-static struct interface *zebra_interface_if_lookup(struct stream *,
- vrf_id_t vrf_id);
static int eigrp_zebra_read_route(ZAPI_CALLBACK_ARGS);
@@ -114,10 +108,6 @@ void eigrp_zebra_init(void)
zclient_init(zclient, ZEBRA_ROUTE_EIGRP, 0, &eigrpd_privs);
zclient->zebra_connected = eigrp_zebra_connected;
zclient->router_id_update = eigrp_router_id_update_zebra;
- zclient->interface_add = eigrp_interface_add;
- zclient->interface_delete = eigrp_interface_delete;
- zclient->interface_up = eigrp_interface_state_up;
- zclient->interface_down = eigrp_interface_state_down;
zclient->interface_address_add = eigrp_interface_address_add;
zclient->interface_address_delete = eigrp_interface_address_delete;
zclient->redistribute_route_add = eigrp_zebra_read_route;
@@ -151,56 +141,6 @@ static int eigrp_zebra_read_route(ZAPI_CALLBACK_ARGS)
return 0;
}
-/* Inteface addition message from zebra. */
-static int eigrp_interface_add(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
- struct eigrp_interface *ei;
-
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
-
- if (!ifp->info)
- return 0;
-
- ei = ifp->info;
-
- ei->params.type = eigrp_default_iftype(ifp);
-
- eigrp_if_update(ifp);
-
- return 0;
-}
-
-static int eigrp_interface_delete(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
- struct stream *s;
-
- s = zclient->ibuf;
- /* zebra_interface_state_read () updates interface structure in iflist
- */
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- if (if_is_up(ifp))
- zlog_warn("Zebra: got delete of %s, but interface is still up",
- ifp->name);
-
- if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
- zlog_debug(
- "Zebra: interface delete %s index %d flags %llx metric %d mtu %d",
- ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
- ifp->metric, ifp->mtu);
-
- if (ifp->info)
- eigrp_if_free(ifp->info, INTERFACE_DOWN_BY_ZEBRA);
-
- if_set_index(ifp, IFINDEX_INTERNAL);
- return 0;
-}
-
static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS)
{
struct connected *c;
@@ -254,93 +194,6 @@ static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int eigrp_interface_state_up(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
-
- ifp = zebra_interface_if_lookup(zclient->ibuf, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- /* Interface is already up. */
- if (if_is_operative(ifp)) {
- /* Temporarily keep ifp values. */
- struct interface if_tmp;
- memcpy(&if_tmp, ifp, sizeof(struct interface));
-
- zebra_interface_if_set_value(zclient->ibuf, ifp);
-
- if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
- zlog_debug("Zebra: Interface[%s] state update.",
- ifp->name);
-
- if (if_tmp.bandwidth != ifp->bandwidth) {
- if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
- zlog_debug(
- "Zebra: Interface[%s] bandwidth change %d -> %d.",
- ifp->name, if_tmp.bandwidth,
- ifp->bandwidth);
-
- // eigrp_if_recalculate_output_cost (ifp);
- }
-
- if (if_tmp.mtu != ifp->mtu) {
- if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
- zlog_debug(
- "Zebra: Interface[%s] MTU change %u -> %u.",
- ifp->name, if_tmp.mtu, ifp->mtu);
-
- /* Must reset the interface (simulate down/up) when MTU
- * changes. */
- eigrp_if_reset(ifp);
- }
- return 0;
- }
-
- zebra_interface_if_set_value(zclient->ibuf, ifp);
-
- if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
- zlog_debug("Zebra: Interface[%s] state change to up.",
- ifp->name);
-
- if (ifp->info)
- eigrp_if_up(ifp->info);
-
- return 0;
-}
-
-static int eigrp_interface_state_down(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
- zlog_debug("Zebra: Interface[%s] state change to down.",
- ifp->name);
-
- if (ifp->info)
- eigrp_if_down(ifp->info);
-
- return 0;
-}
-
-static struct interface *zebra_interface_if_lookup(struct stream *s,
- vrf_id_t vrf_id)
-{
- char ifname_tmp[INTERFACE_NAMSIZ];
-
- /* Read interface name. */
- stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
-
- /* And look it up. */
- return if_lookup_by_name(ifname_tmp, vrf_id);
-}
-
void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p,
struct list *successors, uint32_t distance)
{
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
index bc6688012..232df14e1 100644
--- a/include/linux/fib_rules.h
+++ b/include/linux/fib_rules.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_FIB_RULES_H
#define __LINUX_FIB_RULES_H
@@ -22,13 +23,23 @@ struct fib_rule_hdr {
__u8 tos;
__u8 table;
- __u8 res1; /* reserved */
+ __u8 res1; /* reserved */
__u8 res2; /* reserved */
__u8 action;
__u32 flags;
};
+struct fib_rule_uid_range {
+ __u32 start;
+ __u32 end;
+};
+
+struct fib_rule_port_range {
+ __u16 start;
+ __u16 end;
+};
+
enum {
FRA_UNSPEC,
FRA_DST, /* destination address */
@@ -43,7 +54,7 @@ enum {
FRA_UNUSED5,
FRA_FWMARK, /* mark */
FRA_FLOW, /* flow/class id */
- FRA_UNUSED6,
+ FRA_TUN_ID,
FRA_SUPPRESS_IFGROUP,
FRA_SUPPRESS_PREFIXLEN,
FRA_TABLE, /* Extended table id */
@@ -51,6 +62,11 @@ enum {
FRA_OIFNAME,
FRA_PAD,
FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
+ FRA_UID_RANGE, /* UID range */
+ FRA_PROTOCOL, /* Originator of the rule */
+ FRA_IP_PROTO, /* ip proto */
+ FRA_SPORT_RANGE, /* sport */
+ FRA_DPORT_RANGE, /* dport */
__FRA_MAX
};
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
index a924606f3..dfcf3ce00 100644
--- a/include/linux/if_addr.h
+++ b/include/linux/if_addr.h
@@ -34,6 +34,7 @@ enum {
IFA_MULTICAST,
IFA_FLAGS,
IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */
+ IFA_TARGET_NETNSID,
__IFA_MAX,
};
@@ -63,7 +64,9 @@ struct ifa_cacheinfo {
};
/* backwards compatibility for userspace */
+#ifndef __KERNEL__
#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+#endif
#endif
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 156f4434c..fb79481cb 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* Linux ethernet bridge
*
@@ -10,8 +11,8 @@
* 2 of the License, or (at your option) any later version.
*/
-#ifndef _LINUX_IF_BRIDGE_H
-#define _LINUX_IF_BRIDGE_H
+#ifndef _UAPI_LINUX_IF_BRIDGE_H
+#define _UAPI_LINUX_IF_BRIDGE_H
#include <linux/types.h>
#include <linux/if_ether.h>
@@ -96,7 +97,7 @@ struct __fdb_entry {
__u32 ageing_timer_value;
__u8 port_hi;
__u8 pad0;
- __u16 unused;
+ __u16 vlan;
};
/* Bridge Flags */
@@ -236,6 +237,7 @@ struct br_mdb_entry {
#define MDB_PERMANENT 1
__u8 state;
#define MDB_FLAGS_OFFLOAD (1 << 0)
+#define MDB_FLAGS_FAST_LEAVE (1 << 1)
__u8 flags;
__u16 vid;
struct {
@@ -291,4 +293,4 @@ struct br_mcast_stats {
__u64 mcast_bytes[BR_MCAST_DIR_SIZE];
__u64 mcast_packets[BR_MCAST_DIR_SIZE];
};
-#endif /* _LINUX_IF_BRIDGE_H */
+#endif /* _UAPI_LINUX_IF_BRIDGE_H */
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 1f97d0560..22a45914a 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -1,5 +1,6 @@
-#ifndef _LINUX_IF_LINK_H
-#define _LINUX_IF_LINK_H
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_IF_LINK_H
+#define _UAPI_LINUX_IF_LINK_H
#include <linux/types.h>
#include <linux/netlink.h>
@@ -158,6 +159,14 @@ enum {
IFLA_PAD,
IFLA_XDP,
IFLA_EVENT,
+ IFLA_NEW_NETNSID,
+ IFLA_IF_NETNSID,
+ IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */
+ IFLA_CARRIER_UP_COUNT,
+ IFLA_CARRIER_DOWN_COUNT,
+ IFLA_NEW_IFINDEX,
+ IFLA_MIN_MTU,
+ IFLA_MAX_MTU,
__IFLA_MAX
};
@@ -165,8 +174,10 @@ enum {
#define IFLA_MAX (__IFLA_MAX - 1)
/* backwards compatibility for userspace */
+#ifndef __KERNEL__
#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+#endif
enum {
IFLA_INET_UNSPEC,
@@ -276,6 +287,7 @@ enum {
IFLA_BR_MCAST_STATS_ENABLED,
IFLA_BR_MCAST_IGMP_VERSION,
IFLA_BR_MCAST_MLD_VERSION,
+ IFLA_BR_VLAN_STATS_PER_PORT,
__IFLA_BR_MAX,
};
@@ -323,6 +335,14 @@ enum {
IFLA_BRPORT_MCAST_TO_UCAST,
IFLA_BRPORT_VLAN_TUNNEL,
IFLA_BRPORT_BCAST_FLOOD,
+ IFLA_BRPORT_GROUP_FWD_MASK,
+ IFLA_BRPORT_NEIGH_SUPPRESS,
+ IFLA_BRPORT_ISOLATED,
+ IFLA_BRPORT_BACKUP_PORT,
+ IFLA_BRPORT_PEER_LINK = 60, /* MLAG peer link */
+ IFLA_BRPORT_DUAL_LINK, /* MLAG Dual Connected link */
+ IFLA_BRPORT_GROUP_FWD_MASKHI,
+ IFLA_BRPORT_DUAL_LINK_READY,
__IFLA_BRPORT_MAX
};
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
@@ -448,6 +468,16 @@ enum {
#define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1)
+/* XFRM section */
+enum {
+ IFLA_XFRM_UNSPEC,
+ IFLA_XFRM_LINK,
+ IFLA_XFRM_IF_ID,
+ __IFLA_XFRM_MAX
+};
+
+#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1)
+
enum macsec_validation_type {
MACSEC_VALIDATE_DISABLED = 0,
MACSEC_VALIDATE_CHECK = 1,
@@ -460,6 +490,7 @@ enum macsec_validation_type {
enum {
IFLA_IPVLAN_UNSPEC,
IFLA_IPVLAN_MODE,
+ IFLA_IPVLAN_FLAGS,
__IFLA_IPVLAN_MAX
};
@@ -472,6 +503,9 @@ enum ipvlan_mode {
IPVLAN_MODE_MAX
};
+#define IPVLAN_F_PRIVATE 0x01
+#define IPVLAN_F_VEPA 0x02
+
/* VXLAN section */
enum {
IFLA_VXLAN_UNSPEC,
@@ -502,6 +536,7 @@ enum {
IFLA_VXLAN_COLLECT_METADATA,
IFLA_VXLAN_LABEL,
IFLA_VXLAN_GPE,
+ IFLA_VXLAN_TTL_INHERIT,
__IFLA_VXLAN_MAX
};
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
@@ -585,6 +620,8 @@ enum {
IFLA_BOND_AD_USER_PORT_KEY,
IFLA_BOND_AD_ACTOR_SYSTEM,
IFLA_BOND_TLB_DYNAMIC_LB,
+ IFLA_BOND_CL_START = 60,
+ IFLA_BOND_AD_LACP_BYPASS = IFLA_BOND_CL_START,
__IFLA_BOND_MAX,
};
@@ -612,6 +649,9 @@ enum {
IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
+
+ IFLA_BOND_SLAVE_CL_START = 50,
+ IFLA_BOND_SLAVE_AD_RX_BYPASS = IFLA_BOND_SLAVE_CL_START,
__IFLA_BOND_SLAVE_MAX,
};
@@ -721,6 +761,8 @@ enum {
IFLA_VF_STATS_BROADCAST,
IFLA_VF_STATS_MULTICAST,
IFLA_VF_STATS_PAD,
+ IFLA_VF_STATS_RX_DROPPED,
+ IFLA_VF_STATS_TX_DROPPED,
__IFLA_VF_STATS_MAX,
};
@@ -872,6 +914,7 @@ enum {
enum {
LINK_XSTATS_TYPE_UNSPEC,
LINK_XSTATS_TYPE_BRIDGE,
+ LINK_XSTATS_TYPE_BOND,
__LINK_XSTATS_TYPE_MAX
};
#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)
@@ -902,6 +945,7 @@ enum {
XDP_ATTACHED_DRV,
XDP_ATTACHED_SKB,
XDP_ATTACHED_HW,
+ XDP_ATTACHED_MULTI,
};
enum {
@@ -910,6 +954,9 @@ enum {
IFLA_XDP_ATTACHED,
IFLA_XDP_FLAGS,
IFLA_XDP_PROG_ID,
+ IFLA_XDP_DRV_PROG_ID,
+ IFLA_XDP_SKB_PROG_ID,
+ IFLA_XDP_HW_PROG_ID,
__IFLA_XDP_MAX,
};
@@ -925,4 +972,43 @@ enum {
IFLA_EVENT_BONDING_OPTIONS, /* change in bonding options */
};
-#endif /* _LINUX_IF_LINK_H */
+/* tun section */
+
+enum {
+ IFLA_TUN_UNSPEC,
+ IFLA_TUN_OWNER,
+ IFLA_TUN_GROUP,
+ IFLA_TUN_TYPE,
+ IFLA_TUN_PI,
+ IFLA_TUN_VNET_HDR,
+ IFLA_TUN_PERSIST,
+ IFLA_TUN_MULTI_QUEUE,
+ IFLA_TUN_NUM_QUEUES,
+ IFLA_TUN_NUM_DISABLED_QUEUES,
+ __IFLA_TUN_MAX,
+};
+
+#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1)
+
+/* rmnet section */
+
+#define RMNET_FLAGS_INGRESS_DEAGGREGATION (1U << 0)
+#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1)
+#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2)
+#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3)
+
+enum {
+ IFLA_RMNET_UNSPEC,
+ IFLA_RMNET_MUX_ID,
+ IFLA_RMNET_FLAGS,
+ __IFLA_RMNET_MAX,
+};
+
+#define IFLA_RMNET_MAX (__IFLA_RMNET_MAX - 1)
+
+struct ifla_rmnet_flags {
+ __u32 flags;
+ __u32 mask;
+};
+
+#endif /* _UAPI_LINUX_IF_LINK_H */
diff --git a/include/linux/lwtunnel.h b/include/linux/lwtunnel.h
index 329842627..de696ca12 100644
--- a/include/linux/lwtunnel.h
+++ b/include/linux/lwtunnel.h
@@ -1,5 +1,6 @@
-#ifndef _LWTUNNEL_H_
-#define _LWTUNNEL_H_
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LWTUNNEL_H_
+#define _UAPI_LWTUNNEL_H_
#include <linux/types.h>
@@ -67,4 +68,4 @@ enum {
#define LWT_BPF_MAX_HEADROOM 256
-#endif /* _LWTUNNEL_H_ */
+#endif /* _UAPI_LWTUNNEL_H_ */
diff --git a/include/linux/mpls_iptunnel.h b/include/linux/mpls_iptunnel.h
index 1a0e57b45..521f2e605 100644
--- a/include/linux/mpls_iptunnel.h
+++ b/include/linux/mpls_iptunnel.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* mpls tunnel api
*
@@ -10,8 +11,8 @@
* 2 of the License, or (at your option) any later version.
*/
-#ifndef _LINUX_MPLS_IPTUNNEL_H
-#define _LINUX_MPLS_IPTUNNEL_H
+#ifndef _UAPI_LINUX_MPLS_IPTUNNEL_H
+#define _UAPI_LINUX_MPLS_IPTUNNEL_H
/* MPLS tunnel attributes
* [RTA_ENCAP] = {
@@ -27,4 +28,4 @@ enum {
};
#define MPLS_IPTUNNEL_MAX (__MPLS_IPTUNNEL_MAX - 1)
-#endif /* _LINUX_MPLS_IPTUNNEL_H */
+#endif /* _UAPI_LINUX_MPLS_IPTUNNEL_H */
diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h
index 3199d2898..cd144e309 100644
--- a/include/linux/neighbour.h
+++ b/include/linux/neighbour.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_NEIGHBOUR_H
#define __LINUX_NEIGHBOUR_H
@@ -27,6 +28,7 @@ enum {
NDA_MASTER,
NDA_LINK_NETNSID,
NDA_SRC_VNI,
+ NDA_PROTOCOL, /* Originator of entry */
__NDA_MAX
};
@@ -42,6 +44,7 @@ enum {
#define NTF_PROXY 0x08 /* == ATF_PUBL */
#define NTF_EXT_LEARNED 0x10
#define NTF_OFFLOADED 0x20
+#define NTF_STICKY 0x40
#define NTF_ROUTER 0x80
/*
diff --git a/include/linux/net_namespace.h b/include/linux/net_namespace.h
index 9a92b7e14..0187c74d8 100644
--- a/include/linux/net_namespace.h
+++ b/include/linux/net_namespace.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* Copyright (c) 2015 6WIND S.A.
* Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
*
@@ -5,8 +6,8 @@
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
-#ifndef _LINUX_NET_NAMESPACE_H_
-#define _LINUX_NET_NAMESPACE_H_
+#ifndef _UAPI_LINUX_NET_NAMESPACE_H_
+#define _UAPI_LINUX_NET_NAMESPACE_H_
/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
enum {
@@ -20,4 +21,4 @@ enum {
#define NETNSA_MAX (__NETNSA_MAX - 1)
-#endif /* _LINUX_NET_NAMESPACE_H_ */
+#endif /* _UAPI_LINUX_NET_NAMESPACE_H_ */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 0b2c29bd0..750a36be6 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef __LINUX_NETLINK_H
-#define __LINUX_NETLINK_H
+#ifndef _UAPI__LINUX_NETLINK_H
+#define _UAPI__LINUX_NETLINK_H
#include <linux/kernel.h>
#include <linux/socket.h> /* for __kernel_sa_family_t */
@@ -16,7 +16,7 @@
#define NETLINK_SELINUX 7 /* SELinux event notifications */
#define NETLINK_ISCSI 8 /* Open-iSCSI */
#define NETLINK_AUDIT 9 /* auditing */
-#define NETLINK_FIB_LOOKUP 10
+#define NETLINK_FIB_LOOKUP 10
#define NETLINK_CONNECTOR 11
#define NETLINK_NETFILTER 12 /* netfilter subsystem */
#define NETLINK_IP6_FW 13
@@ -32,7 +32,7 @@
#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG
-#define MAX_LINKS 32
+#define MAX_LINKS 32
struct sockaddr_nl {
__kernel_sa_family_t nl_family; /* AF_NETLINK */
@@ -147,12 +147,15 @@ enum nlmsgerr_attrs {
#define NETLINK_PKTINFO 3
#define NETLINK_BROADCAST_ERROR 4
#define NETLINK_NO_ENOBUFS 5
+#ifndef __KERNEL__
#define NETLINK_RX_RING 6
#define NETLINK_TX_RING 7
+#endif
#define NETLINK_LISTEN_ALL_NSID 8
#define NETLINK_LIST_MEMBERSHIPS 9
#define NETLINK_CAP_ACK 10
#define NETLINK_EXT_ACK 11
+#define NETLINK_GET_STRICT_CHK 12
struct nl_pktinfo {
__u32 group;
@@ -175,6 +178,7 @@ struct nl_mmap_hdr {
__u32 nm_gid;
};
+#ifndef __KERNEL__
enum nl_mmap_status {
NL_MMAP_STATUS_UNUSED,
NL_MMAP_STATUS_RESERVED,
@@ -186,6 +190,7 @@ enum nl_mmap_status {
#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO
#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+#endif
#define NET_MAJOR 36 /* Major 36 is reserved for networking */
@@ -244,4 +249,4 @@ struct nla_bitfield32 {
__u32 selector;
};
-#endif /* __LINUX_NETLINK_H */
+#endif /* _UAPI__LINUX_NETLINK_H */
diff --git a/include/linux/nexthop.h b/include/linux/nexthop.h
new file mode 100644
index 000000000..e4d6e256e
--- /dev/null
+++ b/include/linux/nexthop.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_NEXTHOP_H
+#define _LINUX_NEXTHOP_H
+
+#include <linux/types.h>
+
+#define RTM_NHA(h) ((struct rtattr *)(((char *)(h)) + \
+ NLMSG_ALIGN(sizeof(struct nhmsg))))
+
+struct nhmsg {
+ unsigned char nh_family;
+ unsigned char nh_scope; /* return only */
+ unsigned char nh_protocol; /* Routing protocol that installed nh */
+ unsigned char resvd;
+ unsigned int nh_flags; /* RTNH_F flags */
+};
+
+struct nexthop_grp {
+ __u32 id; /* nexthop id - must exist */
+ __u8 weight; /* weight of this nexthop */
+ __u8 resvd1;
+ __u16 resvd2;
+};
+
+enum {
+ NEXTHOP_GRP_TYPE_MPATH, /* default type if not specified */
+ __NEXTHOP_GRP_TYPE_MAX,
+};
+
+#define NEXTHOP_GRP_TYPE_MAX (__NEXTHOP_GRP_TYPE_MAX - 1)
+
+enum {
+ NHA_UNSPEC,
+ NHA_ID, /* u32; id for nexthop. id == 0 means auto-assign */
+
+ NHA_GROUP, /* array of nexthop_grp */
+ NHA_GROUP_TYPE, /* u16 one of NEXTHOP_GRP_TYPE */
+ /* if NHA_GROUP attribute is added, no other attributes can be set */
+
+ NHA_BLACKHOLE, /* flag; nexthop used to blackhole packets */
+ /* if NHA_BLACKHOLE is added, OIF, GATEWAY, ENCAP can not be set */
+
+ NHA_OIF, /* u32; nexthop device */
+ NHA_GATEWAY, /* be32 (IPv4) or in6_addr (IPv6) gw address */
+ NHA_ENCAP_TYPE, /* u16; lwt encap type */
+ NHA_ENCAP, /* lwt encap data */
+
+ /* NHA_OIF can be appended to dump request to return only
+ * nexthops using given device
+ */
+ NHA_GROUPS, /* flag; only return nexthop groups in dump */
+ NHA_MASTER, /* u32; only return nexthops with given master dev */
+
+ __NHA_MAX,
+};
+
+#define NHA_MAX (__NHA_MAX - 1)
+#endif
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 813e9e076..eddbc0450 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -1,5 +1,6 @@
-#ifndef __LINUX_RTNETLINK_H
-#define __LINUX_RTNETLINK_H
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI__LINUX_RTNETLINK_H
+#define _UAPI__LINUX_RTNETLINK_H
#include <linux/types.h>
#include <linux/netlink.h>
@@ -149,6 +150,20 @@ enum {
RTM_NEWCACHEREPORT = 96,
#define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT
+ RTM_NEWCHAIN = 100,
+#define RTM_NEWCHAIN RTM_NEWCHAIN
+ RTM_DELCHAIN,
+#define RTM_DELCHAIN RTM_DELCHAIN
+ RTM_GETCHAIN,
+#define RTM_GETCHAIN RTM_GETCHAIN
+
+ RTM_NEWNEXTHOP = 104,
+#define RTM_NEWNEXTHOP RTM_NEWNEXTHOP
+ RTM_DELNEXTHOP,
+#define RTM_DELNEXTHOP RTM_DELNEXTHOP
+ RTM_GETNEXTHOP,
+#define RTM_GETNEXTHOP RTM_GETNEXTHOP
+
__RTM_MAX,
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
};
@@ -157,7 +172,7 @@ enum {
#define RTM_NR_FAMILIES (RTM_NR_MSGTYPES >> 2)
#define RTM_FAM(cmd) (((cmd) - RTM_BASE) >> 2)
-/*
+/*
Generic structure for encapsulation of optional route information.
It is reminiscent of sockaddr, but with sa_family replaced
with attribute type.
@@ -197,7 +212,7 @@ struct rtmsg {
unsigned char rtm_table; /* Routing table id */
unsigned char rtm_protocol; /* Routing protocol; see below */
- unsigned char rtm_scope; /* See below */
+ unsigned char rtm_scope; /* See below */
unsigned char rtm_type; /* See below */
unsigned rtm_flags;
@@ -253,6 +268,11 @@ enum {
#define RTPROT_DHCP 16 /* DHCP client */
#define RTPROT_MROUTED 17 /* Multicast daemon */
#define RTPROT_BABEL 42 /* Babel daemon */
+#define RTPROT_BGP 186 /* BGP Routes */
+#define RTPROT_ISIS 187 /* ISIS Routes */
+#define RTPROT_OSPF 188 /* OSPF Routes */
+#define RTPROT_RIP 189 /* RIP Routes */
+#define RTPROT_EIGRP 192 /* EIGRP Routes */
/* rtm_scope
@@ -326,6 +346,10 @@ enum rtattr_type_t {
RTA_PAD,
RTA_UID,
RTA_TTL_PROPAGATE,
+ RTA_IP_PROTO,
+ RTA_SPORT,
+ RTA_DPORT,
+ RTA_NH_ID,
__RTA_MAX
};
@@ -430,6 +454,8 @@ enum {
#define RTAX_QUICKACK RTAX_QUICKACK
RTAX_CC_ALGO,
#define RTAX_CC_ALGO RTAX_CC_ALGO
+ RTAX_FASTOPEN_NO_COOKIE,
+#define RTAX_FASTOPEN_NO_COOKIE RTAX_FASTOPEN_NO_COOKIE
__RTAX_MAX
};
@@ -497,7 +523,7 @@ struct ifinfomsg {
};
/********************************************************************
- * prefix information
+ * prefix information
****/
struct prefixmsg {
@@ -511,7 +537,7 @@ struct prefixmsg {
unsigned char prefix_pad3;
};
-enum
+enum
{
PREFIX_UNSPEC,
PREFIX_ADDRESS,
@@ -538,9 +564,19 @@ struct tcmsg {
int tcm_ifindex;
__u32 tcm_handle;
__u32 tcm_parent;
+/* tcm_block_index is used instead of tcm_parent
+ * in case tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK
+ */
+#define tcm_block_index tcm_parent
__u32 tcm_info;
};
+/* For manipulation of filters in shared block, tcm_ifindex is set to
+ * TCM_IFINDEX_MAGIC_BLOCK, and tcm_parent is aliased to tcm_block_index
+ * which is the block index.
+ */
+#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
+
enum {
TCA_UNSPEC,
TCA_KIND,
@@ -554,6 +590,9 @@ enum {
TCA_PAD,
TCA_DUMP_INVISIBLE,
TCA_CHAIN,
+ TCA_HW_OFFLOAD,
+ TCA_INGRESS_BLOCK,
+ TCA_EGRESS_BLOCK,
__TCA_MAX
};
@@ -586,6 +625,7 @@ enum {
#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1)
+#ifndef __KERNEL__
/* RTnetlink multicast groups - backwards compatibility for userspace */
#define RTMGRP_LINK 1
#define RTMGRP_NOTIFY 2
@@ -606,6 +646,7 @@ enum {
#define RTMGRP_DECnet_ROUTE 0x4000
#define RTMGRP_IPV6_PREFIX 0x20000
+#endif
/* RTnetlink multicast groups */
enum rtnetlink_groups {
@@ -671,6 +712,8 @@ enum rtnetlink_groups {
#define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R
RTNLGRP_IPV6_MROUTE_R,
#define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R
+ RTNLGRP_NEXTHOP,
+#define RTNLGRP_NEXTHOP RTNLGRP_NEXTHOP
__RTNLGRP_MAX
};
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
@@ -715,4 +758,4 @@ enum {
-#endif /* __LINUX_RTNETLINK_H */
+#endif /* _UAPI__LINUX_RTNETLINK_H */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 8c1e50177..8eb960217 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -1,5 +1,6 @@
-#ifndef _LINUX_SOCKET_H
-#define _LINUX_SOCKET_H
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_SOCKET_H
+#define _UAPI_LINUX_SOCKET_H
/*
* Desired design of maximum size and alignment (see RFC2553)
@@ -18,4 +19,4 @@ struct __kernel_sockaddr_storage {
/* _SS_MAXSIZE value minus size of ss_family */
} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */
-#endif /* _LINUX_SOCKET_H */
+#endif /* _UAPI_LINUX_SOCKET_H */
diff --git a/include/subdir.am b/include/subdir.am
index 0d7fed285..b1ca1be54 100644
--- a/include/subdir.am
+++ b/include/subdir.am
@@ -6,6 +6,7 @@ noinst_HEADERS += \
include/linux/mpls_iptunnel.h \
include/linux/neighbour.h \
include/linux/netlink.h \
+ include/linux/nexthop.h \
include/linux/rtnetlink.h \
include/linux/socket.h \
include/linux/net_namespace.h \
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 9b368cc40..d2ec6ff56 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -254,6 +254,7 @@ void isis_adj_state_change(struct isis_adjacency *adj,
reason ? reason : "unspecified");
}
+ circuit->adj_state_changes++;
#ifndef FABRICD
/* send northbound notification */
isis_notif_adj_state_change(adj, new_state, reason);
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 5da8e6ee9..29fb725b0 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -61,6 +61,8 @@
DEFINE_QOBJ_TYPE(isis_circuit)
+DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp))
+
/*
* Prototypes.
*/
@@ -1389,6 +1391,51 @@ int isis_if_delete_hook(struct interface *ifp)
return 0;
}
+static int isis_ifp_create(struct interface *ifp)
+{
+ if (if_is_operative(ifp))
+ isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),
+ ifp);
+
+ hook_call(isis_if_new_hook, ifp);
+
+ return 0;
+}
+
+static int isis_ifp_up(struct interface *ifp)
+{
+ isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), ifp);
+
+ return 0;
+}
+
+static int isis_ifp_down(struct interface *ifp)
+{
+ struct isis_circuit *circuit;
+
+ circuit = isis_csm_state_change(IF_DOWN_FROM_Z,
+ circuit_scan_by_ifp(ifp), ifp);
+ if (circuit)
+ SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
+
+ return 0;
+}
+
+static int isis_ifp_destroy(struct interface *ifp)
+{
+ if (if_is_operative(ifp))
+ zlog_warn("Zebra: got delete of %s, but interface is still up",
+ ifp->name);
+
+ isis_csm_state_change(IF_DOWN_FROM_Z, circuit_scan_by_ifp(ifp), ifp);
+
+ /* Cannot call if_delete because we should retain the pseudo interface
+ in case there is configuration info attached to it. */
+ if_delete_retain(ifp);
+
+ return 0;
+}
+
void isis_circuit_init(void)
{
/* Initialize Zebra interface data structure */
@@ -1398,4 +1445,6 @@ void isis_circuit_init(void)
/* Install interface node */
install_node(&interface_node, isis_interface_config_write);
if_cmd_init();
+ if_zapi_callbacks(isis_ifp_create, isis_ifp_up,
+ isis_ifp_down, isis_ifp_destroy);
}
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index e3541644a..f677d3ade 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -32,6 +32,8 @@
#include "isis_constants.h"
#include "isis_common.h"
+DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
+
struct isis_lsp;
struct password {
@@ -144,6 +146,13 @@ struct isis_circuit {
uint32_t
desig_changes[2]; /* lanLxDesignatedIntermediateSystemChanges */
uint32_t rej_adjacencies; /* rejectedAdjacencies */
+ /*
+ * Counters as in ietf-isis@2019-09-09.yang
+ */
+ uint32_t id_len_mismatches; /* id-len-mismatch */
+ uint32_t max_area_addr_mismatches; /* max-area-addresses-mismatch */
+ uint32_t auth_type_failures; /*authentication-type-fails */
+ uint32_t auth_failures; /* authentication-fails */
QOBJ_FIELDS
};
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index bd0628675..37f4dcfab 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -188,14 +188,10 @@ DEFPY(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
}
/* check if the interface is a loopback and if so set it as passive */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (ifp && if_is_loopback(ifp))
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
- NB_OP_MODIFY, "true");
- }
- pthread_rwlock_unlock(&running_config->lock);
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (ifp && if_is_loopback(ifp))
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
+ NB_OP_MODIFY, "true");
return nb_cli_apply_changes(vty, NULL);
}
@@ -262,14 +258,10 @@ DEFPY(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
}
/* check if the interface is a loopback and if so set it as passive */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (ifp && if_is_loopback(ifp))
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
- NB_OP_MODIFY, "true");
- }
- pthread_rwlock_unlock(&running_config->lock);
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (ifp && if_is_loopback(ifp))
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
+ NB_OP_MODIFY, "true");
return nb_cli_apply_changes(vty, NULL);
}
@@ -410,26 +402,20 @@ DEFPY(no_is_type, no_is_type_cmd,
"Act as both a station router and an area router\n"
"Act as an area router only\n")
{
- const char *value;
-
- pthread_rwlock_rdlock(&running_config->lock);
- {
- struct isis_area *area;
+ const char *value = NULL;
+ struct isis_area *area;
- area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-
- /*
- * Put the is-type back to defaults:
- * - level-1-2 on first area
- * - level-1 for the rest
- */
- if (area && listgetdata(listhead(isis->area_list)) == area)
- value = "level-1-2";
- else
- value = NULL;
- }
- pthread_rwlock_unlock(&running_config->lock);
+ area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ /*
+ * Put the is-type back to defaults:
+ * - level-1-2 on first area
+ * - level-1 for the rest
+ */
+ if (area && listgetdata(listhead(isis->area_list)) == area)
+ value = "level-1-2";
+ else
+ value = NULL;
nb_cli_enqueue_change(vty, "./is-type", NB_OP_MODIFY, value);
return nb_cli_apply_changes(vty, NULL);
@@ -1817,45 +1803,52 @@ DEFPY(no_isis_circuit_type, no_isis_circuit_type_cmd,
"Level-1-2 adjacencies are formed\n"
"Level-2 only adjacencies are formed\n")
{
- const char *circ_type = NULL;
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ int is_type;
+ const char *circ_type;
/*
* Default value depends on whether the circuit is part of an area,
* and the is-type of the area if there is one. So we need to do this
* here.
*/
- pthread_rwlock_rdlock(&running_config->lock);
- {
- struct interface *ifp;
- struct isis_circuit *circuit;
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (!ifp)
+ goto def_val;
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (!ifp)
- goto unlock;
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ goto def_val;
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit || circuit->state != C_STATE_UP)
- goto unlock;
+ if (circuit->state == C_STATE_UP)
+ is_type = circuit->area->is_type;
+ else
+ goto def_val;
- switch (circuit->area->is_type) {
- case IS_LEVEL_1:
- circ_type = "level-1";
- break;
- case IS_LEVEL_2:
- circ_type = "level-2";
- break;
- case IS_LEVEL_1_AND_2:
- circ_type = "level-1-2";
- break;
- }
+ switch (is_type) {
+ case IS_LEVEL_1:
+ circ_type = "level-1";
+ break;
+ case IS_LEVEL_2:
+ circ_type = "level-2";
+ break;
+ case IS_LEVEL_1_AND_2:
+ circ_type = "level-1-2";
+ break;
+ default:
+ return CMD_ERR_NO_MATCH;
}
-unlock:
- pthread_rwlock_unlock(&running_config->lock);
-
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
NB_OP_MODIFY, circ_type);
return nb_cli_apply_changes(vty, NULL);
+
+def_val:
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
+ NB_OP_MODIFY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode,
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 7f49e9d89..718924daf 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -243,7 +243,7 @@ int main(int argc, char **argv, char **envp)
mt_init();
/* create the global 'isis' instance */
- isis_new(1);
+ isis_new(1, VRF_DEFAULT);
isis_zebra_init(master);
isis_bfd_init();
diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c
index bd6191869..97b7ae4f7 100644
--- a/isisd/isis_northbound.c
+++ b/isisd/isis_northbound.c
@@ -49,6 +49,23 @@
#include "lib/vrf.h"
/*
+ * Helper functions.
+ */
+static const char *isis_yang_adj_state(enum isis_adj_state state)
+{
+ switch (state) {
+ case ISIS_ADJ_DOWN:
+ return "down";
+ case ISIS_ADJ_UP:
+ return "up";
+ case ISIS_ADJ_INITIALIZING:
+ return "init";
+ default:
+ return "failed";
+ }
+}
+
+/*
* XPath: /frr-isisd:isis/instance
*/
static int isis_instance_create(enum nb_event event,
@@ -1401,29 +1418,12 @@ static int isis_instance_mpls_te_create(enum nb_event event,
area->mta->status = enable;
}
- /*
- * Following code is intended to handle two cases;
- *
- * 1) MPLS-TE was disabled at startup time, but now become enabled.
- * In this case, we must enable MPLS-TE Circuit regarding interface
- * MPLS_TE flag
- * 2) MPLS-TE was once enabled then disabled, and now enabled again.
- */
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
- if (circuit->ext == NULL)
- continue;
+ /* Update Extended TLVs according to Interface link parameters */
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ isis_link_params_update(circuit, circuit->interface);
- if (!IS_EXT_TE(circuit->ext)
- && HAS_LINK_PARAMS(circuit->interface))
- isis_link_params_update(circuit, circuit->interface);
- else
- continue;
-
- /* Reoriginate STD_TE & GMPLS circuits */
- if (circuit->area)
- lsp_regenerate_schedule(circuit->area, circuit->is_type,
- 0);
- }
+ /* Reoriginate STD_TE & GMPLS circuits */
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
@@ -1456,13 +1456,11 @@ static int isis_instance_mpls_te_destroy(enum nb_event event,
circuit->ext->status = EXT_LAN_ADJ_SID;
else
circuit->ext->status = 0;
-
- /* Re-originate circuit without STD_TE & GMPLS parameters */
- if (circuit->area)
- lsp_regenerate_schedule(circuit->area, circuit->is_type,
- 0);
}
+ /* Reoriginate STD_TE & GMPLS circuits */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering",
area->area_tag);
@@ -1492,8 +1490,7 @@ static int isis_instance_mpls_te_router_address_modify(enum nb_event event,
area->mta->router_id.s_addr = value.s_addr;
/* And re-schedule LSP update */
- if (listcount(area->area_addrs) > 0)
- lsp_regenerate_schedule(area, area->is_type, 0);
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
@@ -1515,8 +1512,7 @@ static int isis_instance_mpls_te_router_address_destroy(enum nb_event event,
area->mta->router_id.s_addr = INADDR_ANY;
/* And re-schedule LSP update */
- if (listcount(area->area_addrs) > 0)
- lsp_regenerate_schedule(area, area->is_type, 0);
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
@@ -1542,9 +1538,9 @@ static int lib_interface_isis_create(enum nb_event event,
/* check if interface mtu is sufficient. If the area has not
* been created yet, assume default MTU for the area
*/
- ifp = nb_running_get_entry(dnode, NULL, true);
+ ifp = nb_running_get_entry(dnode, NULL, false);
/* zebra might not know yet about the MTU - nothing we can do */
- if (ifp->mtu == 0)
+ if (!ifp || ifp->mtu == 0)
break;
actual_mtu =
if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
@@ -2304,6 +2300,368 @@ static int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
}
/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency
+ */
+static const void *
+lib_interface_isis_adjacencies_adjacency_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct isis_adjacency *adj, *adj_next = NULL;
+ struct list *list;
+ struct listnode *node, *node_next;
+
+ /* Get first adjacency. */
+ if (list_entry == NULL) {
+ ifp = (struct interface *)parent_list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
+ level++) {
+ adj = listnode_head(
+ circuit->u.bc.adjdb[level - 1]);
+ if (adj)
+ break;
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ adj = circuit->u.p2p.neighbor;
+ break;
+ default:
+ adj = NULL;
+ break;
+ }
+
+ return adj;
+ }
+
+ /* Get next adjacency. */
+ adj = (struct isis_adjacency *)list_entry;
+ circuit = adj->circuit;
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ list = circuit->u.bc.adjdb[adj->level - 1];
+ node = listnode_lookup(list, adj);
+ node_next = listnextnode(node);
+ if (node_next)
+ adj_next = listgetdata(node_next);
+ else if (adj->level == ISIS_LEVEL1) {
+ /*
+ * Once we finish the L1 adjacencies, move to the L2
+ * adjacencies list.
+ */
+ list = circuit->u.bc.adjdb[ISIS_LEVEL2 - 1];
+ adj_next = listnode_head(list);
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ /* P2P circuits have at most one adjacency. */
+ default:
+ break;
+ }
+
+ return adj_next;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type
+ */
+static struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_enum(xpath, adj->level);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid
+ */
+static struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_string(xpath, sysid_print(adj->sysid));
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id
+ */
+static struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_uint32(xpath, adj->circuit->circuit_id);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa
+ */
+static struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_string(xpath, snpa_print(adj->snpa));
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer
+ */
+static struct yang_data *
+lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_uint16(xpath, adj->hold_time);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority
+ */
+static struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_uint8(xpath, adj->prio[adj->level - 1]);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state
+ */
+static struct yang_data *
+lib_interface_isis_adjacencies_adjacency_state_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_string(xpath, isis_yang_adj_state(adj->adj_state));
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes
+ */
+static struct yang_data *
+lib_interface_isis_event_counters_adjacency_changes_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->adj_state_changes);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number
+ */
+static struct yang_data *
+lib_interface_isis_event_counters_adjacency_number_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct isis_adjacency *adj;
+ struct listnode *node;
+ uint32_t total = 0;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ /*
+ * TODO: keep track of the number of adjacencies instead of calculating
+ * it on demand.
+ */
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ for (ALL_LIST_ELEMENTS_RO(
+ circuit->u.bc.adjdb[level - 1], node, adj))
+ total++;
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ adj = circuit->u.p2p.neighbor;
+ if (adj)
+ total = 1;
+ break;
+ default:
+ break;
+ }
+
+ return yang_data_new_uint32(xpath, total);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails
+ */
+static struct yang_data *
+lib_interface_isis_event_counters_init_fails_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->init_failures);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects
+ */
+static struct yang_data *
+lib_interface_isis_event_counters_adjacency_rejects_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->rej_adjacencies);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch
+ */
+static struct yang_data *
+lib_interface_isis_event_counters_id_len_mismatch_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->id_len_mismatches);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch
+ */
+static struct yang_data *
+lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->max_area_addr_mismatches);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails
+ */
+static struct yang_data *
+lib_interface_isis_event_counters_authentication_type_fails_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->auth_type_failures);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails
+ */
+static struct yang_data *
+lib_interface_isis_event_counters_authentication_fails_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->auth_failures);
+}
+
+/*
* NOTIFICATIONS
*/
static void notif_prep_instance_hdr(const char *xpath,
@@ -2545,19 +2903,7 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj,
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath);
- switch (new_state) {
- case ISIS_ADJ_DOWN:
- data = yang_data_new_string(xpath_arg, "down");
- break;
- case ISIS_ADJ_UP:
- data = yang_data_new_string(xpath_arg, "up");
- break;
- case ISIS_ADJ_INITIALIZING:
- data = yang_data_new_string(xpath_arg, "init");
- break;
- default:
- data = yang_data_new_string(xpath_arg, "failed");
- }
+ data = yang_data_new_string(xpath_arg, isis_yang_adj_state(new_state));
listnode_add(arguments, data);
if (new_state == ISIS_ADJ_DOWN) {
snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath);
@@ -3484,6 +3830,102 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency",
+ .cbs = {
+ .get_next = lib_interface_isis_adjacencies_adjacency_get_next,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_state_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_adjacency_changes_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_adjacency_number_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_init_fails_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_adjacency_rejects_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_id_len_mismatch_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_authentication_type_fails_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_authentication_fails_get_elem,
+ }
+ },
+ {
.xpath = NULL,
},
}
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index ecfce392f..a637ff003 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -187,7 +187,7 @@ static int process_p2p_hello(struct iih_info *iih)
adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
}
- if (tw_adj && adj->threeway_state == ISIS_THREEWAY_DOWN)
+ if (tw_adj)
adj->ext_circuit_id = tw_adj->local_circuit_id;
/* 8.2.6 Monitoring point-to-point adjacencies */
@@ -576,6 +576,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
if (p2p_hello) {
if (circuit->circ_type != CIRCUIT_T_P2P) {
zlog_warn("p2p hello on non p2p circuit");
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "p2p hello on non p2p circuit",
@@ -586,6 +587,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
} else {
if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
zlog_warn("lan hello on non broadcast circuit");
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "lan hello on non broadcast circuit",
@@ -598,6 +600,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
zlog_debug(
"level %d LAN Hello received over circuit with externalDomain = true",
level);
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit,
@@ -614,6 +617,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
circuit->area->area_tag,
circuit->interface->name);
}
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "Interface level mismatch", raw_pdu);
@@ -643,6 +647,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
"ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %" PRIu16,
circuit->area->area_tag, pdu_name,
circuit->interface->name, iih.pdu_len);
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(circuit, "Invalid PDU length",
raw_pdu);
@@ -654,6 +659,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
flog_err(EC_ISIS_PACKET,
"Level %d LAN Hello with Circuit Type %d", level,
iih.circ_type);
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "LAN Hello with wrong IS-level", raw_pdu);
@@ -667,6 +673,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream),
circuit->rcv_stream, &iih.tlvs, &error_log)) {
zlog_warn("isis_unpack_tlvs() failed: %s", error_log);
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(circuit, "Failed to unpack TLVs",
raw_pdu);
@@ -685,6 +692,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
if (!iih.tlvs->protocols_supported.count) {
zlog_warn("No supported protocols TLV in %s", pdu_name);
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "No supported protocols TLV", raw_pdu);
@@ -702,11 +710,14 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
/* send northbound notification */
stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start,
pdu_end - pdu_start);
- if (auth_code == ISIS_AUTH_FAILURE)
+ if (auth_code == ISIS_AUTH_FAILURE) {
+ circuit->auth_failures++;
isis_notif_authentication_failure(circuit, raw_pdu);
- else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
+ } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
+ circuit->auth_type_failures++;
isis_notif_authentication_type_failure(circuit,
raw_pdu);
+ }
#endif /* ifndef FABRICD */
goto out;
}
@@ -715,6 +726,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
zlog_warn(
"ISIS-Adj (%s): Received IIH with own sysid - discard",
circuit->area->area_tag);
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "Received IIH with our own sysid", raw_pdu);
@@ -752,6 +764,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
"ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH",
circuit->area->area_tag);
}
+ circuit->rej_adjacencies++;
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "Neither IPv4 not IPv6 considered usable",
@@ -940,11 +953,14 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit,
hdr.lsp_id);
#ifndef FABRICD
/* send northbound notification */
- if (auth_code == ISIS_AUTH_FAILURE)
+ if (auth_code == ISIS_AUTH_FAILURE) {
+ circuit->auth_failures++;
isis_notif_authentication_failure(circuit, raw_pdu);
- else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
+ } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
+ circuit->auth_type_failures++;
isis_notif_authentication_type_failure(circuit,
raw_pdu);
+ }
#endif /* ifndef FABRICD */
goto out;
}
@@ -1373,12 +1389,15 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
/* send northbound notification */
stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start,
pdu_end - pdu_start);
- if (auth_code == ISIS_AUTH_FAILURE)
+ if (auth_code == ISIS_AUTH_FAILURE) {
+ circuit->auth_failures++;
isis_notif_authentication_failure(circuit,
raw_pdu);
- else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
+ } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
+ circuit->auth_type_failures++;
isis_notif_authentication_type_failure(circuit,
raw_pdu);
+ }
#endif /* ifndef FABRICD */
goto out;
}
@@ -1614,6 +1633,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
"IDFieldLengthMismatch: ID Length field in a received PDU %" PRIu8
", while the parameter for this IS is %u",
id_len, ISIS_SYS_ID_LEN);
+ circuit->id_len_mismatches++;
#ifndef FABRICD
/* send northbound notification */
isis_notif_id_len_mismatch(circuit, id_len, raw_pdu);
@@ -1666,6 +1686,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
"maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %" PRIu8
" while the parameter for this IS is %u",
max_area_addrs, isis->max_area_addrs);
+ circuit->max_area_addr_mismatches++;
#ifndef FABRICD
/* send northbound notification */
isis_notif_max_area_addr_mismatch(circuit, max_area_addrs,
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
index 44fa45d02..9871d2bcb 100644
--- a/isisd/isis_te.c
+++ b/isisd/isis_te.c
@@ -81,8 +81,7 @@ void isis_link_params_update(struct isis_circuit *circuit,
return;
/* Sanity Check */
- if ((circuit == NULL) || (ifp == NULL)
- || (circuit->state != C_STATE_UP))
+ if ((ifp == NULL) || (circuit->state != C_STATE_UP))
return;
zlog_debug("TE(%s): Update circuit parameters for interface %s",
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 39a2f6ef3..bdf6869f5 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -53,8 +53,6 @@
struct zclient *zclient = NULL;
-DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp))
-
/* Router-id update message from zebra. */
static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
{
@@ -74,79 +72,6 @@ static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int isis_zebra_if_add(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
-
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
-
- if (if_is_operative(ifp))
- isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),
- ifp);
-
- hook_call(isis_if_new_hook, ifp);
-
- return 0;
-}
-
-static int isis_zebra_if_del(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
- struct stream *s;
-
- s = zclient->ibuf;
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (!ifp)
- return 0;
-
- if (if_is_operative(ifp))
- zlog_warn("Zebra: got delete of %s, but interface is still up",
- ifp->name);
-
- isis_csm_state_change(IF_DOWN_FROM_Z, circuit_scan_by_ifp(ifp), ifp);
-
- /* Cannot call if_delete because we should retain the pseudo interface
- in case there is configuration info attached to it. */
- if_delete_retain(ifp);
-
- if_set_index(ifp, IFINDEX_INTERNAL);
-
- return 0;
-}
-
-static int isis_zebra_if_state_up(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), ifp);
-
- return 0;
-}
-
-static int isis_zebra_if_state_down(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- circuit = isis_csm_state_change(IF_DOWN_FROM_Z,
- circuit_scan_by_ifp(ifp), ifp);
- if (circuit)
- SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
-
- return 0;
-}
-
static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
{
struct connected *c;
@@ -388,10 +313,6 @@ void isis_zebra_init(struct thread_master *master)
zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs);
zclient->zebra_connected = isis_zebra_connected;
zclient->router_id_update = isis_router_id_update_zebra;
- zclient->interface_add = isis_zebra_if_add;
- zclient->interface_delete = isis_zebra_if_del;
- zclient->interface_up = isis_zebra_if_state_up;
- zclient->interface_down = isis_zebra_if_state_down;
zclient->interface_address_add = isis_zebra_if_address_add;
zclient->interface_address_delete = isis_zebra_if_address_del;
zclient->interface_link_params = isis_zebra_link_params;
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index 83a32108e..d00f348c8 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -24,8 +24,6 @@
extern struct zclient *zclient;
-DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
-
void isis_zebra_init(struct thread_master *);
void isis_zebra_stop(void);
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 67f557ab5..029a9e068 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -75,12 +75,13 @@ int clear_isis_neighbor_common(struct vty *, const char *id);
int isis_config_write(struct vty *);
-void isis_new(unsigned long process_id)
+void isis_new(unsigned long process_id, vrf_id_t vrf_id)
{
isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis));
/*
* Default values
*/
+ isis->vrf_id = vrf_id;
isis->max_area_addrs = 3;
isis->process_id = process_id;
isis->router_id = 0;
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 308f018c1..f825b6ecb 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -62,6 +62,7 @@ extern struct zebra_privs_t isisd_privs;
struct fabricd;
struct isis {
+ vrf_id_t vrf_id;
unsigned long process_id;
int sysid_set;
uint8_t sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */
@@ -189,7 +190,7 @@ struct isis_area {
DECLARE_QOBJ_TYPE(isis_area)
void isis_init(void);
-void isis_new(unsigned long);
+void isis_new(unsigned long process_id, vrf_id_t vrf_id);
struct isis_area *isis_area_create(const char *);
struct isis_area *isis_area_lookup(const char *);
int isis_area_get(struct vty *vty, const char *area_tag);
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c
index 884ae159b..4df1fc030 100644
--- a/ldpd/ldp_zebra.c
+++ b/ldpd/ldp_zebra.c
@@ -39,9 +39,6 @@ static void ifc2kaddr(struct interface *, struct connected *,
struct kaddr *);
static int ldp_zebra_send_mpls_labels(int, struct kroute *);
static int ldp_router_id_update(ZAPI_CALLBACK_ARGS);
-static int ldp_interface_add(ZAPI_CALLBACK_ARGS);
-static int ldp_interface_delete(ZAPI_CALLBACK_ARGS);
-static int ldp_interface_status_change(ZAPI_CALLBACK_ARGS);
static int ldp_interface_address_add(ZAPI_CALLBACK_ARGS);
static int ldp_interface_address_delete(ZAPI_CALLBACK_ARGS);
static int ldp_zebra_read_route(ZAPI_CALLBACK_ARGS);
@@ -264,39 +261,27 @@ ldp_router_id_update(ZAPI_CALLBACK_ARGS)
}
static int
-ldp_interface_add(ZAPI_CALLBACK_ARGS)
+ldp_ifp_create(struct interface *ifp)
{
- struct interface *ifp;
struct kif kif;
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
debug_zebra_in("interface add %s index %d mtu %d", ifp->name,
ifp->ifindex, ifp->mtu);
ifp2kif(ifp, &kif);
main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif));
- return (0);
+ return 0;
}
static int
-ldp_interface_delete(ZAPI_CALLBACK_ARGS)
+ldp_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
struct kif kif;
- /* zebra_interface_state_read() updates interface structure in iflist */
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- if (ifp == NULL)
- return (0);
-
debug_zebra_in("interface delete %s index %d mtu %d", ifp->name,
ifp->ifindex, ifp->mtu);
- /* To support pseudo interface do not free interface structure. */
- /* if_delete(ifp); */
- if_set_index(ifp, IFINDEX_INTERNAL);
-
ifp2kif(ifp, &kif);
main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif));
@@ -304,22 +289,13 @@ ldp_interface_delete(ZAPI_CALLBACK_ARGS)
}
static int
-ldp_interface_status_change(ZAPI_CALLBACK_ARGS)
+ldp_interface_status_change_helper(struct interface *ifp)
{
- struct interface *ifp;
struct listnode *node;
struct connected *ifc;
struct kif kif;
struct kaddr ka;
- /*
- * zebra_interface_state_read() updates interface structure in
- * iflist.
- */
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- if (ifp == NULL)
- return (0);
-
debug_zebra_in("interface %s state update", ifp->name);
ifp2kif(ifp, &kif);
@@ -342,6 +318,16 @@ ldp_interface_status_change(ZAPI_CALLBACK_ARGS)
return (0);
}
+static int ldp_ifp_up(struct interface *ifp)
+{
+ return ldp_interface_status_change_helper(ifp);
+}
+
+static int ldp_ifp_down(struct interface *ifp)
+{
+ return ldp_interface_status_change_helper(ifp);
+}
+
static int
ldp_interface_address_add(ZAPI_CALLBACK_ARGS)
{
@@ -535,6 +521,9 @@ extern struct zebra_privs_t ldpd_privs;
void
ldp_zebra_init(struct thread_master *master)
{
+ if_zapi_callbacks(ldp_ifp_create, ldp_ifp_up,
+ ldp_ifp_down, ldp_ifp_destroy);
+
/* Set default values. */
zclient = zclient_new(master, &zclient_options_default);
zclient_init(zclient, ZEBRA_ROUTE_LDP, 0, &ldpd_privs);
@@ -542,10 +531,6 @@ ldp_zebra_init(struct thread_master *master)
/* set callbacks */
zclient->zebra_connected = ldp_zebra_connected;
zclient->router_id_update = ldp_router_id_update;
- zclient->interface_add = ldp_interface_add;
- zclient->interface_delete = ldp_interface_delete;
- zclient->interface_up = ldp_interface_status_change;
- zclient->interface_down = ldp_interface_status_change;
zclient->interface_address_add = ldp_interface_address_add;
zclient->interface_address_delete = ldp_interface_address_delete;
zclient->redistribute_route_add = ldp_zebra_read_route;
diff --git a/lib/agentx.c b/lib/agentx.c
index 40cac722a..2c6a43d1a 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -55,13 +55,29 @@ static int agentx_timeout(struct thread *t)
static int agentx_read(struct thread *t)
{
fd_set fds;
+ int flags;
+ int nonblock = false;
struct listnode *ln = THREAD_ARG(t);
list_delete_node(events, ln);
+ /* fix for non blocking socket */
+ flags = fcntl(THREAD_FD(t), F_GETFL, 0);
+ if (-1 == flags)
+ return -1;
+
+ if (flags & O_NONBLOCK)
+ nonblock = true;
+ else
+ fcntl(THREAD_FD(t), F_SETFL, flags | O_NONBLOCK);
+
FD_ZERO(&fds);
FD_SET(THREAD_FD(t), &fds);
snmp_read(&fds);
+ /* Reset the flag */
+ if (!nonblock)
+ fcntl(THREAD_FD(t), F_SETFL, flags);
+
netsnmp_check_outstanding_agent_requests();
agentx_events_update();
return 0;
diff --git a/lib/command.c b/lib/command.c
index eecca2a5f..e52893f0b 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -1135,6 +1135,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
return saved_ret;
if (ret != CMD_SUCCESS && ret != CMD_WARNING
+ && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
&& ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED) {
/* This assumes all nodes above CONFIG_NODE are childs of
* CONFIG_NODE */
@@ -1146,6 +1147,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
ret = cmd_execute_command_real(vline, FILTER_RELAXED,
vty, cmd);
if (ret == CMD_SUCCESS || ret == CMD_WARNING
+ || ret == CMD_ERR_AMBIGUOUS || ret == CMD_ERR_INCOMPLETE
|| ret == CMD_NOT_MY_INSTANCE
|| ret == CMD_WARNING_CONFIG_FAILED)
return ret;
@@ -1330,6 +1332,7 @@ int command_config_read_one_line(struct vty *vty,
if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
&& !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
&& ret != CMD_SUCCESS && ret != CMD_WARNING
+ && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
&& ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
&& vty->node != CONFIG_NODE) {
int saved_node = vty->node;
@@ -1338,6 +1341,7 @@ int command_config_read_one_line(struct vty *vty,
while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
&& !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
&& ret != CMD_SUCCESS && ret != CMD_WARNING
+ && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
&& vty->node > CONFIG_NODE) {
vty->node = node_parent(vty->node);
if (vty->xpath_index > 0)
@@ -1709,6 +1713,8 @@ static int vty_write_config(struct vty *vty)
if (host.noconfig)
return CMD_SUCCESS;
+ nb_cli_show_config_prepare(running_config, false);
+
if (vty->type == VTY_TERM) {
vty_out(vty, "\nCurrent configuration:\n");
vty_out(vty, "!\n");
@@ -1718,16 +1724,12 @@ static int vty_write_config(struct vty *vty)
vty_out(vty, "frr defaults %s\n", DFLT_NAME);
vty_out(vty, "!\n");
- pthread_rwlock_rdlock(&running_config->lock);
- {
- for (i = 0; i < vector_active(cmdvec); i++)
- if ((node = vector_slot(cmdvec, i)) && node->func
- && (node->vtysh || vty->type != VTY_SHELL)) {
- if ((*node->func)(vty))
- vty_out(vty, "!\n");
- }
- }
- pthread_rwlock_unlock(&running_config->lock);
+ for (i = 0; i < vector_active(cmdvec); i++)
+ if ((node = vector_slot(cmdvec, i)) && node->func
+ && (node->vtysh || vty->type != VTY_SHELL)) {
+ if ((*node->func)(vty))
+ vty_out(vty, "!\n");
+ }
if (vty->type == VTY_TERM) {
vty_out(vty, "end\n");
diff --git a/lib/command.h b/lib/command.h
index 137d3748a..d5dc129c7 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -412,7 +412,7 @@ struct cmd_node {
#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nInterface name or neighbor tag\n"
#define NEIGHBOR_ADDR_STR3 "Neighbor address\nIPv6 address\nInterface name\n"
-/* Dameons lists */
+/* Daemons lists */
#define DAEMONS_STR \
"For the zebra daemon\nFor the rip daemon\nFor the ripng daemon\nFor the ospf daemon\nFor the ospfv6 daemon\nFor the bgp daemon\nFor the isis daemon\nFor the pbr daemon\nFor the fabricd daemon\nFor the pim daemon\nFor the static daemon\nFor the sharpd daemon\nFor the vrrpd daemon\n"
#define DAEMONS_LIST \
diff --git a/lib/command_match.c b/lib/command_match.c
index 26d763849..0195aebc1 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -724,7 +724,12 @@ static enum match_type match_ipv4(const char *str)
return no_match;
memcpy(buf, sp, str - sp);
- if (atoi(buf) > 255)
+
+ int v = atoi(buf);
+
+ if (v > 255)
+ return no_match;
+ if (v > 0 && buf[0] == '0')
return no_match;
nums++;
@@ -775,7 +780,12 @@ static enum match_type match_ipv4_prefix(const char *str)
return no_match;
memcpy(buf, sp, str - sp);
- if (atoi(buf) > 255)
+
+ int v = atoi(buf);
+
+ if (v > 255)
+ return no_match;
+ if (v > 0 && buf[0] == '0')
return no_match;
if (dots == 3) {
diff --git a/lib/filter.c b/lib/filter.c
index fe62ca1c1..8c210bd7a 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -1915,6 +1915,7 @@ DEFUN (mac_access_list,
argv_find(argv, argc, "X:X:X:X:X:X", &idx);
if (idx)
mac = argv[idx]->arg;
+ assert(mac);
return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
mac, 0, 1);
@@ -1952,6 +1953,7 @@ DEFUN (no_mac_access_list,
argv_find(argv, argc, "X:X:X:X:X:X", &idx);
if (idx)
mac = argv[idx]->arg;
+ assert(mac);
return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
mac, 0, 0);
@@ -2050,6 +2052,7 @@ DEFUN (access_list_exact,
argv_find(argv, argc, "A.B.C.D/M", &idx);
if (idx)
prefix = argv[idx]->arg;
+ assert(prefix);
idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
@@ -2122,6 +2125,7 @@ DEFUN (no_access_list_exact,
argv_find(argv, argc, "A.B.C.D/M", &idx);
if (idx)
prefix = argv[idx]->arg;
+ assert(prefix);
idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
@@ -2367,6 +2371,7 @@ DEFUN (no_ipv6_access_list_exact,
argv_find(argv, argc, "X:X::X:X/M", &idx);
if (idx)
prefix = argv[idx]->arg;
+ assert(prefix);
idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
diff --git a/lib/frrcu.c b/lib/frrcu.c
index 54626f909..d65a4a98b 100644
--- a/lib/frrcu.c
+++ b/lib/frrcu.c
@@ -55,6 +55,7 @@
#include "atomlist.h"
DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread")
+DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier")
DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head)
@@ -205,7 +206,7 @@ void rcu_thread_unprepare(struct rcu_thread *rt)
rcu_bump();
if (rt != &rcu_thread_main)
/* this free() happens after seqlock_release() below */
- rcu_free_internal(MTYPE_RCU_THREAD, rt, rcu_head);
+ rcu_free_internal(&_mt_RCU_THREAD, rt, rcu_head);
rcu_threads_del(&rcu_threads, rt);
seqlock_release(&rt->rcu);
@@ -225,7 +226,7 @@ static void rcu_bump(void)
{
struct rcu_next *rn;
- rn = XMALLOC(MTYPE_RCU_THREAD, sizeof(*rn));
+ rn = XMALLOC(MTYPE_RCU_NEXT, sizeof(*rn));
/* note: each RCUA_NEXT item corresponds to exactly one seqno bump.
* This means we don't need to communicate which seqno is which
@@ -268,7 +269,7 @@ static void rcu_bump(void)
* "last item is being deleted - start over" case, and then we may end
* up accessing old RCU queue items that are already free'd.
*/
- rcu_free_internal(MTYPE_RCU_THREAD, rn, head_free);
+ rcu_free_internal(&_mt_RCU_NEXT, rn, head_free);
/* Only allow the RCU sweeper to run after these 2 items are queued.
*
diff --git a/lib/if.c b/lib/if.c
index 5f9232756..594961d76 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -58,6 +58,13 @@ DEFINE_QOBJ_TYPE(interface)
DEFINE_HOOK(if_add, (struct interface * ifp), (ifp))
DEFINE_KOOH(if_del, (struct interface * ifp), (ifp))
+struct interface_master{
+ int (*create_hook)(struct interface *ifp);
+ int (*up_hook)(struct interface *ifp);
+ int (*down_hook)(struct interface *ifp);
+ int (*destroy_hook)(struct interface *ifp);
+} ifp_master = { 0, };
+
/* Compare interface names, returning an integer greater than, equal to, or
* less than 0, (following the strcmp convention), according to the
* relationship between ifp1 and ifp2. Interface names consist of an
@@ -134,25 +141,16 @@ static int if_cmp_index_func(const struct interface *ifp1,
}
/* Create new interface structure. */
-static struct interface *if_create_backend(const char *name, ifindex_t ifindex,
- vrf_id_t vrf_id)
+static struct interface *if_new(vrf_id_t vrf_id)
{
- struct vrf *vrf = vrf_get(vrf_id, NULL);
struct interface *ifp;
ifp = XCALLOC(MTYPE_IF, sizeof(struct interface));
- ifp->vrf_id = vrf_id;
- if (name) {
- strlcpy(ifp->name, name, sizeof(ifp->name));
- IFNAME_RB_INSERT(vrf, ifp);
- } else
- ifp->name[0] = '\0';
+ ifp->ifindex = IFINDEX_INTERNAL;
+ ifp->name[0] = '\0';
- if (ifindex != IFINDEX_INTERNAL)
- if_set_index(ifp, ifindex);
- else
- ifp->ifindex = ifindex; /* doesn't add it to the list */
+ ifp->vrf_id = vrf_id;
ifp->connected = list_new();
ifp->connected->del = (void (*)(void *))connected_free;
@@ -164,18 +162,59 @@ static struct interface *if_create_backend(const char *name, ifindex_t ifindex,
SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
QOBJ_REG(ifp, interface);
- hook_call(if_add, ifp);
return ifp;
}
-struct interface *if_create(const char *name, vrf_id_t vrf_id)
+void if_new_via_zapi(struct interface *ifp)
{
- return if_create_backend(name, IFINDEX_INTERNAL, vrf_id);
+ if (ifp_master.create_hook)
+ (*ifp_master.create_hook)(ifp);
+}
+
+void if_destroy_via_zapi(struct interface *ifp)
+{
+ if (ifp_master.destroy_hook)
+ (*ifp_master.destroy_hook)(ifp);
+
+ if_set_index(ifp, IFINDEX_INTERNAL);
+ if (!ifp->configured)
+ if_delete(ifp);
+}
+
+void if_up_via_zapi(struct interface *ifp)
+{
+ if (ifp_master.up_hook)
+ (*ifp_master.up_hook)(ifp);
+}
+
+void if_down_via_zapi(struct interface *ifp)
+{
+ if (ifp_master.down_hook)
+ (*ifp_master.down_hook)(ifp);
+}
+
+struct interface *if_create_name(const char *name, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+
+ ifp = if_new(vrf_id);
+
+ if_set_name(ifp, name);
+
+ hook_call(if_add, ifp);
+ return ifp;
}
struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
{
- return if_create_backend(NULL, ifindex, vrf_id);
+ struct interface *ifp;
+
+ ifp = if_new(vrf_id);
+
+ if_set_index(ifp, ifindex);
+
+ hook_call(if_add, ifp);
+ return ifp;
}
/* Create new interface structure. */
@@ -186,7 +225,9 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
/* remove interface from old master vrf list */
old_vrf = vrf_lookup_by_id(ifp->vrf_id);
if (old_vrf) {
- IFNAME_RB_REMOVE(old_vrf, ifp);
+ if (ifp->name[0] != '\0')
+ IFNAME_RB_REMOVE(old_vrf, ifp);
+
if (ifp->ifindex != IFINDEX_INTERNAL)
IFINDEX_RB_REMOVE(old_vrf, ifp);
}
@@ -194,7 +235,9 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
ifp->vrf_id = vrf_id;
vrf = vrf_get(ifp->vrf_id, NULL);
- IFNAME_RB_INSERT(vrf, ifp);
+ if (ifp->name[0] != '\0')
+ IFNAME_RB_INSERT(vrf, ifp);
+
if (ifp->ifindex != IFINDEX_INTERNAL)
IFINDEX_RB_INSERT(vrf, ifp);
@@ -207,21 +250,18 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
if (yang_module_find("frr-interface")) {
struct lyd_node *if_dnode;
- pthread_rwlock_wrlock(&running_config->lock);
- {
- if_dnode = yang_dnode_get(
- running_config->dnode,
- "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
- ifp->name, old_vrf->name);
- if (if_dnode) {
- yang_dnode_change_leaf(if_dnode, vrf->name);
- running_config->version++;
- }
+ if_dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
+ ifp->name, old_vrf->name);
+ if (if_dnode) {
+ yang_dnode_change_leaf(if_dnode, vrf->name);
+ running_config->version++;
}
- pthread_rwlock_unlock(&running_config->lock);
}
}
+
/* Delete interface structure. */
void if_delete_retain(struct interface *ifp)
{
@@ -480,7 +520,7 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
ifp = if_lookup_by_name(name, vrf_id);
if (ifp)
return ifp;
- return if_create(name, vrf_id);
+ return if_create_name(name, vrf_id);
case VRF_BACKEND_VRF_LITE:
ifp = if_lookup_by_name_all_vrf(name);
if (ifp) {
@@ -492,7 +532,7 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
if_update_to_new_vrf(ifp, vrf_id);
return ifp;
}
- return if_create(name, vrf_id);
+ return if_create_name(name, vrf_id);
}
return NULL;
@@ -530,14 +570,14 @@ void if_set_index(struct interface *ifp, ifindex_t ifindex)
{
struct vrf *vrf;
- vrf = vrf_lookup_by_id(ifp->vrf_id);
+ vrf = vrf_get(ifp->vrf_id, NULL);
assert(vrf);
if (ifp->ifindex == ifindex)
return;
if (ifp->ifindex != IFINDEX_INTERNAL)
- IFINDEX_RB_REMOVE(vrf, ifp)
+ IFINDEX_RB_REMOVE(vrf, ifp);
ifp->ifindex = ifindex;
@@ -545,6 +585,25 @@ void if_set_index(struct interface *ifp, ifindex_t ifindex)
IFINDEX_RB_INSERT(vrf, ifp)
}
+void if_set_name(struct interface *ifp, const char *name)
+{
+ struct vrf *vrf;
+
+ vrf = vrf_get(ifp->vrf_id, NULL);
+ assert(vrf);
+
+ if (if_cmp_name_func(ifp->name, name) == 0)
+ return;
+
+ if (ifp->name[0] != '\0')
+ IFNAME_RB_REMOVE(vrf, ifp);
+
+ strlcpy(ifp->name, name, sizeof(ifp->name));
+
+ if (ifp->name[0] != '\0')
+ IFNAME_RB_INSERT(vrf, ifp);
+}
+
/* Does interface up ? */
int if_is_up(const struct interface *ifp)
{
@@ -1199,7 +1258,7 @@ void if_link_params_free(struct interface *ifp)
*/
DEFPY_NOSH (interface,
interface_cmd,
- "interface IFNAME [vrf NAME$vrfname]",
+ "interface IFNAME [vrf NAME$vrf_name]",
"Select an interface to configure\n"
"Interface's name\n"
VRF_CMD_HELP_STR)
@@ -1209,8 +1268,8 @@ DEFPY_NOSH (interface,
struct interface *ifp;
int ret;
- if (!vrfname)
- vrfname = VRF_DEFAULT_NAME;
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
/*
* This command requires special handling to maintain backward
@@ -1219,7 +1278,7 @@ DEFPY_NOSH (interface,
* interface is found, then a new one should be created on the default
* VRF.
*/
- VRF_GET_ID(vrf_id, vrfname, false);
+ VRF_GET_ID(vrf_id, vrf_name, false);
ifp = if_lookup_by_name_all_vrf(ifname);
if (ifp && ifp->vrf_id != vrf_id) {
struct vrf *vrf;
@@ -1230,24 +1289,24 @@ DEFPY_NOSH (interface,
*/
if (vrf_id != VRF_DEFAULT) {
vty_out(vty, "%% interface %s not in %s vrf\n", ifname,
- vrfname);
+ vrf_name);
return CMD_WARNING_CONFIG_FAILED;
}
/*
* Special case 2: a VRF name was *not* specified, and the found
* interface is associated to a VRF other than the default one.
- * Update vrf_id and vrfname to account for that.
+ * Update vrf_id and vrf_name to account for that.
*/
vrf = vrf_lookup_by_id(ifp->vrf_id);
assert(vrf);
vrf_id = ifp->vrf_id;
- vrfname = vrf->name;
+ vrf_name = vrf->name;
}
snprintf(xpath_list, sizeof(xpath_list),
"/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname,
- vrfname);
+ vrf_name);
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
ret = nb_cli_apply_changes(vty, xpath_list);
@@ -1270,20 +1329,20 @@ DEFPY_NOSH (interface,
DEFPY (no_interface,
no_interface_cmd,
- "no interface IFNAME [vrf NAME$vrfname]",
+ "no interface IFNAME [vrf NAME$vrf_name]",
NO_STR
"Delete a pseudo interface's configuration\n"
"Interface's name\n"
VRF_CMD_HELP_STR)
{
- if (!vrfname)
- vrfname = VRF_DEFAULT_NAME;
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(
vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']",
- ifname, vrfname);
+ ifname, vrf_name);
}
static void cli_show_interface(struct vty *vty, struct lyd_node *dnode,
@@ -1370,6 +1429,17 @@ void if_cmd_init(void)
install_element(INTERFACE_NODE, &no_interface_desc_cmd);
}
+void if_zapi_callbacks(int (*create)(struct interface *ifp),
+ int (*up)(struct interface *ifp),
+ int (*down)(struct interface *ifp),
+ int (*destroy)(struct interface *ifp))
+{
+ ifp_master.create_hook = create;
+ ifp_master.up_hook = up;
+ ifp_master.down_hook = down;
+ ifp_master.destroy_hook = destroy;
+}
+
/* ------- Northbound callbacks ------- */
/*
@@ -1426,6 +1496,8 @@ static int lib_interface_create(enum nb_event event,
#else
ifp = if_get_by_name(ifname, vrf->vrf_id);
#endif /* SUNOS_5 */
+
+ ifp->configured = true;
nb_running_set_entry(dnode, ifp);
break;
}
@@ -1453,6 +1525,8 @@ static int lib_interface_destroy(enum nb_event event,
break;
case NB_EV_APPLY:
ifp = nb_running_unset_entry(dnode);
+
+ ifp->configured = false;
if_delete(ifp);
break;
}
@@ -1461,6 +1535,60 @@ static int lib_interface_destroy(enum nb_event event,
}
/*
+ * XPath: /frr-interface:lib/interface
+ */
+static const void *lib_interface_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ struct vrf *vrf;
+ struct interface *pif = (struct interface *)list_entry;
+
+ if (list_entry == NULL) {
+ vrf = RB_MIN(vrf_name_head, &vrfs_by_name);
+ assert(vrf);
+ pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
+ } else {
+ vrf = vrf_lookup_by_id(pif->vrf_id);
+ pif = RB_NEXT(if_name_head, pif);
+ /* if no more interfaces, switch to next vrf */
+ while (pif == NULL) {
+ vrf = RB_NEXT(vrf_name_head, vrf);
+ if (!vrf)
+ return NULL;
+ pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
+ }
+ }
+
+ return pif;
+}
+
+static int lib_interface_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct interface *ifp = list_entry;
+
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ assert(vrf);
+
+ keys->num = 2;
+ strlcpy(keys->key[0], ifp->name, sizeof(keys->key[0]));
+ strlcpy(keys->key[1], vrf->name, sizeof(keys->key[1]));
+
+ return NB_OK;
+}
+
+static const void *lib_interface_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ const char *ifname = keys->key[0];
+ const char *vrfname = keys->key[1];
+ struct vrf *vrf = vrf_lookup_by_name(vrfname);
+
+ return vrf ? if_lookup_by_name(ifname, vrf->vrf_id) : NULL;
+}
+
+/*
* XPath: /frr-interface:lib/interface/description
*/
static int lib_interface_description_modify(enum nb_event event,
@@ -1505,6 +1633,9 @@ const struct frr_yang_module_info frr_interface_info = {
.create = lib_interface_create,
.destroy = lib_interface_destroy,
.cli_show = cli_show_interface,
+ .get_next = lib_interface_get_next,
+ .get_keys = lib_interface_get_keys,
+ .lookup_entry = lib_interface_lookup_entry,
},
},
{
diff --git a/lib/if.h b/lib/if.h
index e3ec278f9..1ee6561e8 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -293,13 +293,19 @@ struct interface {
struct route_node *node;
vrf_id_t vrf_id;
+ /*
+ * Has the end users entered `interface XXXX` from the cli in some
+ * fashion?
+ */
+ bool configured;
+
QOBJ_FIELDS
};
RB_HEAD(if_name_head, interface);
RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func)
RB_HEAD(if_index_head, interface);
-RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_func)
+RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_index_func)
DECLARE_QOBJ_TYPE(interface)
#define IFNAME_RB_INSERT(vrf, ifp) \
@@ -473,7 +479,11 @@ extern int if_cmp_name_func(const char *p1, const char *p2);
* else think before you use VRF_UNKNOWN
*/
extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
-extern struct interface *if_create(const char *name, vrf_id_t vrf_id);
+
+/* Create new interface, adds to name list only */
+extern struct interface *if_create_name(const char *name, vrf_id_t vrf_id);
+
+/* Create new interface, adds to index list only */
extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id);
extern struct interface *if_lookup_by_index_all_vrf(ifindex_t);
@@ -486,13 +496,15 @@ extern struct interface *if_lookup_prefix(struct prefix *prefix,
size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
struct interface ***result, vrf_id_t vrf_id);
-/* These 3 functions are to be used when the ifname argument is terminated
- by a '\0' character: */
extern struct interface *if_lookup_by_name_all_vrf(const char *ifname);
extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id);
extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id);
extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
+
+/* Sets the index and adds to index list */
extern void if_set_index(struct interface *ifp, ifindex_t ifindex);
+/* Sets the name and adds to name list */
+extern void if_set_name(struct interface *ifp, const char *name);
/* Delete the interface, but do not free the structure, and leave it in the
interface list. It is often advisable to leave the pseudo interface
@@ -552,6 +564,16 @@ void if_link_params_free(struct interface *);
/* Northbound. */
extern void if_cmd_init(void);
+extern void if_zapi_callbacks(int (*create)(struct interface *ifp),
+ int (*up)(struct interface *ifp),
+ int (*down)(struct interface *ifp),
+ int (*destroy)(struct interface *ifp));
+
+extern void if_new_via_zapi(struct interface *ifp);
+extern void if_up_via_zapi(struct interface *ifp);
+extern void if_down_via_zapi(struct interface *ifp);
+extern void if_destroy_via_zapi(struct interface *ifp);
+
extern const struct frr_yang_module_info frr_interface_info;
#ifdef __cplusplus
diff --git a/lib/json.c b/lib/json.c
index efc379404..991240639 100644
--- a/lib/json.c
+++ b/lib/json.c
@@ -47,11 +47,7 @@ void json_object_string_add(struct json_object *obj, const char *key,
void json_object_int_add(struct json_object *obj, const char *key, int64_t i)
{
-#if defined(HAVE_JSON_C_JSON_H)
json_object_object_add(obj, key, json_object_new_int64(i));
-#else
- json_object_object_add(obj, key, json_object_new_int((int)i));
-#endif
}
void json_object_boolean_false_add(struct json_object *obj, const char *key)
@@ -78,16 +74,3 @@ void json_object_free(struct json_object *obj)
{
json_object_put(obj);
}
-
-#if !defined(HAVE_JSON_C_JSON_H)
-int json_object_object_get_ex(struct json_object *obj, const char *key,
- struct json_object **value)
-{
- *value = json_object_object_get(obj, key);
-
- if (*value)
- return 1;
-
- return 0;
-}
-#endif
diff --git a/lib/json.h b/lib/json.h
index c4d566b31..c8866c524 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -25,7 +25,7 @@
extern "C" {
#endif
-#if defined(HAVE_JSON_C_JSON_H)
+#include "command.h"
#include <json-c/json.h>
/*
@@ -41,21 +41,6 @@ extern "C" {
json_object_iter_equal(&(joi), &(join)) == 0; \
json_object_iter_next(&(joi)))
-#else
-#include <json/json.h>
-
-/*
- * json_object_to_json_string_ext is only available for json-c
- * so let's just turn it back to the original usage.
- */
-#define json_object_to_json_string_ext(A, B) json_object_to_json_string (A)
-
-extern int json_object_object_get_ex(struct json_object *obj, const char *key,
- struct json_object **value);
-#endif
-
-#include "command.h"
-
extern bool use_json(const int argc, struct cmd_token *argv[]);
extern void json_object_string_add(struct json_object *obj, const char *key,
const char *s);
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 478fe4e20..8ef32eaa8 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -853,27 +853,34 @@ static void frr_daemonize(void)
*/
static int frr_config_read_in(struct thread *t)
{
- if (!vty_read_config(NULL, di->config_file, config_default) &&
- di->backup_config_file) {
+ if (!vty_read_config(vty_shared_candidate_config, di->config_file,
+ config_default)
+ && di->backup_config_file) {
char *orig = XSTRDUP(MTYPE_TMP, host_config_get());
zlog_info("Attempting to read backup config file: %s specified",
di->backup_config_file);
- vty_read_config(NULL, di->backup_config_file, config_default);
+ vty_read_config(vty_shared_candidate_config,
+ di->backup_config_file, config_default);
host_config_set(orig);
XFREE(MTYPE_TMP, orig);
}
/*
- * Update the shared candidate after reading the startup configuration.
+ * Automatically commit the candidate configuration after
+ * reading the configuration file.
*/
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_replace(vty_shared_candidate_config, running_config,
- true);
+ if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) {
+ int ret;
+
+ ret = nb_candidate_commit(vty_shared_candidate_config,
+ NB_CLIENT_CLI, NULL, true,
+ "Read configuration file", NULL);
+ if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
+ zlog_err("%s: failed to read configuration file.",
+ __func__);
}
- pthread_rwlock_unlock(&running_config->lock);
return 0;
}
diff --git a/lib/memory.h b/lib/memory.h
index 14cd76f2f..8de5c4c2b 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -101,14 +101,9 @@ struct memgroup {
*_mg_##mname.ref = _mg_##mname.next; \
}
-
-/* the array is a trick to make the "MTYPE_FOO" name work as a pointer without
- * putting a & in front of it, so we can do "XMALLOC(MTYPE_FOO, ...)" instead
- * of "XMALLOC(&MTYPE_FOO, ...)".
- */
#define DECLARE_MTYPE(name) \
extern struct memtype _mt_##name; \
- extern struct memtype MTYPE_##name[1]; \
+ extern struct memtype *const MTYPE_##name; \
/* end */
#define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \
@@ -138,17 +133,14 @@ struct memgroup {
} \
/* end */
-/* can't quite get gcc to emit the alias correctly, so asm-alias it is :/ */
#define DEFINE_MTYPE(group, name, desc) \
DEFINE_MTYPE_ATTR(group, name, , desc) \
- __asm__(".equiv MTYPE_" #name ", _mt_" #name "\n\t" \
- ".global MTYPE_" #name "\n"); \
+ struct memtype *const MTYPE_##name = &_mt_##name; \
/* end */
-/* and this one's borked on clang, it drops static on aliases :/, so... asm */
+
#define DEFINE_MTYPE_STATIC(group, name, desc) \
DEFINE_MTYPE_ATTR(group, name, static, desc) \
- extern struct memtype MTYPE_##name[1]; \
- __asm__(".equiv MTYPE_" #name ", _mt_" #name "\n"); \
+ static struct memtype *const MTYPE_##name = &_mt_##name; \
/* end */
DECLARE_MGROUP(LIB)
diff --git a/lib/nexthop.c b/lib/nexthop.c
index cf5bed3d6..73c2de0cd 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -349,7 +349,7 @@ const char *nexthop2str(const struct nexthop *nexthop, char *str, int size)
* left branch is 'resolved' and right branch is 'next':
* https://en.wikipedia.org/wiki/Tree_traversal#/media/File:Sorted_binary_tree_preorder.svg
*/
-struct nexthop *nexthop_next(struct nexthop *nexthop)
+struct nexthop *nexthop_next(const struct nexthop *nexthop)
{
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
return nexthop->resolved;
@@ -364,6 +364,19 @@ struct nexthop *nexthop_next(struct nexthop *nexthop)
return NULL;
}
+/* Return the next nexthop in the tree that is resolved and active */
+struct nexthop *nexthop_next_active_resolved(const struct nexthop *nexthop)
+{
+ struct nexthop *next = nexthop_next(nexthop);
+
+ while (next
+ && (CHECK_FLAG(next->flags, NEXTHOP_FLAG_RECURSIVE)
+ || !CHECK_FLAG(next->flags, NEXTHOP_FLAG_ACTIVE)))
+ next = nexthop_next(next);
+
+ return next;
+}
+
unsigned int nexthop_level(struct nexthop *nexthop)
{
unsigned int rv = 0;
@@ -374,16 +387,13 @@ unsigned int nexthop_level(struct nexthop *nexthop)
return rv;
}
-uint32_t nexthop_hash(const struct nexthop *nexthop)
+/* Only hash word-sized things, let cmp do the rest. */
+uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
{
uint32_t key = 0x45afe398;
key = jhash_3words(nexthop->type, nexthop->vrf_id,
nexthop->nh_label_type, key);
- /* gate and blackhole are together in a union */
- key = jhash(&nexthop->gate, sizeof(nexthop->gate), key);
- key = jhash(&nexthop->src, sizeof(nexthop->src), key);
- key = jhash(&nexthop->rmap_src, sizeof(nexthop->rmap_src), key);
if (nexthop->nh_label) {
int labels = nexthop->nh_label->num_labels;
@@ -410,17 +420,35 @@ uint32_t nexthop_hash(const struct nexthop *nexthop)
key = jhash_1word(nexthop->nh_label->label[i], key);
}
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- case NEXTHOP_TYPE_IFINDEX:
- key = jhash_1word(nexthop->ifindex, key);
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV6:
- break;
- }
+ key = jhash_2words(nexthop->ifindex,
+ CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK),
+ key);
+
+ return key;
+}
+
+
+#define GATE_SIZE 4 /* Number of uint32_t words in struct g_addr */
+
+/* For a more granular hash */
+uint32_t nexthop_hash(const struct nexthop *nexthop)
+{
+ uint32_t gate_src_rmap_raw[GATE_SIZE * 3] = {};
+ /* Get all the quick stuff */
+ uint32_t key = nexthop_hash_quick(nexthop);
+
+ assert(((sizeof(nexthop->gate) + sizeof(nexthop->src)
+ + sizeof(nexthop->rmap_src))
+ / 3)
+ == (GATE_SIZE * sizeof(uint32_t)));
+
+ memcpy(gate_src_rmap_raw, &nexthop->gate, GATE_SIZE);
+ memcpy(gate_src_rmap_raw + GATE_SIZE, &nexthop->src, GATE_SIZE);
+ memcpy(gate_src_rmap_raw + (2 * GATE_SIZE), &nexthop->rmap_src,
+ GATE_SIZE);
+
+ key = jhash2(gate_src_rmap_raw, (GATE_SIZE * 3), key);
+
return key;
}
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 9dd5fc6fd..fe029f186 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -137,6 +137,14 @@ void nexthop_del_labels(struct nexthop *);
* 32-bit hash of nexthop
*/
uint32_t nexthop_hash(const struct nexthop *nexthop);
+/*
+ * Hash a nexthop only on word-sized attributes:
+ * - vrf_id
+ * - ifindex
+ * - type
+ * - (some) flags
+ */
+uint32_t nexthop_hash_quick(const struct nexthop *nexthop);
extern bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2);
extern bool nexthop_same_no_labels(const struct nexthop *nh1,
@@ -153,7 +161,9 @@ extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2);
extern const char *nexthop2str(const struct nexthop *nexthop,
char *str, int size);
-extern struct nexthop *nexthop_next(struct nexthop *nexthop);
+extern struct nexthop *nexthop_next(const struct nexthop *nexthop);
+extern struct nexthop *
+nexthop_next_active_resolved(const struct nexthop *nexthop);
extern unsigned int nexthop_level(struct nexthop *nexthop);
/* Copies to an already allocated nexthop struct */
extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index abe2096ce..9552f8956 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -81,6 +81,17 @@ uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg)
return num;
}
+uint8_t nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg)
+{
+ struct nexthop *nhop;
+ uint8_t num = 0;
+
+ for (nhop = nhg->nexthop; nhop; nhop = nhop->next)
+ num++;
+
+ return num;
+}
+
uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
{
struct nexthop *nhop;
@@ -94,7 +105,22 @@ uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
return num;
}
-struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh)
+uint8_t
+nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg)
+{
+ struct nexthop *nhop;
+ uint8_t num = 0;
+
+ for (nhop = nhg->nexthop; nhop; nhop = nhop->next) {
+ if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE))
+ num++;
+ }
+
+ return num;
+}
+
+struct nexthop *nexthop_exists(const struct nexthop_group *nhg,
+ const struct nexthop *nh)
{
struct nexthop *nexthop;
@@ -106,6 +132,74 @@ struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh)
return NULL;
}
+static bool
+nexthop_group_equal_common(const struct nexthop_group *nhg1,
+ const struct nexthop_group *nhg2,
+ uint8_t (*nexthop_group_nexthop_num_func)(
+ const struct nexthop_group *nhg))
+{
+ if (nhg1 && !nhg2)
+ return false;
+
+ if (!nhg1 && nhg2)
+ return false;
+
+ if (nhg1 == nhg2)
+ return true;
+
+ if (nexthop_group_nexthop_num_func(nhg1)
+ != nexthop_group_nexthop_num_func(nhg2))
+ return false;
+
+ return true;
+}
+
+/* This assumes ordered */
+bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1,
+ const struct nexthop_group *nhg2)
+{
+ struct nexthop *nh1 = NULL;
+ struct nexthop *nh2 = NULL;
+
+ if (!nexthop_group_equal_common(nhg1, nhg2,
+ &nexthop_group_nexthop_num_no_recurse))
+ return false;
+
+ for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2;
+ nh1 = nh1->next, nh2 = nh2->next) {
+ if (nh1 && !nh2)
+ return false;
+ if (!nh1 && nh2)
+ return false;
+ if (!nexthop_same(nh1, nh2))
+ return false;
+ }
+
+ return true;
+}
+
+/* This assumes ordered */
+bool nexthop_group_equal(const struct nexthop_group *nhg1,
+ const struct nexthop_group *nhg2)
+{
+ struct nexthop *nh1 = NULL;
+ struct nexthop *nh2 = NULL;
+
+ if (!nexthop_group_equal_common(nhg1, nhg2, &nexthop_group_nexthop_num))
+ return false;
+
+ for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2;
+ nh1 = nexthop_next(nh1), nh2 = nexthop_next(nh2)) {
+ if (nh1 && !nh2)
+ return false;
+ if (!nh1 && nh2)
+ return false;
+ if (!nexthop_same(nh1, nh2))
+ return false;
+ }
+
+ return true;
+}
struct nexthop_group *nexthop_group_new(void)
{
return XCALLOC(MTYPE_NEXTHOP_GROUP, sizeof(struct nexthop_group));
@@ -119,6 +213,9 @@ void nexthop_group_copy(struct nexthop_group *to, struct nexthop_group *from)
void nexthop_group_delete(struct nexthop_group **nhg)
{
+ if ((*nhg)->nexthop)
+ nexthops_free((*nhg)->nexthop);
+
XFREE(MTYPE_NEXTHOP_GROUP, *nhg);
}
@@ -217,7 +314,7 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
}
}
-uint32_t nexthop_group_hash(const struct nexthop_group *nhg)
+uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg)
{
struct nexthop *nh;
uint32_t key = 0;
@@ -232,6 +329,35 @@ uint32_t nexthop_group_hash(const struct nexthop_group *nhg)
return key;
}
+uint32_t nexthop_group_hash(const struct nexthop_group *nhg)
+{
+ struct nexthop *nh;
+ uint32_t key = 0;
+
+ for (ALL_NEXTHOPS_PTR(nhg, nh))
+ key = jhash_1word(nexthop_hash(nh), key);
+
+ return key;
+}
+
+void nexthop_group_mark_duplicates(struct nexthop_group *nhg)
+{
+ struct nexthop *nexthop, *prev;
+
+ for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
+ for (ALL_NEXTHOPS_PTR(nhg, prev)) {
+ if (prev == nexthop)
+ break;
+ if (nexthop_same_firsthop(nexthop, prev)) {
+ SET_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_DUPLICATE);
+ break;
+ }
+ }
+ }
+}
+
static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc)
{
struct nexthop *nexthop;
@@ -475,7 +601,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
<A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
|INTERFACE$intf\
>\
- [nexthop-vrf NAME$name]",
+ [nexthop-vrf NAME$vrf_name]",
NO_STR
"Specify one of the nexthops in this ECMP group\n"
"v4 Address\n"
@@ -490,7 +616,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
struct nexthop *nh;
bool legal;
- legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
+ legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name);
if (nhop.type == NEXTHOP_TYPE_IPV6
&& IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
@@ -502,7 +628,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
nh = nexthop_exists(&nhgc->nhg, &nhop);
if (no) {
- nexthop_group_unsave_nhop(nhgc, name, addr, intf);
+ nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf);
if (nh) {
_nexthop_del(&nhgc->nhg, nh);
@@ -520,7 +646,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
_nexthop_add(&nhgc->nhg.nexthop, nh);
}
- nexthop_group_save_nhop(nhgc, name, addr, intf);
+ nexthop_group_save_nhop(nhgc, vrf_name, addr, intf);
if (legal && nhg_hooks.add_nexthop)
nhg_hooks.add_nexthop(nhgc, nh);
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 4f4d40eb3..391775c69 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -47,7 +47,9 @@ void nexthop_group_copy(struct nexthop_group *to,
void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
struct nexthop *rparent);
+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);
/* The following for loop allows to iterate over the nexthop
* structure of routes.
@@ -110,8 +112,15 @@ void nexthop_group_disable_vrf(struct vrf *vrf);
void nexthop_group_interface_state_change(struct interface *ifp,
ifindex_t oldifindex);
-extern struct nexthop *nexthop_exists(struct nexthop_group *nhg,
- struct nexthop *nh);
+extern struct nexthop *nexthop_exists(const struct nexthop_group *nhg,
+ const struct nexthop *nh);
+/* This assumes ordered */
+extern bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1,
+ const struct nexthop_group *nhg2);
+
+/* This assumes ordered */
+extern bool nexthop_group_equal(const struct nexthop_group *nhg1,
+ const struct nexthop_group *nhg2);
extern struct nexthop_group_cmd *nhgc_find(const char *name);
@@ -120,7 +129,11 @@ extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh);
/* Return the number of nexthops in this nhg */
extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg);
extern uint8_t
+nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg);
+extern uint8_t
nexthop_group_active_nexthop_num(const struct nexthop_group *nhg);
+extern uint8_t
+nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg);
#ifdef __cplusplus
}
diff --git a/lib/northbound.c b/lib/northbound.c
index a814f23e1..debd46362 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -64,6 +64,9 @@ static bool transaction_in_progress;
static int nb_callback_configuration(const enum nb_event event,
struct nb_config_change *change);
+static void nb_log_callback(const enum nb_event event,
+ enum nb_operation operation, const char *xpath,
+ const char *value);
static struct nb_transaction *nb_transaction_new(struct nb_config *config,
struct nb_config_cbs *changes,
enum nb_client client,
@@ -180,7 +183,18 @@ static int nb_node_validate_cb(const struct nb_node *nb_node,
valid = nb_operation_is_valid(operation, nb_node->snode);
- if (!valid && callback_implemented)
+ /*
+ * Add an exception for operational data callbacks. A rw list usually
+ * doesn't need any associated operational data callbacks. But if this
+ * rw list is augmented by another module which adds state nodes under
+ * it, then this list will need to have the 'get_next()', 'get_keys()'
+ * and 'lookup_entry()' callbacks. As such, never log a warning when
+ * these callbacks are implemented when they are not needed, since this
+ * depends on context (e.g. some daemons might augment "frr-interface"
+ * while others don't).
+ */
+ if (!valid && callback_implemented && operation != NB_OP_GET_NEXT
+ && operation != NB_OP_GET_KEYS && operation != NB_OP_LOOKUP_ENTRY)
flog_warn(EC_LIB_NB_CB_UNNEEDED,
"unneeded '%s' callback for '%s'",
nb_operation_name(operation), nb_node->xpath);
@@ -211,6 +225,8 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node)
!!nb_node->cbs.destroy, false);
error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move,
false);
+ error += nb_node_validate_cb(nb_node, NB_OP_PRE_VALIDATE,
+ !!nb_node->cbs.pre_validate, true);
error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH,
!!nb_node->cbs.apply_finish, true);
error += nb_node_validate_cb(nb_node, NB_OP_GET_ELEM,
@@ -265,7 +281,6 @@ struct nb_config *nb_config_new(struct lyd_node *dnode)
else
config->dnode = yang_dnode_new(ly_native_ctx, true);
config->version = 0;
- pthread_rwlock_init(&config->lock, NULL);
return config;
}
@@ -274,7 +289,6 @@ void nb_config_free(struct nb_config *config)
{
if (config->dnode)
yang_dnode_free(config->dnode);
- pthread_rwlock_destroy(&config->lock);
XFREE(MTYPE_NB_CONFIG, config);
}
@@ -285,7 +299,6 @@ struct nb_config *nb_config_dup(const struct nb_config *config)
dup = XCALLOC(MTYPE_NB_CONFIG, sizeof(*dup));
dup->dnode = yang_dnode_dup(config->dnode);
dup->version = config->version;
- pthread_rwlock_init(&dup->lock, NULL);
return dup;
}
@@ -335,23 +348,39 @@ static inline int nb_config_cb_compare(const struct nb_config_cb *a,
return 1;
/*
- * Use XPath as a tie-breaker. This will naturally sort parent nodes
- * before their children.
+ * Preserve the order of the configuration changes as told by libyang.
*/
- return strcmp(a->xpath, b->xpath);
+ if (a->seq < b->seq)
+ return -1;
+ if (a->seq > b->seq)
+ return 1;
+
+ /*
+ * All 'apply_finish' callbacks have their sequence number set to zero.
+ * In this case, compare them using their dnode pointers (the order
+ * doesn't matter for callbacks that have the same priority).
+ */
+ if (a->dnode < b->dnode)
+ return -1;
+ if (a->dnode > b->dnode)
+ return 1;
+
+ return 0;
}
RB_GENERATE(nb_config_cbs, nb_config_cb, entry, nb_config_cb_compare);
static void nb_config_diff_add_change(struct nb_config_cbs *changes,
enum nb_operation operation,
+ uint32_t *seq,
const struct lyd_node *dnode)
{
struct nb_config_change *change;
change = XCALLOC(MTYPE_TMP, sizeof(*change));
change->cb.operation = operation;
+ change->cb.seq = *seq;
+ *seq = *seq + 1;
change->cb.nb_node = dnode->schema->priv;
- yang_dnode_get_path(dnode, change->cb.xpath, sizeof(change->cb.xpath));
change->cb.dnode = dnode;
RB_INSERT(nb_config_cbs, changes, &change->cb);
@@ -374,7 +403,7 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes)
* configurations. Given a new subtree, calculate all new YANG data nodes,
* excluding default leafs and leaf-lists. This is a recursive function.
*/
-static void nb_config_diff_created(const struct lyd_node *dnode,
+static void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
struct nb_config_cbs *changes)
{
enum nb_operation operation;
@@ -393,16 +422,17 @@ static void nb_config_diff_created(const struct lyd_node *dnode,
else
return;
- nb_config_diff_add_change(changes, operation, dnode);
+ nb_config_diff_add_change(changes, operation, seq, dnode);
break;
case LYS_CONTAINER:
case LYS_LIST:
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
- nb_config_diff_add_change(changes, NB_OP_CREATE, dnode);
+ nb_config_diff_add_change(changes, NB_OP_CREATE, seq,
+ dnode);
/* Process child nodes recursively. */
LY_TREE_FOR (dnode->child, child) {
- nb_config_diff_created(child, changes);
+ nb_config_diff_created(child, seq, changes);
}
break;
default:
@@ -410,11 +440,11 @@ static void nb_config_diff_created(const struct lyd_node *dnode,
}
}
-static void nb_config_diff_deleted(const struct lyd_node *dnode,
+static void nb_config_diff_deleted(const struct lyd_node *dnode, uint32_t *seq,
struct nb_config_cbs *changes)
{
if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
- nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode);
+ nb_config_diff_add_change(changes, NB_OP_DESTROY, seq, dnode);
else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
struct lyd_node *child;
@@ -425,7 +455,7 @@ static void nb_config_diff_deleted(const struct lyd_node *dnode,
* when applicable (i.e. optional nodes).
*/
LY_TREE_FOR (dnode->child, child) {
- nb_config_diff_deleted(child, changes);
+ nb_config_diff_deleted(child, seq, changes);
}
}
}
@@ -436,6 +466,7 @@ static void nb_config_diff(const struct nb_config *config1,
struct nb_config_cbs *changes)
{
struct lyd_difflist *diff;
+ uint32_t seq = 0;
diff = lyd_diff(config1->dnode, config2->dnode,
LYD_DIFFOPT_WITHDEFAULTS);
@@ -450,15 +481,16 @@ static void nb_config_diff(const struct nb_config *config1,
switch (type) {
case LYD_DIFF_CREATED:
dnode = diff->second[i];
- nb_config_diff_created(dnode, changes);
+ nb_config_diff_created(dnode, &seq, changes);
break;
case LYD_DIFF_DELETED:
dnode = diff->first[i];
- nb_config_diff_deleted(dnode, changes);
+ nb_config_diff_deleted(dnode, &seq, changes);
break;
case LYD_DIFF_CHANGED:
dnode = diff->second[i];
- nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode);
+ nb_config_diff_add_change(changes, NB_OP_MODIFY, &seq,
+ dnode);
break;
case LYD_DIFF_MOVEDAFTER1:
case LYD_DIFF_MOVEDAFTER2:
@@ -498,17 +530,6 @@ int nb_candidate_edit(struct nb_config *candidate,
__func__);
return NB_ERR;
}
-
- /*
- * If a new node was created, call lyd_validate() only to create
- * default child nodes.
- */
- if (dnode) {
- lyd_schema_sort(dnode, 0);
- lyd_validate(&dnode,
- LYD_OPT_CONFIG | LYD_OPT_WHENAUTODEL,
- ly_native_ctx);
- }
break;
case NB_OP_DESTROY:
dnode = yang_dnode_get(candidate->dnode, xpath_edit);
@@ -535,28 +556,17 @@ int nb_candidate_edit(struct nb_config *candidate,
bool nb_candidate_needs_update(const struct nb_config *candidate)
{
- bool ret = false;
-
- pthread_rwlock_rdlock(&running_config->lock);
- {
- if (candidate->version < running_config->version)
- ret = true;
- }
- pthread_rwlock_unlock(&running_config->lock);
+ if (candidate->version < running_config->version)
+ return true;
- return ret;
+ return false;
}
int nb_candidate_update(struct nb_config *candidate)
{
struct nb_config *updated_config;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- updated_config = nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
-
+ updated_config = nb_config_dup(running_config);
if (nb_config_merge(updated_config, candidate, true) != NB_OK)
return NB_ERR;
@@ -583,14 +593,45 @@ static int nb_candidate_validate_yang(struct nb_config *candidate)
}
/* Perform code-level validation using the northbound callbacks. */
-static int nb_candidate_validate_changes(struct nb_config *candidate,
- struct nb_config_cbs *changes)
+static int nb_candidate_validate_code(struct nb_config *candidate,
+ struct nb_config_cbs *changes)
{
struct nb_config_cb *cb;
+ struct lyd_node *root, *next, *child;
+ int ret;
+
+ /* First validate the candidate as a whole. */
+ LY_TREE_FOR (candidate->dnode, root) {
+ LY_TREE_DFS_BEGIN (root, next, child) {
+ struct nb_node *nb_node;
+
+ nb_node = child->schema->priv;
+ if (!nb_node->cbs.pre_validate)
+ goto next;
+ if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config,
+ DEBUG_MODE_ALL)) {
+ char xpath[XPATH_MAXLEN];
+
+ yang_dnode_get_path(child, xpath,
+ sizeof(xpath));
+ nb_log_callback(NB_EV_VALIDATE,
+ NB_OP_PRE_VALIDATE, xpath,
+ NULL);
+ }
+
+ ret = (*nb_node->cbs.pre_validate)(child);
+ if (ret != NB_OK)
+ return NB_ERR_VALIDATION;
+
+ next:
+ LY_TREE_DFS_END(root, next, child);
+ }
+ }
+
+ /* Now validate the configuration changes. */
RB_FOREACH (cb, nb_config_cbs, changes) {
struct nb_config_change *change = (struct nb_config_change *)cb;
- int ret;
ret = nb_callback_configuration(NB_EV_VALIDATE, change);
if (ret != NB_OK)
@@ -609,13 +650,9 @@ int nb_candidate_validate(struct nb_config *candidate)
return NB_ERR_VALIDATION;
RB_INIT(nb_config_cbs, &changes);
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_diff(running_config, candidate, &changes);
- ret = nb_candidate_validate_changes(candidate, &changes);
- nb_config_diff_del_changes(&changes);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ nb_config_diff(running_config, candidate, &changes);
+ ret = nb_candidate_validate_code(candidate, &changes);
+ nb_config_diff_del_changes(&changes);
return ret;
}
@@ -635,36 +672,26 @@ int nb_candidate_commit_prepare(struct nb_config *candidate,
}
RB_INIT(nb_config_cbs, &changes);
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_diff(running_config, candidate, &changes);
- if (RB_EMPTY(nb_config_cbs, &changes)) {
- pthread_rwlock_unlock(&running_config->lock);
- return NB_ERR_NO_CHANGES;
- }
+ nb_config_diff(running_config, candidate, &changes);
+ if (RB_EMPTY(nb_config_cbs, &changes))
+ return NB_ERR_NO_CHANGES;
- if (nb_candidate_validate_changes(candidate, &changes)
- != NB_OK) {
- flog_warn(
- EC_LIB_NB_CANDIDATE_INVALID,
- "%s: failed to validate candidate configuration",
- __func__);
- nb_config_diff_del_changes(&changes);
- pthread_rwlock_unlock(&running_config->lock);
- return NB_ERR_VALIDATION;
- }
+ if (nb_candidate_validate_code(candidate, &changes) != NB_OK) {
+ flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
+ "%s: failed to validate candidate configuration",
+ __func__);
+ nb_config_diff_del_changes(&changes);
+ return NB_ERR_VALIDATION;
+ }
- *transaction = nb_transaction_new(candidate, &changes, client,
- user, comment);
- if (*transaction == NULL) {
- flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
- "%s: failed to create transaction", __func__);
- nb_config_diff_del_changes(&changes);
- pthread_rwlock_unlock(&running_config->lock);
- return NB_ERR_LOCKED;
- }
+ *transaction =
+ nb_transaction_new(candidate, &changes, client, user, comment);
+ if (*transaction == NULL) {
+ flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
+ "%s: failed to create transaction", __func__);
+ nb_config_diff_del_changes(&changes);
+ return NB_ERR_LOCKED;
}
- pthread_rwlock_unlock(&running_config->lock);
return nb_transaction_process(NB_EV_PREPARE, *transaction);
}
@@ -683,11 +710,7 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction,
/* Replace running by candidate. */
transaction->config->version++;
- pthread_rwlock_wrlock(&running_config->lock);
- {
- nb_config_replace(running_config, transaction->config, true);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ nb_config_replace(running_config, transaction->config, true);
/* Record transaction. */
if (save_transaction
@@ -786,7 +809,7 @@ static int nb_callback_configuration(const enum nb_event event,
struct nb_config_change *change)
{
enum nb_operation operation = change->cb.operation;
- const char *xpath = change->cb.xpath;
+ char xpath[XPATH_MAXLEN];
const struct nb_node *nb_node = change->cb.nb_node;
const struct lyd_node *dnode = change->cb.dnode;
union nb_resource *resource;
@@ -798,6 +821,7 @@ static int nb_callback_configuration(const enum nb_event event,
if (dnode && !yang_snode_is_typeless_data(dnode->schema))
value = yang_dnode_get_string(dnode, NULL);
+ yang_dnode_get_path(dnode, xpath, sizeof(xpath));
nb_log_callback(event, operation, xpath, value);
}
@@ -820,6 +844,7 @@ static int nb_callback_configuration(const enum nb_event event,
ret = (*nb_node->cbs.move)(event, dnode);
break;
default:
+ yang_dnode_get_path(dnode, xpath, sizeof(xpath));
flog_err(EC_LIB_DEVELOPMENT,
"%s: unknown operation (%u) [xpath %s]", __func__,
operation, xpath);
@@ -830,6 +855,8 @@ static int nb_callback_configuration(const enum nb_event event,
int priority;
enum lib_log_refs ref;
+ yang_dnode_get_path(dnode, xpath, sizeof(xpath));
+
switch (event) {
case NB_EV_VALIDATE:
priority = LOG_WARNING;
@@ -961,65 +988,51 @@ static int nb_transaction_process(enum nb_event event,
{
struct nb_config_cb *cb;
- /*
- * Need to lock the running configuration since transaction->changes
- * can contain pointers to data nodes from the running configuration.
- */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- RB_FOREACH (cb, nb_config_cbs, &transaction->changes) {
- struct nb_config_change *change =
- (struct nb_config_change *)cb;
- int ret;
+ RB_FOREACH (cb, nb_config_cbs, &transaction->changes) {
+ struct nb_config_change *change = (struct nb_config_change *)cb;
+ int ret;
+ /*
+ * Only try to release resources that were allocated
+ * successfully.
+ */
+ if (event == NB_EV_ABORT && change->prepare_ok == false)
+ break;
+
+ /* Call the appropriate callback. */
+ ret = nb_callback_configuration(event, change);
+ switch (event) {
+ case NB_EV_PREPARE:
+ if (ret != NB_OK)
+ return ret;
+ change->prepare_ok = true;
+ break;
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
/*
- * Only try to release resources that were allocated
- * successfully.
+ * At this point it's not possible to reject the
+ * transaction anymore, so any failure here can lead to
+ * inconsistencies and should be treated as a bug.
+ * Operations prone to errors, like validations and
+ * resource allocations, should be performed during the
+ * 'prepare' phase.
*/
- if (event == NB_EV_ABORT && change->prepare_ok == false)
- break;
-
- /* Call the appropriate callback. */
- ret = nb_callback_configuration(event, change);
- switch (event) {
- case NB_EV_PREPARE:
- if (ret != NB_OK) {
- pthread_rwlock_unlock(
- &running_config->lock);
- return ret;
- }
- change->prepare_ok = true;
- break;
- case NB_EV_ABORT:
- case NB_EV_APPLY:
- /*
- * At this point it's not possible to reject the
- * transaction anymore, so any failure here can
- * lead to inconsistencies and should be treated
- * as a bug. Operations prone to errors, like
- * validations and resource allocations, should
- * be performed during the 'prepare' phase.
- */
- break;
- default:
- break;
- }
+ break;
+ default:
+ break;
}
}
- pthread_rwlock_unlock(&running_config->lock);
return NB_OK;
}
static struct nb_config_cb *
-nb_apply_finish_cb_new(struct nb_config_cbs *cbs, const char *xpath,
- const struct nb_node *nb_node,
+nb_apply_finish_cb_new(struct nb_config_cbs *cbs, const struct nb_node *nb_node,
const struct lyd_node *dnode)
{
struct nb_config_cb *cb;
cb = XCALLOC(MTYPE_TMP, sizeof(*cb));
- strlcpy(cb->xpath, xpath, sizeof(cb->xpath));
cb->nb_node = nb_node;
cb->dnode = dnode;
RB_INSERT(nb_config_cbs, cbs, cb);
@@ -1028,13 +1041,15 @@ nb_apply_finish_cb_new(struct nb_config_cbs *cbs, const char *xpath,
}
static struct nb_config_cb *
-nb_apply_finish_cb_find(struct nb_config_cbs *cbs, const char *xpath,
- const struct nb_node *nb_node)
+nb_apply_finish_cb_find(struct nb_config_cbs *cbs,
+ const struct nb_node *nb_node,
+ const struct lyd_node *dnode)
{
struct nb_config_cb s;
- strlcpy(s.xpath, xpath, sizeof(s.xpath));
+ s.seq = 0;
s.nb_node = nb_node;
+ s.dnode = dnode;
return RB_FIND(nb_config_cbs, cbs, &s);
}
@@ -1043,6 +1058,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction)
{
struct nb_config_cbs cbs;
struct nb_config_cb *cb;
+ char xpath[XPATH_MAXLEN];
/* Initialize tree of 'apply_finish' callbacks. */
RB_INIT(nb_config_cbs, &cbs);
@@ -1059,8 +1075,6 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction)
* be called though).
*/
if (change->cb.operation == NB_OP_DESTROY) {
- char xpath[XPATH_MAXLEN];
-
dnode = dnode->parent;
if (!dnode)
break;
@@ -1076,7 +1090,6 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction)
xpath);
}
while (dnode) {
- char xpath[XPATH_MAXLEN];
struct nb_node *nb_node;
nb_node = dnode->schema->priv;
@@ -1087,11 +1100,10 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction)
* Don't call the callback more than once for the same
* data node.
*/
- yang_dnode_get_path(dnode, xpath, sizeof(xpath));
- if (nb_apply_finish_cb_find(&cbs, xpath, nb_node))
+ if (nb_apply_finish_cb_find(&cbs, nb_node, dnode))
goto next;
- nb_apply_finish_cb_new(&cbs, xpath, nb_node, dnode);
+ nb_apply_finish_cb_new(&cbs, nb_node, dnode);
next:
dnode = dnode->parent;
@@ -1100,9 +1112,11 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction)
/* Call the 'apply_finish' callbacks, sorted by their priorities. */
RB_FOREACH (cb, nb_config_cbs, &cbs) {
- if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config, DEBUG_MODE_ALL))
- nb_log_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH,
- cb->xpath, NULL);
+ if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config, DEBUG_MODE_ALL)) {
+ yang_dnode_get_path(cb->dnode, xpath, sizeof(xpath));
+ nb_log_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, xpath,
+ NULL);
+ }
(*cb->nb_node->cbs.apply_finish)(cb->dnode);
}
@@ -1310,9 +1324,27 @@ static int nb_oper_data_iter_node(const struct lys_node *snode,
/* Update XPath. */
strlcpy(xpath, xpath_parent, sizeof(xpath));
- if (!first && snode->nodetype != LYS_USES)
- snprintf(xpath + strlen(xpath), sizeof(xpath) - strlen(xpath),
- "/%s", snode->name);
+ if (!first && snode->nodetype != LYS_USES) {
+ struct lys_node *parent;
+
+ /* Get the real parent. */
+ parent = snode->parent;
+ while (parent && parent->nodetype == LYS_USES)
+ parent = parent->parent;
+
+ /*
+ * When necessary, include the namespace of the augmenting
+ * module.
+ */
+ if (parent && parent->nodetype == LYS_AUGMENT)
+ snprintf(xpath + strlen(xpath),
+ sizeof(xpath) - strlen(xpath), "/%s:%s",
+ snode->module->name, snode->name);
+ else
+ snprintf(xpath + strlen(xpath),
+ sizeof(xpath) - strlen(xpath), "/%s",
+ snode->name);
+ }
nb_node = snode->priv;
switch (snode->nodetype) {
@@ -1550,6 +1582,7 @@ bool nb_operation_is_valid(enum nb_operation operation,
return false;
}
return true;
+ case NB_OP_PRE_VALIDATE:
case NB_OP_APPLY_FINISH:
if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return false;
@@ -1768,6 +1801,8 @@ const char *nb_operation_name(enum nb_operation operation)
return "destroy";
case NB_OP_MOVE:
return "move";
+ case NB_OP_PRE_VALIDATE:
+ return "pre_validate";
case NB_OP_APPLY_FINISH:
return "apply_finish";
case NB_OP_GET_ELEM:
diff --git a/lib/northbound.h b/lib/northbound.h
index ce79d907f..f52fcc90c 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -72,6 +72,7 @@ enum nb_operation {
NB_OP_MODIFY,
NB_OP_DESTROY,
NB_OP_MOVE,
+ NB_OP_PRE_VALIDATE,
NB_OP_APPLY_FINISH,
NB_OP_GET_ELEM,
NB_OP_GET_NEXT,
@@ -199,6 +200,19 @@ struct nb_callbacks {
/*
* Optional configuration callback.
*
+ * This callback can be used to validate subsections of the
+ * configuration being committed before validating the configuration
+ * changes themselves. It's useful to perform more complex validations
+ * that depend on the relationship between multiple nodes.
+ *
+ * dnode
+ * libyang data node associated with the 'pre_validate' callback.
+ */
+ int (*pre_validate)(const struct lyd_node *dnode);
+
+ /*
+ * Optional configuration callback.
+ *
* The 'apply_finish' callbacks are called after all other callbacks
* during the apply phase (NB_EV_APPLY). These callbacks are called only
* under one of the following two cases:
@@ -435,26 +449,15 @@ enum nb_client {
/* Northbound configuration. */
struct nb_config {
- /* Configuration data. */
struct lyd_node *dnode;
-
- /* Configuration version. */
uint32_t version;
-
- /*
- * Lock protecting this structure. The use of this lock is always
- * necessary when reading or modifying the global running configuration.
- * For candidate configurations, use of this lock is optional depending
- * on the threading scheme of the northbound plugin.
- */
- pthread_rwlock_t lock;
};
/* Northbound configuration callback. */
struct nb_config_cb {
RB_ENTRY(nb_config_cb) entry;
enum nb_operation operation;
- char xpath[XPATH_MAXLEN];
+ uint32_t seq;
const struct nb_node *nb_node;
const struct lyd_node *dnode;
};
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 884c01a45..d3e788d5d 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -40,6 +40,7 @@ struct debug nb_dbg_cbs_state = {0, "Northbound callbacks: state"};
struct debug nb_dbg_cbs_rpc = {0, "Northbound callbacks: RPCs"};
struct debug nb_dbg_notif = {0, "Northbound notifications"};
struct debug nb_dbg_events = {0, "Northbound events"};
+struct debug nb_dbg_libyang = {0, "libyang debugging"};
struct nb_config *vty_shared_candidate_config;
static struct thread_master *master;
@@ -84,20 +85,12 @@ void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
{
- struct nb_config *candidate_transitory;
char xpath_base[XPATH_MAXLEN] = {};
bool error = false;
int ret;
VTY_CHECK_XPATH;
- /*
- * Create a copy of the candidate configuration. For consistency, we
- * need to ensure that either all changes made by the command are
- * accepted or none are.
- */
- candidate_transitory = nb_config_dup(vty->candidate_config);
-
/* Parse the base XPath format string. */
if (xpath_base_fmt) {
va_list ap;
@@ -137,7 +130,7 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH,
"%s: unknown data path: %s", __func__, xpath);
error = true;
- break;
+ continue;
}
/* If the value is not set, get the default if it exists. */
@@ -149,7 +142,7 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
* Ignore "not found" errors when editing the candidate
* configuration.
*/
- ret = nb_candidate_edit(candidate_transitory, nb_node,
+ ret = nb_candidate_edit(vty->candidate_config, nb_node,
change->operation, xpath, NULL, data);
yang_data_free(data);
if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) {
@@ -159,29 +152,20 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
__func__, nb_operation_name(change->operation),
xpath);
error = true;
- break;
+ continue;
}
}
if (error) {
- nb_config_free(candidate_transitory);
-
- switch (frr_get_cli_mode()) {
- case FRR_CLI_CLASSIC:
- vty_out(vty, "%% Configuration failed.\n\n");
- break;
- case FRR_CLI_TRANSACTIONAL:
- vty_out(vty,
- "%% Failed to edit candidate configuration.\n\n");
- break;
- }
+ /*
+ * Failure to edit the candidate configuration should never
+ * happen in practice, unless there's a bug in the code. When
+ * that happens, log the error but otherwise ignore it.
+ */
+ vty_out(vty, "%% Failed to edit configuration.\n\n");
vty_show_libyang_errors(vty, ly_native_ctx);
-
- return CMD_WARNING_CONFIG_FAILED;
}
- nb_config_replace(vty->candidate_config, candidate_transitory, false);
-
/* Do an implicit "commit" when using the classic CLI mode. */
if (frr_get_cli_mode() == FRR_CLI_CLASSIC) {
ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI,
@@ -193,13 +177,8 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
"Please check the logs for more details.\n");
/* Regenerate candidate for consistency. */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_replace(vty->candidate_config,
- running_config, true);
- }
- pthread_rwlock_unlock(&running_config->lock);
-
+ nb_config_replace(vty->candidate_config, running_config,
+ true);
return CMD_WARNING_CONFIG_FAILED;
}
}
@@ -307,12 +286,7 @@ static int nb_cli_commit(struct vty *vty, bool force,
/* "confirm" parameter. */
if (confirmed_timeout) {
- pthread_rwlock_rdlock(&running_config->lock);
- {
- vty->confirmed_commit_rollback =
- nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ vty->confirmed_commit_rollback = nb_config_dup(running_config);
vty->t_confirmed_commit_timeout = NULL;
thread_add_timer(master, nb_cli_confirmed_commit_timeout, vty,
@@ -326,13 +300,8 @@ static int nb_cli_commit(struct vty *vty, bool force,
/* Map northbound return code to CLI return code. */
switch (ret) {
case NB_OK:
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_replace(vty->candidate_config_base,
- running_config, true);
- }
- pthread_rwlock_unlock(&running_config->lock);
-
+ nb_config_replace(vty->candidate_config_base, running_config,
+ true);
vty_out(vty,
"%% Configuration committed successfully (Transaction ID #%u).\n\n",
transaction_id);
@@ -453,6 +422,27 @@ static struct lyd_node *ly_iter_next_up(const struct lyd_node *elem)
return elem->parent;
}
+/* Prepare the configuration for display. */
+void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults)
+{
+ /* Nothing to do for daemons that don't implement any YANG module. */
+ if (config->dnode == NULL)
+ return;
+
+ lyd_schema_sort(config->dnode, 1);
+
+ /*
+ * When "with-defaults" is used, call lyd_validate() only to create
+ * default child nodes, ignoring any possible validation error. This
+ * doesn't need to be done when displaying the running configuration
+ * since it's always fully validated.
+ */
+ if (with_defaults && config != running_config)
+ (void)lyd_validate(&config->dnode,
+ LYD_OPT_CONFIG | LYD_OPT_WHENAUTODEL,
+ ly_native_ctx);
+}
+
void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
bool with_defaults)
{
@@ -545,6 +535,8 @@ static int nb_cli_show_config(struct vty *vty, struct nb_config *config,
struct yang_translator *translator,
bool with_defaults)
{
+ nb_cli_show_config_prepare(config, with_defaults);
+
switch (format) {
case NB_CFG_FMT_CMDS:
nb_cli_show_config_cmds(vty, config, with_defaults);
@@ -729,12 +721,7 @@ DEFPY (config_update,
return CMD_WARNING;
}
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_config_replace(vty->candidate_config_base, running_config,
- true);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ nb_config_replace(vty->candidate_config_base, running_config, true);
vty_out(vty, "%% Candidate configuration updated successfully.\n\n");
@@ -834,12 +821,8 @@ DEFPY (show_config_running,
}
}
- pthread_rwlock_rdlock(&running_config->lock);
- {
- nb_cli_show_config(vty, running_config, format, translator,
- !!with_defaults);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ nb_cli_show_config(vty, running_config, format, translator,
+ !!with_defaults);
return CMD_SUCCESS;
}
@@ -953,68 +936,57 @@ DEFPY (show_config_compare,
struct nb_config *config2, *config_transaction2 = NULL;
int ret = CMD_WARNING;
- /*
- * For simplicity, lock the running configuration regardless if it's
- * going to be used or not.
- */
- pthread_rwlock_rdlock(&running_config->lock);
- {
- if (c1_candidate)
- config1 = vty->candidate_config;
- else if (c1_running)
- config1 = running_config;
- else {
- config_transaction1 = nb_db_transaction_load(c1_tid);
- if (!config_transaction1) {
- vty_out(vty,
- "%% Transaction %u does not exist\n\n",
- (unsigned int)c1_tid);
- goto exit;
- }
- config1 = config_transaction1;
+ if (c1_candidate)
+ config1 = vty->candidate_config;
+ else if (c1_running)
+ config1 = running_config;
+ else {
+ config_transaction1 = nb_db_transaction_load(c1_tid);
+ if (!config_transaction1) {
+ vty_out(vty, "%% Transaction %u does not exist\n\n",
+ (unsigned int)c1_tid);
+ goto exit;
}
+ config1 = config_transaction1;
+ }
- if (c2_candidate)
- config2 = vty->candidate_config;
- else if (c2_running)
- config2 = running_config;
- else {
- config_transaction2 = nb_db_transaction_load(c2_tid);
- if (!config_transaction2) {
- vty_out(vty,
- "%% Transaction %u does not exist\n\n",
- (unsigned int)c2_tid);
- goto exit;
- }
- config2 = config_transaction2;
+ if (c2_candidate)
+ config2 = vty->candidate_config;
+ else if (c2_running)
+ config2 = running_config;
+ else {
+ config_transaction2 = nb_db_transaction_load(c2_tid);
+ if (!config_transaction2) {
+ vty_out(vty, "%% Transaction %u does not exist\n\n",
+ (unsigned int)c2_tid);
+ goto exit;
}
+ config2 = config_transaction2;
+ }
- if (json)
- format = NB_CFG_FMT_JSON;
- else if (xml)
- format = NB_CFG_FMT_XML;
- else
- format = NB_CFG_FMT_CMDS;
+ if (json)
+ format = NB_CFG_FMT_JSON;
+ else if (xml)
+ format = NB_CFG_FMT_XML;
+ else
+ format = NB_CFG_FMT_CMDS;
- if (translator_family) {
- translator = yang_translator_find(translator_family);
- if (!translator) {
- vty_out(vty,
- "%% Module translator \"%s\" not found\n",
- translator_family);
- goto exit;
- }
+ if (translator_family) {
+ translator = yang_translator_find(translator_family);
+ if (!translator) {
+ vty_out(vty, "%% Module translator \"%s\" not found\n",
+ translator_family);
+ goto exit;
}
-
- ret = nb_cli_show_config_compare(vty, config1, config2, format,
- translator);
- exit:
- if (config_transaction1)
- nb_config_free(config_transaction1);
- if (config_transaction2)
- nb_config_free(config_transaction2);
}
- pthread_rwlock_unlock(&running_config->lock);
+
+ ret = nb_cli_show_config_compare(vty, config1, config2, format,
+ translator);
+exit:
+ if (config_transaction1)
+ nb_config_free(config_transaction1);
+ if (config_transaction2)
+ nb_config_free(config_transaction2);
return ret;
}
@@ -1610,7 +1582,7 @@ DEFPY (rollback_config,
/* Debug CLI commands. */
static struct debug *nb_debugs[] = {
&nb_dbg_cbs_config, &nb_dbg_cbs_state, &nb_dbg_cbs_rpc,
- &nb_dbg_notif, &nb_dbg_events,
+ &nb_dbg_notif, &nb_dbg_events, &nb_dbg_libyang,
};
static const char *const nb_debugs_conflines[] = {
@@ -1619,6 +1591,7 @@ static const char *const nb_debugs_conflines[] = {
"debug northbound callbacks rpc",
"debug northbound notifications",
"debug northbound events",
+ "debug northbound libyang",
};
DEFINE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set));
@@ -1643,6 +1616,7 @@ DEFPY (debug_nb,
callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\
|notifications$notifications\
|events$events\
+ |libyang$libyang\
>]",
NO_STR
DEBUG_STR
@@ -1652,7 +1626,8 @@ DEFPY (debug_nb,
"State\n"
"RPC\n"
"Notifications\n"
- "Events\n")
+ "Events\n"
+ "libyang debugging\n")
{
uint32_t mode = DEBUG_NODE2MODE(vty->node);
@@ -1670,10 +1645,16 @@ DEFPY (debug_nb,
DEBUG_MODE_SET(&nb_dbg_notif, mode, !no);
if (events)
DEBUG_MODE_SET(&nb_dbg_events, mode, !no);
+ if (libyang) {
+ DEBUG_MODE_SET(&nb_dbg_libyang, mode, !no);
+ yang_debugging_set(!no);
+ }
/* no specific debug --> act on all of them */
- if (strmatch(argv[argc - 1]->text, "northbound"))
+ if (strmatch(argv[argc - 1]->text, "northbound")) {
nb_debug_set_all(mode, !no);
+ yang_debugging_set(!no);
+ }
return CMD_SUCCESS;
}
diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h
index 209239ca6..b2d8c8f03 100644
--- a/lib/northbound_cli.h
+++ b/lib/northbound_cli.h
@@ -109,6 +109,8 @@ extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
/* Prototypes of internal functions. */
+extern void nb_cli_show_config_prepare(struct nb_config *config,
+ bool with_defaults);
extern void nb_cli_confirmed_commit_clean(struct vty *vty);
extern int nb_cli_confirmed_commit_rollback(struct vty *vty);
extern void nb_cli_install_default(int node);
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index e9669fc7e..2fc3c81cf 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -289,11 +289,7 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
struct cdb_iter_args iter_args;
int ret;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- candidate = nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ candidate = nb_config_dup(running_config);
/* Iterate over all configuration changes. */
iter_args.candidate = candidate;
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index a55da23dd..089899368 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -18,6 +18,8 @@
//
#include <zebra.h>
+#include <grpcpp/grpcpp.h>
+#include "grpc/frr-northbound.grpc.pb.h"
#include "log.h"
#include "libfrr.h"
@@ -32,9 +34,6 @@
#include <memory>
#include <string>
-#include <grpcpp/grpcpp.h>
-#include "grpc/frr-northbound.grpc.pb.h"
-
#define GRPC_DEFAULT_PORT 50051
/*
@@ -617,6 +616,11 @@ class NorthboundImpl final : public frr::Northbound::Service
return LYD_JSON;
case frr::XML:
return LYD_XML;
+ default:
+ flog_err(EC_LIB_DEVELOPMENT,
+ "%s: unknown data encoding format (%u)",
+ __func__, encoding);
+ exit(1);
}
}
@@ -702,15 +706,10 @@ class NorthboundImpl final : public frr::Northbound::Service
{
struct lyd_node *dnode;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- dnode = yang_dnode_get(running_config->dnode,
- path.empty() ? NULL
- : path.c_str());
- if (dnode)
- dnode = yang_dnode_dup(dnode);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ dnode = yang_dnode_get(running_config->dnode,
+ path.empty() ? NULL : path.c_str());
+ if (dnode)
+ dnode = yang_dnode_dup(dnode);
return dnode;
}
@@ -817,11 +816,7 @@ class NorthboundImpl final : public frr::Northbound::Service
struct candidate *candidate = &_candidates[candidate_id];
candidate->id = candidate_id;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- candidate->config = nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ candidate->config = nb_config_dup(running_config);
candidate->transaction = NULL;
return candidate;
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 77183282b..b94c93976 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -256,11 +256,7 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session,
return ret;
}
- pthread_rwlock_rdlock(&running_config->lock);
- {
- candidate = nb_config_dup(running_config);
- }
- pthread_rwlock_unlock(&running_config->lock);
+ candidate = nb_config_dup(running_config);
while ((ret = sr_get_change_next(session, it, &sr_op, &sr_old_val,
&sr_new_val))
diff --git a/lib/pbr.h b/lib/pbr.h
index ecd50447e..cf6ac41d3 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -90,7 +90,7 @@ struct pbr_rule {
uint32_t unique;
struct pbr_filter filter;
struct pbr_action action;
- uint32_t ifindex;
+ ifindex_t ifindex;
};
/* TCP flags value shared
diff --git a/lib/prefix.c b/lib/prefix.c
index 35b679ab9..5071ca820 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -601,6 +601,53 @@ int prefix_match(const struct prefix *n, const struct prefix *p)
if (np[offset] != pp[offset])
return 0;
return 1;
+
+}
+
+/*
+ * n is a type5 evpn prefix. This function tries to see if there is an
+ * ip-prefix within n which matches prefix p
+ * If n includes p prefix then return 1 else return 0.
+ */
+int evpn_type5_prefix_match(const struct prefix *n, const struct prefix *p)
+{
+ int offset;
+ int shift;
+ int prefixlen;
+ const uint8_t *np, *pp;
+ struct prefix_evpn *evp;
+
+ if (n->family != AF_EVPN)
+ return 0;
+
+ evp = (struct prefix_evpn *)n;
+ pp = p->u.val;
+
+ if ((evp->prefix.route_type != 5) ||
+ (p->family == AF_INET6 && !is_evpn_prefix_ipaddr_v6(evp)) ||
+ (p->family == AF_INET && !is_evpn_prefix_ipaddr_v4(evp)) ||
+ (is_evpn_prefix_ipaddr_none(evp)))
+ return 0;
+
+ prefixlen = evp->prefix.prefix_addr.ip_prefix_length;
+ np = &evp->prefix.prefix_addr.ip.ip.addr;
+
+ /* If n's prefix is longer than p's one return 0. */
+ if (prefixlen > p->prefixlen)
+ return 0;
+
+ offset = prefixlen / PNBBY;
+ shift = prefixlen % PNBBY;
+
+ if (shift)
+ if (maskbit[shift] & (np[offset] ^ pp[offset]))
+ return 0;
+
+ while (offset--)
+ if (np[offset] != pp[offset])
+ return 0;
+ return 1;
+
}
/* If n includes p then return 1 else return 0. Prefix mask is not considered */
@@ -773,8 +820,18 @@ int prefix_cmp(union prefixconstptr up1, union prefixconstptr up2)
if (i)
return i;
- return numcmp(pp1[offset] & maskbit[shift],
- pp2[offset] & maskbit[shift]);
+ /*
+ * At this point offset was the same, if we have shift
+ * that means we still have data to compare, if shift is
+ * 0 then we are at the end of the data structure
+ * and should just return, as that we will be accessing
+ * memory beyond the end of the party zone
+ */
+ if (shift)
+ return numcmp(pp1[offset] & maskbit[shift],
+ pp2[offset] & maskbit[shift]);
+
+ return 0;
}
/*
diff --git a/lib/prefix.h b/lib/prefix.h
index 24c146e02..784927616 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -407,6 +407,8 @@ extern void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
char *buf, int buf_size);
extern const char *prefix_sg2str(const struct prefix_sg *sg, char *str);
extern const char *prefix2str(union prefixconstptr, char *, int);
+extern int evpn_type5_prefix_match(const struct prefix *evpn_pfx,
+ const struct prefix *match_pfx);
extern int prefix_match(const struct prefix *, const struct prefix *);
extern int prefix_match_network_statement(const struct prefix *,
const struct prefix *);
diff --git a/lib/printf/glue.c b/lib/printf/glue.c
index 1b760dc2d..29ca26ad5 100644
--- a/lib/printf/glue.c
+++ b/lib/printf/glue.c
@@ -101,9 +101,11 @@ char *vasnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
va_copy(ap2, ap);
len = vbprintfrr(&fb, fmt, ap);
- if (len < 0)
+ if (len < 0) {
+ va_end(ap2);
/* error = malformed format string => try something useful */
return qstrdup(mt, fmt);
+ }
if ((size_t)len >= outsz - 1) {
ret = qmalloc(mt, len + 1);
@@ -112,6 +114,8 @@ char *vasnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
vbprintfrr(&fb, fmt, ap2);
}
+
+ va_end(ap2);
ret[len] = '\0';
return ret;
}
diff --git a/lib/printf/printf-pos.c b/lib/printf/printf-pos.c
index 1f5f283e8..45e4f8622 100644
--- a/lib/printf/printf-pos.c
+++ b/lib/printf/printf-pos.c
@@ -98,7 +98,7 @@ inittypes(struct typetable *types)
types->table = types->stattable;
types->tablesize = STATIC_ARG_TBL_SIZE;
- types->tablemax = 0;
+ types->tablemax = 0;
types->nextarg = 1;
for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
types->table[n] = T_UNUSED;
@@ -106,7 +106,7 @@ inittypes(struct typetable *types)
/*
* struct typetable destructor.
- */
+ */
static inline void
freetypes(struct typetable *types)
{
@@ -255,7 +255,7 @@ addwaster(struct typetable *types, wchar_t **fmtp)
* initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
* It will be replaces with a malloc-ed one if it overflows.
* Returns 0 on success. On failure, returns nonzero and sets errno.
- */
+ */
int
_frr_find_arguments (const char *fmt0, va_list ap, union arg **argtable)
{
diff --git a/lib/route_types.txt b/lib/route_types.txt
index 59f3a91cf..71d0a4644 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -84,6 +84,7 @@ ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR"
ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric"
ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP"
+ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
@@ -113,3 +114,4 @@ ZEBRA_ROUTE_PBR, "Policy Based Routing (PBR)"
ZEBRA_ROUTE_BFD, "Bidirectional Fowarding Detection (BFD)"
ZEBRA_ROUTE_VRRP, "Virtual Router Redundancy Protocol (VRRP)"
ZEBRA_ROUTE_OPENFABRIC, "OpenFabric Routing Protocol"
+ZEBRA_ROUTE_NHG, "Zebra Nexthop Groups (NHG)"
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 8e38a2927..7726d74ff 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -72,6 +72,21 @@ int getsockopt_so_sendbuf(const int sock)
return optval;
}
+int getsockopt_so_recvbuf(const int sock)
+{
+ uint32_t optval;
+ socklen_t optlen = sizeof(optval);
+ int ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&optval,
+ &optlen);
+ if (ret < 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "fd %d: can't getsockopt SO_RCVBUF: %d (%s)", sock,
+ errno, safe_strerror(errno));
+ return ret;
+ }
+ return optval;
+}
+
static void *getsockopt_cmsg_data(struct msghdr *msgh, int level, int type)
{
struct cmsghdr *cmsg;
diff --git a/lib/sockopt.h b/lib/sockopt.h
index 732fec92a..f6b57b8e0 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -30,6 +30,7 @@ extern "C" {
extern void setsockopt_so_recvbuf(int sock, int size);
extern void setsockopt_so_sendbuf(const int sock, int size);
extern int getsockopt_so_sendbuf(const int sock);
+extern int getsockopt_so_recvbuf(const int sock);
extern int setsockopt_ipv6_pktinfo(int, int);
extern int setsockopt_ipv6_checksum(int, int);
diff --git a/lib/subdir.am b/lib/subdir.am
index e0f135238..23b195038 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -104,6 +104,7 @@ lib_libfrr_la_SOURCES = \
nodist_lib_libfrr_la_SOURCES = \
yang/frr-interface.yang.c \
yang/frr-route-types.yang.c \
+ yang/ietf/ietf-routing-types.yang.c \
yang/frr-module-translator.yang.c \
# end
diff --git a/lib/systemd.c b/lib/systemd.c
index 8a2a5eeac..44db48d00 100644
--- a/lib/systemd.c
+++ b/lib/systemd.c
@@ -86,6 +86,7 @@ static int systemd_get_watchdog_time(int the_process)
void systemd_send_stopping(void)
{
+ systemd_send_information("STATUS=");
systemd_send_information("STOPPING=1");
}
@@ -116,3 +117,11 @@ void systemd_send_started(struct thread_master *m, int the_process)
if (wsecs != 0)
thread_add_timer(m, systemd_send_watchdog, m, wsecs, NULL);
}
+
+void systemd_send_status(const char *status)
+{
+ char buffer[1024];
+
+ snprintf(buffer, sizeof(buffer), "STATUS=%s", status);
+ systemd_send_information(buffer);
+}
diff --git a/lib/systemd.h b/lib/systemd.h
index 6e43df527..1f730720c 100644
--- a/lib/systemd.h
+++ b/lib/systemd.h
@@ -42,6 +42,11 @@ void systemd_send_stopping(void);
*/
void systemd_send_started(struct thread_master *master, int the_process);
+/*
+ * status - A status string to send to systemd
+ */
+void systemd_send_status(const char *status);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/thread.c b/lib/thread.c
index 90c794e88..649fe500c 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -109,6 +109,7 @@ static void cpu_record_hash_free(void *a)
XFREE(MTYPE_THREAD_STATS, hist);
}
+#ifndef EXCLUDE_CPU_TIME
static void vty_out_cpu_thread_history(struct vty *vty,
struct cpu_thread_history *a)
{
@@ -219,6 +220,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
if (tmp.total_calls > 0)
vty_out_cpu_thread_history(vty, &tmp);
}
+#endif
static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[])
{
@@ -288,6 +290,7 @@ static uint8_t parse_filter(const char *filterstr)
return filter;
}
+#ifndef EXCLUDE_CPU_TIME
DEFUN (show_thread_cpu,
show_thread_cpu_cmd,
"show thread cpu [FILTER]",
@@ -313,6 +316,7 @@ DEFUN (show_thread_cpu,
cpu_record_print(vty, filter);
return CMD_SUCCESS;
}
+#endif
static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
{
@@ -403,7 +407,9 @@ DEFUN (clear_thread_cpu,
void thread_cmd_init(void)
{
+#ifndef EXCLUDE_CPU_TIME
install_element(VIEW_NODE, &show_thread_cpu_cmd);
+#endif
install_element(VIEW_NODE, &show_thread_poll_cmd);
install_element(ENABLE_NODE, &clear_thread_cpu_cmd);
}
@@ -975,6 +981,8 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state)
(master->handler.pfdcount - i - 1)
* sizeof(struct pollfd));
master->handler.pfdcount--;
+ master->handler.pfds[master->handler.pfdcount].fd = 0;
+ master->handler.pfds[master->handler.pfdcount].events = 0;
}
/* If we have the same pollfd in the copy, perform the same operations,
@@ -989,6 +997,8 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state)
(master->handler.copycount - i - 1)
* sizeof(struct pollfd));
master->handler.copycount--;
+ master->handler.copy[master->handler.copycount].fd = 0;
+ master->handler.copy[master->handler.copycount].events = 0;
}
}
@@ -1292,11 +1302,15 @@ static void thread_process_io(struct thread_master *m, unsigned int num)
(m->handler.pfdcount - i - 1)
* sizeof(struct pollfd));
m->handler.pfdcount--;
+ m->handler.pfds[m->handler.pfdcount].fd = 0;
+ m->handler.pfds[m->handler.pfdcount].events = 0;
memmove(pfds + i, pfds + i + 1,
(m->handler.copycount - i - 1)
* sizeof(struct pollfd));
m->handler.copycount--;
+ m->handler.copy[m->handler.copycount].fd = 0;
+ m->handler.copy[m->handler.copycount].events = 0;
i--;
}
@@ -1503,7 +1517,9 @@ void thread_getrusage(RUSAGE_T *r)
#define FRR_RUSAGE RUSAGE_SELF
#endif
monotime(&r->real);
+#ifndef EXCLUDE_CPU_TIME
getrusage(FRR_RUSAGE, &(r->cpu));
+#endif
}
/*
@@ -1519,9 +1535,11 @@ void thread_getrusage(RUSAGE_T *r)
*/
void thread_call(struct thread *thread)
{
+#ifndef EXCLUDE_CPU_TIME
_Atomic unsigned long realtime, cputime;
unsigned long exp;
unsigned long helper;
+#endif
RUSAGE_T before, after;
GETRUSAGE(&before);
@@ -1533,6 +1551,7 @@ void thread_call(struct thread *thread)
GETRUSAGE(&after);
+#ifndef EXCLUDE_CPU_TIME
realtime = thread_consumed_time(&after, &before, &helper);
cputime = helper;
@@ -1577,6 +1596,7 @@ void thread_call(struct thread *thread)
realtime / 1000, cputime / 1000);
}
#endif /* CONSUMED_TIME_CHECK */
+#endif /* Exclude CPU Time */
}
/* Execute thread */
diff --git a/lib/typesafe.c b/lib/typesafe.c
index 7e5939d5b..6635cf750 100644
--- a/lib/typesafe.c
+++ b/lib/typesafe.c
@@ -473,7 +473,7 @@ void typesafe_heap_resize(struct heap_head *head, bool grow)
newsize &= ~(HEAP_NARY - 1);
if (newsize == head->arraysz)
return;
-
+
head->array = XREALLOC(MTYPE_HEAP_ARRAY, head->array,
newsize * sizeof(struct heap_item *));
head->arraysz = newsize;
diff --git a/lib/vrf.c b/lib/vrf.c
index 4c6df797a..2411cc311 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -472,6 +472,14 @@ static const struct cmd_variable_handler vrf_var_handlers[] = {
.varname = "vrf",
.completions = vrf_autocomplete,
},
+ {
+ .varname = "vrf_name",
+ .completions = vrf_autocomplete,
+ },
+ {
+ .varname = "nexthop_vrf",
+ .completions = vrf_autocomplete,
+ },
{.completions = NULL},
};
diff --git a/lib/vty.c b/lib/vty.c
index deb9391bd..c08e5e151 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2341,8 +2341,7 @@ static void vty_read_file(struct nb_config *config, FILE *confp)
* Automatically commit the candidate configuration after
* reading the configuration file.
*/
- if (config == NULL && vty->candidate_config
- && frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) {
+ if (config == NULL) {
ret = nb_candidate_commit(vty->candidate_config, NB_CLIENT_CLI,
vty, true, "Read configuration file",
NULL);
@@ -2582,22 +2581,17 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
vty->private_config = private_config;
vty->xpath_index = 0;
- pthread_rwlock_rdlock(&running_config->lock);
- {
- if (private_config) {
- vty->candidate_config = nb_config_dup(running_config);
+ if (private_config) {
+ vty->candidate_config = nb_config_dup(running_config);
+ vty->candidate_config_base = nb_config_dup(running_config);
+ vty_out(vty,
+ "Warning: uncommitted changes will be discarded on exit.\n\n");
+ } else {
+ vty->candidate_config = vty_shared_candidate_config;
+ if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
vty->candidate_config_base =
nb_config_dup(running_config);
- vty_out(vty,
- "Warning: uncommitted changes will be discarded on exit.\n\n");
- } else {
- vty->candidate_config = vty_shared_candidate_config;
- if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
- vty->candidate_config_base =
- nb_config_dup(running_config);
- }
}
- pthread_rwlock_unlock(&running_config->lock);
return CMD_SUCCESS;
}
diff --git a/lib/vty.h b/lib/vty.h
index c7352efbd..a0b8e8afa 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -254,7 +254,8 @@ static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
#define VTY_CHECK_XPATH \
do { \
- if (vty->xpath_index > 0 \
+ if (vty->type != VTY_FILE && !vty->private_config \
+ && vty->xpath_index > 0 \
&& !yang_dnode_exists(vty->candidate_config->dnode, \
VTY_CURR_XPATH)) { \
vty_out(vty, \
diff --git a/lib/yang.c b/lib/yang.c
index 674f3610d..d153f7553 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -595,7 +595,7 @@ struct yang_data *yang_data_list_find(const struct list *list,
/* Make libyang log its errors using FRR logging infrastructure. */
static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
{
- int priority;
+ int priority = LOG_ERR;
switch (level) {
case LY_LLERR:
@@ -605,10 +605,9 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
priority = LOG_WARNING;
break;
case LY_LLVRB:
+ case LY_LLDBG:
priority = LOG_DEBUG;
break;
- default:
- return;
}
if (path)
@@ -617,6 +616,17 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
zlog(priority, "libyang: %s", msg);
}
+void yang_debugging_set(bool enable)
+{
+ if (enable) {
+ ly_verb(LY_LLDBG);
+ ly_verb_dbg(0xFF);
+ } else {
+ ly_verb(LY_LLERR);
+ ly_verb_dbg(0);
+ }
+}
+
struct ly_ctx *yang_ctx_new_setup(void)
{
struct ly_ctx *ctx;
diff --git a/lib/yang.h b/lib/yang.h
index 322c74c76..6892e3601 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -486,6 +486,14 @@ extern struct yang_data *yang_data_list_find(const struct list *list,
extern struct ly_ctx *yang_ctx_new_setup(void);
/*
+ * Enable or disable libyang verbose debugging.
+ *
+ * enable
+ * When set to true, enable libyang verbose debugging, otherwise disable it.
+ */
+extern void yang_debugging_set(bool enable);
+
+/*
* Initialize the YANG subsystem. Should be called only once during the
* daemon initialization process.
*/
diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c
index cd776f333..a308b18b7 100644
--- a/lib/yang_wrappers.c
+++ b/lib/yang_wrappers.c
@@ -782,6 +782,66 @@ void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt,
}
/*
+ * Derived type: IP prefix.
+ */
+void yang_str2prefix(const char *value, union prefixptr prefix)
+{
+ (void)str2prefix(value, prefix.p);
+ apply_mask(prefix.p);
+}
+
+struct yang_data *yang_data_new_prefix(const char *xpath,
+ union prefixconstptr prefix)
+{
+ char value_str[PREFIX2STR_BUFFER];
+
+ (void)prefix2str(prefix.p, value_str, sizeof(value_str));
+ return yang_data_new(xpath, value_str);
+}
+
+void yang_dnode_get_prefix(struct prefix *prefix, const struct lyd_node *dnode,
+ const char *xpath_fmt, ...)
+{
+ const struct lyd_node_leaf_list *dleaf;
+
+ assert(dnode);
+ if (xpath_fmt) {
+ va_list ap;
+ char xpath[XPATH_MAXLEN];
+
+ va_start(ap, xpath_fmt);
+ vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+ va_end(ap);
+ dnode = yang_dnode_get(dnode, xpath);
+ YANG_DNODE_GET_ASSERT(dnode, xpath);
+ }
+
+ /*
+ * Initialize prefix to avoid static analyzer complaints about
+ * uninitialized memory.
+ */
+ memset(prefix, 0, sizeof(*prefix));
+
+ dleaf = (const struct lyd_node_leaf_list *)dnode;
+ assert(dleaf->value_type == LY_TYPE_STRING);
+ (void)str2prefix(dleaf->value_str, prefix);
+}
+
+void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt, ...)
+{
+ char xpath[XPATH_MAXLEN];
+ const char *value;
+ va_list ap;
+
+ va_start(ap, xpath_fmt);
+ vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+ va_end(ap);
+
+ value = yang_get_default_value(xpath);
+ yang_str2prefix(value, var);
+}
+
+/*
* Derived type: ipv4.
*/
void yang_str2ipv4(const char *value, struct in_addr *addr)
diff --git a/lib/yang_wrappers.h b/lib/yang_wrappers.h
index ab7abe173..10d1ea314 100644
--- a/lib/yang_wrappers.h
+++ b/lib/yang_wrappers.h
@@ -114,6 +114,16 @@ extern const char *yang_get_default_string(const char *xpath_fmt, ...);
extern void yang_get_default_string_buf(char *buf, size_t size,
const char *xpath_fmt, ...);
+/* ip prefix */
+extern void yang_str2prefix(const char *value, union prefixptr prefix);
+extern struct yang_data *yang_data_new_prefix(const char *xpath,
+ union prefixconstptr prefix);
+extern void yang_dnode_get_prefix(struct prefix *prefix,
+ const struct lyd_node *dnode,
+ const char *xpath_fmt, ...);
+extern void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt,
+ ...);
+
/* ipv4 */
extern void yang_str2ipv4(const char *value, struct in_addr *addr);
extern struct yang_data *yang_data_new_ipv4(const char *xpath,
diff --git a/lib/zclient.c b/lib/zclient.c
index 92a495ac6..a135d1874 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -49,6 +49,9 @@ enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
/* Prototype for event manager. */
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 sockaddr_storage zclient_addr;
@@ -290,6 +293,10 @@ int zclient_send_message(struct zclient *zclient)
return 0;
}
+/*
+ * If we add more data to this structure please ensure that
+ * struct zmsghdr in lib/zclient.h is updated as appropriate.
+ */
void zclient_create_header(struct stream *s, uint16_t command, vrf_id_t vrf_id)
{
/* length placeholder, caller can update */
@@ -1547,10 +1554,11 @@ static void zclient_vrf_delete(struct zclient *zclient, vrf_id_t vrf_id)
vrf_delete(vrf);
}
-struct interface *zebra_interface_add_read(struct stream *s, vrf_id_t vrf_id)
+static void zclient_interface_add(struct zclient *zclient, vrf_id_t vrf_id)
{
struct interface *ifp;
char ifname_tmp[INTERFACE_NAMSIZ];
+ struct stream *s = zclient->ibuf;
/* Read interface name. */
stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
@@ -1560,15 +1568,14 @@ struct interface *zebra_interface_add_read(struct stream *s, vrf_id_t vrf_id)
zebra_interface_if_set_value(s, ifp);
- return ifp;
+ if_new_via_zapi(ifp);
}
/*
* Read interface up/down msg (ZEBRA_INTERFACE_UP/ZEBRA_INTERFACE_DOWN)
* from zebra server. The format of this message is the same as
- * that sent for ZEBRA_INTERFACE_ADD/ZEBRA_INTERFACE_DELETE (see
- * comments for zebra_interface_add_read), except that no sockaddr_dl
- * is sent at the tail of the message.
+ * that sent for ZEBRA_INTERFACE_ADD/ZEBRA_INTERFACE_DELETE,
+ * except that no sockaddr_dl is sent at the tail of the message.
*/
struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id)
{
@@ -1592,6 +1599,46 @@ struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id)
return ifp;
}
+static void zclient_interface_delete(struct zclient *zclient, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct stream *s = zclient->ibuf;
+
+ ifp = zebra_interface_state_read(s, vrf_id);
+
+ if (ifp == NULL)
+ return;
+
+ if_destroy_via_zapi(ifp);
+ return;
+}
+
+static void zclient_interface_up(struct zclient *zclient, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct stream *s = zclient->ibuf;
+
+ ifp = zebra_interface_state_read(s, vrf_id);
+
+ if (!ifp)
+ return;
+
+ if_up_via_zapi(ifp);
+}
+
+static void zclient_interface_down(struct zclient *zclient, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct stream *s = zclient->ibuf;
+
+ ifp = zebra_interface_state_read(s, vrf_id);
+
+ if (!ifp)
+ return;
+
+ if_down_via_zapi(ifp);
+}
+
static void link_params_set_value(struct stream *s, struct if_link_params *iflp)
{
@@ -1656,7 +1703,8 @@ struct interface *zebra_interface_link_params_read(struct stream *s,
return ifp;
}
-void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
+static void zebra_interface_if_set_value(struct stream *s,
+ struct interface *ifp)
{
uint8_t link_params_status = 0;
ifindex_t old_ifindex;
@@ -1944,7 +1992,7 @@ struct interface *zebra_interface_vrf_update_read(struct stream *s,
}
/* Fetch new VRF Id. */
- new_id = stream_getw(s);
+ new_id = stream_getl(s);
*new_vrf_id = new_id;
return ifp;
@@ -2789,14 +2837,10 @@ static int zclient_read(struct thread *thread)
zclient_vrf_delete(zclient, vrf_id);
break;
case ZEBRA_INTERFACE_ADD:
- if (zclient->interface_add)
- (*zclient->interface_add)(command, zclient, length,
- vrf_id);
+ zclient_interface_add(zclient, vrf_id);
break;
case ZEBRA_INTERFACE_DELETE:
- if (zclient->interface_delete)
- (*zclient->interface_delete)(command, zclient, length,
- vrf_id);
+ zclient_interface_delete(zclient, vrf_id);
break;
case ZEBRA_INTERFACE_ADDRESS_ADD:
if (zclient->interface_address_add)
@@ -2824,14 +2868,10 @@ static int zclient_read(struct thread *thread)
command, zclient, length, vrf_id);
break;
case ZEBRA_INTERFACE_UP:
- if (zclient->interface_up)
- (*zclient->interface_up)(command, zclient, length,
- vrf_id);
+ zclient_interface_up(zclient, vrf_id);
break;
case ZEBRA_INTERFACE_DOWN:
- if (zclient->interface_down)
- (*zclient->interface_down)(command, zclient, length,
- vrf_id);
+ zclient_interface_down(zclient, vrf_id);
break;
case ZEBRA_INTERFACE_VRF_UPDATE:
if (zclient->interface_vrf_update)
diff --git a/lib/zclient.h b/lib/zclient.h
index eb3c97b11..2131d4d47 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -240,10 +240,6 @@ struct zclient {
void (*zebra_connected)(struct zclient *);
void (*zebra_capabilities)(struct zclient_capabilities *cap);
int (*router_id_update)(ZAPI_CALLBACK_ARGS);
- int (*interface_add)(ZAPI_CALLBACK_ARGS);
- int (*interface_delete)(ZAPI_CALLBACK_ARGS);
- int (*interface_up)(ZAPI_CALLBACK_ARGS);
- int (*interface_down)(ZAPI_CALLBACK_ARGS);
int (*interface_address_add)(ZAPI_CALLBACK_ARGS);
int (*interface_address_delete)(ZAPI_CALLBACK_ARGS);
int (*interface_link_params)(ZAPI_CALLBACK_ARGS);
@@ -302,7 +298,8 @@ struct zmsghdr {
uint8_t version;
vrf_id_t vrf_id;
uint16_t command;
-};
+} __attribute__((packed));
+#define ZAPI_HEADER_CMD_LOCATION offsetof(struct zmsghdr, command)
struct zapi_nexthop {
enum nexthop_types_t type;
@@ -617,7 +614,6 @@ extern bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr);
extern void zclient_interface_set_master(struct zclient *client,
struct interface *master,
struct interface *slave);
-extern struct interface *zebra_interface_add_read(struct stream *, vrf_id_t);
extern struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t);
extern struct connected *zebra_interface_address_read(int, struct stream *,
vrf_id_t);
@@ -626,7 +622,6 @@ zebra_interface_nbr_address_read(int, struct stream *, vrf_id_t);
extern struct interface *zebra_interface_vrf_update_read(struct stream *s,
vrf_id_t vrf_id,
vrf_id_t *new_vrf_id);
-extern void zebra_interface_if_set_value(struct stream *, struct interface *);
extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
extern struct interface *zebra_interface_link_params_read(struct stream *s,
diff --git a/lib/zebra.h b/lib/zebra.h
index b17ef700b..de9a347e1 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -52,10 +52,9 @@ typedef unsigned char uint8_t;
#include <sys/types.h>
#include <sys/param.h>
#ifdef HAVE_SYS_SYSCTL_H
-#ifdef GNU_LINUX
-#include <linux/types.h>
-#endif
+#ifndef GNU_LINUX
#include <sys/sysctl.h>
+#endif
#endif /* HAVE_SYS_SYSCTL_H */
#include <sys/ioctl.h>
#ifdef HAVE_SYS_CONF_H
diff --git a/nhrpd/list.h b/nhrpd/list.h
index ee7f1c440..a43687ac0 100644
--- a/nhrpd/list.h
+++ b/nhrpd/list.h
@@ -198,9 +198,12 @@ static inline int list_empty(const struct list_head *n)
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
+ for (pos = ((head)->next != head ? \
+ list_entry((head)->next, typeof(*pos), member) : \
+ NULL), \
+ n = (pos ? \
+ list_entry(pos->member.next, typeof(*pos), member) : NULL); \
+ pos && (&pos->member != (head)); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif
diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c
index 8f1ba14fe..e4f614c7c 100644
--- a/nhrpd/nhrp_interface.c
+++ b/nhrpd/nhrp_interface.c
@@ -296,15 +296,8 @@ void nhrp_interface_update(struct interface *ifp)
}
}
-int nhrp_interface_add(ZAPI_CALLBACK_ARGS)
+int nhrp_ifp_create(struct interface *ifp)
{
- struct interface *ifp;
-
- /* read and add the interface in the iflist. */
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
- if (ifp == NULL)
- return 0;
-
debugf(NHRP_DEBUG_IF, "if-add: %s, ifindex: %u, hw_type: %d %s",
ifp->name, ifp->ifindex, ifp->ll_type,
if_link_type_str(ifp->ll_type));
@@ -314,49 +307,28 @@ int nhrp_interface_add(ZAPI_CALLBACK_ARGS)
return 0;
}
-int nhrp_interface_delete(ZAPI_CALLBACK_ARGS)
+int nhrp_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
- struct stream *s;
-
- s = zclient->ibuf;
- ifp = zebra_interface_state_read(s, vrf_id);
- if (ifp == NULL)
- return 0;
-
debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name);
nhrp_interface_update(ifp);
- if_set_index(ifp, IFINDEX_INTERNAL);
-
return 0;
}
-int nhrp_interface_up(ZAPI_CALLBACK_ARGS)
+int nhrp_ifp_up(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- if (ifp == NULL)
- return 0;
-
debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name);
nhrp_interface_update_nbma(ifp);
return 0;
}
-int nhrp_interface_down(ZAPI_CALLBACK_ARGS)
+int nhrp_ifp_down(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- if (ifp == NULL)
- return 0;
-
debugf(NHRP_DEBUG_IF, "if-down: %s", ifp->name);
nhrp_interface_update(ifp);
+
return 0;
}
diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c
index 969638cd7..c6c83614e 100644
--- a/nhrpd/nhrp_main.c
+++ b/nhrpd/nhrp_main.c
@@ -152,6 +152,8 @@ int main(int argc, char **argv)
nhrp_vc_init();
nhrp_packet_init();
vici_init();
+ if_zapi_callbacks(nhrp_ifp_create, nhrp_ifp_up,
+ nhrp_ifp_down, nhrp_ifp_destroy);
nhrp_zebra_init();
nhrp_shortcut_init();
diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c
index a788eb2ef..cfca86a9b 100644
--- a/nhrpd/nhrp_route.c
+++ b/nhrpd/nhrp_route.c
@@ -345,10 +345,6 @@ void nhrp_zebra_init(void)
zclient = zclient_new(master, &zclient_options_default);
zclient->zebra_connected = nhrp_zebra_connected;
- zclient->interface_add = nhrp_interface_add;
- zclient->interface_delete = nhrp_interface_delete;
- zclient->interface_up = nhrp_interface_up;
- zclient->interface_down = nhrp_interface_down;
zclient->interface_address_add = nhrp_interface_address_add;
zclient->interface_address_delete = nhrp_interface_address_delete;
zclient->redistribute_route_add = nhrp_route_read;
diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c
index cfedc1c6b..ba8c5d495 100644
--- a/nhrpd/nhrp_vty.c
+++ b/nhrpd/nhrp_vty.c
@@ -523,7 +523,7 @@ DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd,
{
VTY_DECLVAR_CONTEXT(interface, ifp);
afi_t afi = cmd_to_afi(argv[1]);
- union sockunion proto_addr;
+ union sockunion proto_addr, nbma_addr;
struct nhrp_cache *c;
if (str2sockunion(argv[4]->arg, &proto_addr) < 0
@@ -534,7 +534,8 @@ DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd,
if (!c || !c->map)
return nhrp_vty_return(vty, NHRP_ERR_ENTRY_NOT_FOUND);
- nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL);
+ nhrp_cache_update_binding(c, c->cur.type, -1,
+ nhrp_peer_get(ifp, &nbma_addr), 0, NULL);
return CMD_SUCCESS;
}
diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h
index 670c9f4f1..cbee5951f 100644
--- a/nhrpd/nhrpd.h
+++ b/nhrpd/nhrpd.h
@@ -76,8 +76,9 @@ static inline void notifier_del(struct notifier_block *n)
static inline void notifier_call(struct notifier_list *l, int cmd)
{
struct notifier_block *n, *nn;
- list_for_each_entry_safe(n, nn, &l->notifier_head, notifier_entry)
+ list_for_each_entry_safe(n, nn, &l->notifier_head, notifier_entry) {
n->action(n, cmd);
+ }
}
static inline int notifier_active(struct notifier_list *l)
@@ -319,6 +320,10 @@ void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n);
void nhrp_interface_set_protection(struct interface *ifp, const char *profile,
const char *fallback_profile);
void nhrp_interface_set_source(struct interface *ifp, const char *ifname);
+extern int nhrp_ifp_create(struct interface *ifp);
+extern int nhrp_ifp_up(struct interface *ifp);
+extern int nhrp_ifp_down(struct interface *ifp);
+extern int nhrp_ifp_destroy(struct interface *ifp);
int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
const char *nbma_fqdn);
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 692c84ad0..a56ba0a69 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -42,6 +42,7 @@
#include "ospf6_spf.h"
#include "ospf6d.h"
#include "ospf6_bfd.h"
+#include "ospf6_zebra.h"
DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names")
DEFINE_QOBJ_TYPE(ospf6_interface)
@@ -355,8 +356,6 @@ void ospf6_interface_state_update(struct interface *ifp)
oi = (struct ospf6_interface *)ifp->info;
if (oi == NULL)
return;
- if (oi->area == NULL)
- return;
if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE))
return;
@@ -683,6 +682,9 @@ int interface_up(struct thread *thread)
oi = (struct ospf6_interface *)THREAD_ARG(thread);
assert(oi && oi->interface);
+ if (!oi->type_cfg)
+ oi->type = ospf6_default_iftype(oi->interface);
+
/*
* Remove old pointer. If this thread wasn't a timer this
* operation won't make a difference, because it is already NULL.
@@ -774,8 +776,7 @@ int interface_up(struct thread *thread)
}
/* decide next interface state */
- if ((if_is_pointopoint(oi->interface))
- || (oi->type == OSPF_IFTYPE_POINTOPOINT)) {
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
ospf6_interface_state_change(OSPF6_INTERFACE_POINTTOPOINT, oi);
} else if (oi->priority == 0)
ospf6_interface_state_change(OSPF6_INTERFACE_DROTHER, oi);
@@ -880,6 +881,19 @@ int interface_down(struct thread *thread)
}
+static const char *ospf6_iftype_str(uint8_t iftype)
+{
+ switch (iftype) {
+ case OSPF_IFTYPE_LOOPBACK:
+ return "LOOPBACK";
+ case OSPF_IFTYPE_BROADCAST:
+ return "BROADCAST";
+ case OSPF_IFTYPE_POINTOPOINT:
+ return "POINTOPOINT";
+ }
+ return "UNKNOWN";
+}
+
/* show specified interface structure */
static int ospf6_interface_show(struct vty *vty, struct interface *ifp)
{
@@ -888,23 +902,16 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp)
struct prefix *p;
struct listnode *i;
char strbuf[PREFIX2STR_BUFFER], drouter[32], bdrouter[32];
- const char *type;
+ uint8_t default_iftype;
struct timeval res, now;
char duration[32];
struct ospf6_lsa *lsa;
- /* check physical interface type */
- if (if_is_loopback(ifp))
- type = "LOOPBACK";
- else if (if_is_broadcast(ifp))
- type = "BROADCAST";
- else if (if_is_pointopoint(ifp))
- type = "POINTOPOINT";
- else
- type = "UNKNOWN";
+ default_iftype = ospf6_default_iftype(ifp);
vty_out(vty, "%s is %s, type %s\n", ifp->name,
- (if_is_operative(ifp) ? "up" : "down"), type);
+ (if_is_operative(ifp) ? "up" : "down"),
+ ospf6_iftype_str(default_iftype));
vty_out(vty, " Interface ID: %d\n", ifp->ifindex);
if (ifp->info == NULL) {
@@ -913,6 +920,10 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp)
} else
oi = (struct ospf6_interface *)ifp->info;
+ if (if_is_operative(ifp) && oi->type != default_iftype)
+ vty_out(vty, " Operating as type %s\n",
+ ospf6_iftype_str(oi->type));
+
vty_out(vty, " Internet Address:\n");
for (ALL_LIST_ELEMENTS_RO(ifp->connected, i, c)) {
@@ -1809,6 +1820,8 @@ DEFUN (ipv6_ospf6_network,
}
assert(oi);
+ oi->type_cfg = true;
+
if (strncmp(argv[idx_network]->arg, "b", 1) == 0) {
if (oi->type == OSPF_IFTYPE_BROADCAST)
return CMD_SUCCESS;
@@ -1849,6 +1862,8 @@ DEFUN (no_ipv6_ospf6_network,
return CMD_SUCCESS;
}
+ oi->type_cfg = false;
+
type = ospf6_default_iftype(ifp);
if (oi->type == type) {
return CMD_SUCCESS;
@@ -1916,13 +1931,10 @@ static int config_write_ospf6_interface(struct vty *vty)
if (oi->mtu_ignore)
vty_out(vty, " ipv6 ospf6 mtu-ignore\n");
- if (oi->type != ospf6_default_iftype(ifp)) {
- if (oi->type == OSPF_IFTYPE_POINTOPOINT)
- vty_out(vty,
- " ipv6 ospf6 network point-to-point\n");
- else if (oi->type == OSPF_IFTYPE_BROADCAST)
- vty_out(vty, " ipv6 ospf6 network broadcast\n");
- }
+ if (oi->type_cfg && oi->type == OSPF_IFTYPE_POINTOPOINT)
+ vty_out(vty, " ipv6 ospf6 network point-to-point\n");
+ else if (oi->type_cfg && oi->type == OSPF_IFTYPE_BROADCAST)
+ vty_out(vty, " ipv6 ospf6 network broadcast\n");
ospf6_bfd_write_config(vty, oi);
@@ -1935,11 +1947,64 @@ static struct cmd_node interface_node = {
INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */
};
+static int ospf6_ifp_create(struct interface *ifp)
+{
+ if (IS_OSPF6_DEBUG_ZEBRA(RECV))
+ zlog_debug("Zebra Interface add: %s index %d mtu %d", ifp->name,
+ ifp->ifindex, ifp->mtu6);
+ ospf6_interface_if_add(ifp);
+
+ return 0;
+}
+
+static int ospf6_ifp_up(struct interface *ifp)
+{
+ if (IS_OSPF6_DEBUG_ZEBRA(RECV))
+ zlog_debug(
+ "Zebra Interface state change: "
+ "%s index %d flags %llx metric %d mtu %d bandwidth %d",
+ ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
+ ifp->metric, ifp->mtu6, ifp->bandwidth);
+
+ ospf6_interface_state_update(ifp);
+
+ return 0;
+}
+
+static int ospf6_ifp_down(struct interface *ifp)
+{
+ if (IS_OSPF6_DEBUG_ZEBRA(RECV))
+ zlog_debug(
+ "Zebra Interface state change: "
+ "%s index %d flags %llx metric %d mtu %d bandwidth %d",
+ ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
+ ifp->metric, ifp->mtu6, ifp->bandwidth);
+
+ ospf6_interface_state_update(ifp);
+
+ return 0;
+}
+
+static int ospf6_ifp_destroy(struct interface *ifp)
+{
+ if (if_is_up(ifp))
+ zlog_warn("Zebra: got delete of %s, but interface is still up",
+ ifp->name);
+
+ if (IS_OSPF6_DEBUG_ZEBRA(RECV))
+ zlog_debug("Zebra Interface delete: %s index %d mtu %d",
+ ifp->name, ifp->ifindex, ifp->mtu6);
+
+ return 0;
+}
+
void ospf6_interface_init(void)
{
/* Install interface node. */
install_node(&interface_node, config_write_ospf6_interface);
if_cmd_init();
+ if_zapi_callbacks(ospf6_ifp_create, ospf6_ifp_up,
+ ospf6_ifp_down, ospf6_ifp_destroy);
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd);
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index e0c39a29b..53a8910f4 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -55,6 +55,7 @@ struct ospf6_interface {
/* Network Type */
uint8_t type;
+ bool type_cfg;
/* Router Priority */
uint8_t priority;
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
index b551dbdfa..0a9f1c6f7 100644
--- a/ospf6d/ospf6_lsdb.c
+++ b/ospf6d/ospf6_lsdb.c
@@ -298,13 +298,17 @@ struct ospf6_lsa *ospf6_lsdb_next(const struct route_node *iterend,
void ospf6_lsdb_remove_all(struct ospf6_lsdb *lsdb)
{
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
if (lsdb == NULL)
return;
- for (ALL_LSDB(lsdb, lsa))
+ for (iterend = ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
ospf6_lsdb_remove(lsa, lsdb);
+ }
}
void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa)
@@ -319,9 +323,12 @@ void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa)
int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
{
int reschedule = 0;
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
- for (ALL_LSDB(lsdb, lsa)) {
+ for (iterend = ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
if (!OSPF6_LSA_IS_MAXAGE(lsa))
continue;
if (lsa->retrans_count != 0) {
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 4acb5e3b2..da42a2425 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -1866,7 +1866,8 @@ int ospf6_dbdesc_send(struct thread *thread)
int ospf6_dbdesc_send_newone(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
unsigned int size = 0;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
@@ -1876,7 +1877,10 @@ int ospf6_dbdesc_send_newone(struct thread *thread)
structure)
so that ospf6_send_dbdesc () can send those LSAs */
size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc);
- for (ALL_LSDB(on->summary_list, lsa)) {
+
+ for (iterend = ospf6_lsdb_head(on->summary_list, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
if (size + sizeof(struct ospf6_lsa_header)
> ospf6_packet_max(on->ospf6_if)) {
ospf6_lsdb_lsa_unlock(lsa);
@@ -2019,7 +2023,8 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
struct ospf6_lsupdate *lsupdate;
uint8_t *p;
int lsa_cnt;
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
on->thread_send_lsupdate = (struct thread *)NULL;
@@ -2044,7 +2049,9 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
/* lsupdate_list lists those LSA which doesn't need to be
retransmitted. remove those from the list */
- for (ALL_LSDB(on->lsupdate_list, lsa)) {
+ for (iterend = ospf6_lsdb_head(on->lsupdate_list, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
/* MTU check */
if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header))
> ospf6_packet_max(on->ospf6_if)) {
@@ -2074,7 +2081,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
p += OSPF6_LSA_SIZE(lsa->header);
lsa_cnt++;
- assert(lsa->lock == 2);
+ assert(lsa->lock == 1);
ospf6_lsdb_remove(lsa, on->lsupdate_list);
}
@@ -2202,7 +2209,8 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
struct ospf6_lsupdate *lsupdate;
uint8_t *p;
int lsa_cnt;
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
oi = (struct ospf6_interface *)THREAD_ARG(thread);
oi->thread_send_lsupdate = (struct thread *)NULL;
@@ -2228,7 +2236,9 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
lsa_cnt = 0;
- for (ALL_LSDB(oi->lsupdate_list, lsa)) {
+ for (iterend = ospf6_lsdb_head(oi->lsupdate_list, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
/* MTU check */
if ((p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE(lsa->header)))
> ospf6_packet_max(oi)) {
@@ -2263,7 +2273,7 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
p += OSPF6_LSA_SIZE(lsa->header);
lsa_cnt++;
- assert(lsa->lock == 2);
+ assert(lsa->lock == 1);
ospf6_lsdb_remove(lsa, oi->lsupdate_list);
}
@@ -2289,7 +2299,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
struct ospf6_neighbor *on;
struct ospf6_header *oh;
uint8_t *p;
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
int lsa_cnt = 0;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
@@ -2312,7 +2323,9 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
- for (ALL_LSDB(on->lsack_list, lsa)) {
+ for (iterend = ospf6_lsdb_head(on->lsack_list, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
/* MTU check */
if (p - sendbuf + sizeof(struct ospf6_lsa_header)
> ospf6_packet_max(on->ospf6_if)) {
@@ -2340,7 +2353,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
p += sizeof(struct ospf6_lsa_header);
- assert(lsa->lock == 2);
+ assert(lsa->lock == 1);
ospf6_lsdb_remove(lsa, on->lsack_list);
lsa_cnt++;
}
@@ -2367,7 +2380,8 @@ int ospf6_lsack_send_interface(struct thread *thread)
struct ospf6_interface *oi;
struct ospf6_header *oh;
uint8_t *p;
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
int lsa_cnt = 0;
oi = (struct ospf6_interface *)THREAD_ARG(thread);
@@ -2391,7 +2405,9 @@ int ospf6_lsack_send_interface(struct thread *thread)
p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
- for (ALL_LSDB(oi->lsack_list, lsa)) {
+ for (iterend = ospf6_lsdb_head(oi->lsack_list, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
/* MTU check */
if (p - sendbuf + sizeof(struct ospf6_lsa_header)
> ospf6_packet_max(oi)) {
@@ -2409,7 +2425,7 @@ int ospf6_lsack_send_interface(struct thread *thread)
memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
p += sizeof(struct ospf6_lsa_header);
- assert(lsa->lock == 2);
+ assert(lsa->lock == 1);
ospf6_lsdb_remove(lsa, oi->lsack_list);
lsa_cnt++;
}
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 46dc621ae..4318db522 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -112,11 +112,15 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
void ospf6_neighbor_delete(struct ospf6_neighbor *on)
{
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
ospf6_lsdb_remove_all(on->summary_list);
ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa)) {
+
+ for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
ospf6_decrement_retrans_count(lsa);
ospf6_lsdb_remove(lsa, on->retrans_list);
}
@@ -287,7 +291,8 @@ int twoway_received(struct thread *thread)
int negotiation_done(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -301,7 +306,10 @@ int negotiation_done(struct thread *thread)
/* clear ls-list */
ospf6_lsdb_remove_all(on->summary_list);
ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa)) {
+
+ for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
ospf6_decrement_retrans_count(lsa);
ospf6_lsdb_remove(lsa, on->retrans_list);
}
@@ -495,7 +503,8 @@ int seqnumber_mismatch(struct thread *thread)
int bad_lsreq(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -514,7 +523,10 @@ int bad_lsreq(struct thread *thread)
ospf6_lsdb_remove_all(on->summary_list);
ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa)) {
+
+ for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
ospf6_decrement_retrans_count(lsa);
ospf6_lsdb_remove(lsa, on->retrans_list);
}
@@ -532,7 +544,8 @@ int bad_lsreq(struct thread *thread)
int oneway_received(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsa, *lsa_next;
+ const struct route_node *iterend;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -549,7 +562,9 @@ int oneway_received(struct thread *thread)
ospf6_lsdb_remove_all(on->summary_list);
ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa)) {
+ for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa;
+ lsa = lsa_next) {
+ lsa_next = ospf6_lsdb_next(iterend, lsa);
ospf6_decrement_retrans_count(lsa);
ospf6_lsdb_remove(lsa, on->retrans_list);
}
@@ -618,7 +633,7 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on)
snprintf(deadtime, sizeof(deadtime), "%02ld:%02ld:%02ld", h, m, s);
/* Neighbor State */
- if (if_is_pointopoint(on->ospf6_if->interface))
+ if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT)
snprintf(nstate, sizeof(nstate), "PointToPoint");
else {
if (on->router_id == on->drouter)
diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c
index fc7c6177d..1ba89f3bd 100644
--- a/ospf6d/ospf6_snmp.c
+++ b/ospf6d/ospf6_snmp.c
@@ -1130,9 +1130,9 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
return SNMP_INTEGER(ntohl(oi->area->area_id));
break;
case OSPFv3IFTYPE:
- if (if_is_broadcast(oi->interface))
+ if (oi->type == OSPF_IFTYPE_BROADCAST)
return SNMP_INTEGER(1);
- else if (if_is_pointopoint(oi->interface))
+ else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
return SNMP_INTEGER(3);
else
break; /* Unknown, don't put anything */
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 40c612381..95dafff84 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -136,7 +136,7 @@ static void ospf6_top_brouter_hook_remove(struct ospf6_route *route)
ospf6_abr_originate_summary(route);
}
-static struct ospf6 *ospf6_create(void)
+static struct ospf6 *ospf6_create(vrf_id_t vrf_id)
{
struct ospf6 *o;
@@ -144,6 +144,7 @@ static struct ospf6 *ospf6_create(void)
/* initialize */
monotime(&o->starttime);
+ o->vrf_id = vrf_id;
o->area_list = list_new();
o->area_list->cmp = ospf6_area_cmp;
o->lsdb = ospf6_lsdb_create(o);
@@ -325,7 +326,7 @@ DEFUN_NOSH (router_ospf6,
OSPF6_STR)
{
if (ospf6 == NULL) {
- ospf6 = ospf6_create();
+ ospf6 = ospf6_create(VRF_DEFAULT);
if (ospf6->router_id == 0)
ospf6_router_id_update();
}
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
index 381027dcf..ba41fca65 100644
--- a/ospf6d/ospf6_top.h
+++ b/ospf6d/ospf6_top.h
@@ -31,6 +31,9 @@ struct ospf6_master {
/* OSPFv3 top level data structure */
struct ospf6 {
+ /* The relevant vrf_id */
+ vrf_id_t vrf_id;
+
/* my router id */
uint32_t router_id;
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 8454016b2..d8a6a39e1 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -97,57 +97,6 @@ void ospf6_zebra_no_redistribute(int type)
AFI_IP6, type, 0, VRF_DEFAULT);
}
-/* Inteface addition message from zebra. */
-static int ospf6_zebra_if_add(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
-
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
- if (IS_OSPF6_DEBUG_ZEBRA(RECV))
- zlog_debug("Zebra Interface add: %s index %d mtu %d", ifp->name,
- ifp->ifindex, ifp->mtu6);
- ospf6_interface_if_add(ifp);
- return 0;
-}
-
-static int ospf6_zebra_if_del(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
-
- if (!(ifp = zebra_interface_state_read(zclient->ibuf, vrf_id)))
- return 0;
-
- if (if_is_up(ifp))
- zlog_warn("Zebra: got delete of %s, but interface is still up",
- ifp->name);
-
- if (IS_OSPF6_DEBUG_ZEBRA(RECV))
- zlog_debug("Zebra Interface delete: %s index %d mtu %d",
- ifp->name, ifp->ifindex, ifp->mtu6);
-
- if_set_index(ifp, IFINDEX_INTERNAL);
- return 0;
-}
-
-static int ospf6_zebra_if_state_update(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- if (ifp == NULL)
- return 0;
-
- if (IS_OSPF6_DEBUG_ZEBRA(RECV))
- zlog_debug(
- "Zebra Interface state change: "
- "%s index %d flags %llx metric %d mtu %d bandwidth %d",
- ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
- ifp->metric, ifp->mtu6, ifp->bandwidth);
-
- ospf6_interface_state_update(ifp);
- return 0;
-}
-
static int ospf6_zebra_if_address_update_add(ZAPI_CALLBACK_ARGS)
{
struct connected *c;
@@ -583,10 +532,6 @@ void ospf6_zebra_init(struct thread_master *master)
zclient_init(zclient, ZEBRA_ROUTE_OSPF6, 0, &ospf6d_privs);
zclient->zebra_connected = ospf6_zebra_connected;
zclient->router_id_update = ospf6_router_id_update_zebra;
- zclient->interface_add = ospf6_zebra_if_add;
- zclient->interface_delete = ospf6_zebra_if_del;
- zclient->interface_up = ospf6_zebra_if_state_update;
- zclient->interface_down = ospf6_zebra_if_state_update;
zclient->interface_address_add = ospf6_zebra_if_address_update_add;
zclient->interface_address_delete =
ospf6_zebra_if_address_update_delete;
diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c
index 9492de544..44244f651 100644
--- a/ospfd/ospf_ase.c
+++ b/ospfd/ospf_ase.c
@@ -190,7 +190,7 @@ ospf_ase_calculate_asbr_route (struct ospf *ospf,
zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR");
return NULL;
}
-
+
if (al->e[0].fwd_addr.s_addr != 0)
{
if (IS_DEBUG_OSPF (lsa, LSA))
@@ -215,7 +215,7 @@ ospf_ase_calculate_asbr_route (struct ospf *ospf,
asbr.prefixlen = IPV4_MAX_BITLEN;
rn = route_node_match (rt_network, (struct prefix *) &asbr);
-
+
if (rn == NULL)
{
if (IS_DEBUG_OSPF (lsa, LSA))
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 387770870..1f5e0da94 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -50,6 +50,8 @@
DEFINE_QOBJ_TYPE(ospf_interface)
DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd))
+DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp))
+DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp))
int ospf_interface_neighbor_count(struct ospf_interface *oi)
{
@@ -845,9 +847,9 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf,
ospf->vrf_id);
snprintf(ifname, sizeof(ifname), "VLINK%u", vlink_count);
- vi = if_create(ifname, ospf->vrf_id);
+ vi = if_create_name(ifname, ospf->vrf_id);
/*
- * if_create sets ZEBRA_INTERFACE_LINKDETECTION
+ * if_create_name sets ZEBRA_INTERFACE_LINKDETECTION
* virtual links don't need this.
*/
UNSET_FLAG(vi->status, ZEBRA_INTERFACE_LINKDETECTION);
@@ -1218,8 +1220,133 @@ uint8_t ospf_default_iftype(struct interface *ifp)
return OSPF_IFTYPE_BROADCAST;
}
+void ospf_if_interface(struct interface *ifp)
+{
+ hook_call(ospf_if_update, ifp);
+}
+
+static int ospf_ifp_create(struct interface *ifp)
+{
+ struct ospf *ospf = NULL;
+
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
+ zlog_debug(
+ "Zebra: interface add %s vrf %s[%u] index %d flags %llx metric %d mtu %d speed %u",
+ ifp->name, ospf_vrf_id_to_name(ifp->vrf_id),
+ ifp->vrf_id, ifp->ifindex,
+ (unsigned long long)ifp->flags, ifp->metric, ifp->mtu,
+ ifp->speed);
+
+ assert(ifp->info);
+
+ if (IF_DEF_PARAMS(ifp)
+ && !OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp), type)) {
+ SET_IF_PARAM(IF_DEF_PARAMS(ifp), type);
+ IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp);
+ }
+
+ ospf = ospf_lookup_by_vrf_id(ifp->vrf_id);
+ if (!ospf)
+ return 0;
+
+ ospf_if_recalculate_output_cost(ifp);
+
+ ospf_if_update(ospf, ifp);
+
+ hook_call(ospf_if_update, ifp);
+
+ return 0;
+}
+
+static int ospf_ifp_up(struct interface *ifp)
+{
+ struct ospf_interface *oi;
+ struct route_node *rn;
+
+ /* Interface is already up. */
+ if (if_is_operative(ifp)) {
+ /* Temporarily keep ifp values. */
+ struct interface if_tmp;
+ memcpy(&if_tmp, ifp, sizeof(struct interface));
+
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
+ zlog_debug(
+ "Zebra: Interface[%s] state update speed %u -> %u, bw %d -> %d",
+ ifp->name, if_tmp.speed, ifp->speed,
+ if_tmp.bandwidth, ifp->bandwidth);
+
+ ospf_if_recalculate_output_cost(ifp);
+
+ if (if_tmp.mtu != ifp->mtu) {
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
+ zlog_debug(
+ "Zebra: Interface[%s] MTU change %u -> %u.",
+ ifp->name, if_tmp.mtu, ifp->mtu);
+
+ /* Must reset the interface (simulate down/up) when MTU
+ * changes. */
+ ospf_if_reset(ifp);
+ }
+ return 0;
+ }
+
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
+ zlog_debug("Zebra: Interface[%s] state change to up.",
+ ifp->name);
+
+ for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
+ if ((oi = rn->info) == NULL)
+ continue;
+
+ ospf_if_up(oi);
+ }
+
+ return 0;
+}
+
+static int ospf_ifp_down(struct interface *ifp)
+{
+ struct ospf_interface *oi;
+ struct route_node *node;
+
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
+ zlog_debug("Zebra: Interface[%s] state change to down.",
+ ifp->name);
+
+ for (node = route_top(IF_OIFS(ifp)); node; node = route_next(node)) {
+ if ((oi = node->info) == NULL)
+ continue;
+ ospf_if_down(oi);
+ }
+
+ return 0;
+}
+
+static int ospf_ifp_destroy(struct interface *ifp)
+{
+ struct route_node *rn;
+
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
+ zlog_debug(
+ "Zebra: interface delete %s vrf %s[%u] index %d flags %llx metric %d mtu %d",
+ ifp->name, ospf_vrf_id_to_name(ifp->vrf_id),
+ ifp->vrf_id, ifp->ifindex,
+ (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
+
+ hook_call(ospf_if_delete, ifp);
+
+ for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn))
+ if (rn->info)
+ ospf_if_free((struct ospf_interface *)rn->info);
+
+ return 0;
+}
+
void ospf_if_init(void)
{
+ if_zapi_callbacks(ospf_ifp_create, ospf_ifp_up,
+ ospf_ifp_down, ospf_ifp_destroy);
+
/* Initialize Zebra interface data structure. */
hook_register_prio(if_add, 0, ospf_if_new_hook);
hook_register_prio(if_del, 0, ospf_if_delete_hook);
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index 0c903954d..cde52dbb9 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -321,7 +321,12 @@ extern int ospf_interface_neighbor_count(struct ospf_interface *oi);
state of the interface. */
extern void ospf_if_set_multicast(struct ospf_interface *);
+extern void ospf_if_interface(struct interface *ifp);
+
DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd))
+DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp))
+DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp))
+
#endif /* _ZEBRA_OSPF_INTERFACE_H */
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index db41df7c4..5ab0927e7 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -2437,7 +2437,7 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_install(struct ospf *ospf,
#if 0
/* These don't exist yet... */
ospf_summary_incremental_update(new);
- /* Isn't this done by the above call?
+ /* Isn't this done by the above call?
- RFC 2328 Section 16.5 implies it should be */
/* ospf_ase_calculate_schedule(); */
#else /* #if 0 */
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 8fa91f500..d11c34f24 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -10661,7 +10661,7 @@ static void ospf_interface_clear(struct interface *ifp)
DEFUN (clear_ip_ospf_interface,
clear_ip_ospf_interface_cmd,
- "clear ip ospf [vrf <NAME>] interface [IFNAME]",
+ "clear ip ospf [vrf NAME] interface [IFNAME]",
CLEAR_STR
IP_STR
"OSPF information\n"
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index b478832d8..5678d545b 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -55,9 +55,6 @@ DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table")
DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute")
DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments")
-DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp))
-DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp))
-
/* Zebra structure to hold current status. */
struct zclient *zclient = NULL;
@@ -97,167 +94,6 @@ static int ospf_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
return 0;
}
-/* Inteface addition message from zebra. */
-static int ospf_interface_add(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp = NULL;
- struct ospf *ospf = NULL;
-
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
- if (ifp == NULL)
- return 0;
-
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug(
- "Zebra: interface add %s vrf %s[%u] index %d flags %llx metric %d mtu %d speed %u",
- ifp->name, ospf_vrf_id_to_name(ifp->vrf_id),
- ifp->vrf_id, ifp->ifindex,
- (unsigned long long)ifp->flags, ifp->metric, ifp->mtu,
- ifp->speed);
-
- assert(ifp->info);
-
- if (IF_DEF_PARAMS(ifp)
- && !OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp), type)) {
- SET_IF_PARAM(IF_DEF_PARAMS(ifp), type);
- IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp);
- }
-
- ospf = ospf_lookup_by_vrf_id(vrf_id);
- if (!ospf)
- return 0;
-
- ospf_if_recalculate_output_cost(ifp);
-
- ospf_if_update(ospf, ifp);
-
- hook_call(ospf_if_update, ifp);
-
- return 0;
-}
-
-static int ospf_interface_delete(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
- struct stream *s;
- struct route_node *rn;
-
- s = zclient->ibuf;
- /* zebra_interface_state_read() updates interface structure in iflist */
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug(
- "Zebra: interface delete %s vrf %s[%u] index %d flags %llx metric %d mtu %d",
- ifp->name, ospf_vrf_id_to_name(ifp->vrf_id),
- ifp->vrf_id, ifp->ifindex,
- (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
-
- hook_call(ospf_if_delete, ifp);
-
- for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn))
- if (rn->info)
- ospf_if_free((struct ospf_interface *)rn->info);
-
- if_set_index(ifp, IFINDEX_INTERNAL);
- return 0;
-}
-
-static struct interface *zebra_interface_if_lookup(struct stream *s,
- vrf_id_t vrf_id)
-{
- char ifname_tmp[INTERFACE_NAMSIZ];
-
- /* Read interface name. */
- stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
-
- /* And look it up. */
- return if_lookup_by_name(ifname_tmp, vrf_id);
-}
-
-static int ospf_interface_state_up(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
- struct ospf_interface *oi;
- struct route_node *rn;
-
- ifp = zebra_interface_if_lookup(zclient->ibuf, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- /* Interface is already up. */
- if (if_is_operative(ifp)) {
- /* Temporarily keep ifp values. */
- struct interface if_tmp;
- memcpy(&if_tmp, ifp, sizeof(struct interface));
-
- zebra_interface_if_set_value(zclient->ibuf, ifp);
-
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug(
- "Zebra: Interface[%s] state update speed %u -> %u, bw %d -> %d",
- ifp->name, if_tmp.speed, ifp->speed,
- if_tmp.bandwidth, ifp->bandwidth);
-
- ospf_if_recalculate_output_cost(ifp);
-
- if (if_tmp.mtu != ifp->mtu) {
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug(
- "Zebra: Interface[%s] MTU change %u -> %u.",
- ifp->name, if_tmp.mtu, ifp->mtu);
-
- /* Must reset the interface (simulate down/up) when MTU
- * changes. */
- ospf_if_reset(ifp);
- }
- return 0;
- }
-
- zebra_interface_if_set_value(zclient->ibuf, ifp);
-
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug("Zebra: Interface[%s] state change to up.",
- ifp->name);
-
- for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
- if ((oi = rn->info) == NULL)
- continue;
-
- ospf_if_up(oi);
- }
-
- return 0;
-}
-
-static int ospf_interface_state_down(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
- struct ospf_interface *oi;
- struct route_node *node;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
- zlog_debug("Zebra: Interface[%s] state change to down.",
- ifp->name);
-
- for (node = route_top(IF_OIFS(ifp)); node; node = route_next(node)) {
- if ((oi = node->info) == NULL)
- continue;
- ospf_if_down(oi);
- }
-
- return 0;
-}
-
static int ospf_interface_address_add(ZAPI_CALLBACK_ARGS)
{
struct connected *c;
@@ -283,7 +119,7 @@ static int ospf_interface_address_add(ZAPI_CALLBACK_ARGS)
ospf_if_update(ospf, c->ifp);
- hook_call(ospf_if_update, c->ifp);
+ ospf_if_interface(c->ifp);
return 0;
}
@@ -325,7 +161,7 @@ static int ospf_interface_address_delete(ZAPI_CALLBACK_ARGS)
/* Call interface hook functions to clean up */
ospf_if_free(oi);
- hook_call(ospf_if_update, c->ifp);
+ ospf_if_interface(c->ifp);
connected_free(c);
@@ -1524,10 +1360,6 @@ void ospf_zebra_init(struct thread_master *master, unsigned short instance)
zclient_init(zclient, ZEBRA_ROUTE_OSPF, instance, &ospfd_privs);
zclient->zebra_connected = ospf_zebra_connected;
zclient->router_id_update = ospf_router_id_update_zebra;
- zclient->interface_add = ospf_interface_add;
- zclient->interface_delete = ospf_interface_delete;
- zclient->interface_up = ospf_interface_state_up;
- zclient->interface_down = ospf_interface_state_down;
zclient->interface_address_add = ospf_interface_address_add;
zclient->interface_address_delete = ospf_interface_address_delete;
zclient->interface_link_params = ospf_interface_link_params;
diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h
index 673730653..d3f8a0380 100644
--- a/ospfd/ospf_zebra.h
+++ b/ospfd/ospf_zebra.h
@@ -87,7 +87,4 @@ extern void ospf_zebra_init(struct thread_master *, unsigned short);
extern void ospf_zebra_vrf_register(struct ospf *ospf);
extern void ospf_zebra_vrf_deregister(struct ospf *ospf);
-DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp))
-DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp))
-
#endif /* _ZEBRA_OSPF_ZEBRA_H */
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index f4de25587..b12fa6372 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -1339,6 +1339,7 @@ void ospf_if_update(struct ospf *ospf, struct interface *ifp)
/* Update connected redistribute. */
update_redistributed(ospf, 1);
+
}
void ospf_remove_vls_through_area(struct ospf *ospf, struct ospf_area *area)
diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c
index 246d836ac..bb92703ae 100644
--- a/pbrd/pbr_main.c
+++ b/pbrd/pbr_main.c
@@ -166,6 +166,8 @@ int main(int argc, char **argv, char **envp)
access_list_init();
pbr_nht_init();
pbr_map_init();
+ if_zapi_callbacks(pbr_ifp_create, pbr_ifp_up,
+ pbr_ifp_down, pbr_ifp_destroy);
pbr_zebra_init();
pbr_vty_init();
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index 359f869c4..7ccd14d1f 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -267,7 +267,9 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
pbr_map_check_nh_group_change(nhgc->name);
- if (nhop->type == NEXTHOP_TYPE_IFINDEX) {
+ if (nhop->type == NEXTHOP_TYPE_IFINDEX
+ || (nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ && IN6_IS_ADDR_LINKLOCAL(&nhop->gate.ipv6))) {
struct interface *ifp;
ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
@@ -576,8 +578,6 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
hash_release(pbr_nhg_hash, pnhgc);
- _nexthop_del(pbrms->nhg, nh);
- nexthop_free(nh);
nexthop_group_delete(&pbrms->nhg);
XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
}
@@ -637,7 +637,6 @@ void pbr_nht_delete_group(const char *name)
if (pbrms->nhgrp_name
&& strmatch(pbrms->nhgrp_name, name)) {
pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
- nexthop_group_delete(&pbrms->nhg);
pbrms->nhg = NULL;
pbrms->internal_nhg_name = NULL;
pbrm->valid = false;
@@ -711,7 +710,7 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
}
if (pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
- || pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
+ || pnhc->nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
/* GATEWAY_IFINDEX type shouldn't resolve to group */
if (pnhi->nhr->nexthop_num > 1) {
@@ -772,10 +771,15 @@ pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc,
case NEXTHOP_TYPE_IFINDEX:
pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (IN6_IS_ADDR_LINKLOCAL(&pnhc->nexthop->gate.ipv6)) {
+ pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
+ break;
+ }
+ /* Intentional fall thru */
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
pbr_nht_individual_nexthop_gw_update(pnhc, pnhi);
break;
case NEXTHOP_TYPE_BLACKHOLE:
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index 5e7addc9d..069b3e6c9 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -254,7 +254,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
<A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
|INTERFACE$intf\
>\
- [nexthop-vrf NAME$name]",
+ [nexthop-vrf NAME$vrf_name]",
NO_STR
"Set for the PBR-MAP\n"
"Specify one of the nexthops in this map\n"
@@ -276,13 +276,13 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
return CMD_WARNING_CONFIG_FAILED;
}
- if (name)
- vrf = vrf_lookup_by_name(name);
+ if (vrf_name)
+ vrf = vrf_lookup_by_name(vrf_name);
else
vrf = vrf_lookup_by_id(VRF_DEFAULT);
if (!vrf) {
- vty_out(vty, "Specified: %s is non-existent\n", name);
+ vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
return CMD_WARNING_CONFIG_FAILED;
}
@@ -363,7 +363,9 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
pbr_map_check(pbrms);
}
- if (nhop.type == NEXTHOP_TYPE_IFINDEX) {
+ if (nhop.type == NEXTHOP_TYPE_IFINDEX
+ || (nhop.type == NEXTHOP_TYPE_IPV6_IFINDEX
+ && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6))) {
struct interface *ifp;
ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index d74d0fcd2..39e92467a 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -59,15 +59,8 @@ struct pbr_interface *pbr_if_new(struct interface *ifp)
}
/* Inteface addition message from zebra. */
-static int interface_add(ZAPI_CALLBACK_ARGS)
+int pbr_ifp_create(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
-
- if (!ifp)
- return 0;
-
DEBUGD(&pbr_dbg_zebra,
"%s: %s", __PRETTY_FUNCTION__, ifp->name);
@@ -79,24 +72,11 @@ static int interface_add(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int interface_delete(ZAPI_CALLBACK_ARGS)
+int pbr_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
- struct stream *s;
-
- s = zclient->ibuf;
- /* zebra_interface_state_read () updates interface structure in iflist
- */
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
DEBUGD(&pbr_dbg_zebra,
"%s: %s", __PRETTY_FUNCTION__, ifp->name);
- if_set_index(ifp, IFINDEX_INTERNAL);
-
return 0;
}
@@ -133,12 +113,8 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int interface_state_up(ZAPI_CALLBACK_ARGS)
+int pbr_ifp_up(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
DEBUGD(&pbr_dbg_zebra,
"%s: %s is up", __PRETTY_FUNCTION__, ifp->name);
@@ -147,12 +123,8 @@ static int interface_state_up(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int interface_state_down(ZAPI_CALLBACK_ARGS)
+int pbr_ifp_down(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
DEBUGD(&pbr_dbg_zebra,
"%s: %s is down", __PRETTY_FUNCTION__, ifp->name);
@@ -447,10 +419,6 @@ void pbr_zebra_init(void)
zclient_init(zclient, ZEBRA_ROUTE_PBR, 0, &pbr_privs);
zclient->zebra_connected = zebra_connected;
- zclient->interface_add = interface_add;
- zclient->interface_delete = interface_delete;
- zclient->interface_up = interface_state_up;
- zclient->interface_down = interface_state_down;
zclient->interface_address_add = interface_address_add;
zclient->interface_address_delete = interface_address_delete;
zclient->route_notify_owner = route_notify_owner;
@@ -482,6 +450,12 @@ void pbr_send_rnh(struct nexthop *nhop, bool reg)
p.family = AF_INET6;
memcpy(&p.u.prefix6, &nhop->gate.ipv6, 16);
p.prefixlen = 128;
+ if (IN6_IS_ADDR_LINKLOCAL(&nhop->gate.ipv6))
+ /*
+ * Don't bother tracking link locals, just track their
+ * interface state.
+ */
+ return;
break;
}
diff --git a/pbrd/pbr_zebra.h b/pbrd/pbr_zebra.h
index 4cbefe263..d5d938021 100644
--- a/pbrd/pbr_zebra.h
+++ b/pbrd/pbr_zebra.h
@@ -39,4 +39,10 @@ extern void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
struct pbr_map_interface *pmi, bool install);
extern struct pbr_interface *pbr_if_new(struct interface *ifp);
+
+extern int pbr_ifp_create(struct interface *ifp);
+extern int pbr_ifp_up(struct interface *ifp);
+extern int pbr_ifp_down(struct interface *ifp);
+extern int pbr_ifp_destroy(struct interface *ifp);
+
#endif
diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c
index 675092dbe..1383e3db1 100644
--- a/pimd/pim_bsm.c
+++ b/pimd/pim_bsm.c
@@ -290,8 +290,7 @@ void pim_bsm_proc_free(struct pim_instance *pim)
pim_free_bsgrp_data(bsgrp);
}
- if (pim->global_scope.bsrp_table)
- route_table_finish(pim->global_scope.bsrp_table);
+ route_table_finish(pim->global_scope.bsrp_table);
}
static bool is_hold_time_elapsed(void *data)
@@ -683,8 +682,13 @@ static bool pim_bsm_send_intf(uint8_t *buf, int len, struct interface *ifp,
return false;
}
- pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address, dst_addr,
- buf, len, ifp->name);
+ if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
+ dst_addr, buf, len, ifp->name)) {
+ zlog_warn("%s: Could not send BSM message on interface: %s",
+ __PRETTY_FUNCTION__, ifp->name);
+ return false;
+ }
+
pim_ifp->pim_ifstat_bsm_tx++;
pim_ifp->pim->bsm_sent++;
return true;
@@ -1028,7 +1032,8 @@ static uint32_t hash_calc_on_grp_rp(struct prefix group, struct in_addr rp,
else
grpaddr = grpaddr & mask;
rp_add = ntohl(rp.s_addr);
- temp = 1103515245 * ((1103515245 * grpaddr + 12345) ^ rp_add) + 12345;
+ temp = 1103515245 * ((1103515245 * (uint64_t)grpaddr + 12345) ^ rp_add)
+ + 12345;
hash = temp & (0x7fffffff);
return hash;
}
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 28b4af945..6624974c9 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -5996,12 +5996,6 @@ static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty,
return CMD_WARNING_CONFIG_FAILED;
}
- if (result == PIM_GROUP_BAD_ADDR_MASK_COMBO) {
- vty_out(vty, "%% Inconsistent address and mask: %s\n",
- group);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
return CMD_SUCCESS;
}
diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c
index 721d153d7..34c5eb43b 100644
--- a/pimd/pim_hello.c
+++ b/pimd/pim_hello.c
@@ -104,7 +104,7 @@ static void tlv_trace(const char *label, const char *tlv_name,
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s",
- label,
+ label,
src_str, ifname,
tlv_name);
}
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index bdeda2d76..3ee9caebc 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -1476,7 +1476,7 @@ void pim_if_create_pimreg(struct pim_instance *pim)
snprintf(pimreg_name, sizeof(pimreg_name), "pimreg%u",
pim->vrf->data.l.table_id);
- pim->regiface = if_create(pimreg_name, pim->vrf_id);
+ pim->regiface = if_create_name(pimreg_name, pim->vrf_id);
pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
pim_if_new(pim->regiface, false, false, true,
@@ -1526,3 +1526,169 @@ int pim_if_ifchannel_count(struct pim_interface *pim_ifp)
return count;
}
+
+int pim_ifp_create(struct interface *ifp)
+{
+ struct pim_instance *pim;
+
+ pim = pim_get_pim_instance(ifp->vrf_id);
+ if (PIM_DEBUG_ZEBRA) {
+ zlog_debug(
+ "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
+ __PRETTY_FUNCTION__, ifp->name, ifp->ifindex,
+ ifp->vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu,
+ if_is_operative(ifp));
+ }
+
+ if (if_is_operative(ifp)) {
+ struct pim_interface *pim_ifp;
+
+ pim_ifp = ifp->info;
+ /*
+ * If we have a pim_ifp already and this is an if_add
+ * that means that we probably have a vrf move event
+ * If that is the case, set the proper vrfness.
+ */
+ if (pim_ifp)
+ pim_ifp->pim = pim;
+ pim_if_addr_add_all(ifp);
+ }
+
+ /*
+ * If we are a vrf device that is up, open up the pim_socket for
+ * listening
+ * to incoming pim messages irrelevant if the user has configured us
+ * for pim or not.
+ */
+ if (pim_if_is_vrf_device(ifp)) {
+ struct pim_interface *pim_ifp;
+
+ if (!ifp->info) {
+ pim_ifp = pim_if_new(ifp, false, false, false,
+ false /*vxlan_term*/);
+ ifp->info = pim_ifp;
+ }
+
+ pim_sock_add(ifp);
+ }
+
+ if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME,
+ sizeof(PIM_VXLAN_TERM_DEV_NAME)))
+ pim_vxlan_add_term_dev(pim, ifp);
+
+ return 0;
+}
+
+int pim_ifp_up(struct interface *ifp)
+{
+ struct pim_instance *pim;
+ uint32_t table_id;
+
+ if (PIM_DEBUG_ZEBRA) {
+ zlog_debug(
+ "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
+ __PRETTY_FUNCTION__, ifp->name, ifp->ifindex,
+ ifp->vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu,
+ if_is_operative(ifp));
+ }
+
+ pim = pim_get_pim_instance(ifp->vrf_id);
+ if (if_is_operative(ifp)) {
+ struct pim_interface *pim_ifp;
+
+ pim_ifp = ifp->info;
+ /*
+ * If we have a pim_ifp already and this is an if_add
+ * that means that we probably have a vrf move event
+ * If that is the case, set the proper vrfness.
+ */
+ if (pim_ifp)
+ pim_ifp->pim = pim;
+
+ /*
+ pim_if_addr_add_all() suffices for bringing up both IGMP and
+ PIM
+ */
+ pim_if_addr_add_all(ifp);
+ }
+
+ /*
+ * If we have a pimreg device callback and it's for a specific
+ * table set the master appropriately
+ */
+ if (sscanf(ifp->name, "pimreg%" SCNu32, &table_id) == 1) {
+ struct vrf *vrf;
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if ((table_id == vrf->data.l.table_id)
+ && (ifp->vrf_id != vrf->vrf_id)) {
+ struct interface *master = if_lookup_by_name(
+ vrf->name, vrf->vrf_id);
+
+ if (!master) {
+ zlog_debug(
+ "%s: Unable to find Master interface for %s",
+ __PRETTY_FUNCTION__, vrf->name);
+ return 0;
+ }
+ pim_zebra_interface_set_master(master, ifp);
+ }
+ }
+ }
+ return 0;
+}
+
+int pim_ifp_down(struct interface *ifp)
+{
+ if (PIM_DEBUG_ZEBRA) {
+ zlog_debug(
+ "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
+ __PRETTY_FUNCTION__, ifp->name, ifp->ifindex,
+ ifp->vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu,
+ if_is_operative(ifp));
+ }
+
+ if (!if_is_operative(ifp)) {
+ pim_ifchannel_delete_all(ifp);
+ /*
+ pim_if_addr_del_all() suffices for shutting down IGMP,
+ but not for shutting down PIM
+ */
+ pim_if_addr_del_all(ifp);
+
+ /*
+ pim_sock_delete() closes the socket, stops read and timer
+ threads,
+ and kills all neighbors.
+ */
+ if (ifp->info) {
+ pim_sock_delete(ifp, "link down");
+ }
+ }
+
+ if (ifp->info)
+ pim_if_del_vif(ifp);
+
+ return 0;
+}
+
+int pim_ifp_destroy(struct interface *ifp)
+{
+ struct pim_instance *pim;
+
+ if (PIM_DEBUG_ZEBRA) {
+ zlog_debug(
+ "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
+ __PRETTY_FUNCTION__, ifp->name, ifp->ifindex,
+ ifp->vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu,
+ if_is_operative(ifp));
+ }
+
+ if (!if_is_operative(ifp))
+ pim_if_addr_del_all(ifp);
+
+ pim = pim_get_pim_instance(ifp->vrf_id);
+ if (pim && pim->vxlan.term_if == ifp)
+ pim_vxlan_del_term_dev(pim);
+
+ return 0;
+}
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index 1c11e8570..1b76b5230 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -227,4 +227,10 @@ int pim_update_source_set(struct interface *ifp, struct in_addr source);
bool pim_if_is_vrf_device(struct interface *ifp);
int pim_if_ifchannel_count(struct pim_interface *pim_ifp);
+
+extern int pim_ifp_create(struct interface *ifp);
+extern int pim_ifp_up(struct interface *ifp);
+extern int pim_ifp_down(struct interface *ifp);
+extern int pim_ifp_destroy(struct interface *ifp);
+
#endif /* PIM_IFACE_H */
diff --git a/pimd/pim_join.c b/pimd/pim_join.c
index 5e1a4f0c5..686475fef 100644
--- a/pimd/pim_join.c
+++ b/pimd/pim_join.c
@@ -62,7 +62,7 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str,
sizeof(neigh_str));
- zlog_warn(
+ zlog_debug(
"%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
__PRETTY_FUNCTION__, pim_str_sg_dump(sg),
!!(source_flags & PIM_RPT_BIT_MASK),
@@ -94,11 +94,8 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
sizeof(received_rp));
pim_inet4_dump("<local?>", rp->rpf_addr.u.prefix4,
local_rp, sizeof(local_rp));
- if (PIM_DEBUG_PIM_TRACE)
- zlog_warn(
- "%s: Specified RP(%s) in join is different than our configured RP(%s)",
- __PRETTY_FUNCTION__, received_rp,
- local_rp);
+ zlog_warn("%s: Specified RP(%s) in join is different than our configured RP(%s)",
+ __PRETTY_FUNCTION__, received_rp, local_rp);
return;
}
@@ -122,7 +119,7 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh,
pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str,
sizeof(neigh_str));
- zlog_warn(
+ zlog_debug(
"%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
__PRETTY_FUNCTION__, pim_str_sg_dump(sg),
source_flags & PIM_RPT_BIT_MASK,
@@ -185,15 +182,11 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
Check upstream address family
*/
if (msg_upstream_addr.family != AF_INET) {
- if (PIM_DEBUG_PIM_J_P) {
- char src_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<src?>", src_addr, src_str,
- sizeof(src_str));
- zlog_warn(
- "%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
- __PRETTY_FUNCTION__, msg_upstream_addr.family,
- src_str, ifp->name);
- }
+ char src_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
+ zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
+ __PRETTY_FUNCTION__, msg_upstream_addr.family,
+ src_str, ifp->name);
return -2;
}
@@ -270,7 +263,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
upstream_str, sizeof(upstream_str));
pim_inet4_dump("<grp?>", sg.grp, group_str,
sizeof(group_str));
- zlog_warn(
+ zlog_debug(
"%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
__PRETTY_FUNCTION__, upstream_str, group_str,
msg_num_joined_sources, msg_num_pruned_sources,
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index 5a8991c4c..6a7dbe769 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -127,6 +127,8 @@ int main(int argc, char **argv, char **envp)
/*
* Initialize zclient "update" and "lookup" sockets
*/
+ if_zapi_callbacks(pim_ifp_create, pim_ifp_up,
+ pim_ifp_down, pim_ifp_destroy);
pim_zebra_init();
pim_bfd_init();
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index f7f4b54ae..a235ed056 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -611,7 +611,7 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str,
sizeof(ip_dst_str));
- zlog_warn(
+ zlog_debug(
"%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
__PRETTY_FUNCTION__, pim->vrf->name, ifp->name,
igmp, ip_src_str, ip_dst_str);
@@ -643,7 +643,7 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
sizeof(src_str));
pim_inet4_dump("<grp?>", msg->im_dst, grp_str,
sizeof(grp_str));
- zlog_warn(
+ zlog_debug(
"%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
__PRETTY_FUNCTION__,
igmpmsgtype2str[msg->im_msgtype],
@@ -698,12 +698,9 @@ static int mroute_read(struct thread *t)
if (errno == EWOULDBLOCK || errno == EAGAIN)
break;
- if (PIM_DEBUG_MROUTE)
- zlog_warn(
- "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
- __PRETTY_FUNCTION__, rd,
- pim->mroute_socket, errno,
- safe_strerror(errno));
+ zlog_warn("%s: failure reading rd=%d: fd=%d: errno=%d: %s",
+ __PRETTY_FUNCTION__, rd, pim->mroute_socket,
+ errno, safe_strerror(errno));
goto done;
}
@@ -1085,18 +1082,14 @@ void pim_mroute_update_counters(struct channel_oil *c_oil)
pim_zlookup_sg_statistics(c_oil);
if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
- if (PIM_DEBUG_MROUTE) {
- struct prefix_sg sg;
+ struct prefix_sg sg;
- sg.src = c_oil->oil.mfcc_origin;
- sg.grp = c_oil->oil.mfcc_mcastgrp;
+ sg.src = c_oil->oil.mfcc_origin;
+ sg.grp = c_oil->oil.mfcc_mcastgrp;
- zlog_warn(
- "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
- (unsigned long)SIOCGETSGCNT,
- pim_str_sg_dump(&sg), errno,
- safe_strerror(errno));
- }
+ zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
+ (unsigned long)SIOCGETSGCNT, pim_str_sg_dump(&sg),
+ errno, safe_strerror(errno));
return;
}
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 12b28ed9a..cd2d306f3 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -574,6 +574,7 @@ int pim_msg_send(int fd, struct in_addr src, struct in_addr dst,
ip->ip_id = htons(++ip_id);
ip->ip_hl = 5;
ip->ip_v = 4;
+ ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
ip->ip_p = PIM_IP_PROTO_PIM;
ip->ip_src = src;
ip->ip_dst = dst;
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 35c040c64..5542db27c 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -922,10 +922,11 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr,
}
}
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+
/* Deregister old RP addr with Zebra NHT */
if (rp_info->rp.rpf_addr.u.prefix4.s_addr != INADDR_ANY) {
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
if (PIM_DEBUG_PIM_NHT_RP) {
char buf[PREFIX2STR_BUFFER];
diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c
index 82255cd3b..7f03e1838 100644
--- a/pimd/pim_sock.c
+++ b/pimd/pim_sock.c
@@ -255,6 +255,12 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp,
}
}
+ /* Set Tx socket DSCP byte */
+ if (setsockopt_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL)) {
+ zlog_warn("can't set sockopt IP_TOS to PIM/IGMP socket %d: %s",
+ fd, safe_strerror(errno));
+ }
+
return fd;
}
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index b0db23f54..dadcbbe65 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -63,218 +63,6 @@ static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int pim_zebra_if_add(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
- struct pim_instance *pim;
-
- /*
- zebra api adds/dels interfaces using the same call
- interface_add_read below, see comments in lib/zclient.c
- */
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
- if (!ifp)
- return 0;
-
- pim = pim_get_pim_instance(vrf_id);
- if (PIM_DEBUG_ZEBRA) {
- zlog_debug(
- "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
- __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
- (long)ifp->flags, ifp->metric, ifp->mtu,
- if_is_operative(ifp));
- }
-
- if (if_is_operative(ifp)) {
- struct pim_interface *pim_ifp;
-
- pim_ifp = ifp->info;
- /*
- * If we have a pim_ifp already and this is an if_add
- * that means that we probably have a vrf move event
- * If that is the case, set the proper vrfness.
- */
- if (pim_ifp)
- pim_ifp->pim = pim;
- pim_if_addr_add_all(ifp);
- }
-
- /*
- * If we are a vrf device that is up, open up the pim_socket for
- * listening
- * to incoming pim messages irrelevant if the user has configured us
- * for pim or not.
- */
- if (pim_if_is_vrf_device(ifp)) {
- struct pim_interface *pim_ifp;
-
- if (!ifp->info) {
- pim_ifp = pim_if_new(ifp, false, false, false,
- false /*vxlan_term*/);
- ifp->info = pim_ifp;
- }
-
- pim_sock_add(ifp);
- }
-
- if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME,
- sizeof(PIM_VXLAN_TERM_DEV_NAME)))
- pim_vxlan_add_term_dev(pim, ifp);
-
- return 0;
-}
-
-static int pim_zebra_if_del(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
- struct pim_instance *pim;
-
- /*
- zebra api adds/dels interfaces using the same call
- interface_add_read below, see comments in lib/zclient.c
-
- comments in lib/zclient.c seem to indicate that calling
- zebra_interface_add_read is the correct call, but that
- results in an attemted out of bounds read which causes
- pimd to assert. Other clients use zebra_interface_state_read
- and it appears to work just fine.
- */
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- if (!ifp)
- return 0;
-
- if (PIM_DEBUG_ZEBRA) {
- zlog_debug(
- "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
- __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
- (long)ifp->flags, ifp->metric, ifp->mtu,
- if_is_operative(ifp));
- }
-
- if (!if_is_operative(ifp))
- pim_if_addr_del_all(ifp);
-
- if_set_index(ifp, IFINDEX_INTERNAL);
-
- pim = pim_get_pim_instance(vrf_id);
- if (pim && pim->vxlan.term_if == ifp)
- pim_vxlan_del_term_dev(pim);
-
- return 0;
-}
-
-static int pim_zebra_if_state_up(ZAPI_CALLBACK_ARGS)
-{
- struct pim_instance *pim;
- struct interface *ifp;
- uint32_t table_id;
-
- /*
- zebra api notifies interface up/down events by using the same call
- zebra_interface_state_read below, see comments in lib/zclient.c
- */
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- if (!ifp)
- return 0;
-
- if (PIM_DEBUG_ZEBRA) {
- zlog_debug(
- "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
- __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
- (long)ifp->flags, ifp->metric, ifp->mtu,
- if_is_operative(ifp));
- }
-
- pim = pim_get_pim_instance(vrf_id);
- if (if_is_operative(ifp)) {
- struct pim_interface *pim_ifp;
-
- pim_ifp = ifp->info;
- /*
- * If we have a pim_ifp already and this is an if_add
- * that means that we probably have a vrf move event
- * If that is the case, set the proper vrfness.
- */
- if (pim_ifp)
- pim_ifp->pim = pim;
-
- /*
- pim_if_addr_add_all() suffices for bringing up both IGMP and
- PIM
- */
- pim_if_addr_add_all(ifp);
- }
-
- /*
- * If we have a pimreg device callback and it's for a specific
- * table set the master appropriately
- */
- if (sscanf(ifp->name, "pimreg%" SCNu32, &table_id) == 1) {
- struct vrf *vrf;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- if ((table_id == vrf->data.l.table_id)
- && (ifp->vrf_id != vrf->vrf_id)) {
- struct interface *master = if_lookup_by_name(
- vrf->name, vrf->vrf_id);
-
- if (!master) {
- zlog_debug(
- "%s: Unable to find Master interface for %s",
- __PRETTY_FUNCTION__, vrf->name);
- return 0;
- }
- zclient_interface_set_master(zclient, master,
- ifp);
- }
- }
- }
- return 0;
-}
-
-static int pim_zebra_if_state_down(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp;
-
- /*
- zebra api notifies interface up/down events by using the same call
- zebra_interface_state_read below, see comments in lib/zclient.c
- */
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- if (!ifp)
- return 0;
-
- if (PIM_DEBUG_ZEBRA) {
- zlog_debug(
- "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
- __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
- (long)ifp->flags, ifp->metric, ifp->mtu,
- if_is_operative(ifp));
- }
-
- if (!if_is_operative(ifp)) {
- pim_ifchannel_delete_all(ifp);
- /*
- pim_if_addr_del_all() suffices for shutting down IGMP,
- but not for shutting down PIM
- */
- pim_if_addr_del_all(ifp);
-
- /*
- pim_sock_delete() closes the socket, stops read and timer
- threads,
- and kills all neighbors.
- */
- if (ifp->info) {
- pim_sock_delete(ifp, "link down");
- }
- }
-
- if (ifp->info)
- pim_if_del_vif(ifp);
-
- return 0;
-}
-
static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
@@ -793,10 +581,6 @@ void pim_zebra_init(void)
zclient->zebra_capabilities = pim_zebra_capabilities;
zclient->zebra_connected = pim_zebra_connected;
zclient->router_id_update = pim_router_id_update_zebra;
- zclient->interface_add = pim_zebra_if_add;
- zclient->interface_delete = pim_zebra_if_del;
- zclient->interface_up = pim_zebra_if_state_up;
- zclient->interface_down = pim_zebra_if_state_down;
zclient->interface_address_add = pim_zebra_if_address_add;
zclient->interface_address_delete = pim_zebra_if_address_del;
zclient->interface_vrf_update = pim_zebra_interface_vrf_update;
@@ -1180,12 +964,6 @@ void pim_forward_start(struct pim_ifchannel *ch)
{
struct pim_upstream *up = ch->upstream;
uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
- int input_iface_vif_index = 0;
- struct pim_instance *pim;
- struct pim_interface *pim_ifp;
-
- pim_ifp = ch->interface->info;
- pim = pim_ifp->pim;
if (PIM_DEBUG_PIM_TRACE) {
char source_str[INET_ADDRSTRLEN];
@@ -1203,55 +981,6 @@ void pim_forward_start(struct pim_ifchannel *ch)
inet_ntoa(up->upstream_addr));
}
- /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS,
- as part of mroute_del called by pim_forward_stop.
- */
- if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) {
- struct prefix src, grp;
-
- grp.family = AF_INET;
- grp.prefixlen = IPV4_MAX_BITLEN;
- grp.u.prefix4 = up->sg.grp;
- src.family = AF_INET;
- src.prefixlen = IPV4_MAX_BITLEN;
- src.u.prefix4 = up->sg.src;
-
- if (pim_ecmp_nexthop_lookup(pim, &up->rpf.source_nexthop, &src,
- &grp, 0))
- input_iface_vif_index = pim_if_find_vifindex_by_ifindex(
- pim, up->rpf.source_nexthop.interface->ifindex);
-
- if (input_iface_vif_index < 1) {
- if (PIM_DEBUG_PIM_TRACE) {
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", up->sg.src,
- source_str, sizeof(source_str));
- zlog_debug(
- "%s %s: could not find input interface for source %s",
- __FILE__, __PRETTY_FUNCTION__,
- source_str);
- }
- pim_channel_oil_change_iif(pim, up->channel_oil,
- MAXVIFS,
- __PRETTY_FUNCTION__);
- }
-
- else
- pim_channel_oil_change_iif(pim, up->channel_oil,
- input_iface_vif_index,
- __PRETTY_FUNCTION__);
-
- if (PIM_DEBUG_TRACE) {
- struct interface *in_intf = pim_if_find_by_vif_index(
- pim, input_iface_vif_index);
- zlog_debug(
- "%s: Update channel_oil IIF %s VIFI %d entry %s ",
- __PRETTY_FUNCTION__,
- in_intf ? in_intf->name : "Unknown",
- input_iface_vif_index, up->sg_str);
- }
- }
-
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
mask = PIM_OIF_FLAG_PROTO_IGMP;
@@ -1301,3 +1030,9 @@ struct zclient *pim_zebra_zclient_get(void)
else
return NULL;
}
+
+void pim_zebra_interface_set_master(struct interface *vrf,
+ struct interface *ifp)
+{
+ zclient_interface_set_master(zclient, vrf, ifp);
+}
diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h
index c9ed89863..0f216cf5c 100644
--- a/pimd/pim_zebra.h
+++ b/pimd/pim_zebra.h
@@ -51,4 +51,7 @@ void pim_zebra_update_all_interfaces(struct pim_instance *pim);
void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
struct pim_upstream *up,
struct pim_rpf *old);
+
+void pim_zebra_interface_set_master(struct interface *vrf,
+ struct interface *ifp);
#endif /* PIM_ZEBRA_H */
diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c
index 80561f350..3173277ba 100644
--- a/ripd/rip_interface.c
+++ b/ripd/rip_interface.c
@@ -346,20 +346,8 @@ int if_check_address(struct rip *rip, struct in_addr addr)
}
/* Inteface link down message processing. */
-int rip_interface_down(ZAPI_CALLBACK_ARGS)
+static int rip_ifp_down(struct interface *ifp)
{
- struct interface *ifp;
- struct stream *s;
-
- s = zclient->ibuf;
-
- /* zebra_interface_state_read() updates interface structure in
- iflist. */
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
rip_interface_sync(ifp);
rip_if_down(ifp);
@@ -373,17 +361,8 @@ int rip_interface_down(ZAPI_CALLBACK_ARGS)
}
/* Inteface link up message processing */
-int rip_interface_up(ZAPI_CALLBACK_ARGS)
+static int rip_ifp_up(struct interface *ifp)
{
- struct interface *ifp;
-
- /* zebra_interface_state_read () updates interface structure in
- iflist. */
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
if (IS_RIP_DEBUG_ZEBRA)
zlog_debug(
"interface %s vrf %u index %d flags %#llx metric %d mtu %d is up",
@@ -405,11 +384,8 @@ int rip_interface_up(ZAPI_CALLBACK_ARGS)
}
/* Inteface addition message from zebra. */
-int rip_interface_add(ZAPI_CALLBACK_ARGS)
+static int rip_ifp_create(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
rip_interface_sync(ifp);
if (IS_RIP_DEBUG_ZEBRA)
@@ -435,19 +411,8 @@ int rip_interface_add(ZAPI_CALLBACK_ARGS)
return 0;
}
-int rip_interface_delete(ZAPI_CALLBACK_ARGS)
+static int rip_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
- struct stream *s;
-
-
- s = zclient->ibuf;
- /* zebra_interface_state_read() updates interface structure in iflist */
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
rip_interface_sync(ifp);
if (if_is_up(ifp)) {
rip_if_down(ifp);
@@ -458,10 +423,6 @@ int rip_interface_delete(ZAPI_CALLBACK_ARGS)
ifp->name, ifp->vrf_id, ifp->ifindex,
(unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
- /* To support pseudo interface do not free interface structure. */
- /* if_delete(ifp); */
- if_set_index(ifp, IFINDEX_INTERNAL);
-
return 0;
}
@@ -1263,4 +1224,6 @@ void rip_if_init(void)
/* Install interface node. */
install_node(&interface_node, rip_interface_config_write);
if_cmd_init();
+ if_zapi_callbacks(rip_ifp_create, rip_ifp_up,
+ rip_ifp_down, rip_ifp_destroy);
}
diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c
index 5a6b71fba..7260a40b1 100644
--- a/ripd/rip_snmp.c
+++ b/ripd/rip_snmp.c
@@ -551,7 +551,7 @@ static uint8_t *rip2PeerTable(struct variable *v, oid name[], size_t *length,
return (uint8_t *)&domain;
case RIP2PEERLASTUPDATE:
-#if 0
+#if 0
/* We don't know the SNMP agent startup time. We have two choices here:
* - assume ripd startup time equals SNMP agent startup time
* - don't support this variable, at all
diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c
index 0c88cb202..90ee667f0 100644
--- a/ripd/rip_zebra.c
+++ b/ripd/rip_zebra.c
@@ -238,12 +238,8 @@ void rip_zclient_init(struct thread_master *master)
zclient = zclient_new(master, &zclient_options_default);
zclient_init(zclient, ZEBRA_ROUTE_RIP, 0, &ripd_privs);
zclient->zebra_connected = rip_zebra_connected;
- zclient->interface_add = rip_interface_add;
- zclient->interface_delete = rip_interface_delete;
zclient->interface_address_add = rip_interface_address_add;
zclient->interface_address_delete = rip_interface_address_delete;
- zclient->interface_up = rip_interface_up;
- zclient->interface_down = rip_interface_down;
zclient->interface_vrf_update = rip_interface_vrf_update;
zclient->redistribute_route_add = rip_zebra_read_route;
zclient->redistribute_route_del = rip_zebra_read_route;
diff --git a/ripd/ripd.c b/ripd/ripd.c
index cd2ddb1eb..1b5a582cb 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -3660,18 +3660,14 @@ static int rip_vrf_enable(struct vrf *vrf)
if (yang_module_find("frr-ripd") && old_vrf_name) {
struct lyd_node *rip_dnode;
- pthread_rwlock_wrlock(&running_config->lock);
- {
- rip_dnode = yang_dnode_get(
- running_config->dnode,
- "/frr-ripd:ripd/instance[vrf='%s']/vrf",
- old_vrf_name);
- if (rip_dnode) {
- yang_dnode_change_leaf(rip_dnode, vrf->name);
- running_config->version++;
- }
+ rip_dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-ripd:ripd/instance[vrf='%s']/vrf",
+ old_vrf_name);
+ if (rip_dnode) {
+ yang_dnode_change_leaf(rip_dnode, vrf->name);
+ running_config->version++;
}
- pthread_rwlock_unlock(&running_config->lock);
}
if (old_vrf_name)
XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name);
diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c
index 9ed9dc28f..9209a7646 100644
--- a/ripngd/ripng_interface.c
+++ b/ripngd/ripng_interface.c
@@ -43,10 +43,10 @@
/* If RFC2133 definition is used. */
#ifndef IPV6_JOIN_GROUP
-#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
#endif
#ifndef IPV6_LEAVE_GROUP
-#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
#endif
DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface")
@@ -196,19 +196,8 @@ static int ripng_if_down(struct interface *ifp)
}
/* Inteface link up message processing. */
-int ripng_interface_up(ZAPI_CALLBACK_ARGS)
+static int ripng_ifp_up(struct interface *ifp)
{
- struct stream *s;
- struct interface *ifp;
-
- /* zebra_interface_state_read() updates interface structure in iflist.
- */
- s = zclient->ibuf;
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
if (IS_RIPNG_DEBUG_ZEBRA)
zlog_debug(
"interface up %s vrf %u index %d flags %llx metric %d mtu %d",
@@ -230,19 +219,8 @@ int ripng_interface_up(ZAPI_CALLBACK_ARGS)
}
/* Inteface link down message processing. */
-int ripng_interface_down(ZAPI_CALLBACK_ARGS)
+static int ripng_ifp_down(struct interface *ifp)
{
- struct stream *s;
- struct interface *ifp;
-
- /* zebra_interface_state_read() updates interface structure in iflist.
- */
- s = zclient->ibuf;
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
ripng_interface_sync(ifp);
ripng_if_down(ifp);
@@ -256,11 +234,8 @@ int ripng_interface_down(ZAPI_CALLBACK_ARGS)
}
/* Inteface addition message from zebra. */
-int ripng_interface_add(ZAPI_CALLBACK_ARGS)
+static int ripng_ifp_create(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
ripng_interface_sync(ifp);
if (IS_RIPNG_DEBUG_ZEBRA)
@@ -281,19 +256,8 @@ int ripng_interface_add(ZAPI_CALLBACK_ARGS)
return 0;
}
-int ripng_interface_delete(ZAPI_CALLBACK_ARGS)
+static int ripng_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
- struct stream *s;
-
- s = zclient->ibuf;
- /* zebra_interface_state_read() updates interface structure in iflist
- */
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
ripng_interface_sync(ifp);
if (if_is_up(ifp)) {
ripng_if_down(ifp);
@@ -304,10 +268,6 @@ int ripng_interface_delete(ZAPI_CALLBACK_ARGS)
ifp->name, ifp->vrf_id, ifp->ifindex,
(unsigned long long)ifp->flags, ifp->metric, ifp->mtu6);
- /* To support pseudo interface do not free interface structure. */
- /* if_delete(ifp); */
- if_set_index(ifp, IFINDEX_INTERNAL);
-
return 0;
}
@@ -999,4 +959,6 @@ void ripng_if_init(void)
/* Install interface node. */
install_node(&interface_node, interface_config_write);
if_cmd_init();
+ if_zapi_callbacks(ripng_ifp_create, ripng_ifp_up,
+ ripng_ifp_down, ripng_ifp_destroy);
}
diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c
index a557a90c8..fa61d69ca 100644
--- a/ripngd/ripng_zebra.c
+++ b/ripngd/ripng_zebra.c
@@ -242,10 +242,6 @@ void zebra_init(struct thread_master *master)
zclient_init(zclient, ZEBRA_ROUTE_RIPNG, 0, &ripngd_privs);
zclient->zebra_connected = ripng_zebra_connected;
- zclient->interface_up = ripng_interface_up;
- zclient->interface_down = ripng_interface_down;
- zclient->interface_add = ripng_interface_add;
- zclient->interface_delete = ripng_interface_delete;
zclient->interface_address_add = ripng_interface_address_add;
zclient->interface_address_delete = ripng_interface_address_delete;
zclient->interface_vrf_update = ripng_interface_vrf_update;
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index 120f46f0d..ad2ddd0db 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -2361,7 +2361,7 @@ DEFUN (show_ipv6_protocols,
return CMD_SUCCESS;
vty_out (vty, "Routing Protocol is \"ripng\"\n");
-
+
vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds\n",
ripng->update_time, 0);
@@ -2795,18 +2795,14 @@ static int ripng_vrf_enable(struct vrf *vrf)
if (yang_module_find("frr-ripngd") && old_vrf_name) {
struct lyd_node *ripng_dnode;
- pthread_rwlock_wrlock(&running_config->lock);
- {
- ripng_dnode = yang_dnode_get(
- running_config->dnode,
- "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
- old_vrf_name);
- if (ripng_dnode) {
- yang_dnode_change_leaf(ripng_dnode, vrf->name);
- running_config->version++;
- }
+ ripng_dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
+ old_vrf_name);
+ if (ripng_dnode) {
+ yang_dnode_change_leaf(ripng_dnode, vrf->name);
+ running_config->version++;
}
- pthread_rwlock_unlock(&running_config->lock);
}
if (old_vrf_name)
XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index 60cfb2e48..486ccf6bf 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -39,7 +39,7 @@
#endif
DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
- "sharp watch [vrf NAME$name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]",
+ "sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
"The vrf we would like to watch if non-default\n"
@@ -54,12 +54,12 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
struct prefix p;
bool type_import;
- if (!name)
- name = VRF_DEFAULT_NAME;
- vrf = vrf_lookup_by_name(name);
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+ vrf = vrf_lookup_by_name(vrf_name);
if (!vrf) {
vty_out(vty, "The vrf NAME specified: %s does not exist\n",
- name);
+ vrf_name);
return CMD_WARNING;
}
@@ -83,7 +83,7 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
}
DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
- "sharp watch [vrf NAME$name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]",
+ "sharp watch [vrf NAME$vrf_name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
"The vrf we would like to watch if non-default\n"
@@ -98,12 +98,12 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
struct prefix p;
bool type_import;
- if (!name)
- name = VRF_DEFAULT_NAME;
- vrf = vrf_lookup_by_name(name);
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+ vrf = vrf_lookup_by_name(vrf_name);
if (!vrf) {
vty_out(vty, "The vrf NAME specified: %s does not exist\n",
- name);
+ vrf_name);
return CMD_WARNING;
}
@@ -162,7 +162,7 @@ DEFPY (install_routes_data_dump,
DEFPY (install_routes,
install_routes_cmd,
- "sharp install routes [vrf NAME$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> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
"Sharp routing Protocol\n"
"install some routes\n"
"Routes to install\n"
@@ -209,13 +209,13 @@ DEFPY (install_routes,
}
sg.r.orig_prefix = prefix;
- if (!name)
- name = VRF_DEFAULT_NAME;
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
- vrf = vrf_lookup_by_name(name);
+ vrf = vrf_lookup_by_name(vrf_name);
if (!vrf) {
vty_out(vty, "The vrf NAME specified: %s does not exist\n",
- name);
+ vrf_name);
return CMD_WARNING;
}
@@ -252,7 +252,7 @@ DEFPY (install_routes,
}
DEFPY(vrf_label, vrf_label_cmd,
- "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$name label (0-100000)$label",
+ "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
"Sharp Routing Protocol\n"
"Give a vrf a label\n"
"Pop and forward for IPv4\n"
@@ -264,10 +264,10 @@ DEFPY(vrf_label, vrf_label_cmd,
struct vrf *vrf;
afi_t afi = (ipv4) ? AFI_IP : AFI_IP6;
- if (strcmp(name, "default") == 0)
+ if (strcmp(vrf_name, "default") == 0)
vrf = vrf_lookup_by_id(VRF_DEFAULT);
else
- vrf = vrf_lookup_by_name(name);
+ vrf = vrf_lookup_by_name(vrf_name);
if (!vrf) {
vty_out(vty, "Unable to find vrf you silly head");
@@ -283,7 +283,7 @@ DEFPY(vrf_label, vrf_label_cmd,
DEFPY (remove_routes,
remove_routes_cmd,
- "sharp remove routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
+ "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
"Sharp Routing Protocol\n"
"Remove some routes\n"
"Routes to remove\n"
@@ -314,10 +314,10 @@ DEFPY (remove_routes,
prefix.u.prefix6 = start6;
}
- vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME);
+ vrf = vrf_lookup_by_name(vrf_name ? vrf_name : VRF_DEFAULT_NAME);
if (!vrf) {
vty_out(vty, "The vrf NAME specified: %s does not exist\n",
- name ? name : VRF_DEFAULT_NAME);
+ vrf_name ? vrf_name : VRF_DEFAULT_NAME);
return CMD_WARNING;
}
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index 6263f429e..da2aa2f53 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -46,51 +46,19 @@ struct zclient *zclient = NULL;
/* For registering threads. */
extern struct thread_master *master;
-static struct interface *zebra_interface_if_lookup(struct stream *s)
-{
- char ifname_tmp[INTERFACE_NAMSIZ];
-
- /* Read interface name. */
- stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
-
- /* And look it up. */
- return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
-}
-
/* Inteface addition message from zebra. */
-static int interface_add(ZAPI_CALLBACK_ARGS)
+static int sharp_ifp_create(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
-
- if (!ifp->info)
- return 0;
-
return 0;
}
-static int interface_delete(ZAPI_CALLBACK_ARGS)
+static int sharp_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
- struct stream *s;
-
- s = zclient->ibuf;
- /* zebra_interface_state_read () updates interface structure in iflist
- */
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- if_set_index(ifp, IFINDEX_INTERNAL);
-
return 0;
}
static int interface_address_add(ZAPI_CALLBACK_ARGS)
{
-
zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
return 0;
@@ -109,19 +77,13 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int interface_state_up(ZAPI_CALLBACK_ARGS)
+static int sharp_ifp_up(struct interface *ifp)
{
-
- zebra_interface_if_lookup(zclient->ibuf);
-
return 0;
}
-static int interface_state_down(ZAPI_CALLBACK_ARGS)
+static int sharp_ifp_down(struct interface *ifp)
{
-
- zebra_interface_state_read(zclient->ibuf, vrf_id);
-
return 0;
}
@@ -243,6 +205,15 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS)
static void zebra_connected(struct zclient *zclient)
{
zclient_send_reg_requests(zclient, VRF_DEFAULT);
+
+ /*
+ * Do not actually turn this on yet
+ * This is just the start of the infrastructure needed here
+ * This can be fixed at a later time.
+ *
+ * zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
+ * ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
+ */
}
void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label)
@@ -338,28 +309,13 @@ void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import,
__PRETTY_FUNCTION__);
}
-static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS)
+static int sharp_debug_nexthops(struct zapi_route *api)
{
- struct sharp_nh_tracker *nht;
- struct zapi_route nhr;
- char buf[PREFIX_STRLEN];
int i;
+ char buf[PREFIX_STRLEN];
- if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
- zlog_warn("%s: Decode of update failed", __PRETTY_FUNCTION__);
-
- return 0;
- }
-
- zlog_debug("Received update for %s",
- prefix2str(&nhr.prefix, buf, sizeof(buf)));
-
- nht = sharp_nh_tracker_get(&nhr.prefix);
- nht->nhop_num = nhr.nexthop_num;
- nht->updates++;
-
- for (i = 0; i < nhr.nexthop_num; i++) {
- struct zapi_nexthop *znh = &nhr.nexthops[i];
+ for (i = 0; i < api->nexthop_num; i++) {
+ struct zapi_nexthop *znh = &api->nexthops[i];
switch (znh->type) {
case NEXTHOP_TYPE_IPV4_IFINDEX:
@@ -389,6 +345,45 @@ static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS)
break;
}
}
+
+ return i;
+}
+static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS)
+{
+ struct sharp_nh_tracker *nht;
+ struct zapi_route nhr;
+
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ zlog_warn("%s: Decode of update failed", __PRETTY_FUNCTION__);
+
+ return 0;
+ }
+
+ zlog_debug("Received update for %pFX", &nhr.prefix);
+
+ nht = sharp_nh_tracker_get(&nhr.prefix);
+ nht->nhop_num = nhr.nexthop_num;
+ nht->updates++;
+
+ sharp_debug_nexthops(&nhr);
+
+ return 0;
+}
+
+static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS)
+{
+ struct zapi_route api;
+
+ if (zapi_route_decode(zclient->ibuf, &api) < 0)
+ zlog_warn("%s: Decode of redistribute failed: %d",
+ __PRETTY_FUNCTION__,
+ ZEBRA_REDISTRIBUTE_ROUTE_ADD);
+
+ zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd),
+ &api.prefix, zebra_route_string(api.type));
+
+ sharp_debug_nexthops(&api);
+
return 0;
}
@@ -398,17 +393,19 @@ void sharp_zebra_init(void)
{
struct zclient_options opt = {.receive_notify = true};
+ if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up,
+ sharp_ifp_down, sharp_ifp_destroy);
+
zclient = zclient_new(master, &opt);
zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs);
zclient->zebra_connected = zebra_connected;
- zclient->interface_add = interface_add;
- zclient->interface_delete = interface_delete;
- zclient->interface_up = interface_state_up;
- zclient->interface_down = interface_state_down;
zclient->interface_address_add = interface_address_add;
zclient->interface_address_delete = interface_address_delete;
zclient->route_notify_owner = route_notify_owner;
zclient->nexthop_update = sharp_nexthop_update;
zclient->import_check_update = sharp_nexthop_update;
+
+ zclient->redistribute_route_add = sharp_redistribute_route;
+ zclient->redistribute_route_del = sharp_redistribute_route;
}
diff --git a/staticd/static_routes.c b/staticd/static_routes.c
index a8a5ca523..e8d6a4289 100644
--- a/staticd/static_routes.c
+++ b/staticd/static_routes.c
@@ -310,10 +310,14 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi,
if (up) {
if (strcmp(si->ifname, ifp->name))
continue;
+ if (si->nh_vrf_id != ifp->vrf_id)
+ continue;
si->ifindex = ifp->ifindex;
} else {
if (si->ifindex != ifp->ifindex)
continue;
+ if (si->nh_vrf_id != ifp->vrf_id)
+ continue;
si->ifindex = IFINDEX_INTERNAL;
}
diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c
index 9dd25fbdd..abb64aad3 100644
--- a/staticd/static_vrf.c
+++ b/staticd/static_vrf.c
@@ -27,6 +27,7 @@
#include "static_memory.h"
#include "static_vrf.h"
#include "static_routes.h"
+#include "static_zebra.h"
#include "static_vty.h"
static void zebra_stable_node_cleanup(struct route_table *table,
@@ -76,6 +77,8 @@ static int static_vrf_new(struct vrf *vrf)
static int static_vrf_enable(struct vrf *vrf)
{
+ static_zebra_vrf_register(vrf);
+
static_fixup_vrf_ids(vrf->info);
/*
@@ -89,6 +92,7 @@ static int static_vrf_enable(struct vrf *vrf)
static int static_vrf_disable(struct vrf *vrf)
{
+ static_zebra_vrf_unregister(vrf);
return 0;
}
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index 1965c2968..976f892ef 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -49,46 +49,16 @@ bool debug;
struct zclient *zclient;
static struct hash *static_nht_hash;
-static struct interface *zebra_interface_if_lookup(struct stream *s)
-{
- char ifname_tmp[INTERFACE_NAMSIZ];
-
- /* Read interface name. */
- stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
-
- /* And look it up. */
- return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
-}
-
/* Inteface addition message from zebra. */
-static int interface_add(ZAPI_CALLBACK_ARGS)
+static int static_ifp_create(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
-
- if (!ifp)
- return 0;
-
static_ifindex_update(ifp, true);
+
return 0;
}
-static int interface_delete(ZAPI_CALLBACK_ARGS)
+static int static_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
- struct stream *s;
-
- s = zclient->ibuf;
- /* zebra_interface_state_read () updates interface structure in iflist
- */
- ifp = zebra_interface_state_read(s, vrf_id);
-
- if (ifp == NULL)
- return 0;
-
- if_set_index(ifp, IFINDEX_INTERNAL);
-
static_ifindex_update(ifp, false);
return 0;
}
@@ -113,37 +83,25 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int interface_state_up(ZAPI_CALLBACK_ARGS)
+static int static_ifp_up(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_if_lookup(zclient->ibuf);
-
- if (ifp) {
- if (if_is_vrf(ifp)) {
- struct static_vrf *svrf =
- static_vrf_lookup_by_id(vrf_id);
+ if (if_is_vrf(ifp)) {
+ struct static_vrf *svrf = static_vrf_lookup_by_id(ifp->vrf_id);
- static_fixup_vrf_ids(svrf);
- static_config_install_delayed_routes(svrf);
- }
-
- /* Install any static reliant on this interface coming up */
- static_install_intf_nh(ifp);
- static_ifindex_update(ifp, true);
+ static_fixup_vrf_ids(svrf);
+ static_config_install_delayed_routes(svrf);
}
+ /* Install any static reliant on this interface coming up */
+ static_install_intf_nh(ifp);
+ static_ifindex_update(ifp, true);
+
return 0;
}
-static int interface_state_down(ZAPI_CALLBACK_ARGS)
+static int static_ifp_down(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
- if (ifp)
- static_ifindex_update(ifp, false);
+ static_ifindex_update(ifp, false);
return 0;
}
@@ -504,19 +462,19 @@ extern void static_zebra_route_add(struct route_node *rn,
ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
zclient, &api);
}
+
void static_zebra_init(void)
{
struct zclient_options opt = { .receive_notify = true };
+ if_zapi_callbacks(static_ifp_create, static_ifp_up,
+ static_ifp_down, static_ifp_destroy);
+
zclient = zclient_new(master, &opt);
zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs);
zclient->zebra_capabilities = static_zebra_capabilities;
zclient->zebra_connected = zebra_connected;
- zclient->interface_add = interface_add;
- zclient->interface_delete = interface_delete;
- zclient->interface_up = interface_state_up;
- zclient->interface_down = interface_state_down;
zclient->interface_address_add = interface_address_add;
zclient->interface_address_delete = interface_address_delete;
zclient->route_notify_owner = route_notify_owner;
@@ -526,3 +484,17 @@ void static_zebra_init(void)
static_nht_hash_cmp,
"Static Nexthop Tracking hash");
}
+
+void static_zebra_vrf_register(struct vrf *vrf)
+{
+ if (vrf->vrf_id == VRF_DEFAULT)
+ return;
+ zclient_send_reg_requests(zclient, vrf->vrf_id);
+}
+
+void static_zebra_vrf_unregister(struct vrf *vrf)
+{
+ if (vrf->vrf_id == VRF_DEFAULT)
+ return;
+ zclient_send_dereg_requests(zclient, vrf->vrf_id);
+}
diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h
index 15f5410b8..962dc3908 100644
--- a/staticd/static_zebra.h
+++ b/staticd/static_zebra.h
@@ -28,4 +28,7 @@ extern void static_zebra_route_add(struct route_node *rn,
struct static_route *si_changed,
vrf_id_t vrf_id, safi_t safi, bool install);
extern void static_zebra_init(void);
+extern void static_zebra_vrf_register(struct vrf *vrf);
+extern void static_zebra_vrf_unregister(struct vrf *vrf);
+
#endif
diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c
index b5db36703..925d3112d 100644
--- a/tests/bgpd/test_aspath.c
+++ b/tests/bgpd/test_aspath.c
@@ -1339,7 +1339,7 @@ int main(void)
{
int i = 0;
qobj_init();
- bgp_master_init(thread_master_create(NULL));
+ bgp_master_init(thread_master_create(NULL), BGP_SOCKET_SNDBUF_SIZE);
master = bm->master;
bgp_option_set(BGP_OPT_NO_LISTEN);
bgp_attr_init();
diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c
index db1cf0611..96e398512 100644
--- a/tests/bgpd/test_capability.c
+++ b/tests/bgpd/test_capability.c
@@ -912,7 +912,7 @@ int main(void)
qobj_init();
master = thread_master_create(NULL);
- bgp_master_init(master);
+ bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
vrf_init(NULL, NULL, NULL, NULL, NULL);
bgp_option_set(BGP_OPT_NO_LISTEN);
diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c
index 603b678cf..fbf2a9fed 100644
--- a/tests/bgpd/test_mp_attr.c
+++ b/tests/bgpd/test_mp_attr.c
@@ -37,6 +37,7 @@
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_network.h"
#define VT100_RESET "\x1b[0m"
#define VT100_RED "\x1b[31m"
@@ -1078,7 +1079,7 @@ int main(void)
cmd_init(0);
bgp_vty_init();
master = thread_master_create("test mp attr");
- bgp_master_init(master);
+ bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
vrf_init(NULL, NULL, NULL, NULL, NULL);
bgp_option_set(BGP_OPT_NO_LISTEN);
bgp_attr_init();
diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c
index 0ecd0fdfe..21f4b3877 100644
--- a/tests/bgpd/test_mpath.c
+++ b/tests/bgpd/test_mpath.c
@@ -38,6 +38,7 @@
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_mpath.h"
#include "bgpd/bgp_evpn.h"
+#include "bgpd/bgp_network.h"
#define VT100_RESET "\x1b[0m"
#define VT100_RED "\x1b[31m"
@@ -379,7 +380,7 @@ static int global_test_init(void)
qobj_init();
master = thread_master_create(NULL);
zclient = zclient_new(master, &zclient_options_default);
- bgp_master_init(master);
+ bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
vrf_init(NULL, NULL, NULL, NULL, NULL);
bgp_option_set(BGP_OPT_NO_LISTEN);
diff --git a/tests/bgpd/test_packet.c b/tests/bgpd/test_packet.c
index 9719aceec..7a038fb02 100644
--- a/tests/bgpd/test_packet.c
+++ b/tests/bgpd/test_packet.c
@@ -34,6 +34,7 @@
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_network.h"
/* need these to link in libbgp */
struct zebra_privs_t *bgpd_privs = NULL;
@@ -58,7 +59,7 @@ int main(int argc, char *argv[])
qobj_init();
bgp_attr_init();
master = thread_master_create(NULL);
- bgp_master_init(master);
+ bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
vrf_init(NULL, NULL, NULL, NULL, NULL);
bgp_option_set(BGP_OPT_NO_LISTEN);
diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c
index e5d3030ed..422d39747 100644
--- a/tests/bgpd/test_peer_attr.c
+++ b/tests/bgpd/test_peer_attr.c
@@ -29,6 +29,7 @@
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_network.h"
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
@@ -1388,7 +1389,7 @@ static void bgp_startup(void)
master = thread_master_create(NULL);
yang_init();
nb_init(master, NULL, 0);
- bgp_master_init(master);
+ bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
bgp_option_set(BGP_OPT_NO_LISTEN);
vrf_init(NULL, NULL, NULL, NULL, NULL);
frr_pthread_init();
diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h
index 7ff210cae..f20bbc52d 100644
--- a/tests/lib/test_typelist.h
+++ b/tests/lib/test_typelist.h
@@ -280,7 +280,7 @@ static void concat(test_, TYPE)(void)
assert(!tmp || tmp->val >= j);
} else
assert(gteq == list_first(&head));
-
+
if (gteq)
assert(gteq->val >= j);
}
diff --git a/tests/topotests/Dockerfile b/tests/topotests/Dockerfile
index fc6d6df53..cdd0ae2f6 100644
--- a/tests/topotests/Dockerfile
+++ b/tests/topotests/Dockerfile
@@ -6,9 +6,11 @@ RUN export DEBIAN_FRONTEND=noninteractive \
autoconf \
binutils \
bison \
+ ca-certificates \
flex \
gdb \
git \
+ gpg \
install-info \
iputils-ping \
iproute2 \
@@ -38,17 +40,15 @@ RUN export DEBIAN_FRONTEND=noninteractive \
&& pip install \
exabgp==3.4.17 \
ipaddr \
- pytest
+ pytest \
+ && rm -rf /var/lib/apt/lists/*
-RUN cd /tmp \
- && wget -q https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/Debian-AMD64-Packages/libyang-dev_0.16.105-1_amd64.deb \
- -O libyang-dev.deb \
- && wget -q https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/Debian-AMD64-Packages/libyang0.16_0.16.105-1_amd64.deb \
- -O libyang.deb \
- && echo "34bef017e527a590020185f05dc39203bdf1c86223e0d990839623ec629d8598 libyang.deb" | sha256sum -c - \
- && echo "fe9cc6e3b173ca56ef49428c281e96bf76c0f910aa75cf85098076411484e8f4 libyang-dev.deb" | sha256sum -c - \
- && dpkg -i libyang*.deb \
- && rm libyang*.deb
+RUN export DEBIAN_FRONTEND=noninteractive \
+ && apt-key adv --keyserver keyserver.ubuntu.com --recv-key 5418F291D0D4A1AA \
+ && echo "deb https://deb.frrouting.org/frr bionic frr-stable" > /etc/apt/sources.list.d/frr.list \
+ && apt-get update \
+ && apt-get install -y libyang-dev \
+ && rm -rf /var/lib/apt/lists/*
RUN groupadd -r -g 92 frr \
&& groupadd -r -g 85 frrvty \
diff --git a/tests/topotests/bfd-topo2/r1/ipv6_routes.json b/tests/topotests/bfd-topo2/r1/ipv6_routes.json
index d09439a8a..0fd03b516 100644
--- a/tests/topotests/bfd-topo2/r1/ipv6_routes.json
+++ b/tests/topotests/bfd-topo2/r1/ipv6_routes.json
@@ -33,7 +33,6 @@
{
"interfaceName": "r1-eth0",
"interfaceIndex": 2,
- "flags": 1,
"active": true,
"afi": "ipv6"
}
diff --git a/tests/topotests/bfd-topo2/r2/ipv4_routes.json b/tests/topotests/bfd-topo2/r2/ipv4_routes.json
index 3c41e1343..69a5f1a5b 100644
--- a/tests/topotests/bfd-topo2/r2/ipv4_routes.json
+++ b/tests/topotests/bfd-topo2/r2/ipv4_routes.json
@@ -11,7 +11,6 @@
{
"active": true,
"directlyConnected": true,
- "flags": 1,
"interfaceIndex": 3,
"interfaceName": "r2-eth1"
}
diff --git a/tests/topotests/bfd-topo2/r2/ipv6_routes.json b/tests/topotests/bfd-topo2/r2/ipv6_routes.json
index bb45bbae5..66abade38 100644
--- a/tests/topotests/bfd-topo2/r2/ipv6_routes.json
+++ b/tests/topotests/bfd-topo2/r2/ipv6_routes.json
@@ -11,7 +11,6 @@
{
"active": true,
"directlyConnected": true,
- "flags": 1,
"interfaceIndex": 4,
"interfaceName": "r2-eth2"
}
diff --git a/tests/topotests/bfd-topo2/r3/ipv4_routes.json b/tests/topotests/bfd-topo2/r3/ipv4_routes.json
index cbf116e68..d4a0812ae 100644
--- a/tests/topotests/bfd-topo2/r3/ipv4_routes.json
+++ b/tests/topotests/bfd-topo2/r3/ipv4_routes.json
@@ -11,7 +11,6 @@
{
"active": true,
"directlyConnected": true,
- "flags": 1,
"interfaceIndex": 2,
"interfaceName": "r3-eth0"
}
diff --git a/tests/topotests/bfd-topo2/r4/ipv6_routes.json b/tests/topotests/bfd-topo2/r4/ipv6_routes.json
index a22c90cbb..af8272c4a 100644
--- a/tests/topotests/bfd-topo2/r4/ipv6_routes.json
+++ b/tests/topotests/bfd-topo2/r4/ipv6_routes.json
@@ -11,7 +11,6 @@
{
"active": true,
"directlyConnected": true,
- "flags": 1,
"interfaceIndex": 2,
"interfaceName": "r4-eth0"
}
diff --git a/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json b/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json
index 50797f130..34f11c0a2 100755
--- a/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json
+++ b/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json
@@ -564,6 +564,16 @@
"ipv6": "auto"
}
},
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ },
"bgp": {
"local_as": "300",
"address_family": {
@@ -620,38 +630,198 @@
"neighbor": {
"r2": {
"dest_link": {
- "r3-link1": {},
- "r3-link2": {},
- "r3-link3": {},
- "r3-link4": {},
- "r3-link5": {},
- "r3-link6": {},
- "r3-link7": {},
- "r3-link8": {},
- "r3-link9": {},
- "r3-link10": {},
- "r3-link11": {},
- "r3-link12": {},
- "r3-link13": {},
- "r3-link14": {},
- "r3-link15": {},
- "r3-link16": {},
- "r3-link17": {},
- "r3-link18": {},
- "r3-link19": {},
- "r3-link20": {},
- "r3-link21": {},
- "r3-link22": {},
- "r3-link23": {},
- "r3-link24": {},
- "r3-link25": {},
- "r3-link26": {},
- "r3-link27": {},
- "r3-link28": {},
- "r3-link29": {},
- "r3-link30": {},
- "r3-link31": {},
- "r3-link32": {}
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link5": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link6": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link7": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link8": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link9": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link10": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link11": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link12": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link13": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link14": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link15": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link16": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link17": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link18": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link19": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link20": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link21": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link22": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link23": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link24": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link25": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link26": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link27": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link28": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link29": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link30": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link31": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link32": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
}
}
}
diff --git a/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json b/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json
index 9010b8c27..9eea9073c 100755
--- a/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json
+++ b/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json
@@ -574,6 +574,16 @@
"ipv6": "auto"
}
},
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ },
"bgp": {
"local_as": "100",
"address_family": {
@@ -630,38 +640,198 @@
"neighbor": {
"r2": {
"dest_link": {
- "r3-link1": {},
- "r3-link2": {},
- "r3-link3": {},
- "r3-link4": {},
- "r3-link5": {},
- "r3-link6": {},
- "r3-link7": {},
- "r3-link8": {},
- "r3-link9": {},
- "r3-link10": {},
- "r3-link11": {},
- "r3-link12": {},
- "r3-link13": {},
- "r3-link14": {},
- "r3-link15": {},
- "r3-link16": {},
- "r3-link17": {},
- "r3-link18": {},
- "r3-link19": {},
- "r3-link20": {},
- "r3-link21": {},
- "r3-link22": {},
- "r3-link23": {},
- "r3-link24": {},
- "r3-link25": {},
- "r3-link26": {},
- "r3-link27": {},
- "r3-link28": {},
- "r3-link29": {},
- "r3-link30": {},
- "r3-link31": {},
- "r3-link32": {}
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link5": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link6": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link7": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link8": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link9": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link10": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link11": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link12": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link13": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link14": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link15": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link16": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link17": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link18": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link19": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link20": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link21": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link22": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link23": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link24": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link25": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link26": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link27": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link28": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link29": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link30": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link31": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ },
+ "r3-link32": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
}
}
}
diff --git a/tests/topotests/bgp-route-map/bgp_route_map_topo1.json b/tests/topotests/bgp-route-map/bgp_route_map_topo1.json
new file mode 100644
index 000000000..e89263961
--- /dev/null
+++ b/tests/topotests/bgp-route-map/bgp_route_map_topo1.json
@@ -0,0 +1,187 @@
+{
+ "address_types": ["ipv4","ipv6"],
+ "ipv4base":"10.0.0.0",
+ "ipv4mask":30,
+ "ipv6base":"fd00::",
+ "ipv6mask":64,
+ "link_ip_start":{"ipv4":"10.0.0.0", "v4mask":30, "ipv6":"fd00::", "v6mask":64},
+ "lo_prefix":{"ipv4":"1.0.", "v4mask":32, "ipv6":"2001:DB8:F::", "v6mask":128},
+ "routers":{
+ "r1":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2":{"ipv4":"auto", "ipv6":"auto"},
+ "r3":{"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp":{
+ "local_as":"100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1":{"ipv4":"auto", "ipv6":"auto"},
+ "r3":{"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp":{
+ "local_as":"100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1":{"ipv4":"auto", "ipv6":"auto"},
+ "r2":{"ipv4":"auto", "ipv6":"auto"},
+ "r4":{"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp":{
+ "local_as":"100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3":{"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp":{
+ "local_as":"200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp-route-map/bgp_route_map_topo2.json b/tests/topotests/bgp-route-map/bgp_route_map_topo2.json
new file mode 100755
index 000000000..c22a4c3ea
--- /dev/null
+++ b/tests/topotests/bgp-route-map/bgp_route_map_topo2.json
@@ -0,0 +1,316 @@
+{
+ "address_types": ["ipv4", "ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:DB8:F::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ },
+ "redistribute": [{
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ },
+ "redistribute": [{
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ }
+ }
+ },
+
+ "static_routes": [{
+ "network": "10.0.20.1/32",
+ "no_of_ip": 2,
+ "next_hop": "10.0.0.2"
+ },
+ {
+ "network": "1::1/128",
+ "no_of_ip": 2,
+ "next_hop": "fd00::2"
+ }]
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r5": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r5": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r5": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp-route-map/test_route_map_topo1.py b/tests/topotests/bgp-route-map/test_route_map_topo1.py
new file mode 100755
index 000000000..86ec6c82d
--- /dev/null
+++ b/tests/topotests/bgp-route-map/test_route_map_topo1.py
@@ -0,0 +1,1361 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2019 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+#################################
+# TOPOLOGY
+#################################
+"""
+
+ +-------+
+ +------- | R2 |
+ | +-------+
+ | |
+ +-------+ |
+ | R1 | |
+ +-------+ |
+ | |
+ | +-------+ +-------+
+ +---------- | R3 |----------| R4 |
+ +-------+ +-------+
+
+"""
+
+#################################
+# TEST SUMMARY
+#################################
+"""
+Following tests are covered to test route-map functionality:
+TC_34:
+ Verify if route-maps is applied in both inbound and
+ outbound direction to same neighbor/interface.
+TC_36:
+ Test permit/deny statements operation in route-maps with a
+ permutation and combination of permit/deny in prefix-lists
+TC_35:
+ Test multiple sequence numbers in a single route-map for different
+ match/set clauses.
+TC_37:
+ Test add/remove route-maps with multiple set
+ clauses and without any match statement.(Set only)
+TC_38:
+ Test add/remove route-maps with multiple match
+ clauses and without any set statement.(Match only)
+"""
+
+import sys
+import json
+import time
+import pytest
+import inspect
+import os
+from time import sleep
+
+# 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, get_topogen
+from mininet.topo import Topo
+
+# Required to instantiate the topology builder class.
+from lib.topojson import *
+from lib.common_config import (
+ start_topology, write_test_header,
+ write_test_footer, verify_bgp_community,
+ verify_rib, delete_route_maps, create_bgp_community_lists,
+ interface_status, create_route_maps, create_prefix_lists,
+ verify_route_maps, check_address_types,
+ shutdown_bringup_interface, verify_prefix_lists, reset_config_on_routers)
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence, create_router_bgp,
+ clear_bgp_and_verify, verify_bgp_attributes)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+
+# Global variables
+bgp_convergence = False
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+# Reading the data from JSON File for topology and configuration creation
+jsonFile = "{}/bgp_route_map_topo1.json".format(CWD)
+try:
+ with open(jsonFile, 'r') as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+bgp_convergence = False
+NETWORK = {
+ "ipv4": ["11.0.20.1/32", "20.0.20.1/32"],
+ "ipv6": ["1::1/128", "2::1/128"]
+}
+MASK = {"ipv4": "32", "ipv6": "128"}
+NEXT_HOP = {
+ "ipv4": "10.0.0.2",
+ "ipv6": "fd00::2"
+}
+ADDR_TYPES = check_address_types()
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder
+
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function"""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global ADDR_TYPES
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Checking BGP convergence
+ global bgp_convergence
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Api call verify whether BGP is converged
+ bgp_convergence = verify_bgp_convergence(tgen, topo)
+ assert bgp_convergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(bgp_convergence))
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: {}".
+ format(time.asctime(time.localtime(time.time()))))
+ logger.info("=" * 40)
+
+
+def test_route_map_inbound_outbound_same_neighbor_p0(request):
+ """
+ TC_34:
+ Verify if route-maps is applied in both inbound and
+ outbound direction to same neighbor/interface.
+ """
+
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ for adt in ADDR_TYPES:
+
+ # Create Static routes
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[adt][0],
+ "no_of_ip": 9,
+ "next_hop": NEXT_HOP[adt],
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Api call to redistribute static routes
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "local_as": 100,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_dict_2 = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK[adt][1],
+ "no_of_ip": 9,
+ "next_hop": NEXT_HOP[adt],
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Api call to redistribute static routes
+ input_dict_5 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_dict_2 = {
+ "r3": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1_ipv4": [{
+ "seqid": 10,
+ "action": "permit",
+ "network": NETWORK["ipv4"][0]
+ }],
+ "pf_list_2_ipv4": [{
+ "seqid": 10,
+ "action": "permit",
+ "network": NETWORK["ipv4"][1]
+ }]
+ },
+ "ipv6": {
+ "pf_list_1_ipv6": [{
+ "seqid": 100,
+ "action": "permit",
+ "network": NETWORK["ipv6"][0]
+ }],
+ "pf_list_2_ipv6": [{
+ "seqid": 100,
+ "action": "permit",
+ "network": NETWORK["ipv6"][1]
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_6 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_tag_1_{}".format(addr_type): [{
+ "action": "deny",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_list_1_{}".format(addr_type)
+ }
+ }
+ }],
+ "rmap_match_tag_2_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_list_2_{}".format(addr_type)
+ }
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_7 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {"name":
+ "rmap_match_tag_1_ipv4",
+ "direction": "in"},
+ {"name":
+ "rmap_match_tag_1_ipv4",
+ "direction": "out"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {"name":
+ "rmap_match_tag_1_ipv6",
+ "direction": "in"},
+ {"name":
+ "rmap_match_tag_1_ipv6",
+ "direction": "out"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for adt in ADDR_TYPES:
+ # Verifying RIB routes
+ dut = "r3"
+ protocol = "bgp"
+ input_dict_2 = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK[adt][1]],
+ "no_of_ip": 9,
+ "next_hop": NEXT_HOP[adt]
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol)
+ assert result is not True, "Testcase {} : Failed \n"
+ "Expected behavior: routes are not present in rib \n"
+ "Error: {}".format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = "r4"
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK[adt][0]],
+ "no_of_ip": 9,
+ "next_hop": NEXT_HOP[adt]
+ }
+ ]
+ }
+ }
+ result = verify_rib(tgen, adt, dut, input_dict, protocol=protocol)
+ assert result is not True, "Testcase {} : Failed \n "
+ "Expected behavior: routes are not present in rib \n "
+ "Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+@pytest.mark.parametrize("prefix_action, rmap_action", [("permit", "permit"),
+ ("permit", "deny"), ("deny", "permit"),
+ ("deny", "deny")])
+def test_route_map_with_action_values_combination_of_prefix_action_p0(
+ request, prefix_action, rmap_action):
+ """
+ TC_36:
+ Test permit/deny statements operation in route-maps with a permutation and
+ combination of permit/deny in prefix-lists
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ for adt in ADDR_TYPES:
+ # Create Static routes
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[adt][0],
+ "no_of_ip": 9,
+ "next_hop": NEXT_HOP[adt]
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Api call to redistribute static routes
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "local_as": 100,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Permit in perfix list and route-map
+ input_dict_2 = {
+ "r3": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1_ipv4": [{
+ "seqid": 10,
+ "network": "any",
+ "action": prefix_action
+ }]
+ },
+ "ipv6": {
+ "pf_list_1_ipv6": [{
+ "seqid": 100,
+ "network": "any",
+ "action": prefix_action
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": rmap_action,
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_list_1_{}".format(addr_type)
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_7 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {"name":
+ "rmap_match_pf_1_ipv4",
+ "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {"name":
+ "rmap_match_pf_1_ipv6",
+ "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ dut = "r3"
+ protocol = "bgp"
+ input_dict_2 = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK[adt][0]],
+ "no_of_ip": 9,
+ "next_hop": NEXT_HOP[adt],
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol)
+ if "deny" in [prefix_action, rmap_action]:
+ assert result is not True, "Testcase {} : Failed \n Error: {}".\
+ format(tc_name, result)
+ else:
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+
+def test_route_map_multiple_seq_different_match_set_clause_p0(request):
+ """
+ TC_35:
+ Test multiple sequence numbers in a single route-map for different
+ match/set clauses.
+ """
+
+ tgen = get_topogen()
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ for adt in ADDR_TYPES:
+ # Create Static routes
+ input_dict = {
+ "r1": {
+ "static_routes": [{
+ "network": NETWORK[adt][0],
+ "no_of_ip": 1,
+ "next_hop": NEXT_HOP[adt]
+ }]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Api call to redistribute static routes
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ "r3": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1_ipv4": [{
+ "seqid": 10,
+ "network": "any",
+ "action": "permit"
+ }]
+ },
+ "ipv6": {
+ "pf_list_1_ipv6": [{
+ "seqid": 100,
+ "network": "any",
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_list_2_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "aspath": {
+ "as_num": 500
+ }
+ }
+ },
+ {
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_list_2_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150,
+ }
+ },
+ {
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 50
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for adt in ADDR_TYPES:
+ # Verifying RIB routes
+ dut = "r3"
+ protocol = "bgp"
+ input_dict = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_list1": [{
+ "set": {
+ "med": 50,
+ }
+ }],
+ }
+ }
+ }
+
+ static_routes = [NETWORK[adt][0]]
+
+ time.sleep(2)
+ result = verify_bgp_attributes(tgen, adt, dut, static_routes,
+ "rmap_match_pf_list1", input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ dut = "r4"
+ result = verify_bgp_attributes(tgen, adt, dut, static_routes,
+ "rmap_match_pf_list1", input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ logger.info("Testcase " + tc_name + " :Passed \n")
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_route_map_set_only_no_match_p0(request):
+ """
+ TC_37:
+ Test add/remove route-maps with multiple set
+ clauses and without any match statement.(Set only)
+ """
+
+ tgen = get_topogen()
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ for adt in ADDR_TYPES:
+ # Create Static routes
+ input_dict = {
+ "r1": {
+ "static_routes": [{
+ "network": NETWORK[adt][0],
+ "no_of_ip": 1,
+ "next_hop": NEXT_HOP[adt]
+ }]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Api call to redistribute static routes
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create route map
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1": [
+ {
+ "action": "permit",
+ "set": {
+ "med": 50,
+ "localpref": 150,
+ "weight": 4000
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name": "rmap_match_pf_1",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name": "rmap_match_pf_1",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name": "rmap_match_pf_1",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name": "rmap_match_pf_1",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ time.sleep(2)
+ for adt in ADDR_TYPES:
+ input_dict_4 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1": [
+ {
+ "action": "permit",
+ "set": {
+ "med": 50,
+ }
+ }
+ ]
+ }
+ }
+ }
+ # Verifying RIB routes
+ static_routes = [NETWORK[adt][0]]
+ result = verify_bgp_attributes(tgen, adt, "r3", static_routes,
+ "rmap_match_pf_1", input_dict_3)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ result = verify_bgp_attributes(tgen, adt, "r4", static_routes,
+ "rmap_match_pf_1", input_dict_4)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ logger.info("Testcase " + tc_name + " :Passed \n")
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_route_map_match_only_no_set_p0(request):
+ """
+ TC_38:
+ Test add/remove route-maps with multiple match
+ clauses and without any set statement.(Match only)
+ """
+
+ tgen = get_topogen()
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ for adt in ADDR_TYPES:
+ # Create Static routes
+ input_dict = {
+ "r1": {
+ "static_routes": [{
+ "network": NETWORK[adt][0],
+ "no_of_ip": 1,
+ "next_hop": NEXT_HOP[adt]
+ }]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Api call to redistribute static routes
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ "r1": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1_ipv4": [{
+ "seqid": 10,
+ "network": "any",
+ "action": "permit"
+ }]
+ },
+ "ipv6": {
+ "pf_list_1_ipv6": [{
+ "seqid": 100,
+ "network": "any",
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ "set": {
+ "med": 50,
+ "localpref": 150,
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create ip prefix list
+ input_dict_5 = {
+ "r3": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1_ipv4": [{
+ "seqid": 10,
+ "network": "any",
+ "action": "permit"
+ }]
+ },
+ "ipv6": {
+ "pf_list_1_ipv6": [{
+ "seqid": 100,
+ "network": "any",
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_6 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_2_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_list_1_{}".format(addr_type)
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_7 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv4",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv4",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv6",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv6",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for adt in ADDR_TYPES:
+ # Verifying RIB routes
+ static_routes = [NETWORK[adt][0]]
+ result = verify_bgp_attributes(tgen, adt, "r3", static_routes,
+ "rmap_match_pf_1", input_dict_3)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
+
+
diff --git a/tests/topotests/bgp-route-map/test_route_map_topo2.py b/tests/topotests/bgp-route-map/test_route_map_topo2.py
new file mode 100755
index 000000000..7009fc97c
--- /dev/null
+++ b/tests/topotests/bgp-route-map/test_route_map_topo2.py
@@ -0,0 +1,3916 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2019 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""Following tests are covered to test route-map functionality.
+TC_57:
+ Create route map to match prefix-list and permit inbound
+ and outbound prefixes and set criteria on match
+TC_52:
+ Test modify set/match clauses in a route-map to see
+ if it takes immediate effect.
+TC_61:
+ Delete the route maps.
+TC_50_1:
+ Test modify/remove prefix-lists referenced by a
+ route-map for match statement.
+TC_50_1:
+ Remove prefix-list referencec by route-map match cluase
+ and verifying it reflecting as intended
+TC_51:
+ Add and remove community-list referencec by route-map match cluase
+ and verifying it reflecting as intended
+TC_45:
+ Test multiple match statements as part of a route-map's single
+ sequence number. (Logical OR-ed of multiple match statements)
+TC_44:
+ Test multiple match statements as part of a route-map's single
+ sequence number. (Logical AND of multiple match statements)
+TC_41:
+ Test add/remove route-maps to specific neighbor and see if
+ it takes effect as intended
+TC_56:
+ Test clear BGP sessions and interface flaps to see if
+ route-map properties are intact.
+TC_46:
+ Verify if a blank sequence number can be create(without any
+ match/set clause) and check if it allows all the traffic/prefixes
+TC_48:
+ Create route map setting local preference and weight to eBGP peeer
+ and metric to ibgp peer and verifying it should not get advertised
+TC_43:
+ Test multiple set statements as part of a route-map's
+ single sequence number.
+TC_54:
+ Verify route-maps continue clause functionality.
+TC_55:
+ Verify route-maps goto clause functionality.
+TC_53:
+ Verify route-maps call clause functionality.
+TC_58:
+ Create route map deny inbound and outbound prefixes on
+ match prefix list and set criteria on match
+TC_59:
+ Create route map to permit inbound prefixes with filter
+ match tag and set criteria
+TC_60
+ Create route map to deny outbound prefixes with filter match tag,
+ and set criteria
+"""
+
+#################################
+# TOPOLOGY
+#################################
+"""
+
+ +-------+
+ +--------- | R2 |
+ | +-------+
+ |iBGP |
+ +-------+ |
+ | R1 | |iBGP
+ +-------+ |
+ | |
+ | iBGP +-------+ eBGP +-------+
+ +---------- | R3 |----------| R4 |
+ +-------+ +-------+
+ |
+ |eBGP
+ |
+ +-------+
+ | R5 |
+ +-------+
+
+
+"""
+
+import sys
+import json
+import time
+import pytest
+import inspect
+import os
+from time import sleep
+
+# 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, get_topogen
+from mininet.topo import Topo
+
+# Required to instantiate the topology builder class.
+from lib.common_config import (
+ start_topology, write_test_header,
+ write_test_footer, create_static_routes,
+ verify_rib, delete_route_maps, create_bgp_community_lists,
+ interface_status, create_route_maps, create_prefix_lists,
+ verify_route_maps, check_address_types, verify_bgp_community,
+ shutdown_bringup_interface, verify_prefix_lists, reset_config_on_routers)
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence, create_router_bgp,
+ clear_bgp_and_verify, verify_bgp_attributes)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology and configuration creation
+jsonFile = "{}/bgp_route_map_topo2.json".format(CWD)
+
+try:
+ with open(jsonFile, 'r') as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+# Global variables
+bgp_convergence = False
+NETWORK = {
+ "ipv4": ["11.0.20.1/32", "11.0.20.2/32"],
+ "ipv6": ["2::1/128", "2::2/128"]
+}
+
+bgp_convergence = False
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+
+
+class BGPRmapTopo(Topo):
+ """BGPRmapTopo.
+
+ BGPRmap topology 1
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology and configuration from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """setup_module.
+
+ Set up the pytest environment
+ * `mod`: module name
+ """
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("="*40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(BGPRmapTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Checking BGP convergence
+ global bgp_convergence
+ global ADDR_TYPES
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Api call verify whether BGP is converged
+ bgp_convergence = verify_bgp_convergence(tgen, topo)
+ assert bgp_convergence is True, ('setup_module :Failed \n Error:'
+ ' {}'.format(bgp_convergence))
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """teardown_module.
+
+ Teardown the pytest environment.
+ * `mod`: module name
+ """
+ logger.info("Running teardown_module to delete topology")
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: {}".format(
+ time.asctime(time.localtime(time.time()))))
+ logger.info("="*40)
+
+
+#####################################################
+# Tests starting
+#####################################################
+
+
+def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0():
+ """
+ TC: 57
+ Create route map to match prefix-list and permit inbound
+ and outbound prefixes and set criteria on match
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit',
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit',
+ }]
+ }
+ }
+ }
+ }
+
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+ for addr_type in ADDR_TYPES:
+ # Create route map
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_" + addr_type
+ }
+ },
+ "set": {
+ "localpref": 150,
+ "weight": 100
+ }
+ },
+ ],
+ "rmap_match_pf_2_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_" + addr_type
+ }
+ },
+ "set": {
+ "med": 50
+ }
+ },
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+
+ # dual stack changes
+ for addr_type in ADDR_TYPES:
+ result4 = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result4)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ # dual stack changes
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result4 = verify_bgp_attributes(tgen, addr_type, dut, routes[
+ addr_type],rmap_name, input_dict_3)
+ assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result4)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ # dual stack changes
+ for addr_type in ADDR_TYPES:
+ result4 = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result4)
+
+ # Verifying BGP set attributes
+ dut = 'r4'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ # dual stack changes
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_2_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_modify_set_match_clauses_in_rmap_p0():
+ """
+ TC_52:
+ Test modify set/match clauses in a route-map to see
+ if it takes immediate effect.
+ """
+
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit',
+ }],
+ 'pf_list_2_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit',
+ }],
+ 'pf_list_2_ipv6': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150,
+ }
+ }],
+ "rmap_match_pf_2_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 50
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ # dual stack changes
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result4 = verify_bgp_attributes(tgen, addr_type, dut, routes[
+ addr_type],rmap_name, input_dict_3)
+ assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result4)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ # dual stack changes
+ for addr_type in ADDR_TYPES:
+ result4 = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result4)
+
+ # Verifying BGP set attributes
+ dut = 'r4'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_2_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[
+ addr_type],rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Modify set/match clause of in-used route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 1000,
+ }
+ }],
+ "rmap_match_pf_2_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 2000
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r4'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_2_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_delete_route_maps_p1():
+ """
+ TC_61:
+ Delete the route maps.
+ """
+
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_tag_1_{}".format(addr_type): [{
+ "action": "deny",
+ "match": {
+ addr_type: {
+ "tag": "4001"
+ }
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Delete route maps
+ for addr_type in ADDR_TYPES:
+ input_dict = {
+ 'r3': {
+ 'route_maps': ['rmap_match_tag_1_{}'.format(addr_type)]
+ }
+ }
+ result = delete_route_maps(tgen, input_dict)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_route_maps(tgen, input_dict)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_modify_prefix_list_referenced_by_rmap_p0():
+ """
+ TC_50_1:
+ Test modify/remove prefix-lists referenced by a
+ route-map for match statement.
+ """
+
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit',
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit',
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150,
+ "weight": 100
+ }
+ }],
+ "rmap_match_pf_2_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 50
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r4'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_2_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Modify ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'deny'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'deny'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ sleep(5)
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behaviour: routes are not present \n '
+ 'Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behaviour: routes are not present \n '
+ 'Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_remove_prefix_list_referenced_by_rmap_p0():
+ """
+ TC_50_1:
+ Remove prefix-list referencec by route-map match cluase
+ and verifying it reflecting as intended
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150,
+ }
+ }],
+ "rmap_match_pf_2_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 50
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r4'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_2_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Remove/Delete prefix list
+ input_dict_3 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit',
+ 'delete': True
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit',
+ 'delete': True
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_prefix_lists(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Api call to clear bgp, so config changes would be reflected
+ dut = 'r3'
+ result = clear_bgp_and_verify(tgen, topo, dut)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behaviour: routes are not present \n '
+ 'Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behaviour: routes are not present \n '
+ 'Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_add_and_remove_community_list_referenced_by_rmap_p0():
+ """
+ TC_51:
+ Add and remove community-list referencec by route-map match cluase
+ and verifying it reflecting as intended
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Creating configuration from JSON
+ # build_config_from_json(tgen, topo)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_5 = {
+ "r1": {
+ "route_maps": {
+ "rm_r1_out_{}".format(addr_type): [{
+ "action": "permit",
+ "set": {
+ "large_community": {"num": "1:1:1 1:2:3 2:1:1 2:2:2"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_5)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_6 = {
+ 'r1': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name": "rm_r1_out_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name": "rm_r1_out_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ # Create standard large commumity-list
+ input_dict_1 = {
+ "r3": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "rmap_lcomm_{}".format(addr_type),
+ "value": "1:1:1 1:2:3 2:1:1 2:2:2",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_1)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ # Create route map
+ input_dict_2 = {
+ "r3": {
+ "route_maps": {
+ "rm_r3_in_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type : {
+ "large-community-list": {"id": "rmap_lcomm_"+
+ addr_type}
+ }
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_3 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name": "rm_r3_in_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name": "rm_r3_in_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_3)
+
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ sleep(5)
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verify large-community-list
+ dut = 'r3'
+ networks = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ input_dict_4 = {
+ 'largeCommunity': '1:1:1 1:2:3 2:1:1 2:2:2'
+ }
+ for addr_type in ADDR_TYPES:
+ result = verify_bgp_community(tgen, addr_type, dut, networks[
+ addr_type],input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_multiple_match_statement_in_route_map_logical_ORed_p0():
+ """
+ TC_45:
+ Test multiple match statements as part of a route-map's single
+ sequence number. (Logical OR-ed of multiple match statements)
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Api call to advertise networks
+ input_dict_nw1 = {
+ 'r1': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": '10.0.30.1/32'}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": '1::1/128'}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_nw1)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Api call to advertise networks
+ input_dict_nw2 = {
+ 'r1': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": '20.0.30.1/32'}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": '2::1/128'}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_nw2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_2_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_2_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ input_dict_3_addr_type ={}
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150
+ }
+ }]
+ }
+ }
+ }
+ input_dict_3_addr_type[addr_type] = input_dict_3
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 200
+ }
+ }]
+ }
+ }
+ }
+ input_dict_3_addr_type[addr_type] = input_dict_3
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_6 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.30.1/32"],
+ "ipv6": ["1::1/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3_addr_type[addr_type])
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ routes = {
+ "ipv4": ["20.0.30.1/32"],
+ "ipv6": ["2::1/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_multiple_match_statement_in_route_map_logical_ANDed():
+ """
+ TC_44:
+ Test multiple match statements as part of a route-map's single
+ sequence number. (Logical AND of multiple match statements)
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_5 = {
+ "r1": {
+ "route_maps": {
+ "rm_r1_out_{}".format(addr_type): [{
+ "action": "permit",
+ "set": {
+ "large_community": {
+ "num": "1:1:1 1:2:3 2:1:1 2:2:2"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_5)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ for addr_type in ADDR_TYPES:
+ input_dict_6 = {
+ 'r1': {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name":
+ "rm_r1_out_{}".format(addr_type),
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ # Create standard large commumity-list
+ input_dict_1 = {
+ "r3": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "rmap_lcomm_{}".format(addr_type),
+ "value": "1:1:1 1:2:3 2:1:1 2:2:2",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_1)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150,
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ # Create route map
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type : {
+ "large_community_list": {"id": "rmap_lcomm_"+
+ addr_type}
+ }
+ },
+ "set": {
+ "localpref": 150,
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+ # Configure neighbor for route map
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_{}".format(addr_type),
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+ # sleep(10)
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_add_remove_rmap_to_specific_neighbor_p0():
+ """
+ TC_41:
+ Test add/remove route-maps to specific neighbor and see if
+ it takes effect as intended
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'deny'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'deny'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150,
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is not True, 'Testcase {} : \n'
+ 'Expected Behavior: Routes are not present in RIB \n'
+ ' Error: {}'.format(
+ tc_name, result)
+
+ # Remove applied rmap from neighbor
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in',
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in',
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0():
+ """
+ TC_56:
+ Test clear BGP sessions and interface flaps to see if
+ route-map properties are intact.
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150,
+ "weight": 100
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # clear bgp, so config changes would be reflected
+ dut = 'r3'
+ result = clear_bgp_and_verify(tgen, topo, dut)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Flap interface to see if route-map properties are intact
+ # Shutdown interface
+ dut = "r3"
+ intf = "r3-r1-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ sleep(5)
+
+ # Bringup interface
+ dut = "r3"
+ intf = "r3-r1-eth0"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ # Verify BGP convergence once interface is up
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, (
+ 'setup_module :Failed \n Error:' ' {}'.format(result))
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_rmap_without_match_and_set_clause_p0():
+ """
+ TC_46:
+ Verify if a blank sequence number can be create(without any
+ match/set clause) and check if it allows all the traffic/prefixes
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_no_match_set_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '5'
+ }],
+ "rmap_no_match_set_2_{}".format(addr_type): [{
+ "action": "deny",
+ 'seq_id': '5'
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_no_match_set_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_no_match_set_2_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_no_match_set_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_no_match_set_2_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behaviour: routes are not present \n '
+ 'Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0():
+ """
+ TC_48:
+ Create route map setting local preference and weight to eBGP peeer
+ and metric to ibgp peer and verifying it should not get advertised
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ input_dict_3_addr_type ={}
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(
+ addr_type)
+ }
+ },
+ "set": {
+ "med": 50
+ }
+ }],
+ "rmap_match_pf_2_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(
+ addr_type)
+ }},
+ "set": {
+ "localpref": 150
+ }
+ }],
+ "rmap_match_pf_3_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(
+ addr_type)
+ }},
+ "set": {
+ "weight": 1000
+ }
+ }]
+ }
+ }
+ }
+ input_dict_3_addr_type[addr_type] = input_dict_3
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_3_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_3_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ rmap_name = "rmap_match_pf_1"
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[
+ addr_type],rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r4'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ rmap_name = "rmap_match_pf_2"
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_2_{}".format(addr_type)
+
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3_addr_type[addr_type])
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behaviour: Attributes are not set \n'
+ 'Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r5'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+ # Verifying BGP set attributes
+ dut = 'r5'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+
+ rmap_name = "rmap_match_pf_3"
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_3_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3_addr_type[addr_type])
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behaviour: Attributes are not set \n'
+ 'Error: {}'.format(
+ tc_name, result)
+
+ logger.info("Expected behaviour: {}".format(result))
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_multiple_set_on_single_sequence_in_rmap_p0():
+ """
+ TC_43:
+ Test multiple set statements as part of a route-map's
+ single sequence number.
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150,
+ "weight": 100,
+ "med": 50
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+
+ rmap_name = "rmap_match_pf_1"
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_route_maps_with_continue_clause_p0():
+ """
+ TC_54:
+ Verify route-maps continue clause functionality.
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '10',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150
+ },
+ "continue": "30"
+ },
+ {
+ "action": "permit",
+ 'seq_id': '20',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 200
+ }
+ },
+ {
+ "action": "permit",
+ 'seq_id': '30',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 100
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ rmap_name = "rmap_match_pf_1"
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ seq_id = {
+ "ipv4": ["10", "30"],
+ "ipv6": ["10", "30"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[
+ addr_type],rmap_name, input_dict_3, seq_id[addr_type])
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_route_maps_with_goto_clause_p0():
+ """
+ TC_55:
+ Verify route-maps goto clause functionality.
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ 'seq_id': '10',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "goto": "30"
+ },
+ {
+ "action": "permit",
+ 'seq_id': '20',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 100
+ }
+ },
+ {
+ "action": "permit",
+ 'seq_id': '30',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 200
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ rmap_name = "rmap_match_pf_1"
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ seq_id = {
+ "ipv4": ["10", "30"],
+ "ipv6": ["10", "30"]
+ }
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[
+ addr_type],rmap_name, input_dict_3, seq_id[addr_type])
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_route_maps_with_call_clause_p0():
+ """
+ TC_53:
+ Verify route-maps call clause functionality.
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150
+ },
+ "call": "rmap_match_pf_2_{}".format(addr_type)
+ }],
+ "rmap_match_pf_2_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 200
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv6",
+ "direction": 'in'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying BGP set attributes
+ dut = 'r3'
+ routes = {
+ "ipv4": ["10.0.20.1/32", "10.0.20.2/32"],
+ "ipv6": ["1::1/128", "1::2/128"]
+ }
+ rmap_name = "rmap_match_pf_1"
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_1_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ rmap_name = "rmap_match_pf_2"
+ for addr_type in ADDR_TYPES:
+ rmap_name = "rmap_match_pf_2_{}".format(addr_type)
+ result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type],
+ rmap_name, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0():
+ """
+ TC_58:
+ Create route map deny inbound and outbound prefixes on
+ match prefix list and set criteria on match
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ # Create ip prefix list
+ input_dict_2 = {
+ 'r3': {
+ 'prefix_lists': {
+ 'ipv4': {
+ 'pf_list_1_ipv4': [{
+ 'seqid': 10,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ },
+ 'ipv6': {
+ 'pf_list_1_ipv6': [{
+ 'seqid': 100,
+ 'network': 'any',
+ 'action': 'permit'
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_{}".format(addr_type): [{
+ "action": "deny",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 150,
+ }
+ }],
+ "rmap_match_pf_2_{}".format(addr_type): [{
+ "action": "deny",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "med": 50
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r3': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_1_ipv4",
+ "direction": 'in'
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [{
+ "name":
+ "rmap_match_pf_2_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+ input_dict = topo["routers"]
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behaviour: routes are not present \n '
+ 'Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r4'
+ protocol = 'bgp'
+ for addr_type in ADDR_TYPES:
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behaviour: routes are not present \n '
+ 'Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_create_rmap_to_match_tag_permit_inbound_prefixes_p0():
+ """
+ TC_59:
+ Create route map to permit inbound prefixes with filter
+ match tag and set criteria
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ for addr_type in ADDR_TYPES:
+ # Create Static routes
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": "Null0",
+ "tag": 4001
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Api call to redistribute static routes
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "local_as": 100,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create route map
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "rmap_match_tag_1_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "tag": "4001"
+ }
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r1': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name":
+ "rmap_match_tag_1_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name":
+ "rmap_match_tag_1_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+
+ for addr_type in ADDR_TYPES:
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": "Null0",
+ "tag": 4001
+ }
+ ]
+ }
+ }
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+
+def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0():
+ """
+ TC_60
+ Create route map to deny outbound prefixes with filter match tag,
+ and set criteria
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip('skipped because of BGP Convergence failure')
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ for addr_type in ADDR_TYPES:
+ # Create Static routes
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": "Null0",
+ "tag": 4001
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Api call to redistribute static routes
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "local_as": 100,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Create route map
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "rmap_match_tag_1_{}".format(addr_type): [{
+ "action": "deny",
+ "match": {
+ addr_type: {
+ "tag": "4001"
+ }
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_4 = {
+ 'r1': {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name":
+ "rmap_match_tag_1_ipv4",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name":
+ "rmap_match_tag_1_ipv6",
+ "direction": 'out'
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ # Verifying RIB routes
+ dut = 'r3'
+ protocol = 'bgp'
+
+ for addr_type in ADDR_TYPES:
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": "Null0",
+ "tag": 4001
+ }
+ ]
+ }
+ }
+ result = verify_rib(tgen, addr_type, dut, input_dict,
+ protocol=protocol)
+ assert result is not True, 'Testcase {} : Failed \n'
+ 'Expected behavior: routes are denied \n Error: {}'.format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+ # Uncomment next line for debugging
+ # tgen.mininet_cli()
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json b/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json
index d0378b564..acf5c8b27 100644
--- a/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json
+++ b/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json
@@ -10,7 +10,6 @@
{
"interfaceName": "r1-eth0",
"interfaceIndex": 2,
- "flags": 1,
"active": true,
"afi": "ipv6"
}
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
index 149a420a3..547a5949a 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
@@ -11,16 +11,17 @@ for rtr in l3mdev_rtrs:
rtrs = ['r1', 'r3', 'r4']
for rtr in rtrs:
- luCommand(rtr, 'ip link show type vrf {}-cust1'.format(rtr),'cust1: .*UP,LOWER_UP','pass','VRF cust1 up')
- luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'r..eth4: .*UP,LOWER_UP.* 192.168','pass','VRF cust1 IP config')
+ luCommand(rtr, 'ip link show type vrf {}-cust1'.format(rtr),'cust1: .*UP','pass','VRF cust1 intf up')
+ luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'r..eth4.*UP','pass','VRF cust1 IP intf up')
+ luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'192.168','pass','VRF cust1 IP config')
luCommand(rtr, 'ip route show vrf {}-cust1'.format(rtr),'192.168...0/24 dev r.-eth','pass','VRF cust1 interface route')
-luCommand('r4', 'ip link show type vrf r4-cust2','cust2: .*UP,LOWER_UP','pass','VRF cust2 up')
-luCommand('r4', 'ip add show vrf r4-cust2','r..eth5.*UP,LOWER_UP.* 192.168','pass','VRF cust1 IP config')
+luCommand('r4', 'ip link show type vrf r4-cust2','cust2: .*UP','pass','VRF cust2 up')
+luCommand('r4', 'ip add show vrf r4-cust2','r..eth5.*UP.* 192.168','pass','VRF cust1 IP config')
luCommand(rtr, 'ip route show vrf r4-cust2'.format(rtr),'192.168...0/24 dev r.-eth','pass','VRF cust2 interface route')
rtrs = ['ce1', 'ce2', 'ce3']
for rtr in rtrs:
luCommand(rtr, 'ip route show','192.168...0/24 dev ce.-eth0','pass','CE interface route')
luCommand(rtr,'ping 192.168.1.1 -c 1',' 0. packet loss','wait','CE->PE ping')
-luCommand('ce4', 'ip link show type vrf ce4-cust2','cust2: .*UP,LOWER_UP','pass','VRF cust2 up')
+luCommand('ce4', 'ip link show type vrf ce4-cust2','cust2: .*UP','pass','VRF cust2 up')
luCommand('ce4', 'ip route show vrf ce4-cust2','192.168...0/24 dev ce.-eth0','pass','CE interface route')
luCommand('ce4','ping 192.168.2.1 -c 1 -I ce4-cust2',' 0. packet loss','wait','CE4->PE4 ping')
diff --git a/tests/topotests/bgp_large_community/__init__.py b/tests/topotests/bgp_large_community/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_large_community/__init__.py
diff --git a/tests/topotests/bgp_large_community/bgp_large_community_topo_1.json b/tests/topotests/bgp_large_community/bgp_large_community_topo_1.json
new file mode 100644
index 000000000..902c01bcb
--- /dev/null
+++ b/tests/topotests/bgp_large_community/bgp_large_community_topo_1.json
@@ -0,0 +1,262 @@
+{
+ "ipv4base": "192.168.1.0",
+ "ipv4mask": 24,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "192.168.1.0",
+ "v4mask": 24,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:DB8:F::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "1000000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r5-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "4000000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r4-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r4-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r5": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r4-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "6000000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r5-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r5-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_large_community/bgp_large_community_topo_2.json b/tests/topotests/bgp_large_community/bgp_large_community_topo_2.json
new file mode 100644
index 000000000..6f1ca90af
--- /dev/null
+++ b/tests/topotests/bgp_large_community/bgp_large_community_topo_2.json
@@ -0,0 +1,344 @@
+{
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:DB8:F::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "1000000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "1000000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "4000000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {}
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {}
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r5": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "5000000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r5": {}
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r5": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r5": {}
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r5": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r6": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "6000000",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r6": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r6": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r6": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r6": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
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
new file mode 100755
index 000000000..83ec1e784
--- /dev/null
+++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
@@ -0,0 +1,1281 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2019 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""
+Following tests are covered to test large-community/community functionality:
+1. Verify if large community attribute can be configured only in correct
+ canonical format.
+2. Verify that the community attribute value, which we have advertised are
+ received in correct format and values, at the receiving end.
+3. Verify BGP Large Community attribute"s transitive property attribute.
+4. Verify that BGP Large Communities attribute are malformed, if the length of
+ the BGP Large Communities Attribute value, expressed in octets,
+ is not a non-zero multiple of 12.
+5. Verify if overriding large community values works fine.
+6. Verify that large community values" aggregation works fine.
+7. Standard community also work fine in conjunction with large-community.
+8. Matching prefixes based on attributes other than prefix list and make use
+ of set clause (IPV6).
+9. Matching prefixes based on attributes other than prefix list and make use
+ of set clause (IPV4).
+10. Verify community and large-community list operations in route-map with all
+ clause (exact, all, any, regex) works.
+11. Verify that any value in BGP Large communities for boundary values.
+12. Clear BGP neighbor-ship and check if large community and community
+ attributes are getting re-populated.
+
+"""
+
+import pytest
+import time
+from os import path as os_path
+import sys
+from json import load as json_load
+
+# Required to instantiate the topology builder class.
+from lib.topogen import Topogen, get_topogen
+from mininet.topo import Topo
+
+from lib.common_config import (
+ start_topology, write_test_header,
+ write_test_footer, reset_config_on_routers,
+ create_route_maps, create_bgp_community_lists,
+ create_prefix_lists, verify_bgp_community, step,
+ check_address_types
+)
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence, create_router_bgp,
+ clear_bgp_and_verify
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Save the Current Working Directory to find configuration files.
+CWD = os_path.dirname(os_path.realpath(__file__))
+sys.path.append(os_path.join(CWD, "../"))
+sys.path.append(os_path.join(CWD, "../lib/"))
+
+# Reading the data from JSON File for topology and configuration creation
+jsonFile = "{}/bgp_large_community_topo_1.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json_load(topoJson)
+except IOError:
+ logger.info("Could not read file:", jsonFile)
+
+# Global variables
+bgp_convergence = False
+NETWORK = {
+ "ipv4": ["200.50.2.0", "200.50.2.1", "200.50.2.0"],
+ "ipv6": ["1::1", "1::2", "1::0"]
+}
+MASK = {"ipv4": "32", "ipv6": "128"}
+NET_MASK = {"ipv4": "24", "ipv6": "120"}
+IPV4_NET = ["200.50.2.0"]
+IPV6_NET = ["1::0"]
+CONFIG_ROUTER_R1 = False
+CONFIG_ROUTER_R2 = False
+CONFIG_ROUTER_ADDITIVE = False
+ADDR_TYPES = []
+LARGE_COMM = {
+ "r1": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1",
+ "r2": "2:1:1 2:2:1 2:3:1 2:4:1 2:5:1",
+ "mal_1": "1:1 1:2 1:3 1:4 1:5",
+ "pf_list_1": "0:0:1 0:0:10 0:0:100",
+ "pf_list_2": "0:0:2 0:0:20 0:0:200",
+ "agg_1": "0:0:1 0:0:2 0:0:10 0:0:20 0:0:100 0:0:200 2:1:1 "
+ "2:2:1 2:3:1 2:4:1 2:5:1",
+ "agg_2": "0:0:2 0:0:20 0:0:200 2:1:1 "
+ "2:2:1 2:3:1 2:4:1 2:5:1"
+}
+STANDARD_COMM = {
+ "r1": "1:1 1:2 1:3 1:4 1:5",
+ "r2": "2:1 2:2 2:3 2:4 2:5",
+ "mal_1": "1 2 3 4 5",
+ "pf_list_1": "0:1 0:10 0:100",
+ "pf_list_2": "0:2 0:20 0:200",
+ "agg_1": "0:1 0:2 0:10 0:20 0:100 0:200 2:1 2:2 2:3 2:4 2:5",
+ "agg_2": "0:2 0:20 0:200 2:1 2:2 2:3 2:4 2:5"
+}
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder
+
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function"""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global ADDR_TYPES
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Checking BGP convergence
+ global bgp_convergence
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ ##tgen.mininet_cli()
+ # Api call verify whether BGP is converged
+ bgp_convergence = verify_bgp_convergence(tgen, topo)
+ assert bgp_convergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(bgp_convergence))
+
+ ADDR_TYPES = check_address_types()
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: {}".
+ format(time.asctime(time.localtime(time.time()))))
+ logger.info("=" * 40)
+
+
+def config_router_r1(tgen, topo, tc_name):
+ global CONFIG_ROUTER_R1
+
+ input_dict_1 = {
+ "r1": {
+ "route_maps": {
+ "LC1": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": LARGE_COMM["r1"]
+ },
+ "community": {
+ "num": STANDARD_COMM["r1"]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+
+ step("Configuring LC1 on r1")
+ result = create_route_maps(tgen, input_dict_1)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_2 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "%s/%s" % (
+ NETWORK["ipv4"][0], MASK["ipv4"]),
+ "no_of_network": 4
+ }
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "LC1",
+ "direction": "out"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "LC1",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "%s/%s" % (
+ NETWORK["ipv6"][0], MASK["ipv6"]),
+ "no_of_network": 4
+ }
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "LC1",
+ "direction": "out"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "LC1",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ step("Applying LC1 on r1 neighbors and advertising networks")
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ CONFIG_ROUTER_R1 = True
+
+
+def config_router_r2(tgen, topo, tc_name):
+ global CONFIG_ROUTER_R2
+
+ input_dict = {
+ "r2": {
+ "route_maps": {
+ "LC2": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": LARGE_COMM["r2"]
+ },
+ "community": {
+ "num": STANDARD_COMM["r2"]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+
+ step("Configuring route-maps LC2 on r2")
+ result = create_route_maps(tgen, input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_1 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [{
+ "name": "LC2",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [{
+ "name": "LC2",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ step("Applying LC2 on r2 neighbors in out direction")
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ CONFIG_ROUTER_R2 = True
+
+
+def config_router_additive(tgen, topo, tc_name):
+ global CONFIG_ROUTER_ADDITIVE
+
+ input_dict = {
+ "r2": {
+ "route_maps": {
+ "LC2": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": LARGE_COMM["r2"],
+ "action": "additive"
+ },
+ "community": {
+ "num": STANDARD_COMM["r2"],
+ "action": "additive"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+
+ step("Configuring LC2 with community attributes as additive")
+ result = create_route_maps(tgen, input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ # tgen.mininet_cli()
+ CONFIG_ROUTER_ADDITIVE = True
+
+
+def config_for_as_path(tgen, topo, tc_name):
+ config_router_r1(tgen, topo, tc_name)
+
+ config_router_r2(tgen, topo, tc_name)
+
+ # Create ipv6 prefix list
+ input_dict_1 = {
+ "r1": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1": [
+ {
+ "seqid": "10",
+ "network": "%s/%s" % (NETWORK["ipv4"][0],
+ MASK["ipv4"]),
+ "action": "permit"
+ }
+ ],
+ "pf_list_2": [
+ {
+ "seqid": "10",
+ "network": "%s/%s" % (NETWORK["ipv4"][1],
+ MASK["ipv4"]),
+ "action": "permit"
+ }
+ ]
+ },
+ "ipv6": {
+ "pf_list_3": [
+ {
+ "seqid": "10",
+ "network": "%s/%s" % (NETWORK["ipv6"][0],
+ MASK["ipv6"]),
+ "action": "permit"
+ }
+ ],
+ "pf_list_4": [
+ {
+ "seqid": "10",
+ "network": "%s/%s" % (NETWORK["ipv6"][1],
+ MASK["ipv6"]),
+ "action": "permit"
+ }
+ ]
+ }
+
+ }
+ }
+ }
+
+ step("Configuring prefix-lists on r1 to filter networks")
+ result = create_prefix_lists(tgen, input_dict_1)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_2 = {
+ "r1": {
+ "route_maps": {
+ "LC1": [
+ {
+ "action": "permit",
+ "seq_id": 10,
+ "match": {
+ "ipv4": {
+ "prefix_lists": "pf_list_1"
+ }
+ },
+ "set": {
+ "large_community": {
+ "num": LARGE_COMM["pf_list_1"]
+ },
+ "community": {
+ "num": STANDARD_COMM["pf_list_1"]
+ }
+ }
+ },
+ {
+ "action": "permit",
+ "seq_id": 20,
+ "match": {
+ "ipv6": {
+ "prefix_lists": "pf_list_3"
+ }
+ },
+ "set": {
+ "large_community": {
+ "num": LARGE_COMM["pf_list_1"]
+ },
+ "community": {
+ "num": STANDARD_COMM["pf_list_1"]
+ }
+ }
+ },
+ {
+ "action": "permit",
+ "seq_id": 30,
+ "match": {
+ "ipv4": {
+ "prefix_lists": "pf_list_2"
+ }
+ },
+ "set": {
+ "large_community": {
+ "num": LARGE_COMM["pf_list_2"]
+ },
+ "community": {
+ "num": STANDARD_COMM["pf_list_2"]
+ }
+ }
+ },
+ {
+ "action": "permit",
+ "seq_id": 40,
+ "match": {
+ "ipv6": {
+ "prefix_lists": "pf_list_4"
+ }
+ },
+ "set": {
+ "large_community": {
+ "num": LARGE_COMM["pf_list_2"]
+ },
+ "community": {
+ "num": STANDARD_COMM["pf_list_2"]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+
+ step("Applying prefix-lists match in route-map LC1 on r1. Setting"
+ " community attritbute for filtered networks")
+ result = create_route_maps(tgen, input_dict_2)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ config_router_additive(tgen, topo, tc_name)
+
+ input_dict_3 = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": LARGE_COMM["pf_list_1"],
+ "large": True
+ },
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": STANDARD_COMM["pf_list_1"],
+ }
+ ]
+ }
+ }
+
+ step("Configuring bgp community lists on r4")
+ result = create_bgp_community_lists(tgen, input_dict_3)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_4 = {
+ "r4": {
+ "route_maps": {
+ "LC4": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {
+ "large_community_list": {"id": "ANY"},
+ "community_list": {"id": "ANY"}
+ },
+ "set": {
+ "aspath": {
+ "as_num": "4000000",
+ "as_action": "prepend"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+
+ step("Applying community list on route-map on r4")
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_5 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r5": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "LC4",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r5": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "LC4",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ step("Applying route-map LC4 out from r4 to r5 ")
+ result = create_router_bgp(tgen, topo, input_dict_5)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+
+#####################################################
+#
+# Test cases
+#
+#####################################################
+def test_large_community_set(request):
+ """
+ Verify if large community attribute can be configured only in correct
+ canonical format.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # API call to modify router id
+ # input_dict dictionary to be provided to configure route_map
+ input_dict = {
+ "r1": {
+ "route_maps": {
+ "LC1": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {"num": LARGE_COMM["r1"]},
+ "community": {"num": STANDARD_COMM["r1"]}
+ }
+ }
+ ]
+ }
+ }
+ }
+
+ step("Trying to set bgp communities")
+ result = create_route_maps(tgen, input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_advertise(request):
+ """
+ Verify that the community attribute value, which we have advertised are
+ received in correct format and values, at the receiving end.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ config_router_r1(tgen, topo, tc_name)
+
+ input_dict = {
+ "largeCommunity": LARGE_COMM["r1"],
+ "community": STANDARD_COMM["r1"],
+ }
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, "r2", [NETWORK[adt][0]],
+ input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_bgp_community(tgen, adt, "r3", [NETWORK[adt][0]],
+ input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_transitive(request):
+ """
+ Verify BGP Large Community attribute"s transitive property attribute.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+
+ config_router_r1(tgen, topo, tc_name)
+
+ input_dict_1 = {
+ "largeCommunity": LARGE_COMM["r1"],
+ "community": STANDARD_COMM["r1"]
+ }
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][0]],
+ input_dict_1)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_override(request):
+ """
+ Verify if overriding large community values works fine.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ config_router_r1(tgen, topo, tc_name)
+
+ config_router_r2(tgen, topo, tc_name)
+
+ input_dict_3 = {
+ "largeCommunity": LARGE_COMM["r2"],
+ "community": STANDARD_COMM["r2"]
+ }
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][1]],
+ input_dict_3)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_additive(request):
+ """
+ Verify that large community values" aggregation works fine.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ config_router_r1(tgen, topo, tc_name)
+
+ config_router_r2(tgen, topo, tc_name)
+
+ config_router_additive(tgen, topo, tc_name)
+
+ input_dict_1 = {
+ "largeCommunity": "%s %s" % (LARGE_COMM["r1"], LARGE_COMM["r2"]),
+ "community": "%s %s" % (STANDARD_COMM["r1"], STANDARD_COMM["r2"])
+ }
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][0]],
+ input_dict_1)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_match_as_path(request):
+ """
+ Matching prefixes based on attributes other than prefix list and make use
+ of set clause.
+ """
+
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ config_for_as_path(tgen, topo, tc_name)
+
+ input_dict = {
+ "largeCommunity": "%s %s" % (
+ LARGE_COMM["pf_list_1"], LARGE_COMM["r2"]),
+ "community": "%s %s" % (
+ STANDARD_COMM["pf_list_1"], STANDARD_COMM["r2"]),
+ }
+
+ input_dict_1 = {
+ "largeCommunity": "%s %s" % (
+ LARGE_COMM["pf_list_2"], LARGE_COMM["r2"]),
+ "community": "%s %s" % (
+ STANDARD_COMM["pf_list_2"], STANDARD_COMM["r2"]),
+ }
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, "r5", [NETWORK[adt][0]],
+ input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ result = verify_bgp_community(tgen, adt, "r5", [NETWORK[adt][1]],
+ input_dict_1, expected=False)
+
+ assert result is not True, "Test case {} : Should fail \n Error: {}". \
+ format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_match_all(request):
+ """
+ Verify community and large-community list operations in route-map with all
+ clause (exact, all, any, regex) works.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ config_router_r1(tgen, topo, tc_name)
+
+ config_router_r2(tgen, topo, tc_name)
+
+ config_router_additive(tgen, topo, tc_name)
+
+ input_dict_1 = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": "1:1:1",
+ "large": True
+ },
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ALL",
+ "value": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1 2:1:1 2:2:1",
+ "large": True
+ },
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "EXP_ALL",
+ "value": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1 2:[1-5]:1",
+ "large": True
+ }
+ ]
+ }
+ }
+
+ step("Create bgp community lists for ANY, EXACT and EXP_ALL match")
+
+ result = create_bgp_community_lists(tgen, input_dict_1)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_2 = {
+ "r4": {
+ "route_maps": {
+ "LC4": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {"large-community-list": {"id": "ANY"}}
+ },
+ {
+ "action": "permit",
+ "seq_id": "20",
+ "match": {"large-community-list": {"id": "EXACT"}}
+ },
+ {
+ "action": "permit",
+ "seq_id": "30",
+ "match": {"large-community-list": {"id": "EXP_ALL"}}
+ }
+ ]
+ }
+ }
+ }
+
+ step("Applying bgp community lits on LC4 route-map")
+ result = create_route_maps(tgen, input_dict_2)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_3 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r5": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "LC4",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r5": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "LC4",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ step("Apply route-mpa LC4 on r4 for r2 neighbor, direction 'in'")
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_4 = {
+ "largeCommunity": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1 2:1:1 2:2:1 2:3:1 "
+ "2:4:1 2:5:1"
+ }
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][0]],
+ input_dict_4)
+ assert result is True, "Test case {} : Should fail \n Error: {}". \
+ format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+#@pytest.mark.skip(reason="as-set not working for ipv6")
+def test_large_community_aggregate_network(request):
+ """
+ Restart router and check if large community and community
+ attributes are getting re-populated.
+ """
+
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+
+ config_for_as_path(tgen, topo, tc_name)
+
+ input_dict = {
+ "community": STANDARD_COMM["agg_1"],
+ "largeCommunity": LARGE_COMM["agg_1"]
+ }
+
+ input_dict_1 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "aggregate_address": [
+ {
+ "network": "%s/%s" % (
+ NETWORK["ipv4"][2], NET_MASK["ipv4"]),
+ "as_set": True
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "aggregate_address": [
+ {
+ "network": "%s/%s" % (
+ NETWORK["ipv6"][2], NET_MASK["ipv6"]),
+ "as_set": True
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ step("Configuring aggregate address as-set on r2")
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, "r4",
+ ["%s/%s" % (NETWORK[adt][2],
+ NET_MASK[adt])],
+ input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_2 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "%s/%s" % (
+ NETWORK["ipv4"][0], MASK["ipv4"]),
+ "no_of_network": 1,
+ "delete": True
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "%s/%s" % (
+ NETWORK["ipv6"][0], MASK["ipv6"]),
+ "no_of_network": 1,
+ "delete": True
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ step("Stop advertising one of the networks")
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_dict_3 = {
+ "community": STANDARD_COMM["agg_2"],
+ "largeCommunity": LARGE_COMM["agg_2"]
+ }
+
+ for adt in ADDR_TYPES:
+ step("Verifying bgp community values on r5 is also modified")
+ result = verify_bgp_community(tgen, adt, "r4",
+ ["%s/%s" % (NETWORK[adt][2],
+ NET_MASK[adt])],
+ input_dict_3)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_boundary_values(request):
+ """
+ Verify that any value in BGP Large communities for boundary values.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ input_dict = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": "0:-1"
+ }
+ ]
+ }
+ }
+
+ step("Checking boundary value for community 0:-1")
+ result = create_bgp_community_lists(tgen, input_dict)
+ assert result is not True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ step("Checking community attribute 0:65536")
+ input_dict_2 = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": "0:65536"
+ }
+ ]
+ }
+ }
+
+ step("Checking boundary value for community 0:65536")
+ result = create_bgp_community_lists(tgen, input_dict_2)
+ assert result is not True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ step("Checking boundary value for community 0:4294967296")
+ input_dict_3 = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": "0:4294967296",
+ "large": True
+ }
+ ]
+ }
+ }
+
+ result = create_bgp_community_lists(tgen, input_dict_3)
+ assert result is not True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+ step("Checking boundary value for community 0:-1:1")
+
+ input_dict_4 = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": "0:-1:1",
+ "large": True
+ }
+ ]
+ }
+ }
+
+ result = create_bgp_community_lists(tgen, input_dict_4)
+ assert result is not True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+
+def test_large_community_after_clear_bgp(request):
+ """
+ Clear BGP neighbor-ship and check if large community and community
+ attributes are getting re-populated.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ config_router_r1(tgen, topo, tc_name)
+
+ input_dict = {
+ "largeCommunity": LARGE_COMM["r1"],
+ "community": STANDARD_COMM["r1"]
+ }
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, "r2", [NETWORK[adt][0]],
+ input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ step("Clearing BGP on r1")
+ clear_bgp_and_verify(tgen, topo, "r1")
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, "r2", [NETWORK[adt][0]],
+ input_dict)
+ assert result is True, "Test case {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
new file mode 100755
index 000000000..cba20551c
--- /dev/null
+++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
@@ -0,0 +1,2408 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2019 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+#Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_large_community_topo_1.py: Test BGP large community.
+
+Following tests are covered:
+1. Verify the standard large-community-lists can permit or deny
+ large community attribute only in the correct canonical format.
+2. Verify the expanded large-community-lists can permit or deny
+ large community attribute both in the correct canonical format
+ as well as REG_EX.
+3. Verify that we can modify a large-community-list is in use,
+ to add/remove attribute value and it takes immediate effect.
+4. Verify that large community attribute gets advertised when
+ route-map is applied to a neighbor and cleared when route-map
+ is removed.
+5. Verify that duplicate BGP Large Community values are NOT be transmitted.
+6. Verify if we want to remove all the large-community attributes from a
+ set of prefix we can set the value as NONE.
+7. Redistribute connected and static routes in BGP process with a route-map
+ appending/removing L-comm attributes.
+8. Verify if we want to remove specific large-community values from
+ a set of prefix we can make use of DELETE operation based on L-comm list.
+9. Verify that if community values are NOT be advertised to a specific
+ neighbour, we negate send-community command.
+ (Send-community all is enabled by default for all neighbors)
+10. Verify that large-community lists can not be configured without providing
+ specific L-community values(for match/delete operation in a route-map).
+11. Verify that Match_EXACT clause should pass only if all of the L-comm
+ values configured (horizontally) in the community list is present in
+ the prefix. There must be no additional L-communities in the prefix.
+12. Verify that Match_ALL clause should pass only if ALL of the L-comm values
+ configured (horizontally) in the community list is present in the prefix.
+ There could be additional L-communities in the prefix that are not present
+ in the L-comm list.
+13. Verify that Match_ANY clause should pass only if at-least any one L-comm
+ value configured(vertically) in large-community list, is present in prefixes.
+14. Verify large-community lists operation in a route-map with match RegEx
+ statements.
+"""
+
+import os
+import sys
+import json
+import pytest
+import time
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+# Import topoJson from lib, to create topology and initial configuration
+from lib.topogen import Topogen, get_topogen
+from mininet.topo import Topo
+
+from lib.common_config import (
+ start_topology, write_test_header,
+ write_test_footer, reset_config_on_routers,
+ create_route_maps, create_bgp_community_lists,
+ create_prefix_lists, verify_bgp_community, step,
+ verify_create_community_list, delete_route_maps,
+ verify_route_maps, create_static_routes,
+ check_address_types
+)
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence, create_router_bgp,
+ clear_bgp_and_verify
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology and configuration creation
+jsonFile = "{}/bgp_large_community_topo_2.json".format(CWD)
+
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+bgp_convergence = False
+
+NETWORKS = {"ipv4": ["200.50.2.0/32"], "ipv6": ["1::1/128"]}
+
+
+class GenerateTopo(Topo):
+ """
+ Test topology builder
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("="*40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(GenerateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Checking BGP convergence
+ global bgp_convergence, ADDR_TYPES
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Api call verify whether BGP is converged
+ # Ipv4
+ bgp_convergence = verify_bgp_convergence(tgen, topo)
+ assert bgp_convergence is True, ("setup_module :Failed \n Error:"
+ " {}".format(bgp_convergence))
+ ADDR_TYPES = check_address_types()
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: {}".\
+ format(time.asctime(time.localtime(time.time()))))
+ logger.info("="*40)
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_create_bgp_standard_large_community_list(request):
+ """
+ Create standard large-community-list and verify it can permit
+ or deny large community attribute only in the correct canonical
+ format.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+
+ step("Create srtandard large community list")
+ input_dict = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "LC_1_STD",
+ "value": "2:1:1 2:1:2 1:2:3",
+ "large": True
+ },
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "LC_2_STD",
+ "value": "3:1:1 3:1:2",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify BGP large community is created")
+ result = verify_create_community_list(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create srtandard large community list with in-correct values")
+ input_dict = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "LC_1_STD_ERR",
+ "value": "0:0:0",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ ## TODO should fail
+ step("Verify BGP large community is created")
+ result = verify_create_community_list(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_create_bgp_expanded_large_community_list(request):
+ """
+ Create expanded large-community-list and verify it can permit
+ or deny large community attribute both in the correct canonical
+ format as well as REG_EX
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create expanded large community list")
+ input_dict = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "LC_1_EXP",
+ "value": "1:1:200 1:2:* 3:2:1",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify BGP large community is created")
+ result = verify_create_community_list(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_modify_large_community_lists_referenced_by_rmap(request):
+ """
+ This test is to verify that we can modify a large-community-list
+ is in use, add/remove attribute value and it takes immediate effect.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create standard large community list")
+ input_dict_1 = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "LC_DEL",
+ "value": "1:2:1 1:3:1 2:1:1 2:2:2 3:3:3",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create route map")
+ input_dict_2 = {
+ "r1": {
+ "route_maps": {
+ "RM_R2_OUT": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "1:2:1 1:3:1 2:10:1 3:3:3 4:4:4 5:5:5",
+ "action": "additive"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "r4": {
+ "route_maps": {
+ "RM_R4_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_comm_list": {
+ "id": "LC_DEL",
+ "delete": True
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map and advertise networks")
+ input_dict_3 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name": "RM_R2_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {
+ "route_maps": [{
+ "name": "RM_R2_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify Community-list")
+ dut = "r4"
+ input_dict_4 = {
+ "largeCommunity": "2:10:1 4:4:4 5:5:5"
+ }
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_lists_with_rmap_apply_and_remove(request):
+ """
+ This test is to verify that large community attribute gets advertised when
+ route-map is applied to a neighbor and cleared when route-map is removed
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create route map")
+ input_dict_1 = {
+ "r4": {
+ "route_maps": {
+ "RM_LC1": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "200:200:1 200:200:10 200:200:20000",
+ "action": "additive"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map and advertise networks")
+ input_dict_2 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r6": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_LC1",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r6": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_LC1",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list")
+ dut = "r6"
+ input_dict_4 = {
+ "largeCommunity": "200:200:1 200:200:10 200:200:20000"
+ }
+
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Delete route map reference by community-list")
+ input_dict_3 = {
+ "r4": {
+ "route_maps": ["RM_LC1"]
+ }
+ }
+ result = delete_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify route map is deleted")
+ result = verify_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list")
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_4, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_duplicate_large_community_list_attributes_not_transitive(request):
+ """
+ This test is to verify that duplicate BGP Large Community values
+ are NOT be transmitted.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create route map")
+ input_dict_1 = {
+ "r4": {
+ "route_maps": {
+ "RM_R4_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "0:0:1 0:0:10 0:0:100 2:0:1 2:0:2 2:0:3"
+ " 2:0:4 2:0:5",
+ "action": "additive"
+ }
+ }
+ }
+ ],
+ "RM_R4_OUT": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "0:0:1 0:0:10 0:0:10000 2:0:1 2:0:2",
+ "action": "additive"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map and advertise networks")
+ input_dict_2 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list")
+ dut = "r6"
+ input_dict_4 = {
+ "largeCommunity":
+ "0:0:1 0:0:10 0:0:100 0:0:10000 2:0:1 2:0:2 2:0:3 2:0:4 2:0:5"
+ }
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_lists_with_rmap_set_none(request):
+ """
+ This test is to verify if we want to remove all the large-community
+ attributes from a set of prefix we can set the value as NONE.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create route map")
+ input_dict_1 = {
+ "r4": {
+ "route_maps": {
+ "RM_R4_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "0:0:1 0:0:10 0:0:100 2:0:1 2:0:2 2:0:3"
+ " 2:0:4",
+ "action": "additive"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "r6": {
+ "route_maps": {
+ "RM_R6_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "none"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map")
+ input_dict_2 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r6": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r6": {
+ "route_maps": [{
+ "name": "RM_R6_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r6": {
+ "route_maps": [{
+ "name": "RM_R6_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify Community-list")
+ dut = "r6"
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_lcomm_lists_with_redistribute_static_connected_rmap(request):
+ """
+ This test is to verify redistribute connected and static ipv4 routes
+ in BGP process with a route-map appending/removing L-comm attributes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("create static routes")
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": "200.50.2.0/32",
+ "next_hop": "10.0.0.6"
+ },
+ {
+ "network": "1::1/128",
+ "next_hop": "fd00:0:0:1::2"
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("redistribute static routes")
+ input_dict_1 = {
+ "r1":{
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": "route-map RM_R2_OUT"
+ },
+ {
+ "redist_type": "connected",
+ "attribute": "route-map RM_R2_OUT"
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": "route-map RM_R2_OUT"
+ },
+ {
+ "redist_type": "connected",
+ "attribute": "route-map RM_R2_OUT"
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create route map")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RM_R2_OUT": [{
+ "action": "permit",
+ "set": {
+ "large_community": {"num":"55:55:55 555:555:555"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list for static and connected ipv4 route on"
+ " r2")
+
+ input_dict_5 = {
+ "largeCommunity": "55:55:55 555:555:555"
+ }
+
+ if "ipv4" in ADDR_TYPES:
+ dut = "r2"
+ networks = ["200.50.2.0/32", "1.0.1.17/32"]
+ result = verify_bgp_community(tgen, "ipv4", dut, networks,
+ input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list for static and connected ipv4 route"
+ " on r4")
+ dut = "r4"
+ networks = ["200.50.2.0/32", "1.0.1.17/32"]
+ result = verify_bgp_community(tgen, "ipv4", dut, networks,
+ input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ if "ipv6" in ADDR_TYPES:
+ step("Verify large-community-list for static and connected ipv6 route"
+ " on r2")
+ dut = "r2"
+ networks = ["1::1/128", "2001:db8:f::1:17/128"]
+ result = verify_bgp_community(tgen, "ipv6", dut, networks,
+ input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list for static and connected ipv6 route"
+ " on r4")
+ dut = "r4"
+ networks = ["1::1/128", "2001:db8:f::1:17/128"]
+ result = verify_bgp_community(tgen, "ipv6", dut, networks,
+ input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_lists_with_rmap_set_delete(request):
+ """
+ This test is to verify if we want to remove specific large-community
+ values from a set of prefix we can make use of DELETE operation based
+ on L-comm list
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("configure route_map")
+ input_dict_2 = {
+ "r6": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "Test",
+ "value": "1:2:1 1:1:10 1:3:100",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create route map")
+ input_dict_3 = {
+ "r6": {
+ "route_maps": {
+ "RM_R6_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_comm_list": {
+ "id": "Test",
+ "delete": True
+ }
+ }
+ }
+ ]
+ }
+ },
+ "r4": {
+ "route_maps": {
+ "RM_R4_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "1:2:1 1:1:10 1:3:100 2:1:1 2:2:2 2:3:3"
+ " 2:4:4 2:5:5",
+ "action": "additive"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map and advertise networks")
+ input_dict_4 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r6": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r6": {
+ "route_maps": [{
+ "name": "RM_R6_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r6": {
+ "route_maps": [{
+ "name": "RM_R6_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list")
+ dut = "r6"
+ input_dict_5 = {
+ "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_lists_with_no_send_community(request):
+ """
+ This test is to verify if we want to remove specific large-community
+ values from a set of prefix we can make use of DELETE operation based
+ on L-comm list
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create route map")
+ input_dict_2 = {
+ "r5": {
+ "route_maps": {
+ "RM_R6_OUT": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map and advertise networks")
+ input_dict_3 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r5": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r6": {
+ "dest_link": {
+ "r5": {
+ "route_maps": [{
+ "name": "RM_R6_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r6": {
+ "dest_link": {
+ "r5": {
+ "route_maps": [{
+ "name": "RM_R6_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list")
+ dut = "r6"
+ input_dict_4 = {
+ "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for no-send-community")
+ input_dict_5 = {
+ "r5": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r6": {
+ "dest_link": {
+ "r5": {
+ "no_send_community": "large"
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r6": {
+ "dest_link": {
+ "r5": {
+ "no_send_community": "large"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify Community-list")
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_4, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_create_large_community_lists_with_no_attribute_values(request):
+ """
+ This test is to verify that large-community lists can not be
+ configured without providing specific L-community values
+ (for match/delete operation in a route-map).
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create standard large commumity-list")
+ input_dict_1 = {
+ "r5": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "Test1",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_1)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_lists_with_rmap_match_exact(request):
+ """
+ This test is to verify that Match_EXACT clause should pass
+ only if all of the L-comm values configured (horizontally)
+ in the community list is present in the prefix. There must
+ be no additional L-communities in the prefix.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create route map")
+ input_dict_2 = {
+ "r2": {
+ "route_maps": {
+ "RM_R4_OUT": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map and advertise networks")
+ input_dict_3 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create standard large commumity-list")
+ input_dict_4 = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "EXACT",
+ "value": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify BGP large community is created")
+ result = verify_create_community_list(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create route map")
+ input_dict_5 = {
+ "r4": {
+ "route_maps": {
+ "RM_R4_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {
+ "large-community-list": ["EXACT"],
+ "match_exact": True
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map")
+ input_dict_6 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list")
+ dut = "r4"
+ input_dict_4 = {
+ "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_lists_with_rmap_match_all(request):
+ """
+ This test is to verify that Match_ALL clause should pass
+ only if ALL of the L-comm values configured (horizontally)
+ in the community list are present in the prefix. There
+ could be additional L-communities in the prefix that are
+ not present in the L-comm list.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create route map")
+ input_dict_2 = {
+ "r2": {
+ "route_maps": {
+ "RM_R4_OUT": [{
+ "action": "permit",
+ "set": {
+ "large_community": {
+ "num": "1:1:1 1:2:3 2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map")
+ input_dict_3 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create standard large commumity-list")
+ input_dict_4 = {
+ "r3": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ALL",
+ "value": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify BGP large community is created")
+ result = verify_create_community_list(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create route map")
+ input_dict_5 = {
+ "r4": {
+ "route_maps": {
+ "RM_R4_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {
+ "large-community-list": {
+ "id": "ALL"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map")
+ input_dict_6 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list")
+ dut = "r4"
+ input_dict_4 = {
+ "largeCommunity": "1:1:1 1:2:3 2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_lists_with_rmap_match_any(request):
+ """
+ This test is to verify that Match_ANY clause should pass
+ only if at-least any one L-comm value configured(vertically)
+ in large-community list, is present in prefixes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create route map")
+ input_dict_2 = {
+ "r2": {
+ "route_maps": {
+ "RM_R4_OUT": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map")
+ input_dict_3 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create standard large commumity-list")
+ input_dict_4 = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": "2:1:1",
+ "large": True
+ },
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": "2:2:1",
+ "large": True
+ },
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": "2:3:1",
+ "large": True
+ },
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ANY",
+ "value": "2:4:1",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify BGP large community is created")
+ result = verify_create_community_list(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create route map")
+ input_dict_5 = {
+ "r4": {
+ "route_maps": {
+ "RM_R4_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {
+ "large-community-list": {
+ "id": "ANY"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map")
+ input_dict_6 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list")
+ dut = "r4"
+ input_dict_7 = {
+ "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_large_community_lists_with_rmap_match_regex(request):
+ """
+ This test is to verify large-community lists" operation in a route-map
+ with match RegEx statements. Match clause should pass only if the
+ complete string of L-comm values are matched
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Create route map")
+ input_dict_2 = {
+ "r2": {
+ "route_maps": {
+ "RM_R4_OUT": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "set": {
+ "large_community": {
+ "num": "1:1:1 1:1:2 2:1:3 2:1:4 2:1:5",
+ },
+ "community": {
+ "num": "1:1 1:2 1:3 1:4 1:5"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map")
+ input_dict_3 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.50.2.0/32"}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "1::1/128"}
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [{
+ "name": "RM_R4_OUT",
+ "direction": "out"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo,input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create standard large commumity-list")
+ input_dict_4 = {
+ "r4": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "ALL",
+ "value": "1:1:1 2:1:3 2:1:4 2:1:5",
+ "large": True
+ },
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "EXP_ALL",
+ "value": "1:1:1 2:1:[3-5]",
+ "large": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify BGP large community is created")
+ result = verify_create_community_list(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create route map")
+ input_dict_5 = {
+ "r4": {
+ "route_maps": {
+ "RM_R4_IN": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {
+ "large_community_list": {
+ "id": "ALL",
+ },
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Configure neighbor for route map")
+ input_dict_6 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ "route_maps": [{
+ "name": "RM_R4_IN",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Verify large-community-list")
+ dut = "r4"
+ input_dict_7 = {
+ "largeCommunity": "1:1:1 1:1:2 2:1:3 2:1:4 2:1:5"
+ }
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Delete route map reference by community-list")
+ input_dict_3 = {
+ "r4": {
+ "route_maps": ["RM_R4_IN"]
+ }
+ }
+ result = delete_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Create route map")
+ input_dict_5 = {
+ "r4": {
+ "route_maps": {
+ "RM_R4_IN": [
+ {
+ "action": "permit",
+ "seq_id": "20",
+ "match": {
+ "large_community_list": {
+ "id": "EXP_ALL",
+ },
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("clear ip bgp")
+ result = clear_bgp_and_verify(tgen, topo, 'r4')
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ step("Verify large-community-list")
+ dut = "r4"
+ input_dict_7 = {
+ "largeCommunity": "1:1:1 1:1:2 2:1:3 2:1:4 2:1:5"
+ }
+ for adt in ADDR_TYPES:
+ result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt],
+ input_dict_7, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".\
+ format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
index 69b8c7ca5..e7f4f40f0 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
@@ -89,9 +89,8 @@ def test_bgp_maximum_prefix_invalid():
def _bgp_converge(router):
while True:
output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
- if output['192.168.255.1']['connectionsEstablished'] > 3:
+ if output['192.168.255.1']['connectionsEstablished'] > 0:
return True
- time.sleep(1)
def _bgp_parsing_nlri(router):
cmd_max_exceeded = 'grep "%MAXPFXEXCEED: No. of IPv4 Unicast prefix received" bgpd.log'
diff --git a/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf b/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf
new file mode 100644
index 000000000..29a119c29
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf
@@ -0,0 +1,8 @@
+hostname spine1
+router bgp 99
+ neighbor 192.168.2.1 remote-as internal
+ neighbor 192.168.4.2 remote-as internal
+ address-family ipv4 uni
+ redistribute connected
+ neighbor 192.168.2.1 route-reflector-client
+ neighbor 192.168.4.2 route-reflector-client
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
new file mode 100644
index 000000000..552e96ddb
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref
@@ -0,0 +1,162 @@
+{
+ "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.2.1",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"spine1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.2.0\/24":[
+ {
+ "prefix":"192.168.2.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":"spine1-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.4.2",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"spine1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.4.0\/24":[
+ {
+ "prefix":"192.168.4.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":"spine1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.5.0\/24":[
+ {
+ "prefix":"192.168.5.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.2.1",
+ "afi":"ipv4",
+ "interfaceIndex":2,
+ "interfaceName":"spine1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0\/24":[
+ {
+ "prefix":"192.168.6.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.4.2",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"spine1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_rr_ibgp/spine1/staticd.conf b/tests/topotests/bgp_rr_ibgp/spine1/staticd.conf
new file mode 100644
index 000000000..6d8f0952d
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/spine1/staticd.conf
@@ -0,0 +1 @@
+hostname spine1
diff --git a/tests/topotests/bgp_rr_ibgp/spine1/zebra.conf b/tests/topotests/bgp_rr_ibgp/spine1/zebra.conf
new file mode 100644
index 000000000..ea25462d5
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/spine1/zebra.conf
@@ -0,0 +1,9 @@
+hostname spine1
+ip forwarding
+ipv6 forwarding
+
+int spine1-eth0
+ ip addr 192.168.2.3/24
+
+int spine1-eth1
+ ip addr 192.168.4.3/24
diff --git a/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf b/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf
new file mode 100644
index 000000000..a865b388a
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf
@@ -0,0 +1,8 @@
+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
new file mode 100644
index 000000000..c428a8832
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref
@@ -0,0 +1,162 @@
+{
+ "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
new file mode 100644
index 000000000..3ee14d262
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf
@@ -0,0 +1 @@
+hostname spine2
diff --git a/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf b/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf
new file mode 100644
index 000000000..a06681fbc
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf
@@ -0,0 +1,9 @@
+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
new file mode 100755
index 000000000..c28394a7a
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py
@@ -0,0 +1,245 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_rr_ibgp_topo1.py
+#
+# Copyright (c) 2019 by
+# Cumulus Networks, Inc.
+# Donald Sharp
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_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.
+
+"""
+
+import os
+import re
+import sys
+import pytest
+import json
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+#####################################################
+##
+## Network Topology Definition
+##
+#####################################################
+
+class NetworkTopo(Topo):
+ "BGP_RR_IBGP Topology 1"
+
+ def build(self, **_opts):
+ "Build function"
+
+ tgen = get_topogen(self)
+
+ 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
+ # 192.168.1.0/24
+ switch = tgen.add_switch('sw1')
+ switch.add_link(tgen.gears['tor1'])
+
+ # 192.168.2.0/24 - tor1 <-> spine1 connection
+ switch = tgen.add_switch('sw2')
+ switch.add_link(tgen.gears['tor1'])
+ switch.add_link(tgen.gears['spine1'])
+
+ # 3rd switch is for a dummy interface (for local netwokr)
+ # 192.168.3.0/24 - tor2
+ switch = tgen.add_switch('sw3')
+ switch.add_link(tgen.gears['tor2'])
+
+ # 192.168.4.0/24 - tor2 <-> spine1 connection
+ switch = tgen.add_switch('sw4')
+ 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'])
+
+#####################################################
+##
+## Tests starting
+##
+#####################################################
+
+def setup_module(module):
+ "Setup topology"
+ tgen = Topogen(NetworkTopo, module.__name__)
+ tgen.start_topology()
+
+ # This is a sample of configuration loading.
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ tgen.start_router()
+ # tgen.mininet_cli()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def test_converge_protocols():
+ "Wait for protocol convergence"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ topotest.sleep(5, 'Waiting for BGP_RR_IBGP convergence')
+
+
+def test_bgp_rr_ibgp_routes():
+ "Test Route Reflection"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Verify BGP_RR_IBGP Status
+ logger.info("Verifying BGP_RR_IBGP routes")
+
+def test_zebra_ipv4_routingTable():
+ "Test 'show ip route'"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ failures = 0
+ router_list = tgen.routers().values()
+ for router in router_list:
+ output = router.vtysh_cmd('show ip route json', isjson=True)
+ refTableFile = '{}/{}/show_ip_route.json_ref'.format(CWD, router.name)
+ expected = json.loads(open(refTableFile).read())
+
+ assertmsg = 'Zebra IPv4 Routing Table verification failed for router {}'.format(router.name)
+ assert topotest.json_cmp(output, expected) is None, assertmsg
+
+def test_shutdown_check_stderr():
+ if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
+ pytest.skip('Skipping test for Stderr output and memory leaks')
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Verifying unexpected STDERR output from daemons")
+
+ router_list = tgen.routers().values()
+ for router in router_list:
+ router.stop()
+
+ log = tgen.net[router.name].getStdErr('bgpd')
+ if log:
+ logger.error('BGPd StdErr Log:' + log)
+ log = tgen.net[router.name].getStdErr('zebra')
+ if log:
+ logger.error('Zebra StdErr Log:' + log)
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
+
+#
+# Auxiliary Functions
+#
diff --git a/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf
new file mode 100644
index 000000000..44a78dffd
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf
@@ -0,0 +1,5 @@
+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
new file mode 100644
index 000000000..223dcebbc
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref
@@ -0,0 +1,169 @@
+{
+ "192.168.1.0\/24":[
+ {
+ "prefix":"192.168.1.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":"tor1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.2.0\/24":[
+ {
+ "prefix":"192.168.2.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":"tor1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0\/24":[
+ {
+ "prefix":"192.168.3.0\/24",
+ "protocol":"bgp",
+ "distance":200,
+ "metric":0,
+ "table":254,
+ "internalStatus":0,
+ "internalFlags":5,
+ "internalNextHopNum":2,
+ "internalNextHopActiveNum":0,
+ "nexthops":[
+ {
+ "flags":0,
+ "ip":"192.168.4.2",
+ "afi":"ipv4"
+ },
+ {
+ "flags":0,
+ "ip":"192.168.6.2",
+ "afi":"ipv4"
+ }
+ ]
+ }
+ ],
+ "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":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":[
+ {
+ "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":4,
+ "interfaceName":"tor1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0\/24":[
+ {
+ "prefix":"192.168.6.0\/24",
+ "protocol":"bgp",
+ "selected":true,
+ "destSelected":true,
+ "distance":200,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "internalStatus":16,
+ "internalFlags":13,
+ "internalNextHopNum":2,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":0,
+ "ip":"192.168.4.2",
+ "afi":"ipv4"
+ },
+ {
+ "flags":3,
+ "fib":true,
+ "ip":"192.168.5.4",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"tor1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_rr_ibgp/tor1/staticd.conf b/tests/topotests/bgp_rr_ibgp/tor1/staticd.conf
new file mode 100644
index 000000000..bb8d510b0
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/tor1/staticd.conf
@@ -0,0 +1 @@
+hostname tor1
diff --git a/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf b/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf
new file mode 100644
index 000000000..f2fa71350
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf
@@ -0,0 +1,12 @@
+hostname tor1
+ip forwarding
+ipv6 forwarding
+
+int tor1-eth0
+ ip addr 192.168.1.1/24
+
+int tor1-eth1
+ ip addr 192.168.2.1/24
+
+int tor1-eth2
+ ip addr 192.168.5.1/24
diff --git a/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf
new file mode 100644
index 000000000..5ef1de260
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf
@@ -0,0 +1,5 @@
+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
new file mode 100644
index 000000000..5f041b8c6
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref
@@ -0,0 +1,169 @@
+{
+ "192.168.1.0\/24":[
+ {
+ "prefix":"192.168.1.0\/24",
+ "protocol":"bgp",
+ "distance":200,
+ "metric":0,
+ "table":254,
+ "internalStatus":0,
+ "internalFlags":5,
+ "internalNextHopNum":2,
+ "internalNextHopActiveNum":0,
+ "nexthops":[
+ {
+ "flags":0,
+ "ip":"192.168.2.1",
+ "afi":"ipv4"
+ },
+ {
+ "flags":0,
+ "ip":"192.168.5.1",
+ "afi":"ipv4"
+ }
+ ]
+ }
+ ],
+ "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":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"
+ }
+ ]
+ }
+ ],
+ "192.168.3.0\/24":[
+ {
+ "prefix":"192.168.3.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":"tor2-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.4.0\/24":[
+ {
+ "prefix":"192.168.4.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":"tor2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.5.0\/24":[
+ {
+ "prefix":"192.168.5.0\/24",
+ "protocol":"bgp",
+ "selected":true,
+ "destSelected":true,
+ "distance":200,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "internalStatus":16,
+ "internalFlags":13,
+ "internalNextHopNum":2,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "flags":0,
+ "ip":"192.168.2.1",
+ "afi":"ipv4"
+ },
+ {
+ "flags":3,
+ "fib":true,
+ "ip":"192.168.6.4",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"tor2-eth2",
+ "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":4,
+ "interfaceName":"tor2-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_rr_ibgp/tor2/staticd.conf b/tests/topotests/bgp_rr_ibgp/tor2/staticd.conf
new file mode 100644
index 000000000..03098e75d
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/tor2/staticd.conf
@@ -0,0 +1 @@
+hostname tor2
diff --git a/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf b/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf
new file mode 100644
index 000000000..3318cbb19
--- /dev/null
+++ b/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf
@@ -0,0 +1,13 @@
+hostname tor2
+ip forwarding
+ipv6 forwarding
+
+int tor2-eth0
+ ip addr 192.168.3.2/24
+
+int tor2-eth1
+ ip addr 192.168.4.2/24
+
+
+int tor2-eth2
+ ip addr 192.168.6.2/24
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json
index 1ca62094b..e5aff94bd 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json
@@ -10,7 +10,6 @@
"internalFlags": 0,
"nexthops": [
{
- "flags": 1,
"afi": "ipv6",
"interfaceIndex": 2,
"interfaceName": "r1-eth0",
diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py
index 49e48ba92..76b0ab017 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -74,3 +74,9 @@ def pytest_runtest_makereport(item, call):
parent._previousfailed = item
logger.error('assert failed at "{}/{}": {}'.format(
modname, item.name, call.excinfo.value))
+
+ # (topogen) Set topology error to avoid advancing in the test.
+ tgen = get_topogen()
+ if tgen is not None:
+ # This will cause topogen to report error on `routers_have_failure`.
+ tgen.set_error('{}/{}'.format(modname, item.name))
diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref
deleted file mode 100644
index fb193265b..000000000
--- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "neighbors":[
- {
- "2.2.2.2":[
- {
- "priority":1,
- "state":"Full/DR",
- "address":"10.0.1.2",
- "ifaceName":"r1-eth1:10.0.1.1",
- "retransmitCounter":0,
- "requestCounter":0,
- "dbSummaryCounter":0
- }
- ]
- },
- {
- "3.3.3.3":[
- {
- "priority":1,
- "state":"Full/DR",
- "address":"10.0.2.3",
- "ifaceName":"r1-eth2:10.0.2.1",
- "retransmitCounter":0,
- "requestCounter":0,
- "dbSummaryCounter":0
- }
- ]
- }
- ]
-}
-
diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh
deleted file mode 100644
index 7c4d0ab58..000000000
--- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "2.2.2.2":[
- {
- "priority":1,
- "state":"Full/DR",
- "address":"10.0.1.2",
- "ifaceName":"r1-eth1:10.0.1.1"
- }
- ],
- "3.3.3.3":[
- {
- "priority":1,
- "state":"Full/DR",
- "address":"10.0.2.3",
- "ifaceName":"r1-eth2:10.0.2.1"
- }
- ]
-}
diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist
deleted file mode 100644
index 2270c3fdd..000000000
--- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "2.2.2.2":{
- "priority":1,
- "state":"Full/DR",
- "address":"10.0.1.2",
- "ifaceName":"r1-eth1:10.0.1.1"
- },
- "3.3.3.3":{
- "priority":1,
- "state":"Full/DR",
- "address":"10.0.2.3",
- "ifaceName":"r1-eth2:10.0.2.1"
- }
-}
diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref
deleted file mode 100644
index 137657975..000000000
--- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "neighbors":[
- {
- "1.1.1.1":[
- {
- "priority":1,
- "state":"Full/Backup",
- "address":"10.0.1.1",
- "ifaceName":"r2-eth1:10.0.1.2",
- "retransmitCounter":0,
- "requestCounter":0,
- "dbSummaryCounter":0
- }
- ]
- },
- {
- "3.3.3.3":[
- {
- "priority":1,
- "state":"Full/DR",
- "address":"10.0.3.3",
- "ifaceName":"r2-eth2:10.0.3.2",
- "retransmitCounter":0,
- "requestCounter":0,
- "dbSummaryCounter":0
- }
- ]
- }
- ]
-}
diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh
deleted file mode 100644
index a982c1cbd..000000000
--- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "1.1.1.1":[
- {
- "priority":1,
- "state":"Full/Backup",
- "address":"10.0.1.1",
- "ifaceName":"r2-eth1:10.0.1.2"
- }
- ],
- "3.3.3.3":[
- {
- "priority":1,
- "state":"Full/DR",
- "address":"10.0.3.3",
- "ifaceName":"r2-eth2:10.0.3.2"
- }
- ]
-}
diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist
deleted file mode 100644
index 18ffbc2f8..000000000
--- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "1.1.1.1":{
- "priority":1,
- "state":"Full/Backup",
- "address":"10.0.1.1",
- "ifaceName":"r2-eth1:10.0.1.2"
- },
- "3.3.3.3":{
- "priority":1,
- "state":"Full/DR",
- "address":"10.0.3.3",
- "ifaceName":"r2-eth2:10.0.3.2"
- }
-}
diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref
deleted file mode 100644
index 41de304b2..000000000
--- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "neighbors":[
- {
- "1.1.1.1":[
- {
- "priority":1,
- "state":"Full/Backup",
- "address":"10.0.2.1",
- "ifaceName":"r3-eth1:10.0.2.3",
- "retransmitCounter":0,
- "requestCounter":0,
- "dbSummaryCounter":0
- }
- ]
- },
- {
- "2.2.2.2":[
- {
- "priority":1,
- "state":"Full/Backup",
- "address":"10.0.3.2",
- "ifaceName":"r3-eth2:10.0.3.3",
- "retransmitCounter":0,
- "requestCounter":0,
- "dbSummaryCounter":0
- }
- ]
- }
- ]
-}
diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh
deleted file mode 100644
index d7e0e4240..000000000
--- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "1.1.1.1":[
- {
- "priority":1,
- "state":"Full/Backup",
- "address":"10.0.2.1",
- "ifaceName":"r3-eth1:10.0.2.3"
- }
- ],
- "2.2.2.2":[
- {
- "priority":1,
- "state":"Full/Backup",
- "address":"10.0.3.2",
- "ifaceName":"r3-eth2:10.0.3.3"
- }
- ]
-}
diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist
deleted file mode 100644
index b0669742a..000000000
--- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "1.1.1.1":{
- "priority":1,
- "state":"Full/Backup",
- "address":"10.0.2.1",
- "ifaceName":"r3-eth1:10.0.2.3"
- },
- "2.2.2.2":{
- "priority":1,
- "state":"Full/Backup",
- "address":"10.0.3.2",
- "ifaceName":"r3-eth2:10.0.3.3"
- }
-}
diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
index 0948c2e41..ce651c50c 100755
--- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
+++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
@@ -144,9 +144,6 @@ def setup_module(mod):
)
tgen.start_router()
- for router in router_list.values():
- if router.has_version('<', '3'):
- tgen.set_error('unsupported version')
def teardown_module(mod):
"Teardown the pytest environment"
@@ -180,30 +177,8 @@ def test_ospf_convergence():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- # Old output (before FRR PR1383) didn't show a list of neighbors.
- # Check for dict object and compare to old output if this is the case
- tgen = get_topogen()
- router = tgen.gears['r1']
- output = router.vtysh_cmd("show ip ospf neighbor json", isjson=True)
-
- # We could have either old format (without "neighbors" and direct list
- # of IP's or new format from PR1659 with "neighbors".
- # Trying old formats first and fall back to new format
- #
- # New format: neighbors have dict instead of list of dicts (PR1723).
- if output.has_key('neighbors'):
- if isinstance(output['neighbors'], dict):
- reffile = "show_ip_ospf_neighbor.json"
- else:
- reffile = "show_ip_ospf_neighbor.ref"
- else:
- if isinstance(output["2.2.2.2"], dict):
- reffile = "show_ip_ospf_neighbor.ref-old-nolist"
- else:
- reffile = "show_ip_ospf_neighbor.ref-no-neigh"
-
for rname in ['r1', 'r2', 'r3']:
- router_compare_json_output(rname, "show ip ospf neighbor json", reffile)
+ router_compare_json_output(rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json")
def test_rib():
logger.info("Test: verify RIB")
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index c05e14a95..7ec584bf5 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -200,29 +200,6 @@ def __create_bgp_global(tgen, input_dict, router, build=False):
config_data.append("bgp router-id {}".format(
router_id))
- aggregate_address = bgp_data.setdefault("aggregate_address",
- {})
- if aggregate_address:
- network = aggregate_address.setdefault("network", None)
- if not network:
- logger.error("Router %s: 'network' not present in "
- "input_dict for BGP", router)
- else:
- cmd = "aggregate-address {}".format(network)
-
- as_set = aggregate_address.setdefault("as_set", False)
- summary = aggregate_address.setdefault("summary", False)
- del_action = aggregate_address.setdefault("delete", False)
- if as_set:
- cmd = "{} {}".format(cmd, "as-set")
- if summary:
- cmd = "{} {}".format(cmd, "summary")
-
- if del_action:
- cmd = "no {}".format(cmd)
-
- config_data.append(cmd)
-
return config_data
@@ -300,15 +277,25 @@ def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router,
ebgp
))
- aggregate_address = addr_data.setdefault("aggregate_address",
- {})
- if aggregate_address:
- ip = aggregate_address("network", None)
- attribute = aggregate_address("attribute", None)
- if ip:
- cmd = "aggregate-address {}".format(ip)
- if attribute:
- cmd = "{} {}".format(cmd, attribute)
+ aggregate_addresses = addr_data.setdefault("aggregate_address", [])
+ for aggregate_address in aggregate_addresses:
+ network = aggregate_address.setdefault("network", None)
+ if not network:
+ logger.debug("Router %s: 'network' not present in "
+ "input_dict for BGP", router)
+ else:
+ cmd = "aggregate-address {}".format(network)
+
+ as_set = aggregate_address.setdefault("as_set", False)
+ summary = aggregate_address.setdefault("summary", False)
+ del_action = aggregate_address.setdefault("delete", False)
+ if as_set:
+ cmd = "{} as-set".format(cmd)
+ if summary:
+ cmd = "{} summary".format(cmd)
+
+ if del_action:
+ cmd = "no {}".format(cmd)
config_data.append(cmd)
@@ -445,10 +432,10 @@ def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type,
bgp_data = input_dict[router]["bgp"]["address_family"]
neigh_data = bgp_data[addr_type]["unicast"]["neighbor"]
- for name, peer_dict in deepcopy(neigh_data).iteritems():
+ for peer_name, peer_dict in deepcopy(neigh_data).iteritems():
for dest_link, peer in peer_dict["dest_link"].iteritems():
deactivate = None
- nh_details = topo[name]
+ nh_details = topo[peer_name]
# Loopback interface
if "source_link" in peer and peer["source_link"] == "lo":
for destRouterLink, data in sorted(nh_details["links"].
@@ -481,14 +468,20 @@ def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type,
send_community = peer.setdefault("send_community", None)
prefix_lists = peer.setdefault("prefix_lists", {})
route_maps = peer.setdefault("route_maps", {})
+ no_send_community = peer.setdefault("no_send_community", None)
# next-hop-self
if next_hop_self:
config_data.append("{} next-hop-self".format(neigh_cxt))
- # no_send_community
+ # send_community
if send_community:
config_data.append("{} send-community".format(neigh_cxt))
+ # no_send_community
+ if no_send_community:
+ config_data.append("no {} send-community {}".format(
+ neigh_cxt, no_send_community))
+
if prefix_lists:
for prefix_list in prefix_lists:
name = prefix_list.setdefault("name", {})
@@ -1229,6 +1222,150 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
return True
+@retry(attempts=3, wait=4, return_is_str=True)
+def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name,
+ input_dict, seq_id=None):
+ """
+ API will verify BGP attributes set by Route-map for given prefix and
+ DUT. it will run "show bgp ipv4/ipv6 {prefix_address} json" command
+ in DUT to verify BGP attributes set by route-map, Set attributes
+ values will be read from input_dict and verified with command output.
+
+ * `tgen`: topogen object
+ * `addr_type` : ip type, ipv4/ipv6
+ * `dut`: Device Under Test
+ * `static_routes`: Static Routes for which BGP set attributes needs to be
+ verified
+ * `rmap_name`: route map name for which set criteria needs to be verified
+ * `input_dict`: defines for which router, AS numbers needs
+ * `seq_id`: sequence number of rmap, default is None
+
+ Usage
+ -----
+ input_dict = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_1_ipv4": [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_" + addr_type
+ }
+ },
+ "set": {
+ "localpref": 150,
+ "weight": 100
+ }
+ }],
+ "rmap_match_pf_2_ipv6": [{
+ "action": "permit",
+ 'seq_id': '5',
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_" + addr_type
+ }
+ },
+ "set": {
+ "med": 50
+ }
+ }]
+ }
+ }
+ }
+ result = verify_bgp_attributes(tgen, 'ipv4', "r1", "10.0.20.1/32",
+ rmap_match_pf_1_ipv4, input_dict)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: verify_bgp_attributes()")
+ for router, rnode in tgen.routers().iteritems():
+ if router != dut:
+ continue
+
+ logger.info('Verifying BGP set attributes for dut {}:'.format(router))
+
+ for static_route in static_routes:
+ cmd = "show bgp {} {} json".format(addr_type, static_route)
+ show_bgp_json = run_frr_cmd(rnode, cmd, isjson=True)
+ print("show_bgp_json $$$$$", show_bgp_json)
+
+ dict_to_test = []
+ tmp_list = []
+ for rmap_router in input_dict.keys():
+ for rmap, values in input_dict[rmap_router][
+ "route_maps"].items():
+ print("rmap == rmap_name $$$$1", rmap, rmap_name)
+ if rmap == rmap_name:
+ print("rmap == rmap_name $$$$", rmap, rmap_name)
+ dict_to_test = values
+ for rmap_dict in values:
+ if seq_id is not None:
+ if type(seq_id) is not list:
+ seq_id = [seq_id]
+
+ if "seq_id" in rmap_dict:
+ rmap_seq_id = \
+ rmap_dict["seq_id"]
+ for _seq_id in seq_id:
+ if _seq_id == rmap_seq_id:
+ tmp_list.append(rmap_dict)
+ if tmp_list:
+ dict_to_test = tmp_list
+
+ print("dict_to_test $$$$", dict_to_test)
+ for rmap_dict in dict_to_test:
+ if "set" in rmap_dict:
+ for criteria in rmap_dict["set"].keys():
+ if criteria not in show_bgp_json[
+ "paths"][0]:
+ errormsg = ("BGP attribute: {}"
+ " is not found in"
+ " cli: {} output "
+ "in router {}".
+ format(criteria,
+ cmd,
+ router))
+ return errormsg
+
+ if rmap_dict["set"][criteria] == \
+ show_bgp_json["paths"][0][
+ criteria]:
+ logger.info("Verifying BGP "
+ "attribute {} for"
+ " route: {} in "
+ "router: {}, found"
+ " expected value:"
+ " {}".
+ format(criteria,
+ static_route,
+ dut,
+ rmap_dict[
+ "set"][
+ criteria]))
+ else:
+ errormsg = \
+ ("Failed: Verifying BGP "
+ "attribute {} for route:"
+ " {} in router: {}, "
+ " expected value: {} but"
+ " found: {}".
+ format(criteria,
+ static_route,
+ dut,
+ rmap_dict["set"]
+ [criteria],
+ show_bgp_json[
+ 'paths'][
+ 0][criteria]))
+ return errormsg
+
+ logger.debug("Exiting lib API: verify_bgp_attributes()")
+ return True
+
@retry(attempts=3, wait=2, return_is_str=True)
def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict,
attribute):
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index f2d33f94a..38b97cba2 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -21,6 +21,7 @@
from collections import OrderedDict
from datetime import datetime
from time import sleep
+from copy import deepcopy
from subprocess import call
from subprocess import STDOUT as SUB_STDOUT
from subprocess import PIPE as SUB_PIPE
@@ -34,11 +35,7 @@ import ConfigParser
import traceback
import socket
import ipaddr
-import re
-from lib import topotest
-
-from functools import partial
from lib.topolog import logger, logger_config
from lib.topogen import TopoRouter
from lib.topotest import interface_set_status
@@ -47,7 +44,7 @@ from lib.topotest import interface_set_status
FRRCFG_FILE = "frr_json.conf"
FRRCFG_BKUP_FILE = "frr_json_initial.conf"
-ERROR_LIST = ["Malformed", "Failure", "Unknown"]
+ERROR_LIST = ["Malformed", "Failure", "Unknown", "Incomplete"]
ROUTER_LIST = []
####
@@ -208,6 +205,7 @@ def create_common_configuration(tgen, router, data, config_type=None,
"interface_config": "! Interfaces Config\n",
"static_route": "! Static Route Config\n",
"prefix_list": "! Prefix List Config\n",
+ "bgp_community_list": "! Community List Config\n",
"route_maps": "! Route Maps Config\n",
"bgp": "! BGP Config\n"
})
@@ -547,13 +545,11 @@ def generate_ips(network, no_of_ips):
Returns list of IPs.
based on start_ip and no_of_ips
- * `network` : from here the ip will start generating, start_ip will be
- first ip
+ * `network` : from here the ip will start generating,
+ start_ip will be
* `no_of_ips` : these many IPs will be generated
-
- Limitation: It will generate IPs only for ip_mask 32
-
"""
+
ipaddress_list = []
if type(network) is not list:
network = [network]
@@ -621,7 +617,7 @@ def write_test_header(tc_name):
""" Display message at beginning of test case"""
count = 20
logger.info("*"*(len(tc_name)+count))
- logger.info("START -> Testcase : %s" % tc_name)
+ step("START -> Testcase : %s" % tc_name, reset=True)
logger.info("*"*(len(tc_name)+count))
@@ -713,9 +709,9 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
kwargs.pop('expected')
ret = func(*args, **kwargs)
logger.debug("Function returned %s" % ret)
- if return_is_str and isinstance(ret, bool):
+ if return_is_str and isinstance(ret, bool) and _expected:
return ret
- elif return_is_str and _expected is False:
+ if isinstance(ret, str) and _expected is False:
return ret
if _attempts == i:
@@ -736,60 +732,29 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
return _retry
-def disable_v6_link_local(tgen, router, intf_name=None):
+class Stepper:
"""
- Disables ipv6 link local addresses for a particular interface or
- all interfaces
-
- * `tgen`: tgen onject
- * `router` : router for which hightest interface should be
- calculated
- * `intf_name` : Interface name for which v6 link local needs to
- be disabled
+ Prints step number for the test case step being executed
"""
+ count = 1
- router_list = tgen.routers()
- for rname, rnode in router_list.iteritems():
- if rname != router:
- continue
-
- linklocal = []
-
- ifaces = router_list[router].run('ip -6 address')
-
- # Fix newlines (make them all the same)
- ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines()
-
- interface = None
- ll_per_if_count = 0
- for line in ifaces:
- # Interface name
- m = re.search('[0-9]+: ([^:]+)[@if0-9:]+ <', line)
- if m:
- interface = m.group(1).split("@")[0]
- ll_per_if_count = 0
-
- # Interface ip
- m = re.search('inet6 (fe80::[0-9a-f]+:[0-9a-f]+:[0-9a-f]+'
- ':[0-9a-f]+[/0-9]*) scope link', line)
- if m:
- local = m.group(1)
- ll_per_if_count += 1
- if ll_per_if_count > 1:
- linklocal += [["%s-%s" % (interface, ll_per_if_count), local]]
- else:
- linklocal += [[interface, local]]
-
- if len(linklocal[0]) > 1:
- link_local_dict = {item[0]: item[1] for item in linklocal}
+ def __call__(self, msg, reset):
+ if reset:
+ Stepper.count = 1
+ logger.info(msg)
+ else:
+ logger.info("STEP %s: '%s'", Stepper.count, msg)
+ Stepper.count += 1
- for lname, laddr in link_local_dict.items():
- if intf_name is not None and lname != intf_name:
- continue
-
- cmd = "ip addr del {} dev {}".format(laddr, lname)
- router_list[router].run(cmd)
+def step(msg, reset=False):
+ """
+ Call Stepper to print test steps. Need to reset at the beginning of test.
+ * ` msg` : Step message body.
+ * `reset` : Reset step count to 1 when set to True.
+ """
+ _step = Stepper()
+ _step(msg, reset)
#############################################
@@ -821,8 +786,6 @@ def create_interfaces_cfg(tgen, topo, build=False):
interface_name = destRouterLink
else:
interface_name = data["interface"]
- if "ipv6" in data:
- disable_v6_link_local(tgen, c_router, interface_name)
interface_data.append("interface {}".format(
str(interface_name)
))
@@ -893,6 +856,7 @@ def create_static_routes(tgen, input_dict, build=False):
"""
result = False
logger.debug("Entering lib API: create_static_routes()")
+ input_dict = deepcopy(input_dict)
try:
for router in input_dict.keys():
if "static_routes" not in input_dict[router]:
@@ -918,16 +882,21 @@ def create_static_routes(tgen, input_dict, build=False):
next_hop = static_route["next_hop"]
network = static_route["network"]
- ip_list = generate_ips([network], no_of_ip)
+ if type(network) is not list:
+ network = [network]
+
+ ip_list = generate_ips(network, no_of_ip)
for ip in ip_list:
addr_type = validate_ip_address(ip)
+
if addr_type == "ipv4":
cmd = "ip route {} {}".format(ip, next_hop)
else:
cmd = "ipv6 route {} {}".format(ip, next_hop)
if tag:
- cmd = "{} {}".format(cmd, str(tag))
+ cmd = "{} tag {}".format(cmd, str(tag))
+
if admin_distance:
cmd = "{} {}".format(cmd, admin_distance)
@@ -1112,11 +1081,11 @@ def create_route_maps(tgen, input_dict, build=False):
"prefix_list": "pf_list_1"
}
- "large-community-list": "{
+ "large-community-list": {
"id": "community_1",
"exact_match": True
}
- "community": {
+ "community_list": {
"id": "community_2",
"exact_match": True
}
@@ -1152,12 +1121,11 @@ def create_route_maps(tgen, input_dict, build=False):
result = False
logger.debug("Entering lib API: create_route_maps()")
-
+ input_dict = deepcopy(input_dict)
try:
for router in input_dict.keys():
if "route_maps" not in input_dict[router]:
- errormsg = "route_maps not present in input_dict"
- logger.debug(errormsg)
+ logger.debug("route_maps not present in input_dict")
continue
rmap_data = []
for rmap_name, rmap_value in \
@@ -1187,10 +1155,41 @@ def create_route_maps(tgen, input_dict, build=False):
rmap_name, rmap_action, seq_id
))
+ if "continue" in rmap_dict:
+ continue_to = rmap_dict["continue"]
+ if continue_to:
+ rmap_data.append("on-match goto {}".
+ format(continue_to))
+ else:
+ logger.error("In continue, 'route-map entry "
+ "sequence number' is not provided")
+ return False
+
+ if "goto" in rmap_dict:
+ go_to = rmap_dict["goto"]
+ if go_to:
+ rmap_data.append("on-match goto {}".
+ format(go_to))
+ else:
+ logger.error("In goto, 'Goto Clause number' is not"
+ " provided")
+ return False
+
+ if "call" in rmap_dict:
+ call_rmap = rmap_dict["call"]
+ if call_rmap:
+ rmap_data.append("call {}".
+ format(call_rmap))
+ else:
+ logger.error("In call, 'destination Route-Map' is"
+ " not provided")
+ return False
+
# Verifying if SET criteria is defined
if "set" in rmap_dict:
set_data = rmap_dict["set"]
-
+ ipv4_data = set_data.setdefault("ipv4", {})
+ ipv6_data = set_data.setdefault("ipv6", {})
local_preference = set_data.setdefault("localpref",
None)
metric = set_data.setdefault("med", None)
@@ -1199,7 +1198,10 @@ def create_route_maps(tgen, input_dict, build=False):
community = set_data.setdefault("community", {})
large_community = set_data.setdefault(
"large_community", {})
+ large_comm_list = set_data.setdefault(
+ "large_comm_list", {})
set_action = set_data.setdefault("set_action", None)
+ nexthop = set_data.setdefault("nexthop", None)
# Local Preference
if local_preference:
@@ -1243,42 +1245,86 @@ def create_route_maps(tgen, input_dict, build=False):
rmap_data.append(cmd)
else:
- logger.errror("In large_community, AS Num not"
- " provided")
+ logger.error("In large_community, AS Num not"
+ " provided")
+ return False
+ if large_comm_list:
+ id = large_comm_list.setdefault("id", None)
+ del_comm = large_comm_list.setdefault("delete",
+ None)
+ if id:
+ cmd = "set large-comm-list {}".format(id)
+ if del_comm:
+ cmd = "{} delete".format(cmd)
+
+ rmap_data.append(cmd)
+ else:
+ logger.error("In large_comm_list 'id' not"
+ " provided")
return False
# Weight
if weight:
rmap_data.append("set weight {}".format(
weight))
+ if ipv6_data:
+ nexthop = ipv6_data.setdefault("nexthop", None)
+ if nexthop:
+ rmap_data.append("set ipv6 next-hop {}".format(
+ nexthop
+ ))
# Adding MATCH and SET sequence to RMAP if defined
if "match" in rmap_dict:
match_data = rmap_dict["match"]
ipv4_data = match_data.setdefault("ipv4", {})
ipv6_data = match_data.setdefault("ipv6", {})
- community = match_data.setdefault("community-list",
- {})
+ community = match_data.setdefault(
+ "community_list",{})
large_community = match_data.setdefault(
- "large-community-list", {}
+ "large_community", {}
+ )
+ large_community_list = match_data.setdefault(
+ "large_community_list", {}
)
- tag = match_data.setdefault("tag", None)
if ipv4_data:
- prefix_name = ipv4_data.setdefault("prefix_lists",
- None)
+ # fetch prefix list data from rmap
+ prefix_name = \
+ ipv4_data.setdefault("prefix_lists",
+ None)
if prefix_name:
- rmap_data.append("match ip address prefix-list"
- " {}".format(prefix_name))
+ rmap_data.append("match ip address"
+ " prefix-list {}".format(prefix_name))
+
+ # fetch tag data from rmap
+ tag = ipv4_data.setdefault("tag", None)
+ if tag:
+ rmap_data.append("match tag {}".format(tag))
+
+ # fetch large community data from rmap
+ large_community_list = ipv4_data.setdefault(
+ "large_community_list",{})
+ large_community = match_data.setdefault(
+ "large_community", {})
+
if ipv6_data:
prefix_name = ipv6_data.setdefault("prefix_lists",
None)
if prefix_name:
- rmap_data.append("match ipv6 address "
- "prefix-list {}".
- format(prefix_name))
- if tag:
- rmap_data.append("match tag {}".format(tag))
+ rmap_data.append("match ipv6 address"
+ " prefix-list {}".format(prefix_name))
+
+ # fetch tag data from rmap
+ tag = ipv6_data.setdefault("tag", None)
+ if tag:
+ rmap_data.append("match tag {}".format(tag))
+
+ # fetch large community data from rmap
+ large_community_list = ipv6_data.setdefault(
+ "large_community_list",{})
+ large_community = match_data.setdefault(
+ "large_community", {})
if community:
if "id" not in community:
@@ -1293,10 +1339,9 @@ def create_route_maps(tgen, input_dict, build=False):
cmd = "{} exact-match".format(cmd)
rmap_data.append(cmd)
-
if large_community:
if "id" not in large_community:
- logger.error("'num' is mandatory for "
+ logger.error("'id' is mandatory for "
"large-community-list in match "
"criteria")
return False
@@ -1306,7 +1351,19 @@ def create_route_maps(tgen, input_dict, build=False):
"exact_match", False)
if exact_match:
cmd = "{} exact-match".format(cmd)
-
+ rmap_data.append(cmd)
+ if large_community_list:
+ if "id" not in large_community_list:
+ logger.error("'id' is mandatory for "
+ "large-community-list in match "
+ "criteria")
+ return False
+ cmd = "match large-community {}".format(
+ large_community_list["id"])
+ exact_match = large_community_list.setdefault(
+ "exact_match", False)
+ if exact_match:
+ cmd = "{} exact-match".format(cmd)
rmap_data.append(cmd)
result = create_common_configuration(tgen, router,
@@ -1320,10 +1377,172 @@ def create_route_maps(tgen, input_dict, build=False):
logger.error(errormsg)
return errormsg
- logger.debug("Exiting lib API: create_prefix_lists()")
+ logger.debug("Exiting lib API: create_route_maps()")
+ return result
+
+
+def delete_route_maps(tgen, input_dict):
+ """
+ Delete ip route maps from device
+
+ * `tgen` : Topogen object
+ * `input_dict` : for which router,
+ route map has to be deleted
+
+ Usage
+ -----
+ # Delete route-map rmap_1 and rmap_2 from router r1
+ input_dict = {
+ "r1": {
+ "route_maps": ["rmap_1", "rmap__2"]
+ }
+ }
+ result = delete_route_maps("ipv4", input_dict)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+ logger.info("Entering lib API: delete_route_maps()")
+
+ for router in input_dict.keys():
+ route_maps = input_dict[router]["route_maps"][:]
+ rmap_data = input_dict[router]
+ rmap_data["route_maps"] = {}
+ for route_map_name in route_maps:
+ rmap_data["route_maps"].update({
+ route_map_name:
+ [{
+ "delete": True
+ }]
+ })
+
+ return create_route_maps(tgen, input_dict)
+
+
+def create_bgp_community_lists(tgen, input_dict, build=False):
+ """
+ Create bgp community-list or large-community-list on the devices as per
+ the arguments passed. Takes list of communities in input.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `build` : Only for initial setup phase this is set as True.
+ Usage
+ -----
+ input_dict_1 = {
+ "r3": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "rmap_lcomm_{}".format(addr_type),
+ "value": "1:1:1 1:2:3 2:1:1 2:2:2",
+ "large": True
+ }
+ ]
+ }
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_1)
+ """
+
+ result = False
+ logger.debug("Entering lib API: create_bgp_community_lists()")
+ input_dict = deepcopy(input_dict)
+ try:
+ for router in input_dict.keys():
+ if "bgp_community_lists" not in input_dict[router]:
+ errormsg = "bgp_community_lists not present in input_dict"
+ logger.debug(errormsg)
+ continue
+
+ config_data = []
+
+ community_list = input_dict[router]["bgp_community_lists"]
+ for community_dict in community_list:
+ del_action = community_dict.setdefault("delete", False)
+ community_type = community_dict.setdefault("community_type",
+ None)
+ action = community_dict.setdefault("action", None)
+ value = community_dict.setdefault("value", '')
+ large = community_dict.setdefault("large", None)
+ name = community_dict.setdefault("name", None)
+ if large:
+ cmd = "bgp large-community-list"
+ else:
+ cmd = "bgp community-list"
+
+ if not large and not (community_type and action and value):
+ errormsg = "community_type, action and value are " \
+ "required in bgp_community_list"
+ logger.error(errormsg)
+ return False
+
+ try:
+ community_type = int(community_type)
+ cmd = "{} {} {} {}".format(cmd, community_type, action,
+ value)
+ except ValueError:
+
+ cmd = "{} {} {} {} {}".format(
+ cmd, community_type, name, action, value)
+
+ if del_action:
+ cmd = "no {}".format(cmd)
+
+ config_data.append(cmd)
+
+ result = create_common_configuration(tgen, router, config_data,
+ "bgp_community_list",
+ build=build)
+
+ except InvalidCLIError:
+ # Traceback
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: create_bgp_community_lists()")
return result
+def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False):
+ """
+ Shutdown or bringup router's interface "
+
+ * `tgen` : Topogen object
+ * `dut` : Device under test
+ * `intf_name` : Interface name to be shut/no shut
+ * `ifaceaction` : Action, to shut/no shut interface,
+ by default is False
+
+ Usage
+ -----
+ dut = "r3"
+ intf = "r3-r1-eth0"
+ # Shut down ineterface
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ # Bring up ineterface
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ router_list = tgen.routers()
+ if ifaceaction:
+ logger.info("Bringing up interface : {}".format(intf_name))
+ else:
+ logger.info("Shutting down interface : {}".format(intf_name))
+
+ interface_set_status(router_list[dut], intf_name, ifaceaction)
+
+
#############################################
# Verification APIs
#############################################
@@ -1625,5 +1844,191 @@ def verify_prefix_lists(tgen, input_dict):
logger.info("Prefix list %s is/are not present in the router"
" from router %s", prefix_list, router)
- logger.debug("Exiting lib API: verify_prefix_lissts()")
+ logger.debug("Exiting lib API: verify_prefix_lists()")
+ return True
+
+
+@retry(attempts=2, wait=4, return_is_str=True, initial_wait=2)
+def verify_route_maps(tgen, input_dict):
+ """
+ Running "show route-map" command and verifying given route-map
+ is present in router.
+ Parameters
+ ----------
+ * `tgen` : topogen object
+ * `input_dict`: data to verify prefix lists
+ Usage
+ -----
+ # To verify rmap_1 and rmap_2 are present in router r1
+ input_dict = {
+ "r1": {
+ "route_maps": ["rmap_1", "rmap_2"]
+ }
+ }
+ result = verify_route_maps(tgen, input_dict)
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: verify_route_maps()")
+
+ for router in input_dict.keys():
+ if router not in tgen.routers():
+ continue
+
+ rnode = tgen.routers()[router]
+ # Show ip route-map
+ show_route_maps = rnode.vtysh_cmd("show route-map")
+
+ # Verify route-map is deleted
+ route_maps = input_dict[router]["route_maps"]
+ for route_map in route_maps:
+ if route_map in show_route_maps:
+ errormsg = ("Route map {} is not deleted from router"
+ " {}".format(route_map, router))
+ return errormsg
+
+ logger.info("Route map %s is/are deleted successfully from"
+ " router %s", route_maps, router)
+
+ logger.debug("Exiting lib API: verify_route_maps()")
+ return True
+
+
+@retry(attempts=3, wait=4, return_is_str=True)
+def verify_bgp_community(tgen, addr_type, router, network, input_dict=None):
+ """
+ API to veiryf BGP large community is attached in route for any given
+ DUT by running "show bgp ipv4/6 {route address} json" command.
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `addr_type` : ip type, ipv4/ipv6
+ * `dut`: Device Under Test
+ * `network`: network for which set criteria needs to be verified
+ * `input_dict`: having details like - for which router, community and
+ values needs to be verified
+ Usage
+ -----
+ networks = ["200.50.2.0/32"]
+ input_dict = {
+ "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ result = verify_bgp_community(tgen, "ipv4", dut, network, input_dict=None)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.info("Entering lib API: verify_bgp_community()")
+ if router not in tgen.routers():
+ return False
+
+ rnode = tgen.routers()[router]
+
+ logger.debug("Verifying BGP community attributes on dut %s: for %s "
+ "network %s", router, addr_type, network)
+
+ for net in network:
+ cmd = "show bgp {} {} json".format(addr_type, net)
+ show_bgp_json = rnode.vtysh_cmd(cmd, isjson=True)
+ logger.info(show_bgp_json)
+ if "paths" not in show_bgp_json:
+ return "Prefix {} not found in BGP table of router: {}". \
+ format(net, router)
+
+ as_paths = show_bgp_json["paths"]
+ found = False
+ for i in range(len(as_paths)):
+ if "largeCommunity" in show_bgp_json["paths"][i] or \
+ "community" in show_bgp_json["paths"][i]:
+ found = True
+ logger.info("Large Community attribute is found for route:"
+ " %s in router: %s", net, router)
+ if input_dict is not None:
+ for criteria, comm_val in input_dict.items():
+ show_val = show_bgp_json["paths"][i][criteria][
+ "string"]
+ if comm_val == show_val:
+ logger.info("Verifying BGP %s for prefix: %s"
+ " in router: %s, found expected"
+ " value: %s", criteria, net, router,
+ comm_val)
+ else:
+ errormsg = "Failed: Verifying BGP attribute" \
+ " {} for route: {} in router: {}" \
+ ", expected value: {} but found" \
+ ": {}".format(
+ criteria, net, router, comm_val,
+ show_val)
+ return errormsg
+
+ if not found:
+ errormsg = (
+ "Large Community attribute is not found for route: "
+ "{} in router: {} ".format(net, router))
+ return errormsg
+
+ logger.debug("Exiting lib API: verify_bgp_community()")
return True
+
+
+def verify_create_community_list(tgen, input_dict):
+ """
+ API is to verify if large community list is created for any given DUT in
+ input_dict by running "sh bgp large-community-list {"comm_name"} detail"
+ command.
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `input_dict`: having details like - for which router, large community
+ needs to be verified
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "large-community-list": {
+ "standard": {
+ "Test1": [{"action": "PERMIT", "attribute":\
+ ""}]
+ }}}}
+ result = verify_create_community_list(tgen, input_dict)
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: verify_create_community_list()")
+
+ for router in input_dict.keys():
+ if router not in tgen.routers():
+ continue
+
+ rnode = tgen.routers()[router]
+
+ logger.info("Verifying large-community is created for dut %s:",
+ router)
+
+ for comm_data in input_dict[router]["bgp_community_lists"]:
+ comm_name = comm_data["name"]
+ comm_type = comm_data["community_type"]
+ show_bgp_community = \
+ run_frr_cmd(rnode,
+ "show bgp large-community-list {} detail".
+ format(comm_name))
+
+ # Verify community list and type
+ if comm_name in show_bgp_community and comm_type in \
+ show_bgp_community:
+ logger.info("BGP %s large-community-list %s is"
+ " created", comm_type, comm_name)
+ else:
+ errormsg = "BGP {} large-community-list {} is not" \
+ " created".format(comm_type, comm_name)
+ return errormsg
+
+ logger.debug("Exiting lib API: verify_create_community_list()")
+ return True
diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py
index 7a00fe4c5..fff5a1e82 100644
--- a/tests/topotests/lib/topojson.py
+++ b/tests/topotests/lib/topojson.py
@@ -35,6 +35,7 @@ from lib.common_config import (
create_static_routes,
create_prefix_lists,
create_route_maps,
+ create_bgp_community_lists
)
from lib.bgp import create_router_bgp
@@ -179,6 +180,7 @@ def build_config_from_json(tgen, topo, save_bkup=True):
("links", create_interfaces_cfg),
("static_routes", create_static_routes),
("prefix_lists", create_prefix_lists),
+ ("bgp_community_list", create_bgp_community_lists),
("route_maps", create_route_maps),
("bgp", create_router_bgp)
])
diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini
index b65f93856..62c825341 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-ecmp-topo2
+norecursedirs = .git example-test example-topojson-test lib docker bgp_rr_ibgp
[topogen]
# Default configuration values
diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c
index b4049b55e..54089b361 100644
--- a/vrrpd/vrrp.c
+++ b/vrrpd/vrrp.c
@@ -281,7 +281,7 @@ void vrrp_check_start(struct vrrp_vrouter *vr)
{
struct vrrp_router *r;
bool start;
- const char *whynot = NULL;
+ const char *whynot;
if (vr->shutdown || vr->ifp == NULL)
return;
@@ -289,27 +289,28 @@ void vrrp_check_start(struct vrrp_vrouter *vr)
r = vr->v4;
/* Must not already be started */
start = r->fsm.state == VRRP_STATE_INITIALIZE;
+ whynot = NULL;
/* Must have a parent interface */
start = start && (vr->ifp != NULL);
- whynot = (!start && !whynot) ? "No base interface" : NULL;
+ whynot = (!start && !whynot) ? "No base interface" : whynot;
#if 0
/* Parent interface must be up */
start = start && if_is_operative(vr->ifp);
#endif
/* Parent interface must have at least one v4 */
start = start && vr->ifp->connected->count > 1;
- whynot = (!start && !whynot) ? "No primary IPv4 address" : NULL;
+ whynot = (!start && !whynot) ? "No primary IPv4 address" : whynot;
/* Must have a macvlan interface */
start = start && (r->mvl_ifp != NULL);
- whynot = (!start && !whynot) ? "No VRRP interface" : NULL;
+ whynot = (!start && !whynot) ? "No VRRP interface" : whynot;
#if 0
/* Macvlan interface must be admin up */
start = start && CHECK_FLAG(r->mvl_ifp->flags, IFF_UP);
#endif
/* Must have at least one VIP configured */
start = start && r->addrs->count > 0;
- whynot =
- (!start && !whynot) ? "No Virtual IP address configured" : NULL;
+ whynot = (!start && !whynot) ? "No Virtual IP address configured"
+ : whynot;
if (start)
vrrp_event(r, VRRP_EVENT_STARTUP);
else if (whynot)
@@ -320,19 +321,20 @@ void vrrp_check_start(struct vrrp_vrouter *vr)
r = vr->v6;
/* Must not already be started */
start = r->fsm.state == VRRP_STATE_INITIALIZE;
+ whynot = NULL;
/* Must not be v2 */
start = start && vr->version != 2;
- whynot = (!start && !whynot) ? "VRRPv2 does not support v6" : NULL;
+ whynot = (!start && !whynot) ? "VRRPv2 does not support v6" : whynot;
/* Must have a parent interface */
start = start && (vr->ifp != NULL);
- whynot = (!start && !whynot) ? "No base interface" : NULL;
+ whynot = (!start && !whynot) ? "No base interface" : whynot;
#if 0
/* Parent interface must be up */
start = start && if_is_operative(vr->ifp);
#endif
/* Must have a macvlan interface */
start = start && (r->mvl_ifp != NULL);
- whynot = (!start && !whynot) ? "No VRRP interface" : NULL;
+ whynot = (!start && !whynot) ? "No VRRP interface" : whynot;
#if 0
/* Macvlan interface must be admin up */
start = start && CHECK_FLAG(r->mvl_ifp->flags, IFF_UP);
@@ -893,7 +895,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src,
THREAD_OFF(r->t_adver_timer);
thread_add_timer_msec(
master, vrrp_adver_timer_expire, r,
- r->vr->advertisement_interval * 10,
+ r->vr->advertisement_interval * CS2MS,
&r->t_adver_timer);
} else if (pkt->hdr.priority > r->priority
|| ((pkt->hdr.priority == r->priority)
@@ -913,7 +915,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src,
THREAD_OFF(r->t_master_down_timer);
thread_add_timer_msec(master,
vrrp_master_down_timer_expire, r,
- r->master_down_interval * 10,
+ r->master_down_interval * CS2MS,
&r->t_master_down_timer);
vrrp_change_state(r, VRRP_STATE_BACKUP);
} else {
@@ -931,7 +933,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src,
THREAD_OFF(r->t_master_down_timer);
thread_add_timer_msec(
master, vrrp_master_down_timer_expire, r,
- r->skew_time * 10, &r->t_master_down_timer);
+ r->skew_time * CS2MS, &r->t_master_down_timer);
} else if (r->vr->preempt_mode == false
|| pkt->hdr.priority >= r->priority) {
if (r->vr->version == 3) {
@@ -942,7 +944,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src,
THREAD_OFF(r->t_master_down_timer);
thread_add_timer_msec(master,
vrrp_master_down_timer_expire, r,
- r->master_down_interval * 10,
+ r->master_down_interval * CS2MS,
&r->t_master_down_timer);
} else if (r->vr->preempt_mode == true
&& pkt->hdr.priority < r->priority) {
@@ -1456,7 +1458,7 @@ static int vrrp_adver_timer_expire(struct thread *thread)
/* Reset the Adver_Timer to Advertisement_Interval */
thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
- r->vr->advertisement_interval * 10,
+ r->vr->advertisement_interval * CS2MS,
&r->t_adver_timer);
} else {
zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
@@ -1480,7 +1482,7 @@ static int vrrp_master_down_timer_expire(struct thread *thread)
r->vr->vrid, family2str(r->family));
thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
- r->vr->advertisement_interval * 10,
+ r->vr->advertisement_interval * CS2MS,
&r->t_adver_timer);
vrrp_change_state(r, VRRP_STATE_MASTER);
@@ -1556,14 +1558,14 @@ static int vrrp_startup(struct vrrp_router *r)
if (r->priority == VRRP_PRIO_MASTER) {
thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
- r->vr->advertisement_interval * 10,
+ r->vr->advertisement_interval * CS2MS,
&r->t_adver_timer);
vrrp_change_state(r, VRRP_STATE_MASTER);
} else {
r->master_adver_interval = r->vr->advertisement_interval;
vrrp_recalculate_timers(r);
thread_add_timer_msec(master, vrrp_master_down_timer_expire, r,
- r->master_down_interval * 10,
+ r->master_down_interval * CS2MS,
&r->t_master_down_timer);
vrrp_change_state(r, VRRP_STATE_BACKUP);
}
diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c
index 2dc3d3f8a..239b02ee7 100644
--- a/vrrpd/vrrp_vty.c
+++ b/vrrpd/vrrp_vty.c
@@ -30,6 +30,7 @@
#include "vrrp.h"
#include "vrrp_debug.h"
#include "vrrp_vty.h"
+#include "vrrp_zebra.h"
#ifndef VTYSH_EXTRACT_PL
#include "vrrpd/vrrp_vty_clippy.c"
#endif
@@ -144,10 +145,11 @@ DEFPY(vrrp_advertisement_interval,
struct vrrp_vrouter *vr;
uint16_t newadvint =
- no ? vd.advertisement_interval * 10 : advertisement_interval;
+ no ? vd.advertisement_interval * CS2MS : advertisement_interval;
- if (newadvint % 10 != 0) {
- vty_out(vty, "%% Value must be a multiple of 10\n");
+ if (newadvint % CS2MS != 0) {
+ vty_out(vty, "%% Value must be a multiple of %u\n",
+ (unsigned int)CS2MS);
return CMD_WARNING_CONFIG_FAILED;
}
@@ -326,8 +328,9 @@ DEFPY(vrrp_default,
"Force VRRP router into administrative shutdown\n")
{
if (adv) {
- if (advint % 10 != 0) {
- vty_out(vty, "%% Value must be a multiple of 10\n");
+ if (advint % CS2MS != 0) {
+ vty_out(vty, "%% Value must be a multiple of %u\n",
+ (unsigned int)CS2MS);
return CMD_WARNING_CONFIG_FAILED;
}
/* all internal computations are in centiseconds */
diff --git a/vrrpd/vrrp_zebra.c b/vrrpd/vrrp_zebra.c
index 72b77c131..a6c575f8d 100644
--- a/vrrpd/vrrp_zebra.c
+++ b/vrrpd/vrrp_zebra.c
@@ -80,83 +80,36 @@ static int vrrp_router_id_update_zebra(int command, struct zclient *zclient,
return 0;
}
-static int vrrp_zebra_if_add(int command, struct zclient *zclient,
- zebra_size_t length, vrf_id_t vrf_id)
+int vrrp_ifp_create(struct interface *ifp)
{
- struct interface *ifp;
-
- /*
- * zebra api adds/dels interfaces using the same call
- * interface_add_read below, see comments in lib/zclient.c
- */
- ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
-
- if (!ifp)
- return 0;
-
- vrrp_zebra_debug_if_state(ifp, vrf_id, __func__);
+ vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__);
vrrp_if_add(ifp);
return 0;
}
-static int vrrp_zebra_if_del(int command, struct zclient *zclient,
- zebra_size_t length, vrf_id_t vrf_id)
+int vrrp_ifp_destroy(struct interface *ifp)
{
- struct interface *ifp;
-
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
- if (!ifp)
- return 0;
-
- vrrp_zebra_debug_if_state(ifp, vrf_id, __func__);
+ vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__);
vrrp_if_del(ifp);
- if_set_index(ifp, IFINDEX_INTERNAL);
-
return 0;
}
-static int vrrp_zebra_if_state_up(int command, struct zclient *zclient,
- zebra_size_t length, vrf_id_t vrf_id)
+int vrrp_ifp_up(struct interface *ifp)
{
- struct interface *ifp;
-
- /*
- * zebra api notifies interface up/down events by using the same call
- * zebra_interface_state_read below, see comments in lib/zclient.c ifp =
- * zebra_interface_state_read(zclient->ibuf, vrf_id);
- */
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
- if (!ifp)
- return 0;
-
- vrrp_zebra_debug_if_state(ifp, vrf_id, __func__);
+ vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__);
vrrp_if_up(ifp);
return 0;
}
-static int vrrp_zebra_if_state_down(int command, struct zclient *zclient,
- zebra_size_t length, vrf_id_t vrf_id)
+int vrrp_ifp_down(struct interface *ifp)
{
- struct interface *ifp;
-
- /*
- * zebra api notifies interface up/down events by using the same call
- * zebra_interface_state_read below, see comments in lib/zclient.c
- */
- ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
-
- if (!ifp)
- return 0;
-
- vrrp_zebra_debug_if_state(ifp, vrf_id, __func__);
+ vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__);
vrrp_if_down(ifp);
@@ -238,15 +191,14 @@ int vrrp_zclient_send_interface_protodown(struct interface *ifp, bool down)
void vrrp_zebra_init(void)
{
+ if_zapi_callbacks(vrrp_ifp_create, vrrp_ifp_up,
+ vrrp_ifp_down, vrrp_ifp_destroy);
+
/* Socket for receiving updates from Zebra daemon */
zclient = zclient_new(master, &zclient_options_default);
zclient->zebra_connected = vrrp_zebra_connected;
zclient->router_id_update = vrrp_router_id_update_zebra;
- zclient->interface_add = vrrp_zebra_if_add;
- zclient->interface_delete = vrrp_zebra_if_del;
- zclient->interface_up = vrrp_zebra_if_state_up;
- zclient->interface_down = vrrp_zebra_if_state_down;
zclient->interface_address_add = vrrp_zebra_if_address_add;
zclient->interface_address_delete = vrrp_zebra_if_address_del;
diff --git a/vrrpd/vrrp_zebra.h b/vrrpd/vrrp_zebra.h
index 84bcba23c..02d7055b8 100644
--- a/vrrpd/vrrp_zebra.h
+++ b/vrrpd/vrrp_zebra.h
@@ -29,4 +29,9 @@ extern void vrrp_zebra_radv_set(struct vrrp_router *r, bool enable);
extern int vrrp_zclient_send_interface_protodown(struct interface *ifp,
bool down);
+extern int vrrp_ifp_create(struct interface *ifp);
+extern int vrrp_ifp_up(struct interface *ifp);
+extern int vrrp_ifp_down(struct interface *ifp);
+extern int vrrp_ifp_destroy(struct interface *ifp);
+
#endif /* __VRRP_ZEBRA_H__ */
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index a762e9555..643dcb7ed 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -492,6 +492,7 @@ static int vtysh_execute_func(const char *line, int pager)
*/
while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON
&& ret != CMD_WARNING && ret != CMD_WARNING_CONFIG_FAILED
+ && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
&& vty->node > CONFIG_NODE) {
vty->node = node_parent(vty->node);
ret = cmd_execute(vty, line, &cmd, 1);
@@ -777,6 +778,7 @@ int vtysh_mark_file(const char *filename)
*/
while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON
&& ret != CMD_WARNING && ret != CMD_WARNING_CONFIG_FAILED
+ && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
&& vty->node > CONFIG_NODE) {
vty->node = node_parent(vty->node);
ret = cmd_execute_command_strict(vline, vty, &cmd);
@@ -1337,7 +1339,7 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end",
}
DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd,
- "router bgp [(1-4294967295)$instasn [<view|vrf> WORD]]",
+ "router bgp [(1-4294967295) [<view|vrf> WORD]]",
ROUTER_STR BGP_STR AS_STR
"BGP view\nBGP VRF\n"
"View/VRF name\n")
@@ -2253,6 +2255,7 @@ DEFUN (vtysh_show_poll,
return ret;
}
+#ifndef EXCLUDE_CPU_TIME
DEFUN (vtysh_show_thread,
vtysh_show_thread_cmd,
"show thread cpu [FILTER]",
@@ -2279,6 +2282,7 @@ DEFUN (vtysh_show_thread,
}
return ret;
}
+#endif
DEFUN (vtysh_show_work_queues,
vtysh_show_work_queues_cmd,
@@ -2422,6 +2426,55 @@ DEFUN (vtysh_show_error_code,
return CMD_SUCCESS;
}
+/* Northbound. */
+DEFUN (show_yang_operational_data,
+ show_yang_operational_data_cmd,
+ "show yang operational-data XPATH\
+ [{\
+ format <json|xml>\
+ |translate WORD\
+ }]" DAEMONS_LIST,
+ SHOW_STR
+ "YANG information\n"
+ "Show YANG operational data\n"
+ "XPath expression specifying the YANG data path\n"
+ "Set the output format\n"
+ "JavaScript Object Notation\n"
+ "Extensible Markup Language\n"
+ "Translate operational data\n"
+ "YANG module translator\n"
+ DAEMONS_STR)
+{
+ int idx_protocol = argc - 1;
+ char *fcmd = argv_concat(argv, argc - 1, 0);
+ int ret = vtysh_client_execute_name(argv[idx_protocol]->text, fcmd);
+ XFREE(MTYPE_TMP, fcmd);
+ return ret;
+}
+
+DEFUNSH(VTYSH_ALL, debug_nb,
+ debug_nb_cmd,
+ "[no] debug northbound\
+ [<\
+ callbacks [{configuration|state|rpc}]\
+ |notifications\
+ |events\
+ |libyang\
+ >]",
+ NO_STR
+ DEBUG_STR
+ "Northbound debugging\n"
+ "Callbacks\n"
+ "Configuration\n"
+ "State\n"
+ "RPC\n"
+ "Notifications\n"
+ "Events\n"
+ "libyang debugging\n")
+{
+ return CMD_SUCCESS;
+}
+
/* Memory */
DEFUN (vtysh_show_memory,
vtysh_show_memory_cmd,
@@ -2548,10 +2601,11 @@ DEFUNSH(VTYSH_ALL, vtysh_log_facility, vtysh_log_facility_cmd,
}
DEFUNSH(VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd,
- "no log facility [FACILITY]", NO_STR
+ "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
+ NO_STR
"Logging control\n"
"Reset syslog facility to default (daemon)\n"
- "Syslog facility\n")
+ LOG_FACILITY_DESC)
{
return CMD_SUCCESS;
}
@@ -4017,12 +4071,19 @@ void vtysh_init_vty(void)
install_element(ENABLE_NODE, &vtysh_debug_memstats_cmd);
install_element(CONFIG_NODE, &vtysh_debug_memstats_cmd);
+ /* northbound */
+ install_element(VIEW_NODE, &show_yang_operational_data_cmd);
+ install_element(ENABLE_NODE, &debug_nb_cmd);
+ install_element(CONFIG_NODE, &debug_nb_cmd);
+
/* misc lib show commands */
install_element(VIEW_NODE, &vtysh_show_memory_cmd);
install_element(VIEW_NODE, &vtysh_show_modules_cmd);
install_element(VIEW_NODE, &vtysh_show_work_queues_cmd);
install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd);
+#ifndef EXCLUDE_CPU_TIME
install_element(VIEW_NODE, &vtysh_show_thread_cmd);
+#endif
install_element(VIEW_NODE, &vtysh_show_poll_cmd);
/* Logging */
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 3ec2eb239..e56c6fbf4 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -406,7 +406,9 @@ void vtysh_config_parse_line(void *arg, const char *line)
== 0
|| strncmp(line, "frr", strlen("frr")) == 0
|| strncmp(line, "agentx", strlen("agentx")) == 0
- || strncmp(line, "no log", strlen("no log")) == 0)
+ || strncmp(line, "no log", strlen("no log")) == 0
+ || strncmp(line, "no ip prefix-list", strlen("no ip prefix-list")) == 0
+ || strncmp(line, "no ipv6 prefix-list", strlen("no ipv6 prefix-list")) == 0)
config_add_line_uniq(config_top, line);
else
config_add_line(config_top, line);
diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c
index a6a910a1d..ea5965582 100644
--- a/watchfrr/watchfrr.c
+++ b/watchfrr/watchfrr.c
@@ -460,12 +460,20 @@ static int run_job(struct restart_info *restart, const char *cmdtype,
return -1;
}
+#if defined HAVE_SYSTEMD
+ char buffer[512];
+
+ snprintf(buffer, sizeof(buffer), "restarting %s", restart->name);
+ systemd_send_status(buffer);
+#endif
+
/* Note: time_elapsed test must come before the force test, since we
need
to make sure that delay is initialized for use below in updating the
restart interval. */
if ((time_elapsed(&delay, &restart->time)->tv_sec < restart->interval)
&& !force) {
+
if (gs.loglevel > LOG_DEBUG + 1)
zlog_debug(
"postponing %s %s: "
@@ -490,6 +498,9 @@ static int run_job(struct restart_info *restart, const char *cmdtype,
restart->pid = 0;
}
+#if defined HAVE_SYSTEMD
+ systemd_send_status("FRR Operational");
+#endif
/* Calculate the new restart interval. */
if (update_interval) {
if (delay.tv_sec > 2 * gs.max_restart_interval)
@@ -707,6 +718,7 @@ static void daemon_send_ready(int exitcode)
fclose(fp);
#if defined HAVE_SYSTEMD
systemd_send_started(master, 0);
+ systemd_send_status("FRR Operational");
#endif
sent = 1;
}
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 3313dc2f2..faa880eff 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -61,6 +61,13 @@ module frr-isisd {
"This type defines IS-IS level of an object.";
}
+ typedef extended-circuit-id {
+ type uint32;
+ description
+ "This type defines the extended circuit ID
+ associated with an interface.";
+ }
+
typedef network-type {
type enumeration {
enum "unknown" {
@@ -95,6 +102,20 @@ module frr-isisd {
pattern, An example LSP ID is 0143.0438.AeF0.02-01";
}
+ typedef snpa {
+ type string {
+ length "0 .. 20";
+ }
+ description
+ "This type defines the Subnetwork Point
+ of Attachment (SNPA) format.
+ The SNPA should be encoded according to the rules
+ specified for the particular type of subnetwork
+ being used. As an example, for an ethernet subnetwork,
+ the SNPA is encoded as a MAC address like
+ '00aa.bbcc.ddee'.";
+ }
+
typedef system-id {
type string {
pattern "[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}";
@@ -275,6 +296,399 @@ module frr-isisd {
}
}
+ grouping interface-config {
+ description "Interface configuration grouping";
+
+ leaf area-tag {
+ type string;
+ mandatory true;
+ description
+ "Area-tag associated to this circuit.";
+ }
+
+ leaf ipv4-routing {
+ type boolean;
+ default "false";
+ description
+ "Routing IS-IS IPv4 traffic over this circuit.";
+ }
+
+ leaf ipv6-routing {
+ type boolean;
+ default "false";
+ description
+ "Routing IS-IS IPv6 traffic over this circuit.";
+ }
+
+ leaf circuit-type {
+ type level;
+ default "level-1-2";
+ description
+ "IS-type of this circuit.";
+ }
+
+ leaf bfd-monitoring {
+ type boolean;
+ default false;
+ description "Monitor IS-IS peers on this circuit.";
+ }
+
+ container csnp-interval {
+ description
+ "Complete Sequence Number PDU (CSNP) generation interval.";
+ leaf level-1 {
+ type uint16 {
+ range "1..600";
+ }
+ units "seconds";
+ default "10";
+ description
+ "CNSP interval for level-1";
+ }
+
+ leaf level-2 {
+ type uint16 {
+ range "1..600";
+ }
+ units "seconds";
+ default "10";
+ description
+ "CNSP interval for level-2";
+ }
+ }
+
+ container psnp-interval {
+ description
+ "Partial Sequence Number PDU (PSNP) generation interval.";
+ leaf level-1 {
+ type uint16 {
+ range "1..120";
+ }
+ units "seconds";
+ default "2";
+ description
+ "PNSP interval for level-1";
+ }
+
+ leaf level-2 {
+ type uint16 {
+ range "1..120";
+ }
+ units "seconds";
+ default "2";
+ description
+ "PCNSP interval for level-2";
+ }
+ }
+
+ container hello {
+ description
+ "Parameters related to IS-IS hello PDUs.";
+ leaf padding {
+ type boolean;
+ default "true";
+ description
+ "Add padding to IS-IS hello PDUs.";
+ }
+
+ container interval {
+ description
+ "Interval between consecutive hello messages.";
+ leaf level-1 {
+ type uint32 {
+ range "1..600";
+ }
+ units "seconds";
+ default "3";
+ description
+ "Holding time for level-1; interval will depend on multiplier.";
+ }
+
+ leaf level-2 {
+ type uint32 {
+ range "1..600";
+ }
+ units "seconds";
+ default "3";
+ description
+ "Holding time for level-2; interval will depend on multiplier.";
+ }
+ }
+
+ container multiplier {
+ description
+ "Multiplier for the hello messages holding time.";
+ leaf level-1 {
+ type uint16 {
+ range "2..100";
+ }
+ default "10";
+ description
+ "Multiplier for the hello holding time.";
+ }
+
+ leaf level-2 {
+ type uint16 {
+ range "2..100";
+ }
+ default "10";
+ description
+ "Multiplier for the hello holding time.";
+ }
+ }
+ }
+
+ container metric {
+ description
+ "Default metric for this IS-IS circuit.";
+ leaf level-1 {
+ type uint32 {
+ range "0..16777215";
+ }
+ must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'";
+ default "10";
+ description
+ "Default level-1 metric for this IS-IS circuit.";
+ }
+
+ leaf level-2 {
+ type uint32 {
+ range "0..16777215";
+ }
+ must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'";
+ default "10";
+ description
+ "Default level-2 metric for this IS-IS circuit.";
+ }
+ }
+
+ container priority {
+ description
+ "Priority for Designated Router election.";
+ leaf level-1 {
+ type uint8 {
+ range "0..127";
+ }
+ default "64";
+ description
+ "Level-1 priority for this IS-IS circuit.";
+ }
+
+ leaf level-2 {
+ type uint8 {
+ range "0..127";
+ }
+ default "64";
+ description
+ "Level-2 priority for this IS-IS circuit.";
+ }
+ }
+
+ leaf network-type {
+ type network-type;
+ default "broadcast";
+ must "(. = \"point-to-point\") or (. = \"broadcast\")";
+ description
+ "Explicitly configured type of IS-IS circuit (broadcast or point-to-point).";
+ }
+
+ leaf passive {
+ type boolean;
+ default "false";
+ description
+ "Interface is in passive mode.";
+ }
+
+ container password {
+ presence "Present if a password is set for this IS interface.";
+ uses isis-password;
+ }
+
+ leaf disable-three-way-handshake {
+ type boolean;
+ default "false";
+ description
+ "Disables three-way handshake when creating new adjacencies.";
+ }
+
+ container multi-topology {
+ description
+ "IS-IS topologies configured on this circuit.";
+ leaf ipv4-unicast {
+ type boolean;
+ default "true";
+ description
+ "IPv4 unicast topology.";
+ }
+
+ leaf ipv4-multicast {
+ type boolean;
+ default "true";
+ description
+ "IPv4 multicast topology.";
+ }
+
+ leaf ipv4-management {
+ type boolean;
+ default "true";
+ description
+ "IPv4 management topology.";
+ }
+
+ leaf ipv6-unicast {
+ type boolean;
+ default "true";
+ description
+ "IPv6 unicast topology.";
+ }
+
+ leaf ipv6-multicast {
+ type boolean;
+ default "true";
+ description
+ "IPv6 multicast topology.";
+ }
+
+ leaf ipv6-management {
+ type boolean;
+ default "true";
+ description
+ "IPv6 management topology.";
+ }
+
+ leaf ipv6-dstsrc {
+ type boolean;
+ default "true";
+ description
+ "IPv6 destination-source topology.";
+ }
+ }
+ }
+
+ grouping adjacency-state {
+ container adjacencies {
+ config false;
+ list adjacency {
+ leaf neighbor-sys-type {
+ type level;
+ description
+ "Level capability of neighboring system";
+ }
+ leaf neighbor-sysid {
+ type system-id;
+ description
+ "The system-id of the neighbor";
+ }
+ leaf neighbor-extended-circuit-id {
+ type extended-circuit-id;
+ description
+ "Circuit ID of the neighbor";
+ }
+ leaf neighbor-snpa {
+ type snpa;
+ description
+ "SNPA of the neighbor";
+ }
+ leaf hold-timer {
+ type uint16;
+ units seconds;
+ description
+ "The holding time in seconds for this
+ adjacency. This value is based on
+ received hello PDUs and the elapsed
+ time since receipt.";
+ }
+ leaf neighbor-priority {
+ type uint8 {
+ range "0 .. 127";
+ }
+ description
+ "Priority of the neighboring IS for becoming
+ the DIS.";
+ }
+ leaf state {
+ type adj-state-type;
+ description
+ "This leaf describes the state of the interface.";
+ }
+
+ description
+ "List of operational adjacencies.";
+ }
+ description
+ "This container lists the adjacencies of
+ the local node.";
+ }
+ description
+ "Adjacency state";
+ }
+
+ grouping event-counters {
+ container event-counters {
+ config false;
+ leaf adjacency-changes {
+ type uint32;
+ description
+ "The number of times an adjacency state change has
+ occurred on this interface.";
+ }
+ leaf adjacency-number {
+ type uint32;
+ description
+ "The number of adjacencies on this interface.";
+ }
+ leaf init-fails {
+ type uint32;
+ description
+ "The number of times initialization of this
+ interface has failed. This counts events such
+ as PPP NCP failures. Failures to form an
+ adjacency are counted by adjacency-rejects.";
+ }
+ leaf adjacency-rejects {
+ type uint32;
+ description
+ "The number of times an adjacency has been
+ rejected on this interface.";
+ }
+ leaf id-len-mismatch {
+ type uint32;
+ description
+ "The number of times an IS-IS PDU with an ID
+ field length different from that for this
+ system has been received on this interface.";
+ }
+ leaf max-area-addresses-mismatch {
+ type uint32;
+ description
+ "The number of times an IS-IS PDU has been
+ received on this interface with the
+ max area address field differing from that of
+ this system.";
+ }
+ leaf authentication-type-fails {
+ type uint32;
+ description
+ "Number of authentication type mismatches.";
+ }
+ leaf authentication-fails {
+ type uint32;
+ description
+ "Number of authentication key failures.";
+ }
+ description "IS-IS interface event counters.";
+ }
+ description
+ "Grouping for IS-IS interface event counters";
+ }
+
+ grouping interface-state {
+ description
+ "IS-IS interface operational state.";
+ uses adjacency-state;
+ uses event-counters;
+ }
+
grouping notification-instance-hdr {
description
"Instance specific IS-IS notification data grouping";
@@ -313,7 +727,7 @@ module frr-isisd {
}
leaf extended-circuit-id {
- type uint32;
+ type extended-circuit-id;
description
"Eextended circuit-id of the interface.";
}
@@ -733,270 +1147,8 @@ module frr-isisd {
presence "Present if an IS-IS circuit is defined for this interface.";
description
"IS-IS interface parameters.";
- leaf area-tag {
- type string;
- mandatory true;
- description
- "Area-tag associated to this circuit.";
- }
-
- leaf ipv4-routing {
- type boolean;
- default "false";
- description
- "Routing IS-IS IPv4 traffic over this circuit.";
- }
-
- leaf ipv6-routing {
- type boolean;
- default "false";
- description
- "Routing IS-IS IPv6 traffic over this circuit.";
- }
-
- leaf circuit-type {
- type level;
- default "level-1-2";
- description
- "IS-type of this circuit.";
- }
-
- leaf bfd-monitoring {
- type boolean;
- default false;
- description "Monitor IS-IS peers on this circuit.";
- }
-
- container csnp-interval {
- description
- "Complete Sequence Number PDU (CSNP) generation interval.";
- leaf level-1 {
- type uint16 {
- range "1..600";
- }
- units "seconds";
- default "10";
- description
- "CNSP interval for level-1";
- }
-
- leaf level-2 {
- type uint16 {
- range "1..600";
- }
- units "seconds";
- default "10";
- description
- "CNSP interval for level-2";
- }
- }
-
- container psnp-interval {
- description
- "Partial Sequence Number PDU (PSNP) generation interval.";
- leaf level-1 {
- type uint16 {
- range "1..120";
- }
- units "seconds";
- default "2";
- description
- "PNSP interval for level-1";
- }
-
- leaf level-2 {
- type uint16 {
- range "1..120";
- }
- units "seconds";
- default "2";
- description
- "PCNSP interval for level-2";
- }
- }
-
- container hello {
- description
- "Parameters related to IS-IS hello PDUs.";
- leaf padding {
- type boolean;
- default "true";
- description
- "Add padding to IS-IS hello PDUs.";
- }
-
- container interval {
- description
- "Interval between consecutive hello messages.";
- leaf level-1 {
- type uint32 {
- range "1..600";
- }
- units "seconds";
- default "3";
- description
- "Holding time for level-1; interval will depend on multiplier.";
- }
-
- leaf level-2 {
- type uint32 {
- range "1..600";
- }
- units "seconds";
- default "3";
- description
- "Holding time for level-2; interval will depend on multiplier.";
- }
- }
-
- container multiplier {
- description
- "Multiplier for the hello messages holding time.";
- leaf level-1 {
- type uint16 {
- range "2..100";
- }
- default "10";
- description
- "Multiplier for the hello holding time.";
- }
-
- leaf level-2 {
- type uint16 {
- range "2..100";
- }
- default "10";
- description
- "Multiplier for the hello holding time.";
- }
- }
- }
-
- container metric {
- description
- "Default metric for this IS-IS circuit.";
- leaf level-1 {
- type uint32 {
- range "0..16777215";
- }
- must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'";
- default "10";
- description
- "Default level-1 metric for this IS-IS circuit.";
- }
-
- leaf level-2 {
- type uint32 {
- range "0..16777215";
- }
- must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'";
- default "10";
- description
- "Default level-2 metric for this IS-IS circuit.";
- }
- }
-
- container priority {
- description
- "Priority for Designated Router election.";
- leaf level-1 {
- type uint8 {
- range "0..127";
- }
- default "64";
- description
- "Level-1 priority for this IS-IS circuit.";
- }
-
- leaf level-2 {
- type uint8 {
- range "0..127";
- }
- default "64";
- description
- "Level-2 priority for this IS-IS circuit.";
- }
- }
-
- leaf network-type {
- type network-type;
- default "broadcast";
- must "(. = \"point-to-point\") or (. = \"broadcast\")";
- description
- "Explicitly configured type of IS-IS circuit (broadcast or point-to-point).";
- }
-
- leaf passive {
- type boolean;
- default "false";
- description
- "Interface is in passive mode.";
- }
-
- container password {
- presence "Present if a password is set for this IS interface.";
- uses isis-password;
- }
-
- leaf disable-three-way-handshake {
- type boolean;
- default "false";
- description
- "Disables three-way handshake when creating new adjacencies.";
- }
-
- container multi-topology {
- description
- "IS-IS topologies configured on this circuit.";
- leaf ipv4-unicast {
- type boolean;
- default "true";
- description
- "IPv4 unicast topology.";
- }
-
- leaf ipv4-multicast {
- type boolean;
- default "true";
- description
- "IPv4 multicast topology.";
- }
-
- leaf ipv4-management {
- type boolean;
- default "true";
- description
- "IPv4 management topology.";
- }
-
- leaf ipv6-unicast {
- type boolean;
- default "true";
- description
- "IPv6 unicast topology.";
- }
-
- leaf ipv6-multicast {
- type boolean;
- default "true";
- description
- "IPv6 multicast topology.";
- }
-
- leaf ipv6-management {
- type boolean;
- default "true";
- description
- "IPv6 management topology.";
- }
-
- leaf ipv6-dstsrc {
- type boolean;
- default "true";
- description
- "IPv6 destination-source topology.";
- }
- }
+ uses interface-config;
+ uses interface-state;
}
}
diff --git a/yang/frr-nexthop.yang b/yang/frr-nexthop.yang
new file mode 100644
index 000000000..7d8ce1b8e
--- /dev/null
+++ b/yang/frr-nexthop.yang
@@ -0,0 +1,209 @@
+module frr-nexthop {
+ yang-version 1.1;
+ namespace "http://frrouting.org/yang/nexthop";
+ prefix frr-nexthop;
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ import ietf-routing-types {
+ prefix rt-types;
+ }
+ import frr-interface {
+ prefix frr-interface;
+ }
+
+ organization
+ "Free Range Routing";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org>
+ FRR Development List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This module defines a model for managing FRR nexthop information.";
+
+ revision 2019-08-15 {
+ description
+ "Initial revision.";
+ }
+
+ typedef gateway-address {
+ type inet:ip-address;
+ }
+
+ typedef nexthop-type {
+ type enumeration {
+ enum "ifindex" {
+ value 1;
+ description
+ "Specific interface.";
+ }
+ enum "ip4" {
+ value 2;
+ description
+ "IPv4 address.";
+ }
+ enum "ip4-ifindex" {
+ value 3;
+ description
+ "IPv4 address and interface.";
+ }
+ enum "ip6" {
+ value 4;
+ description
+ "IPv6 address.";
+ }
+ enum "ip6-ifindex" {
+ value 5;
+ description
+ "IPv6 address and interface.";
+ }
+ enum "blackhole" {
+ value 6;
+ description
+ "Unreachable or prohibited.";
+ }
+ }
+ description
+ "Nexthop types.";
+ }
+
+ typedef blackhole-type {
+ type enumeration {
+ enum "unspec" {
+ value 0;
+ description
+ "Generic unreachable.";
+ }
+ enum "null" {
+ value 1;
+ description
+ "Null type.";
+ }
+ enum "reject" {
+ value 2;
+ description
+ "ICMP unreachable.";
+ }
+ enum "prohibited" {
+ value 3;
+ description
+ "ICMP admin-prohibited.";
+ }
+ }
+ default "null";
+ description
+ "Nexthop blackhole types.";
+ }
+
+ /*
+ * Nexthop object
+ */
+
+ grouping frr-nexthop {
+ leaf nh-type {
+ type nexthop-type;
+ mandatory true;
+ description
+ "The nexthop type.";
+ }
+
+ leaf gateway {
+ type gateway-address;
+ description
+ "The nexthop gateway address.";
+ }
+
+ leaf vrf {
+ type string {
+ length "1..36";
+ }
+ description
+ "The nexthop vrf name, if different from the route.";
+ }
+
+ leaf interface {
+ type frr-interface:interface-ref;
+ description
+ "The nexthop egress interface.";
+ }
+
+ leaf bh-type {
+ type blackhole-type;
+ description
+ "A blackhole sub-type, if the nexthop is a blackhole type.";
+ }
+
+ leaf flags {
+ type uint32;
+ description
+ "The nexthop's raw flags value.";
+ }
+
+ leaf is-duplicate {
+ type empty;
+ description
+ "Duplicate nexthop; will be ignored.";
+ }
+
+ leaf is-recursive {
+ type empty;
+ description
+ "Nexthop must be resolved through another gateway.";
+ }
+
+ leaf is-onlink {
+ type empty;
+ description
+ "Nexthop is directly connected.";
+ }
+
+ leaf is-active {
+ type empty;
+ description
+ "Nexthop is active.";
+ }
+
+ uses rt-types:mpls-label-stack {
+ description
+ "Nexthop's MPLS label stack.";
+ }
+
+ leaf mtu {
+ type uint32;
+ description
+ "The nexthop's specific MTU.";
+ }
+ }
+
+ // End of nexthop
+ /*
+ * Nexthop-group container
+ */
+
+ grouping frr-nexthop-group {
+ description
+ "A nexthop-group, represented as a list of nexthop objects.";
+ leaf name {
+ type string;
+ description
+ "The nexthop-group name.";
+ }
+
+ list entry {
+ key "id";
+ description
+ "A list of nexthop objects.";
+ leaf id {
+ type uint32;
+ description
+ "Identifies a nexthop within a nexthop group; the entries
+ are ordered by id value, and the value has no other meaning.";
+ }
+
+ uses frr-nexthop;
+ }
+ }
+
+ // End of frr-nexthop-group
+}
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
new file mode 100644
index 000000000..74922a22f
--- /dev/null
+++ b/yang/frr-zebra.yang
@@ -0,0 +1,1988 @@
+module frr-zebra {
+ yang-version 1.1;
+ namespace "http://frrouting.org/yang/zebra";
+ prefix frr-zebra;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ import frr-route-types {
+ prefix frr-route-types;
+ }
+
+ import ietf-routing-types {
+ prefix rt-types;
+ }
+
+ import frr-nexthop {
+ prefix frr-nh;
+ }
+
+ import frr-interface {
+ prefix frr-interface;
+ }
+
+ organization
+ "Free Range Routing";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org>
+ FRR Development List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This module defines a model for managing the FRR zebra daemon.";
+
+ revision 2019-06-01 {
+ description
+ "Initial revision.";
+ }
+
+ typedef unix-timestamp {
+ type uint32;
+ units "seconds";
+ description
+ "An absolute time in seconds since the unix epoch.";
+ }
+
+ /*
+ * Multicast RPF mode configurable type
+ */
+
+ typedef mcast-rpf-lookup-mode {
+ type enumeration {
+ enum "none" {
+ value 0;
+ description
+ "No mode set.";
+ }
+ enum "mrib-only" {
+ value 1;
+ description
+ "Lookup in unicast RIB only.";
+ }
+ enum "urib-only" {
+ value 2;
+ description
+ "Lookup in multicast RIB only.";
+ }
+ enum "mrib-then-urib" {
+ value 3;
+ description
+ "Try multicast RIB first, fall back to unicast RIB.";
+ }
+ enum "lower-distance" {
+ value 4;
+ description
+ "Lookup both unicast and mcast, use entry with lower distance.";
+ }
+ enum "longer-prefix" {
+ value 5;
+ description
+ "Lookup both unicast and mcast, use entry with longer prefix.";
+ }
+ }
+ description
+ "Multicast RPF lookup behavior";
+ }
+
+ // End of ip6-route
+ /*
+ * VxLAN Network Identifier type
+ */
+
+ typedef vni-id-type {
+ type uint32 {
+ range "0..16777215";
+ }
+ description
+ "A VxLAN network identifier value.";
+ }
+
+ typedef vni-vtep-flood-type {
+ type enumeration {
+ enum "head-end-repl" {
+ value 0;
+ description
+ "Head-end replication.";
+ }
+ enum "disabled" {
+ value 1;
+ description
+ "Flooding disabled.";
+ }
+ enum "pim-sm" {
+ value 2;
+ description
+ "Multicast PIM-SM.";
+ }
+ }
+ }
+
+ /*
+ * Common route data, shared by v4 and v6 routes.
+ */
+
+ grouping route-common {
+ description
+ "Common information about a route.";
+ leaf vrf {
+ type string {
+ length "1..36";
+ }
+ description
+ "The route's vrf name.";
+ }
+
+ leaf distance {
+ type uint8;
+ description
+ "Admin distance based on routing protocol.";
+ }
+
+ leaf metric {
+ type uint32;
+ description
+ "Route metric value.";
+ }
+
+ leaf tag {
+ type uint32 {
+ range "1..4294967295";
+ }
+ description
+ "Route tag value.";
+ }
+
+ leaf is-selected {
+ type empty;
+ description
+ "Route is the selected or preferred route for the prefix.";
+ }
+
+ leaf is-installed {
+ type empty;
+ description
+ "Route is installed in the FIB.";
+ }
+
+ leaf is-failed {
+ type empty;
+ description
+ "Route installation in FIB has failed.";
+ }
+
+ leaf is-queued {
+ type empty;
+ description
+ "Route has a pending FIB operation that has not completed.";
+ }
+
+ leaf internal-flags {
+ type int32;
+ description
+ "Internal flags for the route.";
+ }
+
+ leaf internal-status {
+ type int32;
+ description
+ "Internal status for the route.";
+ }
+
+ leaf uptime {
+ type uint32;
+ units "seconds";
+ description
+ "Uptime for the route.";
+ }
+
+ container nexthop-group {
+ description
+ "Nexthop information for the route.";
+ uses frr-nh:frr-nexthop-group;
+ }
+ }
+
+ // End of route-common
+ /*
+ * IPv4 Route object.
+ */
+
+ grouping ip4-route {
+ description
+ "An IPv4 route.";
+ leaf prefix {
+ type inet:ipv4-prefix;
+ description
+ "IP address (in the form A.B.C.D) and prefix length,
+ separated by the slash (/) character. The range of
+ values for the prefix-length is 0 to 32.";
+ }
+
+ leaf protocol {
+ type frr-route-types:frr-route-types-v4;
+ description
+ "The protocol owning the route.";
+ }
+
+ uses route-common;
+ }
+
+ // End of ip4-route
+ /*
+ * IPv6 Route object.
+ */
+
+ grouping ip6-route {
+ description
+ "An IPv6 route.";
+ leaf prefix {
+ type inet:ipv6-prefix;
+ description
+ "The route's IPv6 prefix.";
+ }
+
+ leaf protocol {
+ type frr-route-types:frr-route-types-v6;
+ description
+ "The protocol owning the route.";
+ }
+
+ uses route-common;
+ }
+
+ /*
+ * Information about EVPN VNIs
+ */
+
+ grouping vni-information {
+ choice type-choice {
+ case l2 {
+ leaf is-layer2 {
+ type empty;
+ description
+ "Information about an L2 VNI.";
+ }
+
+ leaf vtep-count {
+ type uint32;
+ description
+ "Number of VTEPs.";
+ }
+ }
+
+ case l3 {
+ leaf is-layer3 {
+ type empty;
+ description
+ "Information about an L3 VNI.";
+ }
+ }
+ }
+
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "The VNI identifier.";
+ }
+
+ leaf vxlan-ifname {
+ type frr-interface:interface-ref;
+ description
+ "The VxLAN interface name.";
+ }
+
+ leaf mac-count {
+ type uint32;
+ description
+ "Number of valid MACs.";
+ }
+
+ leaf neighbor-count {
+ type uint32;
+ description
+ "Number of neighbors.";
+ }
+
+ leaf vrf {
+ type string {
+ length "1..36";
+ }
+ description
+ "The tenant VRF.";
+ }
+
+ leaf local-vtep-addr {
+ type inet:ipv4-address;
+ description
+ "The local VTEP IP address.";
+ }
+ }
+
+ /*
+ * Detailed EVPN VNI information for L2.
+ */
+
+ grouping vni-l2-detail {
+ leaf if-index {
+ type uint32;
+ description
+ "The VxLAN ifindex.";
+ }
+
+ leaf advertise-gw {
+ type empty;
+ description
+ "The gateway MAC-IP is being advertised.";
+ }
+
+ leaf mcase-group {
+ type rt-types:ipv4-multicast-group-address;
+ description
+ "The VNI multicast group for BUM traffic.";
+ }
+
+ list remote-vtep-list {
+ leaf remote-vtep {
+ type inet:ipv4-address;
+ description
+ "The remote VTEP IP address.";
+ }
+
+ leaf vtep-flood {
+ type vni-vtep-flood-type;
+ }
+ }
+ }
+
+ /*
+ * Detailed EVPN VNI information for L3.
+ */
+
+ grouping vni-l3-detail {
+ leaf svi-interface {
+ type frr-interface:interface-ref;
+ description
+ "The SVI interface.";
+ }
+
+ leaf is-up {
+ type empty;
+ description
+ "The state is active.";
+ }
+
+ leaf prefix-only {
+ type empty;
+ description
+ "Prefix routes only";
+ }
+
+ leaf router-mac {
+ type yang:mac-address;
+ description
+ "The VNI Router MAC address.";
+ }
+
+ list vni-list {
+ description
+ "A list of the associated L2 VNIs.";
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "An L2 VNI identifier.";
+ }
+ }
+ }
+
+ /*
+ * Debug options
+ */
+
+ grouping zebra-debugs {
+ leaf debug-events {
+ type boolean;
+ description
+ "Debug ZAPI events.";
+ }
+
+ leaf debug-zapi-send {
+ type boolean;
+ description
+ "Debug ZAPI messages sent.";
+ }
+
+ leaf debug-zapi-recv {
+ type boolean;
+ description
+ "Debug ZAPI messages received.";
+ }
+
+ leaf debug-zapi-detail {
+ type boolean;
+ description
+ "Debug ZAPI details.";
+ }
+
+ leaf debug-kernel {
+ type boolean;
+ description
+ "Debug kernel events.";
+ }
+
+ leaf debug-kernel-msg-send {
+ type boolean;
+ description
+ "Debug kernel messages sent.";
+ }
+ leaf debug-kernel-msg-recv {
+ type boolean;
+ description
+ "Debug kernel messages received.";
+ }
+
+ leaf debug-rib {
+ type boolean;
+ description
+ "Debug RIB processing.";
+ }
+
+ leaf debug-rib-detail {
+ type boolean;
+ description
+ "Debug RIB processing details.";
+ }
+
+ leaf debug-fpm {
+ type boolean;
+ description
+ "Debug the FIB Push Interface subsystem.";
+ }
+
+ leaf debug-nht {
+ type boolean;
+ description
+ "Debug Nexthop-tracking.";
+ }
+
+ leaf debug-nht-detail {
+ type boolean;
+ description
+ "Debug Nexthop-tracking details.";
+ }
+
+ leaf debug-mpls {
+ type boolean;
+ description
+ "Debug MPLS.";
+ }
+
+ leaf debug-vxlan {
+ type boolean;
+ description
+ "Debug VxLAN.";
+ }
+
+ leaf debug-pw {
+ type boolean;
+ description
+ "Debug pseudowires.";
+ }
+
+ leaf debug-dplane {
+ type boolean;
+ description
+ "Debug the dataplane subsystem.";
+ }
+
+ leaf debug-dplane-detail {
+ type boolean;
+ description
+ "Debug dataplane subsystem details.";
+ }
+
+ leaf debug-mlag {
+ type boolean;
+ description
+ "Debug MLAG.";
+ }
+ }
+
+ // End of zebra container
+ /*
+ * RPCs
+ */
+
+ rpc get-route-information {
+ description
+ "Retrieve IPv4 or IPv6 unicast routes.";
+ input {
+ choice ip-type {
+ case v4 {
+ leaf ipv4 {
+ type empty;
+ mandatory true;
+ description
+ "Retrieve IPv4 routes.";
+ }
+ leaf prefix-v4 {
+ type inet:ipv4-prefix;
+ description
+ "Retrieve routes matching a specific prefix.";
+ }
+
+ leaf supernets-only {
+ type empty;
+ description
+ "Skip routes that are subnets of classful prefix sizes.";
+ }
+ }
+
+ case v6 {
+ leaf ipv6 {
+ type empty;
+ mandatory true;
+ description
+ "Retrieve IPv6 routes.";
+ }
+
+ leaf prefix-v6 {
+ type inet:ipv6-prefix;
+ description
+ "Retrieve routes matching a specific prefix.";
+ }
+ }
+ }
+
+ choice vrf-choice {
+ case single {
+ leaf vrf {
+ type string {
+ length "1..36";
+ }
+ description
+ "Retrieve routes in a non-default vrf.";
+ }
+ }
+
+ case all {
+ leaf all-vrfs {
+ type empty;
+ description
+ "Retrieve routes from all vrfs.";
+ }
+ }
+ }
+
+ leaf fib-routes {
+ type empty;
+ description
+ "Retrieve FIB routes rather than RIB routes.";
+ }
+
+ leaf table-id {
+ type uint32 {
+ range "1..4294967295";
+ }
+ description
+ "Routing table id to retrieve.";
+ }
+
+ leaf protocol {
+ type frr-route-types:frr-route-types-v4;
+ description
+ "Retrieve routes from a specific protocol daemon.";
+ }
+
+ leaf ospf-instance {
+ type uint32 {
+ range "1..65535";
+ }
+ must '../protocol = "ospf"';
+ description
+ "Retrieve routes from a specific OSPF instance.";
+ }
+
+ choice detail {
+ case det {
+ leaf include-detail {
+ type empty;
+ description
+ "Include detailed information.";
+ }
+ }
+
+ case summ {
+ leaf summary {
+ type empty;
+ description
+ "Include summary information only.";
+ }
+ }
+ }
+ }
+ // End of input
+ output {
+ choice route-list {
+ case v4 {
+ container routes-v4 {
+ description
+ "IPv4 route information.";
+ list route {
+ uses ip4-route;
+ }
+ }
+ }
+
+ case v6 {
+ container routes-v6 {
+ description
+ "IPv6 route information.";
+ list route {
+ uses ip6-route;
+ }
+ }
+ }
+ }
+ }
+ // End of output
+ }
+
+ // End get-route-information
+
+ rpc get-v6-mroute-info {
+ description
+ "Retrieve IPv6 multicast routes.";
+ input {
+ choice vrf-choice {
+ case single {
+ leaf vrf {
+ type string {
+ length "1..36";
+ }
+ description
+ "Retrieve routes in a non-default vrf.";
+ }
+ }
+
+ case all {
+ leaf all-vrfs {
+ type empty;
+ description
+ "Retrieve routes from all vrfs.";
+ }
+ }
+ }
+ }
+
+ output {
+ container routes {
+ description
+ "IPv6 mcast route information.";
+ list route {
+ uses ip6-route;
+ }
+ }
+ }
+ }
+
+ // End get-v6-mroute-info
+
+ rpc get-vrf-info {
+ description
+ "Retrieve VRF information; the default VRF is elided.";
+ // Note: no input clause.
+ output {
+ list vrf-list {
+ leaf name {
+ type string {
+ length "1..36";
+ }
+ description
+ "The VRF name";
+ }
+
+ leaf is-user-config {
+ type empty;
+ description
+ "The VRF was configured by an admin.";
+ }
+
+ leaf vrf-id {
+ type uint32;
+ description
+ "The VRF id.";
+ }
+
+ choice vrf-type {
+ case inactive {
+ leaf is-inactive {
+ type empty;
+ description
+ "The VRF is inactive.";
+ }
+ }
+
+ case netns {
+ leaf netns-name {
+ type string;
+ description
+ "The net namespace name associated with the VRF.";
+ }
+ }
+
+ case table {
+ leaf table-id {
+ type uint32;
+ description
+ "The table-id associated with the VRF.";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // End get-vrf-info
+
+ rpc get-vrf-vni-info {
+ description
+ "Retrieve mappings between EVPN VNI and VRF.";
+ // Note: no input clause.
+ output {
+ list vrf-vni-list {
+ leaf vrf-name {
+ type string {
+ length "1..36";
+ }
+ description
+ "The VRF name.";
+ }
+
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "The EVPN VNI.";
+ }
+
+ leaf vxlan-if-name {
+ type frr-interface:interface-ref;
+ description
+ "The VxLAN interface name.";
+ }
+
+ leaf svi-if-name {
+ type frr-interface:interface-ref;
+ description
+ "The SVI interface name.";
+ }
+
+ leaf router-mac-addr {
+ type yang:mac-address;
+ description
+ "Router MAC address.";
+ }
+
+ leaf is-up {
+ type empty;
+ description
+ "The state is active.";
+ }
+ }
+ }
+ }
+
+ // End get-vrf-vni-info
+
+ rpc get-evpn-info {
+ description
+ "Retrieve global information about EVPN.";
+ // Note: No input clause.
+ output {
+ leaf l2vni-count {
+ type uint32;
+ description
+ "Number of L2 VNIs.";
+ }
+
+ leaf l3vni-count {
+ type uint32;
+ description
+ "Number of L3 VNIs.";
+ }
+
+ leaf advertise-gateway {
+ type empty;
+ description
+ "Advertise the gateway MAC-IP.";
+ }
+
+ leaf advertise-svi {
+ type empty;
+ description
+ "Advertise SVI MAC-IP.";
+ }
+
+ leaf dup-detect {
+ type empty;
+ description
+ "Duplicate address detection is enabled.";
+ }
+
+ leaf dad-max-moves {
+ type uint32;
+ description
+ "Maximum moves allowed before address is considered duplicate.";
+ }
+
+ leaf dad-timeout {
+ type uint32;
+ units "seconds";
+ description
+ "Duplicate address detection timeout.";
+ }
+
+ leaf dad-freeze {
+ type empty;
+ description
+ "Duplicate address detection freeze enabled.";
+ }
+
+ choice dad-freeze-choice {
+ case freeze-permanent {
+ leaf dad-freeze-perm {
+ type empty;
+ description
+ "Duplicate address detection freeze is permanent.";
+ }
+ }
+
+ case freeze-time {
+ leaf dad-freeze-time {
+ type uint32;
+ units "seconds";
+ description
+ "Duplicate address detection freeze timer.";
+ }
+ }
+ }
+ }
+ }
+
+ // End get-evpn-info
+
+ rpc get-vni-info {
+ // If no vni is specified, retrieve global list.
+ input {
+ choice vni-choice {
+ default "all-vnis";
+ case all-vnis {
+ leaf all-vnis {
+ type empty;
+ description
+ "Retrieve information about all VNIs.";
+ }
+ }
+
+ case single-vni {
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "Retrieve information about a specific EVPN VNI.";
+ }
+ }
+ }
+
+ leaf detailed-info {
+ type empty;
+ description
+ "Retrieve detailed information.";
+ }
+ }
+
+ output {
+ list vni-list {
+ description
+ "Information about EVPN VNI objects.";
+ uses vni-information;
+
+ choice detail-choice {
+ case l2 {
+ description
+ "Detailed L2 information.";
+ uses vni-l2-detail;
+ }
+
+ case l3 {
+ description
+ "Detailed L3 information.";
+ uses vni-l3-detail;
+ }
+ }
+ }
+ }
+ }
+
+ // End get-vni-info
+
+ rpc get-evpn-vni-rmac {
+ description
+ "Retrieve information about VxLAN VNI RMACs.";
+ input {
+ choice vni-choice {
+ default "all-vnis";
+ case all-vnis {
+ leaf all-vnis {
+ type empty;
+ description
+ "Retrieve information about all VNIs.";
+ }
+ }
+
+ case single-vni {
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "Retrieve information about a specific EVPN VNI.";
+ }
+
+ leaf vni-rmac {
+ type yang:mac-address;
+ description
+ "A single RMAC address.";
+ }
+ }
+ }
+ }
+
+ output {
+ list rmac-info-list {
+ leaf rmac {
+ type yang:mac-address;
+ description
+ "The RMAC address.";
+ }
+
+ leaf remote-vtep {
+ type inet:ipv4-address;
+ description
+ "The remote VTEP IP address.";
+ }
+
+ leaf refcount {
+ type uint32;
+ description
+ "The refcount of the RMAC.";
+ }
+
+ list prefix-list {
+ leaf prefix-item {
+ type inet:ip-prefix;
+ description
+ "IP prefixes associated with the RMAC.";
+ }
+ }
+ }
+ }
+ }
+
+ // End get-evpn-vni-rmac
+
+ rpc get-evpn-vni-nexthops {
+ description
+ "Retrieve information about EVPN nexthops.";
+ input {
+ choice vni-choice {
+ default "all-vnis";
+ case all-vnis {
+ leaf all-vnis {
+ type empty;
+ description
+ "Retrieve information about all VNIs.";
+ }
+ }
+
+ case single-vni {
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "Retrieve information about a specific EVPN VNI.";
+ }
+
+ leaf vni-ipaddr {
+ type inet:ip-address;
+ description
+ "A single host IP address (v4 or v6).";
+ }
+ }
+ }
+ }
+
+ output {
+ list nh-info-list {
+ leaf ip-addr {
+ type inet:ip-address;
+ description
+ "The nexthop IP address.";
+ }
+
+ leaf mac-addr {
+ type yang:mac-address;
+ description
+ "The nexthop MAC address.";
+ }
+
+ leaf refcount {
+ type uint32;
+ description
+ "The refcount of the RMAC.";
+ }
+
+ list prefix-list {
+ leaf prefix-item {
+ type inet:ip-prefix;
+ description
+ "IP prefixes associated with the RMAC.";
+ }
+ }
+ }
+ }
+ }
+
+ // End get-evpn-vni-vteps
+
+ rpc clear-evpn-dup-addr {
+ description
+ "Clear duplicate address detection state for one or all VNIs.";
+ input {
+ choice clear-dup-choice {
+ case all-case {
+ leaf all-vnis {
+ type empty;
+ description
+ "Clear all VNIs.";
+ }
+ }
+
+ case single-case {
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "Clear state for a single EVPN VNI.";
+ }
+
+ choice ip-mac-choice {
+ description
+ "Clear state for a specific MAC or IP address.";
+ case ip-case {
+ leaf vni-ipaddr {
+ type inet:ip-address;
+ description
+ "A specific IP address (v4 or v6).";
+ }
+ }
+
+ case mac-case {
+ leaf mac-addr {
+ type yang:mac-address;
+ description
+ "A specific MAC address.";
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // End clear-evpn-dup-addr
+
+ rpc get-evpn-macs {
+ description
+ "Retrieve information about EVPN MAC addresses.";
+ input {
+ choice all-choice {
+ default "all-vni";
+ case all-vni {
+ leaf all-vnis {
+ type empty;
+ description
+ "Retrieve information for all VNIs.";
+ }
+
+ choice all-choices {
+ case detail-case {
+ leaf all-detail {
+ type empty;
+ description
+ "Include detailed results.";
+ }
+ }
+
+ case vtep-case {
+ leaf all-vtep-addr {
+ type inet:ipv4-address;
+ description
+ "A single VTEP address.";
+ }
+ }
+
+ case dup-case {
+ leaf all-dup {
+ type empty;
+ description
+ "Show duplicate addresses.";
+ }
+ }
+ }
+ }
+
+ case single-vni {
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "Retrieve information for a single VNI.";
+ }
+
+ choice single-choices {
+ case detail-case {
+ leaf single-detail {
+ type empty;
+ description
+ "Include detailed results.";
+ }
+ }
+
+ case mac-case {
+ leaf single-mac {
+ type yang:mac-address;
+ description
+ "A specific MAC address.";
+ }
+ }
+
+ case vtep-case {
+ leaf single-vtep {
+ type inet:ipv4-address;
+ description
+ "A single VTEP address.";
+ }
+ }
+
+ case dup-case {
+ leaf single-dup {
+ type empty;
+ description
+ "Show duplicate addresses.";
+ }
+ }
+ }
+ }
+ }
+ }
+ // End of input section
+ output {
+ list mac-list {
+ leaf mac-addr {
+ type yang:mac-address;
+ description
+ "The MAC address.";
+ }
+
+ leaf vni {
+ type vni-id-type;
+ description
+ "The VNI value.";
+ }
+
+ leaf local-sequence {
+ type uint32;
+ description
+ "Local sequence number.";
+ }
+
+ leaf remote-sequence {
+ type uint32;
+ description
+ "Remote sequence number.";
+ }
+
+ leaf dad-count {
+ type uint32;
+ description
+ "Duplicate detection counter.";
+ }
+
+ leaf is-duplicate {
+ type empty;
+ description
+ "Duplicate MAC detected.";
+ }
+
+ leaf dup-detect-time {
+ type unix-timestamp;
+ description
+ "If a duplicate, the detection time.";
+ }
+
+ container dup-detect-started {
+ leaf dup-detect-start {
+ type unix-timestamp;
+ description
+ "Duplicate detection process start time.";
+ }
+
+ leaf dup-count {
+ type uint32;
+ description
+ "Duplicate detection count.";
+ }
+ }
+
+ leaf is-auto {
+ type empty;
+ description
+ "This is an Auto MAC.";
+ }
+
+ leaf is-sticky {
+ type empty;
+ description
+ "This is a sticky MAC.";
+ }
+
+ leaf is-default-gw {
+ type empty;
+ description
+ "This is a default-gateway MAC.";
+ }
+
+ leaf is-remote-gw {
+ type empty;
+ description
+ "This is a remote-gateway MAC.";
+ }
+
+ list neighbor-list {
+ leaf neighbor-addr {
+ type inet:ip-address;
+ description
+ "Neighbor address.";
+ }
+
+ leaf is-active {
+ type empty;
+ description
+ "Neighbor is active.";
+ }
+ }
+
+ leaf mac-count {
+ type uint32;
+ description
+ "Number of MACs (local and remote).";
+ }
+
+ choice local-rem-choice {
+ case local-case {
+ leaf intf {
+ type frr-interface:interface-ref;
+ description
+ "The local interface name.";
+ }
+
+ leaf vlan {
+ type uint32;
+ description
+ "A VLAN id.";
+ }
+ }
+
+ case remote-case {
+ leaf vtep-addr {
+ type inet:ipv4-address;
+ description
+ "The remote VTEP IP address.";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // End get-evpn-macs
+
+ rpc get-evpn-arp-cache {
+ description
+ "Retrieve information about EVPN neighbor cache entries.";
+ input {
+ choice all-choice {
+ default "all-vni";
+ case all-vni {
+ leaf all-vnis {
+ type empty;
+ description
+ "Retrieve information for all VNIs.";
+ }
+
+ choice all-choices {
+ case detail-case {
+ leaf all-detail {
+ type empty;
+ description
+ "Include detailed results.";
+ }
+ }
+
+ case dup-case {
+ leaf all-dup {
+ type empty;
+ description
+ "Show duplicates.";
+ }
+ }
+ }
+ }
+
+ case single-vni {
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "Retrieve information for a single VNI.";
+ }
+
+ choice single-choices {
+ case vtep-case {
+ leaf single-vtep {
+ type inet:ipv4-address;
+ description
+ "A single VTEP address.";
+ }
+ }
+
+ case neighbor-case {
+ leaf neighbor-addr {
+ type inet:ip-address;
+ description
+ "A single neighbor address.";
+ }
+ }
+
+ case dup-case {
+ leaf single-dup {
+ type empty;
+ description
+ "Show duplicates.";
+ }
+ }
+ }
+ }
+ }
+ }
+ // End input section
+ output {
+ list vni-list {
+ container vni-container {
+ description
+ "Information for one VNI.";
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "The VNI id.";
+ }
+
+ list neigh-list {
+ description
+ "Information about a VNI's neighbor cache.";
+ leaf mac-addr {
+ type yang:mac-address;
+ description
+ "A neighbor MAC address.";
+ }
+
+ leaf ip-addr {
+ type inet:ip-address;
+ description
+ "A neighbor IP address.";
+ }
+
+ leaf state-active {
+ type empty;
+ description
+ "Indicates whether the entry is active.";
+ }
+
+ choice local-remote-choice {
+ case local-case {
+ leaf is-local {
+ type empty;
+ description
+ "The entry is local.";
+ }
+ }
+
+ case remote-case {
+ leaf is-remote {
+ type empty;
+ description
+ "The entry is remote.";
+ }
+ }
+ }
+
+ leaf is-dup {
+ type empty;
+ description
+ "The entry is a detected duplicate.";
+ }
+
+ leaf is-default-gw {
+ type empty;
+ description
+ "The entry is a default gateway.";
+ }
+
+ leaf is-router {
+ type empty;
+ description
+ "The entry is a router.";
+ }
+
+ leaf local-sequence {
+ type uint32;
+ description
+ "The local sequence number.";
+ }
+
+ leaf remote-sequence {
+ type uint32;
+ description
+ "The remote sequence number.";
+ }
+
+ leaf remote-vtep {
+ type inet:ipv4-address;
+ description
+ "The remote VTEP address.";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // End get-evpn-arp-cache
+
+ rpc get-pbr-ipset {
+ input {
+ leaf name {
+ type string {
+ length "1..32";
+ }
+ description
+ "An optional specific IPset name.";
+ }
+ }
+
+ output {
+ list ipset-list {
+ leaf name {
+ type string {
+ length "1..32";
+ }
+ description
+ "The IPset name.";
+ }
+
+ leaf ipset-type {
+ type enumeration {
+ enum "net-net" {
+ value 1;
+ description
+ "";
+ }
+ enum "net-port-net" {
+ value 2;
+ description
+ "";
+ }
+ enum "net-port" {
+ value 3;
+ description
+ "";
+ }
+ enum "net" {
+ value 4;
+ description
+ "";
+ }
+ }
+ }
+
+ leaf src-prefix {
+ type inet:ip-prefix;
+ description
+ "";
+ }
+
+ leaf dest-prefix {
+ type inet:ip-prefix;
+ description
+ "";
+ }
+
+ leaf src-port {
+ type inet:port-number;
+ description
+ "";
+ }
+
+ leaf dest-port {
+ type inet:port-number;
+ description
+ "";
+ }
+
+ choice proto-choice {
+ description
+ "Filter UDP/TCP only, or a specific protocol number.";
+ case udp-tcp-case {
+ leaf is-udp-tcp {
+ type empty;
+ description
+ "Filter TCP/UDP ports only.";
+ }
+ }
+
+ case proto-case {
+ leaf proto {
+ type uint32;
+ description
+ "Filter a specific protocol number.";
+ }
+ }
+ }
+
+ container icmp-info {
+ description
+ "Additional information for ICMP filters.";
+ leaf type-min {
+ type uint8;
+ description
+ "";
+ }
+
+ leaf type-max {
+ type uint8;
+ description
+ "";
+ }
+
+ leaf code-min {
+ type uint8;
+ description
+ "";
+ }
+
+ leaf code-max {
+ type uint8;
+ description
+ "";
+ }
+ }
+
+ container ipset-stats {
+ leaf is-unique {
+ type empty;
+ description
+ "";
+ }
+
+ leaf packet-counter {
+ type uint64;
+ description
+ "";
+ }
+
+ leaf bytes-counter {
+ type uint64;
+ description
+ "";
+ }
+ }
+ }
+ }
+ }
+
+ // End get-pbr-ipset
+
+ rpc get-pbr-iptable {
+ input {
+ leaf name {
+ type string {
+ length "1..32";
+ }
+ description
+ "An optional single IPtable name.";
+ }
+ }
+
+ output {
+ list iptable-list {
+ leaf name {
+ type string {
+ length "1..32";
+ }
+ description
+ "The IPtable name.";
+ }
+
+ leaf unique-val {
+ type uint32;
+ description
+ "";
+ }
+
+ choice action-choice {
+ description
+ "The table action.";
+ case drop-case {
+ leaf action-drop {
+ type empty;
+ description
+ "";
+ }
+ }
+
+ case redirect-case {
+ leaf action-redirect {
+ type empty;
+ description
+ "";
+ }
+ }
+ }
+
+ leaf min-packet {
+ type uint32;
+ description
+ "";
+ }
+
+ leaf max-packet {
+ type uint32;
+ description
+ "";
+ }
+
+ leaf lookup-src-port {
+ type empty;
+ description
+ "";
+ }
+
+ leaf lookup-dst-port {
+ type empty;
+ description
+ "";
+ }
+
+ leaf tcp-flags {
+ type uint16;
+ description
+ "";
+ }
+
+ leaf tcp-flags-mask {
+ type uint16;
+ description
+ "";
+ }
+
+ leaf protocol-val {
+ type uint32;
+ description
+ "An IP protocol number.";
+ }
+
+ container dscp-info {
+ leaf dscp-value {
+ type uint32;
+ description
+ "A DSCP value to match.";
+ }
+
+ leaf invert-match {
+ type empty;
+ description
+ "If set, exclude the specified value";
+ }
+ }
+
+ container fragment-info {
+ leaf fragment-val {
+ type uint32;
+ description
+ "An IP fragment value.";
+ }
+
+ leaf invert-match {
+ type empty;
+ description
+ "If set, exclude the specified value.";
+ }
+ }
+
+ container iptable-stats {
+ leaf packet-counter {
+ type uint64;
+ description
+ "";
+ }
+
+ leaf bytes-counter {
+ type uint64;
+ description
+ "";
+ }
+ }
+
+ container rule-info {
+ description
+ "Information about a rule, for redirect tables.";
+ leaf table-id {
+ type uint32;
+ description
+ "The rule table id.";
+ }
+
+ leaf table-fwmark {
+ type uint32;
+ description
+ "The firewall mark for the rule.";
+ }
+ }
+ }
+ }
+ }
+
+ // End get-pbr-iptable
+ /*
+ * Handy 'all-at-once' api to retrieve debugs
+ */
+
+ rpc get-debugs {
+ output {
+ uses zebra-debugs;
+ }
+ }
+
+ // End get-debugs
+
+ augment "/frr-interface:lib/frr-interface:interface" {
+ description
+ "Extends interface model with Zebra-related parameters.";
+ container zebra {
+ list ip4-addr-list {
+ key "ip4-prefix";
+ description
+ "IPv4 prefixes for an interface.";
+ leaf ip4-prefix {
+ type inet:ipv4-prefix;
+ description
+ "IPv4 address prefix.";
+ }
+ leaf ip4-peer {
+ type inet:ipv4-prefix;
+ description
+ "Peer prefix, for peer-to-peer interfaces.";
+ }
+ leaf label {
+ type string;
+ description
+ "Optional string label for the address.";
+ }
+ }
+ list ip6-addr-list {
+ key "ip6-prefix";
+ description
+ "IPv6 prefixes for an interface.";
+ leaf ip6-prefix {
+ type inet:ipv6-prefix;
+ description
+ "IPv6 address prefix.";
+ }
+ leaf label {
+ type string;
+ description
+ "Optional string label for the address.";
+ }
+ }
+
+ leaf multicast {
+ type boolean;
+ description
+ "Multicast flag for the interface.";
+ }
+ leaf link-detect {
+ type boolean;
+ description
+ "Link-detection for the interface.";
+ }
+ leaf shutdown {
+ type boolean;
+ description
+ "Interface admin status.";
+ }
+ leaf bandwidth {
+ type uint32 {
+ range "1..100000";
+ }
+ description
+ "Link bandwidth informational parameter, in megabits.";
+ }
+ // TODO -- link-params for (experimental/partial TE use in IGP extensions)
+ }
+ }
+
+ /*
+ * Main zebra container
+ */
+
+ container zebra {
+ description
+ "Data model for the Zebra daemon.";
+ leaf mcast-rpf-lookup {
+ type frr-zebra:mcast-rpf-lookup-mode;
+ default "mrib-then-urib";
+ description
+ "Multicast RPF lookup behavior.";
+ }
+ leaf ip-forwarding {
+ type boolean;
+ description
+ "IP forwarding status.";
+ }
+ leaf ipv6-forwarding {
+ type enumeration {
+ enum unknown {
+ value -1;
+ description
+ "Unknown state.";
+ }
+ enum off {
+ value 0;
+ description
+ "IPv6 forwarding disabled.";
+ }
+ enum on {
+ value 1;
+ description
+ "IPv6 forwarding enabled.";
+ }
+ }
+ description
+ "IPv6 forwarding status.";
+ }
+ leaf workqueue-hold-timer {
+ type uint32 {
+ range "0..10000";
+ }
+ units "milliseconds";
+ default "10";
+ description
+ "Work-queue processing hold timer, in milliseconds.";
+ }
+ leaf zapi-packets {
+ type uint32 {
+ range "1..10000";
+ }
+ default "1000";
+ description
+ "Number of ZAPI packets to process before relinquishing
+ the main thread.";
+ }
+ container import-kernel-table {
+ description
+ "Parameters to use when importing IPv4 routes from a non-main kernel
+ routing table.";
+ leaf table-id {
+ type uint32 {
+ range "1..252";
+ }
+ description
+ "The kernel table id.";
+ }
+ leaf distance {
+ type uint32 {
+ range "1..255";
+ }
+ default "15";
+ description
+ "The admin distance to use for imported routes.";
+ }
+ leaf route-map {
+ type string;
+ description
+ "A route-map to filter imported routes.";
+ }
+ }
+ leaf allow-external-route-update {
+ type empty;
+ description
+ "Allow FRR-controlled routes to be overwritten by external processes";
+ }
+ leaf dplane-queue-limit {
+ type uint32 {
+ range "0..10000";
+ }
+ default "200";
+ description
+ "Limit on the number of updates queued to the dataplane subsystem.";
+ }
+ list vrf-vni-mapping {
+ key "vrf-id";
+ description
+ "EVPN VNI mapping corresponding to a VRF.";
+ leaf vrf-id {
+ type uint32;
+ description
+ "The identifier for a VRF.";
+ }
+ leaf vni-id {
+ type vni-id-type;
+ description
+ "The VNI id to map to the VRF.";
+ }
+ leaf prefix-only {
+ type empty;
+ description
+ "Prefix routes only.";
+ }
+ }
+ /*
+ * Debug options
+ */
+ container debugs {
+ uses zebra-debugs;
+ }
+ /* End of debugs */
+ /*
+ * End of configuration attributes
+ */
+ /*
+ * Operational data.
+ */
+ container state {
+ config false;
+ description
+ "Operational data.";
+ }
+ // End of operational / state container
+ }
+
+ // End interface model augmentation
+}
diff --git a/yang/ietf/ietf-routing-types.yang b/yang/ietf/ietf-routing-types.yang
new file mode 100644
index 000000000..a30427eb1
--- /dev/null
+++ b/yang/ietf/ietf-routing-types.yang
@@ -0,0 +1,751 @@
+module ietf-routing-types {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-routing-types";
+ prefix rt-types;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ organization
+ "IETF RTGWG - Routing Area Working Group";
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/rtgwg/>
+ WG List: <mailto:rtgwg@ietf.org>
+ Editors: Xufeng Liu
+ <mailto:Xufeng_Liu@jabail.com>
+ Yingzhen Qu
+ <mailto:yingzhen.qu@huawei.com>
+ Acee Lindem
+ <mailto:acee@cisco.com>
+ Christian Hopps
+ <mailto:chopps@chopps.org>
+ Lou Berger
+ <mailto:lberger@labn.com>";
+
+ description
+ "This module contains a collection of YANG data types
+ considered generally useful for routing protocols.
+ Copyright (c) 2017 IETF Trust and the persons
+ identified as authors of the code. All rights reserved.
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+ This version of this YANG module is part of RFC 8294; see
+ the RFC itself for full legal notices.";
+ revision 2017-12-04 {
+ description "Initial revision.";
+ reference
+ "RFC 8294: Common YANG Data Types for the Routing Area.
+ Section 3.";
+ }
+
+ /*** Identities related to MPLS/GMPLS ***/
+
+ identity mpls-label-special-purpose-value {
+ description
+ "Base identity for deriving identities describing
+ special-purpose Multiprotocol Label Switching (MPLS) label
+ values.";
+ reference
+ "RFC 7274: Allocating and Retiring Special-Purpose MPLS
+ Labels.";
+ }
+
+ identity ipv4-explicit-null-label {
+ base mpls-label-special-purpose-value;
+ description
+ "This identity represents the IPv4 Explicit NULL Label.";
+ reference
+ "RFC 3032: MPLS Label Stack Encoding. Section 2.1.";
+ }
+
+ identity router-alert-label {
+ base mpls-label-special-purpose-value;
+ description
+ "This identity represents the Router Alert Label.";
+ reference
+ "RFC 3032: MPLS Label Stack Encoding. Section 2.1.";
+ }
+
+ identity ipv6-explicit-null-label {
+ base mpls-label-special-purpose-value;
+ description
+ "This identity represents the IPv6 Explicit NULL Label.";
+ reference
+ "RFC 3032: MPLS Label Stack Encoding. Section 2.1.";
+ }
+
+ identity implicit-null-label {
+ base mpls-label-special-purpose-value;
+ description
+ "This identity represents the Implicit NULL Label.";
+ reference
+ "RFC 3032: MPLS Label Stack Encoding. Section 2.1.";
+ }
+
+ identity entropy-label-indicator {
+ base mpls-label-special-purpose-value;
+ description
+ "This identity represents the Entropy Label Indicator.";
+ reference
+ "RFC 6790: The Use of Entropy Labels in MPLS Forwarding.
+ Sections 3 and 10.1.";
+ }
+
+ identity gal-label {
+ base mpls-label-special-purpose-value;
+ description
+ "This identity represents the Generic Associated Channel
+ (G-ACh) Label (GAL).";
+ reference
+ "RFC 5586: MPLS Generic Associated Channel.
+ Sections 4 and 10.";
+ }
+
+ identity oam-alert-label {
+ base mpls-label-special-purpose-value;
+ description
+ "This identity represents the OAM Alert Label.";
+ reference
+ "RFC 3429: Assignment of the 'OAM Alert Label' for
+ Multiprotocol Label Switching Architecture (MPLS)
+ Operation and Maintenance (OAM) Functions.
+ Sections 3 and 6.";
+ }
+
+ identity extension-label {
+ base mpls-label-special-purpose-value;
+ description
+ "This identity represents the Extension Label.";
+ reference
+ "RFC 7274: Allocating and Retiring Special-Purpose MPLS
+ Labels. Sections 3.1 and 5.";
+ }
+
+ /*** Collection of types related to routing ***/
+
+ typedef router-id {
+ type yang:dotted-quad;
+ description
+ "A 32-bit number in the dotted-quad format assigned to each
+ router. This number uniquely identifies the router within
+ an Autonomous System.";
+ }
+
+ /*** Collection of types related to VPNs ***/
+
+ typedef route-target {
+ type string {
+ pattern
+ '(0:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
+ + '42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
+ + '42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
+ + '42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))|'
+ + '(1:((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
+ + '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
+ + '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
+ + '655[0-2][0-9]|'
+ + '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '(2:(429496729[0-5]|42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|'
+ + '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|'
+ + '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '(6(:[a-fA-F0-9]{2}){6})|'
+ + '(([3-57-9a-fA-F]|[1-9a-fA-F][0-9a-fA-F]{1,3}):'
+ + '[0-9a-fA-F]{1,12})';
+ }
+
+ description
+ "A Route Target is an 8-octet BGP extended community
+ initially identifying a set of sites in a BGP VPN
+ (RFC 4364). However, it has since taken on a more general
+ role in BGP route filtering. A Route Target consists of two
+ or three fields: a 2-octet Type field, an administrator
+ field, and, optionally, an assigned number field.
+ According to the data formats for types 0, 1, 2, and 6 as
+ defined in RFC 4360, RFC 5668, and RFC 7432, the encoding
+ pattern is defined as:
+ 0:2-octet-asn:4-octet-number
+ 1:4-octet-ipv4addr:2-octet-number
+ 2:4-octet-asn:2-octet-number
+ 6:6-octet-mac-address
+ Additionally, a generic pattern is defined for future
+ Route Target types:
+ 2-octet-other-hex-number:6-octet-hex-number
+ Some valid examples are 0:100:100, 1:1.1.1.1:100,
+ 2:1234567890:203, and 6:26:00:08:92:78:00.";
+ reference
+ "RFC 4360: BGP Extended Communities Attribute.
+ RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
+ RFC 5668: 4-Octet AS Specific BGP Extended Community.
+ RFC 7432: BGP MPLS-Based Ethernet VPN.";
+ }
+
+ typedef ipv6-route-target {
+ type string {
+ pattern
+ '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])))'
+ + ':'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0)';
+ pattern '((([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?))'
+ + ':'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0)';
+ }
+ description
+ "An IPv6 Route Target is a 20-octet BGP IPv6 Address
+ Specific Extended Community serving the same function
+ as a standard 8-octet Route Target, except that it only
+ allows an IPv6 address as the global administrator.
+ The format is <ipv6-address:2-octet-number>.
+ Two valid examples are 2001:db8::1:6544 and
+ 2001:db8::5eb1:791:6b37:17958.";
+ reference
+ "RFC 5701: IPv6 Address Specific BGP Extended Community
+ Attribute.";
+ }
+
+ typedef route-target-type {
+ type enumeration {
+ enum import {
+ value 0;
+ description
+ "The Route Target applies to route import.";
+ }
+ enum export {
+ value 1;
+ description
+ "The Route Target applies to route export.";
+ }
+
+ enum both {
+ value 2;
+ description
+ "The Route Target applies to both route import and
+ route export.";
+ }
+ }
+ description
+ "Indicates the role a Route Target takes in route filtering.";
+ reference
+ "RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).";
+ }
+
+ typedef route-distinguisher {
+ type string {
+ pattern
+ '(0:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
+ + '42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
+ + '42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
+ + '42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))|'
+ + '(1:((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
+ + '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
+ + '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
+ + '655[0-2][0-9]|'
+ + '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '(2:(429496729[0-5]|42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|'
+ + '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|'
+ + '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '(6(:[a-fA-F0-9]{2}){6})|'
+ + '(([3-57-9a-fA-F]|[1-9a-fA-F][0-9a-fA-F]{1,3}):'
+ + '[0-9a-fA-F]{1,12})';
+ }
+
+ description
+ "A Route Distinguisher is an 8-octet value used to
+ distinguish routes from different BGP VPNs (RFC 4364).
+ A Route Distinguisher will have the same format as a
+ Route Target as per RFC 4360 and will consist of
+ two or three fields: a 2-octet Type field, an administrator
+ field, and, optionally, an assigned number field.
+ According to the data formats for types 0, 1, 2, and 6 as
+ defined in RFC 4360, RFC 5668, and RFC 7432, the encoding
+ pattern is defined as:
+ 0:2-octet-asn:4-octet-number
+ 1:4-octet-ipv4addr:2-octet-number
+ 2:4-octet-asn:2-octet-number
+ 6:6-octet-mac-address
+ Additionally, a generic pattern is defined for future
+ route discriminator types:
+ 2-octet-other-hex-number:6-octet-hex-number
+ Some valid examples are 0:100:100, 1:1.1.1.1:100,
+ 2:1234567890:203, and 6:26:00:08:92:78:00.";
+ reference
+ "RFC 4360: BGP Extended Communities Attribute.
+ RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
+ RFC 5668: 4-Octet AS Specific BGP Extended Community.
+ RFC 7432: BGP MPLS-Based Ethernet VPN.";
+ }
+
+ typedef route-origin {
+ type string {
+ pattern
+ '(0:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
+ + '42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
+ + '42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
+ + '42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))|'
+ + '(1:((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
+ + '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
+ + '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
+ + '655[0-2][0-9]|'
+ + '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '(2:(429496729[0-5]|42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|'
+ + '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|'
+ + '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '(6(:[a-fA-F0-9]{2}){6})|'
+ + '(([3-57-9a-fA-F]|[1-9a-fA-F][0-9a-fA-F]{1,3}):'
+ + '[0-9a-fA-F]{1,12})';
+ }
+ description
+ "A Route Origin is an 8-octet BGP extended community
+ identifying the set of sites where the BGP route
+ originated (RFC 4364). A Route Origin will have the same
+ format as a Route Target as per RFC 4360 and will consist
+ of two or three fields: a 2-octet Type field, an
+ administrator field, and, optionally, an assigned number
+ field.
+ According to the data formats for types 0, 1, 2, and 6 as
+ defined in RFC 4360, RFC 5668, and RFC 7432, the encoding
+ pattern is defined as:
+ 0:2-octet-asn:4-octet-number
+ 1:4-octet-ipv4addr:2-octet-number
+ 2:4-octet-asn:2-octet-number
+ 6:6-octet-mac-address
+ Additionally, a generic pattern is defined for future
+ Route Origin types:
+ 2-octet-other-hex-number:6-octet-hex-number
+ Some valid examples are 0:100:100, 1:1.1.1.1:100,
+ 2:1234567890:203, and 6:26:00:08:92:78:00.";
+ reference
+ "RFC 4360: BGP Extended Communities Attribute.
+ RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
+ RFC 5668: 4-Octet AS Specific BGP Extended Community.
+ RFC 7432: BGP MPLS-Based Ethernet VPN.";
+ }
+
+ typedef ipv6-route-origin {
+ type string {
+ pattern
+ '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])))'
+ + ':'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0)';
+ pattern '((([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?))'
+ + ':'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0)';
+ }
+ description
+ "An IPv6 Route Origin is a 20-octet BGP IPv6 Address
+ Specific Extended Community serving the same function
+ as a standard 8-octet route, except that it only allows
+ an IPv6 address as the global administrator. The format
+ is <ipv6-address:2-octet-number>.
+ Two valid examples are 2001:db8::1:6544 and
+ 2001:db8::5eb1:791:6b37:17958.";
+ reference
+ "RFC 5701: IPv6 Address Specific BGP Extended Community
+ Attribute.";
+ }
+
+ /*** Collection of types common to multicast ***/
+
+ typedef ipv4-multicast-group-address {
+ type inet:ipv4-address {
+ pattern '(2((2[4-9])|(3[0-9]))\.).*';
+ }
+ description
+ "This type represents an IPv4 multicast group address,
+ which is in the range of 224.0.0.0 to 239.255.255.255.";
+ reference
+ "RFC 1112: Host Extensions for IP Multicasting.";
+ }
+
+ typedef ipv6-multicast-group-address {
+ type inet:ipv6-address {
+ pattern '(([fF]{2}[0-9a-fA-F]{2}):).*';
+ }
+ description
+ "This type represents an IPv6 multicast group address,
+ which is in the range of ff00::/8.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture. Section 2.7.
+ RFC 7346: IPv6 Multicast Address Scopes.";
+ }
+
+ typedef ip-multicast-group-address {
+ type union {
+ type ipv4-multicast-group-address;
+ type ipv6-multicast-group-address;
+ }
+ description
+ "This type represents a version-neutral IP multicast group
+ address. The format of the textual representation implies
+ the IP version.";
+ }
+
+ typedef ipv4-multicast-source-address {
+ type union {
+ type enumeration {
+ enum * {
+ description
+ "Any source address.";
+ }
+ }
+ type inet:ipv4-address;
+ }
+ description
+ "Multicast source IPv4 address type.";
+ }
+
+ typedef ipv6-multicast-source-address {
+ type union {
+ type enumeration {
+ enum * {
+ description
+ "Any source address.";
+ }
+ }
+ type inet:ipv6-address;
+ }
+ description
+ "Multicast source IPv6 address type.";
+ }
+
+ /*** Collection of types common to protocols ***/
+
+ typedef bandwidth-ieee-float32 {
+ type string {
+ pattern
+ '0[xX](0((\.0?)?[pP](\+)?0?|(\.0?))|'
+ + '1(\.([0-9a-fA-F]{0,5}[02468aAcCeE]?)?)?[pP](\+)?(12[0-7]|'
+ + '1[01][0-9]|0?[0-9]?[0-9])?)';
+ }
+ description
+ "Bandwidth in IEEE 754 floating-point 32-bit binary format:
+ (-1)**(S) * 2**(Exponent-127) * (1 + Fraction),
+ where Exponent uses 8 bits and Fraction uses 23 bits.
+ The units are octets per second.
+ The encoding format is the external hexadecimal-significant
+ character sequences specified in IEEE 754 and ISO/IEC C99.
+ The format is restricted to be normalized, non-negative, and
+ non-fraction: 0x1.hhhhhhp{+}d, 0X1.HHHHHHP{+}D, or 0x0p0,
+ where 'h' and 'H' are hexadecimal digits and 'd' and 'D' are
+ integers in the range of [0..127].
+ When six hexadecimal digits are used for 'hhhhhh' or
+ 'HHHHHH', the least significant digit must be an even
+ number. 'x' and 'X' indicate hexadecimal; 'p' and 'P'
+ indicate a power of two. Some examples are 0x0p0, 0x1p10,
+ and 0x1.abcde2p+20.";
+ reference
+ "IEEE Std 754-2008: IEEE Standard for Floating-Point
+ Arithmetic.
+ ISO/IEC C99: Information technology - Programming
+ Languages - C.";
+ }
+
+ typedef link-access-type {
+ type enumeration {
+ enum broadcast {
+ description
+ "Specify broadcast multi-access network.";
+ }
+ enum non-broadcast-multiaccess {
+ description
+ "Specify Non-Broadcast Multi-Access (NBMA) network.";
+ }
+ enum point-to-multipoint {
+ description
+ "Specify point-to-multipoint network.";
+ }
+ enum point-to-point {
+ description
+ "Specify point-to-point network.";
+ }
+ }
+ description
+ "Link access type.";
+ }
+
+ typedef timer-multiplier {
+ type uint8;
+ description
+ "The number of timer value intervals that should be
+ interpreted as a failure.";
+ }
+
+ typedef timer-value-seconds16 {
+ type union {
+ type uint16 {
+ range "1..65535";
+ }
+ type enumeration {
+ enum infinity {
+ description
+ "The timer is set to infinity.";
+ }
+ enum not-set {
+ description
+ "The timer is not set.";
+ }
+ }
+ }
+ units "seconds";
+ description
+ "Timer value type, in seconds (16-bit range).";
+ }
+
+ typedef timer-value-seconds32 {
+ type union {
+ type uint32 {
+ range "1..4294967295";
+ }
+ type enumeration {
+ enum infinity {
+ description
+ "The timer is set to infinity.";
+ }
+ enum not-set {
+ description
+ "The timer is not set.";
+ }
+ }
+ }
+ units "seconds";
+ description
+ "Timer value type, in seconds (32-bit range).";
+ }
+
+ typedef timer-value-milliseconds {
+ type union {
+ type uint32 {
+ range "1..4294967295";
+ }
+ type enumeration {
+ enum infinity {
+ description
+ "The timer is set to infinity.";
+ }
+ enum not-set {
+ description
+ "The timer is not set.";
+ }
+ }
+ }
+ units "milliseconds";
+ description
+ "Timer value type, in milliseconds.";
+ }
+
+ typedef percentage {
+ type uint8 {
+ range "0..100";
+ }
+ description
+ "Integer indicating a percentage value.";
+ }
+
+ typedef timeticks64 {
+ type uint64;
+ description
+ "This type is based on the timeticks type defined in
+ RFC 6991, but with 64-bit width. It represents the time,
+ modulo 2^64, in hundredths of a second between two epochs.";
+ reference
+ "RFC 6991: Common YANG Data Types.";
+ }
+
+ typedef uint24 {
+ type uint32 {
+ range "0..16777215";
+ }
+ description
+ "24-bit unsigned integer.";
+ }
+
+ /*** Collection of types related to MPLS/GMPLS ***/
+
+ typedef generalized-label {
+ type binary;
+ description
+ "Generalized Label. Nodes sending and receiving the
+ Generalized Label are aware of the link-specific
+ label context and type.";
+ reference
+ "RFC 3471: Generalized Multi-Protocol Label Switching (GMPLS)
+ Signaling Functional Description. Section 3.2.";
+ }
+
+ typedef mpls-label-special-purpose {
+ type identityref {
+ base mpls-label-special-purpose-value;
+ }
+ description
+ "This type represents the special-purpose MPLS label values.";
+ reference
+ "RFC 3032: MPLS Label Stack Encoding.
+ RFC 7274: Allocating and Retiring Special-Purpose MPLS
+ Labels.";
+ }
+
+ typedef mpls-label-general-use {
+ type uint32 {
+ range "16..1048575";
+ }
+ description
+ "The 20-bit label value in an MPLS label stack as specified
+ in RFC 3032. This label value does not include the
+ encodings of Traffic Class and TTL (Time to Live).
+ The label range specified by this type is for general use,
+ with special-purpose MPLS label values excluded.";
+ reference
+ "RFC 3032: MPLS Label Stack Encoding.";
+ }
+
+ typedef mpls-label {
+ type union {
+ type mpls-label-special-purpose;
+ type mpls-label-general-use;
+ }
+ description
+ "The 20-bit label value in an MPLS label stack as specified
+ in RFC 3032. This label value does not include the
+ encodings of Traffic Class and TTL.";
+ reference
+ "RFC 3032: MPLS Label Stack Encoding.";
+ }
+
+ /*** Groupings **/
+
+ grouping mpls-label-stack {
+ description
+ "This grouping specifies an MPLS label stack. The label
+ stack is encoded as a list of label stack entries. The
+ list key is an identifier that indicates the relative
+ ordering of each entry, with the lowest-value identifier
+ corresponding to the top of the label stack.";
+ container mpls-label-stack {
+ description
+ "Container for a list of MPLS label stack entries.";
+ list entry {
+ key "id";
+ description
+ "List of MPLS label stack entries.";
+ leaf id {
+ type uint8;
+ description
+ "Identifies the entry in a sequence of MPLS label
+ stack entries. An entry with a smaller identifier
+ value precedes an entry with a larger identifier
+ value in the label stack. The value of this ID has
+ no semantic meaning other than relative ordering
+ and referencing the entry.";
+ }
+ leaf label {
+ type rt-types:mpls-label;
+ description
+ "Label value.";
+ }
+
+ leaf ttl {
+ type uint8;
+ description
+ "Time to Live (TTL).";
+ reference
+ "RFC 3032: MPLS Label Stack Encoding.";
+ }
+ leaf traffic-class {
+ type uint8 {
+ range "0..7";
+ }
+ description
+ "Traffic Class (TC).";
+ reference
+ "RFC 5462: Multiprotocol Label Switching (MPLS) Label
+ Stack Entry: 'EXP' Field Renamed to 'Traffic Class'
+ Field.";
+ }
+ }
+ }
+ }
+
+ grouping vpn-route-targets {
+ description
+ "A grouping that specifies Route Target import-export rules
+ used in BGP-enabled VPNs.";
+ reference
+ "RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
+ RFC 4664: Framework for Layer 2 Virtual Private Networks
+ (L2VPNs).";
+ list vpn-target {
+ key "route-target";
+ description
+ "List of Route Targets.";
+ leaf route-target {
+ type rt-types:route-target;
+ description
+ "Route Target value.";
+ }
+ leaf route-target-type {
+ type rt-types:route-target-type;
+ mandatory true;
+ description
+ "Import/export type of the Route Target.";
+ }
+ }
+ }
+}
diff --git a/yang/libyang_plugins/frr_user_types.c b/yang/libyang_plugins/frr_user_types.c
index a293c3a88..48cdceccf 100644
--- a/yang/libyang_plugins/frr_user_types.c
+++ b/yang/libyang_plugins/frr_user_types.c
@@ -99,6 +99,21 @@ static int ipv6_prefix_store_clb(const char *type_name, const char *value_str,
return 0;
}
+static int ip_prefix_store_clb(const char *type_name, const char *value_str,
+ lyd_val *value, char **err_msg)
+{
+ value->ptr = malloc(sizeof(struct prefix));
+ if (!value->ptr)
+ return 1;
+
+ if (str2prefix(value_str, value->ptr) == 0) {
+ free(value->ptr);
+ return 1;
+ }
+
+ return 0;
+}
+
struct lytype_plugin_list frr_user_types[] = {
{"ietf-inet-types", "2013-07-15", "ipv4-address",
ipv4_address_store_clb, free},
@@ -114,5 +129,7 @@ struct lytype_plugin_list frr_user_types[] = {
free},
{"ietf-inet-types", "2013-07-15", "ipv6-prefix", ipv6_prefix_store_clb,
free},
+ {"ietf-inet-types", "2013-07-15", "ip-prefix", ip_prefix_store_clb,
+ free},
{NULL, NULL, NULL, NULL, NULL} /* terminating item */
};
diff --git a/yang/subdir.am b/yang/subdir.am
index 18d2bf160..b69239560 100644
--- a/yang/subdir.am
+++ b/yang/subdir.am
@@ -23,6 +23,7 @@ dist_yangmodels_DATA += yang/frr-module-translator.yang
dist_yangmodels_DATA += yang/frr-test-module.yang
dist_yangmodels_DATA += yang/frr-interface.yang
dist_yangmodels_DATA += yang/frr-route-types.yang
+dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang
if BFDD
dist_yangmodels_DATA += yang/frr-bfdd.yang
diff --git a/zebra/connected.c b/zebra/connected.c
index 6b92945c6..75f4f53bc 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -199,7 +199,7 @@ static void connected_update(struct interface *ifp, struct connected *ifc)
void connected_up(struct interface *ifp, struct connected *ifc)
{
afi_t afi;
- struct prefix p;
+ struct prefix p = {0};
struct nexthop nh = {
.type = NEXTHOP_TYPE_IFINDEX,
.ifindex = ifp->ifindex,
@@ -251,10 +251,10 @@ void connected_up(struct interface *ifp, struct connected *ifc)
metric = (ifc->metric < (uint32_t)METRIC_MAX) ?
ifc->metric : ifp->metric;
rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
- 0, 0, &p, NULL, &nh, zvrf->table_id, metric, 0, 0, 0);
+ 0, 0, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0);
rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
- 0, 0, &p, NULL, &nh, zvrf->table_id, metric, 0, 0, 0);
+ 0, 0, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0);
/* Schedule LSP forwarding entries for processing, if appropriate. */
if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
@@ -385,7 +385,7 @@ void connected_down(struct interface *ifp, struct connected *ifc)
return;
break;
default:
- zlog_info("Unknown AFI: %s", afi2str(afi));
+ zlog_warn("Unknown AFI: %s", afi2str(afi));
break;
}
@@ -393,11 +393,11 @@ void connected_down(struct interface *ifp, struct connected *ifc)
* Same logic as for connected_up(): push the changes into the
* head.
*/
- rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
- 0, 0, &p, NULL, &nh, zvrf->table_id, 0, 0, false);
+ rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
+ 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
- 0, 0, &p, NULL, &nh, zvrf->table_id, 0, 0, false);
+ 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
/* Schedule LSP forwarding entries for processing, if appropriate. */
if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index c71b95f75..c09007bcb 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -66,6 +66,7 @@
#include "zebra/zebra_ptm.h"
#include "zebra/zebra_mpls.h"
#include "zebra/kernel_netlink.h"
+#include "zebra/rt_netlink.h"
#include "zebra/if_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_vxlan.h"
@@ -365,7 +366,7 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
}
}
-static int get_iflink_speed(struct interface *interface)
+static int get_iflink_speed(struct interface *interface, int *error)
{
struct ifreq ifdata;
struct ethtool_cmd ecmd;
@@ -373,6 +374,8 @@ static int get_iflink_speed(struct interface *interface)
int rc;
const char *ifname = interface->name;
+ if (error)
+ *error = 0;
/* initialize struct */
memset(&ifdata, 0, sizeof(ifdata));
@@ -393,6 +396,9 @@ static int get_iflink_speed(struct interface *interface)
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Failure to read interface %s speed: %d %s",
ifname, errno, safe_strerror(errno));
+ /* no vrf socket creation may probably mean vrf issue */
+ if (error)
+ *error = -1;
return 0;
}
/* Get the current link state for the interface */
@@ -404,6 +410,9 @@ static int get_iflink_speed(struct interface *interface)
zlog_debug(
"IOCTL failure to read interface %s speed: %d %s",
ifname, errno, safe_strerror(errno));
+ /* no device means interface unreachable */
+ if (errno == ENODEV && error)
+ *error = -1;
ecmd.speed_hi = 0;
ecmd.speed = 0;
}
@@ -413,9 +422,9 @@ static int get_iflink_speed(struct interface *interface)
return (ecmd.speed_hi << 16) | ecmd.speed;
}
-uint32_t kernel_get_speed(struct interface *ifp)
+uint32_t kernel_get_speed(struct interface *ifp, int *error)
{
- return get_iflink_speed(ifp);
+ return get_iflink_speed(ifp, error);
}
static int netlink_extract_bridge_info(struct rtattr *link_data,
@@ -598,7 +607,6 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
ifindex_t link_ifindex = IFINDEX_INTERNAL;
ifindex_t bond_ifindex = IFINDEX_INTERNAL;
struct zebra_if *zif;
- struct vrf *vrf = NULL;
zns = zebra_ns_lookup(ns_id);
ifi = NLMSG_DATA(h);
@@ -682,7 +690,6 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
- vrf = vrf_get(vrf_id, NULL);
/* Add interface.
* We add by index first because in some cases such as the master
* interface, we have the index before we have the name. Fixing
@@ -691,12 +698,13 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
*/
ifp = if_get_by_ifindex(ifi->ifi_index, vrf_id);
set_ifindex(ifp, ifi->ifi_index, zns); /* add it to ns struct */
- strlcpy(ifp->name, name, sizeof(ifp->name));
- IFNAME_RB_INSERT(vrf, ifp);
+
+ if_set_name(ifp, name);
+
ifp->flags = ifi->ifi_flags & 0x0000fffff;
ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]);
ifp->metric = 0;
- ifp->speed = get_iflink_speed(ifp);
+ ifp->speed = get_iflink_speed(ifp, NULL);
ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
/* Set zebra interface type */
@@ -800,6 +808,23 @@ int interface_lookup_netlink(struct zebra_ns *zns)
/* fixup linkages */
zebra_if_update_all_links();
+ return 0;
+}
+
+/**
+ * interface_addr_lookup_netlink() - Look up interface addresses
+ *
+ * @zns: Zebra netlink socket
+ * Return: Result status
+ */
+static int interface_addr_lookup_netlink(struct zebra_ns *zns)
+{
+ int ret;
+ struct zebra_dplane_info dp_info;
+ struct nlsock *netlink_cmd = &zns->netlink_cmd;
+
+ /* Capture key info from ns struct */
+ zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
/* Get IPv4 address of the interfaces. */
ret = netlink_request_intf_addr(netlink_cmd, AF_INET, RTM_GETADDR, 0);
@@ -1032,7 +1057,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* addr is primary key, SOL if we don't have one */
if (addr == NULL) {
- zlog_debug("%s: NULL address", __func__);
+ zlog_debug("%s: Local Interface Address is NULL for %s",
+ __func__, ifp->name);
return -1;
}
@@ -1096,6 +1122,14 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
NULL, ifa->ifa_prefixlen);
}
+
+ /*
+ * Linux kernel does not send route delete on interface down/addr del
+ * so we have to re-process routes it owns (i.e. kernel routes)
+ */
+ if (h->nlmsg_type != RTM_NEWADDR)
+ rib_update(RIB_UPDATE_KERNEL);
+
return 0;
}
@@ -1324,6 +1358,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
"Intf %s(%u) has gone DOWN",
name, ifp->ifindex);
if_down(ifp);
+ rib_update(RIB_UPDATE_KERNEL);
} else if (if_is_operative(ifp)) {
/* Must notify client daemons of new
* interface status. */
@@ -1363,6 +1398,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
"Intf %s(%u) has gone DOWN",
name, ifp->ifindex);
if_down(ifp);
+ rib_update(RIB_UPDATE_KERNEL);
}
}
@@ -1376,6 +1412,13 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave)
zebra_l2if_update_bond_slave(ifp, bond_ifindex);
}
+
+ zif = ifp->info;
+ if (zif) {
+ XFREE(MTYPE_TMP, zif->desc);
+ if (desc)
+ zif->desc = XSTRDUP(MTYPE_TMP, desc);
+ }
} else {
/* Delete interface notification from kernel */
if (ifp == NULL) {
@@ -1402,13 +1445,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if_delete_update(ifp);
}
- zif = ifp->info;
- if (zif) {
- XFREE(MTYPE_TMP, zif->desc);
- if (desc)
- zif->desc = XSTRDUP(MTYPE_TMP, desc);
- }
-
return 0;
}
@@ -1442,6 +1478,13 @@ int netlink_protodown(struct interface *ifp, bool down)
void interface_list(struct zebra_ns *zns)
{
interface_lookup_netlink(zns);
+ /* We add routes for interface address,
+ * so we need to get the nexthop info
+ * from the kernel before we can do that
+ */
+ netlink_nexthop_read(zns);
+
+ interface_addr_lookup_netlink(zns);
}
#endif /* GNU_LINUX */
diff --git a/zebra/interface.c b/zebra/interface.c
index 6486c0143..daa93e36d 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -70,10 +70,19 @@ static int if_zebra_speed_update(struct thread *thread)
struct zebra_if *zif = ifp->info;
uint32_t new_speed;
bool changed = false;
+ int error = 0;
zif->speed_update = NULL;
- new_speed = kernel_get_speed(ifp);
+ new_speed = kernel_get_speed(ifp, &error);
+
+ /* error may indicate vrf not available or
+ * interfaces not available.
+ * note that loopback & virtual interfaces can return 0 as speed
+ */
+ if (error < 0)
+ return 1;
+
if (new_speed != ifp->speed) {
zlog_info("%s: %s old speed: %u new speed: %u",
__PRETTY_FUNCTION__, ifp->name, ifp->speed,
@@ -98,6 +107,17 @@ static void zebra_if_node_destroy(route_table_delegate_t *delegate,
route_node_destroy(delegate, table, node);
}
+static void zebra_if_nhg_dependents_free(struct zebra_if *zebra_if)
+{
+ nhg_connected_tree_free(&zebra_if->nhg_dependents);
+}
+
+static void zebra_if_nhg_dependents_init(struct zebra_if *zebra_if)
+{
+ nhg_connected_tree_init(&zebra_if->nhg_dependents);
+}
+
+
route_table_delegate_t zebra_if_table_delegate = {
.create_node = route_node_create,
.destroy_node = zebra_if_node_destroy};
@@ -111,6 +131,9 @@ static int if_zebra_new_hook(struct interface *ifp)
zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC;
zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
+
+ zebra_if_nhg_dependents_init(zebra_if);
+
zebra_ptm_if_init(zebra_if);
ifp->ptm_enable = zebra_ptm_get_enable_state();
@@ -166,6 +189,34 @@ static int if_zebra_new_hook(struct interface *ifp)
return 0;
}
+static void if_nhg_dependents_check_valid(struct nhg_hash_entry *nhe)
+{
+ zebra_nhg_check_valid(nhe);
+ if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID))
+ /* Assuming uninstalled as well here */
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+}
+
+static void if_down_nhg_dependents(const struct interface *ifp)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+ struct zebra_if *zif = (struct zebra_if *)ifp->info;
+
+ frr_each(nhg_connected_tree, &zif->nhg_dependents, rb_node_dep)
+ if_nhg_dependents_check_valid(rb_node_dep->nhe);
+}
+
+static void if_nhg_dependents_release(const struct interface *ifp)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+ struct zebra_if *zif = (struct zebra_if *)ifp->info;
+
+ frr_each(nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) {
+ rb_node_dep->nhe->ifp = NULL; /* Null it out */
+ if_nhg_dependents_check_valid(rb_node_dep->nhe);
+ }
+}
+
/* Called when interface is deleted. */
static int if_zebra_delete_hook(struct interface *ifp)
{
@@ -187,7 +238,11 @@ static int if_zebra_delete_hook(struct interface *ifp)
list_delete(&rtadv->AdvDNSSLList);
#endif /* HAVE_RTADV */
+ if_nhg_dependents_release(ifp);
+ zebra_if_nhg_dependents_free(zebra_if);
+
XFREE(MTYPE_TMP, zebra_if->desc);
+
THREAD_OFF(zebra_if->speed_update);
XFREE(MTYPE_ZINFO, zebra_if);
@@ -261,8 +316,10 @@ struct interface *if_lookup_by_name_per_ns(struct zebra_ns *ns,
for (rn = route_top(ns->if_table); rn; rn = route_next(rn)) {
ifp = (struct interface *)rn->info;
- if (ifp && strcmp(ifp->name, ifname) == 0)
+ if (ifp && strcmp(ifp->name, ifname) == 0) {
+ route_unlock_node(rn);
return (ifp);
+ }
}
return NULL;
@@ -767,6 +824,13 @@ void if_delete_update(struct interface *ifp)
memset(&zif->brslave_info, 0,
sizeof(struct zebra_l2info_brslave));
}
+
+ if (!ifp->configured) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("interface %s is being deleted from the system",
+ ifp->name);
+ if_delete(ifp);
+ }
}
/* VRF change for an interface */
@@ -907,6 +971,47 @@ static void if_down_del_nbr_connected(struct interface *ifp)
}
}
+void if_nhg_dependents_add(struct interface *ifp, struct nhg_hash_entry *nhe)
+{
+ if (ifp->info) {
+ struct zebra_if *zif = (struct zebra_if *)ifp->info;
+
+ nhg_connected_tree_add_nhe(&zif->nhg_dependents, nhe);
+ }
+}
+
+void if_nhg_dependents_del(struct interface *ifp, struct nhg_hash_entry *nhe)
+{
+ if (ifp->info) {
+ struct zebra_if *zif = (struct zebra_if *)ifp->info;
+
+ nhg_connected_tree_del_nhe(&zif->nhg_dependents, nhe);
+ }
+}
+
+unsigned int if_nhg_dependents_count(const struct interface *ifp)
+{
+ if (ifp->info) {
+ struct zebra_if *zif = (struct zebra_if *)ifp->info;
+
+ return nhg_connected_tree_count(&zif->nhg_dependents);
+ }
+
+ return 0;
+}
+
+
+bool if_nhg_dependents_is_empty(const struct interface *ifp)
+{
+ if (ifp->info) {
+ struct zebra_if *zif = (struct zebra_if *)ifp->info;
+
+ return nhg_connected_tree_is_empty(&zif->nhg_dependents);
+ }
+
+ return false;
+}
+
/* Interface is up. */
void if_up(struct interface *ifp)
{
@@ -970,6 +1075,8 @@ void if_down(struct interface *ifp)
zif->down_count++;
quagga_timestamp(2, zif->down_last, sizeof(zif->down_last));
+ if_down_nhg_dependents(ifp);
+
/* Handle interface down for specific types for EVPN. Non-VxLAN
* interfaces
* are checked to see if (remote) neighbor entries need to be purged
@@ -1556,7 +1663,7 @@ struct cmd_node interface_node = {INTERFACE_NODE, "%s(config-if)# ", 1};
#endif
/* Show all interfaces to vty. */
DEFPY(show_interface, show_interface_cmd,
- "show interface [vrf NAME$name] [brief$brief]",
+ "show interface [vrf NAME$vrf_name] [brief$brief]",
SHOW_STR
"Interface status and configuration\n"
VRF_CMD_HELP_STR
@@ -1568,8 +1675,8 @@ DEFPY(show_interface, show_interface_cmd,
interface_update_stats();
- if (name)
- VRF_GET_ID(vrf_id, name, false);
+ if (vrf_name)
+ VRF_GET_ID(vrf_id, vrf_name, false);
/* All interface print. */
vrf = vrf_lookup_by_id(vrf_id);
@@ -2034,13 +2141,13 @@ DEFUN (link_params_enable,
/* This command could be issue at startup, when activate MPLS TE */
/* on a new interface or after a ON / OFF / ON toggle */
/* In all case, TE parameters are reset to their default factory */
- if (IS_ZEBRA_DEBUG_EVENT)
+ if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS)
zlog_debug(
"Link-params: enable TE link parameters on interface %s",
ifp->name);
if (!if_link_params_get(ifp)) {
- if (IS_ZEBRA_DEBUG_EVENT)
+ if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS)
zlog_debug(
"Link-params: failed to init TE link parameters %s",
ifp->name);
@@ -2063,8 +2170,9 @@ DEFUN (no_link_params_enable,
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- zlog_debug("MPLS-TE: disable TE link parameters on interface %s",
- ifp->name);
+ if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug("MPLS-TE: disable TE link parameters on interface %s",
+ ifp->name);
if_link_params_free(ifp);
@@ -3195,6 +3303,11 @@ void zebra_if_init(void)
install_node(&interface_node, if_config_write);
install_node(&link_params_node, NULL);
if_cmd_init();
+ /*
+ * This is *intentionally* setting this to NULL, signaling
+ * that interface creation for zebra acts differently
+ */
+ if_zapi_callbacks(NULL, NULL, NULL, NULL);
install_element(VIEW_NODE, &show_interface_cmd);
install_element(VIEW_NODE, &show_interface_vrf_all_cmd);
diff --git a/zebra/interface.h b/zebra/interface.h
index e134b9b42..78ccbae62 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -27,6 +27,7 @@
#include "hook.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_nhg_private.h"
#ifdef __cplusplus
extern "C" {
@@ -277,6 +278,15 @@ struct zebra_if {
/* Installed addresses chains tree. */
struct route_table *ipv4_subnets;
+ /* Nexthops pointing to this interface */
+ /**
+ * Any nexthop that we get should have an
+ * interface. When an interface goes down,
+ * we will use this list to update the nexthops
+ * pointing to it with that info.
+ */
+ struct nhg_connected_tree_head nhg_dependents;
+
/* Information about up/down changes */
unsigned int up_count;
char up_last[QUAGGA_TIMESTAMP_LEN];
@@ -424,6 +434,14 @@ extern void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex,
extern void zebra_if_update_all_links(void);
extern void zebra_if_set_protodown(struct interface *ifp, bool down);
+/* Nexthop group connected functions */
+extern void if_nhg_dependents_add(struct interface *ifp,
+ struct nhg_hash_entry *nhe);
+extern void if_nhg_dependents_del(struct interface *ifp,
+ struct nhg_hash_entry *nhe);
+extern unsigned int if_nhg_dependents_count(const struct interface *ifp);
+extern bool if_nhg_dependents_is_empty(const struct interface *ifp);
+
extern void vrf_add_update(struct vrf *vrfp);
#ifdef HAVE_PROC_NET_DEV
diff --git a/zebra/irdp.h b/zebra/irdp.h
index ff4ab8dfb..c1ea34f3a 100644
--- a/zebra/irdp.h
+++ b/zebra/irdp.h
@@ -51,7 +51,7 @@ extern "C" {
#endif /* INADDR_ALLRTRS_GROUP */
/* Default irdp packet interval */
-#define IRDP_DEFAULT_INTERVAL 300
+#define IRDP_DEFAULT_INTERVAL 300
/* Router constants from RFC1256 */
#define MAX_INITIAL_ADVERT_INTERVAL 16
@@ -123,10 +123,10 @@ struct irdp_interface {
#define IF_ACTIVE (1<<0) /* ICMP Active */
#define IF_BROADCAST (1<<1) /* 255.255.255.255 */
#define IF_SOLICIT (1<<2) /* Solicit active */
-#define IF_DEBUG_MESSAGES (1<<3)
-#define IF_DEBUG_PACKET (1<<4)
-#define IF_DEBUG_MISC (1<<5)
-#define IF_SHUTDOWN (1<<6)
+#define IF_DEBUG_MESSAGES (1<<3)
+#define IF_DEBUG_PACKET (1<<4)
+#define IF_DEBUG_MISC (1<<5)
+#define IF_SHUTDOWN (1<<6)
struct interface *ifp;
struct thread *t_advertise;
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index f52b4746a..23f1a3bf8 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -99,6 +99,9 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
{RTM_NEWRULE, "RTM_NEWRULE"},
{RTM_DELRULE, "RTM_DELRULE"},
{RTM_GETRULE, "RTM_GETRULE"},
+ {RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP"},
+ {RTM_DELNEXTHOP, "RTM_DELNEXTHOP"},
+ {RTM_GETNEXTHOP, "RTM_GETNEXTHOP"},
{0}};
static const struct message rtproto_str[] = {
@@ -291,6 +294,10 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
return netlink_rule_change(h, ns_id, startup);
case RTM_DELRULE:
return netlink_rule_change(h, ns_id, startup);
+ case RTM_NEWNEXTHOP:
+ return netlink_nexthop_change(h, ns_id, startup);
+ case RTM_DELNEXTHOP:
+ return netlink_nexthop_change(h, ns_id, startup);
default:
/*
* If we have received this message then
@@ -884,15 +891,20 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
msg_type,
err->msg.nlmsg_seq,
err->msg.nlmsg_pid);
- } else
- flog_err(
- EC_ZEBRA_UNEXPECTED_MESSAGE,
- "%s error: %s, type=%s(%u), seq=%u, pid=%u",
- nl->name,
- safe_strerror(-errnum),
- nl_msg_type_to_str(msg_type),
- msg_type, err->msg.nlmsg_seq,
- err->msg.nlmsg_pid);
+ } else {
+ if ((msg_type != RTM_GETNEXTHOP)
+ || !startup)
+ flog_err(
+ EC_ZEBRA_UNEXPECTED_MESSAGE,
+ "%s error: %s, type=%s(%u), seq=%u, pid=%u",
+ nl->name,
+ safe_strerror(-errnum),
+ nl_msg_type_to_str(
+ msg_type),
+ msg_type,
+ err->msg.nlmsg_seq,
+ err->msg.nlmsg_pid);
+ }
return -1;
}
@@ -1096,7 +1108,8 @@ void kernel_init(struct zebra_ns *zns)
RTMGRP_IPV4_MROUTE |
RTMGRP_NEIGH |
(1 << (RTNLGRP_IPV4_RULE - 1)) |
- (1 << (RTNLGRP_IPV6_RULE - 1));
+ (1 << (RTNLGRP_IPV6_RULE - 1)) |
+ (1 << (RTNLGRP_NEXTHOP - 1));
snprintf(zns->netlink.name, sizeof(zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 60fbbcc05..c2812aa47 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -643,7 +643,7 @@ int ifm_read(struct if_msghdr *ifm)
if (ifp == NULL) {
/* Interface that zebra was not previously aware of, so
* create. */
- ifp = if_create(ifname, VRF_DEFAULT);
+ ifp = if_create_name(ifname, VRF_DEFAULT);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: creating ifp for ifindex %d",
__func__, ifm->ifm_index);
@@ -1139,16 +1139,17 @@ void rtm_read(struct rt_msghdr *rtm)
*/
if (rtm->rtm_type == RTM_CHANGE)
rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
- 0, zebra_flags, &p, NULL, NULL, RT_TABLE_MAIN,
- 0, 0, true);
+ 0, zebra_flags, &p, NULL, NULL, 0, RT_TABLE_MAIN, 0,
+ 0, true);
if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
|| rtm->rtm_type == RTM_CHANGE)
rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
- zebra_flags, &p, NULL, &nh, RT_TABLE_MAIN, 0, 0, 0, 0);
+ zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN,
+ 0, 0, 0, 0);
else
rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
- 0, zebra_flags, &p, NULL, &nh, RT_TABLE_MAIN,
- 0, 0, true);
+ 0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0,
+ 0, true);
}
/* Interface function for the kernel routing table updates. Support
diff --git a/zebra/main.c b/zebra/main.c
index 99607c0d7..334354eaa 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -142,6 +142,9 @@ static void sigint(void)
zlog_notice("Terminating on signal");
+ atomic_store_explicit(&zrouter.in_shutdown, true,
+ memory_order_relaxed);
+
frr_early_fini();
zebra_dplane_pre_finish();
@@ -162,6 +165,7 @@ static void sigint(void)
}
if (zrouter.lsp_process_q)
work_queue_free_and_null(&zrouter.lsp_process_q);
+
vrf_terminate();
ns_walk_func(zebra_ns_early_shutdown);
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 1ae2ba92b..4e0163f8a 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -119,7 +119,7 @@ static void zebra_redistribute(struct zserv *client, int type,
srcdest_rnode_prefixes(rn, &dst_p, &src_p);
- if (IS_ZEBRA_DEBUG_EVENT)
+ if (IS_ZEBRA_DEBUG_RIB)
zlog_debug(
"%s: client %s %s(%u) checking: selected=%d, type=%d, distance=%d, metric=%d zebra_check_addr=%d",
__func__,
@@ -149,7 +149,8 @@ static void zebra_redistribute(struct zserv *client, int type,
/* Either advertise a route for redistribution to registered clients or */
/* withdraw redistribution if add cannot be done for client */
void redistribute_update(const struct prefix *p, const struct prefix *src_p,
- struct route_entry *re, struct route_entry *prev_re)
+ const struct route_entry *re,
+ const struct route_entry *prev_re)
{
struct listnode *node, *nnode;
struct zserv *client;
@@ -200,7 +201,7 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
send_redistribute = 1;
if (send_redistribute) {
- if (IS_ZEBRA_DEBUG_EVENT) {
+ if (IS_ZEBRA_DEBUG_RIB) {
zlog_debug(
"%s: client %s %s(%u), type=%d, distance=%d, metric=%d",
__func__,
@@ -226,54 +227,102 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
}
}
+/*
+ * During a route delete, where 'new_re' is NULL, redist a delete to all
+ * clients registered for the type of 'old_re'.
+ * During a route update, redist a delete to any clients who will not see
+ * an update when the new route is installed. There are cases when a client
+ * may have seen a redist for 'old_re', but will not see
+ * the redist for 'new_re'.
+ */
void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
- struct route_entry *re)
+ const struct route_entry *old_re,
+ const struct route_entry *new_re)
{
struct listnode *node, *nnode;
struct zserv *client;
- char buf[INET6_ADDRSTRLEN];
int afi;
+ char buf[PREFIX_STRLEN];
+ vrf_id_t vrfid;
+
+ if (old_re)
+ vrfid = old_re->vrf_id;
+ else if (new_re)
+ vrfid = new_re->vrf_id;
+ else
+ return;
if (IS_ZEBRA_DEBUG_RIB) {
- inet_ntop(p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
- zlog_debug("%u:%s/%d: Redist delete re %p (%s)",
- re->vrf_id, buf, p->prefixlen, re,
- zebra_route_string(re->type));
+ zlog_debug(
+ "%u:%s: Redist del: re %p (%s), new re %p (%s)",
+ vrfid, prefix2str(p, buf, sizeof(buf)),
+ old_re,
+ old_re ? zebra_route_string(old_re->type) : "None",
+ new_re,
+ new_re ? zebra_route_string(new_re->type) : "None");
}
/* Add DISTANCE_INFINITY check. */
- if (re->distance == DISTANCE_INFINITY)
+ if (old_re && (old_re->distance == DISTANCE_INFINITY)) {
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("\tSkipping due to Infinite Distance");
return;
+ }
afi = family2afi(p->family);
if (!afi) {
flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF,
"%s: Unknown AFI/SAFI prefix received\n",
- __FUNCTION__);
+ __func__);
return;
}
+ /* Skip invalid (e.g. linklocal) prefix */
if (!zebra_check_addr(p)) {
- if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("Redist delete filter prefix %s",
- prefix2str(p, buf, sizeof(buf)));
+ if (IS_ZEBRA_DEBUG_RIB) {
+ zlog_debug(
+ "%u:%s: Redist del old: skipping invalid prefix",
+ vrfid, prefix2str(p, buf, sizeof(buf)));
+ }
return;
}
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
- if ((is_default_prefix(p)
- && vrf_bitmap_check(client->redist_default[afi],
- re->vrf_id))
- || vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL],
- re->vrf_id)
- || (re->instance
- && redist_check_instance(
- &client->mi_redist[afi][re->type],
- re->instance))
- || vrf_bitmap_check(client->redist[afi][re->type],
- re->vrf_id)) {
+ if (new_re) {
+ /* Skip this client if it will receive an update for the
+ * 'new' re
+ */
+ if (is_default_prefix(p)
+ && vrf_bitmap_check(client->redist_default[afi],
+ new_re->vrf_id))
+ continue;
+ else if (vrf_bitmap_check(
+ client->redist[afi][ZEBRA_ROUTE_ALL],
+ new_re->vrf_id))
+ continue;
+ else if (new_re->instance
+ && redist_check_instance(
+ &client->mi_redist[afi][new_re->type],
+ new_re->instance))
+ continue;
+ else if (vrf_bitmap_check(
+ client->redist[afi][new_re->type],
+ new_re->vrf_id))
+ continue;
+ }
+
+ /* Send a delete for the 'old' re to any subscribed client. */
+ if (old_re
+ && (vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL],
+ old_re->vrf_id)
+ || (old_re->instance
+ && redist_check_instance(
+ &client->mi_redist[afi][old_re->type],
+ old_re->instance))
+ || vrf_bitmap_check(client->redist[afi][old_re->type],
+ old_re->vrf_id))) {
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
- client, p, src_p, re);
+ client, p, src_p, old_re);
}
}
}
@@ -594,7 +643,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
afi = family2afi(rn->p.family);
if (rmap_name)
ret = zebra_import_table_route_map_check(
- afi, re->type, re->instance, &rn->p, re->ng.nexthop,
+ afi, re->type, re->instance, &rn->p, re->ng->nexthop,
zvrf->vrf->vrf_id, re->tag, rmap_name);
if (ret != RMAP_PERMITMATCH) {
@@ -627,10 +676,10 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
newre->metric = re->metric;
newre->mtu = re->mtu;
newre->table = zvrf->table_id;
- newre->nexthop_num = 0;
newre->uptime = monotime(NULL);
newre->instance = re->table;
- route_entry_copy_nexthops(newre, re->ng.nexthop);
+ newre->ng = nexthop_group_new();
+ route_entry_copy_nexthops(newre, re->ng->nexthop);
rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre);
@@ -647,7 +696,7 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
prefix_copy(&p, &rn->p);
rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE,
- re->table, re->flags, &p, NULL, re->ng.nexthop,
+ re->table, re->flags, &p, NULL, re->ng->nexthop, re->nhe_id,
zvrf->table_id, re->metric, re->distance, false);
return 0;
diff --git a/zebra/redistribute.h b/zebra/redistribute.h
index 30ff6bcd0..2685458f9 100644
--- a/zebra/redistribute.h
+++ b/zebra/redistribute.h
@@ -42,11 +42,19 @@ extern void zebra_redistribute_default_delete(ZAPI_HANDLER_ARGS);
extern void redistribute_update(const struct prefix *p,
const struct prefix *src_p,
- struct route_entry *re,
- struct route_entry *prev_re);
-extern void redistribute_delete(const struct prefix *p,
- const struct prefix *src_p,
- struct route_entry *re);
+ const struct route_entry *re,
+ const struct route_entry *prev_re);
+/*
+ * During a route delete, where 'new_re' is NULL, redist a delete to all
+ * clients registered for the type of 'old_re'.
+ * During a route update, redist a delete to any clients who will not see
+ * an update when the new route is installed. There are cases when a client
+ * may have seen a redist for 'old_re', but will not see
+ * the redist for 'new_re'.
+ */
+void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
+ const struct route_entry *old_re,
+ const struct route_entry *new_re);
extern void zebra_interface_up_update(struct interface *);
extern void zebra_interface_down_update(struct interface *);
diff --git a/zebra/rib.h b/zebra/rib.h
index b82428e54..35aa011c0 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -88,11 +88,14 @@ struct route_entry {
struct re_list_item next;
/* Nexthop structure (from RIB) */
- struct nexthop_group ng;
+ struct nexthop_group *ng;
/* Nexthop group from FIB (optional) */
struct nexthop_group fib_ng;
+ /* Nexthop group hash entry ID */
+ uint32_t nhe_id;
+
/* Tag */
route_tag_t tag;
@@ -135,10 +138,6 @@ struct route_entry {
/* Route has Failed installation into the Data Plane in some manner */
#define ROUTE_ENTRY_FAILED 0x20
- /* Nexthop information. */
- uint8_t nexthop_num;
- uint8_t nexthop_active_num;
-
/* Sequence value incremented for each dataplane operation */
uint32_t dplane_sequence;
@@ -154,13 +153,14 @@ struct route_entry {
#define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type)
/* meta-queue structure:
- * sub-queue 0: connected, kernel
- * sub-queue 1: static
- * sub-queue 2: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP
- * sub-queue 3: iBGP, eBGP
- * sub-queue 4: any other origin (if any)
+ * sub-queue 0: nexthop group objects
+ * sub-queue 1: connected, kernel
+ * sub-queue 2: static
+ * sub-queue 3: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP
+ * sub-queue 4: iBGP, eBGP
+ * sub-queue 5: any other origin (if any)
*/
-#define MQ_SIZE 5
+#define MQ_SIZE 6
struct meta_queue {
struct list *subq[MQ_SIZE];
uint32_t size; /* sum of lengths of all subqueues */
@@ -210,7 +210,7 @@ DECLARE_LIST(re_list, struct route_entry, next);
#define RIB_ROUTE_QUEUED(x) (1 << (x))
// If MQ_SIZE is modified this value needs to be updated.
-#define RIB_ROUTE_ANY_QUEUED 0x1F
+#define RIB_ROUTE_ANY_QUEUED 0x3F
/*
* The maximum qindex that can be used.
@@ -301,8 +301,10 @@ typedef struct rib_tables_iter_t_ {
/* Events/reasons triggering a RIB update. */
typedef enum {
+ RIB_UPDATE_KERNEL,
RIB_UPDATE_RMAP_CHANGE,
- RIB_UPDATE_OTHER
+ RIB_UPDATE_OTHER,
+ RIB_UPDATE_MAX
} rib_update_event_t;
extern struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *re,
@@ -362,8 +364,8 @@ extern void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re);
extern int rib_add(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,
- uint32_t table_id, uint32_t metric, uint32_t mtu,
- uint8_t distance, route_tag_t tag);
+ uint32_t nhe_id, uint32_t table_id, uint32_t metric,
+ uint32_t mtu, uint8_t distance, route_tag_t tag);
extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
struct prefix_ipv6 *src_p, struct route_entry *re);
@@ -371,8 +373,8 @@ extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, int flags, struct prefix *p,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
- uint32_t table_id, uint32_t metric, uint8_t distance,
- bool fromkernel);
+ uint32_t nhe_id, uint32_t table_id, uint32_t metric,
+ uint8_t distance, bool fromkernel);
extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
union g_addr *addr,
@@ -384,7 +386,8 @@ extern struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p,
vrf_id_t vrf_id);
-extern void rib_update(vrf_id_t vrf_id, rib_update_event_t event);
+extern void rib_update(rib_update_event_t event);
+extern void rib_update_vrf(vrf_id_t vrf_id, rib_update_event_t event);
extern void rib_update_table(struct route_table *table,
rib_update_event_t event);
extern int rib_sweep_route(struct thread *t);
@@ -395,7 +398,13 @@ extern unsigned long rib_score_proto(uint8_t proto, unsigned short instance);
extern unsigned long rib_score_proto_table(uint8_t proto,
unsigned short instance,
struct route_table *table);
-extern void rib_queue_add(struct route_node *rn);
+
+extern int rib_queue_add(struct route_node *rn);
+
+struct nhg_ctx; /* Forward declaration */
+
+extern int rib_queue_nhg_add(struct nhg_ctx *ctx);
+
extern void meta_queue_free(struct meta_queue *mq);
extern int zebra_rib_labeled_unicast(struct route_entry *re);
extern struct route_table *rib_table_ipv6;
@@ -524,7 +533,7 @@ static inline struct nexthop_group *rib_active_nhg(struct route_entry *re)
if (re->fib_ng.nexthop)
return &(re->fib_ng);
else
- return &(re->ng);
+ return re->ng;
}
extern void zebra_vty_init(void);
diff --git a/zebra/rt.h b/zebra/rt.h
index 59b42fed1..4b9a3f83f 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -40,13 +40,17 @@ extern "C" {
#define RSYSTEM_ROUTE(type) \
((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT)
+
/*
- * Update or delete a route, LSP, pseudowire, or vxlan MAC from the kernel,
- * using info from a dataplane context.
+ * Update or delete a route, nexthop, LSP, pseudowire, or vxlan MAC from the
+ * kernel, using info from a dataplane context.
*/
extern enum zebra_dplane_result kernel_route_update(
struct zebra_dplane_ctx *ctx);
+extern enum zebra_dplane_result
+kernel_nexthop_update(struct zebra_dplane_ctx *ctx);
+
extern enum zebra_dplane_result kernel_lsp_update(
struct zebra_dplane_ctx *ctx);
@@ -66,7 +70,7 @@ extern int kernel_interface_set_master(struct interface *master,
extern int mpls_kernel_init(void);
-extern uint32_t kernel_get_speed(struct interface *ifp);
+extern uint32_t kernel_get_speed(struct interface *ifp, int *error);
extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute);
/*
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 91a302403..915ad1a10 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -27,6 +27,7 @@
#include <linux/mpls_iptunnel.h>
#include <linux/neighbour.h>
#include <linux/rtnetlink.h>
+#include <linux/nexthop.h>
/* Hack for GNU libc version 2. */
#ifndef MSG_TRUNC
@@ -49,6 +50,7 @@
#include "vty.h"
#include "mpls.h"
#include "vxlan.h"
+#include "printfrr.h"
#include "zebra/zapi_msg.h"
#include "zebra/zebra_ns.h"
@@ -62,6 +64,7 @@
#include "zebra/zebra_mpls.h"
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
+#include "zebra/zebra_nhg.h"
#include "zebra/zebra_mroute.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_errors.h"
@@ -72,6 +75,8 @@
static vlanid_t filter_vlan = 0;
+static bool supports_nh;
+
struct gw_family_t {
uint16_t filler;
uint16_t family;
@@ -186,6 +191,7 @@ static inline int zebra2proto(int proto)
proto = RTPROT_OPENFABRIC;
break;
case ZEBRA_ROUTE_TABLE:
+ case ZEBRA_ROUTE_NHG:
proto = RTPROT_ZEBRA;
break;
default:
@@ -205,7 +211,7 @@ static inline int zebra2proto(int proto)
return proto;
}
-static inline int proto2zebra(int proto, int family)
+static inline int proto2zebra(int proto, int family, bool is_nexthop)
{
switch (proto) {
case RTPROT_BABEL:
@@ -249,6 +255,12 @@ static inline int proto2zebra(int proto, int family)
case RTPROT_OPENFABRIC:
proto = ZEBRA_ROUTE_OPENFABRIC;
break;
+ case RTPROT_ZEBRA:
+ if (is_nexthop) {
+ proto = ZEBRA_ROUTE_NHG;
+ break;
+ }
+ /* Intentional fall thru */
default:
/*
* When a user adds a new protocol this will show up
@@ -319,6 +331,169 @@ static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels)
return num_labels;
}
+static struct nexthop
+parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb,
+ enum blackhole_type bh_type, int index, void *prefsrc,
+ void *gate, afi_t afi, vrf_id_t vrf_id)
+{
+ struct interface *ifp = NULL;
+ struct nexthop nh = {0};
+ mpls_label_t labels[MPLS_MAX_LABELS] = {0};
+ int num_labels = 0;
+
+ vrf_id_t nh_vrf_id = vrf_id;
+ size_t sz = (afi == AFI_IP) ? 4 : 16;
+
+ if (bh_type == BLACKHOLE_UNSPEC) {
+ if (index && !gate)
+ nh.type = NEXTHOP_TYPE_IFINDEX;
+ else if (index && gate)
+ nh.type = (afi == AFI_IP) ? NEXTHOP_TYPE_IPV4_IFINDEX
+ : NEXTHOP_TYPE_IPV6_IFINDEX;
+ else if (!index && gate)
+ nh.type = (afi == AFI_IP) ? NEXTHOP_TYPE_IPV4
+ : NEXTHOP_TYPE_IPV6;
+ else {
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = bh_type;
+ }
+ } else {
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = bh_type;
+ }
+ nh.ifindex = index;
+ if (prefsrc)
+ memcpy(&nh.src, prefsrc, sz);
+ if (gate)
+ memcpy(&nh.gate, gate, sz);
+
+ if (index) {
+ ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), index);
+ if (ifp)
+ nh_vrf_id = ifp->vrf_id;
+ }
+ nh.vrf_id = nh_vrf_id;
+
+ if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
+ && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
+ == LWTUNNEL_ENCAP_MPLS) {
+ num_labels = parse_encap_mpls(tb[RTA_ENCAP], labels);
+ }
+
+ if (rtm->rtm_flags & RTNH_F_ONLINK)
+ SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK);
+
+ if (num_labels)
+ nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels);
+
+ return nh;
+}
+
+static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id,
+ struct route_entry *re,
+ struct rtmsg *rtm,
+ struct rtnexthop *rtnh,
+ struct rtattr **tb,
+ void *prefsrc, vrf_id_t vrf_id)
+{
+ void *gate = NULL;
+ struct interface *ifp = NULL;
+ int index = 0;
+ /* MPLS labels */
+ mpls_label_t labels[MPLS_MAX_LABELS] = {0};
+ int num_labels = 0;
+ struct rtattr *rtnh_tb[RTA_MAX + 1] = {};
+
+ int len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
+ vrf_id_t nh_vrf_id = vrf_id;
+
+ re->ng = nexthop_group_new();
+
+ for (;;) {
+ struct nexthop *nh = NULL;
+
+ if (len < (int)sizeof(*rtnh) || rtnh->rtnh_len > len)
+ break;
+
+ index = rtnh->rtnh_ifindex;
+ if (index) {
+ /*
+ * Yes we are looking this up
+ * for every nexthop and just
+ * using the last one looked
+ * up right now
+ */
+ ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
+ index);
+ if (ifp)
+ nh_vrf_id = ifp->vrf_id;
+ else {
+ flog_warn(
+ EC_ZEBRA_UNKNOWN_INTERFACE,
+ "%s: Unknown interface %u specified, defaulting to VRF_DEFAULT",
+ __PRETTY_FUNCTION__, index);
+ nh_vrf_id = VRF_DEFAULT;
+ }
+ } else
+ nh_vrf_id = vrf_id;
+
+ if (rtnh->rtnh_len > sizeof(*rtnh)) {
+ memset(rtnh_tb, 0, sizeof(rtnh_tb));
+
+ netlink_parse_rtattr(rtnh_tb, RTA_MAX, RTNH_DATA(rtnh),
+ rtnh->rtnh_len - sizeof(*rtnh));
+ if (rtnh_tb[RTA_GATEWAY])
+ gate = RTA_DATA(rtnh_tb[RTA_GATEWAY]);
+ if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE]
+ && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE])
+ == LWTUNNEL_ENCAP_MPLS) {
+ num_labels = parse_encap_mpls(
+ rtnh_tb[RTA_ENCAP], labels);
+ }
+ }
+
+ if (gate && rtm->rtm_family == AF_INET) {
+ if (index)
+ nh = route_entry_nexthop_ipv4_ifindex_add(
+ re, gate, prefsrc, index, nh_vrf_id);
+ else
+ nh = route_entry_nexthop_ipv4_add(
+ re, gate, prefsrc, nh_vrf_id);
+ } else if (gate && rtm->rtm_family == AF_INET6) {
+ if (index)
+ nh = route_entry_nexthop_ipv6_ifindex_add(
+ re, gate, index, nh_vrf_id);
+ else
+ nh = route_entry_nexthop_ipv6_add(re, gate,
+ nh_vrf_id);
+ } else
+ nh = route_entry_nexthop_ifindex_add(re, index,
+ nh_vrf_id);
+
+ if (nh) {
+ if (num_labels)
+ nexthop_add_labels(nh, ZEBRA_LSP_STATIC,
+ num_labels, labels);
+
+ if (rtnh->rtnh_flags & RTNH_F_ONLINK)
+ SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK);
+ }
+
+ if (rtnh->rtnh_len == 0)
+ break;
+
+ len -= NLMSG_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+
+ uint8_t nhop_num = nexthop_group_nexthop_num(re->ng);
+
+ if (!nhop_num)
+ nexthop_group_delete(&re->ng);
+
+ return nhop_num;
+}
+
/* Looking up routing table by netlink interface. */
static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
int startup)
@@ -340,6 +515,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
uint32_t mtu = 0;
uint8_t distance = 0;
route_tag_t tag = 0;
+ uint32_t nhe_id = 0;
void *dest = NULL;
void *gate = NULL;
@@ -347,10 +523,6 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
void *src = NULL; /* IPv6 srcdest source prefix */
enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
- /* MPLS labels */
- mpls_label_t labels[MPLS_MAX_LABELS] = {0};
- int num_labels = 0;
-
rtm = NLMSG_DATA(h);
if (startup && h->nlmsg_type != RTM_NEWROUTE)
@@ -423,7 +595,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
/* Route which inserted by Zebra. */
if (is_selfroute(rtm->rtm_protocol)) {
flags |= ZEBRA_FLAG_SELFROUTE;
- proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family);
+ proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family, false);
}
if (tb[RTA_OIF])
index = *(int *)RTA_DATA(tb[RTA_OIF]);
@@ -444,6 +616,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
if (tb[RTA_GATEWAY])
gate = RTA_DATA(tb[RTA_GATEWAY]);
+ if (tb[RTA_NH_ID])
+ nhe_id = *(uint32_t *)RTA_DATA(tb[RTA_NH_ID]);
+
if (tb[RTA_PRIORITY])
metric = *(int *)RTA_DATA(tb[RTA_PRIORITY]);
@@ -547,75 +722,24 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
afi = AFI_IP6;
if (h->nlmsg_type == RTM_NEWROUTE) {
- struct interface *ifp;
- vrf_id_t nh_vrf_id = vrf_id;
if (!tb[RTA_MULTIPATH]) {
- struct nexthop nh;
- size_t sz = (afi == AFI_IP) ? 4 : 16;
-
- memset(&nh, 0, sizeof(nh));
-
- if (bh_type == BLACKHOLE_UNSPEC) {
- if (index && !gate)
- nh.type = NEXTHOP_TYPE_IFINDEX;
- else if (index && gate)
- nh.type =
- (afi == AFI_IP)
- ? NEXTHOP_TYPE_IPV4_IFINDEX
- : NEXTHOP_TYPE_IPV6_IFINDEX;
- else if (!index && gate)
- nh.type = (afi == AFI_IP)
- ? NEXTHOP_TYPE_IPV4
- : NEXTHOP_TYPE_IPV6;
- else {
- nh.type = NEXTHOP_TYPE_BLACKHOLE;
- nh.bh_type = bh_type;
- }
- } else {
- nh.type = NEXTHOP_TYPE_BLACKHOLE;
- nh.bh_type = bh_type;
- }
- nh.ifindex = index;
- if (prefsrc)
- memcpy(&nh.src, prefsrc, sz);
- if (gate)
- memcpy(&nh.gate, gate, sz);
-
- if (index) {
- ifp = if_lookup_by_index_per_ns(
- zebra_ns_lookup(ns_id),
- index);
- if (ifp)
- nh_vrf_id = ifp->vrf_id;
- }
- nh.vrf_id = nh_vrf_id;
+ struct nexthop nh = {0};
- if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
- && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
- == LWTUNNEL_ENCAP_MPLS) {
- num_labels =
- parse_encap_mpls(tb[RTA_ENCAP], labels);
+ if (!nhe_id) {
+ nh = parse_nexthop_unicast(
+ ns_id, rtm, tb, bh_type, index, prefsrc,
+ gate, afi, vrf_id);
}
-
- if (rtm->rtm_flags & RTNH_F_ONLINK)
- SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK);
-
- if (num_labels)
- nexthop_add_labels(&nh, ZEBRA_LSP_STATIC,
- num_labels, labels);
-
rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p,
- &src_p, &nh, table, metric, mtu, distance, tag);
+ &src_p, &nh, nhe_id, table, metric, mtu,
+ distance, tag);
} else {
/* This is a multipath route */
-
struct route_entry *re;
struct rtnexthop *rtnh =
(struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]);
- len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
-
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
re->type = proto;
re->distance = distance;
@@ -624,148 +748,73 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
re->mtu = mtu;
re->vrf_id = vrf_id;
re->table = table;
- re->nexthop_num = 0;
re->uptime = monotime(NULL);
re->tag = tag;
+ re->nhe_id = nhe_id;
- for (;;) {
- struct nexthop *nh = NULL;
-
- if (len < (int)sizeof(*rtnh)
- || rtnh->rtnh_len > len)
- break;
-
- index = rtnh->rtnh_ifindex;
- if (index) {
- /*
- * Yes we are looking this up
- * for every nexthop and just
- * using the last one looked
- * up right now
- */
- ifp = if_lookup_by_index_per_ns(
- zebra_ns_lookup(ns_id),
- index);
- if (ifp)
- nh_vrf_id = ifp->vrf_id;
- else {
- flog_warn(
- EC_ZEBRA_UNKNOWN_INTERFACE,
- "%s: Unknown interface %u specified, defaulting to VRF_DEFAULT",
- __PRETTY_FUNCTION__,
- index);
- nh_vrf_id = VRF_DEFAULT;
- }
- } else
- nh_vrf_id = vrf_id;
-
- gate = 0;
- if (rtnh->rtnh_len > sizeof(*rtnh)) {
- memset(tb, 0, sizeof(tb));
- netlink_parse_rtattr(
- tb, RTA_MAX, RTNH_DATA(rtnh),
- rtnh->rtnh_len - sizeof(*rtnh));
- if (tb[RTA_GATEWAY])
- gate = RTA_DATA(
- tb[RTA_GATEWAY]);
- if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
- && *(uint16_t *)RTA_DATA(
- tb[RTA_ENCAP_TYPE])
- == LWTUNNEL_ENCAP_MPLS) {
- num_labels = parse_encap_mpls(
- tb[RTA_ENCAP], labels);
- }
- }
-
- if (gate) {
- if (rtm->rtm_family == AF_INET) {
- if (index)
- nh = route_entry_nexthop_ipv4_ifindex_add(
- re, gate,
- prefsrc, index,
- nh_vrf_id);
- else
- nh = route_entry_nexthop_ipv4_add(
- re, gate,
- prefsrc,
- nh_vrf_id);
- } else if (rtm->rtm_family
- == AF_INET6) {
- if (index)
- nh = route_entry_nexthop_ipv6_ifindex_add(
- re, gate, index,
- nh_vrf_id);
- else
- nh = route_entry_nexthop_ipv6_add(
- re, gate,
- nh_vrf_id);
- }
- } else
- nh = route_entry_nexthop_ifindex_add(
- re, index, nh_vrf_id);
-
- if (nh && num_labels)
- nexthop_add_labels(nh, ZEBRA_LSP_STATIC,
- num_labels, labels);
+ if (!nhe_id) {
+ uint8_t nhop_num =
+ parse_multipath_nexthops_unicast(
+ ns_id, re, rtm, rtnh, tb,
+ prefsrc, vrf_id);
- if (nh && (rtnh->rtnh_flags & RTNH_F_ONLINK))
- SET_FLAG(nh->flags,
- NEXTHOP_FLAG_ONLINK);
-
- if (rtnh->rtnh_len == 0)
- break;
-
- len -= NLMSG_ALIGN(rtnh->rtnh_len);
- rtnh = RTNH_NEXT(rtnh);
+ zserv_nexthop_num_warn(
+ __func__, (const struct prefix *)&p,
+ nhop_num);
}
- zserv_nexthop_num_warn(__func__,
- (const struct prefix *)&p,
- re->nexthop_num);
- if (re->nexthop_num == 0)
- XFREE(MTYPE_RE, re);
- else
+ if (nhe_id || re->ng)
rib_add_multipath(afi, SAFI_UNICAST, &p,
&src_p, re);
+ else
+ XFREE(MTYPE_RE, re);
}
} else {
- if (!tb[RTA_MULTIPATH]) {
- struct nexthop nh;
- size_t sz = (afi == AFI_IP) ? 4 : 16;
-
- memset(&nh, 0, sizeof(nh));
- if (bh_type == BLACKHOLE_UNSPEC) {
- if (index && !gate)
- nh.type = NEXTHOP_TYPE_IFINDEX;
- else if (index && gate)
- nh.type =
- (afi == AFI_IP)
- ? NEXTHOP_TYPE_IPV4_IFINDEX
- : NEXTHOP_TYPE_IPV6_IFINDEX;
- else if (!index && gate)
- nh.type = (afi == AFI_IP)
- ? NEXTHOP_TYPE_IPV4
- : NEXTHOP_TYPE_IPV6;
- else {
+ if (nhe_id) {
+ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
+ &p, &src_p, NULL, nhe_id, table, metric,
+ distance, true);
+ } else {
+ if (!tb[RTA_MULTIPATH]) {
+ struct nexthop nh;
+ size_t sz = (afi == AFI_IP) ? 4 : 16;
+
+ memset(&nh, 0, sizeof(nh));
+ if (bh_type == BLACKHOLE_UNSPEC) {
+ if (index && !gate)
+ nh.type = NEXTHOP_TYPE_IFINDEX;
+ else if (index && gate)
+ nh.type =
+ (afi == AFI_IP)
+ ? NEXTHOP_TYPE_IPV4_IFINDEX
+ : NEXTHOP_TYPE_IPV6_IFINDEX;
+ else if (!index && gate)
+ nh.type =
+ (afi == AFI_IP)
+ ? NEXTHOP_TYPE_IPV4
+ : NEXTHOP_TYPE_IPV6;
+ else {
+ nh.type =
+ NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = BLACKHOLE_UNSPEC;
+ }
+ } else {
nh.type = NEXTHOP_TYPE_BLACKHOLE;
- nh.bh_type = BLACKHOLE_UNSPEC;
+ nh.bh_type = bh_type;
}
+ nh.ifindex = index;
+ if (gate)
+ memcpy(&nh.gate, gate, sz);
+ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
+ flags, &p, &src_p, &nh, 0, table,
+ metric, distance, true);
} else {
- nh.type = NEXTHOP_TYPE_BLACKHOLE;
- nh.bh_type = bh_type;
+ /* XXX: need to compare the entire list of
+ * nexthops here for NLM_F_APPEND stupidity */
+ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
+ flags, &p, &src_p, NULL, 0, table,
+ metric, distance, true);
}
- nh.ifindex = index;
- if (gate)
- memcpy(&nh.gate, gate, sz);
- rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
- &p, &src_p, &nh, table, metric, distance,
- true);
- } else {
- /* XXX: need to compare the entire list of nexthops
- * here for NLM_F_APPEND stupidity */
- rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
- &p, &src_p, NULL, table, metric, distance,
- true);
}
}
@@ -1023,6 +1072,35 @@ static void _netlink_route_rta_add_gateway_info(uint8_t route_family,
}
}
+static int build_label_stack(struct mpls_label_stack *nh_label,
+ mpls_lse_t *out_lse, char *label_buf,
+ size_t label_buf_size)
+{
+ char label_buf1[20];
+ int num_labels = 0;
+
+ for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
+ if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+ continue;
+
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ if (!num_labels)
+ sprintf(label_buf, "label %u",
+ nh_label->label[i]);
+ else {
+ sprintf(label_buf1, "/%u", nh_label->label[i]);
+ strlcat(label_buf, label_buf1, label_buf_size);
+ }
+ }
+
+ out_lse[num_labels] =
+ mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+ num_labels++;
+ }
+
+ return num_labels;
+}
+
/* This function takes a nexthop as argument and adds
* the appropriate netlink attributes to an existing
* netlink message.
@@ -1040,10 +1118,12 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
struct rtmsg *rtmsg,
size_t req_size, int cmd)
{
- struct mpls_label_stack *nh_label;
+
mpls_lse_t out_lse[MPLS_MAX_LABELS];
- int num_labels = 0;
char label_buf[256];
+ int num_labels = 0;
+
+ assert(nexthop);
/*
* label_buf is *only* currently used within debugging.
@@ -1053,30 +1133,8 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
*/
label_buf[0] = '\0';
- assert(nexthop);
- char label_buf1[20];
-
- nh_label = nexthop->nh_label;
-
- for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
- if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
- continue;
-
- if (IS_ZEBRA_DEBUG_KERNEL) {
- if (!num_labels)
- sprintf(label_buf, "label %u",
- nh_label->label[i]);
- else {
- sprintf(label_buf1, "/%u", nh_label->label[i]);
- strlcat(label_buf, label_buf1,
- sizeof(label_buf));
- }
- }
-
- out_lse[num_labels] =
- mpls_lse_encode(nh_label->label[i], 0, 0, 0);
- num_labels++;
- }
+ num_labels = build_label_stack(nexthop->nh_label, out_lse, label_buf,
+ sizeof(label_buf));
if (num_labels) {
/* Set the BoS bit */
@@ -1221,16 +1279,17 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
struct rtmsg *rtmsg,
const union g_addr **src)
{
- struct mpls_label_stack *nh_label;
mpls_lse_t out_lse[MPLS_MAX_LABELS];
- int num_labels = 0;
char label_buf[256];
+ int num_labels = 0;
rtnh->rtnh_len = sizeof(*rtnh);
rtnh->rtnh_flags = 0;
rtnh->rtnh_hops = 0;
rta->rta_len += rtnh->rtnh_len;
+ assert(nexthop);
+
/*
* label_buf is *only* currently used within debugging.
* As such when we assign it we are guarding it inside
@@ -1239,30 +1298,8 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
*/
label_buf[0] = '\0';
- assert(nexthop);
- char label_buf1[20];
-
- nh_label = nexthop->nh_label;
-
- for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
- if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
- continue;
-
- if (IS_ZEBRA_DEBUG_KERNEL) {
- if (!num_labels)
- sprintf(label_buf, "label %u",
- nh_label->label[i]);
- else {
- sprintf(label_buf1, "/%u", nh_label->label[i]);
- strlcat(label_buf, label_buf1,
- sizeof(label_buf));
- }
- }
-
- out_lse[num_labels] =
- mpls_lse_encode(nh_label->label[i], 0, 0, 0);
- num_labels++;
- }
+ num_labels = build_label_stack(nexthop->nh_label, out_lse, label_buf,
+ sizeof(label_buf));
if (num_labels) {
/* Set the BoS bit */
@@ -1430,6 +1467,13 @@ static void _netlink_route_debug(int cmd, const struct prefix *p,
}
}
+static void _netlink_nexthop_debug(int cmd, uint32_t id)
+{
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("netlink_nexthop(): %s, id=%u",
+ nl_msg_type_to_str(cmd), id);
+}
+
static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc)
{
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1440,6 +1484,7 @@ static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc)
static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
int llalen, ns_id_t ns_id)
{
+ uint8_t protocol = RTPROT_ZEBRA;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
@@ -1460,6 +1505,8 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
req.ndm.ndm_ifindex = ifindex;
req.ndm.ndm_type = RTN_UNICAST;
+ addattr_l(&req.n, sizeof(req),
+ NDA_PROTOCOL, &protocol, sizeof(protocol));
addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
@@ -1592,6 +1639,13 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
RTA_PAYLOAD(rta));
}
+ if (supports_nh) {
+ /* Kernel supports nexthop objects */
+ addattr32(&req.n, sizeof(req), RTA_NH_ID,
+ dplane_ctx_get_nhe_id(ctx));
+ goto skip;
+ }
+
/* Count overall nexthops so we can decide whether to use singlepath
* or multipath case.
*/
@@ -1839,6 +1893,262 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
return suc;
}
+/* Char length to debug ID with */
+#define ID_LENGTH 10
+
+static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
+ uint32_t id,
+ const struct nh_grp *z_grp,
+ const uint8_t count)
+{
+ struct nexthop_grp grp[count];
+ /* Need space for max group size, "/", and null term */
+ char buf[(MULTIPATH_NUM * (ID_LENGTH + 1)) + 1];
+ char buf1[ID_LENGTH + 2];
+
+ buf[0] = '\0';
+
+ memset(grp, 0, sizeof(grp));
+
+ if (count) {
+ for (int i = 0; i < count; i++) {
+ grp[i].id = z_grp[i].id;
+ grp[i].weight = z_grp[i].weight;
+
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ if (i == 0)
+ snprintf(buf, sizeof(buf1), "group %u",
+ grp[i].id);
+ else {
+ snprintf(buf1, sizeof(buf1), "/%u",
+ grp[i].id);
+ strlcat(buf, buf1, sizeof(buf));
+ }
+ }
+ }
+ addattr_l(n, req_size, NHA_GROUP, grp, count * sizeof(*grp));
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: ID (%u): %s", __func__, id, buf);
+}
+
+/**
+ * netlink_nexthop() - Nexthop change via the netlink interface
+ *
+ * @ctx: Dataplane ctx
+ *
+ * Return: Result status
+ */
+static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
+{
+ struct {
+ struct nlmsghdr n;
+ struct nhmsg nhm;
+ char buf[NL_PKT_BUF_SIZE];
+ } req;
+
+ mpls_lse_t out_lse[MPLS_MAX_LABELS];
+ char label_buf[256];
+ int num_labels = 0;
+ size_t req_size = sizeof(req);
+
+ /* Nothing to do if the kernel doesn't support nexthop objects */
+ if (!supports_nh)
+ return 0;
+
+ label_buf[0] = '\0';
+
+ memset(&req, 0, req_size);
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
+ req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+
+ if (cmd == RTM_NEWNEXTHOP)
+ req.n.nlmsg_flags |= NLM_F_REPLACE;
+
+ req.n.nlmsg_type = cmd;
+ req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
+
+ req.nhm.nh_family = AF_UNSPEC;
+ /* TODO: Scope? */
+
+ uint32_t id = dplane_ctx_get_nhe_id(ctx);
+
+ if (!id) {
+ flog_err(
+ EC_ZEBRA_NHG_FIB_UPDATE,
+ "Failed trying to update a nexthop group in the kernel that does not have an ID");
+ return -1;
+ }
+
+ addattr32(&req.n, req_size, NHA_ID, id);
+
+ if (cmd == RTM_NEWNEXTHOP) {
+ if (dplane_ctx_get_nhe_nh_grp_count(ctx))
+ _netlink_nexthop_build_group(
+ &req.n, req_size, id,
+ dplane_ctx_get_nhe_nh_grp(ctx),
+ dplane_ctx_get_nhe_nh_grp_count(ctx));
+ else {
+ const struct nexthop *nh =
+ dplane_ctx_get_nhe_ng(ctx)->nexthop;
+ afi_t afi = dplane_ctx_get_nhe_afi(ctx);
+
+ if (afi == AFI_IP)
+ req.nhm.nh_family = AF_INET;
+ else if (afi == AFI_IP6)
+ req.nhm.nh_family = AF_INET6;
+
+ switch (nh->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ addattr_l(&req.n, req_size, NHA_GATEWAY,
+ &nh->gate.ipv4, IPV4_MAX_BYTELEN);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ addattr_l(&req.n, req_size, NHA_GATEWAY,
+ &nh->gate.ipv6, IPV6_MAX_BYTELEN);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ addattr_l(&req.n, req_size, NHA_BLACKHOLE, NULL,
+ 0);
+ /* Blackhole shouldn't have anymore attributes
+ */
+ goto nexthop_done;
+ case NEXTHOP_TYPE_IFINDEX:
+ /* Don't need anymore info for this */
+ break;
+ }
+
+ if (!nh->ifindex) {
+ flog_err(
+ EC_ZEBRA_NHG_FIB_UPDATE,
+ "Context received for kernel nexthop update without an interface");
+ return -1;
+ }
+
+ addattr32(&req.n, req_size, NHA_OIF, nh->ifindex);
+
+ num_labels =
+ build_label_stack(nh->nh_label, out_lse,
+ label_buf, sizeof(label_buf));
+
+ if (num_labels) {
+ /* Set the BoS bit */
+ out_lse[num_labels - 1] |=
+ htonl(1 << MPLS_LS_S_SHIFT);
+
+ /*
+ * TODO: MPLS unsupported for now in kernel.
+ */
+ if (req.nhm.nh_family == AF_MPLS)
+ goto nexthop_done;
+#if 0
+ addattr_l(&req.n, req_size, NHA_NEWDST,
+ &out_lse,
+ num_labels
+ * sizeof(mpls_lse_t));
+#endif
+ else {
+ struct rtattr *nest;
+ uint16_t encap = LWTUNNEL_ENCAP_MPLS;
+
+ addattr_l(&req.n, req_size,
+ NHA_ENCAP_TYPE, &encap,
+ sizeof(uint16_t));
+ nest = addattr_nest(&req.n, req_size,
+ NHA_ENCAP);
+ addattr_l(&req.n, req_size,
+ MPLS_IPTUNNEL_DST, &out_lse,
+ num_labels
+ * sizeof(mpls_lse_t));
+ addattr_nest_end(&req.n, nest);
+ }
+ }
+
+ nexthop_done:
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ char buf[NEXTHOP_STRLEN];
+
+ 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));
+
+ } else if (cmd != RTM_DELNEXTHOP) {
+ flog_err(
+ EC_ZEBRA_NHG_FIB_UPDATE,
+ "Nexthop group kernel update command (%d) does not exist",
+ cmd);
+ return -1;
+ }
+
+ _netlink_nexthop_debug(cmd, id);
+
+ return netlink_talk_info(netlink_talk_filter, &req.n,
+ dplane_ctx_get_ns(ctx), 0);
+}
+
+/**
+ * kernel_nexthop_update() - Update/delete a nexthop from the kernel
+ *
+ * @ctx: Dataplane context
+ *
+ * Return: Dataplane result flag
+ */
+enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
+{
+ 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:
+ 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));
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
+ }
+
+ ret = netlink_nexthop(cmd, ctx);
+
+ return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS
+ : ZEBRA_DPLANE_REQUEST_FAILURE);
+}
+
/*
* Update or delete a prefix from the kernel,
* using info from a dataplane context.
@@ -1916,6 +2226,303 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
}
+/**
+ * netlink_nexthop_process_nh() - Parse the gatway/if info from a new nexthop
+ *
+ * @tb: Netlink RTA data
+ * @family: Address family in the nhmsg
+ * @ifp: Interface connected - this should be NULL, we fill it in
+ * @ns_id: Namspace id
+ *
+ * Return: New nexthop
+ */
+static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
+ unsigned char family,
+ struct interface **ifp,
+ ns_id_t ns_id)
+{
+ struct nexthop nh = {};
+ void *gate = NULL;
+ enum nexthop_types_t type = 0;
+ int if_index = 0;
+ size_t sz = 0;
+ struct interface *ifp_lookup;
+
+ if_index = *(int *)RTA_DATA(tb[NHA_OIF]);
+
+
+ if (tb[NHA_GATEWAY]) {
+ switch (family) {
+ case AF_INET:
+ type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ sz = 4;
+ break;
+ case AF_INET6:
+ type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ sz = 16;
+ break;
+ default:
+ flog_warn(
+ EC_ZEBRA_BAD_NHG_MESSAGE,
+ "Nexthop gateway with bad address family (%d) received from kernel",
+ family);
+ return nh;
+ }
+ gate = RTA_DATA(tb[NHA_GATEWAY]);
+ } else
+ type = NEXTHOP_TYPE_IFINDEX;
+
+ if (type)
+ nh.type = type;
+
+ if (gate)
+ memcpy(&(nh.gate), gate, sz);
+
+ if (if_index)
+ nh.ifindex = if_index;
+
+ ifp_lookup =
+ if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex);
+
+ if (ifp)
+ *ifp = ifp_lookup;
+ if (ifp_lookup)
+ nh.vrf_id = ifp_lookup->vrf_id;
+ else {
+ flog_warn(
+ EC_ZEBRA_UNKNOWN_INTERFACE,
+ "%s: Unknown nexthop interface %u received, defaulting to VRF_DEFAULT",
+ __PRETTY_FUNCTION__, nh.ifindex);
+
+ nh.vrf_id = VRF_DEFAULT;
+ }
+
+ if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) {
+ uint16_t encap_type = *(uint16_t *)RTA_DATA(tb[NHA_ENCAP_TYPE]);
+ int num_labels = 0;
+
+ mpls_label_t labels[MPLS_MAX_LABELS] = {0};
+
+ if (encap_type == LWTUNNEL_ENCAP_MPLS)
+ num_labels = parse_encap_mpls(tb[NHA_ENCAP], labels);
+
+ if (num_labels)
+ nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels,
+ labels);
+ }
+
+ return nh;
+}
+
+static int netlink_nexthop_process_group(struct rtattr **tb,
+ struct nh_grp *z_grp, int z_grp_size)
+{
+ uint8_t count = 0;
+ /* linux/nexthop.h group struct */
+ struct nexthop_grp *n_grp = NULL;
+
+ n_grp = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
+ count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*n_grp));
+
+ if (!count || (count * sizeof(*n_grp)) != RTA_PAYLOAD(tb[NHA_GROUP])) {
+ flog_warn(EC_ZEBRA_BAD_NHG_MESSAGE,
+ "Invalid nexthop group received from the kernel");
+ return count;
+ }
+
+#if 0
+ // TODO: Need type for something?
+ zlog_debug("Nexthop group type: %d",
+ *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE])));
+
+#endif
+
+ for (int i = 0; ((i < count) && (i < z_grp_size)); i++) {
+ z_grp[i].id = n_grp[i].id;
+ z_grp[i].weight = n_grp[i].weight;
+ }
+ return count;
+}
+
+/**
+ * netlink_nexthop_change() - Read in change about nexthops from the kernel
+ *
+ * @h: Netlink message header
+ * @ns_id: Namspace id
+ * @startup: Are we reading under startup conditions?
+ *
+ * Return: Result status
+ */
+int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
+{
+ int len;
+ /* nexthop group id */
+ uint32_t id;
+ unsigned char family;
+ int type;
+ afi_t afi = AFI_UNSPEC;
+ vrf_id_t vrf_id = 0;
+ struct interface *ifp = NULL;
+ struct nhmsg *nhm = NULL;
+ struct nexthop nh = {};
+ struct nh_grp grp[MULTIPATH_NUM] = {};
+ /* Count of nexthops in group array */
+ uint8_t grp_count = 0;
+ struct rtattr *tb[NHA_MAX + 1] = {};
+
+ nhm = NLMSG_DATA(h);
+
+ if (startup && h->nlmsg_type != RTM_NEWNEXTHOP)
+ return 0;
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct nhmsg));
+ if (len < 0) {
+ zlog_warn(
+ "%s: Message received from netlink is of a broken size %d %zu",
+ __PRETTY_FUNCTION__, h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct nhmsg)));
+ return -1;
+ }
+
+ netlink_parse_rtattr(tb, NHA_MAX, RTM_NHA(nhm), len);
+
+
+ if (!tb[NHA_ID]) {
+ flog_warn(
+ EC_ZEBRA_BAD_NHG_MESSAGE,
+ "Nexthop group without an ID received from the kernel");
+ return -1;
+ }
+
+ /* We use the ID key'd nhg table for kernel updates */
+ id = *((uint32_t *)RTA_DATA(tb[NHA_ID]));
+
+ family = nhm->nh_family;
+ afi = family2afi(family);
+
+ type = proto2zebra(nhm->nh_protocol, 0, true);
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s ID (%u) %s NS %u",
+ nl_msg_type_to_str(h->nlmsg_type), id,
+ nl_family_to_str(family), ns_id);
+
+
+ if (h->nlmsg_type == RTM_NEWNEXTHOP) {
+ if (tb[NHA_GROUP]) {
+ /**
+ * If this is a group message its only going to have
+ * an array of nexthop IDs associated with it
+ */
+ grp_count = netlink_nexthop_process_group(
+ tb, grp, array_size(grp));
+ } else {
+ if (tb[NHA_BLACKHOLE]) {
+ /**
+ * This nexthop is just for blackhole-ing
+ * traffic, it should not have an OIF, GATEWAY,
+ * or ENCAP
+ */
+ nh.type = NEXTHOP_TYPE_BLACKHOLE;
+ nh.bh_type = BLACKHOLE_UNSPEC;
+ } else if (tb[NHA_OIF])
+ /**
+ * This is a true new nexthop, so we need
+ * to parse the gateway and device info
+ */
+ nh = netlink_nexthop_process_nh(tb, family,
+ &ifp, ns_id);
+ else {
+
+ flog_warn(
+ EC_ZEBRA_BAD_NHG_MESSAGE,
+ "Invalid Nexthop message received from the kernel with ID (%u)",
+ id);
+ return -1;
+ }
+ SET_FLAG(nh.flags, NEXTHOP_FLAG_ACTIVE);
+ if (nhm->nh_flags & RTNH_F_ONLINK)
+ SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK);
+ vrf_id = nh.vrf_id;
+ }
+
+ if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi,
+ type, startup))
+ return -1;
+
+ } else if (h->nlmsg_type == RTM_DELNEXTHOP)
+ zebra_nhg_kernel_del(id);
+
+ return 0;
+}
+
+#if 0 /* Force off kernel nexthop group installs for now */
+/**
+ * netlink_request_nexthop() - Request nextop information from the kernel
+ * @zns: Zebra namespace
+ * @family: AF_* netlink family
+ * @type: RTM_* route type
+ *
+ * Return: Result status
+ */
+static int netlink_request_nexthop(struct zebra_ns *zns, int family, int type)
+{
+ struct {
+ struct nlmsghdr n;
+ struct nhmsg nhm;
+ } req;
+
+ /* Form the request, specifying filter (rtattr) if needed. */
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_type = type;
+ req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
+ req.nhm.nh_family = family;
+
+ return netlink_request(&zns->netlink_cmd, &req.n);
+}
+
+
+/**
+ * netlink_nexthop_read() - Nexthop read function using netlink interface
+ *
+ * @zns: Zebra name space
+ *
+ * Return: Result status
+ * Only called at bootstrap time.
+ */
+int netlink_nexthop_read(struct zebra_ns *zns)
+{
+ int ret;
+ struct zebra_dplane_info dp_info;
+
+ zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
+
+ /* Get nexthop objects */
+ ret = netlink_request_nexthop(zns, AF_UNSPEC, RTM_GETNEXTHOP);
+ if (ret < 0)
+ return ret;
+ ret = netlink_parse_info(netlink_nexthop_change, &zns->netlink_cmd,
+ &dp_info, 0, 1);
+
+ if (!ret)
+ /* If we succesfully read in nexthop objects,
+ * this kernel must support them.
+ */
+ supports_nh = true;
+ else if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("Nexthop objects not supported on this kernel");
+
+ return ret;
+}
+#else
+int netlink_nexthop_read(struct zebra_ns *zns)
+{
+ return 0;
+}
+#endif
+
+
int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
int llalen, ns_id_t ns_id)
{
@@ -1930,6 +2537,7 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx,
int cmd)
{
+ uint8_t protocol = RTPROT_ZEBRA;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
@@ -1947,9 +2555,11 @@ static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx,
req.n.nlmsg_type = cmd;
req.ndm.ndm_family = PF_BRIDGE;
req.ndm.ndm_state = NUD_NOARP | NUD_PERMANENT;
- req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master"
+ req.ndm.ndm_flags |= NTF_SELF; /* Handle by "self", not "master" */
+ addattr_l(&req.n, sizeof(req),
+ NDA_PROTOCOL, &protocol, sizeof(protocol));
addattr_l(&req.n, sizeof(req), NDA_LLADDR, &dst_mac, 6);
req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
@@ -2297,6 +2907,7 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
static enum zebra_dplane_result
netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx)
{
+ uint8_t protocol = RTPROT_ZEBRA;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
@@ -2330,6 +2941,8 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx)
else
req.ndm.ndm_flags |= NTF_EXT_LEARNED;
+ addattr_l(&req.n, sizeof(req),
+ NDA_PROTOCOL, &protocol, sizeof(protocol));
addattr_l(&req.n, sizeof(req), NDA_LLADDR,
dplane_ctx_mac_get_addr(ctx), 6);
req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
@@ -2748,6 +3361,7 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
int cmd)
{
+ uint8_t protocol = RTPROT_ZEBRA;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
@@ -2782,6 +3396,8 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
req.ndm.ndm_type = RTN_UNICAST;
req.ndm.ndm_flags = flags;
+ addattr_l(&req.n, sizeof(req),
+ NDA_PROTOCOL, &protocol, sizeof(protocol));
ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len);
if (mac)
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index 29e0152bb..2b4b14514 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -69,6 +69,10 @@ extern int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx);
extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int netlink_route_read(struct zebra_ns *zns);
+extern int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id,
+ int startup);
+extern int netlink_nexthop_read(struct zebra_ns *zns);
+
extern int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id);
extern int netlink_macfdb_read(struct zebra_ns *zns);
extern int netlink_macfdb_read_for_bridge(struct zebra_ns *zns,
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
index dc0f29bdb..73b3dd0b4 100644
--- a/zebra/rt_socket.c
+++ b/zebra/rt_socket.c
@@ -364,6 +364,11 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
return res;
}
+enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
+{
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+}
+
int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
int llalen, ns_id_t ns_id)
{
@@ -396,7 +401,7 @@ extern int kernel_interface_set_master(struct interface *master,
return 0;
}
-uint32_t kernel_get_speed(struct interface *ifp)
+uint32_t kernel_get_speed(struct interface *ifp, int *error)
{
return ifp->speed;
}
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index b084fb99c..2228fcfd3 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -58,10 +58,10 @@ DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix")
/* If RFC2133 definition is used. */
#ifndef IPV6_JOIN_GROUP
-#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
#endif
#ifndef IPV6_LEAVE_GROUP
-#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
#endif
#define ALLNODE "ff02::1"
diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c
index 725bb63a0..3ba5d6ee7 100644
--- a/zebra/rtread_getmsg.c
+++ b/zebra/rtread_getmsg.c
@@ -102,7 +102,7 @@ static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry)
nh.gate.ipv4.s_addr = routeEntry->ipRouteNextHop;
rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
- zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0, 0);
+ zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0, 0, 0);
}
void route_read(struct zebra_ns *zns)
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index 8cc5b52b3..2fdb21512 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -54,6 +54,7 @@
*/
static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
{
+ uint8_t protocol = RTPROT_ZEBRA;
int family;
int bytelen;
struct {
@@ -78,13 +79,15 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
req.frh.family = family;
req.frh.action = FR_ACT_TO_TBL;
+ addattr_l(&req.n, sizeof(req),
+ FRA_PROTOCOL, &protocol, sizeof(protocol));
+
/* rule's pref # */
addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority);
/* interface on which applied */
- if (rule->ifp)
- addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifp->name,
- strlen(rule->ifp->name) + 1);
+ addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifname,
+ strlen(rule->ifname) + 1);
/* source IP, if specified */
if (IS_RULE_FILTERING_ON_SRC_IP(rule)) {
@@ -118,8 +121,7 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
zlog_debug(
"Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u",
nl_msg_type_to_str(cmd), nl_family_to_str(family),
- rule->ifp ? rule->ifp->name : "Unknown",
- rule->ifp ? rule->ifp->ifindex : 0, rule->rule.priority,
+ rule->ifname, rule->rule.ifindex, rule->rule.priority,
rule->rule.filter.fwmark,
prefix2str(&rule->rule.filter.src_ip, buf1,
sizeof(buf1)),
@@ -223,13 +225,15 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (tb[FRA_IFNAME] == NULL)
return 0;
- /* If we don't know the interface, we don't care. */
ifname = (char *)RTA_DATA(tb[FRA_IFNAME]);
zns = zebra_ns_lookup(ns_id);
- rule.ifp = if_lookup_by_name_per_ns(zns, ifname);
- if (!rule.ifp)
+
+ /* If we don't know the interface, we don't care. */
+ if (!if_lookup_by_name_per_ns(zns, ifname))
return 0;
+ strlcpy(rule.ifname, ifname, sizeof(rule.ifname));
+
if (tb[FRA_PRIORITY])
rule.rule.priority = *(uint32_t *)RTA_DATA(tb[FRA_PRIORITY]);
@@ -264,8 +268,8 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
zlog_debug(
"Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
nl_msg_type_to_str(h->nlmsg_type),
- nl_family_to_str(frh->family), rule.ifp->name,
- rule.ifp->ifindex, rule.rule.priority,
+ nl_family_to_str(frh->family), rule.ifname,
+ rule.rule.ifindex, rule.rule.priority,
prefix2str(&rule.rule.filter.src_ip, buf1,
sizeof(buf1)),
prefix2str(&rule.rule.filter.dst_ip, buf2,
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 25040a271..28847ce09 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -137,6 +137,7 @@ noinst_HEADERS += \
zebra/zebra_mpls.h \
zebra/zebra_mroute.h \
zebra/zebra_nhg.h \
+ zebra/zebra_nhg_private.h \
zebra/zebra_ns.h \
zebra/zebra_pbr.h \
zebra/zebra_ptm.h \
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 826d31ef3..d6ade783c 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -516,12 +516,13 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp)
int zsend_redistribute_route(int cmd, struct zserv *client,
const struct prefix *p,
- const struct prefix *src_p, struct route_entry *re)
+ const struct prefix *src_p,
+ const struct route_entry *re)
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
struct nexthop *nexthop;
- int count = 0;
+ uint8_t count = 0;
afi_t afi;
size_t stream_size =
MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route));
@@ -558,12 +559,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
memcpy(&api.src_prefix, src_p, sizeof(api.src_prefix));
}
- /* Nexthops. */
- if (re->nexthop_active_num) {
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = re->nexthop_active_num;
- }
- for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
+ for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) {
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
continue;
@@ -594,6 +590,12 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
count++;
}
+ /* Nexthops. */
+ if (count) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = count;
+ }
+
/* Attributes. */
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = re->distance;
@@ -664,7 +666,8 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client,
* nexthop we are looking up. Therefore, we will just iterate
* over the top chain of nexthops.
*/
- for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
+ for (nexthop = re->ng->nexthop; nexthop;
+ nexthop = nexthop->next)
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
num += zserv_encode_nexthop(s, nexthop);
@@ -782,10 +785,7 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
stream_putl(s, rule->rule.seq);
stream_putl(s, rule->rule.priority);
stream_putl(s, rule->rule.unique);
- if (rule->ifp)
- stream_putl(s, rule->ifp->ifindex);
- else
- stream_putl(s, 0);
+ stream_putl(s, rule->rule.ifindex);
stream_putw_at(s, 0, stream_get_endp(s));
@@ -1424,7 +1424,9 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
re->flags = api.flags;
re->uptime = monotime(NULL);
re->vrf_id = vrf_id;
- if (api.tableid && vrf_id == VRF_DEFAULT)
+ re->ng = nexthop_group_new();
+
+ if (api.tableid)
re->table = api.tableid;
else
re->table = zvrf->table_id;
@@ -1435,6 +1437,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
"%s: received a route without nexthops for prefix %pFX from client %s",
__func__, &api.prefix,
zebra_route_string(client->proto));
+
+ nexthop_group_delete(&re->ng);
XFREE(MTYPE_RE, re);
return;
}
@@ -1533,7 +1537,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
EC_ZEBRA_NEXTHOP_CREATION_FAILED,
"%s: Nexthops Specified: %d but we failed to properly create one",
__PRETTY_FUNCTION__, api.nexthop_num);
- nexthops_free(re->ng.nexthop);
+ nexthop_group_delete(&re->ng);
XFREE(MTYPE_RE, re);
return;
}
@@ -1575,7 +1579,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
flog_warn(EC_ZEBRA_RX_SRCDEST_WRONG_AFI,
"%s: Received SRC Prefix but afi is not v6",
__PRETTY_FUNCTION__);
- nexthops_free(re->ng.nexthop);
+ nexthop_group_delete(&re->ng);
XFREE(MTYPE_RE, re);
return;
}
@@ -1623,13 +1627,13 @@ static void zread_route_del(ZAPI_HANDLER_ARGS)
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
src_p = &api.src_prefix;
- if (api.vrf_id == VRF_DEFAULT && api.tableid != 0)
+ if (api.tableid)
table_id = api.tableid;
else
table_id = zvrf->table_id;
rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance,
- api.flags, &api.prefix, src_p, NULL, table_id, api.metric,
+ api.flags, &api.prefix, src_p, NULL, 0, table_id, api.metric,
api.distance, false);
/* Stats */
@@ -2293,7 +2297,6 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
struct zebra_pbr_rule zpr;
struct stream *s;
uint32_t total, i;
- ifindex_t ifindex;
s = msg;
STREAM_GETL(s, total);
@@ -2318,17 +2321,20 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
STREAM_GETW(s, zpr.rule.filter.dst_port);
STREAM_GETL(s, zpr.rule.filter.fwmark);
STREAM_GETL(s, zpr.rule.action.table);
- STREAM_GETL(s, ifindex);
+ STREAM_GETL(s, zpr.rule.ifindex);
+
+ if (zpr.rule.ifindex) {
+ struct interface *ifp;
- if (ifindex) {
- zpr.ifp = if_lookup_by_index_per_ns(
- zvrf->zns,
- ifindex);
- if (!zpr.ifp) {
+ ifp = if_lookup_by_index_per_ns(zvrf->zns,
+ zpr.rule.ifindex);
+ if (!ifp) {
zlog_debug("Failed to lookup ifindex: %u",
- ifindex);
+ zpr.rule.ifindex);
return;
}
+
+ strlcpy(zpr.ifname, ifp->name, sizeof(zpr.ifname));
}
if (!is_default_prefix(&zpr.rule.filter.src_ip))
diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h
index 884edfef0..996a255ff 100644
--- a/zebra/zapi_msg.h
+++ b/zebra/zapi_msg.h
@@ -65,7 +65,8 @@ extern int zsend_interface_update(int cmd, struct zserv *client,
extern int zsend_redistribute_route(int cmd, struct zserv *zclient,
const struct prefix *p,
const struct prefix *src_p,
- struct route_entry *re);
+ const struct route_entry *re);
+
extern int zsend_router_id_update(struct zserv *zclient, struct prefix *p,
vrf_id_t vrf_id);
extern int zsend_interface_vrf_update(struct zserv *zclient,
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 12f8a1ae3..a88b0a38d 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -67,6 +67,20 @@ const uint32_t DPLANE_DEFAULT_NEW_WORK = 100;
#endif /* DPLANE_DEBUG */
/*
+ * Nexthop information captured for nexthop/nexthop group updates
+ */
+struct dplane_nexthop_info {
+ uint32_t id;
+ afi_t afi;
+ vrf_id_t vrf_id;
+ int type;
+
+ struct nexthop_group ng;
+ struct nh_grp nh_grp[MULTIPATH_NUM];
+ uint8_t nh_grp_count;
+};
+
+/*
* Route information captured for route updates.
*/
struct dplane_route_info {
@@ -95,6 +109,9 @@ struct dplane_route_info {
uint32_t zd_mtu;
uint32_t zd_nexthop_mtu;
+ /* Nexthop hash entry info */
+ struct dplane_nexthop_info nhe;
+
/* Nexthops */
struct nexthop_group zd_ng;
@@ -321,6 +338,9 @@ static struct zebra_dplane_globals {
_Atomic uint32_t dg_route_errors;
_Atomic uint32_t dg_other_errors;
+ _Atomic uint32_t dg_nexthops_in;
+ _Atomic uint32_t dg_nexthop_errors;
+
_Atomic uint32_t dg_lsps_in;
_Atomic uint32_t dg_lsp_errors;
@@ -461,6 +481,18 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
break;
+ case DPLANE_OP_NH_INSTALL:
+ case DPLANE_OP_NH_UPDATE:
+ case DPLANE_OP_NH_DELETE: {
+ if ((*pctx)->u.rinfo.nhe.ng.nexthop) {
+ /* This deals with recursive nexthops too */
+ nexthops_free((*pctx)->u.rinfo.nhe.ng.nexthop);
+
+ (*pctx)->u.rinfo.nhe.ng.nexthop = NULL;
+ }
+ break;
+ }
+
case DPLANE_OP_LSP_INSTALL:
case DPLANE_OP_LSP_UPDATE:
case DPLANE_OP_LSP_DELETE:
@@ -638,6 +670,17 @@ const char *dplane_op2str(enum dplane_op_e op)
ret = "ROUTE_NOTIFY";
break;
+ /* Nexthop update */
+ case DPLANE_OP_NH_INSTALL:
+ ret = "NH_INSTALL";
+ break;
+ case DPLANE_OP_NH_UPDATE:
+ ret = "NH_UPDATE";
+ break;
+ case DPLANE_OP_NH_DELETE:
+ ret = "NH_DELETE";
+ break;
+
case DPLANE_OP_LSP_INSTALL:
ret = "LSP_INSTALL";
break;
@@ -1015,6 +1058,51 @@ const struct zebra_dplane_info *dplane_ctx_get_ns(
return &(ctx->zd_ns_info);
}
+/* Accessors for nexthop information */
+uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.nhe.id;
+}
+
+afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.nhe.afi;
+}
+
+vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.nhe.vrf_id;
+}
+
+int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.nhe.type;
+}
+
+const struct nexthop_group *
+dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return &(ctx->u.rinfo.nhe.ng);
+}
+
+const struct nh_grp *
+dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.nhe.nh_grp;
+}
+
+uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.nhe.nh_grp_count;
+}
+
/* Accessors for LSP information */
mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx)
@@ -1419,7 +1507,7 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
ctx->u.rinfo.zd_safi = info->safi;
/* Copy nexthops; recursive info is included too */
- copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng.nexthop, NULL);
+ copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng->nexthop, NULL);
/* Ensure that the dplane's nexthops flags are clear. */
for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop))
@@ -1437,6 +1525,29 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
zns = zvrf->zns;
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));
+
+ ctx->u.rinfo.nhe.id = nhe->id;
+ /*
+ * Check if the nhe is installed/queued before doing anything
+ * with this route.
+ *
+ * If its a delete we only use the prefix anyway, so this only
+ * matters for INSTALL/UPDATE.
+ */
+ if (((op == DPLANE_OP_ROUTE_INSTALL)
+ || (op == DPLANE_OP_ROUTE_UPDATE))
+ && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
+ && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
+ ret = ENOENT;
+ goto done;
+ }
+ }
+#endif /* HAVE_NETLINK */
+
/* Trying out the sequence number idea, so we can try to detect
* when a result is stale.
*/
@@ -1449,6 +1560,64 @@ done:
return ret;
}
+/**
+ * dplane_ctx_nexthop_init() - Initialize a context block for a nexthop update
+ *
+ * @ctx: Dataplane context to init
+ * @op: Operation being performed
+ * @nhe: Nexthop group hash entry
+ *
+ * Return: Result status
+ */
+static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op,
+ struct nhg_hash_entry *nhe)
+{
+ struct zebra_vrf *zvrf = NULL;
+ struct zebra_ns *zns = NULL;
+
+ int ret = EINVAL;
+
+ if (!ctx || !nhe)
+ goto done;
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ /* Copy over nhe info */
+ ctx->u.rinfo.nhe.id = nhe->id;
+ ctx->u.rinfo.nhe.afi = nhe->afi;
+ ctx->u.rinfo.nhe.vrf_id = nhe->vrf_id;
+ ctx->u.rinfo.nhe.type = nhe->type;
+
+ nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), nhe->nhg);
+
+ /* If its a group, convert it to a grp array of ids */
+ if (!zebra_nhg_depends_is_empty(nhe)
+ && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE))
+ ctx->u.rinfo.nhe.nh_grp_count = zebra_nhg_nhe2grp(
+ ctx->u.rinfo.nhe.nh_grp, nhe, MULTIPATH_NUM);
+
+ zvrf = vrf_info_lookup(nhe->vrf_id);
+
+ /*
+ * Fallback to default namespace if the vrf got ripped out from under
+ * us.
+ */
+ zns = zvrf ? zvrf->zns : zebra_ns_lookup(NS_DEFAULT);
+
+ /*
+ * TODO: Might not need to mark this as an update, since
+ * it probably won't require two messages
+ */
+ dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE));
+
+ ret = AOK;
+
+done:
+ return ret;
+}
+
/*
* Capture information for an LSP update in a dplane context.
*/
@@ -1577,7 +1746,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
if (re)
copy_nexthops(&(ctx->u.pw.nhg.nexthop),
- re->ng.nexthop, NULL);
+ re->ng->nexthop, NULL);
route_unlock_node(rn);
}
@@ -1673,7 +1842,7 @@ dplane_route_update_internal(struct route_node *rn,
* We'll need these to do per-nexthop deletes.
*/
copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
- old_re->ng.nexthop, NULL);
+ old_re->ng->nexthop, NULL);
#endif /* !HAVE_NETLINK */
}
@@ -1688,7 +1857,53 @@ dplane_route_update_internal(struct route_node *rn,
if (ret == AOK)
result = ZEBRA_DPLANE_REQUEST_QUEUED;
else {
- atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, 1,
+ if (ret == ENOENT)
+ result = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ else
+ atomic_fetch_add_explicit(&zdplane_info.dg_route_errors,
+ 1, memory_order_relaxed);
+ if (ctx)
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
+/**
+ * dplane_nexthop_update_internal() - Helper for enqueuing nexthop changes
+ *
+ * @nhe: Nexthop group hash entry where the change occured
+ * @op: The operation to be enqued
+ *
+ * Return: Result of the change
+ */
+static enum zebra_dplane_result
+dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret = EINVAL;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ /* Obtain context block */
+ ctx = dplane_ctx_alloc();
+ if (!ctx) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = dplane_ctx_nexthop_init(ctx, op, nhe);
+ if (ret == AOK)
+ ret = dplane_update_enqueue(ctx);
+
+done:
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_nexthop_errors, 1,
memory_order_relaxed);
if (ctx)
dplane_ctx_free(&ctx);
@@ -1853,6 +2068,45 @@ done:
}
/*
+ * Enqueue a nexthop add for the dataplane.
+ */
+enum zebra_dplane_result dplane_nexthop_add(struct nhg_hash_entry *nhe)
+{
+ enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ if (nhe)
+ ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_INSTALL);
+ return ret;
+}
+
+/*
+ * Enqueue a nexthop update for the dataplane.
+ *
+ * Might not need this func since zebra's nexthop objects should be immutable?
+ */
+enum zebra_dplane_result dplane_nexthop_update(struct nhg_hash_entry *nhe)
+{
+ enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ if (nhe)
+ ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_UPDATE);
+ return ret;
+}
+
+/*
+ * Enqueue a nexthop removal for the dataplane.
+ */
+enum zebra_dplane_result dplane_nexthop_delete(struct nhg_hash_entry *nhe)
+{
+ enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ if (nhe)
+ ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_DELETE);
+
+ return ret;
+}
+
+/*
* Enqueue LSP add for the dataplane.
*/
enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp)
@@ -2511,6 +2765,18 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed)
}
/*
+ * Helper for 'show run' etc.
+ */
+int dplane_config_write_helper(struct vty *vty)
+{
+ if (zdplane_info.dg_max_queued_updates != DPLANE_DEFAULT_MAX_QUEUED)
+ vty_out(vty, "zebra dplane limit %u\n",
+ zdplane_info.dg_max_queued_updates);
+
+ return 0;
+}
+
+/*
* Provider registration
*/
int dplane_provider_register(const char *name,
@@ -2861,6 +3127,33 @@ kernel_dplane_address_update(struct zebra_dplane_ctx *ctx)
return res;
}
+/**
+ * kernel_dplane_nexthop_update() - Handler for kernel nexthop updates
+ *
+ * @ctx: Dataplane context
+ *
+ * Return: Dataplane result flag
+ */
+static enum zebra_dplane_result
+kernel_dplane_nexthop_update(struct zebra_dplane_ctx *ctx)
+{
+ enum zebra_dplane_result res;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ zlog_debug("ID (%u) Dplane nexthop update ctx %p op %s",
+ dplane_ctx_get_nhe_id(ctx), ctx,
+ dplane_op2str(dplane_ctx_get_op(ctx)));
+ }
+
+ res = kernel_nexthop_update(ctx);
+
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(&zdplane_info.dg_nexthop_errors, 1,
+ memory_order_relaxed);
+
+ return res;
+}
+
/*
* Handler for kernel-facing EVPN MAC address updates
*/
@@ -2955,6 +3248,12 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
res = kernel_dplane_route_update(ctx);
break;
+ case DPLANE_OP_NH_INSTALL:
+ case DPLANE_OP_NH_UPDATE:
+ case DPLANE_OP_NH_DELETE:
+ res = kernel_dplane_nexthop_update(ctx);
+ break;
+
case DPLANE_OP_LSP_INSTALL:
case DPLANE_OP_LSP_UPDATE:
case DPLANE_OP_LSP_DELETE:
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 30dfdafdf..fede3bfcc 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -30,6 +30,7 @@
#include "zebra/rib.h"
#include "zebra/zserv.h"
#include "zebra/zebra_mpls.h"
+#include "zebra/zebra_nhg.h"
#ifdef __cplusplus
extern "C" {
@@ -108,6 +109,11 @@ enum dplane_op_e {
DPLANE_OP_ROUTE_DELETE,
DPLANE_OP_ROUTE_NOTIFY,
+ /* Nexthop update */
+ DPLANE_OP_NH_INSTALL,
+ DPLANE_OP_NH_UPDATE,
+ DPLANE_OP_NH_DELETE,
+
/* LSP update */
DPLANE_OP_LSP_INSTALL,
DPLANE_OP_LSP_UPDATE,
@@ -269,6 +275,17 @@ const struct nexthop_group *dplane_ctx_get_ng(
const struct nexthop_group *dplane_ctx_get_old_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);
+vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx);
+const struct nexthop_group *
+dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx);
+const struct nh_grp *
+dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx);
+uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx);
+
/* Accessors for LSP information */
mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_in_label(struct zebra_dplane_ctx *ctx,
@@ -373,6 +390,16 @@ enum zebra_dplane_result dplane_route_notif_update(
enum dplane_op_e op,
struct zebra_dplane_ctx *ctx);
+
+/* Forward ref of nhg_hash_entry */
+struct nhg_hash_entry;
+/*
+ * Enqueue a nexthop change operation for the dataplane.
+ */
+enum zebra_dplane_result dplane_nexthop_add(struct nhg_hash_entry *nhe);
+enum zebra_dplane_result dplane_nexthop_update(struct nhg_hash_entry *nhe);
+enum zebra_dplane_result dplane_nexthop_delete(struct nhg_hash_entry *nhe);
+
/*
* Enqueue LSP change operations for the dataplane.
*/
@@ -455,6 +482,7 @@ uint32_t dplane_get_in_queue_len(void);
*/
int dplane_show_helper(struct vty *vty, bool detailed);
int dplane_show_provs_helper(struct vty *vty, bool detailed);
+int dplane_config_write_helper(struct vty *vty);
/*
* Dataplane providers: modules that process or consume dataplane events.
diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c
index a7e5147af..5a0905d59 100644
--- a/zebra/zebra_errors.c
+++ b/zebra/zebra_errors.c
@@ -283,6 +283,39 @@ static struct log_ref ferr_zebra_err[] = {
.description = "Zebra received an event from inotify, but failed to read what it was.",
.suggestion = "Notify a developer.",
},
+ {
+ .code = EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
+ .title =
+ "Nexthop Group Hash Table Insert Failure",
+ .description =
+ "Zebra failed in inserting a Nexthop Group into its hash tables.",
+ .suggestion =
+ "Check to see if the entry already exists or if the netlink message was parsed incorrectly."
+ },
+ {
+ .code = EC_ZEBRA_NHG_SYNC,
+ .title =
+ "Zebra's Nexthop Groups are out of sync",
+ .description =
+ "Zebra's nexthop group tables are out of sync with the nexthop groups in the fib.",
+ .suggestion =
+ "Check the current status of the kernels nexthop groups and compare it to Zebra's."
+ },
+ {
+ .code = EC_ZEBRA_NHG_FIB_UPDATE,
+ .title =
+ "Zebra failed updating the fib with Nexthop Group",
+ .description =
+ "Zebra was not able to successfully install a new nexthop group into the fib",
+ .suggestion =
+ "Check to see if the nexthop group on the route you tried to install is valid."
+ },
+ {
+ .code = EC_ZEBRA_IF_LOOKUP_FAILED,
+ .title = "Zebra interface lookup failed",
+ .description = "Zebra attempted to look up a interface for a particular vrf_id and interface index, but didn't find anything.",
+ .suggestion = "If you entered a command to trigger this error, make sure you entered the arguments correctly. Check your config file for any potential errors. If these look correct, seek help.",
+ },
/* Warnings */
{
.code = EC_ZEBRAING_LM_PROTO_MISMATCH,
@@ -729,6 +762,24 @@ static struct log_ref ferr_zebra_err[] = {
"Check network topology to detect duplicate host IP for correctness.",
},
{
+ .code = EC_ZEBRA_BAD_NHG_MESSAGE,
+ .title =
+ "Bad Nexthop Group Message",
+ .description =
+ "Zebra received Nexthop Group message from the kernel that it cannot process.",
+ .suggestion =
+ "Check the kernel's link states and routing table to see how it matches ours."
+ },
+ {
+ .code = EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
+ .title =
+ "Duplicate Nexthop Group Message",
+ .description =
+ "Zebra received Nexthop Group message from the kernel that it is identical to one it/we already have but with a different ID.",
+ .suggestion =
+ "See if the nexthop you are trying to add is already present in the fib."
+ },
+ {
.code = END_FERR,
}
};
diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h
index 222055dd8..f9ccc2db2 100644
--- a/zebra/zebra_errors.h
+++ b/zebra/zebra_errors.h
@@ -72,6 +72,10 @@ enum zebra_log_refs {
EC_ZEBRA_VNI_DEL_FAILED,
EC_ZEBRA_VTEP_ADD_FAILED,
EC_ZEBRA_VNI_ADD_FAILED,
+ EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
+ EC_ZEBRA_NHG_SYNC,
+ EC_ZEBRA_NHG_FIB_UPDATE,
+ EC_ZEBRA_IF_LOOKUP_FAILED,
/* warnings */
EC_ZEBRA_NS_NOTIFY_READ,
EC_ZEBRAING_LM_PROTO_MISMATCH,
@@ -125,6 +129,8 @@ enum zebra_log_refs {
EC_ZEBRA_DUP_MAC_DETECTED,
EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
EC_ZEBRA_DUP_IP_DETECTED,
+ EC_ZEBRA_BAD_NHG_MESSAGE,
+ EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
};
void zebra_error_init(void);
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 4144c0afe..5d88d4eeb 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -711,7 +711,6 @@ static void zfpm_connection_down(const char *detail)
* Start thread to clean up state after the connection goes down.
*/
assert(!zfpm_g->t_conn_down);
- zfpm_debug("Starting conn_down thread");
zfpm_rnodes_iter_init(&zfpm_g->t_conn_down_state.iter);
zfpm_g->t_conn_down = NULL;
thread_add_timer_msec(zfpm_g->master, zfpm_conn_down_thread_cb, NULL, 0,
@@ -806,8 +805,6 @@ static int zfpm_read_cb(struct thread *thread)
goto done;
}
- zfpm_debug("Read out a full fpm message");
-
/*
* Just throw it away for now.
*/
@@ -1249,7 +1246,7 @@ static int zfpm_connect_cb(struct thread *t)
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
- zfpm_debug("Failed to create socket for connect(): %s",
+ zlog_err("Failed to create socket for connect(): %s",
strerror(errno));
zfpm_g->stats.connect_no_sock++;
return 0;
diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c
index e87fa0ad7..debcf60ee 100644
--- a/zebra/zebra_fpm_dt.c
+++ b/zebra/zebra_fpm_dt.c
@@ -90,7 +90,7 @@ static int zfpm_dt_find_route(rib_dest_t **dest_p, struct route_entry **re_p)
if (!re)
continue;
- if (re->nexthop_active_num <= 0)
+ if (nexthop_group_active_nexthop_num(re->ng) == 0)
continue;
*dest_p = dest;
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index f347d3955..b54d8fbc1 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -314,7 +314,7 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd,
ri->rtm_type = RTN_UNICAST;
ri->metric = &re->metric;
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) {
if (ri->num_nhs >= zrouter.multipath_num)
break;
diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c
index 3054b8a34..a11517ab8 100644
--- a/zebra/zebra_fpm_protobuf.c
+++ b/zebra/zebra_fpm_protobuf.c
@@ -173,7 +173,7 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator,
* Figure out the set of nexthops to be added to the message.
*/
num_nhs = 0;
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) {
if (num_nhs >= zrouter.multipath_num)
break;
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 3c4497ebd..ef1bd0260 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -185,7 +185,7 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
* the label advertised by the recursive nexthop (plus we don't have the
* logic yet to push multiple labels).
*/
- for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
+ for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) {
/* Skip inactive and recursive entries. */
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
continue;
@@ -635,7 +635,7 @@ static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe,
|| !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
continue;
- for (match_nh = match->ng.nexthop; match_nh;
+ for (match_nh = match->ng->nexthop; match_nh;
match_nh = match_nh->next) {
if (match->type == ZEBRA_ROUTE_CONNECT
|| nexthop->ifindex == match_nh->ifindex) {
@@ -686,10 +686,10 @@ static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe,
break;
}
- if (!match || !match->ng.nexthop)
+ if (!match || !match->ng->nexthop)
return 0;
- nexthop->ifindex = match->ng.nexthop->ifindex;
+ nexthop->ifindex = match->ng->nexthop->ifindex;
return 1;
}
@@ -2326,8 +2326,10 @@ static int zebra_mpls_cleanup_zclient_labels(struct zserv *client)
&args);
/* Cleanup FTNs. */
- mpls_ftn_uninstall_all(zvrf, AFI_IP, client->proto);
- mpls_ftn_uninstall_all(zvrf, AFI_IP6, client->proto);
+ mpls_ftn_uninstall_all(zvrf, AFI_IP,
+ lsp_type_from_re_type(client->proto));
+ mpls_ftn_uninstall_all(zvrf, AFI_IP6,
+ lsp_type_from_re_type(client->proto));
}
return 0;
@@ -2588,11 +2590,13 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
struct route_node *rn;
struct route_entry *re;
struct nexthop *nexthop;
+ struct nexthop_group new_grp = {};
+ struct nhg_hash_entry *nhe = NULL;
bool found;
+ afi_t afi = family2afi(prefix->family);
/* Lookup table. */
- table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
- zvrf_id(zvrf));
+ table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
if (!table)
return -1;
@@ -2608,8 +2612,15 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
if (re == NULL)
return -1;
+ /*
+ * Copy over current nexthops into a temporary group.
+ * We can't just change the values here since we are hashing
+ * on labels. We need to create a whole new group
+ */
+ nexthop_group_copy(&new_grp, re->ng);
+
found = false;
- for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
+ for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) {
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
@@ -2623,7 +2634,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
continue;
if (!mpls_ftn_update_nexthop(add, nexthop, type,
out_label))
- return 0;
+ break;
found = true;
break;
case NEXTHOP_TYPE_IPV6:
@@ -2638,7 +2649,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
continue;
if (!mpls_ftn_update_nexthop(add, nexthop, type,
out_label))
- return 0;
+ break;
found = true;
break;
default:
@@ -2646,14 +2657,19 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
}
}
- if (!found)
- return -1;
+ if (found) {
+ nhe = zebra_nhg_rib_find(0, &new_grp, afi);
- SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
- SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
- rib_queue_add(rn);
+ zebra_nhg_re_update_ref(re, nhe);
- return 0;
+ SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
+ SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+ rib_queue_add(rn);
+ }
+
+ nexthops_free(new_grp.nexthop);
+
+ return found ? 0 : -1;
}
int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
@@ -2682,7 +2698,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
if (re == NULL)
return -1;
- for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
+ for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next)
nexthop_del_labels(nexthop);
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
@@ -2887,7 +2903,12 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
for (rn = route_top(table); rn; rn = route_next(rn)) {
update = 0;
RNODE_FOREACH_RE (rn, re) {
- for (nexthop = re->ng.nexthop; nexthop;
+ struct nexthop_group new_grp = {};
+ struct nhg_hash_entry *nhe = NULL;
+
+ nexthop_group_copy(&new_grp, re->ng);
+
+ for (nexthop = new_grp.nexthop; nexthop;
nexthop = nexthop->next) {
if (nexthop->nh_label_type != lsp_type)
continue;
@@ -2898,6 +2919,14 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
ROUTE_ENTRY_LABELS_CHANGED);
update = 1;
}
+
+ if (CHECK_FLAG(re->status,
+ ROUTE_ENTRY_LABELS_CHANGED)) {
+ nhe = zebra_nhg_rib_find(0, &new_grp, afi);
+ zebra_nhg_re_update_ref(re, nhe);
+ }
+
+ nexthops_free(new_grp.nexthop);
}
if (update)
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 35df02a19..05da25b2b 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -26,14 +26,1093 @@
#include "lib/nexthop_group_private.h"
#include "lib/routemap.h"
#include "lib/mpls.h"
+#include "lib/jhash.h"
+#include "lib/debug.h"
#include "zebra/connected.h"
#include "zebra/debug.h"
#include "zebra/zebra_router.h"
-#include "zebra/zebra_nhg.h"
+#include "zebra/zebra_nhg_private.h"
#include "zebra/zebra_rnh.h"
#include "zebra/zebra_routemap.h"
+#include "zebra/zebra_memory.h"
+#include "zebra/zserv.h"
#include "zebra/rt.h"
+#include "zebra_errors.h"
+#include "zebra_dplane.h"
+#include "zebra/interface.h"
+
+DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
+DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
+DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
+
+/* id counter to keep in sync with kernel */
+uint32_t id_counter;
+
+static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi);
+static void depends_add(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *depend);
+static struct nhg_hash_entry *
+depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
+ afi_t afi);
+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 void nhg_connected_free(struct nhg_connected *dep)
+{
+ XFREE(MTYPE_NHG_CONNECTED, dep);
+}
+
+static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
+{
+ struct nhg_connected *new = NULL;
+
+ new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
+ new->nhe = nhe;
+
+ return new;
+}
+
+void nhg_connected_tree_free(struct nhg_connected_tree_head *head)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+
+ if (!nhg_connected_tree_is_empty(head)) {
+ frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
+ nhg_connected_tree_del(head, rb_node_dep);
+ nhg_connected_free(rb_node_dep);
+ }
+ }
+}
+
+bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head)
+{
+ return nhg_connected_tree_count(head) ? false : true;
+}
+
+struct nhg_connected *
+nhg_connected_tree_root(struct nhg_connected_tree_head *head)
+{
+ return nhg_connected_tree_first(head);
+}
+
+void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *depend)
+{
+ struct nhg_connected lookup = {};
+ struct nhg_connected *remove = NULL;
+
+ lookup.nhe = depend;
+
+ /* Lookup to find the element, then remove it */
+ remove = nhg_connected_tree_find(head, &lookup);
+ remove = nhg_connected_tree_del(head, remove);
+
+ if (remove)
+ nhg_connected_free(remove);
+}
+
+void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *depend)
+{
+ struct nhg_connected *new = NULL;
+
+ new = nhg_connected_new(depend);
+
+ if (new)
+ nhg_connected_tree_add(head, new);
+}
+
+static void
+nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head *head)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+
+ frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
+ zebra_nhg_decrement_ref(rb_node_dep->nhe);
+ }
+}
+
+static void
+nhg_connected_tree_increment_ref(struct nhg_connected_tree_head *head)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+
+ frr_each(nhg_connected_tree, head, rb_node_dep) {
+ zebra_nhg_increment_ref(rb_node_dep->nhe);
+ }
+}
+
+struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe)
+{
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)
+ && !zebra_nhg_depends_is_empty(nhe)) {
+ nhe = nhg_connected_tree_root(&nhe->nhg_depends)->nhe;
+ return zebra_nhg_resolve(nhe);
+ }
+
+ return nhe;
+}
+
+unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
+{
+ return nhg_connected_tree_count(&nhe->nhg_depends);
+}
+
+bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
+{
+ return nhg_connected_tree_is_empty(&nhe->nhg_depends);
+}
+
+static void zebra_nhg_depends_del(struct nhg_hash_entry *from,
+ struct nhg_hash_entry *depend)
+{
+ nhg_connected_tree_del_nhe(&from->nhg_depends, depend);
+}
+
+static void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
+{
+ nhg_connected_tree_init(&nhe->nhg_depends);
+}
+
+unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe)
+{
+ return nhg_connected_tree_count(&nhe->nhg_dependents);
+}
+
+
+bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe)
+{
+ return nhg_connected_tree_is_empty(&nhe->nhg_dependents);
+}
+
+static void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
+ struct nhg_hash_entry *dependent)
+{
+ nhg_connected_tree_del_nhe(&from->nhg_dependents, dependent);
+}
+
+static void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
+ struct nhg_hash_entry *dependent)
+{
+ nhg_connected_tree_add_nhe(&to->nhg_dependents, dependent);
+}
+
+static void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe)
+{
+ nhg_connected_tree_init(&nhe->nhg_dependents);
+}
+
+/* Release this nhe from anything depending on it */
+static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+
+ frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) {
+ zebra_nhg_depends_del(rb_node_dep->nhe, nhe);
+ /* recheck validity of the dependent */
+ zebra_nhg_check_valid(rb_node_dep->nhe);
+ }
+}
+
+/* Release this nhe from anything that it depends on */
+static void zebra_nhg_depends_release(struct nhg_hash_entry *nhe)
+{
+ if (!zebra_nhg_depends_is_empty(nhe)) {
+ struct nhg_connected *rb_node_dep = NULL;
+
+ frr_each_safe(nhg_connected_tree, &nhe->nhg_depends,
+ rb_node_dep) {
+ zebra_nhg_dependents_del(rb_node_dep->nhe, nhe);
+ }
+ }
+}
+
+
+struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
+{
+ struct nhg_hash_entry lookup = {};
+
+ lookup.id = id;
+ return hash_lookup(zrouter.nhgs_id, &lookup);
+}
+
+static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
+{
+ if (hash_lookup(zrouter.nhgs_id, nhe)) {
+ flog_err(
+ EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
+ "Failed inserting NHG id=%u into the ID hash table, entry already exists",
+ nhe->id);
+ return -1;
+ }
+
+ hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
+
+ return 0;
+}
+
+static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
+{
+ nhe->ifp = ifp;
+ if_nhg_dependents_add(ifp, nhe);
+}
+
+static void
+zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
+ struct nhg_connected_tree_head nhg_depends)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+
+ /* This has been allocated higher above in the stack. Could probably
+ * re-allocate and free the old stuff but just using the same memory
+ * for now. Otherwise, their might be a time trade-off for repeated
+ * alloc/frees as startup.
+ */
+ 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) {
+ 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;
+
+ ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex,
+ nhe->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->vrf_id,
+ nhe->id);
+ }
+}
+
+static struct nhg_hash_entry *zebra_nhg_copy(struct nhg_hash_entry *copy,
+ uint32_t id)
+{
+ struct nhg_hash_entry *nhe;
+
+ nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
+
+ nhe->id = id;
+
+ nhe->nhg = nexthop_group_new();
+ nexthop_group_copy(nhe->nhg, copy->nhg);
+
+ nhe->vrf_id = copy->vrf_id;
+ nhe->afi = copy->afi;
+ nhe->type = copy->type ? copy->type : ZEBRA_ROUTE_NHG;
+ nhe->refcnt = 0;
+ nhe->dplane_ref = zebra_router_get_next_sequence();
+
+ return nhe;
+}
+
+/* Allocation via hash handler */
+static void *zebra_nhg_hash_alloc(void *arg)
+{
+ struct nhg_hash_entry *nhe = NULL;
+ struct nhg_hash_entry *copy = arg;
+
+ nhe = zebra_nhg_copy(copy, copy->id);
+
+ /* 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_insert_id(nhe);
+
+ return nhe;
+}
+
+uint32_t zebra_nhg_hash_key(const void *arg)
+{
+ const struct nhg_hash_entry *nhe = arg;
+
+ uint32_t key = 0x5a351234;
+
+ key = jhash_3words(nhe->vrf_id, nhe->afi, nexthop_group_hash(nhe->nhg),
+ key);
+
+ return key;
+}
+
+uint32_t zebra_nhg_id_key(const void *arg)
+{
+ const struct nhg_hash_entry *nhe = arg;
+
+ return nhe->id;
+}
+
+bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
+{
+ const struct nhg_hash_entry *nhe1 = arg1;
+ const struct nhg_hash_entry *nhe2 = arg2;
+
+ /* No matter what if they equal IDs, assume equal */
+ if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
+ return true;
+
+ if (nhe1->vrf_id != nhe2->vrf_id)
+ return false;
+
+ if (nhe1->afi != nhe2->afi)
+ return false;
+
+ if (nexthop_group_active_nexthop_num_no_recurse(nhe1->nhg)
+ != nexthop_group_active_nexthop_num_no_recurse(nhe2->nhg))
+ return false;
+
+ if (!nexthop_group_equal_no_recurse(nhe1->nhg, nhe2->nhg))
+ return false;
+
+ return true;
+}
+
+bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
+{
+ const struct nhg_hash_entry *nhe1 = arg1;
+ const struct nhg_hash_entry *nhe2 = arg2;
+
+ return nhe1->id == nhe2->id;
+}
+
+static int zebra_nhg_process_grp(struct nexthop_group *nhg,
+ struct nhg_connected_tree_head *depends,
+ struct nh_grp *grp, uint8_t count)
+{
+ nhg_connected_tree_init(depends);
+
+ for (int i = 0; i < count; i++) {
+ struct nhg_hash_entry *depend = NULL;
+ /* We do not care about nexthop_grp.weight at
+ * this time. But we should figure out
+ * how to adapt this to our code in
+ * the future.
+ */
+ depend = depends_find_id_add(depends, grp[i].id);
+
+ if (!depend) {
+ flog_err(
+ EC_ZEBRA_NHG_SYNC,
+ "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
+ grp[i].id);
+ return -1;
+ }
+
+ /*
+ * If this is a nexthop with its own group
+ * dependencies, add them as well. Not sure its
+ * even possible to have a group within a group
+ * in the kernel.
+ */
+
+ copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, NULL);
+ }
+
+ return 0;
+}
+
+static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
+ struct nexthop *nh, afi_t afi)
+{
+ struct nhg_hash_entry *depend = NULL;
+ struct nexthop_group resolved_ng = {};
+
+ _nexthop_group_add_sorted(&resolved_ng, nh);
+
+ depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
+ depends_add(nhg_depends, depend);
+}
+
+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;
+
+ lookup.type = type ? type : ZEBRA_ROUTE_NHG;
+ lookup.nhg = nhg;
+
+ if (lookup.nhg->nexthop->next) {
+ /* Groups can have all vrfs and AF's in them */
+ lookup.afi = AFI_UNSPEC;
+ lookup.vrf_id = 0;
+ } else {
+ switch (lookup.nhg->nexthop->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.
+ */
+ lookup.afi = afi;
+ break;
+ case (NEXTHOP_TYPE_IPV4_IFINDEX):
+ case (NEXTHOP_TYPE_IPV4):
+ lookup.afi = AFI_IP;
+ break;
+ case (NEXTHOP_TYPE_IPV6_IFINDEX):
+ case (NEXTHOP_TYPE_IPV6):
+ lookup.afi = AFI_IP6;
+ break;
+ }
+
+ lookup.vrf_id = vrf_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;
+
+ if (recursive)
+ SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
+ }
+ return created;
+}
+
+/* Find/create a single nexthop */
+static struct nhg_hash_entry *
+zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
+{
+ struct nhg_hash_entry *nhe = NULL;
+ struct nexthop_group nhg = {};
+
+ _nexthop_group_add_sorted(&nhg, nh);
+
+ zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, 0);
+
+ return nhe;
+}
+
+static struct nhg_ctx *nhg_ctx_new()
+{
+ struct nhg_ctx *new = NULL;
+
+ new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
+
+ return new;
+}
+
+static void nhg_ctx_free(struct nhg_ctx *ctx)
+{
+ XFREE(MTYPE_NHG_CTX, ctx);
+}
+
+static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx)
+{
+ return ctx->id;
+}
+
+static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_status status)
+{
+ ctx->status = status;
+}
+
+static enum nhg_ctx_status nhg_ctx_get_status(const struct nhg_ctx *ctx)
+{
+ return ctx->status;
+}
+
+static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op)
+{
+ ctx->op = op;
+}
+
+static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
+{
+ return ctx->op;
+}
+
+static vrf_id_t nhg_ctx_get_vrf_id(const struct nhg_ctx *ctx)
+{
+ return ctx->vrf_id;
+}
+
+static int nhg_ctx_get_type(const struct nhg_ctx *ctx)
+{
+ return ctx->type;
+}
+
+static int nhg_ctx_get_afi(const struct nhg_ctx *ctx)
+{
+ return ctx->afi;
+}
+
+static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx)
+{
+ return &ctx->u.nh;
+}
+
+static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx)
+{
+ return ctx->count;
+}
+
+static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
+{
+ return ctx->u.grp;
+}
+
+static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
+ struct nh_grp *grp, vrf_id_t vrf_id,
+ afi_t afi, int type, uint8_t count)
+{
+ struct nhg_ctx *ctx = NULL;
+
+ ctx = nhg_ctx_new();
+
+ ctx->id = id;
+ ctx->vrf_id = vrf_id;
+ ctx->afi = afi;
+ ctx->type = type;
+ ctx->count = count;
+
+ if (count)
+ /* Copy over the array */
+ memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp));
+ else if (nh)
+ ctx->u.nh = *nh;
+
+ return ctx;
+}
+
+static bool zebra_nhg_contains_unhashable(struct nhg_hash_entry *nhe)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+
+ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
+ if (CHECK_FLAG(rb_node_dep->nhe->flags,
+ NEXTHOP_GROUP_UNHASHABLE))
+ return true;
+ }
+
+ return false;
+}
+
+static void zebra_nhg_set_unhashable(struct nhg_hash_entry *nhe)
+{
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE);
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+
+ flog_warn(
+ EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
+ "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring",
+ nhe->id);
+}
+
+static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe)
+{
+ struct nhg_connected *rb_node_dep;
+
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+
+ frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
+ zebra_nhg_set_valid(rb_node_dep->nhe);
+}
+
+static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
+{
+ struct nhg_connected *rb_node_dep;
+
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+
+ /* Update validity of nexthops depending on it */
+ frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
+ zebra_nhg_check_valid(rb_node_dep->nhe);
+}
+
+void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+ bool valid = false;
+
+ /* If anthing else in the group is valid, the group is valid */
+ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
+ if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) {
+ valid = true;
+ goto done;
+ }
+ }
+
+done:
+ if (valid)
+ zebra_nhg_set_valid(nhe);
+ else
+ zebra_nhg_set_invalid(nhe);
+}
+
+
+static void zebra_nhg_release(struct nhg_hash_entry *nhe)
+{
+ /* Remove it from any lists it may be on */
+ zebra_nhg_depends_release(nhe);
+ zebra_nhg_dependents_release(nhe);
+ if (nhe->ifp)
+ if_nhg_dependents_del(nhe->ifp, nhe);
+
+ /*
+ * If its unhashable, we didn't store it here and have to be
+ * sure we don't clear one thats actually being used.
+ */
+ if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
+ hash_release(zrouter.nhgs, nhe);
+
+ hash_release(zrouter.nhgs_id, nhe);
+}
+
+static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe)
+{
+ zebra_nhg_release(nhe);
+ zebra_nhg_free(nhe);
+}
+
+static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe)
+{
+ /* Update validity of groups depending on it */
+ struct nhg_connected *rb_node_dep;
+
+ frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
+ zebra_nhg_set_valid(rb_node_dep->nhe);
+}
+
+/*
+ * The kernel/other program has changed the state of a nexthop object we are
+ * using.
+ */
+static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe,
+ bool is_delete)
+{
+ if (nhe->refcnt) {
+ flog_err(
+ EC_ZEBRA_NHG_SYNC,
+ "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down",
+ (is_delete ? "deleted" : "updated"), nhe->id);
+
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ zebra_nhg_install_kernel(nhe);
+ } else
+ zebra_nhg_handle_uninstall(nhe);
+}
+
+static int nhg_ctx_process_new(struct nhg_ctx *ctx)
+{
+ struct nexthop_group *nhg = NULL;
+ struct nhg_connected_tree_head nhg_depends = {};
+ struct nhg_hash_entry *lookup = NULL;
+ struct nhg_hash_entry *nhe = NULL;
+
+ uint32_t id = nhg_ctx_get_id(ctx);
+ uint8_t count = nhg_ctx_get_count(ctx);
+ vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx);
+ int type = nhg_ctx_get_type(ctx);
+ afi_t afi = nhg_ctx_get_afi(ctx);
+
+ lookup = zebra_nhg_lookup_id(id);
+
+ if (lookup) {
+ /* This is already present in our table, hence an update
+ * that we did not initate.
+ */
+ zebra_nhg_handle_kernel_state_change(lookup, false);
+ return 0;
+ }
+
+ if (nhg_ctx_get_count(ctx)) {
+ nhg = nexthop_group_new();
+ if (zebra_nhg_process_grp(nhg, &nhg_depends,
+ nhg_ctx_get_grp(ctx), count)) {
+ depends_decrement_free(&nhg_depends);
+ nexthop_group_delete(&nhg);
+ return -ENOENT;
+ }
+
+ if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type,
+ afi))
+ depends_decrement_free(&nhg_depends);
+
+ /* These got copied over in zebra_nhg_alloc() */
+ nexthop_group_delete(&nhg);
+ } else
+ nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi,
+ type);
+
+ if (nhe) {
+ if (id != nhe->id) {
+ struct nhg_hash_entry *kernel_nhe = NULL;
+
+ /* Duplicate but with different ID from
+ * the kernel
+ */
+
+ /* The kernel allows duplicate nexthops
+ * as long as they have different IDs.
+ * We are ignoring those to prevent
+ * syncing problems with the kernel
+ * changes.
+ *
+ * We maintain them *ONLY* in the ID hash table to
+ * track them and set the flag to indicated
+ * their attributes are unhashable.
+ */
+
+ kernel_nhe = zebra_nhg_copy(nhe, id);
+ zebra_nhg_insert_id(kernel_nhe);
+ zebra_nhg_set_unhashable(kernel_nhe);
+ } else if (zebra_nhg_contains_unhashable(nhe)) {
+ /* The group we got contains an unhashable/duplicated
+ * depend, so lets mark this group as unhashable as well
+ * and release it from the non-ID hash.
+ */
+ hash_release(zrouter.nhgs, nhe);
+ zebra_nhg_set_unhashable(nhe);
+ } else {
+ /* It actually created a new nhe */
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ }
+ } else {
+ flog_err(
+ EC_ZEBRA_TABLE_LOOKUP_FAILED,
+ "Zebra failed to find or create a nexthop hash entry for ID (%u)",
+ id);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int nhg_ctx_process_del(struct nhg_ctx *ctx)
+{
+ struct nhg_hash_entry *nhe = NULL;
+ uint32_t id = nhg_ctx_get_id(ctx);
+
+ nhe = zebra_nhg_lookup_id(id);
+
+ if (!nhe) {
+ flog_warn(
+ EC_ZEBRA_BAD_NHG_MESSAGE,
+ "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
+ id);
+ return -1;
+ }
+
+ zebra_nhg_handle_kernel_state_change(nhe, true);
+
+ return 0;
+}
+
+static void nhg_ctx_process_finish(struct nhg_ctx *ctx)
+{
+ struct nexthop *nh;
+
+ /*
+ * Just freeing for now, maybe do something more in the future
+ * based on flag.
+ */
+
+ if (nhg_ctx_get_count(ctx))
+ goto done;
+
+ nh = nhg_ctx_get_nh(ctx);
+
+ nexthop_del_labels(nh);
+
+done:
+ nhg_ctx_free(ctx);
+}
+
+static int queue_add(struct nhg_ctx *ctx)
+{
+ /* If its queued or already processed do nothing */
+ if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED)
+ return 0;
+
+ if (rib_queue_nhg_add(ctx)) {
+ nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
+ return -1;
+ }
+
+ nhg_ctx_set_status(ctx, NHG_CTX_QUEUED);
+
+ return 0;
+}
+
+int nhg_ctx_process(struct nhg_ctx *ctx)
+{
+ int ret = 0;
+
+ switch (nhg_ctx_get_op(ctx)) {
+ case NHG_CTX_OP_NEW:
+ ret = nhg_ctx_process_new(ctx);
+ if (nhg_ctx_get_count(ctx) && ret == -ENOENT
+ && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) {
+ /**
+ * We have entered a situation where we are
+ * processing a group from the kernel
+ * that has a contained nexthop which
+ * we have not yet processed.
+ *
+ * Re-enqueue this ctx to be handled exactly one
+ * more time (indicated by the flag).
+ *
+ * By the time we get back to it, we
+ * should have processed its depends.
+ */
+ nhg_ctx_set_status(ctx, NHG_CTX_NONE);
+ if (queue_add(ctx) == 0) {
+ nhg_ctx_set_status(ctx, NHG_CTX_REQUEUED);
+ return 0;
+ }
+ }
+ break;
+ case NHG_CTX_OP_DEL:
+ ret = nhg_ctx_process_del(ctx);
+ case NHG_CTX_OP_NONE:
+ break;
+ }
+
+ nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
+
+ nhg_ctx_process_finish(ctx);
+
+ return ret;
+}
+
+/* Kernel-side, you either get a single new nexthop or a array of ID's */
+int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
+ uint8_t count, vrf_id_t vrf_id, afi_t afi, int type,
+ int startup)
+{
+ struct nhg_ctx *ctx = NULL;
+
+ if (id > id_counter)
+ /* Increase our counter so we don't try to create
+ * an ID that already exists
+ */
+ id_counter = id;
+
+ ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count);
+ nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
+
+ /* Under statup conditions, we need to handle them immediately
+ * like we do for routes. Otherwise, we are going to get a route
+ * with a nhe_id that we have not handled.
+ */
+ if (startup)
+ return nhg_ctx_process(ctx);
+
+ if (queue_add(ctx)) {
+ nhg_ctx_process_finish(ctx);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Kernel-side, received delete message */
+int zebra_nhg_kernel_del(uint32_t id)
+{
+ struct nhg_ctx *ctx = NULL;
+
+ ctx = nhg_ctx_init(id, NULL, NULL, 0, 0, 0, 0);
+
+ nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
+
+ if (queue_add(ctx)) {
+ nhg_ctx_process_finish(ctx);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Some dependency helper functions */
+static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
+{
+ struct nexthop *lookup = NULL;
+ struct nhg_hash_entry *nhe = NULL;
+
+ copy_nexthops(&lookup, nh, NULL);
+
+ /* Clear it, in case its a group */
+ nexthops_free(lookup->next);
+ nexthops_free(lookup->prev);
+ lookup->next = NULL;
+ lookup->prev = NULL;
+
+ nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
+
+ nexthops_free(lookup);
+
+ return nhe;
+}
+
+static void depends_add(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *depend)
+{
+ nhg_connected_tree_add_nhe(head, depend);
+ zebra_nhg_increment_ref(depend);
+}
+
+static struct nhg_hash_entry *
+depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
+ afi_t afi)
+{
+ struct nhg_hash_entry *depend = NULL;
+
+ depend = depends_find(nh, afi);
+
+ if (depend)
+ depends_add(head, depend);
+
+ return depend;
+}
+
+static struct nhg_hash_entry *
+depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id)
+{
+ struct nhg_hash_entry *depend = NULL;
+
+ depend = zebra_nhg_lookup_id(id);
+
+ if (depend)
+ depends_add(head, depend);
+
+ return depend;
+}
+
+static void depends_decrement_free(struct nhg_connected_tree_head *head)
+{
+ nhg_connected_tree_decrement_ref(head);
+ nhg_connected_tree_free(head);
+}
+
+/* Rib-side, you get a nexthop group struct */
+struct nhg_hash_entry *
+zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
+{
+ struct nhg_hash_entry *nhe = NULL;
+
+ if (!(nhg && nhg->nexthop)) {
+ flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
+ "No nexthop passed to %s", __func__);
+ return NULL;
+ }
+
+ zebra_nhg_find(&nhe, id, nhg, NULL, nhg->nexthop->vrf_id, rt_afi, 0);
+
+ return nhe;
+}
+
+static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
+{
+ nexthop_group_delete(&nhe->nhg);
+ /* Decrement to remove connection ref */
+ nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
+ nhg_connected_tree_free(&nhe->nhg_depends);
+ nhg_connected_tree_free(&nhe->nhg_dependents);
+}
+
+void zebra_nhg_free(void *arg)
+{
+ struct nhg_hash_entry *nhe = NULL;
+
+ nhe = (struct nhg_hash_entry *)arg;
+
+ if (nhe->refcnt)
+ zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
+
+ zebra_nhg_free_members(nhe);
+
+ XFREE(MTYPE_NHG, nhe);
+}
+
+void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
+{
+ nhe->refcnt--;
+
+ if (!zebra_nhg_depends_is_empty(nhe))
+ nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
+
+ if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
+ zebra_nhg_uninstall_kernel(nhe);
+}
+
+void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
+{
+ nhe->refcnt++;
+
+ if (!zebra_nhg_depends_is_empty(nhe))
+ nhg_connected_tree_increment_ref(&nhe->nhg_depends);
+}
static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
struct nexthop *nexthop)
@@ -152,7 +1231,8 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop,
/*
* Given a nexthop we need to properly recursively resolve
* the route. As such, do a table lookup to find and match
- * if at all possible. Set the nexthop->ifindex as appropriate
+ * if at all possible. Set the nexthop->ifindex and resolved_id
+ * as appropriate
*/
static int nexthop_active(afi_t afi, struct route_entry *re,
struct nexthop *nexthop, struct route_node *top)
@@ -171,16 +1251,23 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|| nexthop->type == NEXTHOP_TYPE_IPV6)
nexthop->ifindex = 0;
+
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
nexthops_free(nexthop->resolved);
nexthop->resolved = NULL;
re->nexthop_mtu = 0;
/*
- * If the kernel has sent us a route, then
+ * If the kernel has sent us a NEW route, then
* by golly gee whiz it's a good route.
+ *
+ * If its an already INSTALLED route we have already handled, then the
+ * kernel route's nexthop might have became unreachable
+ * and we have to handle that.
*/
- if (re->type == ZEBRA_ROUTE_KERNEL || re->type == ZEBRA_ROUTE_SYSTEM)
+ if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
+ && (re->type == ZEBRA_ROUTE_KERNEL
+ || re->type == ZEBRA_ROUTE_SYSTEM))
return 1;
/*
@@ -204,13 +1291,12 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (connected_is_unnumbered(ifp)) {
if (if_is_operative(ifp))
return 1;
- else {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- "\t%s: Onlink and interface %s is not operative",
- __PRETTY_FUNCTION__, ifp->name);
- return 0;
- }
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug(
+ "\t%s: Onlink and interface %s is not operative",
+ __PRETTY_FUNCTION__, ifp->name);
+ return 0;
}
if (!if_is_operative(ifp)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
@@ -270,7 +1356,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
/* Pick up selected route. */
/* However, do not resolve over default route unless explicitly
- * allowed. */
+ * allowed.
+ */
if (is_default_prefix(&rn->p)
&& !rnh_resolve_via_default(zvrf, p.family)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
@@ -288,7 +1375,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
match = dest->selected_fib;
/* If there is no selected route or matched route is EGP, go up
- tree. */
+ * tree.
+ */
if (!match) {
do {
rn = rn->parent;
@@ -301,7 +1389,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (match->type == ZEBRA_ROUTE_CONNECT) {
/* Directly point connected route. */
- newhop = match->ng.nexthop;
+ newhop = match->ng->nexthop;
if (newhop) {
if (nexthop->type == NEXTHOP_TYPE_IPV4
|| nexthop->type == NEXTHOP_TYPE_IPV6)
@@ -310,7 +1398,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
return 1;
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
resolved = 0;
- for (ALL_NEXTHOPS(match->ng, newhop)) {
+ for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
if (!CHECK_FLAG(match->status,
ROUTE_ENTRY_INSTALLED))
continue;
@@ -324,13 +1412,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
}
if (resolved)
re->nexthop_mtu = match->mtu;
+
if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("\t%s: Recursion failed to find",
__PRETTY_FUNCTION__);
return resolved;
} else if (re->type == ZEBRA_ROUTE_STATIC) {
resolved = 0;
- for (ALL_NEXTHOPS(match->ng, newhop)) {
+ for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
if (!CHECK_FLAG(match->status,
ROUTE_ENTRY_INSTALLED))
continue;
@@ -376,6 +1465,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
* appropriately as well. An existing route map can turn
* (otherwise active) nexthop into inactive, but not vice versa.
*
+ * If it finds a nexthop recursivedly, set the resolved_id
+ * to match that nexthop's nhg_hash_entry ID;
+ *
* The return value is the final value of 'ACTIVE' flag.
*/
static unsigned nexthop_active_check(struct route_node *rn,
@@ -499,23 +1591,29 @@ static unsigned nexthop_active_check(struct route_node *rn,
/*
* Iterate over all nexthops of the given RIB entry and refresh their
- * ACTIVE flag. re->nexthop_active_num is updated accordingly. If any
- * nexthop is found to toggle the ACTIVE flag, the whole re structure
- * is flagged with ROUTE_ENTRY_CHANGED.
+ * 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 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;
+
+ afi_t rt_afi = family2afi(rn->p.family);
- re->nexthop_active_num = 0;
UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
- for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
+ /* Copy over the nexthops in current state */
+ nexthop_group_copy(&new_grp, re->ng);
+
+ for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) {
+
/* No protocol daemon provides src and so we're skipping
* tracking it */
prev_src = nexthop->rmap_src;
@@ -527,14 +1625,19 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
* a multipath perpsective should not be a data plane
* decision point.
*/
- new_active = nexthop_active_check(rn, re, nexthop);
+ new_active =
+ nexthop_active_check(rn, re, nexthop);
+
if (new_active
- && re->nexthop_active_num >= zrouter.multipath_num) {
+ && nexthop_group_active_nexthop_num(&new_grp)
+ >= zrouter.multipath_num) {
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
new_active = 0;
}
+
if (new_active)
- re->nexthop_active_num++;
+ curr_active++;
+
/* Don't allow src setting on IPv6 addr for now */
if (prev_active != new_active || prev_index != nexthop->ifindex
|| ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
@@ -549,6 +1652,269 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
}
- return re->nexthop_active_num;
+ 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);
+
+ zebra_nhg_re_update_ref(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);
+ }
+
+ /*
+ * Do not need these nexthops anymore since they
+ * were either copied over into an nhe or not
+ * used at all.
+ */
+ nexthops_free(new_grp.nexthop);
+ return curr_active;
}
+static void zebra_nhg_re_attach_ref(struct route_entry *re,
+ struct nhg_hash_entry *new)
+{
+ re->ng = new->nhg;
+ re->nhe_id = new->id;
+
+ zebra_nhg_increment_ref(new);
+}
+
+int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new)
+{
+ struct nhg_hash_entry *old = NULL;
+ int ret = 0;
+
+ if (new == NULL) {
+ re->ng = NULL;
+ goto done;
+ }
+
+ if (re->nhe_id != new->id) {
+ old = zebra_nhg_lookup_id(re->nhe_id);
+
+ zebra_nhg_re_attach_ref(re, new);
+
+ if (old)
+ zebra_nhg_decrement_ref(old);
+ } else if (!re->ng)
+ /* This is the first time it's being attached */
+ zebra_nhg_re_attach_ref(re, new);
+
+done:
+ return ret;
+}
+
+/* Convert a nhe into a group array */
+uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, 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;
+
+ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
+ bool duplicate = false;
+
+ depend = rb_node_dep->nhe;
+
+ /*
+ * If its recursive, use its resolved nhe in the group
+ */
+ if (CHECK_FLAG(depend->flags, NEXTHOP_GROUP_RECURSIVE)) {
+ depend = zebra_nhg_resolve(depend);
+ if (!depend) {
+ flog_err(
+ EC_ZEBRA_NHG_FIB_UPDATE,
+ "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
+ nhe->id);
+ continue;
+ }
+ }
+
+ /* 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 (!duplicate) {
+ grp[i].id = depend->id;
+ /* We aren't using weights for anything right now */
+ grp[i].weight = 0;
+ i++;
+ }
+
+ if (i >= max_num)
+ goto done;
+ }
+
+done:
+ return i;
+}
+
+void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
+{
+ struct nhg_connected *rb_node_dep = NULL;
+
+ /* Resolve it first */
+ nhe = zebra_nhg_resolve(nhe);
+
+ /* Make sure all depends are installed/queued */
+ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
+ zebra_nhg_install_kernel(rb_node_dep->nhe);
+ }
+
+ if (!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;
+
+ int ret = dplane_nexthop_add(nhe);
+
+ switch (ret) {
+ case ZEBRA_DPLANE_REQUEST_QUEUED:
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
+ break;
+ case ZEBRA_DPLANE_REQUEST_FAILURE:
+ flog_err(
+ EC_ZEBRA_DP_INSTALL_FAIL,
+ "Failed to install Nexthop ID (%u) into the kernel",
+ nhe->id);
+ break;
+ case ZEBRA_DPLANE_REQUEST_SUCCESS:
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ zebra_nhg_handle_install(nhe);
+ break;
+ }
+ }
+}
+
+void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
+{
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
+ int ret = dplane_nexthop_delete(nhe);
+
+ switch (ret) {
+ case ZEBRA_DPLANE_REQUEST_QUEUED:
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
+ break;
+ case ZEBRA_DPLANE_REQUEST_FAILURE:
+ flog_err(
+ EC_ZEBRA_DP_DELETE_FAIL,
+ "Failed to uninstall Nexthop ID (%u) from the kernel",
+ nhe->id);
+ break;
+ case ZEBRA_DPLANE_REQUEST_SUCCESS:
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ break;
+ }
+ }
+
+ zebra_nhg_handle_uninstall(nhe);
+}
+
+void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
+{
+ enum dplane_op_e op;
+ enum zebra_dplane_result status;
+ uint32_t id = 0;
+ struct nhg_hash_entry *nhe = NULL;
+
+ op = dplane_ctx_get_op(ctx);
+ status = dplane_ctx_get_status(ctx);
+
+ id = dplane_ctx_get_nhe_id(ctx);
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug(
+ "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
+ ctx, dplane_op2str(op), id, dplane_res2str(status));
+
+ switch (op) {
+ case DPLANE_OP_NH_DELETE:
+ if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ flog_err(
+ EC_ZEBRA_DP_DELETE_FAIL,
+ "Failed to uninstall Nexthop ID (%u) from the kernel",
+ id);
+ /* We already free'd the data, nothing to do */
+ break;
+ case DPLANE_OP_NH_INSTALL:
+ case DPLANE_OP_NH_UPDATE:
+ nhe = zebra_nhg_lookup_id(id);
+
+ if (!nhe) {
+ flog_err(
+ EC_ZEBRA_NHG_SYNC,
+ "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
+ dplane_op2str(op), id);
+ break;
+ }
+
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
+ if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ zebra_nhg_handle_install(nhe);
+ } else
+ flog_err(
+ EC_ZEBRA_DP_INSTALL_FAIL,
+ "Failed to install Nexthop ID (%u) into the kernel",
+ nhe->id);
+ 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:
+ break;
+ }
+
+ dplane_ctx_fini(&ctx);
+}
+
+static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
+{
+ struct nhg_hash_entry *nhe = NULL;
+
+ nhe = (struct nhg_hash_entry *)bucket->data;
+
+ /* If its being ref'd, just let it be uninstalled via a route removal */
+ if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
+ zebra_nhg_uninstall_kernel(nhe);
+}
+
+void zebra_nhg_sweep_table(struct hash *hash)
+{
+ hash_iterate(hash, zebra_nhg_sweep_entry, NULL);
+}
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index ff2351c75..1f695433c 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -24,6 +24,205 @@
#define __ZEBRA_NHG_H__
#include "zebra/rib.h"
+#include "lib/nexthop_group.h"
+#include "zebra/zebra_dplane.h"
+
+/* This struct is used exclusively for dataplane
+ * interaction via a dataplane context.
+ *
+ * It is designed to mimic the netlink nexthop_grp
+ * struct in include/linux/nexthop.h
+ */
+struct nh_grp {
+ uint32_t id;
+ uint8_t weight;
+};
+
+PREDECL_RBTREE_UNIQ(nhg_connected_tree);
+
+/*
+ * Hashtables contiaining entries found in `zebra_router`.
+ */
+
+struct nhg_hash_entry {
+ uint32_t id;
+ afi_t afi;
+ vrf_id_t vrf_id;
+ int type;
+
+ struct nexthop_group *nhg;
+
+ /* If this is not a group, it
+ * will be a single nexthop
+ * and must have an interface
+ * associated with it.
+ * Otherwise, this will be null.
+ */
+ struct interface *ifp;
+
+ uint32_t refcnt;
+ uint32_t dplane_ref;
+
+ uint32_t flags;
+
+ /* Dependency tree for other entries.
+ * For instance a group with two
+ * nexthops will have two dependencies
+ * pointing to those nhg_hash_entries.
+ *
+ * Using a rb tree here to make lookups
+ * 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
+ * and correct( ie no recursive pointer ) or a nexthop that is recursively
+ * resolved and correct.
+ */
+#define NEXTHOP_GROUP_VALID (1 << 0)
+/*
+ * Has this nexthop group been installed? At this point in time, this
+ * means that the data-plane has been told about this nexthop group
+ * and it's possible usage by a route entry.
+ */
+#define NEXTHOP_GROUP_INSTALLED (1 << 1)
+/*
+ * Has the nexthop group been queued to be send to the FIB?
+ * The NEXTHOP_GROUP_VALID flag should also be set by this point.
+ */
+#define NEXTHOP_GROUP_QUEUED (1 << 2)
+/*
+ * Is this a nexthop that is recursively resolved?
+ */
+#define NEXTHOP_GROUP_RECURSIVE (1 << 3)
+/*
+ * This is a nexthop group we got from the kernel, it is identical to
+ * one we already have. (The kernel allows duplicate nexthops, we don't
+ * since we hash on them). We are only tracking it in our ID table,
+ * it is unusable by our created routes but may be used by routes we get
+ * from the kernel. Therefore, it is unhashable.
+ */
+#define NEXTHOP_GROUP_UNHASHABLE (1 << 4)
+};
+
+/* Was this one we created, either this session or previously? */
+#define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG)
+
+
+enum nhg_ctx_op_e {
+ NHG_CTX_OP_NONE = 0,
+ NHG_CTX_OP_NEW,
+ NHG_CTX_OP_DEL,
+};
+
+enum nhg_ctx_status {
+ NHG_CTX_NONE = 0,
+ NHG_CTX_QUEUED,
+ NHG_CTX_REQUEUED,
+ NHG_CTX_SUCCESS,
+ NHG_CTX_FAILURE,
+};
+
+/*
+ * Context needed to queue nhg updates on the
+ * work queue.
+ */
+struct nhg_ctx {
+
+ /* Unique ID */
+ uint32_t id;
+
+ vrf_id_t vrf_id;
+ afi_t afi;
+ /*
+ * This should only every be ZEBRA_ROUTE_NHG unless we get a a kernel
+ * created nexthop not made by us.
+ */
+ int type;
+
+ /* If its a group array, how many? */
+ uint8_t count;
+
+ /* Its either a single nexthop or an array of ID's */
+ union {
+ struct nexthop nh;
+ struct nh_grp grp[MULTIPATH_NUM];
+ } u;
+
+ enum nhg_ctx_op_e op;
+ enum nhg_ctx_status status;
+};
+
+
+/**
+ * NHE abstracted tree functions.
+ * Use these where possible instead of the direct ones access ones.
+ */
+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);
+extern bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe);
+
+extern unsigned int
+zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe);
+extern bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe);
+
+/* Lookup ID, doesn't create */
+extern struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id);
+
+/* Hash functions */
+extern uint32_t zebra_nhg_hash_key(const void *arg);
+extern uint32_t zebra_nhg_id_key(const void *arg);
+
+extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2);
+extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2);
+
+/*
+ * Process a context off of a queue.
+ * Specifically this should be from
+ * the rib meta queue.
+ */
+extern int nhg_ctx_process(struct nhg_ctx *ctx);
+
+/* Find via kernel nh creation */
+extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
+ struct nh_grp *grp, uint8_t count,
+ vrf_id_t vrf_id, afi_t afi, int type,
+ int startup);
+/* Del via kernel */
+extern int zebra_nhg_kernel_del(uint32_t id);
+
+/* Find via route creation */
+extern struct nhg_hash_entry *
+zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, 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);
+extern int zebra_nhg_re_update_ref(struct route_entry *re,
+ struct nhg_hash_entry *nhe);
+
+/* Check validity of nhe, if invalid will update dependents as well */
+extern void zebra_nhg_check_valid(struct nhg_hash_entry *nhe);
+
+/* Convert nhe depends to a grp context that can be passed around safely */
+extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
+ int size);
+
+/* Dataplane install/uninstall */
+extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe);
+extern void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe);
+
+/* Forward ref of dplane update context type */
+struct zebra_dplane_ctx;
+extern void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx);
+
+
+/* Sweet the nhg hash tables for old entries on restart */
+extern void zebra_nhg_sweep_table(struct hash *hash);
+
+/* Nexthop resolution processing */
extern int nexthop_active_update(struct route_node *rn, struct route_entry *re);
#endif
diff --git a/zebra/zebra_nhg_private.h b/zebra/zebra_nhg_private.h
new file mode 100644
index 000000000..170e2357e
--- /dev/null
+++ b/zebra/zebra_nhg_private.h
@@ -0,0 +1,62 @@
+/*
+ * Nexthop Group Private Functions.
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ * Stephen Worley
+ *
+ * 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
+ */
+
+/**
+ * These functions should only be used internally for nhg_hash_entry
+ * manipulation and in certain special cases.
+ *
+ * Please use `zebra/zebra_nhg.h` for any general nhg_hash_entry api needs.
+ */
+
+#ifndef __ZEBRA_NHG_PRIVATE_H__
+#define __ZEBRA_NHG_PRIVATE_H__
+
+#include "zebra/zebra_nhg.h"
+
+/* Abstraction for connected trees */
+struct nhg_connected {
+ struct nhg_connected_tree_item tree_item;
+ struct nhg_hash_entry *nhe;
+};
+
+static int nhg_connected_cmp(const struct nhg_connected *con1,
+ const struct nhg_connected *con2)
+{
+ return (con1->nhe->id - con2->nhe->id);
+}
+
+DECLARE_RBTREE_UNIQ(nhg_connected_tree, struct nhg_connected, tree_item,
+ nhg_connected_cmp);
+
+/* nhg connected tree direct access functions */
+extern void nhg_connected_tree_init(struct nhg_connected_tree_head *head);
+extern void nhg_connected_tree_free(struct nhg_connected_tree_head *head);
+extern bool
+nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head);
+extern struct nhg_connected *
+nhg_connected_tree_root(struct nhg_connected_tree_head *head);
+extern void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *nhe);
+extern void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *nhe);
+
+extern void zebra_nhg_free(void *arg);
+
+#endif /* __ZEBRA_NHG_PRIVATE_H__ */
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index f95a4ff95..e24d2e2b4 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -144,17 +144,12 @@ uint32_t zebra_pbr_rules_hash_key(const void *arg)
key = jhash_3words(rule->rule.seq, rule->rule.priority,
rule->rule.action.table,
prefix_hash_key(&rule->rule.filter.src_ip));
- if (rule->ifp)
- key = jhash_1word(rule->ifp->ifindex, key);
- else
- key = jhash_1word(0, key);
if (rule->rule.filter.fwmark)
- key = jhash_1word(rule->rule.filter.fwmark, key);
+ key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id,
+ rule->rule.ifindex, key);
else
- key = jhash_1word(0, key);
-
- key = jhash_1word(rule->vrf_id, key);
+ key = jhash_2words(rule->vrf_id, rule->rule.ifindex, key);
return jhash_3words(rule->rule.filter.src_port,
rule->rule.filter.dst_port,
@@ -196,7 +191,7 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
return false;
- if (r1->ifp != r2->ifp)
+ if (r1->rule.ifindex != r2->rule.ifindex)
return false;
if (r1->vrf_id != r2->vrf_id)
@@ -208,7 +203,7 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
struct pbr_rule_unique_lookup {
struct zebra_pbr_rule *rule;
uint32_t unique;
- struct interface *ifp;
+ ifindex_t ifindex;
vrf_id_t vrf_id;
};
@@ -218,7 +213,7 @@ static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data)
struct zebra_pbr_rule *rule = b->data;
if (pul->unique == rule->rule.unique
- && pul->ifp == rule->ifp
+ && pul->ifindex == rule->rule.ifindex
&& pul->vrf_id == rule->vrf_id) {
pul->rule = rule;
return HASHWALK_ABORT;
@@ -233,7 +228,7 @@ pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule)
struct pbr_rule_unique_lookup pul;
pul.unique = zrule->rule.unique;
- pul.ifp = zrule->ifp;
+ pul.ifindex = zrule->rule.ifindex;
pul.rule = NULL;
pul.vrf_id = zrule->vrf_id;
hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul);
@@ -471,8 +466,12 @@ static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data)
if (rule->sock == *sock) {
(void)kernel_del_pbr_rule(rule);
- hash_release(zrouter.rules_hash, rule);
- XFREE(MTYPE_TMP, rule);
+ if (hash_release(zrouter.rules_hash, rule))
+ XFREE(MTYPE_TMP, rule);
+ else
+ zlog_debug(
+ "%s: Rule seq: %u is being cleaned but we can't find it in our tables",
+ __func__, rule->rule.seq);
}
}
diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h
index fcc9c5c39..b7fbc9b7d 100644
--- a/zebra/zebra_pbr.h
+++ b/zebra/zebra_pbr.h
@@ -41,7 +41,7 @@ struct zebra_pbr_rule {
struct pbr_rule rule;
- struct interface *ifp;
+ char ifname[INTERFACE_NAMSIZ];
vrf_id_t vrf_id;
};
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index 09edbc9a6..3f1567a95 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -259,7 +259,7 @@ static int zebra_pw_check_reachability(struct zebra_pw *pw)
* Need to ensure that there's a label binding for all nexthops.
* Otherwise, ECMP for this route could render the pseudowire unusable.
*/
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) {
if (!nexthop->nh_label) {
if (IS_ZEBRA_DEBUG_PW)
zlog_debug("%s: unlabeled route for %s",
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index d8fb9ae3c..e0bf1a58f 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -56,7 +56,8 @@
#include "zebra/zebra_vxlan.h"
#include "zebra/zapi_msg.h"
#include "zebra/zebra_dplane.h"
-#include "zebra/zebra_nhg.h"
+
+DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object");
/*
* Event, list, and mutex for delivery of dataplane results
@@ -77,34 +78,35 @@ static const struct {
uint8_t distance;
uint8_t meta_q_map;
} route_info[ZEBRA_ROUTE_MAX] = {
- [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 4},
- [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 0},
- [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 0},
- [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 1},
- [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 2},
- [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 2},
- [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 2},
- [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 2},
- [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 2},
- [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 3},
- [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 4},
- [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 2},
- [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 2},
- [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 4},
- [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 4},
- [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 1},
- [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 4},
- [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 3},
- [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 3},
- [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 3},
- [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 3},
- [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 3},
- [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 2},
- [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 4},
- [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 4},
- [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 4},
- [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 2},
- [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 4}
+ [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Uneeded for nhg's */, 0},
+ [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 5},
+ [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 1},
+ [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 1},
+ [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 2},
+ [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 3},
+ [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 3},
+ [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 3},
+ [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 3},
+ [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 3},
+ [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 4},
+ [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 5},
+ [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 3},
+ [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 3},
+ [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 5},
+ [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 5},
+ [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 2},
+ [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 5},
+ [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 4},
+ [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 4},
+ [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 4},
+ [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 4},
+ [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 4},
+ [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 3},
+ [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 5},
+ [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 5},
+ [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 5},
+ [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 3},
+ [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 5}
/* Any new route type added to zebra, should be mirrored here */
/* no entry/default: 150 */
@@ -194,8 +196,7 @@ int zebra_check_addr(const struct prefix *p)
/* Add nexthop to the end of a rib node's nexthop list */
void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop)
{
- _nexthop_group_add_sorted(&re->ng, nexthop);
- re->nexthop_num++;
+ _nexthop_group_add_sorted(re->ng, nexthop);
}
@@ -204,10 +205,8 @@ void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop)
*/
void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh)
{
- assert(!re->ng.nexthop);
- copy_nexthops(&re->ng.nexthop, nh, NULL);
- for (struct nexthop *nexthop = nh; nexthop; nexthop = nexthop->next)
- re->nexthop_num++;
+ assert(!re->ng->nexthop);
+ copy_nexthops(&re->ng->nexthop, nh, NULL);
}
/* Delete specified nexthop from the list. */
@@ -218,8 +217,7 @@ void route_entry_nexthop_delete(struct route_entry *re, struct nexthop *nexthop)
if (nexthop->prev)
nexthop->prev->next = nexthop->next;
else
- re->ng.nexthop = nexthop->next;
- re->nexthop_num--;
+ re->ng->nexthop = nexthop->next;
}
@@ -503,7 +501,7 @@ int zebra_rib_labeled_unicast(struct route_entry *re)
if (re->type != ZEBRA_ROUTE_BGP)
return 0;
- for (ALL_NEXTHOPS(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
if (!nexthop->nh_label || !nexthop->nh_label->num_labels)
return 0;
@@ -527,26 +525,17 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
srcdest_rnode_prefixes(rn, &p, &src_p);
if (info->safi != SAFI_UNICAST) {
- for (ALL_NEXTHOPS(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
return;
- } else {
- struct nexthop *prev;
-
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
- for (ALL_NEXTHOPS(re->ng, prev)) {
- if (prev == nexthop)
- break;
- if (nexthop_same_firsthop(nexthop, prev)) {
- SET_FLAG(nexthop->flags,
- NEXTHOP_FLAG_DUPLICATE);
- break;
- }
- }
- }
}
+
+ /*
+ * Install the resolved nexthop object first.
+ */
+ zebra_nhg_install_kernel(zebra_nhg_lookup_id(re->nhe_id));
+
/*
* If this is a replace to a new RE let the originator of the RE
* know that they've lost
@@ -584,7 +573,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
if (!RIB_SYSTEM_ROUTE(old)) {
/* Clear old route's FIB flags */
- for (ALL_NEXTHOPS(old->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(old->ng, nexthop)) {
UNSET_FLAG(nexthop->flags,
NEXTHOP_FLAG_FIB);
}
@@ -622,7 +611,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
if (info->safi != SAFI_UNICAST) {
UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
- for (ALL_NEXTHOPS(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
return;
}
@@ -682,7 +671,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re)
re->fib_ng.nexthop = NULL;
}
- for (ALL_NEXTHOPS(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
}
@@ -691,7 +680,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re)
srcdest_rnode_prefixes(rn, &p, &src_p);
- redistribute_delete(p, src_p, re);
+ redistribute_delete(p, src_p, re, NULL);
UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED);
}
}
@@ -858,7 +847,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
/* Update real nexthop. This may actually determine if nexthop is active
* or not. */
- if (!nexthop_group_active_nexthop_num(&new->ng)) {
+ if (!nexthop_group_active_nexthop_num(new->ng)) {
UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
return;
}
@@ -927,7 +916,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
/* Update the nexthop; we could determine here that nexthop is
* inactive. */
- if (nexthop_group_active_nexthop_num(&new->ng))
+ if (nexthop_group_active_nexthop_num(new->ng))
nh_active = 1;
/* If nexthop is active, install the selected route, if
@@ -1045,15 +1034,19 @@ static struct route_entry *rib_choose_best(struct route_entry *current,
/* both are connected. are either loop or vrf? */
struct nexthop *nexthop = NULL;
- for (ALL_NEXTHOPS(alternate->ng, nexthop)) {
- if (if_is_loopback_or_vrf(if_lookup_by_index(
- nexthop->ifindex, alternate->vrf_id)))
+ for (ALL_NEXTHOPS_PTR(alternate->ng, nexthop)) {
+ struct interface *ifp = if_lookup_by_index(
+ nexthop->ifindex, alternate->vrf_id);
+
+ if (ifp && if_is_loopback_or_vrf(ifp))
return alternate;
}
- for (ALL_NEXTHOPS(current->ng, nexthop)) {
- if (if_is_loopback_or_vrf(if_lookup_by_index(
- nexthop->ifindex, current->vrf_id)))
+ for (ALL_NEXTHOPS_PTR(current->ng, nexthop)) {
+ struct interface *ifp = if_lookup_by_index(
+ nexthop->ifindex, current->vrf_id);
+
+ if (ifp && if_is_loopback_or_vrf(ifp))
return current;
}
@@ -1080,6 +1073,12 @@ static struct route_entry *rib_choose_best(struct route_entry *current,
return current;
}
+/* Core function for processing nexthop group contexts's off metaq */
+static void rib_nhg_process(struct nhg_ctx *ctx)
+{
+ nhg_ctx_process(ctx);
+}
+
/* Core function for processing routing information base. */
static void rib_process(struct route_node *rn)
{
@@ -1248,8 +1247,17 @@ static void rib_process(struct route_node *rn)
SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED);
if (old_selected) {
- if (!new_selected)
- redistribute_delete(p, src_p, old_selected);
+ /*
+ * If we're removing the old entry, we should tell
+ * redist subscribers about that *if* they aren't
+ * going to see a redist for the new entry.
+ */
+ if (!new_selected || CHECK_FLAG(old_selected->status,
+ ROUTE_ENTRY_REMOVED))
+ redistribute_delete(p, src_p,
+ old_selected,
+ new_selected);
+
if (old_selected != new_selected)
UNSET_FLAG(old_selected->flags,
ZEBRA_FLAG_SELECTED);
@@ -1365,7 +1373,7 @@ static void zebra_rib_fixup_system(struct route_node *rn)
SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
- for (ALL_NEXTHOPS(re->ng, nhop)) {
+ for (ALL_NEXTHOPS_PTR(re->ng, nhop)) {
if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
@@ -1413,76 +1421,20 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
* status.
*/
- /*
- * First check the fib nexthop-group, if it's present. The comparison
- * here is quite strict: we require that the fib sets match exactly.
+ /* Check both fib group and notif group for equivalence.
+ *
+ * Let's assume the nexthops are ordered here to save time.
*/
- matched = false;
- do {
- if (re->fib_ng.nexthop == NULL)
- break;
-
- matched = true;
-
- /* First check the route's fib nexthops */
- for (ALL_NEXTHOPS(re->fib_ng, nexthop)) {
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- continue;
-
- ctx_nexthop = NULL;
- for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
- ctx_nexthop)) {
- if (nexthop_same(ctx_nexthop, nexthop))
- break;
- }
-
- if (ctx_nexthop == NULL) {
- /* Nexthop not in the new installed set */
- if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
- nexthop2str(nexthop, nh_str,
- sizeof(nh_str));
- zlog_debug("update_from_ctx: no match for fib nh %s",
- nh_str);
- }
-
- matched = false;
- break;
- }
- }
-
- if (!matched)
- break;
-
- /* Check the new installed set */
- ctx_nexthop = NULL;
- for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) {
-
- if (CHECK_FLAG(ctx_nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE))
- continue;
-
- /* Compare with the current group's nexthops */
- nexthop = NULL;
- for (ALL_NEXTHOPS(re->fib_ng, nexthop)) {
- if (nexthop_same(nexthop, ctx_nexthop))
- break;
- }
-
- if (nexthop == NULL) {
- /* Nexthop not in the old installed set */
- if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
- nexthop2str(ctx_nexthop, nh_str,
- sizeof(nh_str));
- zlog_debug("update_from_ctx: no fib match for notif nh %s",
- nh_str);
- }
- matched = false;
- break;
- }
+ if (nexthop_group_equal(&re->fib_ng, dplane_ctx_get_ng(ctx)) == false) {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ zlog_debug(
+ "%u:%s update_from_ctx: notif nh and fib nh mismatch",
+ re->vrf_id, dest_str);
}
- } while (0);
+ matched = false;
+ } else
+ matched = true;
/* If the new FIB set matches the existing FIB set, we're done. */
if (matched) {
@@ -1515,9 +1467,22 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
* walk the RIB group, looking for the 'installable' candidate
* nexthops, and then check those against the set
* that is actually installed.
+ *
+ * Assume nexthops are ordered here as well.
*/
matched = true;
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+
+ ctx_nexthop = dplane_ctx_get_ng(ctx)->nexthop;
+
+ /* Get the first `installed` one to check against.
+ * If the dataplane doesn't set these to be what was actually installed,
+ * it will just be whatever was in re->ng?
+ */
+ if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
+ || !CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop);
+
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
@@ -1526,20 +1491,15 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
continue;
/* Check for a FIB nexthop corresponding to the RIB nexthop */
- ctx_nexthop = NULL;
- for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) {
- if (nexthop_same(ctx_nexthop, nexthop))
- break;
- }
-
- /* If the FIB doesn't know about the nexthop,
- * it's not installed
- */
- if (ctx_nexthop == NULL) {
+ if (nexthop_same(ctx_nexthop, nexthop) == false) {
+ /* If the FIB doesn't know about the nexthop,
+ * it's not installed
+ */
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
nexthop2str(nexthop, nh_str, sizeof(nh_str));
- zlog_debug("update_from_ctx: no notif match for rib nh %s",
- nh_str);
+ zlog_debug(
+ "update_from_ctx: no notif match for rib nh %s",
+ nh_str);
}
matched = false;
@@ -1547,7 +1507,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
changed_p = true;
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- break;
+
+ /* Keep checking nexthops */
+ continue;
}
if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_FIB)) {
@@ -1561,6 +1523,8 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
}
+
+ ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop);
}
/* If all nexthops were processed, we're done */
@@ -1983,6 +1947,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
* not-installed; or not-installed to installed.
*/
if (start_count > 0 && end_count > 0) {
+ if (debug_p)
+ zlog_debug("%u:%s applied nexthop changes from dplane notification",
+ dplane_ctx_get_vrf(ctx), dest_str);
/* Changed nexthops - update kernel/others */
dplane_route_notif_update(rn, re,
@@ -2026,7 +1993,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_DELETE, ctx);
/* Redistribute, lsp, and nht update */
- redistribute_delete(dest_pfx, src_pfx, re);
+ redistribute_delete(dest_pfx, src_pfx, re, NULL);
zebra_rib_evaluate_rn_nexthops(
rn, zebra_router_get_next_sequence());
@@ -2042,19 +2009,28 @@ done:
dplane_ctx_fini(&ctx);
}
-/* Take a list of route_node structs and return 1, if there was a record
- * picked from it and processed by rib_process(). Don't process more,
- * than one RN record; operate only in the specified sub-queue.
- */
-static unsigned int process_subq(struct list *subq, uint8_t qindex)
+static void process_subq_nhg(struct listnode *lnode)
{
- struct listnode *lnode = listhead(subq);
- struct route_node *rnode;
- rib_dest_t *dest;
- struct zebra_vrf *zvrf = NULL;
+ struct nhg_ctx *ctx = NULL;
+ uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
- if (!lnode)
- return 0;
+ ctx = listgetdata(lnode);
+
+ if (!ctx)
+ return;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("NHG Context id=%u dequeued from sub-queue %u",
+ ctx->id, qindex);
+
+ rib_nhg_process(ctx);
+}
+
+static void process_subq_route(struct listnode *lnode, uint8_t qindex)
+{
+ struct route_node *rnode = NULL;
+ rib_dest_t *dest = NULL;
+ struct zebra_vrf *zvrf = NULL;
rnode = listgetdata(lnode);
dest = rib_dest_from_rnode(rnode);
@@ -2084,7 +2060,26 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex)
}
#endif
route_unlock_node(rnode);
+}
+
+/* Take a list of route_node structs and return 1, if there was a record
+ * picked from it and processed by rib_process(). Don't process more,
+ * than one RN record; operate only in the specified sub-queue.
+ */
+static unsigned int process_subq(struct list *subq, uint8_t qindex)
+{
+ struct listnode *lnode = listhead(subq);
+
+ if (!lnode)
+ return 0;
+
+ if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map)
+ process_subq_nhg(lnode);
+ else
+ process_subq_route(lnode, qindex);
+
list_delete_node(subq, lnode);
+
return 1;
}
@@ -2142,11 +2137,14 @@ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data)
* original metaqueue index value will win and we'll end up with
* the route node enqueued once.
*/
-static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn)
+static int rib_meta_queue_add(struct meta_queue *mq, void *data)
{
+ struct route_node *rn = NULL;
struct route_entry *re = NULL, *curr_re = NULL;
uint8_t qindex = MQ_SIZE, curr_qindex = MQ_SIZE;
+ rn = (struct route_node *)data;
+
RNODE_FOREACH_RE (rn, curr_re) {
curr_qindex = route_info[curr_re->type].meta_q_map;
@@ -2157,7 +2155,7 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn)
}
if (!re)
- return;
+ return -1;
/* Invariant: at this point we always have rn->info set. */
if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
@@ -2166,7 +2164,7 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn)
rnode_debug(rn, re->vrf_id,
"rn %p is already queued in sub-queue %u",
(void *)rn, qindex);
- return;
+ return -1;
}
SET_FLAG(rib_dest_from_rnode(rn)->flags, RIB_ROUTE_QUEUED(qindex));
@@ -2177,26 +2175,37 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn)
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %u",
(void *)rn, qindex);
+
+ return 0;
}
-/* Add route_node to work queue and schedule processing */
-void rib_queue_add(struct route_node *rn)
+static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
{
- assert(rn);
+ struct nhg_ctx *ctx = NULL;
+ uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
- /* Pointless to queue a route_node with no RIB entries to add or remove
- */
- if (!rnode_to_ribs(rn)) {
- zlog_debug("%s: called for route_node (%p, %d) with no ribs",
- __func__, (void *)rn, rn->lock);
- zlog_backtrace(LOG_DEBUG);
- return;
- }
+ ctx = (struct nhg_ctx *)data;
+
+ if (!ctx)
+ return -1;
+
+ listnode_add(mq->subq[qindex], ctx);
+ mq->size++;
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("NHG Context id=%u queued into sub-queue %u",
+ ctx->id, qindex);
+
+ return 0;
+}
+
+static int mq_add_handler(void *data,
+ int (*mq_add_func)(struct meta_queue *mq, void *data))
+{
if (zrouter.ribq == NULL) {
flog_err(EC_ZEBRA_WQ_NONEXISTENT,
"%s: work_queue does not exist!", __func__);
- return;
+ return -1;
}
/*
@@ -2210,9 +2219,31 @@ void rib_queue_add(struct route_node *rn)
if (work_queue_empty(zrouter.ribq))
work_queue_add(zrouter.ribq, zrouter.mq);
- rib_meta_queue_add(zrouter.mq, rn);
+ return mq_add_func(zrouter.mq, data);
+}
- return;
+/* Add route_node to work queue and schedule processing */
+int rib_queue_add(struct route_node *rn)
+{
+ assert(rn);
+
+ /* Pointless to queue a route_node with no RIB entries to add or remove
+ */
+ if (!rnode_to_ribs(rn)) {
+ zlog_debug("%s: called for route_node (%p, %d) with no ribs",
+ __func__, (void *)rn, rn->lock);
+ zlog_backtrace(LOG_DEBUG);
+ return -1;
+ }
+
+ return mq_add_handler(rn, &rib_meta_queue_add);
+}
+
+int rib_queue_nhg_add(struct nhg_ctx *ctx)
+{
+ assert(ctx);
+
+ return mq_add_handler(ctx, &rib_meta_queue_nhg_add);
}
/* Create new meta queue.
@@ -2380,6 +2411,7 @@ 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);
@@ -2394,7 +2426,13 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
if (dest->selected_fib == re)
dest->selected_fib = NULL;
- nexthops_free(re->ng.nexthop);
+ if (re->nhe_id) {
+ nhe = zebra_nhg_lookup_id(re->nhe_id);
+ if (nhe)
+ zebra_nhg_decrement_ref(nhe);
+ } else if (re->ng)
+ nexthop_group_delete(&re->ng);
+
nexthops_free(re->fib_ng.nexthop);
XFREE(MTYPE_RE, re);
@@ -2460,9 +2498,10 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
"%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,
- re->nexthop_num, re->nexthop_active_num);
+ nexthop_group_nexthop_num(re->ng),
+ nexthop_group_active_nexthop_num(re->ng));
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) {
struct interface *ifp;
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
@@ -2613,6 +2652,7 @@ 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 nhg_hash_entry *nhe = NULL;
struct route_table *table;
struct route_node *rn;
struct route_entry *same = NULL;
@@ -2626,10 +2666,58 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
/* Lookup table. */
table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table);
if (!table) {
+ if (re->ng)
+ nexthop_group_delete(&re->ng);
XFREE(MTYPE_RE, re);
return 0;
}
+ if (re->nhe_id) {
+ 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);
+ return -1;
+ }
+ } else {
+ nhe = zebra_nhg_rib_find(0, re->ng, afi);
+
+ /*
+ * The nexthops got copied over into an nhe,
+ * so free them now.
+ */
+ nexthop_group_delete(&re->ng);
+
+ if (!nhe) {
+ char buf[PREFIX_STRLEN] = "";
+ char buf2[PREFIX_STRLEN] = "";
+
+ flog_err(
+ EC_ZEBRA_TABLE_LOOKUP_FAILED,
+ "Zebra failed to find or create a nexthop hash entry for %s%s%s",
+ prefix2str(p, buf, sizeof(buf)),
+ src_p ? " from " : "",
+ src_p ? prefix2str(src_p, buf2, sizeof(buf2))
+ : "");
+
+ XFREE(MTYPE_RE, re);
+ return -1;
+ }
+ }
+
+ /*
+ * Attach the re to the nhe's nexthop group.
+ *
+ * TODO: This will need to change when we start getting IDs from upper
+ * level protocols, as the refcnt might be wrong, since it checks
+ * if old_id != new_id.
+ */
+ zebra_nhg_re_update_ref(re, nhe);
+
/* Make it sure prefixlen is applied to the prefix. */
apply_mask(p);
if (src_p)
@@ -2706,8 +2794,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, int flags, struct prefix *p,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
- uint32_t table_id, uint32_t metric, uint8_t distance,
- bool fromkernel)
+ uint32_t nhe_id, uint32_t table_id, uint32_t metric,
+ uint8_t distance, bool fromkernel)
{
struct route_table *table;
struct route_node *rn;
@@ -2770,31 +2858,37 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric)
continue;
- if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng.nexthop)
+ if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng->nexthop)
&& rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) {
if (rtnh->ifindex != nh->ifindex)
continue;
same = re;
break;
}
+
/* Make sure that the route found has the same gateway. */
- else {
- if (nh == NULL) {
+ if (nhe_id && re->nhe_id == nhe_id) {
+ same = re;
+ break;
+ }
+
+ if (nh == NULL) {
+ same = re;
+ break;
+ }
+ for (ALL_NEXTHOPS_PTR(re->ng, rtnh)) {
+ /*
+ * No guarantee all kernel send nh with labels
+ * on delete.
+ */
+ if (nexthop_same_no_labels(rtnh, nh)) {
same = re;
break;
}
- for (ALL_NEXTHOPS(re->ng, rtnh))
- /*
- * No guarantee all kernel send nh with labels
- * on delete.
- */
- if (nexthop_same_no_labels(rtnh, nh)) {
- same = re;
- break;
- }
- if (same)
- break;
}
+
+ if (same)
+ break;
}
/* If same type of route can't be found and this message is from
kernel. */
@@ -2824,7 +2918,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
if (allow_delete) {
UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED);
/* Unset flags. */
- for (rtnh = fib->ng.nexthop; rtnh;
+ for (rtnh = fib->ng->nexthop; rtnh;
rtnh = rtnh->next)
UNSET_FLAG(rtnh->flags,
NEXTHOP_FLAG_FIB);
@@ -2880,7 +2974,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) {
struct nexthop *tmp_nh;
- for (ALL_NEXTHOPS(re->ng, tmp_nh)) {
+ for (ALL_NEXTHOPS_PTR(re->ng, tmp_nh)) {
struct ipaddr vtep_ip;
memset(&vtep_ip, 0, sizeof(struct ipaddr));
@@ -2915,11 +3009,11 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
int rib_add(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,
- uint32_t table_id, uint32_t metric, uint32_t mtu, uint8_t distance,
- route_tag_t tag)
+ uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint32_t mtu,
+ uint8_t distance, route_tag_t tag)
{
- struct route_entry *re;
- struct nexthop *nexthop;
+ struct route_entry *re = NULL;
+ struct nexthop *nexthop = NULL;
/* Allocate new route_entry structure. */
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
@@ -2931,23 +3025,82 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
re->mtu = mtu;
re->table = table_id;
re->vrf_id = vrf_id;
- re->nexthop_num = 0;
re->uptime = monotime(NULL);
re->tag = tag;
+ re->nhe_id = nhe_id;
- /* Add nexthop. */
- nexthop = nexthop_new();
- *nexthop = *nh;
- route_entry_nexthop_add(re, nexthop);
+ if (!nhe_id) {
+ re->ng = nexthop_group_new();
+
+ /* Add nexthop. */
+ nexthop = nexthop_new();
+ *nexthop = *nh;
+ route_entry_nexthop_add(re, nexthop);
+ }
return rib_add_multipath(afi, safi, p, src_p, re);
}
+static const char *rib_update_event2str(rib_update_event_t event)
+{
+ const char *ret = "UNKNOWN";
+
+ switch (event) {
+ case RIB_UPDATE_KERNEL:
+ ret = "RIB_UPDATE_KERNEL";
+ break;
+ case RIB_UPDATE_RMAP_CHANGE:
+ ret = "RIB_UPDATE_RMAP_CHANGE";
+ break;
+ case RIB_UPDATE_OTHER:
+ ret = "RIB_UPDATE_OTHER";
+ break;
+ case RIB_UPDATE_MAX:
+ break;
+ }
+
+ return ret;
+}
+
+
+/* Schedule route nodes to be processed if they match the type */
+static void rib_update_route_node(struct route_node *rn, int type)
+{
+ struct route_entry *re, *next;
+ bool re_changed = false;
+
+ RNODE_FOREACH_RE_SAFE (rn, re, next) {
+ if (type == ZEBRA_ROUTE_ALL || type == re->type) {
+ SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
+ re_changed = true;
+ }
+ }
+
+ if (re_changed)
+ rib_queue_add(rn);
+}
+
/* Schedule routes of a particular table (address-family) based on event. */
void rib_update_table(struct route_table *table, rib_update_event_t event)
{
struct route_node *rn;
- struct route_entry *re, *next;
+
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct zebra_vrf *zvrf;
+ struct vrf *vrf;
+
+ zvrf = table->info ? ((rib_table_info_t *)table->info)->zvrf
+ : NULL;
+ vrf = zvrf ? zvrf->vrf : NULL;
+
+ zlog_debug("%s: %s VRF %s Table %u event %s", __func__,
+ table->info ? afi2str(
+ ((rib_table_info_t *)table->info)->afi)
+ : "Unknown",
+ vrf ? vrf->name : "Unknown",
+ zvrf ? zvrf->table_id : 0,
+ rib_update_event2str(event));
+ }
/* Walk all routes and queue for processing, if appropriate for
* the trigger event.
@@ -2958,49 +3111,139 @@ void rib_update_table(struct route_table *table, rib_update_event_t event)
* has already been queued we don't
* need to queue it up again
*/
- if (rn->info && CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
- RIB_ROUTE_ANY_QUEUED))
+ if (rn->info
+ && CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
+ RIB_ROUTE_ANY_QUEUED))
continue;
+
switch (event) {
+ case RIB_UPDATE_KERNEL:
+ rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL);
+ break;
case RIB_UPDATE_RMAP_CHANGE:
case RIB_UPDATE_OTHER:
- /* Right now, examine all routes. Can restrict to a
- * protocol in
- * some cases (TODO).
- */
- if (rnode_to_ribs(rn)) {
- RNODE_FOREACH_RE_SAFE (rn, re, next)
- SET_FLAG(re->status,
- ROUTE_ENTRY_CHANGED);
- rib_queue_add(rn);
- }
+ rib_update_route_node(rn, ZEBRA_ROUTE_ALL);
break;
-
default:
break;
}
}
}
-/* RIB update function. */
-void rib_update(vrf_id_t vrf_id, rib_update_event_t event)
+static void rib_update_handle_vrf(vrf_id_t vrf_id, rib_update_event_t event)
{
struct route_table *table;
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: Handling VRF %s event %s", __func__,
+ vrf_id_to_name(vrf_id), rib_update_event2str(event));
+
/* Process routes of interested address-families. */
table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
- if (table) {
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%s : AFI_IP event %d", __func__, event);
+ if (table)
rib_update_table(table, event);
- }
table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, vrf_id);
- if (table) {
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%s : AFI_IP6 event %d", __func__, event);
+ if (table)
rib_update_table(table, event);
- }
+}
+
+static void rib_update_handle_vrf_all(rib_update_event_t event)
+{
+ struct zebra_router_table *zrt;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: Handling VRF (ALL) event %s", __func__,
+ rib_update_event2str(event));
+
+ /* Just iterate over all the route tables, rather than vrf lookups */
+ RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables)
+ rib_update_table(zrt->table, event);
+}
+
+struct rib_update_ctx {
+ rib_update_event_t event;
+ bool vrf_all;
+ vrf_id_t vrf_id;
+};
+
+static struct rib_update_ctx *rib_update_ctx_init(vrf_id_t vrf_id,
+ rib_update_event_t event)
+{
+ struct rib_update_ctx *ctx;
+
+ ctx = XCALLOC(MTYPE_RIB_UPDATE_CTX, sizeof(struct rib_update_ctx));
+
+ ctx->event = event;
+ ctx->vrf_id = vrf_id;
+
+ return ctx;
+}
+
+static void rib_update_ctx_fini(struct rib_update_ctx **ctx)
+{
+ XFREE(MTYPE_RIB_UPDATE_CTX, *ctx);
+
+ *ctx = NULL;
+}
+
+static int rib_update_handler(struct thread *thread)
+{
+ struct rib_update_ctx *ctx;
+
+ ctx = THREAD_ARG(thread);
+
+ if (ctx->vrf_all)
+ rib_update_handle_vrf_all(ctx->event);
+ else
+ rib_update_handle_vrf(ctx->vrf_id, ctx->event);
+
+ rib_update_ctx_fini(&ctx);
+
+ return 0;
+}
+
+/*
+ * Thread list to ensure we don't schedule a ton of events
+ * if interfaces are flapping for instance.
+ */
+static struct thread *t_rib_update_threads[RIB_UPDATE_MAX];
+
+/* Schedule a RIB update event for specific vrf */
+void rib_update_vrf(vrf_id_t vrf_id, rib_update_event_t event)
+{
+ struct rib_update_ctx *ctx;
+
+ ctx = rib_update_ctx_init(vrf_id, event);
+
+ /* Don't worry about making sure multiple rib updates for specific vrf
+ * are scheduled at once for now. If it becomes a problem, we can use a
+ * lookup of some sort to keep track of running threads via t_vrf_id
+ * like how we are doing it in t_rib_update_threads[].
+ */
+ thread_add_event(zrouter.master, rib_update_handler, ctx, 0, NULL);
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: Scheduled VRF %s, event %s", __func__,
+ vrf_id_to_name(ctx->vrf_id),
+ rib_update_event2str(event));
+}
+
+/* Schedule a RIB update event for all vrfs */
+void rib_update(rib_update_event_t event)
+{
+ struct rib_update_ctx *ctx;
+
+ ctx = rib_update_ctx_init(0, event);
+
+ ctx->vrf_all = true;
+
+ if (!thread_add_event(zrouter.master, rib_update_handler, ctx, 0,
+ &t_rib_update_threads[event]))
+ rib_update_ctx_fini(&ctx); /* Already scheduled */
+ else if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: Schedued VRF (ALL), event %s", __func__,
+ rib_update_event2str(event));
}
/* Delete self installed routes after zebra is relaunched. */
@@ -3053,7 +3296,7 @@ void rib_sweep_table(struct route_table *table)
* this decision needs to be revisited
*/
SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
- for (ALL_NEXTHOPS(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
rib_uninstall_kernel(rn, re);
@@ -3077,6 +3320,7 @@ int rib_sweep_route(struct thread *t)
}
zebra_router_sweep_route();
+ zebra_router_sweep_nhgs();
return 0;
}
@@ -3190,6 +3434,7 @@ static int rib_process_dplane_results(struct thread *thread)
{
struct zebra_dplane_ctx *ctx;
struct dplane_ctx_q ctxlist;
+ bool shut_p = false;
/* Dequeue a list of completed updates with one lock/unlock cycle */
@@ -3209,6 +3454,21 @@ static int rib_process_dplane_results(struct thread *thread)
if (ctx == NULL)
break;
+ /* If zebra is shutting down, avoid processing results,
+ * just drain the results queue.
+ */
+ shut_p = atomic_load_explicit(&zrouter.in_shutdown,
+ memory_order_relaxed);
+ if (shut_p) {
+ while (ctx) {
+ dplane_ctx_fini(&ctx);
+
+ ctx = dplane_ctx_dequeue(&ctxlist);
+ }
+
+ continue;
+ }
+
while (ctx) {
switch (dplane_ctx_get_op(ctx)) {
case DPLANE_OP_ROUTE_INSTALL:
@@ -3231,6 +3491,12 @@ static int rib_process_dplane_results(struct thread *thread)
rib_process_dplane_notify(ctx);
break;
+ case DPLANE_OP_NH_INSTALL:
+ case DPLANE_OP_NH_UPDATE:
+ case DPLANE_OP_NH_DELETE:
+ zebra_nhg_dplane_result(ctx);
+ break;
+
case DPLANE_OP_LSP_INSTALL:
case DPLANE_OP_LSP_UPDATE:
case DPLANE_OP_LSP_DELETE:
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index bcaf1b520..60e23cc4d 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -337,7 +337,7 @@ static void addr2hostprefix(int af, const union g_addr *addr,
break;
default:
memset(prefix, 0, sizeof(*prefix));
- zlog_debug("%s: unknown address family %d", __func__, af);
+ zlog_warn("%s: unknown address family %d", __func__, af);
break;
}
}
@@ -384,7 +384,7 @@ static void zebra_rnh_clear_nexthop_rnh_filters(struct route_entry *re)
struct nexthop *nexthop;
if (re) {
- for (nexthop = re->ng.nexthop; nexthop;
+ for (nexthop = re->ng->nexthop; nexthop;
nexthop = nexthop->next) {
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED);
}
@@ -403,7 +403,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf,
route_map_result_t ret;
if (prn && re) {
- for (nexthop = re->ng.nexthop; nexthop;
+ for (nexthop = re->ng->nexthop; nexthop;
nexthop = nexthop->next) {
ret = zebra_nht_route_map_check(
afi, proto, &prn->p, zvrf, re, nexthop);
@@ -688,7 +688,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
/* Just being SELECTED isn't quite enough - must
* have an installed nexthop to be useful.
*/
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) {
if (rnh_nexthop_valid(re, nexthop))
break;
}
@@ -707,7 +707,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
break;
if (re->type == ZEBRA_ROUTE_NHRP) {
- for (nexthop = re->ng.nexthop; nexthop;
+ for (nexthop = re->ng->nexthop; nexthop;
nexthop = nexthop->next)
if (nexthop->type
== NEXTHOP_TYPE_IFINDEX)
@@ -916,7 +916,8 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
table = get_rnh_table(vrfid, afi, type);
if (!table) {
- zlog_debug("print_rnhs: rnh table not found");
+ if (IS_ZEBRA_DEBUG_NHT)
+ zlog_debug("print_rnhs: rnh table not found");
return;
}
@@ -939,7 +940,7 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
return;
/* free RE and nexthops */
- nexthops_free(re->ng.nexthop);
+ nexthop_group_delete(&re->ng);
XFREE(MTYPE_RE, re);
}
@@ -962,8 +963,9 @@ static void copy_state(struct rnh *rnh, struct route_entry *re,
state->metric = re->metric;
state->vrf_id = re->vrf_id;
state->status = re->status;
+ state->ng = nexthop_group_new();
- route_entry_copy_nexthops(state, re->ng.nexthop);
+ route_entry_copy_nexthops(state, re->ng->nexthop);
rnh->state = state;
}
@@ -981,10 +983,11 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2)
if (r1->metric != r2->metric)
return 1;
- if (r1->nexthop_num != r2->nexthop_num)
+ if (nexthop_group_nexthop_num(r1->ng)
+ != nexthop_group_nexthop_num(r2->ng))
return 1;
- if (nexthop_group_hash(&r1->ng) != nexthop_group_hash(&r2->ng))
+ if (nexthop_group_hash(r1->ng) != nexthop_group_hash(r2->ng))
return 1;
return 0;
@@ -1034,7 +1037,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
num = 0;
nump = stream_get_endp(s);
stream_putc(s, 0);
- for (ALL_NEXTHOPS(re->ng, nh))
+ for (ALL_NEXTHOPS_PTR(re->ng, nh))
if (rnh_nexthop_valid(re, nh)) {
stream_putl(s, nh->vrf_id);
stream_putc(s, nh->type);
@@ -1134,7 +1137,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
if (rnh->state) {
vty_out(vty, " resolved via %s\n",
zebra_route_string(rnh->state->type));
- for (nexthop = rnh->state->ng.nexthop; nexthop;
+ for (nexthop = rnh->state->ng->nexthop; nexthop;
nexthop = nexthop->next)
print_nh(nexthop, vty);
} else
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index 1e9f9e4ec..e5319c64a 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -29,7 +29,7 @@
#include "zebra_pbr.h"
#include "zebra_vxlan.h"
#include "zebra_mlag.h"
-#include "zebra_nhg.h"
+#include "zebra_nhg_private.h"
#include "debug.h"
DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info")
@@ -154,6 +154,11 @@ void zebra_router_sweep_route(void)
}
}
+void zebra_router_sweep_nhgs(void)
+{
+ zebra_nhg_sweep_table(zrouter.nhgs_id);
+}
+
static void zebra_router_free_table(struct zebra_router_table *zrt)
{
void *table_info;
@@ -218,6 +223,11 @@ void zebra_router_terminate(void)
zebra_vxlan_disable();
zebra_mlag_terminate();
+ hash_clean(zrouter.nhgs, zebra_nhg_free);
+ hash_free(zrouter.nhgs);
+ hash_clean(zrouter.nhgs_id, NULL);
+ hash_free(zrouter.nhgs_id);
+
hash_clean(zrouter.rules_hash, zebra_pbr_rules_free);
hash_free(zrouter.rules_hash);
@@ -253,4 +263,11 @@ void zebra_router_init(void)
zrouter.iptable_hash = hash_create_size(8, zebra_pbr_iptable_hash_key,
zebra_pbr_iptable_hash_equal,
"IPtable Hash Entry");
+
+ zrouter.nhgs =
+ hash_create_size(8, zebra_nhg_hash_key, zebra_nhg_hash_equal,
+ "Zebra Router Nexthop Groups");
+ zrouter.nhgs_id =
+ hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal,
+ "Zebra Router Nexthop Groups ID index");
}
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index e50f8a118..ac4c96147 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -74,6 +74,8 @@ struct zebra_mlag_info {
};
struct zebra_router {
+ atomic_bool in_shutdown;
+
/* Thread master */
struct thread_master *master;
@@ -130,6 +132,12 @@ struct zebra_router {
* Time for when we sweep the rib from old routes
*/
time_t startup_time;
+
+ /*
+ * The hash of nexthop groups associated with this router
+ */
+ struct hash *nhgs;
+ struct hash *nhgs_id;
};
#define GRACEFUL_RESTART_TIME 60
@@ -137,6 +145,7 @@ struct zebra_router {
extern struct zebra_router zrouter;
extern void zebra_router_init(void);
+extern void zebra_router_cleanup(void);
extern void zebra_router_terminate(void);
extern struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf,
@@ -151,6 +160,7 @@ extern void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid,
extern int zebra_router_config_write(struct vty *vty);
extern void zebra_router_sweep_route(void);
+extern void zebra_router_sweep_nhgs(void);
extern void zebra_router_show_table_summary(struct vty *vty);
diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c
index 74eab765c..56c766432 100644
--- a/zebra/zebra_snmp.c
+++ b/zebra/zebra_snmp.c
@@ -285,8 +285,8 @@ static void check_replace(struct route_node *np2, struct route_entry *re2,
return;
}
- if (in_addr_cmp((uint8_t *)&(*re)->ng.nexthop->gate.ipv4,
- (uint8_t *)&re2->ng.nexthop->gate.ipv4)
+ if (in_addr_cmp((uint8_t *)&(*re)->ng->nexthop->gate.ipv4,
+ (uint8_t *)&re2->ng->nexthop->gate.ipv4)
<= 0)
return;
@@ -372,7 +372,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[],
(uint8_t *)&dest)) {
RNODE_FOREACH_RE (*np, *re) {
if (!in_addr_cmp((uint8_t *)&(*re)
- ->ng.nexthop
+ ->ng->nexthop
->gate.ipv4,
(uint8_t *)&nexthop))
if (proto
@@ -406,7 +406,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[],
|| ((policy == policy2) && (proto < proto2))
|| ((policy == policy2) && (proto == proto2)
&& (in_addr_cmp(
- (uint8_t *)&re2->ng.nexthop
+ (uint8_t *)&re2->ng->nexthop
->gate.ipv4,
(uint8_t *)&nexthop)
>= 0)))
@@ -432,7 +432,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[],
{
struct nexthop *nexthop;
- nexthop = (*re)->ng.nexthop;
+ nexthop = (*re)->ng->nexthop;
if (nexthop) {
pnt = (uint8_t *)&nexthop->gate.ipv4;
for (i = 0; i < 4; i++)
@@ -462,7 +462,7 @@ static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len,
if (!np)
return NULL;
- nexthop = re->ng.nexthop;
+ nexthop = re->ng->nexthop;
if (!nexthop)
return NULL;
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 72d0b6866..f425c0e49 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -92,7 +92,7 @@ static int zebra_vrf_new(struct vrf *vrf)
struct zebra_vrf *zvrf;
if (IS_ZEBRA_DEBUG_EVENT)
- zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id);
+ zlog_debug("VRF %s created, id %u", vrf->name, vrf->vrf_id);
zvrf = zebra_vrf_alloc();
vrf->info = zvrf;
@@ -487,7 +487,11 @@ static int vrf_config_write(struct vty *vty)
if (zvrf_id(zvrf) == VRF_DEFAULT) {
if (zvrf->l3vni)
- vty_out(vty, "vni %u\n", zvrf->l3vni);
+ vty_out(vty, "vni %u%s\n", zvrf->l3vni,
+ is_l3vni_for_prefix_routes_only(
+ zvrf->l3vni)
+ ? " prefix-routes-only"
+ : "");
if (zvrf->zebra_rnh_ip_default_route)
vty_out(vty, "ip nht resolve-via-default\n");
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 798448109..9d1745473 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -52,6 +52,8 @@
#include "zebra/ipforward.h"
#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_pbr.h"
+#include "zebra/zebra_nhg.h"
+#include "zebra/interface.h"
extern int allow_delete;
@@ -62,7 +64,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
bool supernets_only, int type,
unsigned short ospf_instance_id);
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
- int mcast, bool use_fib);
+ int mcast, bool use_fib, bool show_ng);
static void vty_show_ip_route_summary(struct vty *vty,
struct route_table *table);
static void vty_show_ip_route_summary_prefix(struct vty *vty,
@@ -154,7 +156,7 @@ DEFUN (show_ip_rpf_addr,
re = rib_match_ipv4_multicast(VRF_DEFAULT, addr, &rn);
if (re)
- vty_show_ip_route_detail(vty, rn, 1, false);
+ vty_show_ip_route_detail(vty, rn, 1, false, false);
else
vty_out(vty, "%% No match for RPF lookup\n");
@@ -186,7 +188,7 @@ static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
/* 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)
+ int mcast, bool use_fib, bool show_ng)
{
struct route_entry *re;
struct nexthop *nexthop;
@@ -258,7 +260,10 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
tm->tm_hour);
vty_out(vty, " ago\n");
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ if (show_ng)
+ vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id);
+
+ for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) {
char addrstr[32];
vty_out(vty, " %c%s",
@@ -394,6 +399,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
json_object *json_labels = NULL;
time_t uptime;
struct tm *tm;
+ struct vrf *vrf = NULL;
rib_dest_t *dest = rib_dest_from_rnode(rn);
struct nexthop_group *nhg;
@@ -407,7 +413,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
if (is_fib)
nhg = rib_active_nhg(re);
else
- nhg = &(re->ng);
+ nhg = re->ng;
if (json) {
json_route = json_object_new_object();
@@ -422,9 +428,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
json_object_int_add(json_route, "instance",
re->instance);
- if (re->vrf_id)
+ if (re->vrf_id) {
json_object_int_add(json_route, "vrfId", re->vrf_id);
+ vrf = vrf_lookup_by_id(re->vrf_id);
+ json_object_string_add(json_route, "vrfName",
+ vrf->name);
+ }
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
json_object_boolean_true_add(json_route, "selected");
@@ -456,9 +466,9 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
json_object_int_add(json_route, "internalFlags",
re->flags);
json_object_int_add(json_route, "internalNextHopNum",
- re->nexthop_num);
+ nexthop_group_nexthop_num(re->ng));
json_object_int_add(json_route, "internalNextHopActiveNum",
- re->nexthop_active_num);
+ nexthop_group_active_nexthop_num(re->ng));
if (uptime < ONE_DAY_SECOND)
sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
tm->tm_sec);
@@ -565,9 +575,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
if ((nexthop->vrf_id != re->vrf_id)
&& (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
- struct vrf *vrf =
- vrf_lookup_by_id(nexthop->vrf_id);
-
+ vrf = vrf_lookup_by_id(nexthop->vrf_id);
json_object_string_add(json_nexthop, "vrf",
vrf->name);
}
@@ -1022,10 +1030,9 @@ DEFPY (show_route_all_table_vrf,
continue;
if (zrt->afi != afi || zrt->safi != SAFI_UNICAST)
continue;
- if (zrt->table)
- do_show_route_helper(vty, info->zvrf, zrt->table, afi,
- false, 0, false, false,
- 0, 0, !!json, zrt->tableid);
+
+ do_show_route_helper(vty, info->zvrf, zrt->table, afi, false, 0,
+ false, false, 0, 0, !!json, zrt->tableid);
}
return CMD_SUCCESS;
}
@@ -1099,6 +1106,295 @@ DEFUN (ip_nht_default_route,
return CMD_SUCCESS;
}
+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);
+
+ vty_out(vty, "ID: %u\n", nhe->id);
+ vty_out(vty, " RefCnt: %d\n", nhe->refcnt);
+
+ if (nhe_vrf)
+ vty_out(vty, " VRF: %s\n", nhe_vrf->name);
+ else
+ vty_out(vty, " VRF: UNKNOWN\n");
+
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
+ vty_out(vty, " Duplicate - from kernel not hashable\n");
+
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
+ vty_out(vty, " Valid");
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED))
+ vty_out(vty, ", Installed");
+ vty_out(vty, "\n");
+ }
+ if (nhe->ifp)
+ vty_out(vty, " Interface Index: %d\n", nhe->ifp->ifindex);
+
+ if (!zebra_nhg_depends_is_empty(nhe)) {
+ vty_out(vty, " Depends:");
+ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
+ vty_out(vty, " (%u)", rb_node_dep->nhe->id);
+ }
+ vty_out(vty, "\n");
+ }
+
+ for (ALL_NEXTHOPS_PTR(nhe->nhg, nexthop)) {
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ vty_out(vty, " ");
+ else
+ /* Make recursive nexthops a bit more clear */
+ vty_out(vty, " ");
+
+ 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;
+
+ 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;
+ }
+
+ 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_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)");
+
+ 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;
+ }
+
+ /* 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));
+ }
+
+ vty_out(vty, "\n");
+ }
+
+ if (!zebra_nhg_dependents_is_empty(nhe)) {
+ vty_out(vty, " Dependents:");
+ frr_each(nhg_connected_tree, &nhe->nhg_dependents,
+ rb_node_dep) {
+ vty_out(vty, " (%u)", rb_node_dep->nhe->id);
+ }
+ vty_out(vty, "\n");
+ }
+
+}
+
+static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id)
+{
+ struct nhg_hash_entry *nhe = NULL;
+
+ nhe = zebra_nhg_lookup_id(id);
+
+ if (nhe)
+ show_nexthop_group_out(vty, nhe);
+ else {
+ vty_out(vty, "Nexthop Group ID: %u does not exist\n", id);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+static void show_nexthop_group_cmd_helper(struct vty *vty,
+ struct zebra_vrf *zvrf, afi_t afi)
+{
+ struct list *list = hash_to_list(zrouter.nhgs);
+ struct nhg_hash_entry *nhe = NULL;
+ struct listnode *node = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(list, node, nhe)) {
+
+ if (afi && nhe->afi != afi)
+ continue;
+
+ if (nhe->vrf_id != zvrf->vrf->vrf_id)
+ continue;
+
+ show_nexthop_group_out(vty, nhe);
+ }
+
+ list_delete(&list);
+}
+
+static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp)
+{
+ struct zebra_if *zebra_if = NULL;
+ struct nhg_connected *rb_node_dep = NULL;
+
+ zebra_if = ifp->info;
+
+ if (!if_nhg_dependents_is_empty(ifp)) {
+ vty_out(vty, "Interface %s:\n", ifp->name);
+
+ frr_each(nhg_connected_tree, &zebra_if->nhg_dependents,
+ rb_node_dep) {
+ vty_out(vty, " ");
+ show_nexthop_group_out(vty, rb_node_dep->nhe);
+ }
+ }
+}
+
+DEFPY (show_interface_nexthop_group,
+ show_interface_nexthop_group_cmd,
+ "show interface [IFNAME$if_name] nexthop-group",
+ SHOW_STR
+ "Interface status and configuration\n"
+ "Interface name\n"
+ "Show Nexthop Groups\n")
+{
+ struct vrf *vrf = NULL;
+ struct interface *ifp = NULL;
+ bool found = false;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (if_name) {
+ ifp = if_lookup_by_name(if_name, vrf->vrf_id);
+ if (ifp) {
+ if_nexthop_group_dump_vty(vty, ifp);
+ found = true;
+ }
+ } else {
+ FOR_ALL_INTERFACES (vrf, ifp)
+ if_nexthop_group_dump_vty(vty, ifp);
+ found = true;
+ }
+ }
+
+ if (!found) {
+ vty_out(vty, "%% Can't find interface %s\n", if_name);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_nexthop_group,
+ show_nexthop_group_cmd,
+ "show nexthop-group <(0-4294967295)$id|[<ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
+ SHOW_STR
+ "Show Nexthop Groups\n"
+ "Nexthop Group ID\n"
+ IP_STR
+ IP6_STR
+ VRF_FULL_CMD_HELP_STR)
+{
+
+ struct zebra_vrf *zvrf = NULL;
+ afi_t afi = 0;
+
+ if (id)
+ return show_nexthop_group_id_cmd_helper(vty, id);
+
+ if (v4)
+ afi = AFI_IP;
+ else if (v6)
+ afi = AFI_IP6;
+
+ if (vrf_all) {
+ struct vrf *vrf;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf->info;
+ if (!zvrf)
+ continue;
+
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ show_nexthop_group_cmd_helper(vty, zvrf, afi);
+ }
+
+ return CMD_SUCCESS;
+ }
+
+ if (vrf_name)
+ zvrf = zebra_vrf_lookup_by_name(vrf_name);
+ else
+ zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
+
+ if (!zvrf) {
+ vty_out(vty, "VRF %s specified does not exist", vrf_name);
+ return CMD_WARNING;
+ }
+
+ show_nexthop_group_cmd_helper(vty, zvrf, afi);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (no_ip_nht_default_route,
no_ip_nht_default_route_cmd,
"no ip nht resolve-via-default",
@@ -1263,7 +1559,7 @@ DEFPY (show_route_detail,
|X:X::X:X/M$prefix\
>\
>\
- [json$json]",
+ [json$json] [nexthop-group$ng]",
SHOW_STR
IP_STR
"IPv6 forwarding table\n"
@@ -1277,7 +1573,8 @@ DEFPY (show_route_detail,
VRF_FULL_CMD_HELP_STR
"IPv6 Address\n"
"IPv6 prefix\n"
- JSON_STR)
+ JSON_STR
+ "Nexthop Group Information\n")
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
struct route_table *table;
@@ -1286,6 +1583,7 @@ DEFPY (show_route_detail,
bool use_fib = !!fib;
rib_dest_t *dest;
bool network_found = false;
+ bool show_ng = !!ng;
if (address_str)
prefix_str = address_str;
@@ -1319,10 +1617,10 @@ DEFPY (show_route_detail,
network_found = true;
if (json)
- vty_show_ip_route_detail_json(vty, rn,
- use_fib);
+ vty_show_ip_route_detail_json(vty, rn, use_fib);
else
- vty_show_ip_route_detail(vty, rn, 0, use_fib);
+ vty_show_ip_route_detail(vty, rn, 0, use_fib,
+ show_ng);
route_unlock_node(rn);
}
@@ -1374,7 +1672,7 @@ DEFPY (show_route_detail,
if (json)
vty_show_ip_route_detail_json(vty, rn, use_fib);
else
- vty_show_ip_route_detail(vty, rn, 0, use_fib);
+ vty_show_ip_route_detail(vty, rn, 0, use_fib, show_ng);
route_unlock_node(rn);
}
@@ -1537,7 +1835,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
fib_cnt[ZEBRA_ROUTE_TOTAL]++;
fib_cnt[re->type]++;
}
- for (nexthop = re->ng.nexthop; (!cnt && nexthop);
+ for (nexthop = re->ng->nexthop; (!cnt && nexthop);
nexthop = nexthop->next) {
cnt++;
rib_cnt[ZEBRA_ROUTE_TOTAL]++;
@@ -2655,6 +2953,10 @@ static int config_write_protocol(struct vty *vty)
== MCAST_MIX_DISTANCE
? "lower-distance"
: "longer-prefix");
+
+ /* Include dataplane info */
+ dplane_config_write_helper(vty);
+
return 1;
}
@@ -3027,6 +3329,9 @@ void zebra_vty_init(void)
install_element(CONFIG_NODE, &zebra_packet_process_cmd);
install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
+ install_element(VIEW_NODE, &show_nexthop_group_cmd);
+ install_element(VIEW_NODE, &show_interface_nexthop_group_cmd);
+
install_element(VIEW_NODE, &show_vrf_cmd);
install_element(VIEW_NODE, &show_vrf_vni_cmd);
install_element(VIEW_NODE, &show_route_cmd);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index c7f2976ac..1d2748c8e 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -5775,12 +5775,14 @@ static void process_remote_macip_del(vni_t vni,
vlan_if = zvni_map_to_svi(vxl->access_vlan,
zif->brslave_info.br_if);
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry",
- __PRETTY_FUNCTION__,
- ipaddr2str(ipaddr, buf1,
- sizeof(buf1)), n->flags,
- vlan_if->name);
- neigh_read_specific_ip(ipaddr, vlan_if);
+ zlog_debug(
+ "%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry",
+ __PRETTY_FUNCTION__,
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)),
+ n->flags,
+ vlan_if ? vlan_if->name : "Unknown");
+ if (vlan_if)
+ neigh_read_specific_ip(ipaddr, vlan_if);
}
/* When the MAC changes for an IP, it is possible the
@@ -9153,6 +9155,11 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
if (zvni->advertise_svi_macip == advertise)
return;
+ /* Store flag even though SVI is not present.
+ * Once SVI comes up triggers self MAC-IP route add.
+ */
+ zvni->advertise_svi_macip = advertise;
+
ifp = zvni->vxlan_if;
if (!ifp)
return;
@@ -9164,20 +9171,17 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
return;
zl2_info = zif->l2info.vxl;
-
vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
zif->brslave_info.br_if);
if (!vlan_if)
return;
if (advertise) {
- zvni->advertise_svi_macip = advertise;
/* Add primary SVI MAC-IP */
zvni_add_macip_for_intf(vlan_if, zvni);
} else {
- /* Del primary MAC-IP */
+ /* Del primary SVI MAC-IP */
zvni_del_macip_for_intf(vlan_if, zvni);
- zvni->advertise_svi_macip = advertise;
}
}
diff --git a/zebra/zserv.c b/zebra/zserv.c
index c008441d6..b0991e98f 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -240,7 +240,7 @@ static int zserv_write(struct thread *thread)
if (cache->tail) {
msg = cache->tail;
stream_set_getp(msg, 0);
- wcmd = stream_getw_from(msg, 6);
+ wcmd = stream_getw_from(msg, ZAPI_HEADER_CMD_LOCATION);
}
while (stream_fifo_head(cache)) {