diff options
Diffstat (limited to 'zebra/zebra_rib.c')
| -rw-r--r-- | zebra/zebra_rib.c | 1369 |
1 files changed, 853 insertions, 516 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d0babbb9e4..fceaaaa9f0 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -76,52 +76,70 @@ static struct dplane_ctx_q rib_dplane_q; DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason), (rn, reason)); +DEFINE_HOOK(rib_shutdown, (struct route_node * rn), (rn)); + + +/* Meta Q's specific names */ +enum meta_queue_indexes { + META_QUEUE_NHG, + META_QUEUE_EVPN, + META_QUEUE_EARLY_ROUTE, + META_QUEUE_EARLY_LABEL, + META_QUEUE_CONNECTED, + META_QUEUE_KERNEL, + META_QUEUE_STATIC, + META_QUEUE_NOTBGP, + META_QUEUE_BGP, + META_QUEUE_OTHER, +}; /* Each route type's string and default distance value. */ static const struct { int key; uint8_t distance; - uint8_t meta_q_map; + enum meta_queue_indexes meta_q_map; } route_info[ZEBRA_ROUTE_MAX] = { - [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Unneeded for nhg's */, 0}, - [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 7}, - [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 3}, - [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 2}, - [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 4}, - [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 5}, - [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 5}, - [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 5}, - [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 5}, - [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 5}, - [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 6}, - [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 7}, - [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 5}, - [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 5}, - [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 7}, - [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 7}, - [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 4}, - [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 7}, - [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 6}, - [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 6}, - [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 6}, - [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 6}, - [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 6}, - [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 5}, - [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 7}, - [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 7}, - [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 7}, - [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 5}, - [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 7}, - [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, 7}, - [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, 255, 7}, + [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Unneeded for nhg's */, + META_QUEUE_NHG}, + [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, META_QUEUE_KERNEL}, + [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, META_QUEUE_KERNEL}, + [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, META_QUEUE_CONNECTED}, + [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, META_QUEUE_STATIC}, + [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, META_QUEUE_NOTBGP}, + [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, META_QUEUE_NOTBGP}, + [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, META_QUEUE_NOTBGP}, + [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, META_QUEUE_NOTBGP}, + [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, META_QUEUE_NOTBGP}, + [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, + META_QUEUE_BGP}, + [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, META_QUEUE_OTHER}, + [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, META_QUEUE_NOTBGP}, + [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, META_QUEUE_NOTBGP}, + [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, META_QUEUE_OTHER}, + [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, META_QUEUE_OTHER}, + [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, META_QUEUE_STATIC}, + [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, META_QUEUE_OTHER}, + [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, META_QUEUE_BGP}, + [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, META_QUEUE_BGP}, + [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, + META_QUEUE_BGP}, + [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, META_QUEUE_BGP}, + [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, + META_QUEUE_BGP}, + [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, META_QUEUE_NOTBGP}, + [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, META_QUEUE_OTHER}, + [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, META_QUEUE_OTHER}, + [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, META_QUEUE_OTHER}, + [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, + META_QUEUE_NOTBGP}, + [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, META_QUEUE_OTHER}, + [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, META_QUEUE_OTHER}, + [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, 255, META_QUEUE_OTHER}, /* Any new route type added to zebra, should be mirrored here */ /* no entry/default: 150 */ }; -/* EVPN/VXLAN subqueue is number 1 */ -#define META_QUEUE_EVPN 1 - /* Wrapper struct for nhg workqueue items; a 'ctx' is an incoming update * from the OS, and an 'nhe' is a nhe update. */ @@ -159,29 +177,56 @@ struct wq_evpn_wrapper { #define WQ_EVPN_WRAPPER_TYPE_REM_MACIP 0x03 #define WQ_EVPN_WRAPPER_TYPE_REM_VTEP 0x04 +enum wq_label_types { + WQ_LABEL_FTN_UNINSTALL, + WQ_LABEL_LABELS_PROCESS, +}; + +struct wq_label_wrapper { + enum wq_label_types type; + vrf_id_t vrf_id; + + struct prefix p; + enum lsp_types_t ltype; + uint8_t route_type; + uint8_t route_instance; + + bool add_p; + struct zapi_labels zl; + + int afi; +}; + +static void rib_addnode(struct route_node *rn, struct route_entry *re, + int process); + /* %pRN is already a printer for route_nodes that just prints the prefix */ #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pZN" (struct route_node *) #endif -static const char *subqueue2str(uint8_t index) +static const char *subqueue2str(enum meta_queue_indexes index) { switch (index) { - case 0: + case META_QUEUE_NHG: return "NHG Objects"; - case 1: + case META_QUEUE_EVPN: return "EVPN/VxLan Objects"; - case 2: + case META_QUEUE_EARLY_ROUTE: + return "Early Route Processing"; + case META_QUEUE_EARLY_LABEL: + return "Early Label Handling"; + case META_QUEUE_CONNECTED: return "Connected Routes"; - case 3: + case META_QUEUE_KERNEL: return "Kernel Routes"; - case 4: + case META_QUEUE_STATIC: return "Static Routes"; - case 5: + case META_QUEUE_NOTBGP: return "RIP/OSPF/ISIS/EIGRP/NHRP Routes"; - case 6: + case META_QUEUE_BGP: return "BGP Routes"; - case 7: + case META_QUEUE_OTHER: return "Other Routes"; } @@ -901,6 +946,9 @@ void zebra_rtable_node_cleanup(struct route_table *table, if (node->info) { rib_dest_t *dest = node->info; + /* Remove from update queue of FPM module */ + hook_call(rib_shutdown, node); + rnh_list_fini(&dest->nht); XFREE(MTYPE_RIB_DEST, node->info); } @@ -2407,7 +2455,7 @@ static void process_subq_nhg(struct listnode *lnode) struct nhg_ctx *ctx; struct nhg_hash_entry *nhe, *newnhe; struct wq_nhg_wrapper *w; - uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; + uint8_t qindex = META_QUEUE_NHG; w = listgetdata(lnode); @@ -2454,6 +2502,33 @@ static void process_subq_nhg(struct listnode *lnode) XFREE(MTYPE_WQ_WRAPPER, w); } +static void process_subq_early_label(struct listnode *lnode) +{ + struct wq_label_wrapper *w = listgetdata(lnode); + struct zebra_vrf *zvrf; + + if (!w) + return; + + zvrf = vrf_info_lookup(w->vrf_id); + if (!zvrf) { + XFREE(MTYPE_WQ_WRAPPER, w); + return; + } + + switch (w->type) { + case WQ_LABEL_FTN_UNINSTALL: + zebra_mpls_ftn_uninstall(zvrf, w->ltype, &w->p, w->route_type, + w->route_instance); + break; + case WQ_LABEL_LABELS_PROCESS: + zebra_mpls_zapi_labels_process(w->add_p, zvrf, &w->zl); + break; + } + + XFREE(MTYPE_WQ_WRAPPER, w); +} + static void process_subq_route(struct listnode *lnode, uint8_t qindex) { struct route_node *rnode = NULL; @@ -2492,23 +2567,494 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex) route_unlock_node(rnode); } +static void rib_re_nhg_free(struct route_entry *re) +{ + if (re->nhe && re->nhe_id) { + assert(re->nhe->id == re->nhe_id); + route_entry_update_nhe(re, NULL); + } else if (re->nhe && re->nhe->nhg.nexthop) + nexthops_free(re->nhe->nhg.nexthop); + + nexthops_free(re->fib_ng.nexthop); +} + +struct zebra_early_route { + afi_t afi; + safi_t safi; + struct prefix p; + struct prefix_ipv6 src_p; + bool src_p_provided; + struct route_entry *re; + struct nhg_hash_entry *re_nhe; + bool startup; + bool deletion; + bool fromkernel; +}; + +static void early_route_memory_free(struct zebra_early_route *ere) +{ + if (ere->re_nhe) + zebra_nhg_free(ere->re_nhe); + + XFREE(MTYPE_RE, ere->re); + XFREE(MTYPE_WQ_WRAPPER, ere); +} + +static void process_subq_early_route_add(struct zebra_early_route *ere) +{ + struct route_entry *re = ere->re; + struct route_table *table; + struct nhg_hash_entry *nhe = NULL; + struct route_node *rn; + struct route_entry *same = NULL, *first_same = NULL; + int same_count = 0; + rib_dest_t *dest; + + /* Lookup table. */ + table = zebra_vrf_get_table_with_table_id(ere->afi, ere->safi, + re->vrf_id, re->table); + if (!table) { + early_route_memory_free(ere); + return; + } + + if (re->nhe_id > 0) { + nhe = zebra_nhg_lookup_id(re->nhe_id); + + if (!nhe) { + /* + * We've received from the kernel a nexthop id + * that we don't have saved yet. More than likely + * it has not been processed and is on the + * queue to be processed. Let's stop what we + * are doing and cause the meta q to be processed + * storing this for later. + * + * This is being done this way because zebra + * runs with the assumption t + */ + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find the nexthop hash entry for id=%u in a route entry %pFX", + re->nhe_id, &ere->p); + + early_route_memory_free(ere); + return; + } + } else { + /* Lookup nhe from route information */ + nhe = zebra_nhg_rib_find_nhe(ere->re_nhe, ere->afi); + if (!nhe) { + char buf2[PREFIX_STRLEN] = ""; + + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find or create a nexthop hash entry for %pFX%s%s", + &ere->p, ere->src_p_provided ? " from " : "", + ere->src_p_provided + ? prefix2str(&ere->src_p, buf2, + sizeof(buf2)) + : ""); + + early_route_memory_free(ere); + return; + } + } + + /* + * Attach the re to the nhe's nexthop group. + * + * TODO: This will need to change when we start getting IDs from upper + * level protocols, as the refcnt might be wrong, since it checks + * if old_id != new_id. + */ + route_entry_update_nhe(re, nhe); + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask(&ere->p); + if (ere->src_p_provided) + apply_mask_ipv6(&ere->src_p); + + /* Set default distance by route type. */ + if (re->distance == 0) + re->distance = route_distance(re->type); + + /* Lookup route node.*/ + rn = srcdest_rnode_get(table, &ere->p, + ere->src_p_provided ? &ere->src_p : NULL); + + /* + * If same type of route are installed, treat it as a implicit + * withdraw. If the user has specified the No route replace semantics + * for the install don't do a route replace. + */ + RNODE_FOREACH_RE (rn, same) { + if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) { + same_count++; + continue; + } + + /* Compare various route_entry properties */ + if (rib_compare_routes(re, same)) { + same_count++; + + if (first_same == NULL) + first_same = same; + } + } + + same = first_same; + + if (!ere->startup && (re->flags & ZEBRA_FLAG_SELFROUTE) && + zrouter.asic_offloaded) { + if (!same) { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug( + "prefix: %pRN is a self route where we do not have an entry for it. Dropping this update, it's useless", + rn); + /* + * We are not on startup, this is a self route + * and we have asic offload. Which means + * we are getting a callback for a entry + * that was already deleted to the kernel + * but an earlier response was just handed + * back. Drop it on the floor + */ + early_route_memory_free(ere); + return; + } + } + + /* If this route is kernel/connected route, notify the dataplane. */ + if (RIB_SYSTEM_ROUTE(re)) { + /* Notify dataplane */ + dplane_sys_route_add(rn, re); + } + + /* Link new re to node.*/ + if (IS_ZEBRA_DEBUG_RIB) { + rnode_debug( + rn, re->vrf_id, + "Inserting route rn %p, re %p (%s) existing %p, same_count %d", + rn, re, zebra_route_string(re->type), same, same_count); + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + route_entry_dump( + &ere->p, + ere->src_p_provided ? &ere->src_p : NULL, re); + } + + SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + rib_addnode(rn, re, 1); + + /* Free implicit route.*/ + if (same) + rib_delnode(rn, same); + + /* See if we can remove some RE entries that are queued for + * removal, but won't be considered in rib processing. + */ + dest = rib_dest_from_rnode(rn); + RNODE_FOREACH_RE_SAFE (rn, re, same) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) { + /* If the route was used earlier, must retain it. */ + if (dest && re == dest->selected_fib) + continue; + + if (IS_ZEBRA_DEBUG_RIB) + rnode_debug(rn, re->vrf_id, + "rn %p, removing unneeded re %p", + rn, re); + + rib_unlink(rn, re); + } + } + + route_unlock_node(rn); + if (ere->re_nhe) + zebra_nhg_free(ere->re_nhe); + XFREE(MTYPE_WQ_WRAPPER, ere); +} + +static void process_subq_early_route_delete(struct zebra_early_route *ere) +{ + struct route_table *table; + struct route_node *rn; + struct route_entry *re; + struct route_entry *fib = NULL; + struct route_entry *same = NULL; + struct nexthop *rtnh; + char buf2[INET6_ADDRSTRLEN]; + rib_dest_t *dest; + + if (ere->src_p_provided) + assert(!ere->src_p.prefixlen || ere->afi == AFI_IP6); + + /* Lookup table. */ + table = zebra_vrf_lookup_table_with_table_id( + ere->afi, ere->safi, ere->re->vrf_id, ere->re->table); + if (!table) { + early_route_memory_free(ere); + return; + } + + /* Apply mask. */ + apply_mask(&ere->p); + if (ere->src_p_provided) + apply_mask_ipv6(&ere->src_p); + + /* Lookup route node. */ + rn = srcdest_rnode_lookup(table, &ere->p, + ere->src_p_provided ? &ere->src_p : NULL); + if (!rn) { + if (IS_ZEBRA_DEBUG_RIB) { + char src_buf[PREFIX_STRLEN]; + struct vrf *vrf = vrf_lookup_by_id(ere->re->vrf_id); + + if (ere->src_p_provided && ere->src_p.prefixlen) + prefix2str(&ere->src_p, src_buf, + sizeof(src_buf)); + else + src_buf[0] = '\0'; + + zlog_debug("%s[%d]:%pRN%s%s doesn't exist in rib", + vrf->name, ere->re->table, rn, + (src_buf[0] != '\0') ? " from " : "", + src_buf); + } + early_route_memory_free(ere); + return; + } + + dest = rib_dest_from_rnode(rn); + fib = dest->selected_fib; + + struct nexthop *nh = NULL; + + if (ere->re->nhe) + nh = ere->re->nhe->nhg.nexthop; + + /* Lookup same type route. */ + RNODE_FOREACH_RE (rn, re) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) + continue; + + if (re->type != ere->re->type) + continue; + if (re->instance != ere->re->instance) + continue; + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_RR_USE_DISTANCE) && + ere->re->distance != re->distance) + continue; + + if (re->type == ZEBRA_ROUTE_KERNEL && + re->metric != ere->re->metric) + continue; + if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = nh) && + rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { + if (rtnh->ifindex != nh->ifindex) + continue; + same = re; + break; + } + + /* Make sure that the route found has the same gateway. */ + if (ere->re->nhe_id && re->nhe_id == ere->re->nhe_id) { + same = re; + break; + } + + if (nh == NULL) { + same = re; + break; + } + for (ALL_NEXTHOPS(re->nhe->nhg, rtnh)) { + /* + * No guarantee all kernel send nh with labels + * on delete. + */ + if (nexthop_same_no_labels(rtnh, nh)) { + same = re; + break; + } + } + + if (same) + break; + } + /* + * If same type of route can't be found and this message is from + * kernel. + */ + if (!same) { + /* + * In the past(HA!) we could get here because + * we were receiving a route delete from the + * kernel and we're not marking the proto + * as coming from it's appropriate originator. + * Now that we are properly noticing the fact + * that the kernel has deleted our route we + * are not going to get called in this path + * I am going to leave this here because + * this might still work this way on non-linux + * platforms as well as some weird state I have + * not properly thought of yet. + * If we can show that this code path is + * dead then we can remove it. + */ + if (fib && CHECK_FLAG(ere->re->flags, ZEBRA_FLAG_SELFROUTE)) { + if (IS_ZEBRA_DEBUG_RIB) { + rnode_debug( + rn, ere->re->vrf_id, + "rn %p, re %p (%s) was deleted from kernel, adding", + rn, fib, zebra_route_string(fib->type)); + } + if (zrouter.allow_delete || + CHECK_FLAG(dest->flags, RIB_ROUTE_ANY_QUEUED)) { + UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); + /* Unset flags. */ + for (rtnh = fib->nhe->nhg.nexthop; rtnh; + rtnh = rtnh->next) + UNSET_FLAG(rtnh->flags, + NEXTHOP_FLAG_FIB); + + /* + * This is a non FRR route + * as such we should mark + * it as deleted + */ + dest->selected_fib = NULL; + } else { + /* + * This means someone else, other than Zebra, + * has deleted a Zebra router from the kernel. + * We will add it back + */ + rib_install_kernel(rn, fib, NULL); + } + } else { + if (IS_ZEBRA_DEBUG_RIB) { + if (nh) + rnode_debug( + rn, ere->re->vrf_id, + "via %s ifindex %d type %d doesn't exist in rib", + inet_ntop(afi2family(ere->afi), + &nh->gate, buf2, + sizeof(buf2)), + nh->ifindex, ere->re->type); + else + rnode_debug( + rn, ere->re->vrf_id, + "type %d doesn't exist in rib", + ere->re->type); + } + route_unlock_node(rn); + early_route_memory_free(ere); + return; + } + } + + if (same) { + struct nexthop *tmp_nh; + + if (ere->fromkernel && + CHECK_FLAG(ere->re->flags, ZEBRA_FLAG_SELFROUTE) && + !zrouter.allow_delete) { + rib_install_kernel(rn, same, NULL); + route_unlock_node(rn); + + early_route_memory_free(ere); + return; + } + + /* Special handling for IPv4 or IPv6 routes sourced from + * EVPN - the nexthop (and associated MAC) need to be + * uninstalled if no more refs. + */ + for (ALL_NEXTHOPS(re->nhe->nhg, tmp_nh)) { + struct ipaddr vtep_ip; + + if (CHECK_FLAG(tmp_nh->flags, NEXTHOP_FLAG_EVPN)) { + memset(&vtep_ip, 0, sizeof(struct ipaddr)); + if (ere->afi == AFI_IP) { + vtep_ip.ipa_type = IPADDR_V4; + memcpy(&(vtep_ip.ipaddr_v4), + &(tmp_nh->gate.ipv4), + sizeof(struct in_addr)); + } else { + vtep_ip.ipa_type = IPADDR_V6; + memcpy(&(vtep_ip.ipaddr_v6), + &(tmp_nh->gate.ipv6), + sizeof(struct in6_addr)); + } + zebra_rib_queue_evpn_route_del( + re->vrf_id, &vtep_ip, &ere->p); + } + } + + /* Notify dplane if system route changes */ + if (RIB_SYSTEM_ROUTE(re)) + dplane_sys_route_del(rn, same); + + rib_delnode(rn, same); + } + + route_unlock_node(rn); + + early_route_memory_free(ere); +} + +/* + * When FRR receives a route we need to match the route up to + * nexthop groups. That we also may have just received + * place the data on this queue so that this work of finding + * the nexthop group entries for the route entry is always + * done after the nexthop group has had a chance to be processed + */ +static void process_subq_early_route(struct listnode *lnode) +{ + struct zebra_early_route *ere = listgetdata(lnode); + + if (ere->deletion) + process_subq_early_route_delete(ere); + else + process_subq_early_route_add(ere); +} + /* * Examine the specified subqueue; process one entry and return 1 if * there is a node, return 0 otherwise. */ -static unsigned int process_subq(struct list *subq, uint8_t qindex) +static unsigned int process_subq(struct list *subq, + enum meta_queue_indexes qindex) { struct listnode *lnode = listhead(subq); if (!lnode) return 0; - if (qindex == META_QUEUE_EVPN) + switch (qindex) { + case META_QUEUE_EVPN: process_subq_evpn(lnode); - else if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map) + break; + case META_QUEUE_NHG: process_subq_nhg(lnode); - else + break; + case META_QUEUE_EARLY_ROUTE: + process_subq_early_route(lnode); + break; + case META_QUEUE_EARLY_LABEL: + process_subq_early_label(lnode); + break; + case META_QUEUE_CONNECTED: + case META_QUEUE_KERNEL: + case META_QUEUE_STATIC: + case META_QUEUE_NOTBGP: + case META_QUEUE_BGP: + case META_QUEUE_OTHER: process_subq_route(lnode, qindex); + break; + } list_delete_node(subq, lnode); @@ -2530,8 +3076,9 @@ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data) queue_len = dplane_get_in_queue_len(); if (queue_len > queue_limit) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("rib queue: dplane queue len %u, limit %u, retrying", - queue_len, queue_limit); + zlog_debug( + "rib queue: dplane queue len %u, limit %u, retrying", + queue_len, queue_limit); /* Ensure that the meta-queue is actually enqueued */ if (work_queue_empty(zrouter.ribq)) @@ -2610,10 +3157,17 @@ static int rib_meta_queue_add(struct meta_queue *mq, void *data) return 0; } +static int early_label_meta_queue_add(struct meta_queue *mq, void *data) +{ + listnode_add(mq->subq[META_QUEUE_EARLY_LABEL], data); + mq->size++; + return 0; +} + static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data) { struct nhg_ctx *ctx = NULL; - uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; + uint8_t qindex = META_QUEUE_NHG; struct wq_nhg_wrapper *w; ctx = (struct nhg_ctx *)data; @@ -2639,7 +3193,7 @@ static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data) static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) { struct nhg_hash_entry *nhe = NULL; - uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; + uint8_t qindex = META_QUEUE_NHG; struct wq_nhg_wrapper *w; nhe = (struct nhg_hash_entry *)data; @@ -2693,6 +3247,44 @@ static int mq_add_handler(void *data, return mq_add_func(zrouter.mq, data); } +void mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, + struct prefix *prefix, uint8_t route_type, + uint8_t route_instance) +{ + struct wq_label_wrapper *w; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_label_wrapper)); + + w->type = WQ_LABEL_FTN_UNINSTALL; + w->vrf_id = zvrf->vrf->vrf_id; + w->p = *prefix; + w->ltype = type; + w->route_type = route_type; + w->route_instance = route_instance; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("Early Label Handling for %pFX", prefix); + + mq_add_handler(w, early_label_meta_queue_add); +} + +void mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf, + const struct zapi_labels *zl) +{ + struct wq_label_wrapper *w; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_label_wrapper)); + w->type = WQ_LABEL_LABELS_PROCESS; + w->vrf_id = zvrf->vrf->vrf_id; + w->add_p = add_p; + w->zl = *zl; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("Early Label Handling: Labels Process"); + + mq_add_handler(w, early_label_meta_queue_add); +} + /* Add route_node to work queue and schedule processing */ int rib_queue_add(struct route_node *rn) { @@ -2933,131 +3525,174 @@ int zebra_rib_queue_evpn_rem_vtep_del(vrf_id_t vrf_id, vni_t vni, return mq_add_handler(w, rib_meta_queue_evpn_add); } +/* Create new meta queue. + A destructor function doesn't seem to be necessary here. + */ +static struct meta_queue *meta_queue_new(void) +{ + struct meta_queue *new; + unsigned i; + + new = XCALLOC(MTYPE_WORK_QUEUE, sizeof(struct meta_queue)); + + for (i = 0; i < MQ_SIZE; i++) { + new->subq[i] = list_new(); + assert(new->subq[i]); + } + + return new; +} + /* Clean up the EVPN meta-queue list */ -static void evpn_meta_queue_free(struct list *l) +static void evpn_meta_queue_free(struct meta_queue *mq, struct list *l, + struct zebra_vrf *zvrf) { - struct listnode *node; + struct listnode *node, *nnode; struct wq_evpn_wrapper *w; /* Free the node wrapper object, and the struct it wraps */ - while ((node = listhead(l)) != NULL) { - w = node->data; + for (ALL_LIST_ELEMENTS(l, node, nnode, w)) { + if (zvrf) { + vrf_id_t vrf_id = zvrf->vrf->vrf_id; + + if (w->vrf_id != vrf_id) + continue; + } + node->data = NULL; XFREE(MTYPE_WQ_WRAPPER, w); list_delete_node(l, node); + mq->size--; } } /* Clean up the nhg meta-queue list */ -static void nhg_meta_queue_free(struct list *l) +static void nhg_meta_queue_free(struct meta_queue *mq, struct list *l, + struct zebra_vrf *zvrf) { struct wq_nhg_wrapper *w; - struct listnode *node; + struct listnode *node, *nnode; /* Free the node wrapper object, and the struct it wraps */ - while ((node = listhead(l)) != NULL) { - w = node->data; - node->data = NULL; + for (ALL_LIST_ELEMENTS(l, node, nnode, w)) { + if (zvrf) { + vrf_id_t vrf_id = zvrf->vrf->vrf_id; + if (w->type == WQ_NHG_WRAPPER_TYPE_CTX && + w->u.ctx->vrf_id != vrf_id) + continue; + else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG && + w->u.nhe->vrf_id != vrf_id) + continue; + } if (w->type == WQ_NHG_WRAPPER_TYPE_CTX) nhg_ctx_free(&w->u.ctx); else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG) zebra_nhg_free(w->u.nhe); + node->data = NULL; XFREE(MTYPE_WQ_WRAPPER, w); list_delete_node(l, node); + mq->size--; } } -/* Create new meta queue. - A destructor function doesn't seem to be necessary here. - */ -static struct meta_queue *meta_queue_new(void) +static void early_label_meta_queue_free(struct meta_queue *mq, struct list *l, + struct zebra_vrf *zvrf) { - struct meta_queue *new; - unsigned i; + struct wq_label_wrapper *w; + struct listnode *node, *nnode; - new = XCALLOC(MTYPE_WORK_QUEUE, sizeof(struct meta_queue)); + for (ALL_LIST_ELEMENTS(l, node, nnode, w)) { + if (zvrf && zvrf->vrf->vrf_id != w->vrf_id) + continue; - for (i = 0; i < MQ_SIZE; i++) { - new->subq[i] = list_new(); - assert(new->subq[i]); - } + switch (w->type) { + case WQ_LABEL_FTN_UNINSTALL: + case WQ_LABEL_LABELS_PROCESS: + break; + } - return new; + node->data = NULL; + XFREE(MTYPE_WQ_WRAPPER, w); + list_delete_node(l, node); + mq->size--; + } } -void meta_queue_free(struct meta_queue *mq) +static void rib_meta_queue_free(struct meta_queue *mq, struct list *l, + struct zebra_vrf *zvrf) { - unsigned i; + struct route_node *rnode; + struct listnode *node, *nnode; - for (i = 0; i < MQ_SIZE; i++) { - /* Some subqueues may need cleanup - nhgs for example */ - if (i == route_info[ZEBRA_ROUTE_NHG].meta_q_map) - nhg_meta_queue_free(mq->subq[i]); - else if (i == META_QUEUE_EVPN) - evpn_meta_queue_free(mq->subq[i]); + for (ALL_LIST_ELEMENTS(l, node, nnode, rnode)) { + rib_dest_t *dest = rib_dest_from_rnode(rnode); - list_delete(&mq->subq[i]); - } + if (dest && rib_dest_vrf(dest) != zvrf) + continue; - XFREE(MTYPE_WORK_QUEUE, mq); + route_unlock_node(rnode); + node->data = NULL; + list_delete_node(l, node); + mq->size--; + } } -void rib_meta_queue_free_vrf(struct meta_queue *mq, struct zebra_vrf *zvrf) +static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, + struct zebra_vrf *zvrf) { - vrf_id_t vrf_id = zvrf->vrf->vrf_id; - unsigned int i; - - for (i = 0; i < MQ_SIZE; i++) { - struct listnode *lnode, *nnode; - void *data; - bool del; + struct zebra_early_route *zer; + struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS(mq->subq[i], lnode, nnode, data)) { - del = false; - - if (i == META_QUEUE_EVPN) { - struct wq_evpn_wrapper *w = data; + for (ALL_LIST_ELEMENTS(l, node, nnode, zer)) { + if (zvrf && zer->re->vrf_id != zvrf->vrf->vrf_id) + continue; - if (w->vrf_id == vrf_id) { - XFREE(MTYPE_WQ_WRAPPER, w); - del = true; - } - } else if (i == - route_info[ZEBRA_ROUTE_NHG].meta_q_map) { - struct wq_nhg_wrapper *w = data; - - if (w->type == WQ_NHG_WRAPPER_TYPE_CTX && - w->u.ctx->vrf_id == vrf_id) { - nhg_ctx_free(&w->u.ctx); - XFREE(MTYPE_WQ_WRAPPER, w); - del = true; - } else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG && - w->u.nhe->vrf_id == vrf_id) { - zebra_nhg_free(w->u.nhe); - XFREE(MTYPE_WQ_WRAPPER, w); - del = true; - } - } else { - struct route_node *rnode = data; - rib_dest_t *dest = rib_dest_from_rnode(rnode); + XFREE(MTYPE_RE, zer); + node->data = NULL; + list_delete_node(l, node); + mq->size--; + } +} - if (dest && rib_dest_vrf(dest) == zvrf) { - route_unlock_node(rnode); - del = true; - } - } +void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf) +{ + enum meta_queue_indexes i; - if (del) { - list_delete_node(mq->subq[i], lnode); - mq->size--; - } + for (i = 0; i < MQ_SIZE; i++) { + /* Some subqueues may need cleanup - nhgs for example */ + switch (i) { + case META_QUEUE_NHG: + nhg_meta_queue_free(mq, mq->subq[i], zvrf); + break; + case META_QUEUE_EVPN: + evpn_meta_queue_free(mq, mq->subq[i], zvrf); + break; + case META_QUEUE_EARLY_ROUTE: + early_route_meta_queue_free(mq, mq->subq[i], zvrf); + break; + case META_QUEUE_EARLY_LABEL: + early_label_meta_queue_free(mq, mq->subq[i], zvrf); + break; + case META_QUEUE_CONNECTED: + case META_QUEUE_KERNEL: + case META_QUEUE_STATIC: + case META_QUEUE_NOTBGP: + case META_QUEUE_BGP: + case META_QUEUE_OTHER: + rib_meta_queue_free(mq, mq->subq[i], zvrf); + break; } + if (!zvrf) + list_delete(&mq->subq[i]); } + + if (!zvrf) + XFREE(MTYPE_WORK_QUEUE, mq); } /* initialise zebra rib work queue */ @@ -3186,17 +3821,6 @@ static void rib_addnode(struct route_node *rn, rib_link(rn, re, process); } -static void rib_re_nhg_free(struct route_entry *re) -{ - if (re->nhe && re->nhe_id) { - assert(re->nhe->id == re->nhe_id); - route_entry_update_nhe(re, NULL); - } else if (re->nhe && re->nhe->nhg.nexthop) - nexthops_free(re->nhe->nhg.nexthop); - - nexthops_free(re->fib_ng.nexthop); -} - /* * rib_unlink * @@ -3402,6 +4026,46 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, zlog_debug("%s: dump complete", straddr); } +static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data) +{ + struct zebra_early_route *ere = data; + + listnode_add(mq->subq[META_QUEUE_EARLY_ROUTE], data); + mq->size++; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug( + "Route %pFX(%u) queued for processing into sub-queue %s", + &ere->p, ere->re->vrf_id, + subqueue2str(META_QUEUE_EARLY_ROUTE)); + + return 0; +} + +struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, + uint8_t instance, uint32_t flags, + uint32_t nhe_id, + uint32_t table_id, + uint32_t metric, uint32_t mtu, + uint8_t distance, route_tag_t tag) +{ + struct route_entry *re; + + re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); + re->type = type; + re->instance = instance; + re->distance = distance; + re->flags = flags; + re->metric = metric; + re->mtu = mtu; + re->table = table_id; + re->vrf_id = vrf_id; + re->uptime = monotime(NULL); + re->tag = tag; + re->nhe_id = nhe_id; + + return re; +} /* * Internal route-add implementation; there are a couple of different public * signatures. Callers in this path are responsible for the memory they @@ -3417,162 +4081,25 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, struct prefix_ipv6 *src_p, struct route_entry *re, struct nhg_hash_entry *re_nhe, bool startup) { - struct nhg_hash_entry *nhe = NULL; - struct route_table *table; - struct route_node *rn; - struct route_entry *same = NULL, *first_same = NULL; - int ret = 0; - int same_count = 0; - rib_dest_t *dest; + struct zebra_early_route *ere; - if (!re || !re_nhe) + if (!re) return -1; assert(!src_p || !src_p->prefixlen || afi == AFI_IP6); - /* Lookup table. */ - table = zebra_vrf_get_table_with_table_id(afi, safi, re->vrf_id, - re->table); - if (!table) - return -1; - - if (re->nhe_id > 0) { - nhe = zebra_nhg_lookup_id(re->nhe_id); - - if (!nhe) { - flog_err( - EC_ZEBRA_TABLE_LOOKUP_FAILED, - "Zebra failed to find the nexthop hash entry for id=%u in a route entry", - re->nhe_id); - - return -1; - } - } else { - /* Lookup nhe from route information */ - nhe = zebra_nhg_rib_find_nhe(re_nhe, afi); - if (!nhe) { - char buf2[PREFIX_STRLEN] = ""; - - flog_err( - EC_ZEBRA_TABLE_LOOKUP_FAILED, - "Zebra failed to find or create a nexthop hash entry for %pFX%s%s", - p, src_p ? " from " : "", - src_p ? prefix2str(src_p, buf2, sizeof(buf2)) - : ""); - - return -1; - } - } - - /* - * Attach the re to the nhe's nexthop group. - * - * TODO: This will need to change when we start getting IDs from upper - * level protocols, as the refcnt might be wrong, since it checks - * if old_id != new_id. - */ - route_entry_update_nhe(re, nhe); - - /* Make it sure prefixlen is applied to the prefix. */ - apply_mask(p); + ere = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(*ere)); + ere->afi = afi; + ere->safi = safi; + ere->p = *p; if (src_p) - apply_mask_ipv6(src_p); - - /* Set default distance by route type. */ - if (re->distance == 0) - re->distance = route_distance(re->type); - - /* Lookup route node.*/ - rn = srcdest_rnode_get(table, p, src_p); - - /* - * If same type of route are installed, treat it as a implicit - * withdraw. If the user has specified the No route replace semantics - * for the install don't do a route replace. - */ - RNODE_FOREACH_RE (rn, same) { - if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) { - same_count++; - continue; - } - - /* Compare various route_entry properties */ - if (rib_compare_routes(re, same)) { - same_count++; - - if (first_same == NULL) - first_same = same; - } - } - - same = first_same; - - if (!startup && - (re->flags & ZEBRA_FLAG_SELFROUTE) && zrouter.asic_offloaded) { - if (!same) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("prefix: %pRN is a self route where we do not have an entry for it. Dropping this update, it's useless", rn); - /* - * We are not on startup, this is a self route - * and we have asic offload. Which means - * we are getting a callback for a entry - * that was already deleted to the kernel - * but an earlier response was just handed - * back. Drop it on the floor - */ - rib_re_nhg_free(re); - - XFREE(MTYPE_RE, re); - return ret; - } - } - - /* If this route is kernel/connected route, notify the dataplane. */ - if (RIB_SYSTEM_ROUTE(re)) { - /* Notify dataplane */ - dplane_sys_route_add(rn, re); - } - - /* Link new re to node.*/ - if (IS_ZEBRA_DEBUG_RIB) { - rnode_debug(rn, re->vrf_id, - "Inserting route rn %p, re %p (%s) existing %p, same_count %d", - rn, re, zebra_route_string(re->type), same, - same_count); - - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - route_entry_dump(p, src_p, re); - } - - SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - rib_addnode(rn, re, 1); - - /* Free implicit route.*/ - if (same) { - ret = 1; - rib_delnode(rn, same); - } + ere->src_p = *src_p; + ere->src_p_provided = !!src_p; + ere->re = re; + ere->re_nhe = re_nhe; + ere->startup = startup; - /* See if we can remove some RE entries that are queued for - * removal, but won't be considered in rib processing. - */ - dest = rib_dest_from_rnode(rn); - RNODE_FOREACH_RE_SAFE (rn, re, same) { - if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) { - /* If the route was used earlier, must retain it. */ - if (dest && re == dest->selected_fib) - continue; - - if (IS_ZEBRA_DEBUG_RIB) - rnode_debug(rn, re->vrf_id, "rn %p, removing unneeded re %p", - rn, re); - - rib_unlink(rn, re); - } - } - - route_unlock_node(rn); - return ret; + return mq_add_handler(ere, rib_meta_queue_early_route_add); } /* @@ -3583,7 +4110,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct nexthop_group *ng, bool startup) { int ret; - struct nhg_hash_entry nhe; + struct nhg_hash_entry nhe, *n; if (!re) return -1; @@ -3601,10 +4128,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, else if (re->nhe_id > 0) nhe.id = re->nhe_id; - ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, &nhe, startup); - - /* In this path, the callers expect memory to be freed. */ - nexthop_group_delete(&ng); + n = zebra_nhe_copy(&nhe, 0); + ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup); /* In error cases, free the route also */ if (ret < 0) @@ -3619,212 +4144,32 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint8_t distance, bool fromkernel) { - struct route_table *table; - struct route_node *rn; - struct route_entry *re; - struct route_entry *fib = NULL; - struct route_entry *same = NULL; - struct nexthop *rtnh; - char buf2[INET6_ADDRSTRLEN]; - rib_dest_t *dest; - - assert(!src_p || !src_p->prefixlen || afi == AFI_IP6); - - /* Lookup table. */ - table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id, - table_id); - if (!table) - return; - - /* Apply mask. */ - apply_mask(p); - if (src_p) - apply_mask_ipv6(src_p); - - /* Lookup route node. */ - rn = srcdest_rnode_lookup(table, p, src_p); - if (!rn) { - if (IS_ZEBRA_DEBUG_RIB) { - char src_buf[PREFIX_STRLEN]; - struct vrf *vrf = vrf_lookup_by_id(vrf_id); - - if (src_p && src_p->prefixlen) - prefix2str(src_p, src_buf, sizeof(src_buf)); - else - src_buf[0] = '\0'; - - zlog_debug("%s[%d]:%pRN%s%s doesn't exist in rib", - vrf->name, table_id, rn, - (src_buf[0] != '\0') ? " from " : "", - src_buf); - } - return; - } - - dest = rib_dest_from_rnode(rn); - fib = dest->selected_fib; - - /* Lookup same type route. */ - RNODE_FOREACH_RE (rn, re) { - if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) - continue; - - if (re->type != type) - continue; - if (re->instance != instance) - continue; - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_RR_USE_DISTANCE) && - distance != re->distance) - continue; - - if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric) - continue; - if (re->type == ZEBRA_ROUTE_CONNECT && - (rtnh = re->nhe->nhg.nexthop) - && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { - if (rtnh->ifindex != nh->ifindex) - continue; - same = re; - break; - } - - /* Make sure that the route found has the same gateway. */ - if (nhe_id && re->nhe_id == nhe_id) { - same = re; - break; - } - - if (nh == NULL) { - same = re; - break; - } - for (ALL_NEXTHOPS(re->nhe->nhg, rtnh)) { - /* - * No guarantee all kernel send nh with labels - * on delete. - */ - if (nexthop_same_no_labels(rtnh, nh)) { - same = re; - break; - } - } - - if (same) - break; - } - /* If same type of route can't be found and this message is from - kernel. */ - if (!same) { - /* - * In the past(HA!) we could get here because - * we were receiving a route delete from the - * kernel and we're not marking the proto - * as coming from it's appropriate originator. - * Now that we are properly noticing the fact - * that the kernel has deleted our route we - * are not going to get called in this path - * I am going to leave this here because - * this might still work this way on non-linux - * platforms as well as some weird state I have - * not properly thought of yet. - * If we can show that this code path is - * dead then we can remove it. - */ - if (fib && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) { - if (IS_ZEBRA_DEBUG_RIB) { - rnode_debug(rn, vrf_id, - "rn %p, re %p (%s) was deleted from kernel, adding", - rn, fib, - zebra_route_string(fib->type)); - } - if (zrouter.allow_delete || - CHECK_FLAG(dest->flags, RIB_ROUTE_ANY_QUEUED)) { - UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); - /* Unset flags. */ - for (rtnh = fib->nhe->nhg.nexthop; rtnh; - rtnh = rtnh->next) - UNSET_FLAG(rtnh->flags, - NEXTHOP_FLAG_FIB); - - /* - * This is a non FRR route - * as such we should mark - * it as deleted - */ - dest->selected_fib = NULL; - } else { - /* This means someone else, other than Zebra, - * has deleted - * a Zebra router from the kernel. We will add - * it back */ - rib_install_kernel(rn, fib, NULL); - } - } else { - if (IS_ZEBRA_DEBUG_RIB) { - if (nh) - rnode_debug( - rn, vrf_id, - "via %s ifindex %d type %d doesn't exist in rib", - inet_ntop(afi2family(afi), - &nh->gate, buf2, - sizeof(buf2)), - nh->ifindex, type); - else - rnode_debug( - rn, vrf_id, - "type %d doesn't exist in rib", - type); - } - route_unlock_node(rn); - return; - } - } - - if (same) { - struct nexthop *tmp_nh; - - if (fromkernel && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) && - !zrouter.allow_delete) { - rib_install_kernel(rn, same, NULL); - route_unlock_node(rn); - - return; - } - - /* Special handling for IPv4 or IPv6 routes sourced from - * EVPN - the nexthop (and associated MAC) need to be - * uninstalled if no more refs. - */ - for (ALL_NEXTHOPS(re->nhe->nhg, tmp_nh)) { - struct ipaddr vtep_ip; - - if (CHECK_FLAG(tmp_nh->flags, NEXTHOP_FLAG_EVPN)) { - memset(&vtep_ip, 0, sizeof(struct ipaddr)); - if (afi == AFI_IP) { - vtep_ip.ipa_type = IPADDR_V4; - memcpy(&(vtep_ip.ipaddr_v4), - &(tmp_nh->gate.ipv4), - sizeof(struct in_addr)); - } else { - vtep_ip.ipa_type = IPADDR_V6; - memcpy(&(vtep_ip.ipaddr_v6), - &(tmp_nh->gate.ipv6), - sizeof(struct in6_addr)); - } - zebra_rib_queue_evpn_route_del(re->vrf_id, - &vtep_ip, p); - } - } + struct zebra_early_route *ere; + struct route_entry *re = NULL; + struct nhg_hash_entry *nhe = NULL; - /* Notify dplane if system route changes */ - if (RIB_SYSTEM_ROUTE(re)) - dplane_sys_route_del(rn, same); + re = zebra_rib_route_entry_new(vrf_id, type, instance, flags, nhe_id, + table_id, metric, 0, distance, 0); - rib_delnode(rn, same); + if (nh) { + nhe = zebra_nhg_alloc(); + nhe->nhg.nexthop = nexthop_dup(nh, NULL); } - route_unlock_node(rn); - return; + ere = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(*ere)); + ere->afi = afi; + ere->safi = safi; + ere->p = *p; + if (src_p) + ere->src_p = *src_p; + ere->src_p_provided = !!src_p; + ere->re = re; + ere->re_nhe = nhe; + ere->startup = false; + ere->deletion = true; + ere->fromkernel = fromkernel; + + mq_add_handler(ere, rib_meta_queue_early_route_add); } @@ -3835,36 +4180,23 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, uint8_t distance, route_tag_t tag, bool startup) { struct route_entry *re = NULL; - struct nexthop *nexthop = NULL; - struct nexthop_group *ng = NULL; + struct nexthop nexthop = {}; + struct nexthop_group ng = {}; /* Allocate new route_entry structure. */ - re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); - re->type = type; - re->instance = instance; - re->distance = distance; - re->flags = flags; - re->metric = metric; - re->mtu = mtu; - re->table = table_id; - re->vrf_id = vrf_id; - re->uptime = monotime(NULL); - re->tag = tag; - re->nhe_id = nhe_id; + re = zebra_rib_route_entry_new(vrf_id, type, instance, flags, nhe_id, + table_id, metric, mtu, distance, tag); /* If the owner of the route supplies a shared nexthop-group id, * we'll use that. Otherwise, pass the nexthop along directly. */ if (!nhe_id) { - ng = nexthop_group_new(); - /* Add nexthop. */ - nexthop = nexthop_new(); - *nexthop = *nh; - nexthop_group_add_sorted(ng, nexthop); + nexthop = *nh; + nexthop_group_add_sorted(&ng, &nexthop); } - return rib_add_multipath(afi, safi, p, src_p, re, ng, startup); + return rib_add_multipath(afi, safi, p, src_p, re, &ng, startup); } static const char *rib_update_event2str(enum rib_update_event event) @@ -4367,6 +4699,11 @@ static void rib_process_dplane_results(struct thread *thread) zebra_if_dplane_result(ctx); break; + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: + break; + /* Some op codes not handled here */ case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_UNINSTALL: |
