diff options
| -rw-r--r-- | ldpd/init.c | 67 | ||||
| -rw-r--r-- | ldpd/labelmapping.c | 72 | ||||
| -rw-r--r-- | ldpd/lde.c | 40 | ||||
| -rw-r--r-- | ldpd/lde.h | 3 | ||||
| -rw-r--r-- | ldpd/ldp.h | 8 | ||||
| -rw-r--r-- | ldpd/ldpe.h | 2 | ||||
| -rw-r--r-- | ldpd/log.c | 2 | ||||
| -rw-r--r-- | ldpd/neighbor.c | 1 | ||||
| -rw-r--r-- | ldpd/notification.c | 40 | 
9 files changed, 192 insertions, 43 deletions
diff --git a/ldpd/init.c b/ldpd/init.c index 13104b4ee6..bc3a69edc7 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -26,6 +26,7 @@  static int	gen_init_prms_tlv(struct ibuf *, struct nbr *);  static int	gen_cap_dynamic_tlv(struct ibuf *);  static int	gen_cap_twcard_tlv(struct ibuf *, int); +static int	gen_cap_unotif_tlv(struct ibuf *, int);  void  send_init(struct nbr *nbr) @@ -37,7 +38,7 @@ send_init(struct nbr *nbr)  	debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id));  	size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE + -	    CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE; +	    CAP_TLV_DYNAMIC_SIZE + CAP_TLV_TWCARD_SIZE + CAP_TLV_UNOTIF_SIZE;  	if ((buf = ibuf_open(size)) == NULL)  		fatal(__func__); @@ -47,6 +48,7 @@ send_init(struct nbr *nbr)  	err |= gen_init_prms_tlv(buf, nbr);  	err |= gen_cap_dynamic_tlv(buf);  	err |= gen_cap_twcard_tlv(buf, 1); +	err |= gen_cap_unotif_tlv(buf, 1);  	if (err) {  		ibuf_free(buf);  		return; @@ -167,6 +169,26 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)  			log_debug("%s: lsr-id %s announced the Typed Wildcard "  			    "FEC capability", __func__, inet_ntoa(nbr->id));  			break; +		case TLV_TYPE_UNOTIF_CAP: +			if (tlv_len != CAP_TLV_UNOTIF_LEN) { +				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, +				    msg.type); +				return (-1); +			} + +			if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) { +				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, +				    msg.type); +				return (-1); +			} +			caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF; + +			nbr->flags |= F_NBR_CAP_UNOTIF; + +			log_debug("%s: lsr-id %s announced the Unrecognized " +			    "Notification capability", __func__, +			    inet_ntoa(nbr->id)); +			break;  		default:  			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))  				send_notification_rtlvs(nbr, S_UNSSUPORTDCAP, @@ -217,6 +239,9 @@ send_capability(struct nbr *nbr, uint16_t capability, int enable)  	case TLV_TYPE_TWCARD_CAP:  		err |= gen_cap_twcard_tlv(buf, enable);  		break; +	case TLV_TYPE_UNOTIF_CAP: +		err |= gen_cap_unotif_tlv(buf, enable); +		break;  	case TLV_TYPE_DYNAMIC_CAP:  		/*  		 * RFC 5561 - Section 9: @@ -299,6 +324,32 @@ recv_capability(struct nbr *nbr, char *buf, uint16_t len)  			    "capability", __func__, inet_ntoa(nbr->id),  			    (enable) ? "announced" : "withdrew");  			break; +		case TLV_TYPE_UNOTIF_CAP: +			if (tlv_len != CAP_TLV_UNOTIF_LEN) { +				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, +				    msg.type); +				return (-1); +			} + +			if (caps_rcvd & F_CAP_TLV_RCVD_UNOTIF) { +				session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, +				    msg.type); +				return (-1); +			} +			caps_rcvd |= F_CAP_TLV_RCVD_UNOTIF; + +			memcpy(&reserved, buf, sizeof(reserved)); +			enable = reserved & STATE_BIT; +			if (enable) +				nbr->flags |= F_NBR_CAP_UNOTIF; +			else +				nbr->flags &= ~F_NBR_CAP_UNOTIF; + +			log_debug("%s: lsr-id %s %s the Unrecognized " +			    "Notification capability", __func__, +			    inet_ntoa(nbr->id), (enable) ? "announced" : +			    "withdrew"); +			break;  		case TLV_TYPE_DYNAMIC_CAP:  			/*  		 	 * RFC 5561 - Section 9: @@ -371,3 +422,17 @@ gen_cap_twcard_tlv(struct ibuf *buf, int enable)  	return (ibuf_add(buf, &cap, CAP_TLV_TWCARD_SIZE));  } + +static int +gen_cap_unotif_tlv(struct ibuf *buf, int enable) +{ +	struct capability_tlv	cap; + +	memset(&cap, 0, sizeof(cap)); +	cap.type = htons(TLV_TYPE_UNOTIF_CAP); +	cap.length = htons(CAP_TLV_UNOTIF_LEN); +	if (enable) +		cap.reserved = STATE_BIT; + +	return (ibuf_add(buf, &cap, CAP_TLV_UNOTIF_SIZE)); +} diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 55b890ac70..75acfd7d50 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -72,36 +72,8 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)  		}  		/* calculate size */ -		msg_size = LDP_MSG_SIZE + TLV_HDR_SIZE; -		switch (me->map.type) { -		case MAP_TYPE_WILDCARD: -			msg_size += FEC_ELM_WCARD_LEN; -			break; -		case MAP_TYPE_PREFIX: -			msg_size += FEC_ELM_PREFIX_MIN_LEN + -			    PREFIX_SIZE(me->map.fec.prefix.prefixlen); -			break; -		case MAP_TYPE_PWID: -			msg_size += FEC_PWID_ELM_MIN_LEN; -			if (me->map.flags & F_MAP_PW_ID) -				msg_size += PW_STATUS_TLV_LEN; -			if (me->map.flags & F_MAP_PW_IFMTU) -				msg_size += FEC_SUBTLV_IFMTU_SIZE; -	    		if (me->map.flags & F_MAP_PW_STATUS) -				msg_size += PW_STATUS_TLV_SIZE; -			break; -		case MAP_TYPE_TYPED_WCARD: -			msg_size += FEC_ELM_TWCARD_MIN_LEN; -			switch (me->map.fec.twcard.type) { -			case MAP_TYPE_PREFIX: -			case MAP_TYPE_PWID: -				msg_size += sizeof(uint16_t); -				break; -			default: -				fatalx("send_labelmessage: unexpected fec type"); -			} -			break; -		} +		msg_size = LDP_MSG_SIZE; +		msg_size += len_fec_tlv(&me->map);  		if (me->map.label != NO_LABEL)  			msg_size += LABEL_TLV_SIZE;  		if (me->map.flags & F_MAP_REQ_ID) @@ -548,6 +520,46 @@ gen_pw_status_tlv(struct ibuf *buf, uint32_t status)  	return (ibuf_add(buf, &st, sizeof(st)));  } +uint16_t +len_fec_tlv(struct map *map) +{ +	uint16_t	 len = TLV_HDR_SIZE; + +	switch (map->type) { +	case MAP_TYPE_WILDCARD: +		len += FEC_ELM_WCARD_LEN; +		break; +	case MAP_TYPE_PREFIX: +		len += FEC_ELM_PREFIX_MIN_LEN + +		    PREFIX_SIZE(map->fec.prefix.prefixlen); +		break; +	case MAP_TYPE_PWID: +		len += FEC_PWID_ELM_MIN_LEN; +		if (map->flags & F_MAP_PW_ID) +			len += PW_STATUS_TLV_LEN; +		if (map->flags & F_MAP_PW_IFMTU) +			len += FEC_SUBTLV_IFMTU_SIZE; +    		if (map->flags & F_MAP_PW_STATUS) +			len += PW_STATUS_TLV_SIZE; +		break; +	case MAP_TYPE_TYPED_WCARD: +		len += FEC_ELM_TWCARD_MIN_LEN; +		switch (map->fec.twcard.type) { +		case MAP_TYPE_PREFIX: +		case MAP_TYPE_PWID: +			len += sizeof(uint16_t); +			break; +		default: +			fatalx("len_fec_tlv: unexpected fec type"); +		} +		break; +	default: +		fatalx("len_fec_tlv: unexpected fec type"); +	} + +	return (len); +} +  int  gen_fec_tlv(struct ibuf *buf, struct map *map)  { diff --git a/ldpd/lde.c b/ldpd/lde.c index 2392dbf6d0..e64f18dfc9 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -319,6 +319,13 @@ lde_dispatch_imsg(struct thread *thread)  			case S_PW_STATUS:  				l2vpn_recv_pw_status(ln, &nm);  				break; +			case S_ENDOFLIB: +				/* +				 * Do nothing for now. Should be useful in +				 * the future when we implement LDP-IGP +				 * Synchronization (RFC 5443) and Graceful +				 * Restart (RFC 3478). +				 */  			default:  				break;  			} @@ -1099,6 +1106,38 @@ lde_send_notification(struct lde_nbr *ln, uint32_t status_code, uint32_t msg_id,  	    &nm, sizeof(nm));  } +void +lde_send_notification_eol_prefix(struct lde_nbr *ln, int af) +{ +	struct notify_msg nm; + +	memset(&nm, 0, sizeof(nm)); +	nm.status_code = S_ENDOFLIB; +	nm.fec.type = MAP_TYPE_TYPED_WCARD; +	nm.fec.fec.twcard.type = MAP_TYPE_PREFIX; +	nm.fec.fec.twcard.u.prefix_af = af; +	nm.flags |= F_NOTIF_FEC; + +	lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, +	    &nm, sizeof(nm)); +} + +void +lde_send_notification_eol_pwid(struct lde_nbr *ln, uint16_t pw_type) +{ +	struct notify_msg nm; + +	memset(&nm, 0, sizeof(nm)); +	nm.status_code = S_ENDOFLIB; +	nm.fec.type = MAP_TYPE_TYPED_WCARD; +	nm.fec.fec.twcard.type = MAP_TYPE_PWID; +	nm.fec.fec.twcard.u.pw_type = pw_type; +	nm.flags |= F_NOTIF_FEC; + +	lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, +	    &nm, sizeof(nm)); +} +  static __inline int  lde_nbr_compare(struct lde_nbr *a, struct lde_nbr *b)  { @@ -1116,6 +1155,7 @@ lde_nbr_new(uint32_t peerid, struct lde_nbr *new)  	ln->id = new->id;  	ln->v4_enabled = new->v4_enabled;  	ln->v6_enabled = new->v6_enabled; +	ln->flags = new->flags;  	ln->peerid = peerid;  	fec_init(&ln->recv_map);  	fec_init(&ln->sent_map); diff --git a/ldpd/lde.h b/ldpd/lde.h index b3af1bbaa4..a2b51dad32 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -90,6 +90,7 @@ struct lde_nbr {  	struct in_addr		 id;  	int			 v4_enabled;	/* announce/process v4 msgs */  	int			 v6_enabled;	/* announce/process v6 msgs */ +	int			 flags;		/* capabilities */  	struct fec_tree		 recv_req;  	struct fec_tree		 sent_req;  	struct fec_tree		 recv_map; @@ -155,6 +156,8 @@ void		 lde_send_labelrelease(struct lde_nbr *, struct fec_node *,  		    struct map *, uint32_t);  void		 lde_send_notification(struct lde_nbr *, uint32_t, uint32_t,  		    uint16_t); +void		 lde_send_notification_eol_prefix(struct lde_nbr *, int); +void		 lde_send_notification_eol_pwid(struct lde_nbr *, uint16_t);  struct lde_nbr	*lde_nbr_find_by_lsrid(struct in_addr);  struct lde_nbr	*lde_nbr_find_by_addr(int, union ldpd_addr *);  struct lde_map	*lde_map_add(struct lde_nbr *, struct fec_node *, int); diff --git a/ldpd/ldp.h b/ldpd/ldp.h index ffdadf8be9..0a42ab4076 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -101,6 +101,8 @@  #define TLV_TYPE_DYNAMIC_CAP	0x8506  /* RFC 5918 */  #define TLV_TYPE_TWCARD_CAP	0x850B +/* RFC 5919 */ +#define TLV_TYPE_UNOTIF_CAP	0x8603  /* RFC 7552 */  #define TLV_TYPE_DUALSTACK	0x8701 @@ -204,6 +206,8 @@ struct hello_prms_opt16_tlv {  #define S_WITHDRAW_MTHD	0x0000002B  /* RFC 5561 */  #define	S_UNSSUPORTDCAP	0x0000002E +/* RFC 5919 */ +#define	S_ENDOFLIB	0x0000002F  /* RFC 7552 */  #define	S_TRANS_MISMTCH	0x80000032  #define	S_DS_NONCMPLNCE	0x80000033 @@ -244,6 +248,7 @@ struct capability_tlv {  #define F_CAP_TLV_RCVD_DYNAMIC	0x01  #define F_CAP_TLV_RCVD_TWCARD	0x02 +#define F_CAP_TLV_RCVD_UNOTIF	0x04  #define CAP_TLV_DYNAMIC_SIZE	5  #define CAP_TLV_DYNAMIC_LEN	1 @@ -251,6 +256,9 @@ struct capability_tlv {  #define CAP_TLV_TWCARD_SIZE	5  #define CAP_TLV_TWCARD_LEN	1 +#define CAP_TLV_UNOTIF_SIZE	5 +#define CAP_TLV_UNOTIF_LEN	1 +  #define	AF_IPV4			0x1  #define	AF_IPV6			0x2 diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 24512989de..2bd0568d68 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -113,6 +113,7 @@ struct nbr {  #define F_NBR_GTSM_NEGOTIATED	 0x01  #define F_NBR_CAP_DYNAMIC	 0x02  #define F_NBR_CAP_TWCARD	 0x04 +#define F_NBR_CAP_UNOTIF	 0x08  RB_HEAD(nbr_id_head, nbr);  RB_PROTOTYPE(nbr_id_head, nbr, id_tree, nbr_id_compare) @@ -186,6 +187,7 @@ int	 recv_address(struct nbr *, char *, uint16_t);  void	 send_labelmessage(struct nbr *, uint16_t, struct mapping_head *);  int	 recv_labelmessage(struct nbr *, char *, uint16_t, uint16_t);  int	 gen_pw_status_tlv(struct ibuf *, uint32_t); +uint16_t len_fec_tlv(struct map *);  int	 gen_fec_tlv(struct ibuf *, struct map *);  int	 tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,  	    uint16_t, struct map *); diff --git a/ldpd/log.c b/ldpd/log.c index 5ad8ca0caf..b30604db0d 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -584,6 +584,8 @@ status_code_name(uint32_t status)  		return ("Label Withdraw PW Status Method");  	case S_UNSSUPORTDCAP:  		return ("Unsupported Capability"); +	case S_ENDOFLIB: +		return ("End-of-LIB");  	case S_TRANS_MISMTCH:  		return ("Transport Connection Mismatch");  	case S_DS_NONCMPLNCE: diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index d24ceb1229..077d472850 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -744,6 +744,7 @@ nbr_act_session_operational(struct nbr *nbr)  	lde_nbr.id = nbr->id;  	lde_nbr.v4_enabled = nbr->v4_enabled;  	lde_nbr.v6_enabled = nbr->v6_enabled; +	lde_nbr.flags = nbr->flags;  	return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0,  	    &lde_nbr, sizeof(lde_nbr)));  } diff --git a/ldpd/notification.c b/ldpd/notification.c index 69d4ab8028..393994ed5f 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -38,16 +38,8 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)  	size = LDP_HDR_SIZE + LDP_MSG_SIZE + STATUS_SIZE;  	if (nm->flags & F_NOTIF_PW_STATUS)  		size += PW_STATUS_TLV_SIZE; -	if (nm->flags & F_NOTIF_FEC) { -		size += TLV_HDR_SIZE; -		switch (nm->fec.type) { -		case MAP_TYPE_PWID: -			size += FEC_PWID_ELM_MIN_LEN; -			if (nm->fec.flags & F_MAP_PW_ID) -				size += sizeof(uint32_t); -			break; -		} -	} +	if (nm->flags & F_NOTIF_FEC) +		size += len_fec_tlv(&nm->fec);  	if (nm->flags & F_NOTIF_RETURNED_TLVS)  		size += TLV_HDR_SIZE * 2 + nm->rtlvs.length; @@ -204,7 +196,9 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)  		len -= tlv_len;  	} -	if (nm.status_code == S_PW_STATUS) { +	/* sanity checks */ +	switch (nm.status_code) { +	case S_PW_STATUS:  		if (!(nm.flags & (F_NOTIF_PW_STATUS|F_NOTIF_FEC))) {  			send_notification(nbr->tcp, S_MISS_MSG,  			    msg.id, msg.type); @@ -219,6 +213,21 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)  			    msg.id, msg.type);  			return (-1);  		} +		break; +	case S_ENDOFLIB: +		if (!(nm.flags & F_NOTIF_FEC)) { +			send_notification(nbr->tcp, S_MISS_MSG, +			    msg.id, msg.type); +			return (-1); +		} +		if (nm.fec.type != MAP_TYPE_TYPED_WCARD) { +			send_notification(nbr->tcp, S_BAD_TLV_VAL, +			    msg.id, msg.type); +			return (-1); +		} +		break; +	default: +		break;  	}  	log_msg_notification(0, nbr, &nm); @@ -231,9 +240,16 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)  		return (-1);  	} -	if (nm.status_code == S_PW_STATUS) +	/* lde needs to know about a few notification messages */ +	switch (nm.status_code) { +	case S_PW_STATUS: +	case S_ENDOFLIB:  		ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0,  		    &nm, sizeof(nm)); +		break; +	default: +		break; +	}  	return (0);  }  | 
