mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 19:42:14 +00:00 
			
		
		
		
	Merge branch 'stable/3.0'
... with a lot of fixups. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
		
						commit
						9cdce038c5
					
				
							
								
								
									
										65
									
								
								ldpd/l2vpn.c
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								ldpd/l2vpn.c
									
									
									
									
									
								
							| @ -235,6 +235,7 @@ void | ||||
| l2vpn_pw_init(struct l2vpn_pw *pw) | ||||
| { | ||||
| 	struct fec	 fec; | ||||
| 	struct zapi_pw	 zpw; | ||||
| 
 | ||||
| 	l2vpn_pw_reset(pw); | ||||
| 
 | ||||
| @ -242,16 +243,23 @@ l2vpn_pw_init(struct l2vpn_pw *pw) | ||||
| 	lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, | ||||
| 	    0, (void *)pw); | ||||
| 	lde_kernel_update(&fec); | ||||
| 
 | ||||
| 	pw2zpw(pw, &zpw); | ||||
| 	lde_imsg_compose_parent(IMSG_KPW_ADD, 0, &zpw, sizeof(zpw)); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| l2vpn_pw_exit(struct l2vpn_pw *pw) | ||||
| { | ||||
| 	struct fec	 fec; | ||||
| 	struct zapi_pw	 zpw; | ||||
| 
 | ||||
| 	l2vpn_pw_fec(pw, &fec); | ||||
| 	lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0); | ||||
| 	lde_kernel_update(&fec); | ||||
| 
 | ||||
| 	pw2zpw(pw, &zpw); | ||||
| 	lde_imsg_compose_parent(IMSG_KPW_DELETE, 0, &zpw, sizeof(zpw)); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| @ -269,7 +277,8 @@ l2vpn_pw_reset(struct l2vpn_pw *pw) | ||||
| { | ||||
| 	pw->remote_group = 0; | ||||
| 	pw->remote_mtu = 0; | ||||
| 	pw->remote_status = 0; | ||||
| 	pw->local_status = PW_FORWARDING; | ||||
| 	pw->remote_status = PW_NOT_FORWARDING; | ||||
| 
 | ||||
| 	if (pw->flags & F_PW_CWORD_CONF) | ||||
| 		pw->flags |= F_PW_CWORD; | ||||
| @ -475,6 +484,56 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int | ||||
| l2vpn_pw_status_update(struct zapi_pw_status *zpw) | ||||
| { | ||||
| 	struct l2vpn		*l2vpn; | ||||
| 	struct l2vpn_pw		*pw = NULL; | ||||
| 	struct lde_nbr		*ln; | ||||
| 	struct fec		 fec; | ||||
| 	uint32_t		 local_status; | ||||
| 
 | ||||
| 	RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) { | ||||
| 		pw = l2vpn_pw_find(l2vpn, zpw->ifname); | ||||
| 		if (pw) | ||||
| 			break; | ||||
| 	} | ||||
| 	if (!pw) { | ||||
| 		log_warnx("%s: pseudowire %s not found", __func__, zpw->ifname); | ||||
| 		return (1); | ||||
| 	} | ||||
| 
 | ||||
| 	if (zpw->status == PW_STATUS_UP) | ||||
| 		local_status = PW_FORWARDING; | ||||
| 	else | ||||
| 		local_status = PW_NOT_FORWARDING; | ||||
| 
 | ||||
| 	/* local status didn't change */ | ||||
| 	if (pw->local_status == local_status) | ||||
| 		return (0); | ||||
| 	pw->local_status = local_status; | ||||
| 
 | ||||
| 	/* notify remote peer about the status update */ | ||||
| 	ln = lde_nbr_find_by_lsrid(pw->lsr_id); | ||||
| 	if (ln == NULL) | ||||
| 		return (0); | ||||
| 	l2vpn_pw_fec(pw, &fec); | ||||
| 	if (pw->flags & F_PW_STATUSTLV) | ||||
| 		l2vpn_send_pw_status(ln, local_status, &fec); | ||||
| 	else { | ||||
| 		struct fec_node *fn; | ||||
| 		fn = (struct fec_node *)fec_find(&ft, &fec); | ||||
| 		if (fn) { | ||||
| 			if (pw->local_status == PW_FORWARDING) | ||||
| 				lde_send_labelmapping(ln, fn, 1); | ||||
| 			else | ||||
| 				lde_send_labelwithdraw(ln, fn, NULL, NULL); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return (0); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| l2vpn_pw_ctl(pid_t pid) | ||||
| { | ||||
| @ -491,7 +550,9 @@ l2vpn_pw_ctl(pid_t pid) | ||||
| 			    sizeof(pwctl.ifname)); | ||||
| 			pwctl.pwid = pw->pwid; | ||||
| 			pwctl.lsr_id = pw->lsr_id; | ||||
| 			pwctl.status = pw->flags & F_PW_STATUS_UP; | ||||
| 			if (pw->local_status == PW_FORWARDING && | ||||
| 			    pw->remote_status == PW_FORWARDING) | ||||
| 				pwctl.status = 1; | ||||
| 
 | ||||
| 			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0, | ||||
| 			    pid, &pwctl, sizeof(pwctl)); | ||||
|  | ||||
							
								
								
									
										60
									
								
								ldpd/lde.c
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								ldpd/lde.c
									
									
									
									
									
								
							| @ -472,6 +472,15 @@ lde_dispatch_parent(struct thread *thread) | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 		case IMSG_PW_UPDATE: | ||||
| 			if (imsg.hdr.len != IMSG_HEADER_SIZE + | ||||
| 			    sizeof(struct zapi_pw_status)) | ||||
| 				fatalx("PW_UPDATE imsg with wrong len"); | ||||
| 
 | ||||
| 			if (l2vpn_pw_status_update(imsg.data) != 0) | ||||
| 				log_warnx("%s: error updating PW status", | ||||
| 				    __func__); | ||||
| 			break; | ||||
| 		case IMSG_NETWORK_ADD: | ||||
| 		case IMSG_NETWORK_UPDATE: | ||||
| 			if (imsg.hdr.len != IMSG_HEADER_SIZE + | ||||
| @ -712,8 +721,8 @@ lde_update_label(struct fec_node *fn) | ||||
| void | ||||
| lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) | ||||
| { | ||||
| 	struct kroute	kr; | ||||
| 	struct kpw	kpw; | ||||
| 	struct kroute	 kr; | ||||
| 	struct zapi_pw	 zpw; | ||||
| 	struct l2vpn_pw	*pw; | ||||
| 
 | ||||
| 	switch (fn->fec.type) { | ||||
| @ -751,19 +760,10 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) | ||||
| 			return; | ||||
| 
 | ||||
| 		pw = (struct l2vpn_pw *) fn->data; | ||||
| 		pw->flags |= F_PW_STATUS_UP; | ||||
| 
 | ||||
| 		memset(&kpw, 0, sizeof(kpw)); | ||||
| 		kpw.ifindex = pw->ifindex; | ||||
| 		kpw.pw_type = fn->fec.u.pwid.type; | ||||
| 		kpw.af = pw->af; | ||||
| 		kpw.nexthop = pw->addr; | ||||
| 		kpw.local_label = fn->local_label; | ||||
| 		kpw.remote_label = fnh->remote_label; | ||||
| 		kpw.flags = pw->flags; | ||||
| 
 | ||||
| 		lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw, | ||||
| 		    sizeof(kpw)); | ||||
| 		pw2zpw(pw, &zpw); | ||||
| 		zpw.local_label = fn->local_label; | ||||
| 		zpw.remote_label = fnh->remote_label; | ||||
| 		lde_imsg_compose_parent(IMSG_KPW_SET, 0, &zpw, sizeof(zpw)); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| @ -772,7 +772,7 @@ void | ||||
| lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) | ||||
| { | ||||
| 	struct kroute	 kr; | ||||
| 	struct kpw	 kpw; | ||||
| 	struct zapi_pw	 zpw; | ||||
| 	struct l2vpn_pw	*pw; | ||||
| 
 | ||||
| 	switch (fn->fec.type) { | ||||
| @ -806,21 +806,10 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) | ||||
| 		break; | ||||
| 	case FEC_TYPE_PWID: | ||||
| 		pw = (struct l2vpn_pw *) fn->data; | ||||
| 		if (!(pw->flags & F_PW_STATUS_UP)) | ||||
| 			return; | ||||
| 		pw->flags &= ~F_PW_STATUS_UP; | ||||
| 
 | ||||
| 		memset(&kpw, 0, sizeof(kpw)); | ||||
| 		kpw.ifindex = pw->ifindex; | ||||
| 		kpw.pw_type = fn->fec.u.pwid.type; | ||||
| 		kpw.af = pw->af; | ||||
| 		kpw.nexthop = pw->addr; | ||||
| 		kpw.local_label = fn->local_label; | ||||
| 		kpw.remote_label = fnh->remote_label; | ||||
| 		kpw.flags = pw->flags; | ||||
| 
 | ||||
| 		lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw, | ||||
| 		    sizeof(kpw)); | ||||
| 		pw2zpw(pw, &zpw); | ||||
| 		zpw.local_label = fn->local_label; | ||||
| 		zpw.remote_label = fnh->remote_label; | ||||
| 		lde_imsg_compose_parent(IMSG_KPW_UNSET, 0, &zpw, sizeof(zpw)); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| @ -901,8 +890,12 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) | ||||
| 	 */ | ||||
| 	lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); | ||||
| 	if (lw) { | ||||
| 		if (!fec_find(&ln->sent_map_pending, &fn->fec)) | ||||
| 		if (!fec_find(&ln->sent_map_pending, &fn->fec)) { | ||||
| 			debug_evt("%s: FEC %s: scheduling to send label " | ||||
| 			    "mapping later (waiting for pending label release)", | ||||
| 			    __func__, log_fec(&fn->fec)); | ||||
| 			lde_map_pending_add(ln, fn); | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| @ -948,8 +941,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) | ||||
| 			map.flags |= F_MAP_PW_CWORD; | ||||
| 		if (pw->flags & F_PW_STATUSTLV) { | ||||
| 			map.flags |= F_MAP_PW_STATUS; | ||||
| 			/* VPLS are always up */ | ||||
| 			map.pw_status = PW_FORWARDING; | ||||
| 			map.pw_status = pw->local_status; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| @ -238,6 +238,7 @@ void		 l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t, | ||||
| void		 l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *); | ||||
| void		 l2vpn_recv_pw_status_wcard(struct lde_nbr *, | ||||
| 		    struct notify_msg *); | ||||
| int 		 l2vpn_pw_status_update(struct zapi_pw_status *); | ||||
| void		 l2vpn_pw_ctl(pid_t); | ||||
| void		 l2vpn_binding_ctl(pid_t); | ||||
| 
 | ||||
|  | ||||
| @ -396,8 +396,7 @@ lde_kernel_update(struct fec *fec) | ||||
| 		lde_gc_start_timer(); | ||||
| 	} else { | ||||
| 		fn->local_label = lde_update_label(fn); | ||||
| 		if (fn->local_label != NO_LABEL && | ||||
| 		    RB_EMPTY(lde_map_head, &fn->upstream)) | ||||
| 		if (fn->local_label != NO_LABEL) | ||||
| 			/* FEC.1: perform lsr label distribution procedure */ | ||||
| 			RB_FOREACH(ln, nbr_tree, &lde_nbrs) | ||||
| 				lde_send_labelmapping(ln, fn, 1); | ||||
| @ -531,6 +530,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) | ||||
| 				pw->remote_mtu = map->fec.pwid.ifmtu; | ||||
| 			if (map->flags & F_MAP_PW_STATUS) | ||||
| 				pw->remote_status = map->pw_status; | ||||
| 			else | ||||
| 				pw->remote_status = PW_FORWARDING; | ||||
| 			fnh->remote_label = map->label; | ||||
| 			if (l2vpn_pw_ok(pw, fnh)) | ||||
| 				lde_send_change_klabel(fn, fnh); | ||||
| @ -774,6 +775,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) | ||||
| 			pw = (struct l2vpn_pw *) fn->data; | ||||
| 			if (pw == NULL) | ||||
| 				continue; | ||||
| 			pw->remote_status = PW_NOT_FORWARDING; | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| @ -802,6 +804,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) | ||||
| 	struct fec_node	*fn; | ||||
| 	struct fec_nh	*fnh; | ||||
| 	struct lde_map	*me; | ||||
| 	struct l2vpn_pw	*pw; | ||||
| 
 | ||||
| 	/* LWd.2: send label release */ | ||||
| 	lde_send_labelrelease(ln, NULL, map, map->label); | ||||
| @ -825,6 +828,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) | ||||
| 			case FEC_TYPE_PWID: | ||||
| 				if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr) | ||||
| 					continue; | ||||
| 				pw = (struct l2vpn_pw *) fn->data; | ||||
| 				if (pw) | ||||
| 					pw->remote_status = PW_NOT_FORWARDING; | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
|  | ||||
| @ -285,9 +285,6 @@ struct address_list_tlv { | ||||
| #define	MAP_TYPE_GENPWID	0x81 | ||||
| 
 | ||||
| #define CONTROL_WORD_FLAG	0x8000 | ||||
| #define PW_TYPE_ETHERNET_TAGGED	0x0004 | ||||
| #define PW_TYPE_ETHERNET	0x0005 | ||||
| #define PW_TYPE_WILDCARD	0x7FFF | ||||
| #define DEFAULT_PW_TYPE		PW_TYPE_ETHERNET | ||||
| 
 | ||||
| #define PW_TWCARD_RESERVED_BIT	0x8000 | ||||
|  | ||||
| @ -52,6 +52,8 @@ static int	 ldp_interface_address_delete(int, struct zclient *, | ||||
| 		    zebra_size_t, vrf_id_t); | ||||
| static int	 ldp_zebra_read_route(int, struct zclient *, zebra_size_t, | ||||
| 		    vrf_id_t); | ||||
| static int	 ldp_zebra_read_pw_status_update(int, struct zclient *, | ||||
| 		    zebra_size_t, vrf_id_t); | ||||
| static void	 ldp_zebra_connected(struct zclient *); | ||||
| 
 | ||||
| static struct zclient	*zclient; | ||||
| @ -92,6 +94,25 @@ ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
| pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw) | ||||
| { | ||||
| 	memset(zpw, 0, sizeof(*zpw)); | ||||
| 	strlcpy(zpw->ifname, pw->ifname, sizeof(zpw->ifname)); | ||||
| 	zpw->ifindex = pw->ifindex; | ||||
| 	zpw->type = pw->l2vpn->pw_type; | ||||
| 	zpw->af = pw->af; | ||||
| 	zpw->nexthop.ipv6 = pw->addr.v6; | ||||
| 	zpw->local_label = NO_LABEL; | ||||
| 	zpw->remote_label = NO_LABEL; | ||||
| 	if (pw->flags & F_PW_CWORD) | ||||
| 		zpw->flags = F_PSEUDOWIRE_CWORD; | ||||
| 	zpw->data.ldp.lsr_id = pw->lsr_id; | ||||
| 	zpw->data.ldp.pwid = pw->pwid; | ||||
| 	strlcpy(zpw->data.ldp.vpn_name, pw->l2vpn->name, | ||||
| 	    sizeof(zpw->data.ldp.vpn_name)); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| zebra_send_mpls_labels(int cmd, struct kroute *kr) | ||||
| { | ||||
| @ -152,17 +173,40 @@ kr_delete(struct kroute *kr) | ||||
| } | ||||
| 
 | ||||
| int | ||||
| kmpw_set(struct kpw *kpw) | ||||
| kmpw_add(struct zapi_pw *zpw) | ||||
| { | ||||
| 	/* TODO */ | ||||
| 	return (0); | ||||
| 	debug_zebra_out("pseudowire %s nexthop %s (add)", | ||||
| 	    zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); | ||||
| 
 | ||||
| 	return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw)); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| kmpw_unset(struct kpw *kpw) | ||||
| kmpw_del(struct zapi_pw *zpw) | ||||
| { | ||||
| 	/* TODO */ | ||||
| 	return (0); | ||||
| 	debug_zebra_out("pseudowire %s nexthop %s (del)", | ||||
| 	    zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); | ||||
| 
 | ||||
| 	return (zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw)); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| kmpw_set(struct zapi_pw *zpw) | ||||
| { | ||||
| 	debug_zebra_out("pseudowire %s nexthop %s labels %u/%u (set)", | ||||
| 	    zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop), | ||||
| 	    zpw->local_label, zpw->remote_label); | ||||
| 
 | ||||
| 	return (zebra_send_pw(zclient, ZEBRA_PW_SET, zpw)); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| kmpw_unset(struct zapi_pw *zpw) | ||||
| { | ||||
| 	debug_zebra_out("pseudowire %s nexthop %s (unset)", | ||||
| 	    zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); | ||||
| 
 | ||||
| 	return (zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw)); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| @ -464,6 +508,25 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, | ||||
| 	return (0); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Receive PW status update from Zebra and send it to LDE process. | ||||
|  */ | ||||
| static int | ||||
| ldp_zebra_read_pw_status_update(int command, struct zclient *zclient, | ||||
|     zebra_size_t length, vrf_id_t vrf_id) | ||||
| { | ||||
| 	struct zapi_pw_status	 zpw; | ||||
| 
 | ||||
| 	zebra_read_pw_status_update(command, zclient, length, vrf_id, &zpw); | ||||
| 
 | ||||
| 	debug_zebra_in("pseudowire %s status %s", zpw.ifname, | ||||
| 	    (zpw.status == PW_STATUS_UP) ? "up" : "down"); | ||||
| 
 | ||||
| 	main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &zpw, sizeof(zpw)); | ||||
| 
 | ||||
| 	return (0); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| ldp_zebra_connected(struct zclient *zclient) | ||||
| { | ||||
| @ -494,6 +557,7 @@ ldp_zebra_init(struct thread_master *master) | ||||
| 	zclient->redistribute_route_ipv4_del = ldp_zebra_read_route; | ||||
| 	zclient->redistribute_route_ipv6_add = ldp_zebra_read_route; | ||||
| 	zclient->redistribute_route_ipv6_del = ldp_zebra_read_route; | ||||
| 	zclient->pw_status_update = ldp_zebra_read_pw_status_update; | ||||
| } | ||||
| 
 | ||||
| void | ||||
|  | ||||
							
								
								
									
										41
									
								
								ldpd/ldpd.c
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								ldpd/ldpd.c
									
									
									
									
									
								
							| @ -578,21 +578,36 @@ main_dispatch_lde(struct thread *thread) | ||||
| 			if (kr_delete(imsg.data)) | ||||
| 				log_warnx("%s: error deleting route", __func__); | ||||
| 			break; | ||||
| 		case IMSG_KPWLABEL_CHANGE: | ||||
| 		case IMSG_KPW_ADD: | ||||
| 		case IMSG_KPW_DELETE: | ||||
| 		case IMSG_KPW_SET: | ||||
| 		case IMSG_KPW_UNSET: | ||||
| 			if (imsg.hdr.len - IMSG_HEADER_SIZE != | ||||
| 			    sizeof(struct kpw)) | ||||
| 			    sizeof(struct zapi_pw)) | ||||
| 				fatalx("invalid size of IMSG_KPWLABEL_CHANGE"); | ||||
| 			if (kmpw_set(imsg.data)) | ||||
| 				log_warnx("%s: error changing pseudowire", | ||||
| 				    __func__); | ||||
| 			break; | ||||
| 		case IMSG_KPWLABEL_DELETE: | ||||
| 			if (imsg.hdr.len - IMSG_HEADER_SIZE != | ||||
| 			    sizeof(struct kpw)) | ||||
| 				fatalx("invalid size of IMSG_KPWLABEL_DELETE"); | ||||
| 			if (kmpw_unset(imsg.data)) | ||||
| 				log_warnx("%s: error unsetting pseudowire", | ||||
| 				    __func__); | ||||
| 
 | ||||
| 			switch (imsg.hdr.type) { | ||||
| 			case IMSG_KPW_ADD: | ||||
| 				if (kmpw_add(imsg.data)) | ||||
| 					log_warnx("%s: error adding " | ||||
| 					    "pseudowire", __func__); | ||||
| 				break; | ||||
| 			case IMSG_KPW_DELETE: | ||||
| 				if (kmpw_del(imsg.data)) | ||||
| 					log_warnx("%s: error deleting " | ||||
| 					    "pseudowire", __func__); | ||||
| 				break; | ||||
| 			case IMSG_KPW_SET: | ||||
| 				if (kmpw_set(imsg.data)) | ||||
| 					log_warnx("%s: error setting " | ||||
| 					    "pseudowire", __func__); | ||||
| 				break; | ||||
| 			case IMSG_KPW_UNSET: | ||||
| 				if (kmpw_unset(imsg.data)) | ||||
| 					log_warnx("%s: error unsetting " | ||||
| 					    "pseudowire", __func__); | ||||
| 				break; | ||||
| 			} | ||||
| 			break; | ||||
| 		case IMSG_ACL_CHECK: | ||||
| 			if (imsg.hdr.len != IMSG_HEADER_SIZE + | ||||
|  | ||||
							
								
								
									
										33
									
								
								ldpd/ldpd.h
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								ldpd/ldpd.h
									
									
									
									
									
								
							| @ -30,6 +30,8 @@ | ||||
| #include "prefix.h" | ||||
| #include "filter.h" | ||||
| #include "vty.h" | ||||
| #include "pw.h" | ||||
| #include "zclient.h" | ||||
| 
 | ||||
| #include "ldp.h" | ||||
| 
 | ||||
| @ -44,7 +46,6 @@ | ||||
| #define LDPD_OPT_NOACTION	0x00000004 | ||||
| 
 | ||||
| #define TCP_MD5_KEY_LEN		80 | ||||
| #define L2VPN_NAME_LEN		32 | ||||
| 
 | ||||
| #define	RT_BUF_SIZE		16384 | ||||
| #define	MAX_RTSOCK_BUF		128 * 1024 | ||||
| @ -102,8 +103,10 @@ enum imsg_type { | ||||
| 	IMSG_CTL_LOG_VERBOSE, | ||||
| 	IMSG_KLABEL_CHANGE, | ||||
| 	IMSG_KLABEL_DELETE, | ||||
| 	IMSG_KPWLABEL_CHANGE, | ||||
| 	IMSG_KPWLABEL_DELETE, | ||||
| 	IMSG_KPW_ADD, | ||||
| 	IMSG_KPW_DELETE, | ||||
| 	IMSG_KPW_SET, | ||||
| 	IMSG_KPW_UNSET, | ||||
| 	IMSG_IFSTATUS, | ||||
| 	IMSG_NEWADDR, | ||||
| 	IMSG_DELADDR, | ||||
| @ -147,7 +150,8 @@ enum imsg_type { | ||||
| 	IMSG_DEBUG_UPDATE, | ||||
| 	IMSG_LOG, | ||||
| 	IMSG_ACL_CHECK, | ||||
| 	IMSG_INIT | ||||
| 	IMSG_INIT, | ||||
| 	IMSG_PW_UPDATE | ||||
| }; | ||||
| 
 | ||||
| struct ldpd_init { | ||||
| @ -407,6 +411,7 @@ struct l2vpn_pw { | ||||
| 	unsigned int		 ifindex; | ||||
| 	uint32_t		 remote_group; | ||||
| 	uint16_t		 remote_mtu; | ||||
| 	uint32_t		 local_status; | ||||
| 	uint32_t		 remote_status; | ||||
| 	uint8_t			 flags; | ||||
| 	QOBJ_FIELDS | ||||
| @ -418,8 +423,7 @@ DECLARE_QOBJ_TYPE(l2vpn_pw) | ||||
| #define F_PW_STATUSTLV		0x02	/* status tlv negotiated */ | ||||
| #define F_PW_CWORD_CONF		0x04	/* control word configured */ | ||||
| #define F_PW_CWORD		0x08	/* control word negotiated */ | ||||
| #define F_PW_STATUS_UP		0x10	/* pseudowire is operational */ | ||||
| #define F_PW_STATIC_NBR_ADDR	0x20	/* static neighbor address configured */ | ||||
| #define F_PW_STATIC_NBR_ADDR	0x10	/* static neighbor address configured */ | ||||
| 
 | ||||
| struct l2vpn { | ||||
| 	RB_ENTRY(l2vpn)		 entry; | ||||
| @ -542,16 +546,6 @@ struct kroute { | ||||
| 	uint16_t		 flags; | ||||
| }; | ||||
| 
 | ||||
| struct kpw { | ||||
| 	unsigned short		 ifindex; | ||||
| 	int			 pw_type; | ||||
| 	int			 af; | ||||
| 	union ldpd_addr		 nexthop; | ||||
| 	uint32_t		 local_label; | ||||
| 	uint32_t		 remote_label; | ||||
| 	uint8_t			 flags; | ||||
| }; | ||||
| 
 | ||||
| struct kaddr { | ||||
| 	char			 ifname[IF_NAMESIZE]; | ||||
| 	unsigned short		 ifindex; | ||||
| @ -668,11 +662,14 @@ struct ldpd_conf	*parse_config(char *); | ||||
| int			 cmdline_symset(char *); | ||||
| 
 | ||||
| /* kroute.c */ | ||||
| void		 pw2zpw(struct l2vpn_pw *, struct zapi_pw *); | ||||
| void		 kif_redistribute(const char *); | ||||
| int		 kr_change(struct kroute *); | ||||
| int		 kr_delete(struct kroute *); | ||||
| int		 kmpw_set(struct kpw *); | ||||
| int		 kmpw_unset(struct kpw *); | ||||
| int		 kmpw_add(struct zapi_pw *); | ||||
| int		 kmpw_del(struct zapi_pw *); | ||||
| int		 kmpw_set(struct zapi_pw *); | ||||
| int		 kmpw_unset(struct zapi_pw *); | ||||
| 
 | ||||
| /* util.c */ | ||||
| uint8_t		 mask2prefixlen(in_addr_t); | ||||
|  | ||||
| @ -289,6 +289,8 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr, | ||||
| void | ||||
| nbr_del(struct nbr *nbr) | ||||
| { | ||||
| 	struct adj		*adj; | ||||
| 
 | ||||
| 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); | ||||
| 
 | ||||
| 	nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); | ||||
| @ -314,6 +316,11 @@ nbr_del(struct nbr *nbr) | ||||
| 	mapping_list_clr(&nbr->release_list); | ||||
| 	mapping_list_clr(&nbr->abortreq_list); | ||||
| 
 | ||||
| 	while ((adj = RB_ROOT(nbr_adj_head, &nbr->adj_tree)) != NULL) { | ||||
| 		adj->nbr = NULL; | ||||
| 		RB_REMOVE(nbr_adj_head, &nbr->adj_tree, adj); | ||||
| 	} | ||||
| 
 | ||||
| 	if (nbr->peerid) | ||||
| 		RB_REMOVE(nbr_pid_head, &nbrs_by_pid, nbr); | ||||
| 	RB_REMOVE(nbr_id_head, &nbrs_by_id, nbr); | ||||
|  | ||||
| @ -110,6 +110,7 @@ const char *node_names[] = { | ||||
| 	"forwarding",		    // FORWARDING_NODE,
 | ||||
| 	"protocol",		    // PROTOCOL_NODE,
 | ||||
| 	"mpls",			    // MPLS_NODE,
 | ||||
| 	"pw",			    // PW_NODE,
 | ||||
| 	"vty",			    // VTY_NODE,
 | ||||
| 	"link-params",		    // LINK_PARAMS_NODE,
 | ||||
| 	"bgp evpn vni",		    // BGP_EVPN_VNI_NODE,
 | ||||
| @ -1253,6 +1254,7 @@ void cmd_exit(struct vty *vty) | ||||
| 		vty_config_unlock(vty); | ||||
| 		break; | ||||
| 	case INTERFACE_NODE: | ||||
| 	case PW_NODE: | ||||
| 	case NS_NODE: | ||||
| 	case VRF_NODE: | ||||
| 	case ZEBRA_NODE: | ||||
| @ -1338,6 +1340,7 @@ DEFUN (config_end, | ||||
| 		break; | ||||
| 	case CONFIG_NODE: | ||||
| 	case INTERFACE_NODE: | ||||
| 	case PW_NODE: | ||||
| 	case NS_NODE: | ||||
| 	case VRF_NODE: | ||||
| 	case ZEBRA_NODE: | ||||
|  | ||||
| @ -132,6 +132,7 @@ enum node_type { | ||||
| 	FORWARDING_NODE,	/* IP forwarding node. */ | ||||
| 	PROTOCOL_NODE,		/* protocol filtering node */ | ||||
| 	MPLS_NODE,		/* MPLS config node */ | ||||
| 	PW_NODE,		/* Pseudowire config node */ | ||||
| 	VTY_NODE,		/* Vty node. */ | ||||
| 	LINK_PARAMS_NODE,       /* Link-parameters node */ | ||||
| 	BGP_EVPN_VNI_NODE,      /* BGP EVPN VNI */ | ||||
|  | ||||
| @ -34,7 +34,7 @@ | ||||
| 
 | ||||
| /* Architectual Constants */ | ||||
| #ifdef DEBUG | ||||
| #define OSPF_LS_REFRESH_TIME                    60 | ||||
| #define OSPF_LS_REFRESH_TIME                   120 | ||||
| #else | ||||
| #define OSPF_LS_REFRESH_TIME                  1800 | ||||
| #endif | ||||
|  | ||||
| @ -916,6 +916,11 @@ static const struct zebra_desc_table command_types[] = { | ||||
| 	DESC_ENTRY(ZEBRA_MACIP_DEL), | ||||
| 	DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD), | ||||
| 	DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL), | ||||
| 	DESC_ENTRY(ZEBRA_PW_ADD), | ||||
| 	DESC_ENTRY(ZEBRA_PW_DELETE), | ||||
| 	DESC_ENTRY(ZEBRA_PW_SET), | ||||
| 	DESC_ENTRY(ZEBRA_PW_UNSET), | ||||
| 	DESC_ENTRY(ZEBRA_PW_STATUS_UPDATE), | ||||
| }; | ||||
| #undef DESC_ENTRY | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										52
									
								
								lib/pw.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								lib/pw.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| /* Pseudowire definitions
 | ||||
|  * Copyright (C) 2016 Volta Networks, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; see the file COPYING; if not, write to the | ||||
|  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | ||||
|  * MA 02110-1301 USA | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _FRR_PW_H | ||||
| #define _FRR_PW_H | ||||
| 
 | ||||
| /* L2VPN name length. */ | ||||
| #define L2VPN_NAME_LEN		32 | ||||
| 
 | ||||
| /* Pseudowire type - LDP and BGP use the same values. */ | ||||
| #define PW_TYPE_ETHERNET_TAGGED	0x0004	/* RFC 4446 */ | ||||
| #define PW_TYPE_ETHERNET	0x0005	/* RFC 4446 */ | ||||
| #define PW_TYPE_WILDCARD	0x7FFF	/* RFC 4863, RFC 6668 */ | ||||
| 
 | ||||
| /* Pseudowire flags. */ | ||||
| #define F_PSEUDOWIRE_CWORD	0x01 | ||||
| 
 | ||||
| /* Pseudowire status. */ | ||||
| #define PW_STATUS_DOWN		0 | ||||
| #define PW_STATUS_UP		1 | ||||
| 
 | ||||
| /*
 | ||||
|  * Protocol-specific information about the pseudowire. | ||||
|  */ | ||||
| union pw_protocol_fields { | ||||
| 	struct { | ||||
| 		struct in_addr lsr_id; | ||||
| 		uint32_t pwid; | ||||
| 		char vpn_name[L2VPN_NAME_LEN]; | ||||
| 	} ldp; | ||||
| 	struct { | ||||
| 		/* TODO */ | ||||
| 	} bgp; | ||||
| }; | ||||
| 
 | ||||
| #endif /* _FRR_PW_H */ | ||||
| @ -123,6 +123,7 @@ pkginclude_HEADERS += \ | ||||
| 	lib/prefix.h \ | ||||
| 	lib/privs.h \ | ||||
| 	lib/ptm_lib.h \ | ||||
| 	lib/pw.h \ | ||||
| 	lib/qobj.h \ | ||||
| 	lib/route_types.h \ | ||||
| 	lib/routemap.h \ | ||||
|  | ||||
| @ -684,6 +684,7 @@ static void vty_end_config(struct vty *vty) | ||||
| 		break; | ||||
| 	case CONFIG_NODE: | ||||
| 	case INTERFACE_NODE: | ||||
| 	case PW_NODE: | ||||
| 	case ZEBRA_NODE: | ||||
| 	case RIP_NODE: | ||||
| 	case RIPNG_NODE: | ||||
| @ -1094,6 +1095,7 @@ static void vty_stop_input(struct vty *vty) | ||||
| 		break; | ||||
| 	case CONFIG_NODE: | ||||
| 	case INTERFACE_NODE: | ||||
| 	case PW_NODE: | ||||
| 	case ZEBRA_NODE: | ||||
| 	case RIP_NODE: | ||||
| 	case RIPNG_NODE: | ||||
|  | ||||
| @ -1834,6 +1834,69 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw) | ||||
| { | ||||
| 	struct stream *s; | ||||
| 
 | ||||
| 	/* Reset stream. */ | ||||
| 	s = zclient->obuf; | ||||
| 	stream_reset(s); | ||||
| 
 | ||||
| 	zclient_create_header(s, command, VRF_DEFAULT); | ||||
| 	stream_write(s, pw->ifname, IF_NAMESIZE); | ||||
| 	stream_putl(s, pw->ifindex); | ||||
| 
 | ||||
| 	/* Put type */ | ||||
| 	stream_putl(s, pw->type); | ||||
| 
 | ||||
| 	/* Put nexthop */ | ||||
| 	stream_putl(s, pw->af); | ||||
| 	switch (pw->af) { | ||||
| 	case AF_INET: | ||||
| 		stream_put_in_addr(s, &pw->nexthop.ipv4); | ||||
| 		break; | ||||
| 	case AF_INET6: | ||||
| 		stream_write(s, (u_char *)&pw->nexthop.ipv6, 16); | ||||
| 		break; | ||||
| 	default: | ||||
| 		zlog_err("%s: unknown af", __func__); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Put labels */ | ||||
| 	stream_putl(s, pw->local_label); | ||||
| 	stream_putl(s, pw->remote_label); | ||||
| 
 | ||||
| 	/* Put flags */ | ||||
| 	stream_putc(s, pw->flags); | ||||
| 
 | ||||
| 	/* Protocol specific fields */ | ||||
| 	stream_write(s, &pw->data, sizeof(union pw_protocol_fields)); | ||||
| 
 | ||||
| 	/* Put length at the first point of the stream. */ | ||||
| 	stream_putw_at(s, 0, stream_get_endp(s)); | ||||
| 
 | ||||
| 	return zclient_send_message(zclient); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Receive PW status update from Zebra and send it to LDE process. | ||||
|  */ | ||||
| void zebra_read_pw_status_update(int command, struct zclient *zclient, | ||||
| 				 zebra_size_t length, vrf_id_t vrf_id, | ||||
| 				 struct zapi_pw_status *pw) | ||||
| { | ||||
| 	struct stream *s; | ||||
| 
 | ||||
| 	memset(pw, 0, sizeof(struct zapi_pw_status)); | ||||
| 	s = zclient->ibuf; | ||||
| 
 | ||||
| 	/* Get data. */ | ||||
| 	stream_get(pw->ifname, s, IF_NAMESIZE); | ||||
| 	pw->ifindex = stream_getl(s); | ||||
| 	pw->status = stream_getl(s); | ||||
| } | ||||
| 
 | ||||
| /* Zebra client message read function. */ | ||||
| static int zclient_read(struct thread *thread) | ||||
| { | ||||
| @ -2061,6 +2124,11 @@ static int zclient_read(struct thread *thread) | ||||
| 			(*zclient->local_macip_del)(command, zclient, length, | ||||
| 						    vrf_id); | ||||
| 		break; | ||||
| 	case ZEBRA_PW_STATUS_UPDATE: | ||||
| 		if (zclient->pw_status_update) | ||||
| 			(*zclient->pw_status_update)(command, zclient, length, | ||||
| 						     vrf_id); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| @ -30,6 +30,12 @@ | ||||
| /* For vrf_bitmap_t. */ | ||||
| #include "vrf.h" | ||||
| 
 | ||||
| /* For union g_addr */ | ||||
| #include "nexthop.h" | ||||
| 
 | ||||
| /* For union pw_protocol_fields */ | ||||
| #include "pw.h" | ||||
| 
 | ||||
| /* For input/output buffer to zebra. */ | ||||
| #define ZEBRA_MAX_PACKET_SIZ          4096 | ||||
| 
 | ||||
| @ -106,6 +112,11 @@ typedef enum { | ||||
| 	ZEBRA_MACIP_DEL, | ||||
| 	ZEBRA_REMOTE_MACIP_ADD, | ||||
| 	ZEBRA_REMOTE_MACIP_DEL, | ||||
| 	ZEBRA_PW_ADD, | ||||
| 	ZEBRA_PW_DELETE, | ||||
| 	ZEBRA_PW_SET, | ||||
| 	ZEBRA_PW_UNSET, | ||||
| 	ZEBRA_PW_STATUS_UPDATE, | ||||
| } zebra_message_types_t; | ||||
| 
 | ||||
| struct redist_proto { | ||||
| @ -187,6 +198,7 @@ struct zclient { | ||||
| 	int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t); | ||||
| 	int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t); | ||||
| 	int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t); | ||||
| 	int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t); | ||||
| }; | ||||
| 
 | ||||
| /* Zebra API message flag. */ | ||||
| @ -266,6 +278,25 @@ struct zapi_ipv4 { | ||||
| 	vrf_id_t vrf_id; | ||||
| }; | ||||
| 
 | ||||
| struct zapi_pw { | ||||
| 	char ifname[IF_NAMESIZE]; | ||||
| 	ifindex_t ifindex; | ||||
| 	int type; | ||||
| 	int af; | ||||
| 	union g_addr nexthop; | ||||
| 	uint32_t local_label; | ||||
| 	uint32_t remote_label; | ||||
| 	uint8_t flags; | ||||
| 	union pw_protocol_fields data; | ||||
| 	uint8_t protocol; | ||||
| }; | ||||
| 
 | ||||
| struct zapi_pw_status { | ||||
| 	char ifname[IF_NAMESIZE]; | ||||
| 	ifindex_t ifindex; | ||||
| 	uint32_t status; | ||||
| }; | ||||
| 
 | ||||
| /* Prototypes of zebra client service functions. */ | ||||
| extern struct zclient *zclient_new(struct thread_master *); | ||||
| extern void zclient_init(struct zclient *, int, u_short); | ||||
| @ -338,6 +369,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, u_char keep, | ||||
| 			      uint32_t *end); | ||||
| extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start, | ||||
| 				  uint32_t end); | ||||
| extern int zebra_send_pw(struct zclient *zclient, int command, | ||||
| 			 struct zapi_pw *pw); | ||||
| extern void zebra_read_pw_status_update(int command, struct zclient *zclient, | ||||
| 					zebra_size_t length, vrf_id_t vrf_id, | ||||
| 					struct zapi_pw_status *pw); | ||||
| 
 | ||||
| /* IPv6 prefix add and delete function prototype. */ | ||||
| 
 | ||||
| struct zapi_ipv6 { | ||||
|  | ||||
| @ -83,8 +83,7 @@ static void _lsdb_count_assert(struct ospf6_lsdb *lsdb) | ||||
| 	zlog_debug("PANIC !! lsdb[%p]->count = %d, real = %d", lsdb, | ||||
| 		   lsdb->count, num); | ||||
| 	for (ALL_LSDB(lsdb, debug)) | ||||
| 		zlog_debug("%p %p %s lsdb[%p]", debug->prev, debug->next, | ||||
| 			   debug->name, debug->lsdb); | ||||
| 		zlog_debug("%s lsdb[%p]", debug->name, debug->lsdb); | ||||
| 	zlog_debug("DUMP END"); | ||||
| 
 | ||||
| 	assert(num == lsdb->count); | ||||
|  | ||||
| @ -147,6 +147,7 @@ vtysh_cmd_FILES = $(vtysh_scan) \ | ||||
| 	          $(top_srcdir)/zebra/zebra_fpm.c \
 | ||||
| 		  $(top_srcdir)/zebra/zebra_ptm.c \
 | ||||
| 		  $(top_srcdir)/zebra/zebra_mpls_vty.c \
 | ||||
| 		  $(top_srcdir)/zebra/zebra_pw.c \
 | ||||
| 		  $(top_srcdir)/watchfrr/watchfrr_vty.c \
 | ||||
| 	          $(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC) | ||||
| 
 | ||||
|  | ||||
| @ -923,6 +923,10 @@ static struct cmd_node interface_node = { | ||||
| 	INTERFACE_NODE, "%s(config-if)# ", | ||||
| }; | ||||
| 
 | ||||
| static struct cmd_node pw_node = { | ||||
| 	PW_NODE, "%s(config-pw)# ", | ||||
| }; | ||||
| 
 | ||||
| static struct cmd_node ns_node = { | ||||
| 	NS_NODE, "%s(config-logical-router)# ", | ||||
| }; | ||||
| @ -1418,6 +1422,7 @@ static int vtysh_exit(struct vty *vty) | ||||
| 		vty->node = ENABLE_NODE; | ||||
| 		break; | ||||
| 	case INTERFACE_NODE: | ||||
| 	case PW_NODE: | ||||
| 	case NS_NODE: | ||||
| 	case VRF_NODE: | ||||
| 	case ZEBRA_NODE: | ||||
| @ -1671,6 +1676,15 @@ DEFUNSH(VTYSH_INTERFACE, vtysh_interface, vtysh_interface_cmd, | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| DEFUNSH(VTYSH_ZEBRA, vtysh_pseudowire, vtysh_pseudowire_cmd, | ||||
| 	"pseudowire IFNAME", | ||||
| 	"Static pseudowire configuration\n" | ||||
| 	"Pseudowire name\n") | ||||
| { | ||||
| 	vty->node = PW_NODE; | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| /* TODO Implement "no interface command in isisd. */ | ||||
| DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | ||||
| 	      | VTYSH_EIGRPD, | ||||
| @ -2921,6 +2935,7 @@ void vtysh_init_vty(void) | ||||
| 	install_node(&bgp_node, NULL); | ||||
| 	install_node(&rip_node, NULL); | ||||
| 	install_node(&interface_node, NULL); | ||||
| 	install_node(&pw_node, NULL); | ||||
| 	install_node(&link_params_node, NULL); | ||||
| 	install_node(&ns_node, NULL); | ||||
| 	install_node(&vrf_node, NULL); | ||||
| @ -3093,6 +3108,10 @@ void vtysh_init_vty(void) | ||||
| 	install_element(LINK_PARAMS_NODE, &vtysh_exit_interface_cmd); | ||||
| 	install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd); | ||||
| 
 | ||||
| 	install_element(PW_NODE, &vtysh_end_all_cmd); | ||||
| 	install_element(PW_NODE, &vtysh_exit_interface_cmd); | ||||
| 	install_element(PW_NODE, &vtysh_quit_interface_cmd); | ||||
| 
 | ||||
| 	install_element(NS_NODE, &vtysh_end_all_cmd); | ||||
| 
 | ||||
| 	install_element(CONFIG_NODE, &vtysh_ns_cmd); | ||||
| @ -3168,6 +3187,7 @@ void vtysh_init_vty(void) | ||||
| 	install_element(CONFIG_NODE, &vtysh_interface_cmd); | ||||
| 	install_element(CONFIG_NODE, &vtysh_no_interface_cmd); | ||||
| 	install_element(CONFIG_NODE, &vtysh_no_interface_vrf_cmd); | ||||
| 	install_element(CONFIG_NODE, &vtysh_pseudowire_cmd); | ||||
| 	install_element(INTERFACE_NODE, &vtysh_link_params_cmd); | ||||
| 	install_element(ENABLE_NODE, &vtysh_show_running_config_cmd); | ||||
| 	install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd); | ||||
|  | ||||
| @ -181,6 +181,8 @@ void vtysh_config_parse_line(void *arg, const char *line) | ||||
| 	default: | ||||
| 		if (strncmp(line, "interface", strlen("interface")) == 0) | ||||
| 			config = config_get(INTERFACE_NODE, line); | ||||
| 		else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0) | ||||
| 			config = config_get(PW_NODE, line); | ||||
| 		else if (strncmp(line, "logical-router", strlen("ns")) == 0) | ||||
| 			config = config_get(NS_NODE, line); | ||||
| 		else if (strncmp(line, "vrf", strlen("vrf")) == 0) | ||||
|  | ||||
| @ -32,6 +32,7 @@ unsigned long zebra_debug_fpm; | ||||
| unsigned long zebra_debug_nht; | ||||
| unsigned long zebra_debug_mpls; | ||||
| unsigned long zebra_debug_vxlan; | ||||
| unsigned long zebra_debug_pw; | ||||
| 
 | ||||
| DEFUN (show_debugging_zebra, | ||||
|        show_debugging_zebra_cmd, | ||||
| @ -82,6 +83,8 @@ DEFUN (show_debugging_zebra, | ||||
| 		vty_out(vty, "  Zebra next-hop tracking debugging is on\n"); | ||||
| 	if (IS_ZEBRA_DEBUG_MPLS) | ||||
| 		vty_out(vty, "  Zebra MPLS debugging is on\n"); | ||||
| 	if (IS_ZEBRA_DEBUG_PW) | ||||
| 		vty_out(vty, "  Zebra pseudowire debugging is on\n"); | ||||
| 
 | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| @ -130,6 +133,21 @@ DEFUN (debug_zebra_vxlan, | ||||
| 	return CMD_WARNING; | ||||
| } | ||||
| 
 | ||||
| DEFUN (debug_zebra_pw, | ||||
|        debug_zebra_pw_cmd, | ||||
|        "[no] debug zebra pseudowires", | ||||
|        "Negate a command or set its defaults\n" | ||||
|        DEBUG_STR | ||||
|        "Zebra configuration\n" | ||||
|        "Debug option set for zebra pseudowires\n") | ||||
| { | ||||
| 	if (strmatch(argv[0]->text, "no")) | ||||
| 		UNSET_FLAG(zebra_debug_pw, ZEBRA_DEBUG_PW); | ||||
| 	else | ||||
| 		SET_FLAG(zebra_debug_pw, ZEBRA_DEBUG_PW); | ||||
| 	return CMD_WARNING; | ||||
| } | ||||
| 
 | ||||
| DEFUN (debug_zebra_packet, | ||||
|        debug_zebra_packet_cmd, | ||||
|        "debug zebra packet [<recv|send>] [detail]", | ||||
| @ -419,6 +437,10 @@ static int config_write_debug(struct vty *vty) | ||||
| 		vty_out(vty, "debug zebra vxlan\n"); | ||||
| 		write++; | ||||
| 	} | ||||
| 	if (IS_ZEBRA_DEBUG_PW) { | ||||
| 		vty_out(vty, "debug zebra pseudowires\n"); | ||||
| 		write++; | ||||
| 	} | ||||
| 	return write; | ||||
| } | ||||
| 
 | ||||
| @ -431,6 +453,7 @@ void zebra_debug_init(void) | ||||
| 	zebra_debug_fpm = 0; | ||||
| 	zebra_debug_mpls = 0; | ||||
| 	zebra_debug_vxlan = 0; | ||||
| 	zebra_debug_pw = 0; | ||||
| 
 | ||||
| 	install_node(&debug_node, config_write_debug); | ||||
| 
 | ||||
| @ -440,6 +463,7 @@ void zebra_debug_init(void) | ||||
| 	install_element(ENABLE_NODE, &debug_zebra_nht_cmd); | ||||
| 	install_element(ENABLE_NODE, &debug_zebra_mpls_cmd); | ||||
| 	install_element(ENABLE_NODE, &debug_zebra_vxlan_cmd); | ||||
| 	install_element(ENABLE_NODE, &debug_zebra_pw_cmd); | ||||
| 	install_element(ENABLE_NODE, &debug_zebra_packet_cmd); | ||||
| 	install_element(ENABLE_NODE, &debug_zebra_kernel_cmd); | ||||
| 	install_element(ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd); | ||||
| @ -459,6 +483,7 @@ void zebra_debug_init(void) | ||||
| 	install_element(CONFIG_NODE, &debug_zebra_nht_cmd); | ||||
| 	install_element(CONFIG_NODE, &debug_zebra_mpls_cmd); | ||||
| 	install_element(CONFIG_NODE, &debug_zebra_vxlan_cmd); | ||||
| 	install_element(CONFIG_NODE, &debug_zebra_pw_cmd); | ||||
| 	install_element(CONFIG_NODE, &debug_zebra_packet_cmd); | ||||
| 	install_element(CONFIG_NODE, &debug_zebra_kernel_cmd); | ||||
| 	install_element(CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd); | ||||
|  | ||||
| @ -44,6 +44,8 @@ | ||||
| 
 | ||||
| #define ZEBRA_DEBUG_VXLAN   0x01 | ||||
| 
 | ||||
| #define ZEBRA_DEBUG_PW      0x01 | ||||
| 
 | ||||
| /* Debug related macro. */ | ||||
| #define IS_ZEBRA_DEBUG_EVENT  (zebra_debug_event & ZEBRA_DEBUG_EVENT) | ||||
| 
 | ||||
| @ -66,6 +68,7 @@ | ||||
| #define IS_ZEBRA_DEBUG_NHT  (zebra_debug_nht & ZEBRA_DEBUG_NHT) | ||||
| #define IS_ZEBRA_DEBUG_MPLS  (zebra_debug_mpls & ZEBRA_DEBUG_MPLS) | ||||
| #define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN) | ||||
| #define IS_ZEBRA_DEBUG_PW  (zebra_debug_pw & ZEBRA_DEBUG_PW) | ||||
| 
 | ||||
| extern unsigned long zebra_debug_event; | ||||
| extern unsigned long zebra_debug_packet; | ||||
| @ -75,6 +78,7 @@ extern unsigned long zebra_debug_fpm; | ||||
| extern unsigned long zebra_debug_nht; | ||||
| extern unsigned long zebra_debug_mpls; | ||||
| extern unsigned long zebra_debug_vxlan; | ||||
| extern unsigned long zebra_debug_pw; | ||||
| 
 | ||||
| extern void zebra_debug_init(void); | ||||
| 
 | ||||
|  | ||||
| @ -627,6 +627,7 @@ int ifm_read(struct if_msghdr *ifm) | ||||
| #ifdef HAVE_NET_RT_IFLIST | ||||
| 	ifp->stats = ifm->ifm_data; | ||||
| #endif /* HAVE_NET_RT_IFLIST */ | ||||
| 	ifp->speed = ifm->ifm_data.ifi_baudrate / 1000000; | ||||
| 
 | ||||
| 	if (IS_ZEBRA_DEBUG_KERNEL) | ||||
| 		zlog_debug("%s: interface %s index %d", __func__, ifp->name, | ||||
|  | ||||
| @ -299,6 +299,7 @@ int main(int argc, char **argv) | ||||
| 
 | ||||
| 	zebra_mpls_init(); | ||||
| 	zebra_mpls_vty_init(); | ||||
| 	zebra_pw_vty_init(); | ||||
| 
 | ||||
| 	/* For debug purpose. */ | ||||
| 	/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ | ||||
|  | ||||
| @ -89,6 +89,7 @@ struct route_entry { | ||||
| #define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2 | ||||
| #define ROUTE_ENTRY_CHANGED          0x4 | ||||
| #define ROUTE_ENTRY_SELECTED_FIB     0x8 | ||||
| #define ROUTE_ENTRY_LABELS_CHANGED   0x10 | ||||
| 
 | ||||
| 	/* Nexthop information. */ | ||||
| 	u_char nexthop_num; | ||||
|  | ||||
| @ -56,6 +56,7 @@ zebra_zebra_SOURCES = \ | ||||
| 	zebra/zebra_ns.c \ | ||||
| 	zebra/zebra_ptm.c \ | ||||
| 	zebra/zebra_ptm_redistribute.c \ | ||||
| 	zebra/zebra_pw.c \ | ||||
| 	zebra/zebra_rib.c \ | ||||
| 	zebra/zebra_rnh.c \ | ||||
| 	zebra/zebra_routemap.c \ | ||||
| @ -95,6 +96,7 @@ noinst_HEADERS += \ | ||||
| 	zebra/zebra_ns.h \ | ||||
| 	zebra/zebra_ptm.h \ | ||||
| 	zebra/zebra_ptm_redistribute.h \ | ||||
| 	zebra/zebra_pw.h \ | ||||
| 	zebra/zebra_rnh.h \ | ||||
| 	zebra/zebra_routemap.h \ | ||||
| 	zebra/zebra_static.h \ | ||||
|  | ||||
| @ -2222,7 +2222,7 @@ found: | ||||
| 		return 0; | ||||
| 
 | ||||
| 	SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); | ||||
| 	SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); | ||||
| 	SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); | ||||
| 	rib_queue_add(rn); | ||||
| 
 | ||||
| 	return 0; | ||||
| @ -2405,7 +2405,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi) | ||||
| 				nexthop_del_labels(nexthop); | ||||
| 				SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); | ||||
| 				SET_FLAG(re->status, | ||||
| 					 ROUTE_ENTRY_NEXTHOPS_CHANGED); | ||||
| 					 ROUTE_ENTRY_LABELS_CHANGED); | ||||
| 				update = 1; | ||||
| 			} | ||||
| 
 | ||||
|  | ||||
| @ -37,6 +37,7 @@ extern struct zebra_privs_t zserv_privs; | ||||
| struct { | ||||
| 	u_int32_t rtseq; | ||||
| 	int fd; | ||||
| 	int ioctl_fd; | ||||
| } kr_state; | ||||
| 
 | ||||
| static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, | ||||
| @ -330,6 +331,85 @@ int kernel_del_lsp(zebra_lsp_t *lsp) | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int kmpw_install(struct zebra_pw *pw) | ||||
| { | ||||
| 	struct ifreq ifr; | ||||
| 	struct ifmpwreq imr; | ||||
| 	struct sockaddr_storage ss; | ||||
| 	struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; | ||||
| 	struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; | ||||
| 
 | ||||
| 	memset(&imr, 0, sizeof(imr)); | ||||
| 	switch (pw->type) { | ||||
| 	case PW_TYPE_ETHERNET: | ||||
| 		imr.imr_type = IMR_TYPE_ETHERNET; | ||||
| 		break; | ||||
| 	case PW_TYPE_ETHERNET_TAGGED: | ||||
| 		imr.imr_type = IMR_TYPE_ETHERNET_TAGGED; | ||||
| 		break; | ||||
| 	default: | ||||
| 		zlog_err("%s: unhandled pseudowire type (%#X)", __func__, | ||||
| 			 pw->type); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (pw->flags & F_PSEUDOWIRE_CWORD) | ||||
| 		imr.imr_flags |= IMR_FLAG_CONTROLWORD; | ||||
| 
 | ||||
| 	/* pseudowire nexthop */ | ||||
| 	memset(&ss, 0, sizeof(ss)); | ||||
| 	switch (pw->af) { | ||||
| 	case AF_INET: | ||||
| 		sa_in->sin_family = AF_INET; | ||||
| 		sa_in->sin_len = sizeof(struct sockaddr_in); | ||||
| 		sa_in->sin_addr = pw->nexthop.ipv4; | ||||
| 		break; | ||||
| 	case AF_INET6: | ||||
| 		sa_in6->sin6_family = AF_INET6; | ||||
| 		sa_in6->sin6_len = sizeof(struct sockaddr_in6); | ||||
| 		sa_in6->sin6_addr = pw->nexthop.ipv6; | ||||
| 		break; | ||||
| 	default: | ||||
| 		zlog_err("%s: unhandled pseudowire address-family (%u)", | ||||
| 			 __func__, pw->af); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss, | ||||
| 	       sizeof(imr.imr_nexthop)); | ||||
| 
 | ||||
| 	/* pseudowire local/remote labels */ | ||||
| 	imr.imr_lshim.shim_label = pw->local_label; | ||||
| 	imr.imr_rshim.shim_label = pw->remote_label; | ||||
| 
 | ||||
| 	/* ioctl */ | ||||
| 	memset(&ifr, 0, sizeof(ifr)); | ||||
| 	strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); | ||||
| 	ifr.ifr_data = (caddr_t)&imr; | ||||
| 	if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { | ||||
| 		zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int kmpw_uninstall(struct zebra_pw *pw) | ||||
| { | ||||
| 	struct ifreq ifr; | ||||
| 	struct ifmpwreq imr; | ||||
| 
 | ||||
| 	memset(&ifr, 0, sizeof(ifr)); | ||||
| 	memset(&imr, 0, sizeof(imr)); | ||||
| 	strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); | ||||
| 	ifr.ifr_data = (caddr_t)&imr; | ||||
| 	if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { | ||||
| 		zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #define MAX_RTSOCK_BUF	128 * 1024 | ||||
| int mpls_kernel_init(void) | ||||
| { | ||||
| @ -341,6 +421,12 @@ int mpls_kernel_init(void) | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((kr_state.ioctl_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)) | ||||
| 	    == -1) { | ||||
| 		zlog_warn("%s: ioctl socket", __func__); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* grow receive buffer, don't wanna miss messages */ | ||||
| 	optlen = sizeof(default_rcvbuf); | ||||
| 	if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf, | ||||
| @ -359,6 +445,10 @@ int mpls_kernel_init(void) | ||||
| 
 | ||||
| 	kr_state.rtseq = 1; | ||||
| 
 | ||||
| 	/* register hook to install/uninstall pseudowires */ | ||||
| 	hook_register(pw_install, kmpw_install); | ||||
| 	hook_register(pw_uninstall, kmpw_uninstall); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										533
									
								
								zebra/zebra_pw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										533
									
								
								zebra/zebra_pw.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,533 @@ | ||||
| /* Zebra PW code
 | ||||
|  * Copyright (C) 2016 Volta Networks, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; see the file COPYING; if not, write to the | ||||
|  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | ||||
|  * MA 02110-1301 USA | ||||
|  */ | ||||
| 
 | ||||
| #include <zebra.h> | ||||
| 
 | ||||
| #include "log.h" | ||||
| #include "memory.h" | ||||
| #include "thread.h" | ||||
| #include "command.h" | ||||
| #include "vrf.h" | ||||
| 
 | ||||
| #include "zebra/debug.h" | ||||
| #include "zebra/rib.h" | ||||
| #include "zebra/zserv.h" | ||||
| #include "zebra/zebra_rnh.h" | ||||
| #include "zebra/zebra_vrf.h" | ||||
| #include "zebra/zebra_pw.h" | ||||
| 
 | ||||
| DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire") | ||||
| 
 | ||||
| DEFINE_QOBJ_TYPE(zebra_pw) | ||||
| 
 | ||||
| DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) | ||||
| DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) | ||||
| 
 | ||||
| #define MPLS_NO_LABEL MPLS_INVALID_LABEL | ||||
| 
 | ||||
| extern struct zebra_t zebrad; | ||||
| 
 | ||||
| static int zebra_pw_enabled(struct zebra_pw *); | ||||
| static void zebra_pw_install(struct zebra_pw *); | ||||
| static void zebra_pw_uninstall(struct zebra_pw *); | ||||
| static int zebra_pw_install_retry(struct thread *); | ||||
| static int zebra_pw_check_reachability(struct zebra_pw *); | ||||
| static void zebra_pw_update_status(struct zebra_pw *, int); | ||||
| 
 | ||||
| static inline int zebra_pw_compare(const struct zebra_pw *a, | ||||
| 				   const struct zebra_pw *b) | ||||
| { | ||||
| 	return (strcmp(a->ifname, b->ifname)); | ||||
| } | ||||
| 
 | ||||
| RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare) | ||||
| RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare) | ||||
| 
 | ||||
| struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname, | ||||
| 			      uint8_t protocol, struct zserv *client) | ||||
| { | ||||
| 	struct zebra_pw *pw; | ||||
| 
 | ||||
| 	if (IS_ZEBRA_DEBUG_PW) | ||||
| 		zlog_debug("%u: adding pseudowire %s protocol %s", | ||||
| 			   zvrf_id(zvrf), ifname, zebra_route_string(protocol)); | ||||
| 
 | ||||
| 	pw = XCALLOC(MTYPE_PW, sizeof(*pw)); | ||||
| 	strlcpy(pw->ifname, ifname, sizeof(pw->ifname)); | ||||
| 	pw->protocol = protocol; | ||||
| 	pw->vrf_id = zvrf_id(zvrf); | ||||
| 	pw->client = client; | ||||
| 	pw->status = PW_STATUS_UP; | ||||
| 	pw->local_label = MPLS_NO_LABEL; | ||||
| 	pw->remote_label = MPLS_NO_LABEL; | ||||
| 	pw->flags = F_PSEUDOWIRE_CWORD; | ||||
| 
 | ||||
| 	RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw); | ||||
| 	if (pw->protocol == ZEBRA_ROUTE_STATIC) { | ||||
| 		RB_INSERT(zebra_static_pw_head, &zvrf->static_pseudowires, pw); | ||||
| 		QOBJ_REG(pw, zebra_pw); | ||||
| 	} | ||||
| 
 | ||||
| 	return pw; | ||||
| } | ||||
| 
 | ||||
| void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw) | ||||
| { | ||||
| 	if (IS_ZEBRA_DEBUG_PW) | ||||
| 		zlog_debug("%u: deleting pseudowire %s protocol %s", pw->vrf_id, | ||||
| 			   pw->ifname, zebra_route_string(pw->protocol)); | ||||
| 
 | ||||
| 	/* remove nexthop tracking */ | ||||
| 	zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); | ||||
| 
 | ||||
| 	/* uninstall */ | ||||
| 	if (pw->status == PW_STATUS_UP) | ||||
| 		hook_call(pw_uninstall, pw); | ||||
| 	else if (pw->install_retry_timer) | ||||
| 		THREAD_TIMER_OFF(pw->install_retry_timer); | ||||
| 
 | ||||
| 	/* unlink and release memory */ | ||||
| 	RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw); | ||||
| 	if (pw->protocol == ZEBRA_ROUTE_STATIC) | ||||
| 		RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw); | ||||
| 	XFREE(MTYPE_PW, pw); | ||||
| } | ||||
| 
 | ||||
| void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af, | ||||
| 		     union g_addr *nexthop, uint32_t local_label, | ||||
| 		     uint32_t remote_label, uint8_t flags, | ||||
| 		     union pw_protocol_fields *data) | ||||
| { | ||||
| 	zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); | ||||
| 
 | ||||
| 	pw->ifindex = ifindex; | ||||
| 	pw->type = type; | ||||
| 	pw->af = af; | ||||
| 	pw->nexthop = *nexthop; | ||||
| 	pw->local_label = local_label; | ||||
| 	pw->remote_label = remote_label; | ||||
| 	pw->flags = flags; | ||||
| 	pw->data = *data; | ||||
| 
 | ||||
| 	if (zebra_pw_enabled(pw)) | ||||
| 		zebra_register_rnh_pseudowire(pw->vrf_id, pw); | ||||
| 	else | ||||
| 		zebra_pw_uninstall(pw); | ||||
| } | ||||
| 
 | ||||
| struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname) | ||||
| { | ||||
| 	struct zebra_pw pw; | ||||
| 	strlcpy(pw.ifname, ifname, sizeof(pw.ifname)); | ||||
| 	return (RB_FIND(zebra_pw_head, &zvrf->pseudowires, &pw)); | ||||
| } | ||||
| 
 | ||||
| static int zebra_pw_enabled(struct zebra_pw *pw) | ||||
| { | ||||
| 	if (pw->protocol == ZEBRA_ROUTE_STATIC) { | ||||
| 		if (pw->local_label == MPLS_NO_LABEL | ||||
| 		    || pw->remote_label == MPLS_NO_LABEL || pw->af == AF_UNSPEC) | ||||
| 			return 0; | ||||
| 		return 1; | ||||
| 	} else | ||||
| 		return pw->enabled; | ||||
| } | ||||
| 
 | ||||
| void zebra_pw_update(struct zebra_pw *pw) | ||||
| { | ||||
| 	if (zebra_pw_check_reachability(pw) < 0) { | ||||
| 		zebra_pw_uninstall(pw); | ||||
| 		/* wait for NHT and try again later */ | ||||
| 	} else { | ||||
| 		/*
 | ||||
| 		 * Install or reinstall the pseudowire (e.g. to update | ||||
| 		 * parameters like the nexthop or the use of the control word). | ||||
| 		 */ | ||||
| 		zebra_pw_install(pw); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void zebra_pw_install(struct zebra_pw *pw) | ||||
| { | ||||
| 	if (IS_ZEBRA_DEBUG_PW) | ||||
| 		zlog_debug("%u: installing pseudowire %s protocol %s", | ||||
| 			   pw->vrf_id, pw->ifname, | ||||
| 			   zebra_route_string(pw->protocol)); | ||||
| 
 | ||||
| 	if (hook_call(pw_install, pw)) { | ||||
| 		zebra_pw_install_failure(pw); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (pw->status == PW_STATUS_DOWN) | ||||
| 		zebra_pw_update_status(pw, PW_STATUS_UP); | ||||
| } | ||||
| 
 | ||||
| static void zebra_pw_uninstall(struct zebra_pw *pw) | ||||
| { | ||||
| 	if (pw->status == PW_STATUS_DOWN) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (IS_ZEBRA_DEBUG_PW) | ||||
| 		zlog_debug("%u: uninstalling pseudowire %s protocol %s", | ||||
| 			   pw->vrf_id, pw->ifname, | ||||
| 			   zebra_route_string(pw->protocol)); | ||||
| 
 | ||||
| 	/* ignore any possible error */ | ||||
| 	hook_call(pw_uninstall, pw); | ||||
| 
 | ||||
| 	if (zebra_pw_enabled(pw)) | ||||
| 		zebra_pw_update_status(pw, PW_STATUS_DOWN); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Installation of the pseudowire in the kernel or hardware has failed. This | ||||
|  * function will notify the pseudowire client about the failure and schedule | ||||
|  * to retry the installation later. This function can be called by an external | ||||
|  * agent that performs the pseudowire installation in an asynchronous way. | ||||
|  */ | ||||
| void zebra_pw_install_failure(struct zebra_pw *pw) | ||||
| { | ||||
| 	if (IS_ZEBRA_DEBUG_PW) | ||||
| 		zlog_debug( | ||||
| 			"%u: failed installing pseudowire %s, " | ||||
| 			"scheduling retry in %u seconds", | ||||
| 			pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL); | ||||
| 
 | ||||
| 	/* schedule to retry later */ | ||||
| 	THREAD_TIMER_OFF(pw->install_retry_timer); | ||||
| 	thread_add_timer(zebrad.master, zebra_pw_install_retry, pw, | ||||
| 			 PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer); | ||||
| 
 | ||||
| 	zebra_pw_update_status(pw, PW_STATUS_DOWN); | ||||
| } | ||||
| 
 | ||||
| static int zebra_pw_install_retry(struct thread *thread) | ||||
| { | ||||
| 	struct zebra_pw *pw = THREAD_ARG(thread); | ||||
| 
 | ||||
| 	pw->install_retry_timer = NULL; | ||||
| 	zebra_pw_install(pw); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void zebra_pw_update_status(struct zebra_pw *pw, int status) | ||||
| { | ||||
| 	pw->status = status; | ||||
| 	if (pw->client) | ||||
| 		zsend_pw_update(pw->client, pw); | ||||
| } | ||||
| 
 | ||||
| static int zebra_pw_check_reachability(struct zebra_pw *pw) | ||||
| { | ||||
| 	struct route_entry *re; | ||||
| 	struct nexthop *nexthop; | ||||
| 
 | ||||
| 	/* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */ | ||||
| 
 | ||||
| 	/* find route to the remote end of the pseudowire */ | ||||
| 	re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id, | ||||
| 		       &pw->nexthop, NULL); | ||||
| 	if (!re) { | ||||
| 		if (IS_ZEBRA_DEBUG_PW) | ||||
| 			zlog_warn("%s: no route found for %s", __func__, | ||||
| 				  pw->ifname); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Need to ensure that there's a label binding for all nexthops. | ||||
| 	 * Otherwise, ECMP for this route could render the pseudowire unusable. | ||||
| 	 */ | ||||
| 	for (ALL_NEXTHOPS(re->nexthop, nexthop)) { | ||||
| 		if (!nexthop->nh_label) { | ||||
| 			if (IS_ZEBRA_DEBUG_PW) | ||||
| 				zlog_warn("%s: unlabeled route for %s", | ||||
| 					  __func__, pw->ifname); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void zebra_pw_client_close(struct zserv *client) | ||||
| { | ||||
| 	struct vrf *vrf; | ||||
| 	struct zebra_vrf *zvrf; | ||||
| 	struct zebra_pw *pw, *tmp; | ||||
| 
 | ||||
| 	RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) | ||||
| 	{ | ||||
| 		zvrf = vrf->info; | ||||
| 		RB_FOREACH_SAFE(pw, zebra_pw_head, &zvrf->pseudowires, tmp) | ||||
| 		{ | ||||
| 			if (pw->client != client) | ||||
| 				continue; | ||||
| 			zebra_pw_del(zvrf, pw); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void zebra_pw_init(struct zebra_vrf *zvrf) | ||||
| { | ||||
| 	RB_INIT(zebra_pw_head, &zvrf->pseudowires); | ||||
| 	RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires); | ||||
| } | ||||
| 
 | ||||
| void zebra_pw_exit(struct zebra_vrf *zvrf) | ||||
| { | ||||
| 	struct zebra_pw *pw; | ||||
| 
 | ||||
| 	while ((pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires)) != NULL) | ||||
| 		zebra_pw_del(zvrf, pw); | ||||
| } | ||||
| 
 | ||||
| DEFUN_NOSH (pseudowire_if, | ||||
| 	    pseudowire_if_cmd, | ||||
| 	    "[no] pseudowire IFNAME", | ||||
| 	    NO_STR | ||||
| 	    "Static pseudowire configuration\n" | ||||
| 	    "Pseudowire name\n") | ||||
| { | ||||
| 	struct zebra_vrf *zvrf; | ||||
| 	struct zebra_pw *pw; | ||||
| 	int idx = 0; | ||||
| 	const char *ifname; | ||||
| 
 | ||||
| 	zvrf = vrf_info_lookup(VRF_DEFAULT); | ||||
| 	if (!zvrf) | ||||
| 		return CMD_WARNING; | ||||
| 
 | ||||
| 	argv_find(argv, argc, "IFNAME", &idx); | ||||
| 	ifname = argv[idx]->arg; | ||||
| 	pw = zebra_pw_find(zvrf, ifname); | ||||
| 	if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) { | ||||
| 		vty_out(vty, "%% Pseudowire is not static\n"); | ||||
| 		return CMD_WARNING; | ||||
| 	} | ||||
| 
 | ||||
| 	if (argv_find(argv, argc, "no", &idx)) { | ||||
| 		if (!pw) | ||||
| 			return CMD_SUCCESS; | ||||
| 		zebra_pw_del(zvrf, pw); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!pw) | ||||
| 		pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL); | ||||
| 	VTY_PUSH_CONTEXT(PW_NODE, pw); | ||||
| 
 | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| DEFUN (pseudowire_labels, | ||||
|        pseudowire_labels_cmd, | ||||
|        "[no] mpls label local (16-1048575) remote (16-1048575)", | ||||
|        NO_STR | ||||
|        "MPLS L2VPN PW command\n" | ||||
|        "MPLS L2VPN static labels\n" | ||||
|        "Local pseudowire label\n" | ||||
|        "Local pseudowire label\n" | ||||
|        "Remote pseudowire label\n" | ||||
|        "Remote pseudowire label\n") | ||||
| { | ||||
| 	VTY_DECLVAR_CONTEXT(zebra_pw, pw); | ||||
| 	int idx = 0; | ||||
| 	mpls_label_t local_label, remote_label; | ||||
| 
 | ||||
| 	if (argv_find(argv, argc, "no", &idx)) { | ||||
| 		local_label = MPLS_NO_LABEL; | ||||
| 		remote_label = MPLS_NO_LABEL; | ||||
| 	} else { | ||||
| 		argv_find(argv, argc, "local", &idx); | ||||
| 		local_label = atoi(argv[idx + 1]->arg); | ||||
| 		argv_find(argv, argc, "remote", &idx); | ||||
| 		remote_label = atoi(argv[idx + 1]->arg); | ||||
| 	} | ||||
| 
 | ||||
| 	zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop, | ||||
| 			local_label, remote_label, pw->flags, &pw->data); | ||||
| 
 | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| DEFUN (pseudowire_neighbor, | ||||
|        pseudowire_neighbor_cmd, | ||||
|        "[no] neighbor <A.B.C.D|X:X::X:X>", | ||||
|        NO_STR | ||||
|        "Specify the IPv4 or IPv6 address of the remote endpoint\n" | ||||
|        "IPv4 address\n" | ||||
|        "IPv6 address\n") | ||||
| { | ||||
| 	VTY_DECLVAR_CONTEXT(zebra_pw, pw); | ||||
| 	int idx = 0; | ||||
| 	const char *address; | ||||
| 	int af; | ||||
| 	union g_addr nexthop; | ||||
| 
 | ||||
| 	af = AF_UNSPEC; | ||||
| 	memset(&nexthop, 0, sizeof(nexthop)); | ||||
| 
 | ||||
| 	if (!argv_find(argv, argc, "no", &idx)) { | ||||
| 		argv_find(argv, argc, "neighbor", &idx); | ||||
| 		address = argv[idx + 1]->arg; | ||||
| 
 | ||||
| 		if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1) | ||||
| 			af = AF_INET; | ||||
| 		else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1) | ||||
| 			af = AF_INET6; | ||||
| 		else { | ||||
| 			vty_out(vty, "%% Malformed address\n"); | ||||
| 			return CMD_WARNING; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop, | ||||
| 			pw->local_label, pw->remote_label, pw->flags, | ||||
| 			&pw->data); | ||||
| 
 | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| DEFUN (pseudowire_control_word, | ||||
|        pseudowire_control_word_cmd, | ||||
|        "[no] control-word <exclude|include>", | ||||
|        NO_STR | ||||
|        "Control-word options\n" | ||||
|        "Exclude control-word in pseudowire packets\n" | ||||
|        "Include control-word in pseudowire packets\n") | ||||
| { | ||||
| 	VTY_DECLVAR_CONTEXT(zebra_pw, pw); | ||||
| 	int idx = 0; | ||||
| 	uint8_t flags = 0; | ||||
| 
 | ||||
| 	if (argv_find(argv, argc, "no", &idx)) | ||||
| 		flags = F_PSEUDOWIRE_CWORD; | ||||
| 	else { | ||||
| 		argv_find(argv, argc, "control-word", &idx); | ||||
| 		if (argv[idx + 1]->text[0] == 'i') | ||||
| 			flags = F_PSEUDOWIRE_CWORD; | ||||
| 	} | ||||
| 
 | ||||
| 	zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop, | ||||
| 			pw->local_label, pw->remote_label, flags, &pw->data); | ||||
| 
 | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| DEFUN (show_pseudowires, | ||||
|        show_pseudowires_cmd, | ||||
|        "show pseudowires", | ||||
|        SHOW_STR | ||||
|        "Pseudowires") | ||||
| { | ||||
| 	struct zebra_vrf *zvrf; | ||||
| 	struct zebra_pw *pw; | ||||
| 
 | ||||
| 	zvrf = vrf_info_lookup(VRF_DEFAULT); | ||||
| 	if (!zvrf) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor", | ||||
| 		"Labels", "Protocol", "Status"); | ||||
| 
 | ||||
| 	RB_FOREACH(pw, zebra_pw_head, &zvrf->pseudowires) | ||||
| 	{ | ||||
| 		char buf_nbr[INET6_ADDRSTRLEN]; | ||||
| 		char buf_labels[64]; | ||||
| 
 | ||||
| 		inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr)); | ||||
| 
 | ||||
| 		if (pw->local_label != MPLS_NO_LABEL | ||||
| 		    && pw->remote_label != MPLS_NO_LABEL) | ||||
| 			snprintf(buf_labels, sizeof(buf_labels), "%u/%u", | ||||
| 				 pw->local_label, pw->remote_label); | ||||
| 		else | ||||
| 			snprintf(buf_labels, sizeof(buf_labels), "-"); | ||||
| 
 | ||||
| 		vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname, | ||||
| 			(pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels, | ||||
| 			zebra_route_string(pw->protocol), | ||||
| 			(zebra_pw_enabled(pw) && pw->status == PW_STATUS_UP) | ||||
| 				? "UP" | ||||
| 				: "DOWN"); | ||||
| 	} | ||||
| 
 | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| /* Pseudowire configuration write function. */ | ||||
| static int zebra_pw_config(struct vty *vty) | ||||
| { | ||||
| 	int write = 0; | ||||
| 	struct zebra_vrf *zvrf; | ||||
| 	struct zebra_pw *pw; | ||||
| 
 | ||||
| 	zvrf = vrf_info_lookup(VRF_DEFAULT); | ||||
| 	if (!zvrf) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	RB_FOREACH(pw, zebra_static_pw_head, &zvrf->static_pseudowires) | ||||
| 	{ | ||||
| 		vty_out(vty, "pseudowire %s\n", pw->ifname); | ||||
| 		if (pw->local_label != MPLS_NO_LABEL | ||||
| 		    && pw->remote_label != MPLS_NO_LABEL) | ||||
| 			vty_out(vty, " mpls label local %u remote %u\n", | ||||
| 				pw->local_label, pw->remote_label); | ||||
| 		else | ||||
| 			vty_out(vty, | ||||
| 				" ! Incomplete config, specify the static " | ||||
| 				"MPLS labels\n"); | ||||
| 
 | ||||
| 		if (pw->af != AF_UNSPEC) { | ||||
| 			char buf[INET6_ADDRSTRLEN]; | ||||
| 			inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf)); | ||||
| 			vty_out(vty, " neighbor %s\n", buf); | ||||
| 		} else | ||||
| 			vty_out(vty, | ||||
| 				" ! Incomplete config, specify a neighbor " | ||||
| 				"address\n"); | ||||
| 
 | ||||
| 		if (!(pw->flags & F_PSEUDOWIRE_CWORD)) | ||||
| 			vty_out(vty, " control-word exclude\n"); | ||||
| 
 | ||||
| 		vty_out(vty, "!\n"); | ||||
| 		write = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	return write; | ||||
| } | ||||
| 
 | ||||
| static struct cmd_node pw_node = { | ||||
| 	PW_NODE, "%s(config-pw)# ", 1, | ||||
| }; | ||||
| 
 | ||||
| void zebra_pw_vty_init(void) | ||||
| { | ||||
| 	install_node(&pw_node, zebra_pw_config); | ||||
| 	install_default(PW_NODE); | ||||
| 
 | ||||
| 	install_element(CONFIG_NODE, &pseudowire_if_cmd); | ||||
| 	install_element(PW_NODE, &pseudowire_labels_cmd); | ||||
| 	install_element(PW_NODE, &pseudowire_neighbor_cmd); | ||||
| 	install_element(PW_NODE, &pseudowire_control_word_cmd); | ||||
| 
 | ||||
| 	install_element(VIEW_NODE, &show_pseudowires_cmd); | ||||
| } | ||||
							
								
								
									
										75
									
								
								zebra/zebra_pw.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								zebra/zebra_pw.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| /* Zebra PW code
 | ||||
|  * Copyright (C) 2016 Volta Networks, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; see the file COPYING; if not, write to the | ||||
|  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | ||||
|  * MA 02110-1301 USA | ||||
|  */ | ||||
| 
 | ||||
| #ifndef ZEBRA_PW_H_ | ||||
| #define ZEBRA_PW_H_ | ||||
| 
 | ||||
| #include <net/if.h> | ||||
| #include <netinet/in.h> | ||||
| 
 | ||||
| #include "hook.h" | ||||
| #include "qobj.h" | ||||
| 
 | ||||
| #define PW_INSTALL_RETRY_INTERVAL	30 | ||||
| 
 | ||||
| struct zebra_pw { | ||||
| 	RB_ENTRY(zebra_pw) pw_entry, static_pw_entry; | ||||
| 	vrf_id_t vrf_id; | ||||
| 	char ifname[IF_NAMESIZE]; | ||||
| 	ifindex_t ifindex; | ||||
| 	int type; | ||||
| 	int af; | ||||
| 	union g_addr nexthop; | ||||
| 	uint32_t local_label; | ||||
| 	uint32_t remote_label; | ||||
| 	uint8_t flags; | ||||
| 	union pw_protocol_fields data; | ||||
| 	int enabled; | ||||
| 	int status; | ||||
| 	uint8_t protocol; | ||||
| 	struct zserv *client; | ||||
| 	struct rnh *rnh; | ||||
| 	struct thread *install_retry_timer; | ||||
| 	QOBJ_FIELDS | ||||
| }; | ||||
| DECLARE_QOBJ_TYPE(zebra_pw) | ||||
| 
 | ||||
| RB_HEAD(zebra_pw_head, zebra_pw); | ||||
| RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare); | ||||
| 
 | ||||
| RB_HEAD(zebra_static_pw_head, zebra_pw); | ||||
| RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare); | ||||
| 
 | ||||
| DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) | ||||
| DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) | ||||
| 
 | ||||
| struct zebra_pw *zebra_pw_add(struct zebra_vrf *, const char *, uint8_t, | ||||
| 			      struct zserv *); | ||||
| void zebra_pw_del(struct zebra_vrf *, struct zebra_pw *); | ||||
| void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *, | ||||
| 		     uint32_t, uint32_t, uint8_t, union pw_protocol_fields *); | ||||
| struct zebra_pw *zebra_pw_find(struct zebra_vrf *, const char *); | ||||
| void zebra_pw_update(struct zebra_pw *); | ||||
| void zebra_pw_install_failure(struct zebra_pw *); | ||||
| void zebra_pw_client_close(struct zserv *); | ||||
| void zebra_pw_init(struct zebra_vrf *); | ||||
| void zebra_pw_exit(struct zebra_vrf *); | ||||
| void zebra_pw_vty_init(void); | ||||
| 
 | ||||
| #endif /* ZEBRA_PW_H_ */ | ||||
| @ -126,6 +126,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type) | ||||
| 		rnh->client_list = list_new(); | ||||
| 		rnh->vrf_id = vrfid; | ||||
| 		rnh->zebra_static_route_list = list_new(); | ||||
| 		rnh->zebra_pseudowire_list = list_new(); | ||||
| 		route_lock_node(rn); | ||||
| 		rn->info = rnh; | ||||
| 		rnh->node = rn; | ||||
| @ -161,6 +162,7 @@ void zebra_free_rnh(struct rnh *rnh) | ||||
| 	rnh->flags |= ZEBRA_NHT_DELETED; | ||||
| 	list_free(rnh->client_list); | ||||
| 	list_free(rnh->zebra_static_route_list); | ||||
| 	list_free(rnh->zebra_pseudowire_list); | ||||
| 	free_state(rnh->vrf_id, rnh->state, rnh->node); | ||||
| 	XFREE(MTYPE_RNH, rnh); | ||||
| } | ||||
| @ -210,7 +212,8 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, | ||||
| 	} | ||||
| 	listnode_delete(rnh->client_list, client); | ||||
| 	if (list_isempty(rnh->client_list) | ||||
| 	    && list_isempty(rnh->zebra_static_route_list)) | ||||
| 	    && list_isempty(rnh->zebra_static_route_list) | ||||
| 	    && list_isempty(rnh->zebra_pseudowire_list)) | ||||
| 		zebra_delete_rnh(rnh, type); | ||||
| } | ||||
| 
 | ||||
| @ -237,7 +240,8 @@ void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh, | ||||
| 	listnode_delete(rnh->zebra_static_route_list, static_rn); | ||||
| 
 | ||||
| 	if (list_isempty(rnh->client_list) | ||||
| 	    && list_isempty(rnh->zebra_static_route_list)) | ||||
| 	    && list_isempty(rnh->zebra_static_route_list) | ||||
| 	    && list_isempty(rnh->zebra_pseudowire_list)) | ||||
| 		zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); | ||||
| } | ||||
| 
 | ||||
| @ -284,6 +288,58 @@ void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* XXX move this utility function elsewhere? */ | ||||
| static void addr2hostprefix(int af, const union g_addr *addr, | ||||
| 			    struct prefix *prefix) | ||||
| { | ||||
| 	switch (af) { | ||||
| 	case AF_INET: | ||||
| 		prefix->family = AF_INET; | ||||
| 		prefix->prefixlen = IPV4_MAX_BITLEN; | ||||
| 		prefix->u.prefix4 = addr->ipv4; | ||||
| 		break; | ||||
| 	case AF_INET6: | ||||
| 		prefix->family = AF_INET6; | ||||
| 		prefix->prefixlen = IPV6_MAX_BITLEN; | ||||
| 		prefix->u.prefix6 = addr->ipv6; | ||||
| 		break; | ||||
| 	default: | ||||
| 		zlog_warn("%s: unknown address family %d", __func__, af); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) | ||||
| { | ||||
| 	struct prefix nh; | ||||
| 	struct rnh *rnh; | ||||
| 
 | ||||
| 	addr2hostprefix(pw->af, &pw->nexthop, &nh); | ||||
| 	rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE); | ||||
| 	if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) { | ||||
| 		listnode_add(rnh->zebra_pseudowire_list, pw); | ||||
| 		pw->rnh = rnh; | ||||
| 		zebra_evaluate_rnh(vrf_id, pw->af, 1, RNH_NEXTHOP_TYPE, &nh); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) | ||||
| { | ||||
| 	struct rnh *rnh; | ||||
| 
 | ||||
| 	rnh = pw->rnh; | ||||
| 	if (!rnh) | ||||
| 		return; | ||||
| 
 | ||||
| 	listnode_delete(rnh->zebra_pseudowire_list, pw); | ||||
| 	pw->rnh = NULL; | ||||
| 
 | ||||
| 	if (list_isempty(rnh->client_list) | ||||
| 	    && list_isempty(rnh->zebra_static_route_list) | ||||
| 	    && list_isempty(rnh->zebra_pseudowire_list)) | ||||
| 		zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); | ||||
| } | ||||
| 
 | ||||
| /* Apply the NHT route-map for a client to the route (and nexthops)
 | ||||
|  * resolving a NH. | ||||
|  */ | ||||
| @ -595,6 +651,15 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh) | ||||
| { | ||||
| 	struct zebra_pw *pw; | ||||
| 	struct listnode *node; | ||||
| 
 | ||||
| 	for (ALL_LIST_ELEMENTS_RO(rnh->zebra_pseudowire_list, node, pw)) | ||||
| 		zebra_pw_update(pw); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * See if a tracked nexthop entry has undergone any change, and if so, | ||||
|  * take appropriate action; this involves notifying any clients and/or | ||||
| @ -636,6 +701,9 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force, | ||||
| 		/* Process static routes attached to this nexthop */ | ||||
| 		zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn, | ||||
| 						rnh->state); | ||||
| 
 | ||||
| 		/* Process pseudowires attached to this nexthop */ | ||||
| 		zebra_rnh_process_pseudowires(vrfid, rnh); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -694,8 +762,10 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family, | ||||
| 
 | ||||
| 	re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn); | ||||
| 
 | ||||
| 	if (re) | ||||
| 	if (re) { | ||||
| 		UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); | ||||
| 		UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Evaluate all tracked entries (nexthops or routes for import into BGP)
 | ||||
| @ -840,7 +910,8 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2) | ||||
| 	if (r1->nexthop_num != r2->nexthop_num) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED)) | ||||
| 	if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED) | ||||
| 	    || CHECK_FLAG(r1->status, ROUTE_ENTRY_LABELS_CHANGED)) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	return 0; | ||||
| @ -1003,5 +1074,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty) | ||||
| 	if (!list_isempty(rnh->zebra_static_route_list)) | ||||
| 		vty_out(vty, " zebra%s", | ||||
| 			rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : ""); | ||||
| 	if (!list_isempty(rnh->zebra_pseudowire_list)) | ||||
| 		vty_out(vty, " zebra[pseudowires]"); | ||||
| 	vty_out(vty, "\n"); | ||||
| } | ||||
|  | ||||
| @ -42,6 +42,8 @@ struct rnh { | ||||
| 	struct list * | ||||
| 		zebra_static_route_list; /* static routes dependent on this NH
 | ||||
| 					    */ | ||||
| 	struct list | ||||
| 		*zebra_pseudowire_list; /* pseudowires dependent on this NH */ | ||||
| 	struct route_node *node; | ||||
| 	int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client
 | ||||
| 					  */ | ||||
| @ -67,6 +69,8 @@ extern void zebra_deregister_rnh_static_nexthops(vrf_id_t, | ||||
| 						 struct route_node *rn); | ||||
| extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *, | ||||
| 					   struct route_node *); | ||||
| extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *); | ||||
| extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *); | ||||
| extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, | ||||
| 				    rnh_type_t type); | ||||
| extern void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force, | ||||
|  | ||||
| @ -203,6 +203,7 @@ static int zebra_vrf_delete(struct vrf *vrf) | ||||
| 		zebra_vxlan_close_tables(zvrf); | ||||
| 
 | ||||
| 		zebra_mpls_close_tables(zvrf); | ||||
| 		zebra_pw_exit(zvrf); | ||||
| 
 | ||||
| 		for (ALL_LIST_ELEMENTS_RO(vrf->iflist, node, ifp)) | ||||
| 			if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); | ||||
| @ -372,6 +373,7 @@ struct zebra_vrf *zebra_vrf_alloc(void) | ||||
| 
 | ||||
| 	zebra_vxlan_init_tables(zvrf); | ||||
| 	zebra_mpls_init_tables(zvrf); | ||||
| 	zebra_pw_init(zvrf); | ||||
| 
 | ||||
| 	return zvrf; | ||||
| } | ||||
|  | ||||
| @ -23,6 +23,7 @@ | ||||
| #define __ZEBRA_RIB_H__ | ||||
| 
 | ||||
| #include <zebra/zebra_ns.h> | ||||
| #include <zebra/zebra_pw.h> | ||||
| 
 | ||||
| /* MPLS (Segment Routing) global block */ | ||||
| typedef struct mpls_srgb_t_ { | ||||
| @ -89,6 +90,10 @@ struct zebra_vrf { | ||||
| 	/* MPLS Segment Routing Global block */ | ||||
| 	mpls_srgb_t mpls_srgb; | ||||
| 
 | ||||
| 	/* Pseudowires. */ | ||||
| 	struct zebra_pw_head pseudowires; | ||||
| 	struct zebra_static_pw_head static_pseudowires; | ||||
| 
 | ||||
| 	/* MPLS processing flags */ | ||||
| 	u_int16_t mpls_flags; | ||||
| #define MPLS_FLAG_SCHEDULE_LSPS    (1 << 0) | ||||
|  | ||||
							
								
								
									
										131
									
								
								zebra/zserv.c
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								zebra/zserv.c
									
									
									
									
									
								
							| @ -1085,6 +1085,27 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p, | ||||
| 	return zebra_server_send_message(client); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Function used by Zebra to send a PW status update to LDP daemon | ||||
|  */ | ||||
| int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) | ||||
| { | ||||
| 	struct stream *s; | ||||
| 
 | ||||
| 	s = client->obuf; | ||||
| 	stream_reset(s); | ||||
| 
 | ||||
| 	zserv_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); | ||||
| 	stream_write(s, pw->ifname, IF_NAMESIZE); | ||||
| 	stream_putl(s, pw->ifindex); | ||||
| 	stream_putl(s, pw->status); | ||||
| 
 | ||||
| 	/* Put length at the first point of the stream. */ | ||||
| 	stream_putw_at(s, 0, stream_get_endp(s)); | ||||
| 
 | ||||
| 	return zebra_server_send_message(client); | ||||
| } | ||||
| 
 | ||||
| /* Register zebra server interface information.  Send current all
 | ||||
|    interface and address information. */ | ||||
| static int zread_interface_add(struct zserv *client, u_short length, | ||||
| @ -1877,14 +1898,12 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length, | ||||
| 	if (command == ZEBRA_MPLS_LABELS_ADD) { | ||||
| 		mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate, | ||||
| 				 ifindex); | ||||
| 		if (out_label != MPLS_IMP_NULL_LABEL) | ||||
| 			mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, | ||||
| 					ifindex, distance, out_label); | ||||
| 		mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex, | ||||
| 				distance, out_label); | ||||
| 	} else if (command == ZEBRA_MPLS_LABELS_DELETE) { | ||||
| 		mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex); | ||||
| 		if (out_label != MPLS_IMP_NULL_LABEL) | ||||
| 			mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, | ||||
| 					ifindex, distance, out_label); | ||||
| 		mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex, | ||||
| 				distance, out_label); | ||||
| 	} | ||||
| } | ||||
| /* Send response to a label manager connect request to client */ | ||||
| @ -2039,6 +2058,97 @@ static void zread_label_manager_request(int cmd, struct zserv *client, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int zread_pseudowire(int command, struct zserv *client, u_short length, | ||||
| 			    vrf_id_t vrf_id) | ||||
| { | ||||
| 	struct stream *s; | ||||
| 	struct zebra_vrf *zvrf; | ||||
| 	char ifname[IF_NAMESIZE]; | ||||
| 	ifindex_t ifindex; | ||||
| 	int type; | ||||
| 	int af; | ||||
| 	union g_addr nexthop; | ||||
| 	uint32_t local_label; | ||||
| 	uint32_t remote_label; | ||||
| 	uint8_t flags; | ||||
| 	union pw_protocol_fields data; | ||||
| 	uint8_t protocol; | ||||
| 	struct zebra_pw *pw; | ||||
| 
 | ||||
| 	zvrf = vrf_info_lookup(vrf_id); | ||||
| 	if (!zvrf) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	/* Get input stream.  */ | ||||
| 	s = client->ibuf; | ||||
| 
 | ||||
| 	/* Get data. */ | ||||
| 	stream_get(ifname, s, IF_NAMESIZE); | ||||
| 	ifindex = stream_getl(s); | ||||
| 	type = stream_getl(s); | ||||
| 	af = stream_getl(s); | ||||
| 	switch (af) { | ||||
| 	case AF_INET: | ||||
| 		nexthop.ipv4.s_addr = stream_get_ipv4(s); | ||||
| 		break; | ||||
| 	case AF_INET6: | ||||
| 		stream_get(&nexthop.ipv6, s, 16); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
| 	local_label = stream_getl(s); | ||||
| 	remote_label = stream_getl(s); | ||||
| 	flags = stream_getc(s); | ||||
| 	stream_get(&data, s, sizeof(data)); | ||||
| 	protocol = client->proto; | ||||
| 
 | ||||
| 	pw = zebra_pw_find(zvrf, ifname); | ||||
| 	switch (command) { | ||||
| 	case ZEBRA_PW_ADD: | ||||
| 		if (pw) { | ||||
| 			zlog_warn("%s: pseudowire %s already exists [%s]", | ||||
| 				  __func__, ifname, | ||||
| 				  zserv_command_string(command)); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		zebra_pw_add(zvrf, ifname, protocol, client); | ||||
| 		break; | ||||
| 	case ZEBRA_PW_DELETE: | ||||
| 		if (!pw) { | ||||
| 			zlog_warn("%s: pseudowire %s not found [%s]", __func__, | ||||
| 				  ifname, zserv_command_string(command)); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		zebra_pw_del(zvrf, pw); | ||||
| 		break; | ||||
| 	case ZEBRA_PW_SET: | ||||
| 	case ZEBRA_PW_UNSET: | ||||
| 		if (!pw) { | ||||
| 			zlog_warn("%s: pseudowire %s not found [%s]", __func__, | ||||
| 				  ifname, zserv_command_string(command)); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		switch (command) { | ||||
| 		case ZEBRA_PW_SET: | ||||
| 			pw->enabled = 1; | ||||
| 			break; | ||||
| 		case ZEBRA_PW_UNSET: | ||||
| 			pw->enabled = 0; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		zebra_pw_change(pw, ifindex, type, af, &nexthop, local_label, | ||||
| 				remote_label, flags, &data); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Cleanup registered nexthops (across VRFs) upon client disconnect. */ | ||||
| static void zebra_client_close_cleanup_rnh(struct zserv *client) | ||||
| { | ||||
| @ -2083,6 +2193,9 @@ static void zebra_client_close(struct zserv *client) | ||||
| 	zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT), | ||||
| 					   client); | ||||
| 
 | ||||
| 	/* Remove pseudowires associated with this client */ | ||||
| 	zebra_pw_client_close(client); | ||||
| 
 | ||||
| 	/* Close file descriptor. */ | ||||
| 	if (client->sock) { | ||||
| 		unsigned long nroutes; | ||||
| @ -2436,6 +2549,12 @@ static int zebra_client_read(struct thread *thread) | ||||
| 	case ZEBRA_INTERFACE_SET_MASTER: | ||||
| 		zread_interface_set_master(client, sock, length); | ||||
| 		break; | ||||
| 	case ZEBRA_PW_ADD: | ||||
| 	case ZEBRA_PW_DELETE: | ||||
| 	case ZEBRA_PW_SET: | ||||
| 	case ZEBRA_PW_UNSET: | ||||
| 		zread_pseudowire(command, client, length, vrf_id); | ||||
| 		break; | ||||
| 	default: | ||||
| 		zlog_info("Zebra received unknown command %d", command); | ||||
| 		break; | ||||
|  | ||||
| @ -30,6 +30,8 @@ | ||||
| #include "zclient.h" | ||||
| 
 | ||||
| #include "zebra/zebra_ns.h" | ||||
| #include "zebra/zebra_pw.h" | ||||
| 
 | ||||
| /* Default port information. */ | ||||
| #define ZEBRA_VTY_PORT                2601 | ||||
| 
 | ||||
| @ -175,6 +177,7 @@ extern int zsend_interface_vrf_update(struct zserv *, struct interface *, | ||||
| 				      vrf_id_t); | ||||
| 
 | ||||
| extern int zsend_interface_link_params(struct zserv *, struct interface *); | ||||
| extern int zsend_pw_update(struct zserv *, struct zebra_pw *); | ||||
| 
 | ||||
| extern pid_t pid; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 David Lamparter
						David Lamparter