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 <sharpd@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2017-11-14 09:57:37 -05:00
parent 69df82f3b5
commit 0c555cc6a5
5 changed files with 137 additions and 80 deletions

View File

@ -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

View File

@ -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 *);

View File

@ -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,

View File

@ -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,

View File

@ -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);
}
}
}