diff options
author | Renato Westphal <renato@cvs.openbsd.org> | 2015-07-21 04:52:30 +0000 |
---|---|---|
committer | Renato Westphal <renato@cvs.openbsd.org> | 2015-07-21 04:52:30 +0000 |
commit | a2ae921ed55c91e98ece8ee7f0b365851fb30633 (patch) | |
tree | 40369cff7366d5b45e4df63f807681b223eb63f8 /usr.sbin/ldpd/labelmapping.c | |
parent | 6e1f964c76fe64a2e4d55765a578dbb338c18266 (diff) |
VPLS signaling support.
This patch introduces full support for pseudowire signaling in ldpd(8),
including Control Word and Status TLV negotiation.
As of now it's not possible to configure a VPWS, but the signaling is
the same. In the future, when VPWS support is available in the kernel,
ldpd(8) can be extended to support VPWS with only a few modifications.
Limitations:
* No support for FEC 129, only FEC 128 (more widely deployed);
* No support for group withdraws (not widely deployed);
* No support for MAC withdraws (not widely deployed).
Related RFCs:
* RFC 3916: Requirements for Pseudo-Wire Emulation Edge-to-Edge (PWE3)
* RFC 3985: Pseudo Wire Emulation Edge-to-Edge (PWE3) Architecture
* RFC 4385: Pseudowire Emulation Edge-to-Edge (PWE3) Control Word for
Use over an MPLS PSN
* RFC 4446: IANA Allocations for Pseudowire Edge to Edge Emulation (PWE3)
* RFC 4447: Pseudowire Setup and Maintenance Using the Label Distribution
Protocol (LDP)
* RFC 4448: Encapsulation Methods for Transport of Ethernet over MPLS
Networks
* RFC 4905: Encapsulation Methods for Transport of Layer 2 Frames over
MPLS Networks
* RFC 4906: Transport of Layer 2 Frames Over MPLS
ok claudio@
Diffstat (limited to 'usr.sbin/ldpd/labelmapping.c')
-rw-r--r-- | usr.sbin/ldpd/labelmapping.c | 338 |
1 files changed, 258 insertions, 80 deletions
diff --git a/usr.sbin/ldpd/labelmapping.c b/usr.sbin/ldpd/labelmapping.c index df62ce14e44..2652092c594 100644 --- a/usr.sbin/ldpd/labelmapping.c +++ b/usr.sbin/ldpd/labelmapping.c @@ -1,4 +1,4 @@ -/* $OpenBSD: labelmapping.c,v 1.32 2015/07/19 20:54:16 renato Exp $ */ +/* $OpenBSD: labelmapping.c,v 1.33 2015/07/21 04:52:29 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -40,13 +40,9 @@ void gen_label_tlv(struct ibuf *, u_int32_t); void gen_reqid_tlv(struct ibuf *, u_int32_t); -void gen_fec_tlv(struct ibuf *, struct in_addr, u_int8_t); -void gen_wcard_fec_tlv(struct ibuf *); int tlv_decode_label(struct nbr *, struct ldp_msg *, char *, u_int16_t, u_int32_t *); -int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, u_int16_t, - u_int8_t *, u_int32_t *, u_int8_t *); static void enqueue_pdu(struct nbr *nbr, struct ibuf *buf, u_int16_t size) @@ -82,11 +78,27 @@ send_labelmessage(struct nbr *nbr, u_int16_t type, struct mapping_head *mh) /* calculate size */ tlv_size = LDP_MSG_LEN + TLV_HDR_LEN; - if (me->map.flags & F_MAP_WILDCARD) + + switch (me->map.type) { + case FEC_WILDCARD: tlv_size += FEC_ELM_WCARD_LEN; - else + break; + case FEC_PREFIX: tlv_size += FEC_ELM_PREFIX_MIN_LEN + - PREFIX_SIZE(me->map.prefixlen); + PREFIX_SIZE(me->map.fec.ipv4.prefixlen); + break; + case FEC_PWID: + tlv_size += FEC_PWID_ELM_MIN_LEN; + + if (me->map.flags & F_MAP_PW_ID) + tlv_size += sizeof(u_int32_t); + if (me->map.flags & F_MAP_PW_IFMTU) + tlv_size += FEC_SUBTLV_IFMTU_LEN; + if (me->map.flags & F_MAP_PW_STATUS) + tlv_size += PW_STATUS_TLV_LEN; + break; + } + if (me->map.label != NO_LABEL) tlv_size += LABEL_TLV_LEN; if (me->map.flags & F_MAP_REQ_ID) @@ -103,14 +115,13 @@ send_labelmessage(struct nbr *nbr, u_int16_t type, struct mapping_head *mh) /* append message and tlvs */ gen_msg_tlv(buf, type, tlv_size); - if (me->map.flags & F_MAP_WILDCARD) - gen_wcard_fec_tlv(buf); - else - gen_fec_tlv(buf, me->map.prefix, me->map.prefixlen); + gen_fec_tlv(buf, &me->map); if (me->map.label != NO_LABEL) gen_label_tlv(buf, me->map.label); if (me->map.flags & F_MAP_REQ_ID) gen_reqid_tlv(buf, me->map.requestid); + if (me->map.flags & F_MAP_PW_STATUS) + gen_pw_status_tlv(buf, me->map.pw_status); TAILQ_REMOVE(mh, me, entry); free(me); @@ -128,10 +139,9 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) struct ldp_msg lm; struct tlv ft; u_int32_t label = NO_LABEL, reqid = 0; + u_int32_t pw_status = 0; u_int8_t flags = 0; - int feclen, lbllen, tlen; - u_int8_t addr_type; struct mapping_entry *me; struct mapping_head mh; @@ -168,23 +178,29 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) TAILQ_INSERT_HEAD(&mh, me, entry); if ((tlen = tlv_decode_fec_elm(nbr, &lm, buf, feclen, - &addr_type, &me->map.prefix.s_addr, &me->map.prefixlen)) == -1) + &me->map)) == -1) goto err; + if (me->map.type == FEC_PWID && + type == MSG_TYPE_LABELMAPPING && + !(me->map.flags & F_MAP_PW_ID)) { + send_notification_nbr(nbr, S_MISS_MSG, lm.msgid, + lm.type); + return (-1); + } /* * The Wildcard FEC Element can be used only in the * Label Withdraw and Label Release messages. */ - if (addr_type == FEC_WILDCARD) { + if (me->map.type == FEC_WILDCARD) { switch (type) { - case MSG_TYPE_LABELWITHDRAW: - case MSG_TYPE_LABELRELEASE: - me->map.flags |= F_MAP_WILDCARD; - break; - default: + case MSG_TYPE_LABELMAPPING: + case MSG_TYPE_LABELREQUEST: + case MSG_TYPE_LABELABORTREQ: session_shutdown(nbr, S_BAD_TLV_VAL, lm.msgid, lm.type); goto err; + default: break; } } @@ -218,7 +234,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) /* Optional Parameters */ while (len > 0) { struct tlv tlv; - u_int32_t reqbuf, labelbuf; + u_int32_t reqbuf, labelbuf, statusbuf; if (len < sizeof(tlv)) { session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, @@ -227,10 +243,15 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) } bcopy(buf, &tlv, sizeof(tlv)); + if (ntohs(tlv.length) > len - TLV_HDR_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, lm.msgid, + lm.type); + goto err; + } buf += TLV_HDR_LEN; len -= TLV_HDR_LEN; - switch (ntohs(tlv.type)) { + switch (ntohs(tlv.type) & ~UNKNOWN_FLAG) { case TLV_TYPE_LABELREQUEST: switch (type) { case MSG_TYPE_LABELMAPPING: @@ -287,6 +308,24 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) break; } break; + case TLV_TYPE_PW_STATUS: + switch (type) { + case MSG_TYPE_LABELMAPPING: + if (ntohs(tlv.length) != 4) { + session_shutdown(nbr, S_BAD_TLV_LEN, + lm.msgid, lm.type); + goto err; + } + + flags |= F_MAP_PW_STATUS; + memcpy(&statusbuf, buf, sizeof(statusbuf)); + pw_status = ntohl(statusbuf); + break; + default: + /* ignore */ + break; + } + break; default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) { send_notification_nbr(nbr, S_UNKNOWN_TLV, @@ -307,32 +346,34 @@ recv_labelmessage(struct nbr *nbr, char *buf, u_int16_t len, u_int16_t type) me->map.label = label; if (me->map.flags & F_MAP_REQ_ID) me->map.requestid = reqid; + if (me->map.flags & F_MAP_PW_STATUS) + me->map.pw_status = pw_status; switch (type) { case MSG_TYPE_LABELMAPPING: log_debug("label mapping from nbr %s, FEC %s, " "label %u", inet_ntoa(nbr->id), - log_fec(&me->map), me->map.label); + log_map(&me->map), me->map.label); imsg_type = IMSG_LABEL_MAPPING; break; case MSG_TYPE_LABELREQUEST: log_debug("label request from nbr %s, FEC %s", - inet_ntoa(nbr->id), log_fec(&me->map)); + inet_ntoa(nbr->id), log_map(&me->map)); imsg_type = IMSG_LABEL_REQUEST; break; case MSG_TYPE_LABELWITHDRAW: log_debug("label withdraw from nbr %s, FEC %s", - inet_ntoa(nbr->id), log_fec(&me->map)); + inet_ntoa(nbr->id), log_map(&me->map)); imsg_type = IMSG_LABEL_WITHDRAW; break; case MSG_TYPE_LABELRELEASE: log_debug("label release from nbr %s, FEC %s", - inet_ntoa(nbr->id), log_fec(&me->map)); + inet_ntoa(nbr->id), log_map(&me->map)); imsg_type = IMSG_LABEL_RELEASE; break; case MSG_TYPE_LABELABORTREQ: log_debug("label abort from nbr %s, FEC %s", - inet_ntoa(nbr->id), log_fec(&me->map)); + inet_ntoa(nbr->id), log_map(&me->map)); imsg_type = IMSG_LABEL_ABORT; break; default: @@ -426,54 +467,99 @@ gen_reqid_tlv(struct ibuf *buf, u_int32_t reqid) } void -gen_fec_tlv(struct ibuf *buf, struct in_addr prefix, u_int8_t prefixlen) +gen_pw_status_tlv(struct ibuf *buf, u_int32_t status) { - struct tlv ft; - u_int8_t type; - u_int16_t family; - u_int8_t len; + struct pw_status_tlv st; - len = PREFIX_SIZE(prefixlen); - ft.type = htons(TLV_TYPE_FEC); - ft.length = htons(sizeof(type) + sizeof(family) + sizeof(prefixlen) + - len); + st.type = htons(TLV_TYPE_PW_STATUS); + st.length = htons(sizeof(status)); + st.value = htonl(status); - ibuf_add(buf, &ft, sizeof(ft)); - - type = FEC_PREFIX; - family = htons(FEC_IPV4); - - ibuf_add(buf, &type, sizeof(type)); - ibuf_add(buf, &family, sizeof(family)); - ibuf_add(buf, &prefixlen, sizeof(prefixlen)); - if (len) - ibuf_add(buf, &prefix, len); + ibuf_add(buf, &st, sizeof(st)); } void -gen_wcard_fec_tlv(struct ibuf *buf) +gen_fec_tlv(struct ibuf *buf, struct map *map) { struct tlv ft; - u_int8_t type; + u_int16_t family, len, pw_type, ifmtu; + u_int8_t pw_len = 0; + u_int32_t group_id, pwid; ft.type = htons(TLV_TYPE_FEC); - ft.length = htons(sizeof(type)); - ibuf_add(buf, &ft, sizeof(ft)); - type = FEC_WILDCARD; - ibuf_add(buf, &type, sizeof(type)); + switch (map->type) { + case FEC_WILDCARD: + ft.length = htons(sizeof(u_int8_t)); + ibuf_add(buf, &ft, sizeof(ft)); + ibuf_add(buf, &map->type, sizeof(map->type)); + break; + case FEC_PREFIX: + len = PREFIX_SIZE(map->fec.ipv4.prefixlen); + ft.length = htons(sizeof(map->type) + sizeof(family) + + sizeof(map->fec.ipv4.prefixlen) + len); + ibuf_add(buf, &ft, sizeof(ft)); + + ibuf_add(buf, &map->type, sizeof(map->type)); + family = htons(AF_IPV4); + ibuf_add(buf, &family, sizeof(family)); + ibuf_add(buf, &map->fec.ipv4.prefixlen, + sizeof(map->fec.ipv4.prefixlen)); + if (len) + ibuf_add(buf, &map->fec.ipv4.prefix, len); + break; + case FEC_PWID: + if (map->flags & F_MAP_PW_ID) + pw_len += sizeof(u_int32_t); + if (map->flags & F_MAP_PW_IFMTU) + pw_len += FEC_SUBTLV_IFMTU_LEN; + + len = FEC_PWID_ELM_MIN_LEN + pw_len; + + ft.length = htons(len); + ibuf_add(buf, &ft, sizeof(ft)); + + ibuf_add(buf, &map->type, sizeof(u_int8_t)); + pw_type = map->fec.pwid.type; + if (map->flags & F_MAP_PW_CWORD) + pw_type |= CONTROL_WORD_FLAG; + pw_type = htons(pw_type); + ibuf_add(buf, &pw_type, sizeof(u_int16_t)); + ibuf_add(buf, &pw_len, sizeof(u_int8_t)); + group_id = htonl(map->fec.pwid.group_id); + ibuf_add(buf, &group_id, sizeof(u_int32_t)); + if (map->flags & F_MAP_PW_ID) { + pwid = htonl(map->fec.pwid.pwid); + ibuf_add(buf, &pwid, sizeof(u_int32_t)); + } + if (map->flags & F_MAP_PW_IFMTU) { + struct subtlv stlv; + + stlv.type = SUBTLV_IFMTU; + stlv.length = FEC_SUBTLV_IFMTU_LEN; + ibuf_add(buf, &stlv, sizeof(u_int16_t)); + + ifmtu = htons(map->fec.pwid.ifmtu); + ibuf_add(buf, &ifmtu, sizeof(u_int16_t)); + } + break; + default: + break; + } } int tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, - u_int16_t len, u_int8_t *type, u_int32_t *prefix, u_int8_t *prefixlen) + u_int16_t len, struct map *map) { u_int16_t family, off = 0; + u_int8_t pw_len; - *type = *buf; + map->type = *buf; off += sizeof(u_int8_t); - if (*type == FEC_WILDCARD) { + switch (map->type) { + case FEC_WILDCARD: if (len == FEC_ELM_WCARD_LEN) return (off); else { @@ -481,36 +567,128 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *lm, char *buf, lm->type); return (-1); } - } + break; + case FEC_PREFIX: + if (len < FEC_ELM_PREFIX_MIN_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, + lm->type); + return (-1); + } - if (*type != FEC_PREFIX) { - send_notification_nbr(nbr, S_UNKNOWN_FEC, lm->msgid, lm->type); - return (-1); - } + /* Address Family */ + bcopy(buf + off, &family, sizeof(family)); + off += sizeof(family); - if (len < FEC_ELM_PREFIX_MIN_LEN) { - session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); - return (-1); - } + if (family != htons(AF_IPV4)) { + send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid, + lm->type); + return (-1); + } - bcopy(buf + off, &family, sizeof(family)); - off += sizeof(family); + /* PreLen */ + map->fec.ipv4.prefixlen = buf[off]; + off += sizeof(u_int8_t); - if (family != htons(FEC_IPV4)) { - send_notification_nbr(nbr, S_UNSUP_ADDR, lm->msgid, lm->type); - return (-1); - } + if (len < off + PREFIX_SIZE(map->fec.ipv4.prefixlen)) { + session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, + lm->type); + return (-1); + } - *prefixlen = buf[off]; - off += sizeof(u_int8_t); + /* Prefix */ + map->fec.ipv4.prefix.s_addr = 0; + bcopy(buf + off, &map->fec.ipv4.prefix, + PREFIX_SIZE(map->fec.ipv4.prefixlen)); - if (len < off + PREFIX_SIZE(*prefixlen)) { - session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, lm->type); - return (-1); - } + return (off + PREFIX_SIZE(map->fec.ipv4.prefixlen)); + break; + case FEC_PWID: + if (len < FEC_PWID_ELM_MIN_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, + lm->type); + return (-1); + } + + /* PW type */ + bcopy(buf + off, &map->fec.pwid.type, sizeof(u_int16_t)); + map->fec.pwid.type = ntohs(map->fec.pwid.type); + if (map->fec.pwid.type & CONTROL_WORD_FLAG) { + map->flags |= F_MAP_PW_CWORD; + map->fec.pwid.type &= ~CONTROL_WORD_FLAG; + } + off += sizeof(u_int16_t); + + /* PW info Length */ + pw_len = buf[off]; + off += sizeof(u_int8_t); + + if (len != FEC_PWID_ELM_MIN_LEN + pw_len) { + session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, + lm->type); + return (-1); + } - *prefix = 0; - bcopy(buf + off, prefix, PREFIX_SIZE(*prefixlen)); + /* Group ID */ + bcopy(buf + off, &map->fec.pwid.group_id, sizeof(u_int32_t)); + map->fec.pwid.group_id = ntohl(map->fec.pwid.group_id); + off += sizeof(u_int32_t); - return (off + PREFIX_SIZE(*prefixlen)); + /* PW ID */ + if (pw_len == 0) + return (off); + + if (pw_len < sizeof(u_int32_t)) { + session_shutdown(nbr, S_BAD_TLV_LEN, lm->msgid, + lm->type); + return (-1); + } + + bcopy(buf + off, &map->fec.pwid.pwid, sizeof(u_int32_t)); + map->fec.pwid.pwid = ntohl(map->fec.pwid.pwid); + map->flags |= F_MAP_PW_ID; + off += sizeof(u_int32_t); + pw_len -= sizeof(u_int32_t); + + /* Optional Interface Parameter Sub-TLVs */ + while (pw_len > 0) { + struct subtlv stlv; + + if (pw_len < sizeof(stlv)) { + session_shutdown(nbr, S_BAD_TLV_LEN, + lm->msgid, lm->type); + return (-1); + } + + bcopy(buf + off, &stlv, sizeof(stlv)); + off += SUBTLV_HDR_LEN; + pw_len -= SUBTLV_HDR_LEN; + + switch (stlv.type) { + case SUBTLV_IFMTU: + if (stlv.length != FEC_SUBTLV_IFMTU_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, + lm->msgid, lm->type); + return (-1); + } + bcopy(buf + off, &map->fec.pwid.ifmtu, + sizeof(u_int16_t)); + map->fec.pwid.ifmtu = ntohs(map->fec.pwid.ifmtu); + map->flags |= F_MAP_PW_IFMTU; + break; + default: + /* ignore */ + break; + } + off += stlv.length - SUBTLV_HDR_LEN; + pw_len -= stlv.length - SUBTLV_HDR_LEN; + } + + return (off); + break; + default: + send_notification_nbr(nbr, S_UNKNOWN_FEC, lm->msgid, lm->type); + break; + } + + return (-1); } |