From 0c555cc6a588c9512dcbefe9275acafcb0b0da27 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 14 Nov 2017 09:57:37 -0500 Subject: [PATCH] zebra: Implement call back for route install/delete success/fail When a route is installed or deleted into the kernel allow a callback mechanism to handle the success/failure of the kernel call. This separation is to allow us to do these things: 1) In the future create a true pthread to handle route install/deletes. This way we can schedule these events in a smarter fashion 2) Allow us to use a common southbound api for route install and deletion. Signed-off-by: Donald Sharp --- zebra/rib.h | 6 +-- zebra/rt.h | 32 +++++++++++++- zebra/rt_netlink.c | 62 ++++++++++++++++++---------- zebra/rt_socket.c | 16 +++++-- zebra/zebra_rib.c | 101 +++++++++++++++++++++++---------------------- 5 files changed, 137 insertions(+), 80 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 61beebb409..818844cb6d 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -285,9 +285,9 @@ extern int zebra_check_addr(struct prefix *p); extern void rib_addnode(struct route_node *rn, struct route_entry *re, int process); extern void rib_delnode(struct route_node *rn, struct route_entry *re); -extern int rib_install_kernel(struct route_node *rn, struct route_entry *re, - struct route_entry *old); -extern int rib_uninstall_kernel(struct route_node *rn, struct route_entry *re); +extern void rib_install_kernel(struct route_node *rn, struct route_entry *re, + struct route_entry *old); +extern void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re); /* NOTE: * All rib_add function will not just add prefix into RIB, but diff --git a/zebra/rt.h b/zebra/rt.h index 3ce15e9640..2581b9012c 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -41,8 +41,36 @@ * success failure should be handled by the caller. */ -extern int kernel_route_rib(struct prefix *, struct prefix *, - struct route_entry *, struct route_entry *); + +enum southbound_results { + SOUTHBOUND_INSTALL_SUCCESS, + SOUTHBOUND_INSTALL_FAILURE, + SOUTHBOUND_DELETE_SUCCESS, + SOUTHBOUND_DELETE_FAILURE, +}; + +/* + * Install/delete the specified prefix p from the kernel + * + * old = NULL, new = pointer - Install new + * old = pointer, new = pointer - Route replace Old w/ New + * old = pointer, new = NULL, - Route Delete + * + * Please note not all kernels support route replace + * semantics so we will end up with a delete than + * a re-add. + */ +extern void kernel_route_rib(struct prefix *p, struct prefix *src_p, + struct route_entry *old, struct route_entry *new); + +/* + * So route install/failure may not be immediately known + * so let's separate it out and allow the result to + * be passed back up. + */ +extern void kernel_route_rib_pass_fail(struct prefix *p, + struct route_entry *re, + enum southbound_results res); extern int kernel_address_add_ipv4(struct interface *, struct connected *); extern int kernel_address_delete_ipv4(struct interface *, struct connected *); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3830e1fbde..8afa47753f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1598,33 +1598,51 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) return suc; } -int kernel_route_rib(struct prefix *p, struct prefix *src_p, - struct route_entry *old, struct route_entry *new) +void kernel_route_rib(struct prefix *p, struct prefix *src_p, + struct route_entry *old, struct route_entry *new) { + int ret = 0; + assert(old || new); - if (!old && new) - return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 0); - if (old && !new) - return netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0); + if (new) { + if (p->family == AF_INET) + ret = netlink_route_multipath(RTM_NEWROUTE, p, src_p, + new, (old) ? 1 : 0); + else { + /* + * So v6 route replace semantics are not in + * the kernel at this point as I understand it. + * So let's do a delete than an add. + * In the future once v6 route replace semantics + * are in we can figure out what to do here to + * allow working with old and new kernels. + * + * I'm also intentionally ignoring the failure case + * of the route delete. If that happens yeah we're + * screwed. + */ + if (old) + netlink_route_multipath(RTM_DELROUTE, p, + src_p, old, 0); + ret = netlink_route_multipath(RTM_NEWROUTE, p, + src_p, new, 0); + } + kernel_route_rib_pass_fail(p, new, + (!ret) ? + SOUTHBOUND_INSTALL_SUCCESS : + SOUTHBOUND_INSTALL_FAILURE); + return; + } - if (p->family == AF_INET) - return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 1); + if (old) { + ret = netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0); - /* - * So v6 route replace semantics are not in the kernel at this - * point as I understand it. - * So let's do a delete than an add. - * In the future once v6 route replace semantics are in - * we can figure out what to do here to allow working - * with old and new kernels. - * - * I'm also intentionally ignoring the failure case - * of the route delete. If that happens yeah we're - * screwed. - */ - netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0); - return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 0); + kernel_route_rib_pass_fail(p, old, + (!ret) ? + SOUTHBOUND_DELETE_SUCCESS : + SOUTHBOUND_DELETE_FAILURE); + } } int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index e588794947..4393c87d45 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -387,8 +387,8 @@ static int kernel_rtm(int cmd, struct prefix *p, struct route_entry *re) return 0; } -int kernel_route_rib(struct prefix *p, struct prefix *src_p, - struct route_entry *old, struct route_entry *new) +void kernel_route_rib(struct prefix *p, struct prefix *src_p, + struct route_entry *old, struct route_entry *new) { int route = 0; @@ -409,7 +409,17 @@ int kernel_route_rib(struct prefix *p, struct prefix *src_p, if (zserv_privs.change(ZPRIVS_LOWER)) zlog_err("Can't lower privileges"); - return route; + if (new) { + kernel_route_rib_pass_fail(p, new, + (!route) ? + SOUTHBOUND_INSTALL_SUCCESS : + SOUTBHOUND_INSTALL_FAILURE); + } else { + kernel_route_rib_pass_fail(p, old, + (!route) ? + SOUTHBOUND_DELETE_SUCCESS : + SOUTHBOUND_DELETE_FAILURE); + } } int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 791f319120..58b6965995 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -993,13 +993,49 @@ int zebra_rib_labeled_unicast(struct route_entry *re) return 1; } +void kernel_route_rib_pass_fail(struct prefix *p, struct route_entry *re, + enum southbound_results res) +{ + struct nexthop *nexthop; + char buf[PREFIX_STRLEN]; + + switch (res) { + case SOUTHBOUND_INSTALL_SUCCESS: + for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + else + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + } + zsend_route_notify_owner(re->type, re->instance, re->vrf_id, + p, ZAPI_ROUTE_INSTALLED); + break; + case SOUTHBOUND_INSTALL_FAILURE: + zsend_route_notify_owner(re->type, re->instance, re->vrf_id, + p, ZAPI_ROUTE_FAIL_INSTALL); + zlog_warn("%u:%s: Route install failed", re->vrf_id, + prefix2str(p, buf, sizeof(buf))); + break; + case SOUTHBOUND_DELETE_SUCCESS: + for (ALL_NEXTHOPS(re->nexthop, nexthop)) + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + break; + case SOUTHBOUND_DELETE_FAILURE: + zlog_warn("%u:%s: Route Deletion failure", re->vrf_id, + prefix2str(p, buf, sizeof(buf))); + break; + } +} + /* Update flag indicates whether this is a "replace" or not. Currently, this * is only used for IPv4. */ -int rib_install_kernel(struct route_node *rn, struct route_entry *re, - struct route_entry *old) +void rib_install_kernel(struct route_node *rn, struct route_entry *re, + struct route_entry *old) { - int ret = 0; struct nexthop *nexthop; rib_table_info_t *info = srcdest_rnode_table_info(rn); struct prefix *p, *src_p; @@ -1010,7 +1046,7 @@ int rib_install_kernel(struct route_node *rn, struct route_entry *re, if (info->safi != SAFI_UNICAST) { for (ALL_NEXTHOPS(re->nexthop, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - return ret; + return; } else { struct nexthop *prev; @@ -1042,33 +1078,15 @@ int rib_install_kernel(struct route_node *rn, struct route_entry *re, * the kernel. */ hook_call(rib_update, rn, "installing in kernel"); - ret = kernel_route_rib(p, src_p, old, re); + kernel_route_rib(p, src_p, old, re); zvrf->installs++; - /* If install succeeds, update FIB flag for nexthops. */ - if (!ret) { - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - else - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - } - zsend_route_notify_owner(re->type, re->instance, re->vrf_id, - p, ZAPI_ROUTE_INSTALLED); - } else - zsend_route_notify_owner(re->type, re->instance, re->vrf_id, - p, ZAPI_ROUTE_FAIL_INSTALL); - - return ret; + return; } /* Uninstall the route from kernel. */ -int rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) +void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) { - int ret = 0; struct nexthop *nexthop; rib_table_info_t *info = srcdest_rnode_table_info(rn); struct prefix *p, *src_p; @@ -1079,7 +1097,7 @@ int rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) if (info->safi != SAFI_UNICAST) { for (ALL_NEXTHOPS(re->nexthop, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - return ret; + return; } /* @@ -1087,13 +1105,10 @@ int rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) * the kernel. */ hook_call(rib_update, rn, "uninstalling from kernel"); - ret = kernel_route_rib(p, src_p, re, NULL); + kernel_route_rib(p, src_p, re, NULL); zvrf->removals++; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - - return ret; + return; } /* Uninstall the route from kernel. */ @@ -1207,14 +1222,8 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (zebra_rib_labeled_unicast(new)) zebra_mpls_lsp_install(zvrf, rn, new); - if (!RIB_SYSTEM_ROUTE(new)) { - if (rib_install_kernel(rn, new, NULL)) { - char buf[SRCDEST2STR_BUFFER]; - srcdest_rnode2str(rn, buf, sizeof(buf)); - zlog_warn("%u:%s: Route install failed", zvrf_id(zvrf), - buf); - } - } + if (!RIB_SYSTEM_ROUTE(new)) + rib_install_kernel(rn, new, NULL); UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); } @@ -1301,13 +1310,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (zebra_rib_labeled_unicast(new)) zebra_mpls_lsp_install(zvrf, rn, new); - if (rib_install_kernel(rn, new, old)) { - char buf[SRCDEST2STR_BUFFER]; - srcdest_rnode2str(rn, buf, sizeof(buf)); - installed = 0; - zlog_warn("%u:%s: Route install failed", - zvrf_id(zvrf), buf); - } + rib_install_kernel(rn, new, old); } /* If install succeeded or system route, cleanup flags @@ -2633,7 +2636,6 @@ static void rib_sweep_table(struct route_table *table) struct route_entry *re; struct route_entry *next; struct nexthop *nexthop; - int ret = 0; if (!table) return; @@ -2670,9 +2672,8 @@ static void rib_sweep_table(struct route_table *table) for (ALL_NEXTHOPS(re->nexthop, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - ret = rib_uninstall_kernel(rn, re); - if (!ret) - rib_delnode(rn, re); + rib_uninstall_kernel(rn, re); + rib_delnode(rn, re); } } } -- 2.39.5