From e2b180cc902ee92a464c997f0ab6663ac3986266 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Dec 2023 08:24:01 -0500 Subject: [PATCH 1/3] zebra: Add ability to note that a address is NOPREFIXROUTE The linux kernel can send up a flag that tells us that the connected address is not a PREFIXROUTE. Add the ability to note this and pass it up from the data plane. Signed-off-by: Donald Sharp (cherry picked from commit 466ad88ce12af8d613600717def6a17dc6283ee8) --- zebra/if_netlink.c | 3 +++ zebra/zebra_dplane.c | 15 +++++++++++++++ zebra/zebra_dplane.h | 2 ++ 3 files changed, 20 insertions(+) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index ed2e0a224e05..bd684453cd30 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1474,6 +1474,9 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, if (kernel_flags & IFA_F_SECONDARY) dplane_ctx_intf_set_secondary(ctx); + if (kernel_flags & IFA_F_NOPREFIXROUTE) + dplane_ctx_intf_set_noprefixroute(ctx); + /* Label */ if (tb[IFA_LABEL]) { label = (char *)RTA_DATA(tb[IFA_LABEL]); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 0b406311c90a..f3441f5f2783 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -230,6 +230,7 @@ struct dplane_intf_info { #define DPLANE_INTF_BROADCAST (1 << 2) #define DPLANE_INTF_HAS_DEST DPLANE_INTF_CONNECTED #define DPLANE_INTF_HAS_LABEL (1 << 4) +#define DPLANE_INTF_NOPREFIXROUTE (1 << 5) /* Interface address/prefix */ struct prefix prefix; @@ -2541,6 +2542,13 @@ bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx) return (ctx->u.intf.flags & DPLANE_INTF_CONNECTED); } +bool dplane_ctx_intf_is_noprefixroute(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return (ctx->u.intf.flags & DPLANE_INTF_NOPREFIXROUTE); +} + bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2569,6 +2577,13 @@ void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx) ctx->u.intf.flags |= DPLANE_INTF_SECONDARY; } +void dplane_ctx_intf_set_noprefixroute(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.flags |= DPLANE_INTF_NOPREFIXROUTE; +} + void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 87c2e0365677..6dc52ead143e 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -658,6 +658,8 @@ bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx); void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx); void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx); +bool dplane_ctx_intf_is_noprefixroute(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_intf_set_noprefixroute(struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx); void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx); const struct prefix *dplane_ctx_get_intf_addr( From b311787366bae730b58d416251eed45c608df8a3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Dec 2023 08:33:31 -0500 Subject: [PATCH 2/3] zebra: Add connected with noprefixroute Add ability for the connected routes to know if they are a prefix route or not. sharpd@eva:/work/home/sharpd/frr1$ ip addr show dev dummy1 13: dummy1: mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000 link/ether aa:93:ce:ce:3f:62 brd ff:ff:ff:ff:ff:ff inet 192.168.55.1/24 scope global noprefixroute dummy1 valid_lft forever preferred_lft forever inet 192.168.56.1/24 scope global dummy1 valid_lft forever preferred_lft forever inet6 fe80::a893:ceff:fece:3f62/64 scope link valid_lft forever preferred_lft forever sharpd@eva:/work/home/sharpd/frr1$ sudo vtysh -c "show int dummy1" Interface dummy1 is up, line protocol is up Link ups: 0 last: (never) Link downs: 0 last: (never) vrf: default index 13 metric 0 mtu 1500 speed 0 txqlen 1000 flags: Type: Ethernet HWaddr: aa:93:ce:ce:3f:62 inet 192.168.55.1/24 noprefixroute inet 192.168.56.1/24 inet6 fe80::a893:ceff:fece:3f62/64 Interface Type Other Interface Slave Type None protodown: off sharpd@eva:/work/home/sharpd/frr1$ sudo vtysh -c "show ip route" Codes: K - kernel route, C - connected, L - local, S - static, R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, f - OpenFabric, t - Table-Direct, > - selected route, * - FIB route, q - queued, r - rejected, b - backup t - trapped, o - offload failure K>* 0.0.0.0/0 [0/100] via 192.168.119.1, enp13s0, 00:00:08 K>* 169.254.0.0/16 [0/1000] is directly connected, virbr2 linkdown, 00:00:08 L>* 192.168.44.1/32 is directly connected, dummy2, 00:00:08 L>* 192.168.55.1/32 is directly connected, dummy1, 00:00:08 C>* 192.168.56.0/24 is directly connected, dummy1, 00:00:08 L>* 192.168.56.1/32 is directly connected, dummy1, 00:00:08 L>* 192.168.119.205/32 is directly connected, enp13s0, 00:00:08 sharpd@eva:/work/home/sharpd/frr1$ ip route show default via 192.168.119.1 dev enp13s0 proto dhcp metric 100 169.254.0.0/16 dev virbr2 scope link metric 1000 linkdown 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 192.168.45.0/24 dev virbr2 proto kernel scope link src 192.168.45.1 linkdown 192.168.56.0/24 dev dummy1 proto kernel scope link src 192.168.56.1 192.168.119.0/24 dev enp13s0 proto kernel scope link src 192.168.119.205 metric 100 192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown sharpd@eva:/work/home/sharpd/frr1$ ip route show table 255 local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1 local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1 local 172.17.0.1 dev docker0 proto kernel scope host src 172.17.0.1 broadcast 172.17.255.255 dev docker0 proto kernel scope link src 172.17.0.1 linkdown local 192.168.44.1 dev dummy2 proto kernel scope host src 192.168.44.1 broadcast 192.168.44.255 dev dummy2 proto kernel scope link src 192.168.44.1 local 192.168.45.1 dev virbr2 proto kernel scope host src 192.168.45.1 broadcast 192.168.45.255 dev virbr2 proto kernel scope link src 192.168.45.1 linkdown local 192.168.55.1 dev dummy1 proto kernel scope host src 192.168.55.1 broadcast 192.168.55.255 dev dummy1 proto kernel scope link src 192.168.55.1 local 192.168.56.1 dev dummy1 proto kernel scope host src 192.168.56.1 broadcast 192.168.56.255 dev dummy1 proto kernel scope link src 192.168.56.1 local 192.168.119.205 dev enp13s0 proto kernel scope host src 192.168.119.205 broadcast 192.168.119.255 dev enp13s0 proto kernel scope link src 192.168.119.205 local 192.168.122.1 dev virbr0 proto kernel scope host src 192.168.122.1 broadcast 192.168.122.255 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown Fixes: #14952 Signed-off-by: Donald Sharp (cherry picked from commit 8a574840a4e29d2529fb03cdeeb6a09a11b0bdf5) --- lib/if.h | 2 ++ zebra/connected.c | 30 ++++++++++++++++++------------ zebra/interface.c | 9 +++++++++ 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/lib/if.h b/lib/if.h index 7b4415da45d4..66d1f30d9353 100644 --- a/lib/if.h +++ b/lib/if.h @@ -420,6 +420,8 @@ struct connected { #define ZEBRA_IFA_SECONDARY (1 << 0) #define ZEBRA_IFA_PEER (1 << 1) #define ZEBRA_IFA_UNNUMBERED (1 << 2) +#define ZEBRA_IFA_NOPREFIXROUTE (1 << 3) + /* N.B. the ZEBRA_IFA_PEER flag should be set if and only if a peer address has been configured. If this flag is set, the destination field must contain the peer address. diff --git a/zebra/connected.c b/zebra/connected.c index ee0823f56f45..2977aebfbcd7 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -276,13 +276,15 @@ void connected_up(struct interface *ifp, struct connected *ifc) return; } - rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, - false); - - rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, - false); + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, + zvrf->table_id, metric, 0, 0, 0, false); + + rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, + zvrf->table_id, metric, 0, 0, 0, false); + } /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { @@ -457,11 +459,15 @@ 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, 0, zvrf->table_id, 0, 0, false); - - rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + 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, 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/interface.c b/zebra/interface.c index 1afd9d5a7d8a..9864b825ee88 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1331,6 +1331,9 @@ static void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, if (dplane_ctx_intf_is_secondary(ctx)) SET_FLAG(flags, ZEBRA_IFA_SECONDARY); + if (dplane_ctx_intf_is_noprefixroute(ctx)) + SET_FLAG(flags, ZEBRA_IFA_NOPREFIXROUTE); + /* Label? */ if (dplane_ctx_intf_has_label(ctx)) label = dplane_ctx_get_intf_label(ctx); @@ -2407,6 +2410,12 @@ static void connected_dump_vty(struct vty *vty, json_object *json, else if (CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY)) vty_out(vty, " secondary"); + if (json) + json_object_boolean_add(json_addr, "noPrefixRoute", + CHECK_FLAG(connected->flags, ZEBRA_IFA_NOPREFIXROUTE)); + else if (CHECK_FLAG(connected->flags, ZEBRA_IFA_NOPREFIXROUTE)) + vty_out(vty, " noprefixroute"); + if (json) json_object_boolean_add( json_addr, "unnumbered", From d5214b1182e9c9f4da2ad1fd6c505154fc1cbf06 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Dec 2023 09:27:09 -0500 Subject: [PATCH 3/3] tests: Add a noprefixroute test Add a simple test case to ensure that the noprefixroute code stays working in the future. Signed-off-by: Donald Sharp (cherry picked from commit 0d5c5472c96c91516ae99c87c7a711237f6b45b2) --- .../test_zebra_multiple_connected.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py index 529520cd9e81..0b2937c12a28 100644 --- a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py +++ b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py @@ -144,6 +144,23 @@ def test_zebra_system_recursion(): assert result is None, "Kernel route is missing from zebra" +def test_zebra_noprefix_connected(): + "Test that a noprefixroute created does not create a connected route" + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r1"] + router.run("ip addr add 192.168.44.1/24 dev r1-eth1 noprefixroute") + expected = "% Network not in table" + test_func = partial( + topotest.router_output_cmp, router, "show ip route 192.168.44.0/24", expected + ) + result, diff = topotest.run_and_expect(test_func, "", count=20, wait=1) + assert result, "Connected Route should not have been added" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args))