* 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 *);
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,
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;
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;
* 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;
if (info->safi != SAFI_UNICAST) {
for (ALL_NEXTHOPS(re->nexthop, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- return ret;
+ return;
}
/*
* 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. */
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);
}
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
struct route_entry *re;
struct route_entry *next;
struct nexthop *nexthop;
- int ret = 0;
if (!table)
return;
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);
}
}
}