diff options
author | Timo Teräs <timo.teras@iki.fi> | 2016-01-15 17:36:29 +0200 |
---|---|---|
committer | Paul Jakma <paul.jakma@hpe.com> | 2016-02-26 14:11:46 +0000 |
commit | 0abf6796c3d8ae8f5ea8624668424bc1554de25e (patch) | |
tree | 2d1713deeb970d79930912588341ff756949b49c /zebra/rt_netlink.c | |
parent | b0d02889624eaafa0984873dcd78c086418bdf13 (diff) | |
download | quagga-0abf6796c3d8ae8f5ea8624668424bc1554de25e.tar.bz2 quagga-0abf6796c3d8ae8f5ea8624668424bc1554de25e.tar.xz |
zebra: atomic FIB updates
This commit updates the kernel API so that route changes are
atomically updated using change/replaces messages instead
of first sending a withdraw followed with update.
Same for zclient updates, changes are sent as single ADD
instead of DELETE + ADD.
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Diffstat (limited to 'zebra/rt_netlink.c')
-rw-r--r-- | zebra/rt_netlink.c | 40 |
1 files changed, 18 insertions, 22 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 614f8099..4625ceab 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1607,8 +1607,7 @@ _netlink_route_debug( /* Routing table change via netlink interface. */ static int -netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, - int family) +netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) { int bytelen; struct sockaddr_nl snl; @@ -1616,6 +1615,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, int recursing; int nexthop_num; int discard; + int family = PREFIX_FAMILY(p); const char *routedesc; struct @@ -1632,7 +1632,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); - req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE | NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.r.rtm_family = family; req.r.rtm_table = rib->table; @@ -1803,30 +1803,26 @@ skip: } int -kernel_add_ipv4 (struct prefix *p, struct rib *rib) +kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new) { - return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET); -} + int ret; -int -kernel_delete_ipv4 (struct prefix *p, struct rib *rib) -{ - return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET); -} + if (!old && new) + return netlink_route_multipath (RTM_NEWROUTE, p, new); + if (old && !new) + return netlink_route_multipath (RTM_DELROUTE, p, old); -#ifdef HAVE_IPV6 -int -kernel_add_ipv6 (struct prefix *p, struct rib *rib) -{ - return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6); -} + /* Replace, can be done atomically if metric does not change; + * netlink uses [prefix, tos, priority] to identify prefix */ + if (old->metric == new->metric) + return netlink_route_multipath (RTM_NEWROUTE, p, new); -int -kernel_delete_ipv6 (struct prefix *p, struct rib *rib) -{ - return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6); + /* Add + delete so the prefix does not disappear temporarily */ + ret = netlink_route_multipath (RTM_NEWROUTE, p, new); + if (netlink_route_multipath (RTM_DELROUTE, p, old) < 0) + ret = -1; + return ret; } -#endif /* HAVE_IPV6 */ /* Interface address modification. */ static int |