diff options
Diffstat (limited to 'zebra')
| -rw-r--r-- | zebra/fpm_listener.c | 61 | ||||
| -rw-r--r-- | zebra/interface.c | 19 | ||||
| -rw-r--r-- | zebra/interface.h | 4 | ||||
| -rw-r--r-- | zebra/rtadv.c | 61 | ||||
| -rw-r--r-- | zebra/zebra_neigh.c | 10 | ||||
| -rw-r--r-- | zebra/zebra_nhg.c | 62 | ||||
| -rw-r--r-- | zebra/zebra_nhg.h | 1 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 11 | ||||
| -rw-r--r-- | zebra/zebra_srv6.c | 4 | ||||
| -rw-r--r-- | zebra/zebra_vrf.c | 106 | ||||
| -rw-r--r-- | zebra/zebra_vrf.h | 2 | ||||
| -rw-r--r-- | zebra/zebra_vxlan_if.c | 29 | 
12 files changed, 305 insertions, 65 deletions
diff --git a/zebra/fpm_listener.c b/zebra/fpm_listener.c index 140cfa77cf..43ca6e47b8 100644 --- a/zebra/fpm_listener.c +++ b/zebra/fpm_listener.c @@ -44,6 +44,7 @@ struct glob {  	int sock;  	bool reflect;  	bool dump_hex; +	FILE *output_file;  };  struct glob glob_space; @@ -123,13 +124,13 @@ static int accept_conn(int listen_sock)  	while (1) {  		char buf[120]; -		fprintf(stdout, "Waiting for client connection...\n"); +		fprintf(glob->output_file, "Waiting for client connection...\n");  		client_len = sizeof(client_addr);  		sock = accept(listen_sock, (struct sockaddr *)&client_addr,  			      &client_len);  		if (sock >= 0) { -			fprintf(stdout, "Accepted client %s\n", +			fprintf(glob->output_file, "Accepted client %s\n",  				inet_ntop(AF_INET, &client_addr.sin_addr, buf, sizeof(buf)));  			return sock;  		} @@ -172,8 +173,7 @@ read_fpm_msg(char *buf, size_t buf_len)  		bytes_read = read(glob->sock, cur, need_len);  		if (bytes_read == 0) { -			fprintf(stdout, -				"Socket closed as that read returned 0\n"); +			fprintf(glob->output_file, "Socket closed as that read returned 0\n");  			return NULL;  		} @@ -567,7 +567,7 @@ addr_to_s(unsigned char family, void *addr)  }  /* - * netlink_msg_ctx_print + * netlink_msg_ctx_snprint   */  static int netlink_msg_ctx_snprint(struct netlink_msg_ctx *ctx, char *buf,  				   size_t buf_len) @@ -628,7 +628,7 @@ static void print_netlink_msg_ctx(struct netlink_msg_ctx *ctx)  	char buf[1024];  	netlink_msg_ctx_snprint(ctx, buf, sizeof(buf)); -	printf("%s\n", buf); +	fprintf(glob->output_file, "%s\n", buf);  }  static void fpm_listener_hexdump(const void *mem, size_t len) @@ -641,7 +641,7 @@ static void fpm_listener_hexdump(const void *mem, size_t len)  		return;  	if (len == 0) { -		printf("%016lx: (zero length / no data)\n", (long)src); +		fprintf(glob->output_file, "%016lx: (zero length / no data)\n", (long)src);  		return;  	} @@ -654,14 +654,14 @@ static void fpm_listener_hexdump(const void *mem, size_t len)  		const uint8_t *lineend = src + 8;  		uint32_t line_bytes = 0; -		printf("%016lx: ", (long)src); +		fprintf(glob->output_file, "%016lx: ", (long)src);  		while (src < lineend && src < end) { -			printf("%02x ", *src++); +			fprintf(glob->output_file, "%02x ", *src++);  			line_bytes++;  		}  		if (line_bytes < 8) -			printf("%*s", (8 - line_bytes) * 3, ""); +			fprintf(glob->output_file, "%*s", (8 - line_bytes) * 3, "");  		src -= line_bytes;  		while (src < lineend && src < end && fb.pos < fb.buf + fb.len) { @@ -672,7 +672,7 @@ static void fpm_listener_hexdump(const void *mem, size_t len)  			else  				*fb.pos++ = '.';  		} -		printf("\n"); +		fprintf(glob->output_file, "\n");  	}  } @@ -711,20 +711,17 @@ static void parse_netlink_msg(char *buf, size_t buf_len, fpm_msg_hdr_t *fpm)  			if (glob->reflect && hdr->nlmsg_type == RTM_NEWROUTE &&  			    ctx->rtmsg->rtm_protocol > RTPROT_STATIC) { -				printf("  Route %s(%u) reflecting back\n", -				       netlink_prot_to_s( -					       ctx->rtmsg->rtm_protocol), -				       ctx->rtmsg->rtm_protocol); +				fprintf(glob->output_file, "  Route %s(%u) reflecting back\n", +					netlink_prot_to_s(ctx->rtmsg->rtm_protocol), +					ctx->rtmsg->rtm_protocol);  				ctx->rtmsg->rtm_flags |= RTM_F_OFFLOAD;  				write(glob->sock, fpm, fpm_msg_len(fpm));  			}  			break;  		default: -			fprintf(stdout, -				"Ignoring netlink message - Type: %s(%d)\n", -				netlink_msg_type_to_s(hdr->nlmsg_type), -				hdr->nlmsg_type); +			fprintf(glob->output_file, "Ignoring netlink message - Type: %s(%d)\n", +				netlink_msg_type_to_s(hdr->nlmsg_type), hdr->nlmsg_type);  		}  	}  } @@ -734,8 +731,8 @@ static void parse_netlink_msg(char *buf, size_t buf_len, fpm_msg_hdr_t *fpm)   */  static void process_fpm_msg(fpm_msg_hdr_t *hdr)  { -	fprintf(stdout, "FPM message - Type: %d, Length %d\n", hdr->msg_type, -	      ntohs(hdr->msg_len)); +	fprintf(glob->output_file, "FPM message - Type: %d, Length %d\n", hdr->msg_type, +		ntohs(hdr->msg_len));  	if (hdr->msg_type != FPM_MSG_TYPE_NETLINK) {  		fprintf(stderr, "Unknown fpm message type %u\n", hdr->msg_type); @@ -770,12 +767,12 @@ int main(int argc, char **argv)  	pid_t daemon;  	int r;  	bool fork_daemon = false; - -	setbuf(stdout, NULL); +	const char *output_file = NULL;  	memset(glob, 0, sizeof(*glob)); +	glob->output_file = stdout; -	while ((r = getopt(argc, argv, "rdv")) != -1) { +	while ((r = getopt(argc, argv, "rdvo:")) != -1) {  		switch (r) {  		case 'r':  			glob->reflect = true; @@ -786,9 +783,23 @@ int main(int argc, char **argv)  		case 'v':  			glob->dump_hex = true;  			break; +		case 'o': +			output_file = optarg; +			break;  		}  	} +	if (output_file) { +		glob->output_file = fopen(output_file, "w"); +		if (!glob->output_file) { +			fprintf(stderr, "Failed to open output file %s: %s\n", output_file, +				strerror(errno)); +			exit(1); +		} +	} + +	setbuf(glob->output_file, NULL); +  	if (fork_daemon) {  		daemon = fork(); @@ -805,7 +816,7 @@ int main(int argc, char **argv)  	while (1) {  		glob->sock = accept_conn(glob->server_sock);  		fpm_serve(); -		fprintf(stdout, "Done serving client"); +		fprintf(glob->output_file, "Done serving client\n");  	}  }  #else diff --git a/zebra/interface.c b/zebra/interface.c index b7a790382d..fd1ea380a5 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -40,8 +40,8 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information");  #define ZEBRA_PTM_SUPPORT -DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), -	    (vty, ifp)); +DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, json_object *json_if, struct interface *ifp), +	    (vty, json_if, ifp));  DEFINE_MTYPE_STATIC(ZEBRA, ZIF_DESC, "Intf desc"); @@ -1728,7 +1728,7 @@ interface_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx,  		dplane_ctx_get_ifp_vxlan_vni_array(ctx);  	struct zebra_vxlan_vni vni_start, vni_end;  	struct hash *vni_table = NULL; -	struct zebra_vxlan_vni vni, *vnip; +	struct zebra_vxlan_vni vni;  	vni_t vni_id;  	vlanid_t vid;  	int i; @@ -1762,11 +1762,8 @@ interface_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx,  				vni_start.vni, vni_end.vni, ifp->name,  				ifp->ifindex); -		if (!vni_table) { +		if (!vni_table)  			vni_table = zebra_vxlan_vni_table_create(); -			if (!vni_table) -				return; -		}  		for (vid = vni_start.access_vlan, vni_id = vni_start.vni;  		     vid <= vni_end.access_vlan; vid++, vni_id++) { @@ -1774,9 +1771,7 @@ interface_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx,  			memset(&vni, 0, sizeof(vni));  			vni.vni = vni_id;  			vni.access_vlan = vid; -			vnip = hash_get(vni_table, &vni, zebra_vxlan_vni_alloc); -			if (!vnip) -				return; +			(void)hash_get(vni_table, &vni, zebra_vxlan_vni_alloc);  		}  		memset(&vni_start, 0, sizeof(vni_start)); @@ -2851,7 +2846,7 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)  				&iflp->rmt_ip, iflp->rmt_as);  	} -	hook_call(zebra_if_extra_info, vty, ifp); +	hook_call(zebra_if_extra_info, vty, NULL, ifp);  	if (listhead(ifp->nbr_connected))  		vty_out(vty, "  Neighbor address(s):\n"); @@ -3257,6 +3252,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp,  		json_object_int_add(json_te, "neighborAsbrAs", iflp->rmt_as);  	} +	hook_call(zebra_if_extra_info, vty, json_if, ifp); +  	if (listhead(ifp->nbr_connected)) {  		json_object *json_nbr_addrs; diff --git a/zebra/interface.h b/zebra/interface.h index 0f5c997403..5b45656bd5 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -223,8 +223,8 @@ struct zebra_if {  	char *desc;  }; -DECLARE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), -	     (vty, ifp)); +DECLARE_HOOK(zebra_if_extra_info, (struct vty * vty, json_object *json_if, struct interface *ifp), +	     (vty, json_if, ifp));  #define IS_ZEBRA_IF_VRF(ifp)                                                   \  	(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VRF) diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 467bcb6b16..a767bda72e 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -1726,7 +1726,7 @@ int rtadv_dnssl_encode(uint8_t *out, const char *in)  }  /* Dump interface ND information to vty. */ -static int nd_dump_vty(struct vty *vty, struct interface *ifp) +static int nd_dump_vty(struct vty *vty, json_object *json_if, struct interface *ifp)  {  	struct zebra_if *zif;  	struct rtadvconf *rtadv; @@ -1735,7 +1735,7 @@ static int nd_dump_vty(struct vty *vty, struct interface *ifp)  	zif = (struct zebra_if *)ifp->info;  	rtadv = &zif->rtadv; -	if (rtadv->AdvSendAdvertisements) { +	if (!json_if && rtadv->AdvSendAdvertisements) {  		vty_out(vty,  			"  ND advertised reachable time is %d milliseconds\n",  			rtadv->AdvReachableTime); @@ -1792,6 +1792,63 @@ static int nd_dump_vty(struct vty *vty, struct interface *ifp)  			vty_out(vty,  				"  ND router advertisements with Adv. Interval option.\n");  	} + +	if (json_if && rtadv->AdvSendAdvertisements) { +		json_object_int_add(json_if, "ndAdvertisedReachableTimeMsecs", +				    rtadv->AdvReachableTime); +		json_object_int_add(json_if, "ndAdvertisedRetransmitIntervalMsecs", +				    rtadv->AdvRetransTimer); +		json_object_int_add(json_if, "ndAdvertisedHopCountLimitHops", rtadv->AdvCurHopLimit); +		json_object_int_add(json_if, "ndRouterAdvertisementsSent", zif->ra_sent); +		json_object_int_add(json_if, "ndRouterAdvertisementsRcvd", zif->ra_rcvd); + +		interval = rtadv->MaxRtrAdvInterval; +		if (interval % 1000) +			json_object_int_add(json_if, "ndRouterAdvertisementsIntervalMsecs", +					    interval); +		else +			json_object_int_add(json_if, "ndRouterAdvertisementsIntervalSecs", +					    interval / 1000); + +		json_object_boolean_add(json_if, "ndRouterAdvertisementsDoNotUseFastRetransmit", +					!rtadv->UseFastRexmit); + +		if (rtadv->AdvDefaultLifetime != -1) +			json_object_int_add(json_if, "ndRouterAdvertisementsLiveForSecs", +					    rtadv->AdvDefaultLifetime); +		else +			json_object_boolean_add(json_if, +						"ndRouterAdvertisementsLifetimeTracksRaInterval", +						true); + +		json_object_string_add(json_if, "ndRouterAdvertisementDefaultRouterPreference", +				       rtadv_pref_strs[rtadv->DefaultPreference]); + +		if (rtadv->AdvManagedFlag) +			json_object_boolean_add(json_if, "hostsUseDhcpToObtainRoutableAddresses", +						true); +		else +			json_object_boolean_add(json_if, "hostsUseStatelessAutoconfigForAddresses", +						true); + +		if (rtadv->AdvHomeAgentFlag) { +			json_object_boolean_add(json_if, +						"ndRouterAdvertisementsWithHomeAgentFlagBit", true); +			if (rtadv->HomeAgentLifetime != -1) +				json_object_int_add(json_if, "homeAgentLifetimeSecs", +						    rtadv->HomeAgentLifetime); +			else +				json_object_boolean_add(json_if, +							"homeAgentLifetimeTracksRaLifetime", true); + +			json_object_int_add(json_if, "homeAgentPreference", +					    rtadv->HomeAgentLifetime); +		} +		if (rtadv->AdvIntervalOption) +			json_object_boolean_add(json_if, +						"ndRouterAdvertisementsWithAdvIntervalOption", true); +	} +  	return 0;  } diff --git a/zebra/zebra_neigh.c b/zebra/zebra_neigh.c index a222e7f6e8..8a91f2719b 100644 --- a/zebra/zebra_neigh.c +++ b/zebra/zebra_neigh.c @@ -153,14 +153,18 @@ void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip)  /* kernel neigh delete all for a given interface */  void zebra_neigh_del_all(struct interface *ifp)  { -	struct zebra_neigh_ent *n, *nn; +	struct zebra_neigh_ent *n, *next;  	if (IS_ZEBRA_DEBUG_NEIGH)  		zlog_debug("zebra neigh delete all for interface %s/%d",  			   ifp->name, ifp->ifindex); -	RB_FOREACH_SAFE (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, nn) -		zebra_neigh_del(ifp, &n->ip); +	RB_FOREACH_SAFE (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, next) { +		if (n->ifindex == ifp->ifindex) { +			/* Free the neighbor directly instead of looking it up again */ +			zebra_neigh_free(n); +		} +	}  }  /* kernel neigh add */ diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index f5141c8f23..5b7452a79e 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2930,6 +2930,68 @@ static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg)  	return curr_active;  } +void nexthop_vrf_update(struct route_node *rn, struct route_entry *re, vrf_id_t vrf_id) +{ +	struct nhg_hash_entry *curr_nhe, *new_nhe; +	afi_t rt_afi = family2afi(rn->p.family); +	struct nexthop *nexthop; + +	re->vrf_id = vrf_id; + +	/* Make a local copy of the existing nhe, so we don't work on/modify +	 * the shared nhe. +	 */ +	curr_nhe = zebra_nhe_copy(re->nhe, re->nhe->id); + +	if (IS_ZEBRA_DEBUG_NHG_DETAIL) +		zlog_debug("%s: re %p nhe %p (%pNG), curr_nhe %p", __func__, re, re->nhe, re->nhe, +			   curr_nhe); + +	/* Clear the existing id, if any: this will avoid any confusion +	 * if the id exists, and will also force the creation +	 * of a new nhe reflecting the changes we may make in this local copy. +	 */ +	curr_nhe->id = 0; + +	curr_nhe->vrf_id = vrf_id; +	for (ALL_NEXTHOPS(curr_nhe->nhg, nexthop)) { +		if (!nexthop->ifindex) +			/* change VRF ID of nexthop without interfaces +			 * (eg. blackhole) +			 */ +			nexthop->vrf_id = vrf_id; +	} + +	if (zebra_nhg_get_backup_nhg(curr_nhe)) { +		for (ALL_NEXTHOPS(curr_nhe->backup_info->nhe->nhg, nexthop)) { +			if (!nexthop->ifindex) +				/* change VRF ID of nexthop without interfaces +				 * (eg. blackhole) +				 */ +				nexthop->vrf_id = vrf_id; +		} +	} + +	/* +	 * Ref or create an nhe that matches the current state of the +	 * nexthop(s). +	 */ +	new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi); + +	if (IS_ZEBRA_DEBUG_NHG_DETAIL) +		zlog_debug("%s: re %p CHANGED: nhe %p (%pNG) => new_nhe %p (%pNG)", __func__, re, +			   re->nhe, re->nhe, new_nhe, new_nhe); + +	route_entry_update_nhe(re, new_nhe); + +	/* +	 * Do not need the old / copied nhe anymore since it +	 * was either copied over into a new nhe or not +	 * used at all. +	 */ +	zebra_nhg_free(curr_nhe); +} +  /*   * This function takes the start of two comparable nexthops from two different   * nexthop groups and walks them to see if they can be considered the same diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 0f90627a0d..de6f6123aa 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -401,6 +401,7 @@ extern void zebra_nhg_mark_keep(void);  /* Nexthop resolution processing */  struct route_entry; /* Forward ref to avoid circular includes */ +extern void nexthop_vrf_update(struct route_node *rn, struct route_entry *re, vrf_id_t vrf_id);  extern int nexthop_active_update(struct route_node *rn, struct route_entry *re,  				 struct route_entry *old_re); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8cea605f41..20ec25a431 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -903,6 +903,11 @@ void zebra_rtable_node_cleanup(struct route_table *table,  		rib_unlink(node, re);  	} +	zebra_node_info_cleanup(node); +} + +void zebra_node_info_cleanup(struct route_node *node) +{  	if (node->info) {  		rib_dest_t *dest = node->info; @@ -4498,6 +4503,12 @@ rib_update_handle_kernel_route_down_possibility(struct route_node *rn,  	bool alive = false;  	for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { +		if (!nexthop->ifindex) { +			/* blackhole nexthops have no interfaces */ +			alive = true; +			break; +		} +  		struct interface *ifp = if_lookup_by_index(nexthop->ifindex,  							   nexthop->vrf_id); diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 51efcceb75..f9b5dd8808 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -1236,7 +1236,7 @@ static bool alloc_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block,  				zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]",  					  __func__, sid_func, elib_start,  					  elib_end, ewlib_start, ewlib_end); -				return -1; +				return false;  			}  		} else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {  			uint32_t explicit_start = @@ -1395,7 +1395,7 @@ static bool alloc_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block,  			    dynamic_end) {  				zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted",  					  __func__); -				return NULL; +				return false;  			}  			/* diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 7bfe07b4cf..d652c57388 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -162,6 +162,69 @@ static int zebra_vrf_enable(struct vrf *vrf)  	return 0;  } +/* update the VRF ID of a routing table and their routing entries */ +static void zebra_vrf_disable_update_vrfid(struct zebra_vrf *zvrf, afi_t afi, safi_t safi) +{ +	struct rib_table_info *info; +	struct route_entry *re, *nre; +	struct route_node *rn, *nrn; +	bool empty_table = true; +	bool rn_delete; + +	/* Assign the table to the default VRF. +	 * Although the table is not technically owned by the default VRF, +	 * the code assumes that unassigned routing tables are +	 * associated with the default VRF. +	 */ +	info = route_table_get_info(zvrf->table[afi][safi]); +	info->zvrf = vrf_info_lookup(VRF_DEFAULT); + +	rn = route_top(zvrf->table[afi][safi]); +	if (rn) +		empty_table = false; +	while (rn) { +		if (!rn->info) { +			rn = route_next(rn); +			continue; +		} + +		/* Assign the kernel route entries to the default VRF, +		 * even though they are not actually owned by it. +		 * +		 * Remove route nodes that were created by FRR daemons, +		 * unless they are associated with the table rather than the VRF. +		 * Routes associated with the VRF are not needed once the VRF is +		 * disabled. +		 */ +		rn_delete = true; +		RNODE_FOREACH_RE_SAFE (rn, re, nre) { +			if (re->type == ZEBRA_ROUTE_KERNEL || +			    CHECK_FLAG(re->flags, ZEBRA_FLAG_TABLEID)) { +				nexthop_vrf_update(rn, re, VRF_DEFAULT); +				if (CHECK_FLAG(re->flags, ZEBRA_FLAG_TABLEID)) +					/* reinstall routes */ +					rib_install_kernel(rn, re, NULL); +				rn_delete = false; +			} else +				rib_unlink(rn, re); +		} +		if (rn_delete) { +			nrn = route_next(rn); +			zebra_node_info_cleanup(rn); +			rn->info = NULL; +			route_unlock_node(rn); +			rn = nrn; +		} else { +			empty_table = false; +			rn = route_next(rn); +		} +	} + +	if (empty_table) +		zebra_router_release_table(zvrf, zvrf->table_id, afi, safi); +	zvrf->table[afi][safi] = NULL; +} +  /* Callback upon disabling a VRF. */  static int zebra_vrf_disable(struct vrf *vrf)  { @@ -224,9 +287,13 @@ static int zebra_vrf_disable(struct vrf *vrf)  		 * we no-longer need this pointer.  		 */  		for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { -			zebra_router_release_table(zvrf, zvrf->table_id, afi, -						   safi); -			zvrf->table[afi][safi] = NULL; +			if (!zvrf->table[afi][safi] || vrf->vrf_id == VRF_DEFAULT) { +				zebra_router_release_table(zvrf, zvrf->table_id, afi, safi); +				zvrf->table[afi][safi] = NULL; +				continue; +			} + +			zebra_vrf_disable_update_vrfid(zvrf, afi, safi);  		}  	} @@ -357,19 +424,50 @@ static void zebra_rnhtable_node_cleanup(struct route_table *table,  static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,  				   safi_t safi)  { +	vrf_id_t vrf_id = zvrf->vrf->vrf_id; +	struct rib_table_info *info; +	struct route_entry *re;  	struct route_node *rn;  	struct prefix p;  	assert(!zvrf->table[afi][safi]); +	/* Attempt to retrieve the Linux routing table using zvrf->table_id. +	 * If the table was created before the VRF, it will already exist. +	 * Otherwise, create a new table. +	 */  	zvrf->table[afi][safi] =  		zebra_router_get_table(zvrf, zvrf->table_id, afi, safi); +	/* If the table existed before the VRF was created, info->zvrf was +	 * referring to the default VRF. +	 * Assign the table to the new VRF. +	 * Note: FRR does not allow multiple VRF interfaces to be created with the +	 * same table ID. +	 */ +	info = route_table_get_info(zvrf->table[afi][safi]); +	info->zvrf = zvrf; + +	/* If the table existed before the VRF was created, their routing entries +	 * was owned by the default VRF. +	 * Re-assign all the routing entries to the new VRF. +	 */ +	for (rn = route_top(zvrf->table[afi][safi]); rn; rn = route_next(rn)) { +		if (!rn->info) +			continue; + +		RNODE_FOREACH_RE (rn, re) +			nexthop_vrf_update(rn, re, vrf_id); +	} +  	memset(&p, 0, sizeof(p));  	p.family = afi2family(afi); +	/* create a fake default route or get the existing one */  	rn = srcdest_rnode_get(zvrf->table[afi][safi], &p, NULL); -	zebra_rib_create_dest(rn); +	if (!rn->info) +		/* do not override the existing default route */ +		zebra_rib_create_dest(rn);  }  /* Allocate new zebra VRF. */ diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 334bb93684..289a8fcc47 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -263,6 +263,8 @@ extern void zebra_vrf_init(void);  extern void zebra_rtable_node_cleanup(struct route_table *table,  				      struct route_node *node); +extern void zebra_node_info_cleanup(struct route_node *node); +  #ifdef __cplusplus  } diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c index ea0be2f644..4fd9cb6587 100644 --- a/zebra/zebra_vxlan_if.c +++ b/zebra/zebra_vxlan_if.c @@ -54,6 +54,8 @@  #include "zebra/zebra_evpn_vxlan.h"  #include "zebra/zebra_router.h" +DEFINE_MTYPE_STATIC(ZEBRA, L2_VNI, "L2 VNI"); +  static unsigned int zebra_vxlan_vni_hash_keymake(const void *p)  {  	const struct zebra_vxlan_vni *vni; @@ -527,11 +529,7 @@ static int zebra_vxlan_if_add_update_vni(struct zebra_if *zif,  				   old_vni->access_vlan, vni->vni,  				   vni->access_vlan); -		zebra_evpn_vl_vxl_deref(old_vni->access_vlan, old_vni->vni, -					zif); -		zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif); -		zebra_vxlan_if_update_vni(zif->ifp, vni, ctx); -		zebra_vxlan_vni_free(old_vni); +  	} else {  		int ret; @@ -544,19 +542,20 @@ static int zebra_vxlan_if_add_update_vni(struct zebra_if *zif,  			if (IS_ZEBRA_DEBUG_VXLAN)  				zlog_debug("%s vxlan %s vni %u has error accessing bridge table.",  					   __func__, zif->ifp->name, vni->vni); + +			return 0;  		} else if (ret == 0) {  			if (IS_ZEBRA_DEBUG_VXLAN)  				zlog_debug("%s vxlan %s vni (%u, %u) not present in bridge table", -					   __func__, zif->ifp->name, vni->vni, -					   vni->access_vlan); -			zebra_evpn_vl_vxl_deref(old_vni->access_vlan, -						old_vni->vni, zif); -			zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif); -			zebra_vxlan_if_update_vni(zif->ifp, vni, ctx); -			zebra_vxlan_vni_free(old_vni); +					   __func__, zif->ifp->name, vni->vni, vni->access_vlan);  		}  	} +	zebra_evpn_vl_vxl_deref(old_vni->access_vlan, old_vni->vni, zif); +	zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif); +	zebra_vxlan_if_update_vni(zif->ifp, vni, ctx); +	zebra_vxlan_vni_free(old_vni); +  	return 0;  } @@ -608,7 +607,7 @@ void zebra_vxlan_vni_free(void *arg)  	vni = (struct zebra_vxlan_vni *)arg; -	XFREE(MTYPE_TMP, vni); +	XFREE(MTYPE_L2_VNI, vni);  }  void *zebra_vxlan_vni_alloc(void *p) @@ -617,7 +616,7 @@ void *zebra_vxlan_vni_alloc(void *p)  	const struct zebra_vxlan_vni *vnip;  	vnip = (const struct zebra_vxlan_vni *)p; -	vni = XCALLOC(MTYPE_TMP, sizeof(*vni)); +	vni = XCALLOC(MTYPE_L2_VNI, sizeof(*vni));  	vni->vni = vnip->vni;  	vni->access_vlan = vnip->access_vlan;  	vni->mcast_grp = vnip->mcast_grp; @@ -659,8 +658,6 @@ int zebra_vxlan_if_vni_table_create(struct zebra_if *zif)  	vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);  	vni_info->vni_table = zebra_vxlan_vni_table_create(); -	if (!vni_info->vni_table) -		return -ENOMEM;  	return 0;  }  | 
