From dccc522572a41a2121f006f1fd9fa7c16493197d Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 19 Nov 2015 12:22:55 -0800 Subject: [PATCH] Zebra: Implement route replace for IPv6 Zebra currently performs a delete followed by add when a route needs to be modified. Change this to use the replace semantics of netlink so that the operation can possibly be atomic. Note: This patch handles IPv6 routes, IPv4 already performs a replace. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Dinesh Dutt Ticket: CM-5597 Reviewed By: CCR-3407 Testing Done: Manual testing of various scearnios (Vivek, Satish) Note: This is an import of patch zebra-ipv6-route-replace.patch from 2.5-br. --- zebra/kernel_null.c | 1 + zebra/rt.h | 1 + zebra/rt_ioctl.c | 7 +++ zebra/rt_netlink.c | 6 +++ zebra/rt_socket.c | 7 +++ zebra/zebra_rib.c | 115 +++++++++++++++++--------------------------- 6 files changed, 65 insertions(+), 72 deletions(-) diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index 08fef9b309..64d854a069 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -19,6 +19,7 @@ int kernel_delete_ipv4 (struct prefix *a, struct rib *b) { return 0; } #endif int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; } +int kernel_update_ipv6 (struct prefix *a, struct rib *b) { return 0; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak kernel_delete_ipv6 = kernel_add_ipv6 #else diff --git a/zebra/rt.h b/zebra/rt.h index 6d98f57ca3..8e31bb6c56 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -36,6 +36,7 @@ extern int kernel_address_delete_ipv4 (struct interface *, struct connected *); #ifdef HAVE_IPV6 extern int kernel_add_ipv6 (struct prefix *, struct rib *); +extern int kernel_update_ipv6 (struct prefix *, struct rib *); extern int kernel_delete_ipv6 (struct prefix *, struct rib *); extern int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, unsigned int index, int flags, int table); diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c index 34e2a60feb..5a386e97c9 100644 --- a/zebra/rt_ioctl.c +++ b/zebra/rt_ioctl.c @@ -519,6 +519,13 @@ kernel_add_ipv6 (struct prefix *p, struct rib *rib) return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6); } +int +kernel_update_ipv6 (struct prefix *p, struct rib *rib) +{ + kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6); + return kernel_ioctl_ipv6_multipath(SIOCADDRT, p, rib, AF_INET6); +} + int kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a4da7f079d..183dc6e057 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2112,6 +2112,12 @@ kernel_add_ipv6 (struct prefix *p, struct rib *rib) } } +int +kernel_update_ipv6 (struct prefix *p, struct rib *rib) +{ + return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6, 1); +} + int kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index c366775105..9af2d61dbb 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -473,6 +473,13 @@ kernel_add_ipv6 (struct prefix *p, struct rib *rib) return route; } +int +kernel_update_ipv6 (struct prefix *p, struct rib *rib) +{ + kernel_delete_ipv6 (p, rib); + return kernel_add_ipv6 (p, rib); +} + int kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index a9ea4f2d1d..9eb28483c6 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1292,7 +1292,10 @@ rib_install_kernel (struct route_node *rn, struct rib *rib, int update) ret = kernel_add_ipv4 (&rn->p, rib); break; case AF_INET6: - ret = kernel_add_ipv6 (&rn->p, rib); + if (update) + ret = kernel_update_ipv6 (&rn->p, rib); + else + ret = kernel_add_ipv6 (&rn->p, rib); break; } @@ -1427,7 +1430,6 @@ rib_process (struct route_node *rn) struct nexthop *nexthop = NULL, *tnexthop; int recursing; char buf[INET6_ADDRSTRLEN]; - int update_ok = 0; assert (rn); @@ -1560,30 +1562,21 @@ rib_process (struct route_node *rn) { zfpm_trigger_update (rn, "updating existing route"); - if (! RIB_SYSTEM_ROUTE (select)) - { - /* For v4, use the replace semantics of netlink. */ - if (PREFIX_FAMILY (&rn->p) == AF_INET) - update_ok = 1; - else - rib_uninstall_kernel (rn, select); - } - - /* Set real nexthop. */ /* Need to check if any NHs are active to clear the * the selected flag */ if (nexthop_active_update (rn, select, 1)) { - /* Clear FIB flag for IPv4, install will set it */ - if (update_ok) + if (! RIB_SYSTEM_ROUTE (select)) { + /* Clear FIB flag if performing a replace, will get set again + * as part of install. + */ for (nexthop = select->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + rib_install_kernel (rn, select, 1); } - if (! RIB_SYSTEM_ROUTE (select)) - rib_install_kernel (rn, select, update_ok); /* assuming that the receiver knows how to dedup */ redistribute_update (&rn->p, select, NULL); @@ -1593,8 +1586,8 @@ rib_process (struct route_node *rn) /* Withdraw unreachable redistribute route */ redistribute_delete(&rn->p, select); - /* For IPv4, do the uninstall here. */ - if (update_ok) + /* Do the uninstall here, if not done earlier. */ + if (! RIB_SYSTEM_ROUTE (select)) rib_uninstall_kernel (rn, select); UNSET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); } @@ -1633,25 +1626,16 @@ rib_process (struct route_node *rn) zfpm_trigger_update (rn, "removing existing route"); - /* If there's no route to replace this with, withdraw redistribute */ + /* If there's no route to replace this with, withdraw redistribute and + * uninstall from kernel. + */ if (!select) - redistribute_delete(&rn->p, fib); - - if (! RIB_SYSTEM_ROUTE (fib)) { - /* For v4, use the replace semantics of netlink -- only if there is - * another route to replace this with. - */ - if (PREFIX_FAMILY (&rn->p) == AF_INET) - { - if (!select) - rib_uninstall_kernel (rn, fib); - else - update_ok = 1; - } - else - rib_uninstall_kernel (rn, fib); + redistribute_delete(&rn->p, fib); + if (! RIB_SYSTEM_ROUTE (fib)) + rib_uninstall_kernel (rn, fib); } + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); /* Set real nexthop. */ @@ -1674,15 +1658,19 @@ rib_process (struct route_node *rn) /* Set real nexthop. */ if (nexthop_active_update (rn, select, 1)) { - /* Clear FIB flag for IPv4 for previous installed route. */ - if (update_ok) + if (! RIB_SYSTEM_ROUTE (select)) { - assert (fib); - for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + /* Clear FIB flag if performing a replace, will get set again + * as part of install. + */ + if (fib) + { + for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } + rib_install_kernel (rn, select, fib? 1 : 0); } - if (! RIB_SYSTEM_ROUTE (select)) - rib_install_kernel (rn, select, update_ok); + SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); /* Unconditionally announce, this part is exercised by new routes */ /* If we cannot add, for example route added is learnt by the */ @@ -1692,12 +1680,9 @@ rib_process (struct route_node *rn) } else { - /* For IPv4, uninstall prior route here, if any. */ - if (update_ok) - { - assert (fib); - rib_uninstall_kernel (rn, fib); - } + /* Uninstall prior route here, if needed. */ + if (fib && !RIB_SYSTEM_ROUTE (fib)) + rib_uninstall_kernel (rn, fib); /* if "select", the earlier redist delete wouldn't have happened */ if (fib) redistribute_delete(&rn->p, fib); @@ -2864,31 +2849,17 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { - if (afi == AFI_IP) - { - /* If there are other active nexthops, do an update. */ - if (rib->nexthop_active_num > 1) - { - rib_install_kernel (rn, rib, 1); - redistribute_update (&rn->p, rib, NULL); - } - else - { - redistribute_delete (&rn->p, rib); - rib_uninstall_kernel (rn, rib); - } - } - else - { - redistribute_delete (&rn->p, rib); - rib_uninstall_kernel (rn, rib); - /* Are there other active nexthops? */ - if (rib->nexthop_active_num > 1) - { - rib_install_kernel (rn, rib, 0); - redistribute_update (&rn->p, rib, NULL); - } - } + /* If there are other active nexthops, do an update. */ + if (rib->nexthop_active_num > 1) + { + rib_install_kernel (rn, rib, 1); + redistribute_update (&rn->p, rib, NULL); + } + else + { + redistribute_delete (&rn->p, rib); + rib_uninstall_kernel (rn, rib); + } } if (afi == AFI_IP) -- 2.39.5