diff options
-rw-r--r-- | zebra/rt.h | 3 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 9 | ||||
-rw-r--r-- | zebra/rt_socket.c | 54 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 171 |
4 files changed, 115 insertions, 122 deletions
diff --git a/zebra/rt.h b/zebra/rt.h index bc91edd80..2c77af2aa 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -35,6 +35,9 @@ extern "C" { #endif +#define RSYSTEM_ROUTE(type) \ + ((type) == ZEBRA_ROUTE_KERNEL || (type) == ZEBRA_ROUTE_CONNECT) + /* * Update or delete a route, LSP, or pseudowire from the kernel, * using info from a dataplane context. diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index cf61eb6cb..289ed5a15 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1836,7 +1836,9 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) * of the route delete. If that happens yeah we're * screwed. */ - (void)netlink_route_multipath(RTM_DELROUTE, ctx); + if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) + (void)netlink_route_multipath(RTM_DELROUTE, + ctx); cmd = RTM_NEWROUTE; } @@ -1844,7 +1846,10 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) return ZEBRA_DPLANE_REQUEST_FAILURE; } - ret = netlink_route_multipath(cmd, ctx); + if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) + ret = netlink_route_multipath(cmd, ctx); + else + ret = 0; if ((cmd == RTM_NEWROUTE) && (ret == 0)) { /* Update installed nexthops to signal which have been * installed. diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index f25259f30..8d8bdd0a6 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -304,33 +304,41 @@ static int kernel_rtm(int cmd, const struct prefix *p, enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) { enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS; + uint32_t type, old_type; if (dplane_ctx_get_src(ctx) != NULL) { zlog_err("route add: IPv6 sourcedest routes unsupported!"); return ZEBRA_DPLANE_REQUEST_FAILURE; } + type = dplane_ctx_get_type(ctx); + old_type = dplane_ctx_get_old_type(ctx); + frr_elevate_privs(&zserv_privs) { - if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) - kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), - dplane_ctx_get_ng(ctx), - dplane_ctx_get_metric(ctx)); - else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) - kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), - dplane_ctx_get_ng(ctx), - dplane_ctx_get_metric(ctx)); - else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { + if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) { + if (!RSYSTEM_ROUTE(type)) + kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), + dplane_ctx_get_ng(ctx), + dplane_ctx_get_metric(ctx)); + } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) { + if (!RSYSTEM_ROUTE(type)) + kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), + dplane_ctx_get_ng(ctx), + dplane_ctx_get_metric(ctx)); + } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { /* Must do delete and add separately - * no update available */ - kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), - dplane_ctx_get_old_ng(ctx), - dplane_ctx_get_old_metric(ctx)); - - kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), - dplane_ctx_get_ng(ctx), - dplane_ctx_get_metric(ctx)); + if (!RSYSTEM_ROUTE(old_type)) + kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), + dplane_ctx_get_old_ng(ctx), + dplane_ctx_get_old_metric(ctx)); + + if (!RSYSTEM_ROUTE(type)) + kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), + dplane_ctx_get_ng(ctx), + dplane_ctx_get_metric(ctx)); } else { zlog_err("Invalid routing socket update op %s (%u)", dplane_op2str(dplane_ctx_get_op(ctx)), @@ -339,6 +347,20 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) } } /* Elevated privs */ + if (RSYSTEM_ROUTE(type) + && dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE) { + struct nexthop *nexthop; + + for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), 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); + } + } + } + return res; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index aaf9c4027..ad0733115 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1175,10 +1175,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) if (zebra_rib_labeled_unicast(re)) zebra_mpls_lsp_uninstall(info->zvrf, rn, re); - if (!RIB_SYSTEM_ROUTE(re)) - rib_uninstall_kernel(rn, re); - else - UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + rib_uninstall_kernel(rn, re); dest->selected_fib = NULL; @@ -1258,8 +1255,6 @@ int rib_gc_dest(struct route_node *rn) static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *new) { - rib_dest_t *dest = rib_dest_from_rnode(rn); - hook_call(rib_update, rn, "new route selected"); /* Update real nexthop. This may actually determine if nexthop is active @@ -1281,10 +1276,7 @@ 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)) - rib_install_kernel(rn, new, NULL); - else - dest->selected_fib = new; + rib_install_kernel(rn, new, NULL); UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); } @@ -1292,7 +1284,6 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *old) { - rib_dest_t *dest = rib_dest_from_rnode(rn); hook_call(rib_update, rn, "removing existing route"); /* Uninstall from kernel. */ @@ -1308,20 +1299,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (zebra_rib_labeled_unicast(old)) zebra_mpls_lsp_uninstall(zvrf, rn, old); - if (!RIB_SYSTEM_ROUTE(old)) - rib_uninstall_kernel(rn, old); - else { - UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED); - /* - * We are setting this to NULL here - * because that is what we traditionally - * have been doing. I am not positive - * that this is the right thing to do - * but let's leave the code alone - * for the RIB_SYSTEM_ROUTE case - */ - dest->selected_fib = NULL; - } + rib_uninstall_kernel(rn, old); /* Update nexthop for route, reset changed flag. */ /* Note: this code also handles the Linux case when an interface goes @@ -1340,9 +1318,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, struct route_entry *old, struct route_entry *new) { - struct nexthop *nexthop = NULL; int nh_active = 0; - rib_dest_t *dest = rib_dest_from_rnode(rn); /* * We have to install or update if a new route has been selected or @@ -1384,48 +1360,15 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (zebra_rib_labeled_unicast(old)) zebra_mpls_lsp_uninstall(zvrf, rn, old); - /* Non-system route should be installed. */ - if (!RIB_SYSTEM_ROUTE(new)) { - /* If labeled-unicast route, install transit - * LSP. */ - if (zebra_rib_labeled_unicast(new)) - zebra_mpls_lsp_install(zvrf, rn, new); + /* + * Non-system route should be installed. + * If labeled-unicast route, install transit + * LSP. + */ + if (zebra_rib_labeled_unicast(new)) + zebra_mpls_lsp_install(zvrf, rn, new); - rib_install_kernel(rn, new, old); - } else { - UNSET_FLAG(new->status, ROUTE_ENTRY_INSTALLED); - /* - * We do not need to install the - * selected route because it - * is already isntalled by - * the system( ie not us ) - * so just mark it as winning - * we do need to ensure that - * if we uninstall a route - * from ourselves we don't - * over write this pointer - */ - dest->selected_fib = new; - } - /* If install succeeded or system route, cleanup flags - * for prior route. */ - if (new != old) { - if (RIB_SYSTEM_ROUTE(new)) { - if (!RIB_SYSTEM_ROUTE(old)) - rib_uninstall_kernel(rn, old); - else - UNSET_FLAG( - old->status, - ROUTE_ENTRY_INSTALLED); - } else { - UNSET_FLAG(old->status, - ROUTE_ENTRY_INSTALLED); - for (nexthop = old->ng.nexthop; nexthop; - nexthop = nexthop->next) - UNSET_FLAG(nexthop->flags, - NEXTHOP_FLAG_FIB); - } - } + rib_install_kernel(rn, new, old); } /* @@ -1455,25 +1398,18 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (zebra_rib_labeled_unicast(old)) zebra_mpls_lsp_uninstall(zvrf, rn, old); - if (!RIB_SYSTEM_ROUTE(old)) - rib_uninstall_kernel(rn, old); - else { - UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED); - dest->selected_fib = NULL; - } + rib_uninstall_kernel(rn, old); } } else { /* * Same route selected; check if in the FIB and if not, - * re-install. This - * is housekeeping code to deal with race conditions in kernel - * with linux - * netlink reporting interface up before IPv4 or IPv6 protocol - * is ready + * re-install. This is housekeeping code to deal with + * race conditions in kernel with linux netlink reporting + * interface up before IPv4 or IPv6 protocol is ready * to add routes. */ - if (!RIB_SYSTEM_ROUTE(new) - && !CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED)) + if (!CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED) || + RIB_SYSTEM_ROUTE(new)) rib_install_kernel(rn, new, NULL); } @@ -1725,18 +1661,9 @@ static void rib_process(struct route_node *rn) UNSET_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED); } - if (new_selected) { + if (new_selected) SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED); - /* Special case: new route is system route, so - * dataplane update will not be done - ensure we - * redistribute the route. - */ - if (RIB_SYSTEM_ROUTE(new_selected)) - redistribute_update(p, src_p, new_selected, - old_selected); - } - if (old_selected) { if (!new_selected) redistribute_delete(p, src_p, old_selected); @@ -1821,6 +1748,30 @@ done: return (result); } +static void zebra_rib_fixup_system(struct route_node *rn) +{ + struct route_entry *re; + + RNODE_FOREACH_RE(rn, re) { + struct nexthop *nhop; + + if (!RIB_SYSTEM_ROUTE(re)) + continue; + + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) + continue; + + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + + for (ALL_NEXTHOPS(re->ng, nhop)) { + if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + + SET_FLAG(nhop->flags, NEXTHOP_FLAG_FIB); + } + } +} + /* * Route-update results processing after async dataplane update. */ @@ -1987,6 +1938,17 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) NEXTHOP_FLAG_FIB); } + /* + * System routes are weird in that they + * allow multiple to be installed that match + * to the same prefix, so after we get the + * result we need to clean them up so that + * we can actually use them. + */ + if ((re && RIB_SYSTEM_ROUTE(re)) || + (old_re && RIB_SYSTEM_ROUTE(old_re))) + zebra_rib_fixup_system(rn); + if (zvrf) { zvrf->installs++; /* Set flag for nexthop tracking processing */ @@ -2053,6 +2015,17 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) prefix2str(dest_pfx, dest_str, sizeof(dest_str))); } + + /* + * System routes are weird in that they + * allow multiple to be installed that match + * to the same prefix, so after we get the + * result we need to clean them up so that + * we can actually use them. + */ + if ((re && RIB_SYSTEM_ROUTE(re)) || + (old_re && RIB_SYSTEM_ROUTE(old_re))) + zebra_rib_fixup_system(rn); break; default: break; @@ -2655,7 +2628,7 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id) * revalidation * of the rest of the RE. */ - if (dest->selected_fib && !RIB_SYSTEM_ROUTE(dest->selected_fib)) { + if (dest->selected_fib) { changed = 1; if (IS_ZEBRA_DEBUG_RIB) { char buf[PREFIX_STRLEN]; @@ -2677,7 +2650,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct route_table *table; struct route_node *rn; struct route_entry *same = NULL; - struct nexthop *nexthop; int ret = 0; if (!re) @@ -2741,13 +2713,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, break; } - /* If this route is kernel route, set FIB flag to the route. */ - if (RIB_SYSTEM_ROUTE(re)) { - SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - } - /* Link new re to node.*/ if (IS_ZEBRA_DEBUG_RIB) { rnode_debug(rn, re->vrf_id, @@ -3223,10 +3188,8 @@ void rib_close_table(struct route_table *table) if (info->safi == SAFI_UNICAST) hook_call(rib_update, rn, NULL); - if (!RIB_SYSTEM_ROUTE(dest->selected_fib)) { - rib_uninstall_kernel(rn, dest->selected_fib); - dest->selected_fib = NULL; - } + rib_uninstall_kernel(rn, dest->selected_fib); + dest->selected_fib = NULL; } } } |