summaryrefslogtreecommitdiffstats
path: root/zebra/rt_netlink.c
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2017-02-16 22:59:20 +0100
committerDonald Sharp <sharpd@cumulusnetworks.com>2017-03-01 14:30:55 +0100
commit2f8685a25525580347e82c2de35d5c26d997f934 (patch)
tree490f2eac4dcb7db6e4ece5c5d57c2c0616d72557 /zebra/rt_netlink.c
parentzebra: Add multipath parsing to V6 (diff)
downloadfrr-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.c37
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;
}