X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ldpd%2Flabelmapping.c;h=944f93331f002a3fb1ef6c6ae3cfaa4a6b27171f;hb=c52e2ecf95a9be318912caacc0851d9307e679f7;hp=15861cfd9ac2c37ff32a3fc3db653119810ed68e;hpb=05aac414e69068748a8e6d6f7e3b0bdb74677039;p=mirror_frr.git diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 15861cfd9..944f93331 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -26,14 +26,13 @@ #include "mpls.h" -static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t); +static void enqueue_pdu(struct nbr *, uint16_t, struct ibuf *, uint16_t); static int gen_label_tlv(struct ibuf *, uint32_t); -static int tlv_decode_label(struct nbr *, struct ldp_msg *, char *, - uint16_t, uint32_t *); static int gen_reqid_tlv(struct ibuf *, uint32_t); +static void log_msg_mapping(int, uint16_t, struct nbr *, struct map *); static void -enqueue_pdu(struct nbr *nbr, struct ibuf *buf, uint16_t size) +enqueue_pdu(struct nbr *nbr, uint16_t type, struct ibuf *buf, uint16_t size) { struct ldp_hdr *ldp_hdr; @@ -71,25 +70,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; - } + 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) @@ -99,7 +81,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) /* maximum pdu length exceeded, we need a new ldp pdu */ if (size + msg_size > nbr->max_pdu_len) { - enqueue_pdu(nbr, buf, size); + enqueue_pdu(nbr, type, buf, size); first = 1; continue; } @@ -124,15 +106,35 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) return; } - debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type), - inet_ntoa(nbr->id), log_map(&me->map), - log_label(me->map.label)); + log_msg_mapping(1, type, nbr, &me->map); + + /* no errors - update per neighbor message counters */ + switch (type) { + case MSG_TYPE_LABELMAPPING: + nbr->stats.labelmap_sent++; + break; + case MSG_TYPE_LABELREQUEST: + nbr->stats.labelreq_sent++; + break; + case MSG_TYPE_LABELWITHDRAW: + nbr->stats.labelwdraw_sent++; + break; + case MSG_TYPE_LABELRELEASE: + nbr->stats.labelrel_sent++; + break; + case MSG_TYPE_LABELABORTREQ: + nbr->stats.labelabreq_sent++; + break; + default: + break; + } TAILQ_REMOVE(mh, me, entry); + assert(me != TAILQ_FIRST(mh)); free(me); } - enqueue_pdu(nbr, buf, size); + enqueue_pdu(nbr, type, buf, size); nbr_fsm(nbr, NBR_EVT_PDU_SENT); } @@ -146,7 +148,8 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) uint32_t label = NO_LABEL, reqid = 0; uint32_t pw_status = 0; uint8_t flags = 0; - int feclen, lbllen, tlen; + int feclen, tlen; + uint16_t current_tlv = 1; struct mapping_entry *me; struct mapping_head mh; struct map map; @@ -163,7 +166,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) memcpy(&ft, buf, sizeof(ft)); if (ntohs(ft.type) != TLV_TYPE_FEC) { - send_notification_nbr(nbr, S_MISS_MSG, msg.id, msg.type); + send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); return (-1); } feclen = ntohs(ft.length); @@ -187,9 +190,9 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) !(map.flags & F_MAP_PW_ID) && type != MSG_TYPE_LABELWITHDRAW && type != MSG_TYPE_LABELRELEASE) { - send_notification_nbr(nbr, S_MISS_MSG, msg.id, + send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type); - return (-1); + goto err; } /* @@ -209,6 +212,24 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) } } + /* + * RFC 5561 - Section 4: + * "An LDP implementation that supports the Typed Wildcard + * FEC Element MUST support its use in Label Request, Label + * Withdraw, and Label Release messages". + */ + if (map.type == MAP_TYPE_TYPED_WCARD) { + switch (type) { + case MSG_TYPE_LABELMAPPING: + case MSG_TYPE_LABELABORTREQ: + session_shutdown(nbr, S_UNKNOWN_FEC, msg.id, + msg.type); + goto err; + default: + break; + } + } + /* * LDP supports the use of multiple FEC Elements per * FEC for the Label Mapping message only. @@ -226,19 +247,10 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) feclen -= tlen; } while (feclen > 0); - /* Mandatory Label TLV */ - if (type == MSG_TYPE_LABELMAPPING) { - lbllen = tlv_decode_label(nbr, &msg, buf, len, &label); - if (lbllen == -1) - goto err; - - buf += lbllen; - len -= lbllen; - } - /* Optional Parameters */ while (len > 0) { struct tlv tlv; + uint16_t tlv_type; uint16_t tlv_len; uint32_t reqbuf, labelbuf, statusbuf; @@ -248,6 +260,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) } memcpy(&tlv, buf, TLV_HDR_SIZE); + tlv_type = ntohs(tlv.type); tlv_len = ntohs(tlv.length); if (tlv_len + TLV_HDR_SIZE > len) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); @@ -256,7 +269,18 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) buf += TLV_HDR_SIZE; len -= TLV_HDR_SIZE; - switch (ntohs(tlv.type)) { + /* + * For Label Mapping messages the Label TLV is mandatory and + * should appear right after the FEC TLV. + */ + if (current_tlv == 1 && type == MSG_TYPE_LABELMAPPING && + !(tlv_type & TLV_TYPE_GENERICLABEL)) { + send_notification(nbr->tcp, S_MISS_MSG, msg.id, + msg.type); + goto err; + } + + switch (tlv_type) { case TLV_TYPE_LABELREQUEST: switch (type) { case MSG_TYPE_LABELMAPPING: @@ -282,6 +306,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) break; case TLV_TYPE_GENERICLABEL: switch (type) { + case MSG_TYPE_LABELMAPPING: case MSG_TYPE_LABELWITHDRAW: case MSG_TYPE_LABELRELEASE: if (tlv_len != LABEL_TLV_LEN) { @@ -292,6 +317,16 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) memcpy(&labelbuf, buf, sizeof(labelbuf)); label = ntohl(labelbuf); + /* do not accept invalid labels */ + if (label > MPLS_LABEL_MAX || + (label <= MPLS_LABEL_RESERVED_MAX && + label != MPLS_LABEL_IPV4_EXPLICIT_NULL && + label != MPLS_LABEL_IPV6_EXPLICIT_NULL && + label != MPLS_LABEL_IMPLICIT_NULL)) { + session_shutdown(nbr, S_BAD_TLV_VAL, + msg.id, msg.type); + goto err; + } break; default: /* ignore */ @@ -301,6 +336,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) case TLV_TYPE_ATMLABEL: case TLV_TYPE_FRLABEL: switch (type) { + case MSG_TYPE_LABELMAPPING: case MSG_TYPE_LABELWITHDRAW: case MSG_TYPE_LABELRELEASE: /* unsupported */ @@ -341,13 +377,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) break; default: if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) - send_notification_nbr(nbr, S_UNKNOWN_TLV, - msg.id, msg.type); + send_notification_rtlvs(nbr, S_UNKNOWN_TLV, + msg.id, msg.type, tlv_type, tlv_len, buf); /* ignore unknown tlv */ break; } buf += tlv_len; len -= tlv_len; + current_tlv++; } /* notify lde about the received message. */ @@ -359,7 +396,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) case MAP_TYPE_PREFIX: switch (me->map.fec.prefix.af) { case AF_INET: - if (label == MPLS_LABEL_IPV6NULL) { + if (label == MPLS_LABEL_IPV6_EXPLICIT_NULL) { session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); goto err; @@ -368,7 +405,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) goto next; break; case AF_INET6: - if (label == MPLS_LABEL_IPV4NULL) { + if (label == MPLS_LABEL_IPV4_EXPLICIT_NULL) { session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); goto err; @@ -396,9 +433,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) if (me->map.flags & F_MAP_REQ_ID) me->map.requestid = reqid; - debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type), - inet_ntoa(nbr->id), log_map(&me->map), - log_label(me->map.label)); + log_msg_mapping(0, type, nbr, &me->map); switch (type) { case MSG_TYPE_LABELMAPPING: @@ -425,6 +460,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) next: TAILQ_REMOVE(&mh, me, entry); + assert(me != TAILQ_FIRST(&mh)); free(me); } @@ -449,53 +485,6 @@ gen_label_tlv(struct ibuf *buf, uint32_t label) return (ibuf_add(buf, <, sizeof(lt))); } -static int -tlv_decode_label(struct nbr *nbr, struct ldp_msg *msg, char *buf, - uint16_t len, uint32_t *label) -{ - struct label_tlv lt; - - if (len < sizeof(lt)) { - session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type); - return (-1); - } - memcpy(<, buf, sizeof(lt)); - - if (!(ntohs(lt.type) & TLV_TYPE_GENERICLABEL)) { - send_notification_nbr(nbr, S_MISS_MSG, msg->id, msg->type); - return (-1); - } - - switch (htons(lt.type)) { - case TLV_TYPE_GENERICLABEL: - if (ntohs(lt.length) != sizeof(lt) - TLV_HDR_SIZE) { - session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, - msg->type); - return (-1); - } - - *label = ntohl(lt.label); - if (*label > MPLS_LABEL_MAX || - (*label <= MPLS_LABEL_RESERVED_MAX && - *label != MPLS_LABEL_IPV4NULL && - *label != MPLS_LABEL_IPV6NULL && - *label != MPLS_LABEL_IMPLNULL)) { - session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, - msg->type); - return (-1); - } - break; - case TLV_TYPE_ATMLABEL: - case TLV_TYPE_FRLABEL: - default: - /* unsupported */ - session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, msg->type); - return (-1); - } - - return (sizeof(lt)); -} - static int gen_reqid_tlv(struct ibuf *buf, uint32_t reqid) { @@ -520,12 +509,52 @@ 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) { struct tlv ft; uint16_t family, len, pw_type, ifmtu; - uint8_t pw_len = 0; + uint8_t pw_len = 0, twcard_len; uint32_t group_id, pwid; int err = 0; @@ -595,6 +624,50 @@ gen_fec_tlv(struct ibuf *buf, struct map *map) err |= ibuf_add(buf, &ifmtu, sizeof(uint16_t)); } 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("gen_fec_tlv: unexpected fec type"); + } + ft.length = htons(len); + err |= ibuf_add(buf, &ft, sizeof(ft)); + err |= ibuf_add(buf, &map->type, sizeof(uint8_t)); + err |= ibuf_add(buf, &map->fec.twcard.type, sizeof(uint8_t)); + + switch (map->fec.twcard.type) { + case MAP_TYPE_PREFIX: + twcard_len = sizeof(uint16_t); + err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t)); + + switch (map->fec.twcard.u.prefix_af) { + case AF_INET: + family = htons(AF_IPV4); + break; + case AF_INET6: + family = htons(AF_IPV6); + break; + default: + fatalx("gen_fec_tlv: unknown af"); + break; + } + + err |= ibuf_add(buf, &family, sizeof(uint16_t)); + break; + case MAP_TYPE_PWID: + twcard_len = sizeof(uint16_t); + err |= ibuf_add(buf, &twcard_len, sizeof(uint8_t)); + pw_type = htons(map->fec.twcard.u.pw_type); + err |= ibuf_add(buf, &pw_type, sizeof(uint16_t)); + break; + default: + fatalx("gen_fec_tlv: unexpected fec type"); + } + break; default: break; } @@ -607,7 +680,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, uint16_t len, struct map *map) { uint16_t off = 0; - uint8_t pw_len; + uint8_t pw_len, twcard_len; map->type = *buf; off += sizeof(uint8_t); @@ -642,7 +715,7 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, map->fec.prefix.af = AF_INET6; break; default: - send_notification_nbr(nbr, S_UNSUP_ADDR, msg->id, + send_notification(nbr->tcp, S_UNSUP_ADDR, msg->id, msg->type); return (-1); } @@ -751,11 +824,84 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, pw_len -= stlv.length; } + return (off); + case MAP_TYPE_TYPED_WCARD: + if (len < FEC_ELM_TWCARD_MIN_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, + msg->type); + return (-1); + } + + memcpy(&map->fec.twcard.type, buf + off, sizeof(uint8_t)); + off += sizeof(uint8_t); + memcpy(&twcard_len, buf + off, sizeof(uint8_t)); + off += sizeof(uint8_t); + if (len != FEC_ELM_TWCARD_MIN_LEN + twcard_len) { + session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, + msg->type); + return (-1); + } + + switch (map->fec.twcard.type) { + case MAP_TYPE_PREFIX: + if (twcard_len != sizeof(uint16_t)) { + session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, + msg->type); + return (-1); + } + + memcpy(&map->fec.twcard.u.prefix_af, buf + off, + sizeof(uint16_t)); + map->fec.twcard.u.prefix_af = + ntohs(map->fec.twcard.u.prefix_af); + off += sizeof(uint16_t); + + switch (map->fec.twcard.u.prefix_af) { + case AF_IPV4: + map->fec.twcard.u.prefix_af = AF_INET; + break; + case AF_IPV6: + map->fec.twcard.u.prefix_af = AF_INET6; + break; + default: + session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, + msg->type); + return (-1); + } + break; + case MAP_TYPE_PWID: + if (twcard_len != sizeof(uint16_t)) { + session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, + msg->type); + return (-1); + } + + memcpy(&map->fec.twcard.u.pw_type, buf + off, + sizeof(uint16_t)); + map->fec.twcard.u.pw_type = + ntohs(map->fec.twcard.u.pw_type); + /* ignore the reserved bit as per RFC 6667 */ + map->fec.twcard.u.pw_type &= ~PW_TWCARD_RESERVED_BIT; + off += sizeof(uint16_t); + break; + default: + send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, + msg->type); + return (-1); + } + return (off); default: - send_notification_nbr(nbr, S_UNKNOWN_FEC, msg->id, msg->type); + send_notification(nbr->tcp, S_UNKNOWN_FEC, msg->id, msg->type); break; } return (-1); } + +static void +log_msg_mapping(int out, uint16_t msg_type, struct nbr *nbr, struct map *map) +{ + debug_msg(out, "%s: lsr-id %s, fec %s, label %s", msg_name(msg_type), + inet_ntoa(nbr->id), log_map(map), log_label(map->label)); +}