]>
git.proxmox.com Git - mirror_frr.git/blob - ldpd/labelmapping.c
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);
34 static void log_msg_mapping(int, uint16_t, struct nbr
*, struct map
*);
37 enqueue_pdu(struct nbr
*nbr
, struct ibuf
*buf
, uint16_t size
)
39 struct ldp_hdr
*ldp_hdr
;
41 ldp_hdr
= ibuf_seek(buf
, 0, sizeof(struct ldp_hdr
));
42 ldp_hdr
->length
= htons(size
);
43 evbuf_enqueue(&nbr
->tcp
->wbuf
, buf
);
46 /* Generic function that handles all Label Message types */
48 send_labelmessage(struct nbr
*nbr
, uint16_t type
, struct mapping_head
*mh
)
50 struct ibuf
*buf
= NULL
;
51 struct mapping_entry
*me
;
52 uint16_t msg_size
, size
= 0;
60 while ((me
= TAILQ_FIRST(mh
)) != NULL
) {
63 if ((buf
= ibuf_open(nbr
->max_pdu_len
+
64 LDP_HDR_DEAD_LEN
)) == NULL
)
67 /* real size will be set up later */
68 err
|= gen_ldp_hdr(buf
, 0);
70 size
= LDP_HDR_PDU_LEN
;
75 msg_size
= LDP_MSG_SIZE
+ TLV_HDR_SIZE
;
76 switch (me
->map
.type
) {
77 case MAP_TYPE_WILDCARD
:
78 msg_size
+= FEC_ELM_WCARD_LEN
;
81 msg_size
+= FEC_ELM_PREFIX_MIN_LEN
+
82 PREFIX_SIZE(me
->map
.fec
.prefix
.prefixlen
);
85 msg_size
+= FEC_PWID_ELM_MIN_LEN
;
86 if (me
->map
.flags
& F_MAP_PW_ID
)
87 msg_size
+= PW_STATUS_TLV_LEN
;
88 if (me
->map
.flags
& F_MAP_PW_IFMTU
)
89 msg_size
+= FEC_SUBTLV_IFMTU_SIZE
;
90 if (me
->map
.flags
& F_MAP_PW_STATUS
)
91 msg_size
+= PW_STATUS_TLV_SIZE
;
94 if (me
->map
.label
!= NO_LABEL
)
95 msg_size
+= LABEL_TLV_SIZE
;
96 if (me
->map
.flags
& F_MAP_REQ_ID
)
97 msg_size
+= REQID_TLV_SIZE
;
98 if (me
->map
.flags
& F_MAP_STATUS
)
99 msg_size
+= STATUS_SIZE
;
101 /* maximum pdu length exceeded, we need a new ldp pdu */
102 if (size
+ msg_size
> nbr
->max_pdu_len
) {
103 enqueue_pdu(nbr
, buf
, size
);
110 /* append message and tlvs */
111 err
|= gen_msg_hdr(buf
, type
, msg_size
);
112 err
|= gen_fec_tlv(buf
, &me
->map
);
113 if (me
->map
.label
!= NO_LABEL
)
114 err
|= gen_label_tlv(buf
, me
->map
.label
);
115 if (me
->map
.flags
& F_MAP_REQ_ID
)
116 err
|= gen_reqid_tlv(buf
, me
->map
.requestid
);
117 if (me
->map
.flags
& F_MAP_PW_STATUS
)
118 err
|= gen_pw_status_tlv(buf
, me
->map
.pw_status
);
119 if (me
->map
.flags
& F_MAP_STATUS
)
120 err
|= gen_status_tlv(buf
, me
->map
.st
.status_code
,
121 me
->map
.st
.msg_id
, me
->map
.st
.msg_type
);
124 mapping_list_clr(mh
);
128 log_msg_mapping(1, type
, nbr
, &me
->map
);
130 TAILQ_REMOVE(mh
, me
, entry
);
134 enqueue_pdu(nbr
, buf
, size
);
136 nbr_fsm(nbr
, NBR_EVT_PDU_SENT
);
139 /* Generic function that handles all Label Message types */
141 recv_labelmessage(struct nbr
*nbr
, char *buf
, uint16_t len
, uint16_t type
)
145 uint32_t label
= NO_LABEL
, reqid
= 0;
146 uint32_t pw_status
= 0;
148 int feclen
, lbllen
, tlen
;
149 struct mapping_entry
*me
;
150 struct mapping_head mh
;
153 memcpy(&msg
, buf
, sizeof(msg
));
158 if (len
< sizeof(ft
)) {
159 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
163 memcpy(&ft
, buf
, sizeof(ft
));
164 if (ntohs(ft
.type
) != TLV_TYPE_FEC
) {
165 send_notification(nbr
->tcp
, S_MISS_MSG
, msg
.id
, msg
.type
);
168 feclen
= ntohs(ft
.length
);
169 if (feclen
> len
- TLV_HDR_SIZE
) {
170 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
174 buf
+= TLV_HDR_SIZE
; /* just advance to the end of the fec header */
179 memset(&map
, 0, sizeof(map
));
182 if ((tlen
= tlv_decode_fec_elm(nbr
, &msg
, buf
, feclen
,
185 if (map
.type
== MAP_TYPE_PWID
&&
186 !(map
.flags
& F_MAP_PW_ID
) &&
187 type
!= MSG_TYPE_LABELWITHDRAW
&&
188 type
!= MSG_TYPE_LABELRELEASE
) {
189 send_notification(nbr
->tcp
, S_MISS_MSG
, msg
.id
,
195 * The Wildcard FEC Element can be used only in the
196 * Label Withdraw and Label Release messages.
198 if (map
.type
== MAP_TYPE_WILDCARD
) {
200 case MSG_TYPE_LABELMAPPING
:
201 case MSG_TYPE_LABELREQUEST
:
202 case MSG_TYPE_LABELABORTREQ
:
203 session_shutdown(nbr
, S_UNKNOWN_FEC
, msg
.id
,
212 * LDP supports the use of multiple FEC Elements per
213 * FEC for the Label Mapping message only.
215 if (type
!= MSG_TYPE_LABELMAPPING
&&
217 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
.id
, msg
.type
);
221 mapping_list_add(&mh
, &map
);
226 } while (feclen
> 0);
228 /* Mandatory Label TLV */
229 if (type
== MSG_TYPE_LABELMAPPING
) {
230 lbllen
= tlv_decode_label(nbr
, &msg
, buf
, len
, &label
);
238 /* 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_type
= ntohs(tlv
.type
);
252 tlv_len
= ntohs(tlv
.length
);
253 if (tlv_len
+ TLV_HDR_SIZE
> len
) {
254 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
, msg
.type
);
261 case TLV_TYPE_LABELREQUEST
:
263 case MSG_TYPE_LABELMAPPING
:
264 case MSG_TYPE_LABELREQUEST
:
265 if (tlv_len
!= REQID_TLV_LEN
) {
266 session_shutdown(nbr
, S_BAD_TLV_LEN
,
271 flags
|= F_MAP_REQ_ID
;
272 memcpy(&reqbuf
, buf
, sizeof(reqbuf
));
273 reqid
= ntohl(reqbuf
);
280 case TLV_TYPE_HOPCOUNT
:
281 case TLV_TYPE_PATHVECTOR
:
284 case TLV_TYPE_GENERICLABEL
:
286 case MSG_TYPE_LABELWITHDRAW
:
287 case MSG_TYPE_LABELRELEASE
:
288 if (tlv_len
!= LABEL_TLV_LEN
) {
289 session_shutdown(nbr
, S_BAD_TLV_LEN
,
294 memcpy(&labelbuf
, buf
, sizeof(labelbuf
));
295 label
= ntohl(labelbuf
);
302 case TLV_TYPE_ATMLABEL
:
303 case TLV_TYPE_FRLABEL
:
305 case MSG_TYPE_LABELWITHDRAW
:
306 case MSG_TYPE_LABELRELEASE
:
308 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
.id
,
317 case TLV_TYPE_STATUS
:
318 if (tlv_len
!= STATUS_TLV_LEN
) {
319 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
.id
,
325 case TLV_TYPE_PW_STATUS
:
327 case MSG_TYPE_LABELMAPPING
:
328 if (tlv_len
!= PW_STATUS_TLV_LEN
) {
329 session_shutdown(nbr
, S_BAD_TLV_LEN
,
334 flags
|= F_MAP_PW_STATUS
;
335 memcpy(&statusbuf
, buf
, sizeof(statusbuf
));
336 pw_status
= ntohl(statusbuf
);
344 if (!(ntohs(tlv
.type
) & UNKNOWN_FLAG
))
345 send_notification_rtlvs(nbr
, S_UNKNOWN_TLV
,
346 msg
.id
, msg
.type
, tlv_type
, tlv_len
, buf
);
347 /* ignore unknown tlv */
354 /* notify lde about the received message. */
355 while ((me
= TAILQ_FIRST(&mh
)) != NULL
) {
356 int imsg_type
= IMSG_NONE
;
358 me
->map
.flags
|= flags
;
359 switch (me
->map
.type
) {
360 case MAP_TYPE_PREFIX
:
361 switch (me
->map
.fec
.prefix
.af
) {
363 if (label
== MPLS_LABEL_IPV6NULL
) {
364 session_shutdown(nbr
, S_BAD_TLV_VAL
,
368 if (!nbr
->v4_enabled
)
372 if (label
== MPLS_LABEL_IPV4NULL
) {
373 session_shutdown(nbr
, S_BAD_TLV_VAL
,
377 if (!nbr
->v6_enabled
)
381 fatalx("recv_labelmessage: unknown af");
385 if (label
<= MPLS_LABEL_RESERVED_MAX
) {
386 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
.id
,
390 if (me
->map
.flags
& F_MAP_PW_STATUS
)
391 me
->map
.pw_status
= pw_status
;
396 me
->map
.label
= label
;
397 if (me
->map
.flags
& F_MAP_REQ_ID
)
398 me
->map
.requestid
= reqid
;
400 log_msg_mapping(0, type
, nbr
, &me
->map
);
403 case MSG_TYPE_LABELMAPPING
:
404 imsg_type
= IMSG_LABEL_MAPPING
;
406 case MSG_TYPE_LABELREQUEST
:
407 imsg_type
= IMSG_LABEL_REQUEST
;
409 case MSG_TYPE_LABELWITHDRAW
:
410 imsg_type
= IMSG_LABEL_WITHDRAW
;
412 case MSG_TYPE_LABELRELEASE
:
413 imsg_type
= IMSG_LABEL_RELEASE
;
415 case MSG_TYPE_LABELABORTREQ
:
416 imsg_type
= IMSG_LABEL_ABORT
;
422 ldpe_imsg_compose_lde(imsg_type
, nbr
->peerid
, 0, &me
->map
,
426 TAILQ_REMOVE(&mh
, me
, entry
);
433 mapping_list_clr(&mh
);
438 /* Other TLV related functions */
440 gen_label_tlv(struct ibuf
*buf
, uint32_t label
)
444 lt
.type
= htons(TLV_TYPE_GENERICLABEL
);
445 lt
.length
= htons(LABEL_TLV_LEN
);
446 lt
.label
= htonl(label
);
448 return (ibuf_add(buf
, <
, sizeof(lt
)));
452 tlv_decode_label(struct nbr
*nbr
, struct ldp_msg
*msg
, char *buf
,
453 uint16_t len
, uint32_t *label
)
457 if (len
< sizeof(lt
)) {
458 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
, msg
->type
);
461 memcpy(<
, buf
, sizeof(lt
));
463 if (!(ntohs(lt
.type
) & TLV_TYPE_GENERICLABEL
)) {
464 send_notification(nbr
->tcp
, S_MISS_MSG
, msg
->id
, msg
->type
);
468 switch (htons(lt
.type
)) {
469 case TLV_TYPE_GENERICLABEL
:
470 if (ntohs(lt
.length
) != sizeof(lt
) - TLV_HDR_SIZE
) {
471 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
476 *label
= ntohl(lt
.label
);
477 if (*label
> MPLS_LABEL_MAX
||
478 (*label
<= MPLS_LABEL_RESERVED_MAX
&&
479 *label
!= MPLS_LABEL_IPV4NULL
&&
480 *label
!= MPLS_LABEL_IPV6NULL
&&
481 *label
!= MPLS_LABEL_IMPLNULL
)) {
482 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
->id
,
487 case TLV_TYPE_ATMLABEL
:
488 case TLV_TYPE_FRLABEL
:
491 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
->id
, msg
->type
);
499 gen_reqid_tlv(struct ibuf
*buf
, uint32_t reqid
)
503 rt
.type
= htons(TLV_TYPE_LABELREQUEST
);
504 rt
.length
= htons(REQID_TLV_LEN
);
505 rt
.reqid
= htonl(reqid
);
507 return (ibuf_add(buf
, &rt
, sizeof(rt
)));
511 gen_pw_status_tlv(struct ibuf
*buf
, uint32_t status
)
513 struct pw_status_tlv st
;
515 st
.type
= htons(TLV_TYPE_PW_STATUS
);
516 st
.length
= htons(PW_STATUS_TLV_LEN
);
517 st
.value
= htonl(status
);
519 return (ibuf_add(buf
, &st
, sizeof(st
)));
523 gen_fec_tlv(struct ibuf
*buf
, struct map
*map
)
526 uint16_t family
, len
, pw_type
, ifmtu
;
528 uint32_t group_id
, pwid
;
531 ft
.type
= htons(TLV_TYPE_FEC
);
534 case MAP_TYPE_WILDCARD
:
535 ft
.length
= htons(sizeof(uint8_t));
536 err
|= ibuf_add(buf
, &ft
, sizeof(ft
));
537 err
|= ibuf_add(buf
, &map
->type
, sizeof(map
->type
));
539 case MAP_TYPE_PREFIX
:
540 len
= PREFIX_SIZE(map
->fec
.prefix
.prefixlen
);
541 ft
.length
= htons(sizeof(map
->type
) + sizeof(family
) +
542 sizeof(map
->fec
.prefix
.prefixlen
) + len
);
543 err
|= ibuf_add(buf
, &ft
, sizeof(ft
));
544 err
|= ibuf_add(buf
, &map
->type
, sizeof(map
->type
));
545 switch (map
->fec
.prefix
.af
) {
547 family
= htons(AF_IPV4
);
550 family
= htons(AF_IPV6
);
553 fatalx("gen_fec_tlv: unknown af");
556 err
|= ibuf_add(buf
, &family
, sizeof(family
));
557 err
|= ibuf_add(buf
, &map
->fec
.prefix
.prefixlen
,
558 sizeof(map
->fec
.prefix
.prefixlen
));
560 err
|= ibuf_add(buf
, &map
->fec
.prefix
.prefix
, len
);
563 if (map
->flags
& F_MAP_PW_ID
)
564 pw_len
+= FEC_PWID_SIZE
;
565 if (map
->flags
& F_MAP_PW_IFMTU
)
566 pw_len
+= FEC_SUBTLV_IFMTU_SIZE
;
568 len
= FEC_PWID_ELM_MIN_LEN
+ pw_len
;
570 ft
.length
= htons(len
);
571 err
|= ibuf_add(buf
, &ft
, sizeof(ft
));
573 err
|= ibuf_add(buf
, &map
->type
, sizeof(uint8_t));
574 pw_type
= map
->fec
.pwid
.type
;
575 if (map
->flags
& F_MAP_PW_CWORD
)
576 pw_type
|= CONTROL_WORD_FLAG
;
577 pw_type
= htons(pw_type
);
578 err
|= ibuf_add(buf
, &pw_type
, sizeof(uint16_t));
579 err
|= ibuf_add(buf
, &pw_len
, sizeof(uint8_t));
580 group_id
= htonl(map
->fec
.pwid
.group_id
);
581 err
|= ibuf_add(buf
, &group_id
, sizeof(uint32_t));
582 if (map
->flags
& F_MAP_PW_ID
) {
583 pwid
= htonl(map
->fec
.pwid
.pwid
);
584 err
|= ibuf_add(buf
, &pwid
, sizeof(uint32_t));
586 if (map
->flags
& F_MAP_PW_IFMTU
) {
589 stlv
.type
= SUBTLV_IFMTU
;
590 stlv
.length
= FEC_SUBTLV_IFMTU_SIZE
;
591 err
|= ibuf_add(buf
, &stlv
, sizeof(uint16_t));
593 ifmtu
= htons(map
->fec
.pwid
.ifmtu
);
594 err
|= ibuf_add(buf
, &ifmtu
, sizeof(uint16_t));
605 tlv_decode_fec_elm(struct nbr
*nbr
, struct ldp_msg
*msg
, char *buf
,
606 uint16_t len
, struct map
*map
)
612 off
+= sizeof(uint8_t);
615 case MAP_TYPE_WILDCARD
:
616 if (len
== FEC_ELM_WCARD_LEN
)
619 session_shutdown(nbr
, S_BAD_TLV_VAL
, msg
->id
,
624 case MAP_TYPE_PREFIX
:
625 if (len
< FEC_ELM_PREFIX_MIN_LEN
) {
626 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
632 memcpy(&map
->fec
.prefix
.af
, buf
+ off
,
633 sizeof(map
->fec
.prefix
.af
));
634 off
+= sizeof(map
->fec
.prefix
.af
);
635 map
->fec
.prefix
.af
= ntohs(map
->fec
.prefix
.af
);
636 switch (map
->fec
.prefix
.af
) {
638 map
->fec
.prefix
.af
= AF_INET
;
641 map
->fec
.prefix
.af
= AF_INET6
;
644 send_notification(nbr
->tcp
, S_UNSUP_ADDR
, msg
->id
,
650 map
->fec
.prefix
.prefixlen
= buf
[off
];
651 off
+= sizeof(uint8_t);
652 if (len
< off
+ PREFIX_SIZE(map
->fec
.prefix
.prefixlen
)) {
653 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
659 memset(&map
->fec
.prefix
.prefix
, 0,
660 sizeof(map
->fec
.prefix
.prefix
));
661 memcpy(&map
->fec
.prefix
.prefix
, buf
+ off
,
662 PREFIX_SIZE(map
->fec
.prefix
.prefixlen
));
664 /* Just in case... */
665 ldp_applymask(map
->fec
.prefix
.af
, &map
->fec
.prefix
.prefix
,
666 &map
->fec
.prefix
.prefix
, map
->fec
.prefix
.prefixlen
);
668 return (off
+ PREFIX_SIZE(map
->fec
.prefix
.prefixlen
));
670 if (len
< FEC_PWID_ELM_MIN_LEN
) {
671 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
677 memcpy(&map
->fec
.pwid
.type
, buf
+ off
, sizeof(uint16_t));
678 map
->fec
.pwid
.type
= ntohs(map
->fec
.pwid
.type
);
679 if (map
->fec
.pwid
.type
& CONTROL_WORD_FLAG
) {
680 map
->flags
|= F_MAP_PW_CWORD
;
681 map
->fec
.pwid
.type
&= ~CONTROL_WORD_FLAG
;
683 off
+= sizeof(uint16_t);
687 off
+= sizeof(uint8_t);
689 if (len
!= FEC_PWID_ELM_MIN_LEN
+ pw_len
) {
690 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
696 memcpy(&map
->fec
.pwid
.group_id
, buf
+ off
, sizeof(uint32_t));
697 map
->fec
.pwid
.group_id
= ntohl(map
->fec
.pwid
.group_id
);
698 off
+= sizeof(uint32_t);
704 if (pw_len
< sizeof(uint32_t)) {
705 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
710 memcpy(&map
->fec
.pwid
.pwid
, buf
+ off
, sizeof(uint32_t));
711 map
->fec
.pwid
.pwid
= ntohl(map
->fec
.pwid
.pwid
);
712 map
->flags
|= F_MAP_PW_ID
;
713 off
+= sizeof(uint32_t);
714 pw_len
-= sizeof(uint32_t);
716 /* Optional Interface Parameter Sub-TLVs */
720 if (pw_len
< sizeof(stlv
)) {
721 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
726 memcpy(&stlv
, buf
+ off
, sizeof(stlv
));
727 if (stlv
.length
> pw_len
) {
728 session_shutdown(nbr
, S_BAD_TLV_LEN
, msg
->id
,
735 if (stlv
.length
!= FEC_SUBTLV_IFMTU_SIZE
) {
736 session_shutdown(nbr
, S_BAD_TLV_LEN
,
740 memcpy(&map
->fec
.pwid
.ifmtu
, buf
+ off
+
741 SUBTLV_HDR_SIZE
, sizeof(uint16_t));
742 map
->fec
.pwid
.ifmtu
= ntohs(map
->fec
.pwid
.ifmtu
);
743 map
->flags
|= F_MAP_PW_IFMTU
;
750 pw_len
-= stlv
.length
;
755 send_notification(nbr
->tcp
, S_UNKNOWN_FEC
, msg
->id
, msg
->type
);
763 log_msg_mapping(int out
, uint16_t msg_type
, struct nbr
*nbr
, struct map
*map
)
765 debug_msg(out
, "%s: lsr-id %s, fec %s, label %s", msg_name(msg_type
),
766 inet_ntoa(nbr
->id
), log_map(map
), log_label(map
->label
));