diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-02-16 22:59:20 +0100 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-03-01 14:30:55 +0100 |
commit | 2f8685a25525580347e82c2de35d5c26d997f934 (patch) | |
tree | 490f2eac4dcb7db6e4ece5c5d57c2c0616d72557 /zebra/rt_netlink.c | |
parent | zebra: Add multipath parsing to V6 (diff) | |
download | frr-2f8685a25525580347e82c2de35d5c26d997f934.tar.xz frr-2f8685a25525580347e82c2de35d5c26d997f934.zip |
zebra: Allow multiple rib deletes from linux kernel
The kernel can send a DELROUTE with a individual
nexthop. Technically this is meant to delete that
individual nexthop from the route but zebra
has no way to do this currently. So we just delete
the route.
V4 -> Never sends a DELROUTE with multiple nexthops
as a way to modify the rib. It sends a a NEWROUTE
with RTM_REPLACE with the new appropriate route.
V6 -> Sends a DELROUTE with multiple nexthops
which is supposed to be interpreted as a
subtraction from the route.
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
Diffstat (limited to '')
-rw-r--r-- | zebra/rt_netlink.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 0c3d17dbd..450e15e0f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -353,8 +353,41 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h, } } else - rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags, - &p, NULL, gate, index, table); + { + if (!tb[RTA_MULTIPATH]) + rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags, + &p, NULL, gate, index, table); + else + { + struct rtnexthop *rtnh = + (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); + + len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); + + for (;;) + { + if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) + break; + + gate = NULL; + 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 (gate) + rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags, + &p, NULL, gate, index, table); + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + } + } return 0; } |