]>
git.proxmox.com Git - mirror_frr.git/blob - ldpd/labelmapping.c
62f2a620d22c0c59f376f4bc40b00b19abaf3765
4 * Copyright (c) 2014, 2015 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #include "ldp_debug.h"
29 static void enqueue_pdu(struct nbr
*, struct ibuf
*, uint16_t);
30 static int gen_label_tlv(struct ibuf
*, uint32_t);
31 static int tlv_decode_label(struct nbr
*, struct ldp_msg
*, char *,
32 uint16_t, uint32_t *);
33 static int gen_reqid_tlv(struct ibuf
*, uint32_t);
36 enqueue_pdu(struct nbr
*nbr
, struct ibuf
*buf
, uint16_t size
)
38 struct ldp_hdr
*ldp_hdr
;
40 ldp_hdr
= ibuf_seek(buf
, 0, sizeof(struct ldp_hdr
));
41 ldp_hdr
->length
= htons(size
);
42 evbuf_enqueue(&nbr
->tcp
->wbuf
, buf
);
45 /* Generic function that handles all Label Message types */
47 send_labelmessage(struct nbr
*nbr
, uint16_t type
, struct mapping_head
*mh
)
49 struct ibuf
*buf
= NULL
;
50 struct mapping_entry
*me
;
51 uint16_t msg_size
, size
= 0;
59 while ((me
= TAILQ_FIRST(mh
)) != NULL
) {
62 if ((buf
= ibuf_open(nbr
->max_pdu_len
+
63 LDP_HDR_DEAD_LEN
)) == NULL
)
66 /* real size will be set up later */
67 err
|= gen_ldp_hdr(buf
, 0);
69 size
= LDP_HDR_PDU_LEN
;
74 msg_size
= LDP_MSG_SIZE
+ TLV_HDR_SIZE
;
75 switch (me
->map
.type
) {
76 case MAP_TYPE_WILDCARD
:
77 msg_size
+= FEC_ELM_WCARD_LEN
;
80 msg_size
+= FEC_ELM_PREFIX_MIN_LEN
+
81 PREFIX_SIZE(me
->map
.fec
.prefix
.prefixlen
);
84 msg_size
+= FEC_PWID_ELM_MIN_LEN
;
85 if (me
->map
.flags
& F_MAP_PW_ID
)
86 msg_size
+= PW_STATUS_TLV_LEN
;
87 if (me
->map
.flags
& F_MAP_PW_IFMTU
)
88 msg_size
+= FEC_SUBTLV_IFMTU_SIZE
;
89 if (me
->map
.flags
& F_MAP_PW_STATUS
)
90 msg_size
+= PW_STATUS_TLV_SIZE
;
93 if (me
->map
.label
!= NO_LABEL
)
94 msg_size
+= LABEL_TLV_SIZE
;
95 if (me
->map
.flags
& F_MAP_REQ_ID
)
96 msg_size
+= REQID_TLV_SIZE
;
97 if (me
->map
.flags
& F_MAP_STATUS
)
98 msg_size
+= STATUS_SIZE
;
100 /* maximum pdu length exceeded, we need a new ldp pdu */
101 if (size
+ msg_size
> nbr
->max_pdu_len
) {
102 enqueue_pdu(nbr
, buf
, size
);
109 /* append message and tlvs */
110 err
|= gen_msg_hdr(buf
, type
, msg_size
);
111 err
|= gen_fec_tlv(buf
, &me
->map
);
112 if (me
->map
.label
!= NO_LABEL
)
113 err
|= gen_label_tlv(buf
, me
->map
.label
);
114 if (me
->map
.flags
& F_MAP_REQ_ID
)
115 err
|= gen_reqid_tlv(buf
, me
->map
.requestid
);
116 if (me
->map
.flags
& F_MAP_PW_STATUS
)
117 err
|= gen_pw_status_tlv(buf
, me
->map
.pw_status
);
118 if (me
->map
.flags
& F_MAP_STATUS
)
119 err
|= gen_status_tlv(buf
, me
->map
.st
.status_code
,
120 me
->map
.st
.msg_id
, me
->map
.st
.msg_type
);
123 mapping_list_clr(mh
);
127 debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type
),
128 inet_ntoa(nbr
->id
), log_map(&me
->map
),
129 log_label(me
->map
.label
));
131 TAILQ_REMOVE(mh
, me
, entry
);
135 enqueue_pdu(nbr
, buf
, size
);
137 nbr_fsm(nbr
, NBR_EVT_PDU_SENT
);
140 /* Generic function that handles all Label Message types */
142 recv_labelmessage(struct nbr
*nbr
, char *buf
, uint16_t len
, uint16_t type
)
146 uint32_t label
= NO_LABEL
, reqid
= 0;
147 uint32_t pw_status
= 0;
149 int feclen
, lbllen
, tlen
;
150 struct mapping_entry
*me
;
151 struct mapping_head mh
;
154 memcpy(&msg
, buf
, sizeof(msg
));
159 if (len
< sizeof(ft
)) {
160 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
164 memcpy(&ft
, buf
, sizeof(ft
));
165 if (ntohs(ft
.type
) != TLV_TYPE_FEC
) {
166 send_notification_nbr(nbr
, S_MISS_MSG
, msg
.id
, msg
.type
);
169 feclen
= ntohs(ft
.length
);
170 if (feclen
> len
- TLV_HDR_SIZE
) {
171 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
175 buf
+= TLV_HDR_SIZE
; /* just advance to the end of the fec header */
180 memset(&map
, 0, sizeof(map
));
183 if ((tlen
= tlv_decode_fec_elm(nbr
, &msg
, buf
, feclen
,
186 if (map
.type
== MAP_TYPE_PWID
&&
187 !(map
.flags
& F_MAP_PW_ID
) &&
188 type
!= MSG_TYPE_LABELWITHDRAW
&&
189 type
!= MSG_TYPE_LABELRELEASE
) {
190 send_notification_nbr(nbr
, S_MISS_MSG
, msg
.id
,
196 * The Wildcard FEC Element can be used only in the
197 * Label Withdraw and Label Release messages.
199 if (map
.type
== MAP_TYPE_WILDCARD
) {
201 case MSG_TYPE_LABELMAPPING
:
202 case MSG_TYPE_LABELREQUEST
:
203 case MSG_TYPE_LABELABORTREQ
:
204 session_shutdown(nbr
, S_UNKNOWN_FEC
, msg
.id
,
213 * LDP supports the use of multiple FEC Elements per
214 * FEC for the Label Mapping message only.
216 if (type
!= MSG_TYPE_LABELMAPPING
&&
218 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
.id
, msg
.type
);
222 mapping_list_add(&mh
, &map
);
227 } while (feclen
> 0);
229 /* Mandatory Label TLV */
230 if (type
== MSG_TYPE_LABELMAPPING
) {
231 lbllen
= tlv_decode_label(nbr
, &msg
, buf
, len
, &label
);
239 /* Optional Parameters */
243 uint32_t reqbuf
, labelbuf
, statusbuf
;
245 if (len
< sizeof(tlv
)) {
246 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
250 memcpy(&tlv
, buf
, TLV_HDR_SIZE
);
251 tlv_len
= ntohs(tlv
.length
);
252 if (tlv_len
+ TLV_HDR_SIZE
> len
) {
253 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
259 switch (ntohs(tlv
.type
)) {
260 case TLV_TYPE_LABELREQUEST
:
262 case MSG_TYPE_LABELMAPPING
:
263 case MSG_TYPE_LABELREQUEST
:
264 if (tlv_len
!= REQID_TLV_LEN
) {
265 session_shutdown(nbr
, S_BAD_TLV_LEN
,
270 flags
|= F_MAP_REQ_ID
;
271 memcpy(&reqbuf
, buf
, sizeof(reqbuf
));
272 reqid
= ntohl(reqbuf
);
279 case TLV_TYPE_HOPCOUNT
:
280 case TLV_TYPE_PATHVECTOR
:
283 case TLV_TYPE_GENERICLABEL
:
285 case MSG_TYPE_LABELWITHDRAW
:
286 case MSG_TYPE_LABELRELEASE
:
287 if (tlv_len
!= LABEL_TLV_LEN
) {
288 session_shutdown(nbr
, S_BAD_TLV_LEN
,
293 memcpy(&labelbuf
, buf
, sizeof(labelbuf
));
294 label
= ntohl(labelbuf
);
301 case TLV_TYPE_ATMLABEL
:
302 case TLV_TYPE_FRLABEL
:
304 case MSG_TYPE_LABELWITHDRAW
:
305 case MSG_TYPE_LABELRELEASE
:
307 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
.id
,
316 case TLV_TYPE_STATUS
:
317 if (tlv_len
!= STATUS_TLV_LEN
) {
318 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
,
324 case TLV_TYPE_PW_STATUS
:
326 case MSG_TYPE_LABELMAPPING
:
327 if (tlv_len
!= PW_STATUS_TLV_LEN
) {
328 session_shutdown(nbr
, S_BAD_TLV_LEN
,
333 flags
|= F_MAP_PW_STATUS
;
334 memcpy(&statusbuf
, buf
, sizeof(statusbuf
));
335 pw_status
= ntohl(statusbuf
);
343 if (!(ntohs(tlv
.type
) & UNKNOWN_FLAG
))
344 send_notification_nbr(nbr
, S_UNKNOWN_TLV
,
346 /* ignore unknown tlv */
353 /* notify lde about the received message. */
354 while ((me
= TAILQ_FIRST(&mh
)) != NULL
) {
355 int imsg_type
= IMSG_NONE
;
357 me
->map
.flags
|= flags
;
358 switch (me
->map
.type
) {
359 case MAP_TYPE_PREFIX
:
360 switch (me
->map
.fec
.prefix
.af
) {
362 if (label
== MPLS_LABEL_IPV6NULL
) {
363 session_shutdown(nbr
, S_BAD_TLV_VAL
,
367 if (!nbr
->v4_enabled
)
371 if (label
== MPLS_LABEL_IPV4NULL
) {
372 session_shutdown(nbr
, S_BAD_TLV_VAL
,
376 if (!nbr
->v6_enabled
)
380 fatalx("recv_labelmessage: unknown af");
384 if (label
<= MPLS_LABEL_RESERVED_MAX
) {
385 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
.id
,
389 if (me
->map
.flags
& F_MAP_PW_STATUS
)
390 me
->map
.pw_status
= pw_status
;
395 me
->map
.label
= label
;
396 if (me
->map
.flags
& F_MAP_REQ_ID
)
397 me
->map
.requestid
= reqid
;
399 debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type
),
400 inet_ntoa(nbr
->id
), log_map(&me
->map
),
401 log_label(me
->map
.label
));
404 case MSG_TYPE_LABELMAPPING
:
405 imsg_type
= IMSG_LABEL_MAPPING
;
407 case MSG_TYPE_LABELREQUEST
:
408 imsg_type
= IMSG_LABEL_REQUEST
;
410 case MSG_TYPE_LABELWITHDRAW
:
411 imsg_type
= IMSG_LABEL_WITHDRAW
;
413 case MSG_TYPE_LABELRELEASE
:
414 imsg_type
= IMSG_LABEL_RELEASE
;
416 case MSG_TYPE_LABELABORTREQ
:
417 imsg_type
= IMSG_LABEL_ABORT
;
423 ldpe_imsg_compose_lde(imsg_type
, nbr
->peerid
, 0, &me
->map
,
427 TAILQ_REMOVE(&mh
, me
, entry
);
434 mapping_list_clr(&mh
);
439 /* Other TLV related functions */
441 gen_label_tlv(struct ibuf
*buf
, uint32_t label
)
445 lt
.type
= htons(TLV_TYPE_GENERICLABEL
);
446 lt
.length
= htons(LABEL_TLV_LEN
);
447 lt
.label
= htonl(label
);
449 return (ibuf_add(buf
, <
, sizeof(lt
)));
453 tlv_decode_label(struct nbr
*nbr
, struct ldp_msg
*msg
, char *buf
,
454 uint16_t len
, uint32_t *label
)
458 if (len
< sizeof(lt
)) {
459 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
, msg
->type
);
462 memcpy(<
, buf
, sizeof(lt
));
464 if (!(ntohs(lt
.type
) & TLV_TYPE_GENERICLABEL
)) {
465 send_notification_nbr(nbr
, S_MISS_MSG
, msg
->id
, msg
->type
);
469 switch (htons(lt
.type
)) {
470 case TLV_TYPE_GENERICLABEL
:
471 if (ntohs(lt
.length
) != sizeof(lt
) - TLV_HDR_SIZE
) {
472 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
477 *label
= ntohl(lt
.label
);
478 if (*label
> MPLS_LABEL_MAX
||
479 (*label
<= MPLS_LABEL_RESERVED_MAX
&&
480 *label
!= MPLS_LABEL_IPV4NULL
&&
481 *label
!= MPLS_LABEL_IPV6NULL
&&
482 *label
!= MPLS_LABEL_IMPLNULL
)) {
483 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
->id
,
488 case TLV_TYPE_ATMLABEL
:
489 case TLV_TYPE_FRLABEL
:
492 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
->id
, msg
->type
);
500 gen_reqid_tlv(struct ibuf
*buf
, uint32_t reqid
)
504 rt
.type
= htons(TLV_TYPE_LABELREQUEST
);
505 rt
.length
= htons(REQID_TLV_LEN
);
506 rt
.reqid
= htonl(reqid
);
508 return (ibuf_add(buf
, &rt
, sizeof(rt
)));
512 gen_pw_status_tlv(struct ibuf
*buf
, uint32_t status
)
514 struct pw_status_tlv st
;
516 st
.type
= htons(TLV_TYPE_PW_STATUS
);
517 st
.length
= htons(PW_STATUS_TLV_LEN
);
518 st
.value
= htonl(status
);
520 return (ibuf_add(buf
, &st
, sizeof(st
)));
524 gen_fec_tlv(struct ibuf
*buf
, struct map
*map
)
527 uint16_t family
, len
, pw_type
, ifmtu
;
529 uint32_t group_id
, pwid
;
532 ft
.type
= htons(TLV_TYPE_FEC
);
535 case MAP_TYPE_WILDCARD
:
536 ft
.length
= htons(sizeof(uint8_t));
537 err
|= ibuf_add(buf
, &ft
, sizeof(ft
));
538 err
|= ibuf_add(buf
, &map
->type
, sizeof(map
->type
));
540 case MAP_TYPE_PREFIX
:
541 len
= PREFIX_SIZE(map
->fec
.prefix
.prefixlen
);
542 ft
.length
= htons(sizeof(map
->type
) + sizeof(family
) +
543 sizeof(map
->fec
.prefix
.prefixlen
) + len
);
544 err
|= ibuf_add(buf
, &ft
, sizeof(ft
));
545 err
|= ibuf_add(buf
, &map
->type
, sizeof(map
->type
));
546 switch (map
->fec
.prefix
.af
) {
548 family
= htons(AF_IPV4
);
551 family
= htons(AF_IPV6
);
554 fatalx("gen_fec_tlv: unknown af");
557 err
|= ibuf_add(buf
, &family
, sizeof(family
));
558 err
|= ibuf_add(buf
, &map
->fec
.prefix
.prefixlen
,
559 sizeof(map
->fec
.prefix
.prefixlen
));
561 err
|= ibuf_add(buf
, &map
->fec
.prefix
.prefix
, len
);
564 if (map
->flags
& F_MAP_PW_ID
)
565 pw_len
+= PW_STATUS_TLV_LEN
;
566 if (map
->flags
& F_MAP_PW_IFMTU
)
567 pw_len
+= FEC_SUBTLV_IFMTU_SIZE
;
569 len
= FEC_PWID_ELM_MIN_LEN
+ pw_len
;
571 ft
.length
= htons(len
);
572 err
|= ibuf_add(buf
, &ft
, sizeof(ft
));
574 err
|= ibuf_add(buf
, &map
->type
, sizeof(uint8_t));
575 pw_type
= map
->fec
.pwid
.type
;
576 if (map
->flags
& F_MAP_PW_CWORD
)
577 pw_type
|= CONTROL_WORD_FLAG
;
578 pw_type
= htons(pw_type
);
579 err
|= ibuf_add(buf
, &pw_type
, sizeof(uint16_t));
580 err
|= ibuf_add(buf
, &pw_len
, sizeof(uint8_t));
581 group_id
= htonl(map
->fec
.pwid
.group_id
);
582 err
|= ibuf_add(buf
, &group_id
, sizeof(uint32_t));
583 if (map
->flags
& F_MAP_PW_ID
) {
584 pwid
= htonl(map
->fec
.pwid
.pwid
);
585 err
|= ibuf_add(buf
, &pwid
, sizeof(uint32_t));
587 if (map
->flags
& F_MAP_PW_IFMTU
) {
590 stlv
.type
= SUBTLV_IFMTU
;
591 stlv
.length
= FEC_SUBTLV_IFMTU_SIZE
;
592 err
|= ibuf_add(buf
, &stlv
, sizeof(uint16_t));
594 ifmtu
= htons(map
->fec
.pwid
.ifmtu
);
595 err
|= ibuf_add(buf
, &ifmtu
, sizeof(uint16_t));
606 tlv_decode_fec_elm(struct nbr
*nbr
, struct ldp_msg
*msg
, char *buf
,
607 uint16_t len
, struct map
*map
)
613 off
+= sizeof(uint8_t);
616 case MAP_TYPE_WILDCARD
:
617 if (len
== FEC_ELM_WCARD_LEN
)
620 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
->id
,
625 case MAP_TYPE_PREFIX
:
626 if (len
< FEC_ELM_PREFIX_MIN_LEN
) {
627 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
633 memcpy(&map
->fec
.prefix
.af
, buf
+ off
,
634 sizeof(map
->fec
.prefix
.af
));
635 off
+= sizeof(map
->fec
.prefix
.af
);
636 map
->fec
.prefix
.af
= ntohs(map
->fec
.prefix
.af
);
637 switch (map
->fec
.prefix
.af
) {
639 map
->fec
.prefix
.af
= AF_INET
;
642 map
->fec
.prefix
.af
= AF_INET6
;
645 send_notification_nbr(nbr
, S_UNSUP_ADDR
, msg
->id
,
651 map
->fec
.prefix
.prefixlen
= buf
[off
];
652 off
+= sizeof(uint8_t);
653 if (len
< off
+ PREFIX_SIZE(map
->fec
.prefix
.prefixlen
)) {
654 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
660 memset(&map
->fec
.prefix
.prefix
, 0,
661 sizeof(map
->fec
.prefix
.prefix
));
662 memcpy(&map
->fec
.prefix
.prefix
, buf
+ off
,
663 PREFIX_SIZE(map
->fec
.prefix
.prefixlen
));
665 /* Just in case... */
666 ldp_applymask(map
->fec
.prefix
.af
, &map
->fec
.prefix
.prefix
,
667 &map
->fec
.prefix
.prefix
, map
->fec
.prefix
.prefixlen
);
669 return (off
+ PREFIX_SIZE(map
->fec
.prefix
.prefixlen
));
671 if (len
< FEC_PWID_ELM_MIN_LEN
) {
672 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
678 memcpy(&map
->fec
.pwid
.type
, buf
+ off
, sizeof(uint16_t));
679 map
->fec
.pwid
.type
= ntohs(map
->fec
.pwid
.type
);
680 if (map
->fec
.pwid
.type
& CONTROL_WORD_FLAG
) {
681 map
->flags
|= F_MAP_PW_CWORD
;
682 map
->fec
.pwid
.type
&= ~CONTROL_WORD_FLAG
;
684 off
+= sizeof(uint16_t);
688 off
+= sizeof(uint8_t);
690 if (len
!= FEC_PWID_ELM_MIN_LEN
+ pw_len
) {
691 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
697 memcpy(&map
->fec
.pwid
.group_id
, buf
+ off
, sizeof(uint32_t));
698 map
->fec
.pwid
.group_id
= ntohl(map
->fec
.pwid
.group_id
);
699 off
+= sizeof(uint32_t);
705 if (pw_len
< sizeof(uint32_t)) {
706 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
711 memcpy(&map
->fec
.pwid
.pwid
, buf
+ off
, sizeof(uint32_t));
712 map
->fec
.pwid
.pwid
= ntohl(map
->fec
.pwid
.pwid
);
713 map
->flags
|= F_MAP_PW_ID
;
714 off
+= sizeof(uint32_t);
715 pw_len
-= sizeof(uint32_t);
717 /* Optional Interface Parameter Sub-TLVs */
721 if (pw_len
< sizeof(stlv
)) {
722 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
727 memcpy(&stlv
, buf
+ off
, sizeof(stlv
));
728 if (stlv
.length
> pw_len
) {
729 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
736 if (stlv
.length
!= FEC_SUBTLV_IFMTU_SIZE
) {
737 session_shutdown(nbr
, S_BAD_TLV_LEN
,
741 memcpy(&map
->fec
.pwid
.ifmtu
, buf
+ off
+
742 SUBTLV_HDR_SIZE
, sizeof(uint16_t));
743 map
->fec
.pwid
.ifmtu
= ntohs(map
->fec
.pwid
.ifmtu
);
744 map
->flags
|= F_MAP_PW_IFMTU
;
751 pw_len
-= stlv
.length
;
756 send_notification_nbr(nbr
, S_UNKNOWN_FEC
, msg
->id
, msg
->type
);