diff options
| -rw-r--r-- | zebra/rib.h | 17 | ||||
| -rw-r--r-- | zebra/zapi_msg.c | 7 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 929 | 
3 files changed, 564 insertions, 389 deletions
diff --git a/zebra/rib.h b/zebra/rib.h index 9f34399653..2e8b05f9de 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -178,16 +178,17 @@ struct route_entry {  /* meta-queue structure:   * sub-queue 0: nexthop group objects   * sub-queue 1: EVPN/VxLAN objects - * sub-queue 2: Early Label Processing - * sub-queue 2: connected - * sub-queue 3: kernel - * sub-queue 4: static - * sub-queue 5: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP - * sub-queue 6: iBGP, eBGP - * sub-queue 7: any other origin (if any) typically those that + * sub-queue 2: Early Route Processing + * sub-queue 3: Early Label Processing + * sub-queue 4: connected + * sub-queue 5: kernel + * sub-queue 6: static + * sub-queue 7: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP + * sub-queue 8: iBGP, eBGP + * sub-queue 9: any other origin (if any) typically those that   *              don't generate routes   */ -#define MQ_SIZE 9 +#define MQ_SIZE 10  struct meta_queue {  	struct list *subq[MQ_SIZE];  	uint32_t size; /* sum of lengths of all subqueues */ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index a578395ef8..b68dbb38b6 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2034,7 +2034,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)  	struct nhg_backup_info *bnhg = NULL;  	int ret;  	vrf_id_t vrf_id; -	struct nhg_hash_entry nhe; +	struct nhg_hash_entry nhe, *n = NULL;  	s = msg;  	if (zapi_route_decode(s, &api) < 0) { @@ -2161,9 +2161,10 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)  		zebra_nhe_init(&nhe, afi, ng->nexthop);  		nhe.nhg.nexthop = ng->nexthop;  		nhe.backup_info = bnhg; +		n = zebra_nhe_copy(&nhe, 0);  	} -	ret = rib_add_multipath_nhe(afi, api.safi, &api.prefix, src_p, -				    re, &nhe, false); +	ret = rib_add_multipath_nhe(afi, api.safi, &api.prefix, src_p, re, n, +				    false);  	/*  	 * rib_add_multipath_nhe only fails in a couple spots diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 14e25d16d1..9596783e2b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -81,6 +81,7 @@ DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),  enum meta_queue_indexes {  	META_QUEUE_NHG,  	META_QUEUE_EVPN, +	META_QUEUE_EARLY_ROUTE,  	META_QUEUE_EARLY_LABEL,  	META_QUEUE_CONNECTED,  	META_QUEUE_KERNEL, @@ -194,6 +195,9 @@ struct wq_label_wrapper {  	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 *) @@ -206,6 +210,8 @@ static const char *subqueue2str(enum meta_queue_indexes index)  		return "NHG Objects";  	case META_QUEUE_EVPN:  		return "EVPN/VxLan Objects"; +	case META_QUEUE_EARLY_ROUTE: +		return "Early Route Processing";  	case META_QUEUE_EARLY_LABEL:  		return "Early Label Handling";  	case META_QUEUE_CONNECTED: @@ -2556,6 +2562,460 @@ 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. @@ -2575,6 +3035,9 @@ static unsigned int process_subq(struct list *subq,  	case META_QUEUE_NHG:  		process_subq_nhg(lnode);  		break; +	case META_QUEUE_EARLY_ROUTE: +		process_subq_early_route(lnode); +		break;  	case META_QUEUE_EARLY_LABEL:  		process_subq_early_label(lnode);  		break; @@ -2608,8 +3071,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)) @@ -3056,7 +3520,6 @@ 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.   */ @@ -3174,6 +3637,22 @@ static void rib_meta_queue_free(struct meta_queue *mq, struct list *l,  	}  } +static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, +					struct zebra_vrf *zvrf) +{ +	struct zebra_early_route *zer; +	struct listnode *node, *nnode; + +	for (ALL_LIST_ELEMENTS(l, node, nnode, zer)) { +		if (zvrf && zer->re->vrf_id != zvrf->vrf->vrf_id) +			continue; + +		XFREE(MTYPE_RE, zer); +		node->data = NULL; +		list_delete_node(l, node); +		mq->size--; +	} +}  void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf)  { @@ -3188,6 +3667,9 @@ void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf)  		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; @@ -3334,17 +3816,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   * @@ -3550,6 +4021,22 @@ 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; +} +  /*   * Internal route-add implementation; there are a couple of different public   * signatures. Callers in this path are responsible for the memory they @@ -3565,162 +4052,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); +		ere->src_p = *src_p; +	ere->src_p_provided = !!src_p; +	ere->re = re; +	ere->re_nhe = re_nhe; +	ere->startup = startup; -	/* 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); -	} - -	/* 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);  }  /* @@ -3731,7 +4081,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; @@ -3749,10 +4099,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) @@ -3767,212 +4115,40 @@ 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 = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); +	re->type = type; +	re->instance = instance; +	re->distance = distance; +	re->flags = flags; +	re->metric = metric; +	re->table = table_id; +	re->vrf_id = vrf_id; +	re->uptime = monotime(NULL); +	re->nhe_id = nhe_id; -		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);  } @@ -3983,8 +4159,8 @@ 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)); @@ -4004,15 +4180,12 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,  	 * 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)  | 
