1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* BGP attributes management routines.
3 * Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
23 #include "bgpd/bgpd.h"
24 #include "bgpd/bgp_attr.h"
25 #include "bgpd/bgp_route.h"
26 #include "bgpd/bgp_aspath.h"
27 #include "bgpd/bgp_community.h"
28 #include "bgpd/bgp_debug.h"
29 #include "bgpd/bgp_errors.h"
30 #include "bgpd/bgp_label.h"
31 #include "bgpd/bgp_packet.h"
32 #include "bgpd/bgp_ecommunity.h"
33 #include "bgpd/bgp_lcommunity.h"
34 #include "bgpd/bgp_updgrp.h"
35 #include "bgpd/bgp_encap_types.h"
37 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
38 #include "bgp_encap_types.h"
39 #include "bgp_vnc_types.h"
42 #include "bgp_flowspec_private.h"
45 /* Attribute strings for logging. */
46 static const struct message attr_str
[] = {
47 {BGP_ATTR_ORIGIN
, "ORIGIN"},
48 {BGP_ATTR_AS_PATH
, "AS_PATH"},
49 {BGP_ATTR_NEXT_HOP
, "NEXT_HOP"},
50 {BGP_ATTR_MULTI_EXIT_DISC
, "MULTI_EXIT_DISC"},
51 {BGP_ATTR_LOCAL_PREF
, "LOCAL_PREF"},
52 {BGP_ATTR_ATOMIC_AGGREGATE
, "ATOMIC_AGGREGATE"},
53 {BGP_ATTR_AGGREGATOR
, "AGGREGATOR"},
54 {BGP_ATTR_COMMUNITIES
, "COMMUNITY"},
55 {BGP_ATTR_ORIGINATOR_ID
, "ORIGINATOR_ID"},
56 {BGP_ATTR_CLUSTER_LIST
, "CLUSTER_LIST"},
57 {BGP_ATTR_MP_REACH_NLRI
, "MP_REACH_NLRI"},
58 {BGP_ATTR_MP_UNREACH_NLRI
, "MP_UNREACH_NLRI"},
59 {BGP_ATTR_EXT_COMMUNITIES
, "EXT_COMMUNITIES"},
60 {BGP_ATTR_AS4_PATH
, "AS4_PATH"},
61 {BGP_ATTR_AS4_AGGREGATOR
, "AS4_AGGREGATOR"},
62 {BGP_ATTR_PMSI_TUNNEL
, "PMSI_TUNNEL_ATTRIBUTE"},
63 {BGP_ATTR_ENCAP
, "ENCAP"},
64 {BGP_ATTR_OTC
, "OTC"},
65 #ifdef ENABLE_BGP_VNC_ATTR
66 {BGP_ATTR_VNC
, "VNC"},
68 {BGP_ATTR_LARGE_COMMUNITIES
, "LARGE_COMMUNITY"},
69 {BGP_ATTR_PREFIX_SID
, "PREFIX_SID"},
70 {BGP_ATTR_IPV6_EXT_COMMUNITIES
, "IPV6_EXT_COMMUNITIES"},
71 {BGP_ATTR_AIGP
, "AIGP"},
74 static const struct message attr_flag_str
[] = {
75 {BGP_ATTR_FLAG_OPTIONAL
, "Optional"},
76 {BGP_ATTR_FLAG_TRANS
, "Transitive"},
77 {BGP_ATTR_FLAG_PARTIAL
, "Partial"},
78 /* bgp_attr_flags_diagnose() relies on this bit being last in
80 {BGP_ATTR_FLAG_EXTLEN
, "Extended Length"},
83 static struct hash
*cluster_hash
;
85 static void *cluster_hash_alloc(void *p
)
87 const struct cluster_list
*val
= (const struct cluster_list
*)p
;
88 struct cluster_list
*cluster
;
90 cluster
= XMALLOC(MTYPE_CLUSTER
, sizeof(struct cluster_list
));
91 cluster
->length
= val
->length
;
93 if (cluster
->length
) {
94 cluster
->list
= XMALLOC(MTYPE_CLUSTER_VAL
, val
->length
);
95 memcpy(cluster
->list
, val
->list
, val
->length
);
104 /* Cluster list related functions. */
105 static struct cluster_list
*cluster_parse(struct in_addr
*pnt
, int length
)
107 struct cluster_list tmp
= {};
108 struct cluster_list
*cluster
;
111 tmp
.list
= length
== 0 ? NULL
: pnt
;
113 cluster
= hash_get(cluster_hash
, &tmp
, cluster_hash_alloc
);
118 bool cluster_loop_check(struct cluster_list
*cluster
, struct in_addr originator
)
122 for (i
= 0; i
< cluster
->length
/ 4; i
++)
123 if (cluster
->list
[i
].s_addr
== originator
.s_addr
)
128 static unsigned int cluster_hash_key_make(const void *p
)
130 const struct cluster_list
*cluster
= p
;
132 return jhash(cluster
->list
, cluster
->length
, 0);
135 static bool cluster_hash_cmp(const void *p1
, const void *p2
)
137 const struct cluster_list
*cluster1
= p1
;
138 const struct cluster_list
*cluster2
= p2
;
140 if (cluster1
->list
== cluster2
->list
)
143 if (!cluster1
->list
|| !cluster2
->list
)
146 if (cluster1
->length
!= cluster2
->length
)
149 return (memcmp(cluster1
->list
, cluster2
->list
, cluster1
->length
) == 0);
152 static void cluster_free(struct cluster_list
*cluster
)
154 XFREE(MTYPE_CLUSTER_VAL
, cluster
->list
);
155 XFREE(MTYPE_CLUSTER
, cluster
);
158 static struct cluster_list
*cluster_intern(struct cluster_list
*cluster
)
160 struct cluster_list
*find
;
162 find
= hash_get(cluster_hash
, cluster
, cluster_hash_alloc
);
168 static void cluster_unintern(struct cluster_list
**cluster
)
170 if ((*cluster
)->refcnt
)
171 (*cluster
)->refcnt
--;
173 if ((*cluster
)->refcnt
== 0) {
174 void *p
= hash_release(cluster_hash
, *cluster
);
175 assert(p
== *cluster
);
176 cluster_free(*cluster
);
181 static void cluster_init(void)
183 cluster_hash
= hash_create(cluster_hash_key_make
, cluster_hash_cmp
,
187 static void cluster_finish(void)
189 hash_clean(cluster_hash
, (void (*)(void *))cluster_free
);
190 hash_free(cluster_hash
);
194 static struct hash
*encap_hash
= NULL
;
195 #ifdef ENABLE_BGP_VNC
196 static struct hash
*vnc_hash
= NULL
;
198 static struct hash
*srv6_l3vpn_hash
;
199 static struct hash
*srv6_vpn_hash
;
201 struct bgp_attr_encap_subtlv
*encap_tlv_dup(struct bgp_attr_encap_subtlv
*orig
)
203 struct bgp_attr_encap_subtlv
*new;
204 struct bgp_attr_encap_subtlv
*tail
;
205 struct bgp_attr_encap_subtlv
*p
;
207 for (p
= orig
, tail
= new = NULL
; p
; p
= p
->next
) {
208 int size
= sizeof(struct bgp_attr_encap_subtlv
) + p
->length
;
210 tail
->next
= XCALLOC(MTYPE_ENCAP_TLV
, size
);
213 tail
= new = XCALLOC(MTYPE_ENCAP_TLV
, size
);
216 memcpy(tail
, p
, size
);
223 static void encap_free(struct bgp_attr_encap_subtlv
*p
)
225 struct bgp_attr_encap_subtlv
*next
;
229 XFREE(MTYPE_ENCAP_TLV
, p
);
234 void bgp_attr_flush_encap(struct attr
*attr
)
239 if (attr
->encap_subtlvs
) {
240 encap_free(attr
->encap_subtlvs
);
241 attr
->encap_subtlvs
= NULL
;
243 #ifdef ENABLE_BGP_VNC
244 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
245 bgp_attr_get_vnc_subtlvs(attr
);
248 encap_free(vnc_subtlvs
);
249 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
255 * Compare encap sub-tlv chains
260 * This algorithm could be made faster if needed
262 static bool encap_same(const struct bgp_attr_encap_subtlv
*h1
,
263 const struct bgp_attr_encap_subtlv
*h2
)
265 const struct bgp_attr_encap_subtlv
*p
;
266 const struct bgp_attr_encap_subtlv
*q
;
270 if (h1
== NULL
|| h2
== NULL
)
273 for (p
= h1
; p
; p
= p
->next
) {
274 for (q
= h2
; q
; q
= q
->next
) {
275 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
276 && !memcmp(p
->value
, q
->value
, p
->length
)) {
285 for (p
= h2
; p
; p
= p
->next
) {
286 for (q
= h1
; q
; q
= q
->next
) {
287 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
288 && !memcmp(p
->value
, q
->value
, p
->length
)) {
300 static void *encap_hash_alloc(void *p
)
302 /* Encap structure is already allocated. */
308 #ifdef ENABLE_BGP_VNC
313 static struct bgp_attr_encap_subtlv
*
314 encap_intern(struct bgp_attr_encap_subtlv
*encap
, encap_subtlv_type type
)
316 struct bgp_attr_encap_subtlv
*find
;
317 struct hash
*hash
= encap_hash
;
318 #ifdef ENABLE_BGP_VNC
319 if (type
== VNC_SUBTLV_TYPE
)
323 find
= hash_get(hash
, encap
, encap_hash_alloc
);
331 static void encap_unintern(struct bgp_attr_encap_subtlv
**encapp
,
332 encap_subtlv_type type
)
334 struct bgp_attr_encap_subtlv
*encap
= *encapp
;
338 if (encap
->refcnt
== 0) {
339 struct hash
*hash
= encap_hash
;
340 #ifdef ENABLE_BGP_VNC
341 if (type
== VNC_SUBTLV_TYPE
)
344 hash_release(hash
, encap
);
350 static unsigned int encap_hash_key_make(const void *p
)
352 const struct bgp_attr_encap_subtlv
*encap
= p
;
354 return jhash(encap
->value
, encap
->length
, 0);
357 static bool encap_hash_cmp(const void *p1
, const void *p2
)
359 return encap_same((const struct bgp_attr_encap_subtlv
*)p1
,
360 (const struct bgp_attr_encap_subtlv
*)p2
);
363 static void encap_init(void)
365 encap_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
367 #ifdef ENABLE_BGP_VNC
368 vnc_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
373 static void encap_finish(void)
375 hash_clean(encap_hash
, (void (*)(void *))encap_free
);
376 hash_free(encap_hash
);
378 #ifdef ENABLE_BGP_VNC
379 hash_clean(vnc_hash
, (void (*)(void *))encap_free
);
385 static bool overlay_index_same(const struct attr
*a1
, const struct attr
*a2
)
394 return bgp_route_evpn_same(bgp_attr_get_evpn_overlay(a1
),
395 bgp_attr_get_evpn_overlay(a2
));
398 /* Unknown transit attribute. */
399 static struct hash
*transit_hash
;
401 static void transit_free(struct transit
*transit
)
403 XFREE(MTYPE_TRANSIT_VAL
, transit
->val
);
404 XFREE(MTYPE_TRANSIT
, transit
);
407 static void *transit_hash_alloc(void *p
)
409 /* Transit structure is already allocated. */
413 static struct transit
*transit_intern(struct transit
*transit
)
415 struct transit
*find
;
417 find
= hash_get(transit_hash
, transit
, transit_hash_alloc
);
419 transit_free(transit
);
425 static void transit_unintern(struct transit
**transit
)
427 if ((*transit
)->refcnt
)
428 (*transit
)->refcnt
--;
430 if ((*transit
)->refcnt
== 0) {
431 hash_release(transit_hash
, *transit
);
432 transit_free(*transit
);
437 static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt
, int length
,
446 ptr_get_be16(data
+ 1, &tlv_length
);
449 /* The value field of the AIGP TLV is always 8 octets
450 * long and its value is interpreted as an unsigned 64-bit
453 if (tlv_type
== BGP_AIGP_TLV_METRIC
) {
454 (void)ptr_get_be64(data
+ 3, aigp
);
456 /* If an AIGP attribute is received and its first AIGP
457 * TLV contains the maximum value 0xffffffffffffffff,
458 * the attribute SHOULD be considered to be malformed
459 * and SHOULD be discarded as specified in this section.
461 if (*aigp
== BGP_AIGP_TLV_METRIC_MAX
) {
462 zlog_err("Bad AIGP TLV (%s) length: %llu",
463 BGP_AIGP_TLV_METRIC_DESC
,
464 BGP_AIGP_TLV_METRIC_MAX
);
472 length
-= tlv_length
;
478 static uint64_t bgp_aigp_metric_total(struct bgp_path_info
*bpi
)
480 uint64_t aigp
= bgp_attr_get_aigp_metric(bpi
->attr
);
483 return aigp
+ bpi
->nexthop
->metric
;
488 static void stream_put_bgp_aigp_tlv_metric(struct stream
*s
,
489 struct bgp_path_info
*bpi
)
491 stream_putc(s
, BGP_AIGP_TLV_METRIC
);
492 stream_putw(s
, BGP_AIGP_TLV_METRIC_LEN
);
493 stream_putq(s
, bgp_aigp_metric_total(bpi
));
496 static bool bgp_attr_aigp_valid(uint8_t *pnt
, int length
)
503 zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u",
510 ptr_get_be16(data
+ 1, &tlv_length
);
513 if (length
< tlv_length
) {
515 "Bad AIGP attribute length: %u, but TLV length: %u",
520 if (tlv_length
< 3) {
521 zlog_err("Bad AIGP TLV length (MUST be minimum 3): %u",
526 /* AIGP TLV, Length: 11 */
527 if (tlv_type
== BGP_AIGP_TLV_METRIC
&&
528 tlv_length
!= BGP_AIGP_TLV_METRIC_LEN
) {
529 zlog_err("Bad AIGP TLV (%s) length: %u",
530 BGP_AIGP_TLV_METRIC_DESC
, tlv_length
);
535 length
-= tlv_length
;
541 static void *srv6_l3vpn_hash_alloc(void *p
)
546 static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn
*l3vpn
)
548 XFREE(MTYPE_BGP_SRV6_L3VPN
, l3vpn
);
551 static struct bgp_attr_srv6_l3vpn
*
552 srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn
*l3vpn
)
554 struct bgp_attr_srv6_l3vpn
*find
;
556 find
= hash_get(srv6_l3vpn_hash
, l3vpn
, srv6_l3vpn_hash_alloc
);
558 srv6_l3vpn_free(l3vpn
);
563 static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn
**l3vpnp
)
565 struct bgp_attr_srv6_l3vpn
*l3vpn
= *l3vpnp
;
570 if (l3vpn
->refcnt
== 0) {
571 hash_release(srv6_l3vpn_hash
, l3vpn
);
572 srv6_l3vpn_free(l3vpn
);
577 static void *srv6_vpn_hash_alloc(void *p
)
582 static void srv6_vpn_free(struct bgp_attr_srv6_vpn
*vpn
)
584 XFREE(MTYPE_BGP_SRV6_VPN
, vpn
);
587 static struct bgp_attr_srv6_vpn
*srv6_vpn_intern(struct bgp_attr_srv6_vpn
*vpn
)
589 struct bgp_attr_srv6_vpn
*find
;
591 find
= hash_get(srv6_vpn_hash
, vpn
, srv6_vpn_hash_alloc
);
598 static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn
**vpnp
)
600 struct bgp_attr_srv6_vpn
*vpn
= *vpnp
;
605 if (vpn
->refcnt
== 0) {
606 hash_release(srv6_vpn_hash
, vpn
);
612 static uint32_t srv6_l3vpn_hash_key_make(const void *p
)
614 const struct bgp_attr_srv6_l3vpn
*l3vpn
= p
;
617 key
= jhash(&l3vpn
->sid
, 16, key
);
618 key
= jhash_1word(l3vpn
->sid_flags
, key
);
619 key
= jhash_1word(l3vpn
->endpoint_behavior
, key
);
620 key
= jhash_1word(l3vpn
->loc_block_len
, key
);
621 key
= jhash_1word(l3vpn
->loc_node_len
, key
);
622 key
= jhash_1word(l3vpn
->func_len
, key
);
623 key
= jhash_1word(l3vpn
->arg_len
, key
);
624 key
= jhash_1word(l3vpn
->transposition_len
, key
);
625 key
= jhash_1word(l3vpn
->transposition_offset
, key
);
629 static bool srv6_l3vpn_hash_cmp(const void *p1
, const void *p2
)
631 const struct bgp_attr_srv6_l3vpn
*l3vpn1
= p1
;
632 const struct bgp_attr_srv6_l3vpn
*l3vpn2
= p2
;
634 return sid_same(&l3vpn1
->sid
, &l3vpn2
->sid
)
635 && l3vpn1
->sid_flags
== l3vpn2
->sid_flags
636 && l3vpn1
->endpoint_behavior
== l3vpn2
->endpoint_behavior
637 && l3vpn1
->loc_block_len
== l3vpn2
->loc_block_len
638 && l3vpn1
->loc_node_len
== l3vpn2
->loc_node_len
639 && l3vpn1
->func_len
== l3vpn2
->func_len
640 && l3vpn1
->arg_len
== l3vpn2
->arg_len
641 && l3vpn1
->transposition_len
== l3vpn2
->transposition_len
642 && l3vpn1
->transposition_offset
== l3vpn2
->transposition_offset
;
645 static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn
*h1
,
646 const struct bgp_attr_srv6_l3vpn
*h2
)
650 else if (h1
== NULL
|| h2
== NULL
)
653 return srv6_l3vpn_hash_cmp((const void *)h1
, (const void *)h2
);
656 static unsigned int srv6_vpn_hash_key_make(const void *p
)
658 const struct bgp_attr_srv6_vpn
*vpn
= p
;
661 key
= jhash(&vpn
->sid
, 16, key
);
662 key
= jhash_1word(vpn
->sid_flags
, key
);
666 static bool srv6_vpn_hash_cmp(const void *p1
, const void *p2
)
668 const struct bgp_attr_srv6_vpn
*vpn1
= p1
;
669 const struct bgp_attr_srv6_vpn
*vpn2
= p2
;
671 return sid_same(&vpn1
->sid
, &vpn2
->sid
)
672 && vpn1
->sid_flags
== vpn2
->sid_flags
;
675 static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn
*h1
,
676 const struct bgp_attr_srv6_vpn
*h2
)
680 else if (h1
== NULL
|| h2
== NULL
)
683 return srv6_vpn_hash_cmp((const void *)h1
, (const void *)h2
);
686 static void srv6_init(void)
689 hash_create(srv6_l3vpn_hash_key_make
, srv6_l3vpn_hash_cmp
,
690 "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
691 srv6_vpn_hash
= hash_create(srv6_vpn_hash_key_make
, srv6_vpn_hash_cmp
,
692 "BGP Prefix-SID SRv6-VPN-Service-TLV");
695 static void srv6_finish(void)
697 hash_clean(srv6_l3vpn_hash
, (void (*)(void *))srv6_l3vpn_free
);
698 hash_free(srv6_l3vpn_hash
);
699 srv6_l3vpn_hash
= NULL
;
700 hash_clean(srv6_vpn_hash
, (void (*)(void *))srv6_vpn_free
);
701 hash_free(srv6_vpn_hash
);
702 srv6_vpn_hash
= NULL
;
705 static unsigned int transit_hash_key_make(const void *p
)
707 const struct transit
*transit
= p
;
709 return jhash(transit
->val
, transit
->length
, 0);
712 static bool transit_hash_cmp(const void *p1
, const void *p2
)
714 const struct transit
*transit1
= p1
;
715 const struct transit
*transit2
= p2
;
717 return (transit1
->length
== transit2
->length
718 && memcmp(transit1
->val
, transit2
->val
, transit1
->length
) == 0);
721 static void transit_init(void)
723 transit_hash
= hash_create(transit_hash_key_make
, transit_hash_cmp
,
727 static void transit_finish(void)
729 hash_clean(transit_hash
, (void (*)(void *))transit_free
);
730 hash_free(transit_hash
);
734 /* Attribute hash routines. */
735 static struct hash
*attrhash
;
737 unsigned long int attr_count(void)
739 return attrhash
->count
;
742 unsigned long int attr_unknown_count(void)
744 return transit_hash
->count
;
747 unsigned int attrhash_key_make(const void *p
)
749 const struct attr
*attr
= (struct attr
*)p
;
751 #define MIX(val) key = jhash_1word(val, key)
752 #define MIX3(a, b, c) key = jhash_3words((a), (b), (c), key)
754 MIX3(attr
->origin
, attr
->nexthop
.s_addr
, attr
->med
);
755 MIX3(attr
->local_pref
, attr
->aggregator_as
,
756 attr
->aggregator_addr
.s_addr
);
757 MIX3(attr
->weight
, attr
->mp_nexthop_global_in
.s_addr
,
758 attr
->originator_id
.s_addr
);
759 MIX3(attr
->tag
, attr
->label
, attr
->label_index
);
762 MIX(aspath_key_make(attr
->aspath
));
763 if (bgp_attr_get_community(attr
))
764 MIX(community_hash_make(bgp_attr_get_community(attr
)));
765 if (bgp_attr_get_lcommunity(attr
))
766 MIX(lcommunity_hash_make(bgp_attr_get_lcommunity(attr
)));
767 if (bgp_attr_get_ecommunity(attr
))
768 MIX(ecommunity_hash_make(bgp_attr_get_ecommunity(attr
)));
769 if (bgp_attr_get_ipv6_ecommunity(attr
))
770 MIX(ecommunity_hash_make(bgp_attr_get_ipv6_ecommunity(attr
)));
771 if (bgp_attr_get_cluster(attr
))
772 MIX(cluster_hash_key_make(bgp_attr_get_cluster(attr
)));
773 if (bgp_attr_get_transit(attr
))
774 MIX(transit_hash_key_make(bgp_attr_get_transit(attr
)));
775 if (attr
->encap_subtlvs
)
776 MIX(encap_hash_key_make(attr
->encap_subtlvs
));
777 if (attr
->srv6_l3vpn
)
778 MIX(srv6_l3vpn_hash_key_make(attr
->srv6_l3vpn
));
780 MIX(srv6_vpn_hash_key_make(attr
->srv6_vpn
));
781 #ifdef ENABLE_BGP_VNC
782 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
783 bgp_attr_get_vnc_subtlvs(attr
);
785 MIX(encap_hash_key_make(vnc_subtlvs
));
787 MIX(attr
->mp_nexthop_len
);
788 key
= jhash(attr
->mp_nexthop_global
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
789 key
= jhash(attr
->mp_nexthop_local
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
790 MIX3(attr
->nh_ifindex
, attr
->nh_lla_ifindex
, attr
->distance
);
791 MIX(attr
->rmap_table_id
);
795 MIX(bgp_attr_get_aigp_metric(attr
));
800 bool attrhash_cmp(const void *p1
, const void *p2
)
802 const struct attr
*attr1
= p1
;
803 const struct attr
*attr2
= p2
;
805 if (attr1
->flag
== attr2
->flag
&& attr1
->origin
== attr2
->origin
806 && attr1
->nexthop
.s_addr
== attr2
->nexthop
.s_addr
807 && attr1
->aspath
== attr2
->aspath
808 && bgp_attr_get_community(attr1
)
809 == bgp_attr_get_community(attr2
)
810 && attr1
->med
== attr2
->med
811 && attr1
->local_pref
== attr2
->local_pref
812 && attr1
->rmap_change_flags
== attr2
->rmap_change_flags
) {
813 if (attr1
->aggregator_as
== attr2
->aggregator_as
814 && attr1
->aggregator_addr
.s_addr
815 == attr2
->aggregator_addr
.s_addr
816 && attr1
->weight
== attr2
->weight
817 && attr1
->tag
== attr2
->tag
818 && attr1
->label_index
== attr2
->label_index
819 && attr1
->mp_nexthop_len
== attr2
->mp_nexthop_len
820 && bgp_attr_get_ecommunity(attr1
)
821 == bgp_attr_get_ecommunity(attr2
)
822 && bgp_attr_get_ipv6_ecommunity(attr1
)
823 == bgp_attr_get_ipv6_ecommunity(attr2
)
824 && bgp_attr_get_lcommunity(attr1
)
825 == bgp_attr_get_lcommunity(attr2
)
826 && bgp_attr_get_cluster(attr1
)
827 == bgp_attr_get_cluster(attr2
)
828 && bgp_attr_get_transit(attr1
)
829 == bgp_attr_get_transit(attr2
)
830 && bgp_attr_get_aigp_metric(attr1
)
831 == bgp_attr_get_aigp_metric(attr2
)
832 && attr1
->rmap_table_id
== attr2
->rmap_table_id
833 && (attr1
->encap_tunneltype
== attr2
->encap_tunneltype
)
834 && encap_same(attr1
->encap_subtlvs
, attr2
->encap_subtlvs
)
835 #ifdef ENABLE_BGP_VNC
836 && encap_same(bgp_attr_get_vnc_subtlvs(attr1
),
837 bgp_attr_get_vnc_subtlvs(attr2
))
839 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_global
,
840 &attr2
->mp_nexthop_global
)
841 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_local
,
842 &attr2
->mp_nexthop_local
)
843 && IPV4_ADDR_SAME(&attr1
->mp_nexthop_global_in
,
844 &attr2
->mp_nexthop_global_in
)
845 && IPV4_ADDR_SAME(&attr1
->originator_id
,
846 &attr2
->originator_id
)
847 && overlay_index_same(attr1
, attr2
)
848 && !memcmp(&attr1
->esi
, &attr2
->esi
, sizeof(esi_t
))
849 && attr1
->es_flags
== attr2
->es_flags
850 && attr1
->mm_sync_seqnum
== attr2
->mm_sync_seqnum
851 && attr1
->df_pref
== attr2
->df_pref
852 && attr1
->df_alg
== attr2
->df_alg
853 && attr1
->nh_ifindex
== attr2
->nh_ifindex
854 && attr1
->nh_lla_ifindex
== attr2
->nh_lla_ifindex
855 && attr1
->distance
== attr2
->distance
856 && srv6_l3vpn_same(attr1
->srv6_l3vpn
, attr2
->srv6_l3vpn
)
857 && srv6_vpn_same(attr1
->srv6_vpn
, attr2
->srv6_vpn
)
858 && attr1
->srte_color
== attr2
->srte_color
859 && attr1
->nh_type
== attr2
->nh_type
860 && attr1
->bh_type
== attr2
->bh_type
861 && attr1
->otc
== attr2
->otc
)
868 static void attrhash_init(void)
871 hash_create(attrhash_key_make
, attrhash_cmp
, "BGP Attributes");
875 * special for hash_clean below
877 static void attr_vfree(void *attr
)
879 XFREE(MTYPE_ATTR
, attr
);
882 static void attrhash_finish(void)
884 hash_clean(attrhash
, attr_vfree
);
889 static void attr_show_all_iterator(struct hash_bucket
*bucket
, struct vty
*vty
)
891 struct attr
*attr
= bucket
->data
;
892 struct in6_addr
*sid
= NULL
;
894 if (attr
->srv6_l3vpn
)
895 sid
= &attr
->srv6_l3vpn
->sid
;
896 else if (attr
->srv6_vpn
)
897 sid
= &attr
->srv6_vpn
->sid
;
899 vty_out(vty
, "attr[%ld] nexthop %pI4\n", attr
->refcnt
, &attr
->nexthop
);
903 " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n",
904 attr
->flag
, attr
->distance
, attr
->med
, attr
->local_pref
,
905 attr
->origin
, attr
->weight
, attr
->label
, sid
);
908 void attr_show_all(struct vty
*vty
)
910 hash_iterate(attrhash
, (void (*)(struct hash_bucket
*,
911 void *))attr_show_all_iterator
,
915 static void *bgp_attr_hash_alloc(void *p
)
917 struct attr
*val
= (struct attr
*)p
;
920 attr
= XMALLOC(MTYPE_ATTR
, sizeof(struct attr
));
922 if (val
->encap_subtlvs
) {
923 val
->encap_subtlvs
= NULL
;
925 #ifdef ENABLE_BGP_VNC
926 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
927 bgp_attr_get_vnc_subtlvs(val
);
930 bgp_attr_set_vnc_subtlvs(val
, NULL
);
937 /* Internet argument attribute. */
938 struct attr
*bgp_attr_intern(struct attr
*attr
)
941 struct ecommunity
*ecomm
= NULL
;
942 struct ecommunity
*ipv6_ecomm
= NULL
;
943 struct lcommunity
*lcomm
= NULL
;
944 struct community
*comm
= NULL
;
946 /* Intern referenced structure. */
948 if (!attr
->aspath
->refcnt
)
949 attr
->aspath
= aspath_intern(attr
->aspath
);
951 attr
->aspath
->refcnt
++;
954 comm
= bgp_attr_get_community(attr
);
957 bgp_attr_set_community(attr
, community_intern(comm
));
962 ecomm
= bgp_attr_get_ecommunity(attr
);
965 bgp_attr_set_ecommunity(attr
, ecommunity_intern(ecomm
));
970 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
972 if (!ipv6_ecomm
->refcnt
)
973 bgp_attr_set_ipv6_ecommunity(
974 attr
, ecommunity_intern(ipv6_ecomm
));
976 ipv6_ecomm
->refcnt
++;
979 lcomm
= bgp_attr_get_lcommunity(attr
);
982 bgp_attr_set_lcommunity(attr
, lcommunity_intern(lcomm
));
987 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
990 if (!cluster
->refcnt
)
991 bgp_attr_set_cluster(attr
, cluster_intern(cluster
));
996 struct transit
*transit
= bgp_attr_get_transit(attr
);
999 if (!transit
->refcnt
)
1000 bgp_attr_set_transit(attr
, transit_intern(transit
));
1004 if (attr
->encap_subtlvs
) {
1005 if (!attr
->encap_subtlvs
->refcnt
)
1006 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
1009 attr
->encap_subtlvs
->refcnt
++;
1011 if (attr
->srv6_l3vpn
) {
1012 if (!attr
->srv6_l3vpn
->refcnt
)
1013 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
1015 attr
->srv6_l3vpn
->refcnt
++;
1017 if (attr
->srv6_vpn
) {
1018 if (!attr
->srv6_vpn
->refcnt
)
1019 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
1021 attr
->srv6_vpn
->refcnt
++;
1023 #ifdef ENABLE_BGP_VNC
1024 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1025 bgp_attr_get_vnc_subtlvs(attr
);
1028 if (!vnc_subtlvs
->refcnt
)
1029 bgp_attr_set_vnc_subtlvs(
1031 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
1033 vnc_subtlvs
->refcnt
++;
1037 /* At this point, attr only contains intern'd pointers. that means
1038 * if we find it in attrhash, it has all the same pointers and we
1039 * correctly updated the refcounts on these.
1040 * If we don't find it, we need to allocate a one because in all
1041 * cases this returns a new reference to a hashed attr, but the input
1042 * wasn't on hash. */
1043 find
= (struct attr
*)hash_get(attrhash
, attr
, bgp_attr_hash_alloc
);
1049 /* Make network statement's attribute. */
1050 struct attr
*bgp_attr_default_set(struct attr
*attr
, struct bgp
*bgp
,
1053 memset(attr
, 0, sizeof(struct attr
));
1055 attr
->origin
= origin
;
1056 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1057 attr
->aspath
= aspath_empty();
1058 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1059 attr
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1061 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
1062 attr
->label
= MPLS_INVALID_LABEL
;
1063 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1064 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1065 attr
->local_pref
= bgp
->default_local_pref
;
1070 /* Create the attributes for an aggregate */
1071 struct attr
*bgp_attr_aggregate_intern(
1072 struct bgp
*bgp
, uint8_t origin
, struct aspath
*aspath
,
1073 struct community
*community
, struct ecommunity
*ecommunity
,
1074 struct lcommunity
*lcommunity
, struct bgp_aggregate
*aggregate
,
1075 uint8_t atomic_aggregate
, const struct prefix
*p
)
1079 route_map_result_t ret
;
1081 memset(&attr
, 0, sizeof(attr
));
1083 /* Origin attribute. */
1084 attr
.origin
= origin
;
1085 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1089 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1091 /* AS path attribute. */
1093 attr
.aspath
= aspath_intern(aspath
);
1095 attr
.aspath
= aspath_empty();
1096 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1098 /* Next hop attribute. */
1099 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1102 uint32_t gshut
= COMMUNITY_GSHUT
;
1104 /* If we are not shutting down ourselves and we are
1105 * aggregating a route that contains the GSHUT community we
1106 * need to remove that community when creating the aggregate */
1107 if (!bgp_in_graceful_shutdown(bgp
)
1108 && community_include(community
, gshut
)) {
1109 community_del_val(community
, &gshut
);
1112 bgp_attr_set_community(&attr
, community
);
1116 bgp_attr_set_ecommunity(&attr
, ecommunity
);
1119 bgp_attr_set_lcommunity(&attr
, lcommunity
);
1121 if (bgp_in_graceful_shutdown(bgp
))
1122 bgp_attr_add_gshut_community(&attr
);
1124 attr
.label_index
= BGP_INVALID_LABEL_INDEX
;
1125 attr
.label
= MPLS_INVALID_LABEL
;
1126 attr
.weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1127 attr
.mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1128 if (!aggregate
->as_set
|| atomic_aggregate
)
1129 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1130 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1131 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
))
1132 attr
.aggregator_as
= bgp
->confed_id
;
1134 attr
.aggregator_as
= bgp
->as
;
1135 attr
.aggregator_addr
= bgp
->router_id
;
1137 /* Apply route-map */
1138 if (aggregate
->rmap
.name
) {
1139 struct attr attr_tmp
= attr
;
1140 struct bgp_path_info rmap_path
;
1142 memset(&rmap_path
, 0, sizeof(rmap_path
));
1143 rmap_path
.peer
= bgp
->peer_self
;
1144 rmap_path
.attr
= &attr_tmp
;
1146 SET_FLAG(bgp
->peer_self
->rmap_type
, PEER_RMAP_TYPE_AGGREGATE
);
1148 ret
= route_map_apply(aggregate
->rmap
.map
, p
, &rmap_path
);
1150 bgp
->peer_self
->rmap_type
= 0;
1152 if (ret
== RMAP_DENYMATCH
) {
1153 /* Free uninterned attribute. */
1154 bgp_attr_flush(&attr_tmp
);
1156 /* Unintern original. */
1157 aspath_unintern(&attr
.aspath
);
1161 if (bgp_in_graceful_shutdown(bgp
))
1162 bgp_attr_add_gshut_community(&attr_tmp
);
1164 new = bgp_attr_intern(&attr_tmp
);
1167 if (bgp_in_graceful_shutdown(bgp
))
1168 bgp_attr_add_gshut_community(&attr
);
1170 new = bgp_attr_intern(&attr
);
1173 /* Always release the 'intern()'ed AS Path. */
1174 aspath_unintern(&attr
.aspath
);
1179 /* Unintern just the sub-components of the attr, but not the attr */
1180 void bgp_attr_unintern_sub(struct attr
*attr
)
1182 struct ecommunity
*ecomm
= NULL
;
1183 struct ecommunity
*ipv6_ecomm
= NULL
;
1184 struct cluster_list
*cluster
;
1185 struct lcommunity
*lcomm
= NULL
;
1186 struct community
*comm
= NULL
;
1188 /* aspath refcount shoud be decrement. */
1189 aspath_unintern(&attr
->aspath
);
1190 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
));
1192 comm
= bgp_attr_get_community(attr
);
1193 community_unintern(&comm
);
1194 bgp_attr_set_community(attr
, NULL
);
1196 ecomm
= bgp_attr_get_ecommunity(attr
);
1197 ecommunity_unintern(&ecomm
);
1198 bgp_attr_set_ecommunity(attr
, NULL
);
1200 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1201 ecommunity_unintern(&ipv6_ecomm
);
1202 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1204 lcomm
= bgp_attr_get_lcommunity(attr
);
1205 lcommunity_unintern(&lcomm
);
1206 bgp_attr_set_lcommunity(attr
, NULL
);
1208 cluster
= bgp_attr_get_cluster(attr
);
1210 cluster_unintern(&cluster
);
1211 bgp_attr_set_cluster(attr
, cluster
);
1213 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
));
1215 struct transit
*transit
= bgp_attr_get_transit(attr
);
1218 transit_unintern(&transit
);
1219 bgp_attr_set_transit(attr
, transit
);
1222 if (attr
->encap_subtlvs
)
1223 encap_unintern(&attr
->encap_subtlvs
, ENCAP_SUBTLV_TYPE
);
1225 #ifdef ENABLE_BGP_VNC
1226 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1227 bgp_attr_get_vnc_subtlvs(attr
);
1230 encap_unintern(&vnc_subtlvs
, VNC_SUBTLV_TYPE
);
1231 bgp_attr_set_vnc_subtlvs(attr
, vnc_subtlvs
);
1235 if (attr
->srv6_l3vpn
)
1236 srv6_l3vpn_unintern(&attr
->srv6_l3vpn
);
1239 srv6_vpn_unintern(&attr
->srv6_vpn
);
1242 /* Free bgp attribute and aspath. */
1243 void bgp_attr_unintern(struct attr
**pattr
)
1245 struct attr
*attr
= *pattr
;
1249 /* Decrement attribute reference. */
1254 /* If reference becomes zero then free attribute object. */
1255 if (attr
->refcnt
== 0) {
1256 ret
= hash_release(attrhash
, attr
);
1257 assert(ret
!= NULL
);
1258 XFREE(MTYPE_ATTR
, attr
);
1262 bgp_attr_unintern_sub(&tmp
);
1265 void bgp_attr_flush(struct attr
*attr
)
1267 struct ecommunity
*ecomm
;
1268 struct ecommunity
*ipv6_ecomm
;
1269 struct cluster_list
*cluster
;
1270 struct lcommunity
*lcomm
;
1271 struct community
*comm
;
1273 if (attr
->aspath
&& !attr
->aspath
->refcnt
) {
1274 aspath_free(attr
->aspath
);
1275 attr
->aspath
= NULL
;
1277 comm
= bgp_attr_get_community(attr
);
1278 if (comm
&& !comm
->refcnt
)
1279 community_free(&comm
);
1280 bgp_attr_set_community(attr
, NULL
);
1282 ecomm
= bgp_attr_get_ecommunity(attr
);
1283 if (ecomm
&& !ecomm
->refcnt
)
1284 ecommunity_free(&ecomm
);
1285 bgp_attr_set_ecommunity(attr
, NULL
);
1287 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1288 if (ipv6_ecomm
&& !ipv6_ecomm
->refcnt
)
1289 ecommunity_free(&ipv6_ecomm
);
1290 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1292 lcomm
= bgp_attr_get_lcommunity(attr
);
1293 if (lcomm
&& !lcomm
->refcnt
)
1294 lcommunity_free(&lcomm
);
1295 bgp_attr_set_lcommunity(attr
, NULL
);
1297 cluster
= bgp_attr_get_cluster(attr
);
1298 if (cluster
&& !cluster
->refcnt
) {
1299 cluster_free(cluster
);
1300 bgp_attr_set_cluster(attr
, NULL
);
1303 struct transit
*transit
= bgp_attr_get_transit(attr
);
1305 if (transit
&& !transit
->refcnt
) {
1306 transit_free(transit
);
1307 bgp_attr_set_transit(attr
, NULL
);
1309 if (attr
->encap_subtlvs
&& !attr
->encap_subtlvs
->refcnt
) {
1310 encap_free(attr
->encap_subtlvs
);
1311 attr
->encap_subtlvs
= NULL
;
1313 if (attr
->srv6_l3vpn
&& !attr
->srv6_l3vpn
->refcnt
) {
1314 srv6_l3vpn_free(attr
->srv6_l3vpn
);
1315 attr
->srv6_l3vpn
= NULL
;
1317 if (attr
->srv6_vpn
&& !attr
->srv6_vpn
->refcnt
) {
1318 srv6_vpn_free(attr
->srv6_vpn
);
1319 attr
->srv6_vpn
= NULL
;
1321 #ifdef ENABLE_BGP_VNC
1322 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1323 bgp_attr_get_vnc_subtlvs(attr
);
1325 if (vnc_subtlvs
&& !vnc_subtlvs
->refcnt
) {
1326 encap_free(vnc_subtlvs
);
1327 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
1332 /* Implement draft-scudder-idr-optional-transitive behaviour and
1333 * avoid resetting sessions for malformed attributes which are
1334 * are partial/optional and hence where the error likely was not
1335 * introduced by the sending neighbour.
1337 static enum bgp_attr_parse_ret
1338 bgp_attr_malformed(struct bgp_attr_parser_args
*args
, uint8_t subcode
,
1341 struct peer
*const peer
= args
->peer
;
1342 struct attr
*const attr
= args
->attr
;
1343 const uint8_t flags
= args
->flags
;
1344 /* startp and length must be special-cased, as whether or not to
1345 * send the attribute data with the NOTIFY depends on the error,
1346 * the caller therefore signals this with the seperate length argument
1348 uint8_t *notify_datap
= (length
> 0 ? args
->startp
: NULL
);
1350 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1351 char attr_str
[BUFSIZ
] = {0};
1353 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1355 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1358 /* Only relax error handling for eBGP peers */
1359 if (peer
->sort
!= BGP_PEER_EBGP
) {
1360 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1361 notify_datap
, length
);
1362 return BGP_ATTR_PARSE_ERROR
;
1365 /* Adjust the stream getp to the end of the attribute, in case we can
1366 * still proceed but the caller hasn't read all the attribute.
1368 stream_set_getp(BGP_INPUT(peer
),
1369 (args
->startp
- STREAM_DATA(BGP_INPUT(peer
)))
1372 switch (args
->type
) {
1373 /* where an attribute is relatively inconsequential, e.g. it does not
1374 * affect route selection, and can be safely ignored, then any such
1375 * attributes which are malformed should just be ignored and the route
1376 * processed as normal.
1378 case BGP_ATTR_AS4_AGGREGATOR
:
1379 case BGP_ATTR_AGGREGATOR
:
1380 case BGP_ATTR_ATOMIC_AGGREGATE
:
1381 return BGP_ATTR_PARSE_PROCEED
;
1383 /* Core attributes, particularly ones which may influence route
1384 * selection, should be treat-as-withdraw.
1386 case BGP_ATTR_ORIGIN
:
1387 case BGP_ATTR_AS_PATH
:
1388 case BGP_ATTR_NEXT_HOP
:
1389 case BGP_ATTR_MULTI_EXIT_DISC
:
1390 case BGP_ATTR_LOCAL_PREF
:
1391 case BGP_ATTR_COMMUNITIES
:
1392 case BGP_ATTR_EXT_COMMUNITIES
:
1393 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
1394 case BGP_ATTR_LARGE_COMMUNITIES
:
1395 case BGP_ATTR_ORIGINATOR_ID
:
1396 case BGP_ATTR_CLUSTER_LIST
:
1398 return BGP_ATTR_PARSE_WITHDRAW
;
1399 case BGP_ATTR_MP_REACH_NLRI
:
1400 case BGP_ATTR_MP_UNREACH_NLRI
:
1401 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1402 notify_datap
, length
);
1403 return BGP_ATTR_PARSE_ERROR
;
1406 /* Partial optional attributes that are malformed should not cause
1407 * the whole session to be reset. Instead treat it as a withdrawal
1408 * of the routes, if possible.
1410 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)
1411 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1412 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
))
1413 return BGP_ATTR_PARSE_WITHDRAW
;
1415 /* default to reset */
1416 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1419 /* Find out what is wrong with the path attribute flag bits and log the error.
1420 "Flag bits" here stand for Optional, Transitive and Partial, but not for
1421 Extended Length. Checking O/T/P bits at once implies, that the attribute
1422 being diagnosed is defined by RFC as either a "well-known" or an "optional,
1423 non-transitive" attribute. */
1425 bgp_attr_flags_diagnose(struct bgp_attr_parser_args
*args
,
1426 uint8_t desired_flags
/* how RFC says it must be */
1429 uint8_t seen
= 0, i
;
1430 uint8_t real_flags
= args
->flags
;
1431 const uint8_t attr_code
= args
->type
;
1433 desired_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1434 real_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1435 for (i
= 0; i
<= 2; i
++) /* O,T,P, but not E */
1436 if (CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1437 != CHECK_FLAG(real_flags
, attr_flag_str
[i
].key
)) {
1438 flog_err(EC_BGP_ATTR_FLAG
,
1439 "%s attribute must%s be flagged as \"%s\"",
1440 lookup_msg(attr_str
, attr_code
, NULL
),
1441 CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1444 attr_flag_str
[i
].str
);
1449 "Strange, %s called for attr %s, but no problem found with flags (real flags 0x%x, desired 0x%x)",
1450 __func__
, lookup_msg(attr_str
, attr_code
, NULL
),
1451 real_flags
, desired_flags
);
1455 /* Required flags for attributes. EXTLEN will be masked off when testing,
1456 * as will PARTIAL for optional+transitive attributes.
1458 const uint8_t attr_flags_values
[] = {
1459 [BGP_ATTR_ORIGIN
] = BGP_ATTR_FLAG_TRANS
,
1460 [BGP_ATTR_AS_PATH
] = BGP_ATTR_FLAG_TRANS
,
1461 [BGP_ATTR_NEXT_HOP
] = BGP_ATTR_FLAG_TRANS
,
1462 [BGP_ATTR_MULTI_EXIT_DISC
] = BGP_ATTR_FLAG_OPTIONAL
,
1463 [BGP_ATTR_LOCAL_PREF
] = BGP_ATTR_FLAG_TRANS
,
1464 [BGP_ATTR_ATOMIC_AGGREGATE
] = BGP_ATTR_FLAG_TRANS
,
1465 [BGP_ATTR_AGGREGATOR
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1466 [BGP_ATTR_COMMUNITIES
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1467 [BGP_ATTR_ORIGINATOR_ID
] = BGP_ATTR_FLAG_OPTIONAL
,
1468 [BGP_ATTR_CLUSTER_LIST
] = BGP_ATTR_FLAG_OPTIONAL
,
1469 [BGP_ATTR_MP_REACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1470 [BGP_ATTR_MP_UNREACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1471 [BGP_ATTR_EXT_COMMUNITIES
] =
1472 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1473 [BGP_ATTR_AS4_PATH
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1474 [BGP_ATTR_AS4_AGGREGATOR
] =
1475 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1476 [BGP_ATTR_PMSI_TUNNEL
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1477 [BGP_ATTR_LARGE_COMMUNITIES
] =
1478 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1479 [BGP_ATTR_OTC
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1480 [BGP_ATTR_PREFIX_SID
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1481 [BGP_ATTR_IPV6_EXT_COMMUNITIES
] =
1482 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1483 [BGP_ATTR_AIGP
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1485 static const size_t attr_flags_values_max
= array_size(attr_flags_values
) - 1;
1487 static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args
*args
)
1489 uint8_t mask
= BGP_ATTR_FLAG_EXTLEN
;
1490 const uint8_t flags
= args
->flags
;
1491 const uint8_t attr_code
= args
->type
;
1493 /* there may be attributes we don't know about */
1494 if (attr_code
> attr_flags_values_max
)
1496 if (attr_flags_values
[attr_code
] == 0)
1499 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set
1503 if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL
, flags
)
1504 && !CHECK_FLAG(BGP_ATTR_FLAG_TRANS
, flags
)) {
1507 "%s well-known attributes must have transitive flag set (%x)",
1508 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1512 /* "For well-known attributes and for optional non-transitive
1514 * the Partial bit MUST be set to 0."
1516 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
)) {
1517 if (!CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)) {
1518 flog_err(EC_BGP_ATTR_FLAG
,
1519 "%s well-known attribute must NOT have the partial flag set (%x)",
1520 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1523 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1524 && !CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)) {
1525 flog_err(EC_BGP_ATTR_FLAG
,
1526 "%s optional + transitive attribute must NOT have the partial flag set (%x)",
1527 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1532 /* Optional transitive attributes may go through speakers that don't
1533 * reocgnise them and set the Partial bit.
1535 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1536 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
))
1537 SET_FLAG(mask
, BGP_ATTR_FLAG_PARTIAL
);
1539 if ((flags
& ~mask
) == attr_flags_values
[attr_code
])
1542 bgp_attr_flags_diagnose(args
, attr_flags_values
[attr_code
]);
1546 /* Get origin attribute of the update message. */
1547 static enum bgp_attr_parse_ret
1548 bgp_attr_origin(struct bgp_attr_parser_args
*args
)
1550 struct peer
*const peer
= args
->peer
;
1551 struct attr
*const attr
= args
->attr
;
1552 const bgp_size_t length
= args
->length
;
1554 /* If any recognized attribute has Attribute Length that conflicts
1555 with the expected length (based on the attribute type code), then
1556 the Error Subcode is set to Attribute Length Error. The Data
1557 field contains the erroneous attribute (type, length and
1560 flog_err(EC_BGP_ATTR_LEN
,
1561 "Origin attribute length is not one %d", length
);
1562 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1566 /* Fetch origin attribute. */
1567 attr
->origin
= stream_getc(BGP_INPUT(peer
));
1569 /* If the ORIGIN attribute has an undefined value, then the Error
1570 Subcode is set to Invalid Origin Attribute. The Data field
1571 contains the unrecognized attribute (type, length and value). */
1572 if ((attr
->origin
!= BGP_ORIGIN_IGP
) && (attr
->origin
!= BGP_ORIGIN_EGP
)
1573 && (attr
->origin
!= BGP_ORIGIN_INCOMPLETE
)) {
1574 flog_err(EC_BGP_ATTR_ORIGIN
,
1575 "Origin attribute value is invalid %d", attr
->origin
);
1576 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_INVAL_ORIGIN
,
1580 /* Set oring attribute flag. */
1581 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1586 /* Parse AS path information. This function is wrapper of
1588 static int bgp_attr_aspath(struct bgp_attr_parser_args
*args
)
1590 struct attr
*const attr
= args
->attr
;
1591 struct peer
*const peer
= args
->peer
;
1592 const bgp_size_t length
= args
->length
;
1595 * peer with AS4 => will get 4Byte ASnums
1596 * otherwise, will get 16 Bit
1598 attr
->aspath
= aspath_parse(
1600 CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1601 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
));
1603 /* In case of IBGP, length will be zero. */
1604 if (!attr
->aspath
) {
1605 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1606 "Malformed AS path from %s, length is %d", peer
->host
,
1608 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1612 /* Conformant BGP speakers SHOULD NOT send BGP
1613 * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1614 * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1615 * withdraw" error handling behavior as per [RFC7606].
1617 if (peer
->bgp
->reject_as_sets
&& aspath_check_as_sets(attr
->aspath
)) {
1618 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1619 "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1621 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1625 /* Set aspath attribute flag. */
1626 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1628 return BGP_ATTR_PARSE_PROCEED
;
1631 static enum bgp_attr_parse_ret
bgp_attr_aspath_check(struct peer
*const peer
,
1632 struct attr
*const attr
)
1634 /* These checks were part of bgp_attr_aspath, but with
1635 * as4 we should to check aspath things when
1636 * aspath synthesizing with as4_path has already taken place.
1637 * Otherwise we check ASPATH and use the synthesized thing, and that is
1639 * So do the checks later, i.e. here
1641 struct aspath
*aspath
;
1643 /* Confederation sanity check. */
1644 if ((peer
->sort
== BGP_PEER_CONFED
1645 && !aspath_left_confed_check(attr
->aspath
))
1646 || (peer
->sort
== BGP_PEER_EBGP
1647 && aspath_confed_check(attr
->aspath
))) {
1648 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "Malformed AS path from %s",
1650 return BGP_ATTR_PARSE_WITHDRAW
;
1653 /* First AS check for EBGP. */
1654 if (CHECK_FLAG(peer
->flags
, PEER_FLAG_ENFORCE_FIRST_AS
)) {
1655 if (peer
->sort
== BGP_PEER_EBGP
1656 && !aspath_firstas_check(attr
->aspath
, peer
->as
)) {
1657 flog_err(EC_BGP_ATTR_FIRST_AS
,
1658 "%s incorrect first AS (must be %u)",
1659 peer
->host
, peer
->as
);
1660 return BGP_ATTR_PARSE_WITHDRAW
;
1664 /* Codification of AS 0 Processing */
1665 if (peer
->sort
== BGP_PEER_EBGP
&& aspath_check_as_zero(attr
->aspath
)) {
1667 EC_BGP_ATTR_MAL_AS_PATH
,
1668 "Malformed AS path, AS number is 0 in the path from %s",
1670 return BGP_ATTR_PARSE_WITHDRAW
;
1673 /* local-as prepend */
1674 if (peer
->change_local_as
1675 && !CHECK_FLAG(peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
)) {
1676 aspath
= aspath_dup(attr
->aspath
);
1677 aspath
= aspath_add_seq(aspath
, peer
->change_local_as
);
1678 aspath_unintern(&attr
->aspath
);
1679 attr
->aspath
= aspath_intern(aspath
);
1682 return BGP_ATTR_PARSE_PROCEED
;
1685 /* Parse AS4 path information. This function is another wrapper of
1687 static int bgp_attr_as4_path(struct bgp_attr_parser_args
*args
,
1688 struct aspath
**as4_path
)
1690 struct peer
*const peer
= args
->peer
;
1691 struct attr
*const attr
= args
->attr
;
1692 const bgp_size_t length
= args
->length
;
1694 *as4_path
= aspath_parse(peer
->curr
, length
, 1);
1696 /* In case of IBGP, length will be zero. */
1698 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1699 "Malformed AS4 path from %s, length is %d", peer
->host
,
1701 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1705 /* Conformant BGP speakers SHOULD NOT send BGP
1706 * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1707 * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1708 * withdraw" error handling behavior as per [RFC7606].
1710 if (peer
->bgp
->reject_as_sets
&& aspath_check_as_sets(attr
->aspath
)) {
1711 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1712 "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1714 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1718 /* Set aspath attribute flag. */
1719 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
);
1721 return BGP_ATTR_PARSE_PROCEED
;
1725 * Check that the nexthop attribute is valid.
1727 enum bgp_attr_parse_ret
bgp_attr_nexthop_valid(struct peer
*peer
,
1730 struct bgp
*bgp
= peer
->bgp
;
1732 if (ipv4_martian(&attr
->nexthop
) && !bgp
->allow_martian
) {
1733 uint8_t data
[7]; /* type(2) + length(1) + nhop(4) */
1735 flog_err(EC_BGP_ATTR_MARTIAN_NH
, "Martian nexthop %pI4",
1737 data
[0] = BGP_ATTR_FLAG_TRANS
;
1738 data
[1] = BGP_ATTR_NEXT_HOP
;
1739 data
[2] = BGP_ATTR_NHLEN_IPV4
;
1740 memcpy(&data
[3], &attr
->nexthop
.s_addr
, BGP_ATTR_NHLEN_IPV4
);
1741 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
1742 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1744 return BGP_ATTR_PARSE_ERROR
;
1747 return BGP_ATTR_PARSE_PROCEED
;
1750 /* Nexthop attribute. */
1751 static enum bgp_attr_parse_ret
1752 bgp_attr_nexthop(struct bgp_attr_parser_args
*args
)
1754 struct peer
*const peer
= args
->peer
;
1755 struct attr
*const attr
= args
->attr
;
1756 const bgp_size_t length
= args
->length
;
1758 /* Check nexthop attribute length. */
1760 flog_err(EC_BGP_ATTR_LEN
,
1761 "Nexthop attribute length isn't four [%d]", length
);
1763 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1767 attr
->nexthop
.s_addr
= stream_get_ipv4(peer
->curr
);
1768 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1770 return BGP_ATTR_PARSE_PROCEED
;
1773 /* MED atrribute. */
1774 static enum bgp_attr_parse_ret
bgp_attr_med(struct bgp_attr_parser_args
*args
)
1776 struct peer
*const peer
= args
->peer
;
1777 struct attr
*const attr
= args
->attr
;
1778 const bgp_size_t length
= args
->length
;
1782 flog_err(EC_BGP_ATTR_LEN
,
1783 "MED attribute length isn't four [%d]", length
);
1785 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1789 attr
->med
= stream_getl(peer
->curr
);
1791 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1793 return BGP_ATTR_PARSE_PROCEED
;
1796 /* Local preference attribute. */
1797 static enum bgp_attr_parse_ret
1798 bgp_attr_local_pref(struct bgp_attr_parser_args
*args
)
1800 struct peer
*const peer
= args
->peer
;
1801 struct attr
*const attr
= args
->attr
;
1802 const bgp_size_t length
= args
->length
;
1804 /* if received from an internal neighbor, it SHALL be considered
1805 * malformed if its length is not equal to 4. If malformed, the
1806 * UPDATE message SHALL be handled using the approach of "treat-as-
1809 if (peer
->sort
== BGP_PEER_IBGP
&& length
!= 4) {
1810 flog_err(EC_BGP_ATTR_LEN
,
1811 "LOCAL_PREF attribute length isn't 4 [%u]", length
);
1812 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1816 /* If it is contained in an UPDATE message that is received from an
1817 external peer, then this attribute MUST be ignored by the
1818 receiving speaker. */
1819 if (peer
->sort
== BGP_PEER_EBGP
) {
1820 STREAM_FORWARD_GETP(peer
->curr
, length
);
1821 return BGP_ATTR_PARSE_PROCEED
;
1824 STREAM_GETL(peer
->curr
, attr
->local_pref
);
1826 /* Set the local-pref flag. */
1827 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
1829 return BGP_ATTR_PARSE_PROCEED
;
1832 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1836 /* Atomic aggregate. */
1837 static int bgp_attr_atomic(struct bgp_attr_parser_args
*args
)
1839 struct peer
*const peer
= args
->peer
;
1840 struct attr
*const attr
= args
->attr
;
1841 const bgp_size_t length
= args
->length
;
1845 flog_err(EC_BGP_ATTR_LEN
,
1846 "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1848 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1852 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
1855 /* Set atomic aggregate flag. */
1856 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1858 return BGP_ATTR_PARSE_PROCEED
;
1861 stream_forward_getp(peer
->curr
, length
);
1863 return bgp_attr_ignore(peer
, args
->type
);
1866 /* Aggregator attribute */
1867 static int bgp_attr_aggregator(struct bgp_attr_parser_args
*args
)
1869 struct peer
*const peer
= args
->peer
;
1870 struct attr
*const attr
= args
->attr
;
1871 const bgp_size_t length
= args
->length
;
1876 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1877 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1878 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
))
1881 if (length
!= wantedlen
) {
1882 flog_err(EC_BGP_ATTR_LEN
,
1883 "AGGREGATOR attribute length isn't %u [%u]", wantedlen
,
1885 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1889 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
1890 goto aggregator_ignore
;
1892 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
))
1893 aggregator_as
= stream_getl(peer
->curr
);
1895 aggregator_as
= stream_getw(peer
->curr
);
1897 attr
->aggregator_as
= aggregator_as
;
1898 attr
->aggregator_addr
.s_addr
= stream_get_ipv4(peer
->curr
);
1900 /* Codification of AS 0 Processing */
1901 if (aggregator_as
== BGP_AS_ZERO
) {
1902 flog_err(EC_BGP_ATTR_LEN
,
1903 "%s: AGGREGATOR AS number is 0 for aspath: %s",
1904 peer
->host
, aspath_print(attr
->aspath
));
1906 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1907 char attr_str
[BUFSIZ
] = {0};
1909 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1911 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1914 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1917 return BGP_ATTR_PARSE_PROCEED
;
1920 stream_forward_getp(peer
->curr
, length
);
1922 return bgp_attr_ignore(peer
, args
->type
);
1925 /* New Aggregator attribute */
1926 static enum bgp_attr_parse_ret
1927 bgp_attr_as4_aggregator(struct bgp_attr_parser_args
*args
,
1928 as_t
*as4_aggregator_as
,
1929 struct in_addr
*as4_aggregator_addr
)
1931 struct peer
*const peer
= args
->peer
;
1932 struct attr
*const attr
= args
->attr
;
1933 const bgp_size_t length
= args
->length
;
1937 flog_err(EC_BGP_ATTR_LEN
, "New Aggregator length is not 8 [%d]",
1939 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1943 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
1944 goto as4_aggregator_ignore
;
1946 aggregator_as
= stream_getl(peer
->curr
);
1948 *as4_aggregator_as
= aggregator_as
;
1949 as4_aggregator_addr
->s_addr
= stream_get_ipv4(peer
->curr
);
1951 /* Codification of AS 0 Processing */
1952 if (aggregator_as
== BGP_AS_ZERO
) {
1953 flog_err(EC_BGP_ATTR_LEN
,
1954 "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
1955 peer
->host
, aspath_print(attr
->aspath
));
1957 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1958 char attr_str
[BUFSIZ
] = {0};
1960 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1962 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1965 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
);
1968 return BGP_ATTR_PARSE_PROCEED
;
1970 as4_aggregator_ignore
:
1971 stream_forward_getp(peer
->curr
, length
);
1973 return bgp_attr_ignore(peer
, args
->type
);
1976 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1978 static enum bgp_attr_parse_ret
1979 bgp_attr_munge_as4_attrs(struct peer
*const peer
, struct attr
*const attr
,
1980 struct aspath
*as4_path
, as_t as4_aggregator
,
1981 struct in_addr
*as4_aggregator_addr
)
1983 int ignore_as4_path
= 0;
1984 struct aspath
*newpath
;
1986 if (!attr
->aspath
) {
1987 /* NULL aspath shouldn't be possible as bgp_attr_parse should
1989 * checked that all well-known, mandatory attributes were
1992 * Can only be a problem with peer itself - hard error
1994 return BGP_ATTR_PARSE_ERROR
;
1997 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
1998 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
2000 * It is worth a warning though, because the peer really
2001 * should not send them
2003 if (BGP_DEBUG(as4
, AS4
)) {
2004 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
2005 zlog_debug("[AS4] %s %s AS4_PATH", peer
->host
,
2006 "AS4 capable peer, yet it sent");
2009 & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
2010 zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
2012 "AS4 capable peer, yet it sent");
2015 return BGP_ATTR_PARSE_PROCEED
;
2018 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
2019 * because that may override AS4_PATH
2021 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
))) {
2022 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
))) {
2024 * if the as_number in aggregator is not AS_TRANS,
2025 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
2026 * and the Aggregator shall be taken as
2027 * info on the aggregating node, and the AS_PATH
2028 * shall be taken as the AS_PATH
2030 * the Aggregator shall be ignored and the
2031 * AS4_AGGREGATOR shall be taken as the
2032 * Aggregating node and the AS_PATH is to be
2033 * constructed "as in all other cases"
2035 if (attr
->aggregator_as
!= BGP_AS_TRANS
) {
2037 if (BGP_DEBUG(as4
, AS4
))
2039 "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
2041 ignore_as4_path
= 1;
2043 /* "New_aggregator shall be taken as aggregator"
2045 attr
->aggregator_as
= as4_aggregator
;
2046 attr
->aggregator_addr
.s_addr
=
2047 as4_aggregator_addr
->s_addr
;
2050 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
2051 * That is bogus - but reading the conditions
2052 * we have to handle AS4_AGGREGATOR as if it were
2053 * AGGREGATOR in that case
2055 if (BGP_DEBUG(as4
, AS4
))
2057 "[AS4] %s BGP not AS4 capable peer send AS4_AGGREGATOR but no AGGREGATOR, will take it as if AGGREGATOR with AS_TRANS had been there",
2059 attr
->aggregator_as
= as4_aggregator
;
2060 /* sweep it under the carpet and simulate a "good"
2062 attr
->flag
|= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
));
2066 /* need to reconcile NEW_AS_PATH and AS_PATH */
2067 if (!ignore_as4_path
2068 && (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))) {
2069 newpath
= aspath_reconcile_as4(attr
->aspath
, as4_path
);
2071 return BGP_ATTR_PARSE_ERROR
;
2073 aspath_unintern(&attr
->aspath
);
2074 attr
->aspath
= aspath_intern(newpath
);
2076 return BGP_ATTR_PARSE_PROCEED
;
2079 /* Community attribute. */
2080 static enum bgp_attr_parse_ret
2081 bgp_attr_community(struct bgp_attr_parser_args
*args
)
2083 struct peer
*const peer
= args
->peer
;
2084 struct attr
*const attr
= args
->attr
;
2085 const bgp_size_t length
= args
->length
;
2088 bgp_attr_set_community(attr
, NULL
);
2089 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2093 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2094 goto community_ignore
;
2096 bgp_attr_set_community(
2098 community_parse((uint32_t *)stream_pnt(peer
->curr
), length
));
2100 /* XXX: fix community_parse to use stream API and remove this */
2101 stream_forward_getp(peer
->curr
, length
);
2103 /* The Community attribute SHALL be considered malformed if its
2104 * length is not a non-zero multiple of 4.
2106 if (!bgp_attr_get_community(attr
))
2107 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2110 return BGP_ATTR_PARSE_PROCEED
;
2113 stream_forward_getp(peer
->curr
, length
);
2115 return bgp_attr_ignore(peer
, args
->type
);
2118 /* Originator ID attribute. */
2119 static enum bgp_attr_parse_ret
2120 bgp_attr_originator_id(struct bgp_attr_parser_args
*args
)
2122 struct peer
*const peer
= args
->peer
;
2123 struct attr
*const attr
= args
->attr
;
2124 const bgp_size_t length
= args
->length
;
2126 /* if received from an internal neighbor, it SHALL be considered
2127 * malformed if its length is not equal to 4. If malformed, the
2128 * UPDATE message SHALL be handled using the approach of "treat-as-
2132 flog_err(EC_BGP_ATTR_LEN
, "Bad originator ID length %d",
2135 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2139 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2140 goto originator_id_ignore
;
2142 attr
->originator_id
.s_addr
= stream_get_ipv4(peer
->curr
);
2144 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
2146 return BGP_ATTR_PARSE_PROCEED
;
2148 originator_id_ignore
:
2149 stream_forward_getp(peer
->curr
, length
);
2151 return bgp_attr_ignore(peer
, args
->type
);
2154 /* Cluster list attribute. */
2155 static enum bgp_attr_parse_ret
2156 bgp_attr_cluster_list(struct bgp_attr_parser_args
*args
)
2158 struct peer
*const peer
= args
->peer
;
2159 struct attr
*const attr
= args
->attr
;
2160 const bgp_size_t length
= args
->length
;
2162 /* if received from an internal neighbor, it SHALL be considered
2163 * malformed if its length is not a non-zero multiple of 4. If
2164 * malformed, the UPDATE message SHALL be handled using the approach
2165 * of "treat-as-withdraw".
2167 if (length
== 0 || length
% 4) {
2168 flog_err(EC_BGP_ATTR_LEN
, "Bad cluster list length %d", length
);
2170 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2174 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2175 goto cluster_list_ignore
;
2177 bgp_attr_set_cluster(
2178 attr
, cluster_parse((struct in_addr
*)stream_pnt(peer
->curr
),
2181 /* XXX: Fix cluster_parse to use stream API and then remove this */
2182 stream_forward_getp(peer
->curr
, length
);
2184 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
);
2186 return BGP_ATTR_PARSE_PROCEED
;
2188 cluster_list_ignore
:
2189 stream_forward_getp(peer
->curr
, length
);
2191 return bgp_attr_ignore(peer
, args
->type
);
2194 /* Multiprotocol reachability information parse. */
2195 int bgp_mp_reach_parse(struct bgp_attr_parser_args
*args
,
2196 struct bgp_nlri
*mp_update
)
2200 iana_safi_t pkt_safi
;
2202 bgp_size_t nlri_len
;
2205 struct peer
*const peer
= args
->peer
;
2206 struct attr
*const attr
= args
->attr
;
2207 const bgp_size_t length
= args
->length
;
2209 /* Set end of packet. */
2210 s
= BGP_INPUT(peer
);
2211 start
= stream_get_getp(s
);
2213 /* safe to read statically sized header? */
2214 #define BGP_MP_REACH_MIN_SIZE 5
2215 #define LEN_LEFT (length - (stream_get_getp(s) - start))
2216 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
)) {
2217 zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
2218 __func__
, peer
->host
, (unsigned long)length
);
2219 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2222 /* Load AFI, SAFI. */
2223 pkt_afi
= stream_getw(s
);
2224 pkt_safi
= stream_getc(s
);
2226 /* Convert AFI, SAFI to internal values, check. */
2227 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2228 /* Log if AFI or SAFI is unrecognized. This is not an error
2230 * the attribute is otherwise malformed.
2232 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2234 "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
2235 peer
->host
, iana_afi2str(pkt_afi
),
2236 iana_safi2str(pkt_safi
));
2237 return BGP_ATTR_PARSE_ERROR
;
2240 /* Get nexthop length. */
2241 attr
->mp_nexthop_len
= stream_getc(s
);
2243 if (LEN_LEFT
< attr
->mp_nexthop_len
) {
2245 "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
2246 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2247 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2250 /* Nexthop length check. */
2251 switch (attr
->mp_nexthop_len
) {
2253 if (safi
!= SAFI_FLOWSPEC
) {
2254 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2255 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2256 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2259 case BGP_ATTR_NHLEN_VPNV4
:
2260 stream_getl(s
); /* RD high */
2261 stream_getl(s
); /* RD low */
2263 * NOTE: intentional fall through
2264 * - for consistency in rx processing
2266 * The following comment is to signal GCC this intention
2267 * and suppress the warning
2270 case BGP_ATTR_NHLEN_IPV4
:
2271 stream_get(&attr
->mp_nexthop_global_in
, s
, IPV4_MAX_BYTELEN
);
2272 /* Probably needed for RFC 2283 */
2273 if (attr
->nexthop
.s_addr
== INADDR_ANY
)
2274 memcpy(&attr
->nexthop
.s_addr
,
2275 &attr
->mp_nexthop_global_in
, IPV4_MAX_BYTELEN
);
2277 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
2278 case BGP_ATTR_NHLEN_VPNV6_GLOBAL
:
2279 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL
) {
2280 stream_getl(s
); /* RD high */
2281 stream_getl(s
); /* RD low */
2283 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2284 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2285 if (!peer
->nexthop
.ifp
) {
2286 zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2288 return BGP_ATTR_PARSE_WITHDRAW
;
2290 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2293 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
2294 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
:
2295 if (attr
->mp_nexthop_len
2296 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2297 stream_getl(s
); /* RD high */
2298 stream_getl(s
); /* RD low */
2300 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2301 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2302 if (!peer
->nexthop
.ifp
) {
2303 zlog_warn("%s sent a v6 global and LL attribute but global address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2305 return BGP_ATTR_PARSE_WITHDRAW
;
2307 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2309 if (attr
->mp_nexthop_len
2310 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2311 stream_getl(s
); /* RD high */
2312 stream_getl(s
); /* RD low */
2314 stream_get(&attr
->mp_nexthop_local
, s
, IPV6_MAX_BYTELEN
);
2315 if (!IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_local
)) {
2316 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2318 "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
2319 peer
->host
, &attr
->mp_nexthop_global
,
2320 &attr
->mp_nexthop_local
);
2322 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
2324 if (!peer
->nexthop
.ifp
) {
2325 zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
2327 return BGP_ATTR_PARSE_WITHDRAW
;
2329 attr
->nh_lla_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2332 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2333 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2334 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2338 zlog_info("%s: %s sent SNPA which couldn't be read",
2339 __func__
, peer
->host
);
2340 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2345 if ((val
= stream_getc(s
)))
2347 EC_BGP_DEFUNCT_SNPA_LEN
,
2348 "%s sent non-zero value, %u, for defunct SNPA-length field",
2352 /* must have nrli_len, what is left of the attribute */
2353 nlri_len
= LEN_LEFT
;
2354 if (nlri_len
> STREAM_READABLE(s
)) {
2355 zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
2356 __func__
, peer
->host
);
2357 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2361 zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
2362 __func__
, peer
->host
);
2364 mp_update
->afi
= afi
;
2365 mp_update
->safi
= safi
;
2366 return BGP_ATTR_PARSE_EOR
;
2369 mp_update
->afi
= afi
;
2370 mp_update
->safi
= safi
;
2371 mp_update
->nlri
= stream_pnt(s
);
2372 mp_update
->length
= nlri_len
;
2374 stream_forward_getp(s
, nlri_len
);
2376 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
);
2378 return BGP_ATTR_PARSE_PROCEED
;
2382 /* Multiprotocol unreachable parse */
2383 int bgp_mp_unreach_parse(struct bgp_attr_parser_args
*args
,
2384 struct bgp_nlri
*mp_withdraw
)
2389 iana_safi_t pkt_safi
;
2391 uint16_t withdraw_len
;
2392 struct peer
*const peer
= args
->peer
;
2393 struct attr
*const attr
= args
->attr
;
2394 const bgp_size_t length
= args
->length
;
2398 #define BGP_MP_UNREACH_MIN_SIZE 3
2399 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
2400 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2402 pkt_afi
= stream_getw(s
);
2403 pkt_safi
= stream_getc(s
);
2405 /* Convert AFI, SAFI to internal values, check. */
2406 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2407 /* Log if AFI or SAFI is unrecognized. This is not an error
2409 * the attribute is otherwise malformed.
2411 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2413 "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
2414 peer
->host
, iana_afi2str(pkt_afi
),
2415 iana_safi2str(pkt_safi
));
2416 return BGP_ATTR_PARSE_ERROR
;
2419 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
2421 mp_withdraw
->afi
= afi
;
2422 mp_withdraw
->safi
= safi
;
2423 mp_withdraw
->nlri
= stream_pnt(s
);
2424 mp_withdraw
->length
= withdraw_len
;
2426 stream_forward_getp(s
, withdraw_len
);
2428 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
);
2430 return BGP_ATTR_PARSE_PROCEED
;
2433 /* Large Community attribute. */
2434 static enum bgp_attr_parse_ret
2435 bgp_attr_large_community(struct bgp_attr_parser_args
*args
)
2437 struct peer
*const peer
= args
->peer
;
2438 struct attr
*const attr
= args
->attr
;
2439 const bgp_size_t length
= args
->length
;
2442 * Large community follows new attribute format.
2445 bgp_attr_set_lcommunity(attr
, NULL
);
2446 /* Empty extcomm doesn't seem to be invalid per se */
2447 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2451 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2452 goto large_community_ignore
;
2454 bgp_attr_set_lcommunity(
2455 attr
, lcommunity_parse(stream_pnt(peer
->curr
), length
));
2456 /* XXX: fix ecommunity_parse to use stream API */
2457 stream_forward_getp(peer
->curr
, length
);
2459 if (!bgp_attr_get_lcommunity(attr
))
2460 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2463 return BGP_ATTR_PARSE_PROCEED
;
2465 large_community_ignore
:
2466 stream_forward_getp(peer
->curr
, length
);
2468 return bgp_attr_ignore(peer
, args
->type
);
2471 /* Extended Community attribute. */
2472 static enum bgp_attr_parse_ret
2473 bgp_attr_ext_communities(struct bgp_attr_parser_args
*args
)
2475 struct peer
*const peer
= args
->peer
;
2476 struct attr
*const attr
= args
->attr
;
2477 const bgp_size_t length
= args
->length
;
2480 struct ecommunity
*ecomm
;
2483 bgp_attr_set_ecommunity(attr
, NULL
);
2484 /* Empty extcomm doesn't seem to be invalid per se */
2485 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2489 ecomm
= ecommunity_parse(
2490 stream_pnt(peer
->curr
), length
,
2491 CHECK_FLAG(peer
->flags
,
2492 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2493 bgp_attr_set_ecommunity(attr
, ecomm
);
2494 /* XXX: fix ecommunity_parse to use stream API */
2495 stream_forward_getp(peer
->curr
, length
);
2497 /* The Extended Community attribute SHALL be considered malformed if
2498 * its length is not a non-zero multiple of 8.
2500 if (!bgp_attr_get_ecommunity(attr
))
2501 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2504 /* Extract DF election preference and mobility sequence number */
2505 attr
->df_pref
= bgp_attr_df_pref_from_ec(attr
, &attr
->df_alg
);
2507 /* Extract MAC mobility sequence number, if any. */
2508 attr
->mm_seqnum
= bgp_attr_mac_mobility_seqnum(attr
, &sticky
);
2509 attr
->sticky
= sticky
;
2511 /* Check if this is a Gateway MAC-IP advertisement */
2512 attr
->default_gw
= bgp_attr_default_gw(attr
);
2514 /* Handle scenario where router flag ecommunity is not
2515 * set but default gw ext community is present.
2516 * Use default gateway, set and propogate R-bit.
2518 if (attr
->default_gw
)
2519 attr
->router_flag
= 1;
2521 /* Check EVPN Neighbor advertisement flags, R-bit */
2522 bgp_attr_evpn_na_flag(attr
, &attr
->router_flag
, &proxy
);
2524 attr
->es_flags
|= ATTR_ES_PROXY_ADVERT
;
2526 /* Extract the Rmac, if any */
2527 if (bgp_attr_rmac(attr
, &attr
->rmac
)) {
2528 if (bgp_debug_update(peer
, NULL
, NULL
, 1)
2529 && bgp_mac_exist(&attr
->rmac
))
2530 zlog_debug("%s: router mac %pEA is self mac", __func__
,
2534 /* Get the tunnel type from encap extended community */
2535 bgp_attr_extcom_tunnel_type(attr
,
2536 (bgp_encap_types
*)&attr
->encap_tunneltype
);
2538 /* Extract link bandwidth, if any. */
2539 (void)ecommunity_linkbw_present(bgp_attr_get_ecommunity(attr
),
2542 return BGP_ATTR_PARSE_PROCEED
;
2545 /* IPv6 Extended Community attribute. */
2546 static enum bgp_attr_parse_ret
2547 bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args
*args
)
2549 struct peer
*const peer
= args
->peer
;
2550 struct attr
*const attr
= args
->attr
;
2551 const bgp_size_t length
= args
->length
;
2552 struct ecommunity
*ipv6_ecomm
= NULL
;
2555 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2556 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2560 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2561 goto ipv6_ext_community_ignore
;
2563 ipv6_ecomm
= ecommunity_parse_ipv6(
2564 stream_pnt(peer
->curr
), length
,
2565 CHECK_FLAG(peer
->flags
,
2566 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2567 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2569 /* XXX: fix ecommunity_parse to use stream API */
2570 stream_forward_getp(peer
->curr
, length
);
2573 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2576 return BGP_ATTR_PARSE_PROCEED
;
2578 ipv6_ext_community_ignore
:
2579 stream_forward_getp(peer
->curr
, length
);
2581 return bgp_attr_ignore(peer
, args
->type
);
2584 /* Parse Tunnel Encap attribute in an UPDATE */
2585 static int bgp_attr_encap(uint8_t type
, struct peer
*peer
, /* IN */
2586 bgp_size_t length
, /* IN: attr's length field */
2587 struct attr
*attr
, /* IN: caller already allocated */
2588 uint8_t flag
, /* IN: attr's flags field */
2592 uint16_t tunneltype
= 0;
2594 total
= length
+ (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
2596 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
)
2597 || !CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
2599 "Tunnel Encap attribute flag isn't optional and transitive %d",
2601 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2602 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
2607 if (BGP_ATTR_ENCAP
== type
) {
2608 /* read outer TLV type and length */
2609 uint16_t tlv_length
;
2613 "Tunnel Encap attribute not long enough to contain outer T,L");
2614 bgp_notify_send_with_data(
2615 peer
, BGP_NOTIFY_UPDATE_ERR
,
2616 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2619 tunneltype
= stream_getw(BGP_INPUT(peer
));
2620 tlv_length
= stream_getw(BGP_INPUT(peer
));
2623 if (tlv_length
!= length
) {
2624 zlog_info("%s: tlv_length(%d) != length(%d)",
2625 __func__
, tlv_length
, length
);
2629 while (length
>= 4) {
2630 uint16_t subtype
= 0;
2631 uint16_t sublength
= 0;
2632 struct bgp_attr_encap_subtlv
*tlv
;
2634 if (BGP_ATTR_ENCAP
== type
) {
2635 subtype
= stream_getc(BGP_INPUT(peer
));
2636 sublength
= stream_getc(BGP_INPUT(peer
));
2638 #ifdef ENABLE_BGP_VNC
2640 subtype
= stream_getw(BGP_INPUT(peer
));
2641 sublength
= stream_getw(BGP_INPUT(peer
));
2646 if (sublength
> length
) {
2648 "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2650 bgp_notify_send_with_data(
2651 peer
, BGP_NOTIFY_UPDATE_ERR
,
2652 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2656 /* alloc and copy sub-tlv */
2657 /* TBD make sure these are freed when attributes are released */
2658 tlv
= XCALLOC(MTYPE_ENCAP_TLV
,
2659 sizeof(struct bgp_attr_encap_subtlv
) + sublength
);
2660 tlv
->type
= subtype
;
2661 tlv
->length
= sublength
;
2662 stream_get(tlv
->value
, peer
->curr
, sublength
);
2663 length
-= sublength
;
2665 /* attach tlv to encap chain */
2666 if (BGP_ATTR_ENCAP
== type
) {
2667 struct bgp_attr_encap_subtlv
*stlv_last
;
2668 for (stlv_last
= attr
->encap_subtlvs
;
2669 stlv_last
&& stlv_last
->next
;
2670 stlv_last
= stlv_last
->next
)
2673 stlv_last
->next
= tlv
;
2675 attr
->encap_subtlvs
= tlv
;
2677 #ifdef ENABLE_BGP_VNC
2679 struct bgp_attr_encap_subtlv
*stlv_last
;
2680 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
2681 bgp_attr_get_vnc_subtlvs(attr
);
2683 for (stlv_last
= vnc_subtlvs
;
2684 stlv_last
&& stlv_last
->next
;
2685 stlv_last
= stlv_last
->next
)
2688 stlv_last
->next
= tlv
;
2690 bgp_attr_set_vnc_subtlvs(attr
, tlv
);
2695 if (BGP_ATTR_ENCAP
== type
) {
2696 attr
->encap_tunneltype
= tunneltype
;
2700 /* spurious leftover data */
2702 "Tunnel Encap attribute length is bad: %d leftover octets",
2704 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2705 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2714 /* SRv6 Service Data Sub-Sub-TLV attribute
2715 * draft-ietf-bess-srv6-services-07
2717 static enum bgp_attr_parse_ret
2718 bgp_attr_srv6_service_data(struct bgp_attr_parser_args
*args
)
2720 struct peer
*const peer
= args
->peer
;
2721 struct attr
*const attr
= args
->attr
;
2722 uint8_t type
, loc_block_len
, loc_node_len
, func_len
, arg_len
,
2723 transposition_len
, transposition_offset
;
2725 size_t headersz
= sizeof(type
) + sizeof(length
);
2727 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2730 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2731 headersz
, STREAM_READABLE(peer
->curr
));
2732 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2736 type
= stream_getc(peer
->curr
);
2737 length
= stream_getw(peer
->curr
);
2739 if (STREAM_READABLE(peer
->curr
) < length
) {
2742 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2743 length
, STREAM_READABLE(peer
->curr
));
2744 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2748 if (length
< BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
) {
2751 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %hu remaining in UPDATE)",
2752 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
,
2754 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2758 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
) {
2759 if (STREAM_READABLE(peer
->curr
) <
2760 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
) {
2763 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %zu remaining in UPDATE)",
2764 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
,
2765 STREAM_READABLE(peer
->curr
));
2766 return bgp_attr_malformed(
2767 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2771 loc_block_len
= stream_getc(peer
->curr
);
2772 loc_node_len
= stream_getc(peer
->curr
);
2773 func_len
= stream_getc(peer
->curr
);
2774 arg_len
= stream_getc(peer
->curr
);
2775 transposition_len
= stream_getc(peer
->curr
);
2776 transposition_offset
= stream_getc(peer
->curr
);
2778 /* Log SRv6 Service Data Sub-Sub-TLV */
2779 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2781 "%s: srv6-l3-srv-data loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u, transposition-len=%u, transposition-offset=%u",
2782 __func__
, loc_block_len
, loc_node_len
, func_len
,
2783 arg_len
, transposition_len
,
2784 transposition_offset
);
2787 attr
->srv6_l3vpn
->loc_block_len
= loc_block_len
;
2788 attr
->srv6_l3vpn
->loc_node_len
= loc_node_len
;
2789 attr
->srv6_l3vpn
->func_len
= func_len
;
2790 attr
->srv6_l3vpn
->arg_len
= arg_len
;
2791 attr
->srv6_l3vpn
->transposition_len
= transposition_len
;
2792 attr
->srv6_l3vpn
->transposition_offset
= transposition_offset
;
2796 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2798 "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
2801 stream_forward_getp(peer
->curr
, length
);
2804 return BGP_ATTR_PARSE_PROCEED
;
2807 /* SRv6 Service Sub-TLV attribute
2808 * draft-ietf-bess-srv6-services-07
2810 static enum bgp_attr_parse_ret
2811 bgp_attr_srv6_service(struct bgp_attr_parser_args
*args
)
2813 struct peer
*const peer
= args
->peer
;
2814 struct attr
*const attr
= args
->attr
;
2815 struct in6_addr ipv6_sid
;
2816 uint8_t type
, sid_flags
;
2817 uint16_t length
, endpoint_behavior
;
2818 size_t headersz
= sizeof(type
) + sizeof(length
);
2819 enum bgp_attr_parse_ret err
;
2821 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2824 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2825 headersz
, STREAM_READABLE(peer
->curr
));
2826 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2830 type
= stream_getc(peer
->curr
);
2831 length
= stream_getw(peer
->curr
);
2833 if (STREAM_READABLE(peer
->curr
) < length
) {
2836 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2837 length
, STREAM_READABLE(peer
->curr
));
2838 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2842 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
) {
2843 if (STREAM_READABLE(peer
->curr
) <
2844 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
) {
2847 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %d for attribute data, have %zu remaining in UPDATE)",
2848 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
,
2849 STREAM_READABLE(peer
->curr
));
2850 return bgp_attr_malformed(
2851 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2854 stream_getc(peer
->curr
);
2855 stream_get(&ipv6_sid
, peer
->curr
, sizeof(ipv6_sid
));
2856 sid_flags
= stream_getc(peer
->curr
);
2857 endpoint_behavior
= stream_getw(peer
->curr
);
2858 stream_getc(peer
->curr
);
2860 /* Log SRv6 Service Sub-TLV */
2861 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
))
2863 "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x",
2864 __func__
, &ipv6_sid
, sid_flags
,
2867 /* Configure from Info */
2868 if (attr
->srv6_l3vpn
) {
2869 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2870 "Prefix SID SRv6 L3VPN field repeated");
2871 return bgp_attr_malformed(
2872 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2874 attr
->srv6_l3vpn
= XCALLOC(MTYPE_BGP_SRV6_L3VPN
,
2875 sizeof(struct bgp_attr_srv6_l3vpn
));
2876 sid_copy(&attr
->srv6_l3vpn
->sid
, &ipv6_sid
);
2877 attr
->srv6_l3vpn
->sid_flags
= sid_flags
;
2878 attr
->srv6_l3vpn
->endpoint_behavior
= endpoint_behavior
;
2879 attr
->srv6_l3vpn
->loc_block_len
= 0;
2880 attr
->srv6_l3vpn
->loc_node_len
= 0;
2881 attr
->srv6_l3vpn
->func_len
= 0;
2882 attr
->srv6_l3vpn
->arg_len
= 0;
2883 attr
->srv6_l3vpn
->transposition_len
= 0;
2884 attr
->srv6_l3vpn
->transposition_offset
= 0;
2886 // Sub-Sub-TLV found
2887 if (length
> BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
) {
2888 err
= bgp_attr_srv6_service_data(args
);
2890 if (err
!= BGP_ATTR_PARSE_PROCEED
)
2894 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
2897 /* Placeholder code for unsupported type */
2899 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2901 "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
2904 stream_forward_getp(peer
->curr
, length
);
2907 return BGP_ATTR_PARSE_PROCEED
;
2911 * Read an individual SID value returning how much data we have read
2912 * Returns 0 if there was an error that needs to be passed up the stack
2914 static enum bgp_attr_parse_ret
2915 bgp_attr_psid_sub(uint8_t type
, uint16_t length
,
2916 struct bgp_attr_parser_args
*args
)
2918 struct peer
*const peer
= args
->peer
;
2919 struct attr
*const attr
= args
->attr
;
2920 uint32_t label_index
;
2921 struct in6_addr ipv6_sid
;
2923 uint32_t srgb_range
;
2925 uint8_t sid_type
, sid_flags
;
2927 if (type
== BGP_PREFIX_SID_LABEL_INDEX
) {
2928 if (STREAM_READABLE(peer
->curr
) < length
2929 || length
!= BGP_PREFIX_SID_LABEL_INDEX_LENGTH
) {
2930 flog_err(EC_BGP_ATTR_LEN
,
2931 "Prefix SID label index length is %hu instead of %u",
2932 length
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
2933 return bgp_attr_malformed(args
,
2934 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2938 /* Ignore flags and reserved */
2939 stream_getc(peer
->curr
);
2940 stream_getw(peer
->curr
);
2942 /* Fetch the label index and see if it is valid. */
2943 label_index
= stream_getl(peer
->curr
);
2944 if (label_index
== BGP_INVALID_LABEL_INDEX
)
2945 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2948 /* Store label index; subsequently, we'll check on
2950 attr
->label_index
= label_index
;
2953 /* Placeholder code for the IPv6 SID type */
2954 else if (type
== BGP_PREFIX_SID_IPV6
) {
2955 if (STREAM_READABLE(peer
->curr
) < length
2956 || length
!= BGP_PREFIX_SID_IPV6_LENGTH
) {
2957 flog_err(EC_BGP_ATTR_LEN
,
2958 "Prefix SID IPv6 length is %hu instead of %u",
2959 length
, BGP_PREFIX_SID_IPV6_LENGTH
);
2960 return bgp_attr_malformed(args
,
2961 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2965 /* Ignore reserved */
2966 stream_getc(peer
->curr
);
2967 stream_getw(peer
->curr
);
2969 stream_get(&ipv6_sid
, peer
->curr
, 16);
2972 /* Placeholder code for the Originator SRGB type */
2973 else if (type
== BGP_PREFIX_SID_ORIGINATOR_SRGB
) {
2975 * ietf-idr-bgp-prefix-sid-05:
2976 * Length is the total length of the value portion of the
2977 * TLV: 2 + multiple of 6.
2979 * peer->curr stream readp should be at the beginning of the 16
2980 * bit flag field at this point in the code.
2984 * Check that the TLV length field is sane: at least 2 bytes of
2985 * flag, and at least 1 SRGB (these are 6 bytes each)
2987 if (length
< (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
)) {
2990 "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
2992 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
2993 return bgp_attr_malformed(
2994 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2999 * Check that we actually have at least as much data as
3000 * specified by the length field
3002 if (STREAM_READABLE(peer
->curr
) < length
) {
3003 flog_err(EC_BGP_ATTR_LEN
,
3004 "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain",
3005 length
, STREAM_READABLE(peer
->curr
));
3006 return bgp_attr_malformed(
3007 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3012 * Check that the portion of the TLV containing the sequence of
3013 * SRGBs corresponds to a multiple of the SRGB size; to get
3014 * that length, we skip the 16 bit flags field
3016 stream_getw(peer
->curr
);
3018 if (length
% BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
) {
3021 "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
3022 length
, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
3023 return bgp_attr_malformed(
3024 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3028 srgb_count
= length
/ BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
;
3030 for (int i
= 0; i
< srgb_count
; i
++) {
3031 stream_get(&srgb_base
, peer
->curr
, 3);
3032 stream_get(&srgb_range
, peer
->curr
, 3);
3036 /* Placeholder code for the VPN-SID Service type */
3037 else if (type
== BGP_PREFIX_SID_VPN_SID
) {
3038 if (STREAM_READABLE(peer
->curr
) < length
3039 || length
!= BGP_PREFIX_SID_VPN_SID_LENGTH
) {
3040 flog_err(EC_BGP_ATTR_LEN
,
3041 "Prefix SID VPN SID length is %hu instead of %u",
3042 length
, BGP_PREFIX_SID_VPN_SID_LENGTH
);
3043 return bgp_attr_malformed(args
,
3044 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3048 /* Parse VPN-SID Sub-TLV */
3049 stream_getc(peer
->curr
); /* reserved */
3050 sid_type
= stream_getc(peer
->curr
); /* sid_type */
3051 sid_flags
= stream_getc(peer
->curr
); /* sid_flags */
3052 stream_get(&ipv6_sid
, peer
->curr
,
3053 sizeof(ipv6_sid
)); /* sid_value */
3055 /* Log VPN-SID Sub-TLV */
3056 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
))
3058 "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x",
3059 __func__
, &ipv6_sid
, sid_type
, sid_flags
);
3061 /* Configure from Info */
3062 if (attr
->srv6_vpn
) {
3063 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
3064 "Prefix SID SRv6 VPN field repeated");
3065 return bgp_attr_malformed(
3066 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
3068 attr
->srv6_vpn
= XCALLOC(MTYPE_BGP_SRV6_VPN
,
3069 sizeof(struct bgp_attr_srv6_vpn
));
3070 attr
->srv6_vpn
->sid_flags
= sid_flags
;
3071 sid_copy(&attr
->srv6_vpn
->sid
, &ipv6_sid
);
3072 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
3075 /* Placeholder code for the SRv6 L3 Service type */
3076 else if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE
) {
3077 if (STREAM_READABLE(peer
->curr
) < length
) {
3080 "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain",
3081 length
, STREAM_READABLE(peer
->curr
));
3082 return bgp_attr_malformed(args
,
3083 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3087 /* ignore reserved */
3088 stream_getc(peer
->curr
);
3090 return bgp_attr_srv6_service(args
);
3093 /* Placeholder code for Unsupported TLV */
3096 if (STREAM_READABLE(peer
->curr
) < length
) {
3099 "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE",
3100 length
, STREAM_READABLE(peer
->curr
));
3101 return bgp_attr_malformed(
3102 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3106 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3108 "%s attr Prefix-SID sub-type=%u is not supported, skipped",
3111 stream_forward_getp(peer
->curr
, length
);
3114 return BGP_ATTR_PARSE_PROCEED
;
3117 /* Prefix SID attribute
3118 * draft-ietf-idr-bgp-prefix-sid-05
3120 enum bgp_attr_parse_ret
bgp_attr_prefix_sid(struct bgp_attr_parser_args
*args
)
3122 struct peer
*const peer
= args
->peer
;
3123 struct attr
*const attr
= args
->attr
;
3124 enum bgp_attr_parse_ret ret
;
3126 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
);
3130 size_t headersz
= sizeof(type
) + sizeof(length
);
3131 size_t psid_parsed_length
= 0;
3133 while (STREAM_READABLE(peer
->curr
) > 0
3134 && psid_parsed_length
< args
->length
) {
3136 if (STREAM_READABLE(peer
->curr
) < headersz
) {
3139 "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
3140 headersz
, STREAM_READABLE(peer
->curr
));
3141 return bgp_attr_malformed(
3142 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3146 type
= stream_getc(peer
->curr
);
3147 length
= stream_getw(peer
->curr
);
3149 if (STREAM_READABLE(peer
->curr
) < length
) {
3152 "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
3153 length
, STREAM_READABLE(peer
->curr
));
3154 return bgp_attr_malformed(args
,
3155 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3159 ret
= bgp_attr_psid_sub(type
, length
, args
);
3161 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3164 psid_parsed_length
+= length
+ headersz
;
3166 if (psid_parsed_length
> args
->length
) {
3169 "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
3170 length
+ headersz
, psid_parsed_length
- (length
+ headersz
));
3171 return bgp_attr_malformed(
3172 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3177 return BGP_ATTR_PARSE_PROCEED
;
3180 /* PMSI tunnel attribute (RFC 6514)
3181 * Basic validation checks done here.
3183 static enum bgp_attr_parse_ret
3184 bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args
*args
)
3186 struct peer
*const peer
= args
->peer
;
3187 struct attr
*const attr
= args
->attr
;
3188 const bgp_size_t length
= args
->length
;
3190 int attr_parse_len
= 2 + BGP_LABEL_BYTES
;
3192 /* Verify that the receiver is expecting "ingress replication" as we
3193 * can only support that.
3195 if (length
< attr_parse_len
) {
3196 flog_err(EC_BGP_ATTR_LEN
, "Bad PMSI tunnel attribute length %d",
3198 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3201 stream_getc(peer
->curr
); /* Flags */
3202 tnl_type
= stream_getc(peer
->curr
);
3203 if (tnl_type
> PMSI_TNLTYPE_MAX
) {
3204 flog_err(EC_BGP_ATTR_PMSI_TYPE
,
3205 "Invalid PMSI tunnel attribute type %d", tnl_type
);
3206 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
3209 if (tnl_type
== PMSI_TNLTYPE_INGR_REPL
) {
3211 flog_err(EC_BGP_ATTR_PMSI_LEN
,
3212 "Bad PMSI tunnel attribute length %d for IR",
3214 return bgp_attr_malformed(
3215 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3220 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
);
3221 bgp_attr_set_pmsi_tnl_type(attr
, tnl_type
);
3222 stream_get(&attr
->label
, peer
->curr
, BGP_LABEL_BYTES
);
3224 /* Forward read pointer of input stream. */
3225 stream_forward_getp(peer
->curr
, length
- attr_parse_len
);
3227 return BGP_ATTR_PARSE_PROCEED
;
3230 /* AIGP attribute (rfc7311) */
3231 static enum bgp_attr_parse_ret
bgp_attr_aigp(struct bgp_attr_parser_args
*args
)
3233 struct peer
*const peer
= args
->peer
;
3234 struct attr
*const attr
= args
->attr
;
3235 const bgp_size_t length
= args
->length
;
3236 uint8_t *s
= stream_pnt(peer
->curr
);
3239 /* If an AIGP attribute is received on a BGP session for which
3240 * AIGP_SESSION is disabled, the attribute MUST be treated exactly
3241 * as if it were an unrecognized non-transitive attribute.
3242 * That is, it "MUST be quietly ignored and not passed along to
3244 * For Internal BGP (IBGP) sessions, and for External BGP (EBGP)
3245 * sessions between members of the same BGP Confederation,
3246 * the default value of AIGP_SESSION SHOULD be "enabled".
3248 if (peer
->sort
== BGP_PEER_EBGP
&&
3249 !CHECK_FLAG(peer
->flags
, PEER_FLAG_AIGP
)) {
3251 "%pBP received AIGP attribute, but eBGP peer do not support it",
3256 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
3259 if (!bgp_attr_aigp_valid(s
, length
))
3262 /* Extract AIGP Metric TLV */
3263 if (bgp_attr_aigp_get_tlv_metric(s
, length
, &aigp
))
3264 bgp_attr_set_aigp_metric(attr
, aigp
);
3267 stream_forward_getp(peer
->curr
, length
);
3269 return bgp_attr_ignore(peer
, args
->type
);
3272 /* OTC attribute. */
3273 static enum bgp_attr_parse_ret
bgp_attr_otc(struct bgp_attr_parser_args
*args
)
3275 struct peer
*const peer
= args
->peer
;
3276 struct attr
*const attr
= args
->attr
;
3277 const bgp_size_t length
= args
->length
;
3281 flog_err(EC_BGP_ATTR_LEN
, "OTC attribute length isn't 4 [%u]",
3283 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3287 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
3290 attr
->otc
= stream_getl(peer
->curr
);
3292 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "OTC attribute value is 0");
3293 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
3297 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_OTC
);
3299 return BGP_ATTR_PARSE_PROCEED
;
3302 stream_forward_getp(peer
->curr
, length
);
3304 return bgp_attr_ignore(peer
, args
->type
);
3307 /* BGP unknown attribute treatment. */
3308 static enum bgp_attr_parse_ret
3309 bgp_attr_unknown(struct bgp_attr_parser_args
*args
)
3311 bgp_size_t total
= args
->total
;
3312 struct transit
*transit
;
3313 struct peer
*const peer
= args
->peer
;
3314 struct attr
*const attr
= args
->attr
;
3315 uint8_t *const startp
= args
->startp
;
3316 const uint8_t type
= args
->type
;
3317 const uint8_t flag
= args
->flags
;
3318 const bgp_size_t length
= args
->length
;
3320 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3322 "%s Unknown attribute is received (type %d, length %d)",
3323 peer
->host
, type
, length
);
3325 /* Forward read pointer of input stream. */
3326 stream_forward_getp(peer
->curr
, length
);
3328 if (peer
->discard_attrs
[type
] || peer
->withdraw_attrs
[type
])
3329 return bgp_attr_ignore(peer
, type
);
3331 /* If any of the mandatory well-known attributes are not recognized,
3332 then the Error Subcode is set to Unrecognized Well-known
3333 Attribute. The Data field contains the unrecognized attribute
3334 (type, length and value). */
3335 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
3336 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_UNREC_ATTR
,
3340 /* Unrecognized non-transitive optional attributes must be quietly
3341 ignored and not passed along to other BGP peers. */
3342 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
))
3343 return BGP_ATTR_PARSE_PROCEED
;
3345 /* If a path with recognized transitive optional attribute is
3346 accepted and passed along to other BGP peers and the Partial bit
3347 in the Attribute Flags octet is set to 1 by some previous AS, it
3348 is not set back to 0 by the current AS. */
3349 SET_FLAG(*startp
, BGP_ATTR_FLAG_PARTIAL
);
3351 /* Store transitive attribute to the end of attr->transit. */
3352 transit
= bgp_attr_get_transit(attr
);
3354 transit
= XCALLOC(MTYPE_TRANSIT
, sizeof(struct transit
));
3356 transit
->val
= XREALLOC(MTYPE_TRANSIT_VAL
, transit
->val
,
3357 transit
->length
+ total
);
3359 memcpy(transit
->val
+ transit
->length
, startp
, total
);
3360 transit
->length
+= total
;
3361 bgp_attr_set_transit(attr
, transit
);
3363 return BGP_ATTR_PARSE_PROCEED
;
3366 /* Well-known attribute check. */
3367 static int bgp_attr_check(struct peer
*peer
, struct attr
*attr
)
3371 /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
3373 if (CHECK_FLAG(peer
->cap
, PEER_CAP_RESTART_RCV
) && !attr
->flag
)
3374 return BGP_ATTR_PARSE_PROCEED
;
3376 /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
3377 to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
3378 are present, it should. Check for any other attribute being present
3381 if ((!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)) &&
3382 CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
))))
3383 return BGP_ATTR_PARSE_PROCEED
;
3385 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
)))
3386 type
= BGP_ATTR_ORIGIN
;
3388 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
3389 type
= BGP_ATTR_AS_PATH
;
3391 /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
3393 * NLRI is empty. We can't easily check NLRI empty here though.
3395 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3396 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)))
3397 type
= BGP_ATTR_NEXT_HOP
;
3399 if (peer
->sort
== BGP_PEER_IBGP
3400 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)))
3401 type
= BGP_ATTR_LOCAL_PREF
;
3403 /* If any of the well-known mandatory attributes are not present
3404 * in an UPDATE message, then "treat-as-withdraw" MUST be used.
3407 flog_warn(EC_BGP_MISSING_ATTRIBUTE
,
3408 "%s Missing well-known attribute %s.", peer
->host
,
3409 lookup_msg(attr_str
, type
, NULL
));
3410 return BGP_ATTR_PARSE_WITHDRAW
;
3412 return BGP_ATTR_PARSE_PROCEED
;
3415 /* Read attribute of update packet. This function is called from
3416 bgp_update_receive() in bgp_packet.c. */
3417 enum bgp_attr_parse_ret
bgp_attr_parse(struct peer
*peer
, struct attr
*attr
,
3419 struct bgp_nlri
*mp_update
,
3420 struct bgp_nlri
*mp_withdraw
)
3422 enum bgp_attr_parse_ret ret
;
3426 uint8_t *startp
, *endp
;
3428 uint8_t seen
[BGP_ATTR_BITMAP_SIZE
];
3429 /* we need the as4_path only until we have synthesized the as_path with
3431 /* same goes for as4_aggregator */
3432 struct aspath
*as4_path
= NULL
;
3433 as_t as4_aggregator
= 0;
3434 struct in_addr as4_aggregator_addr
= {.s_addr
= 0};
3435 struct transit
*transit
;
3437 /* Initialize bitmap. */
3438 memset(seen
, 0, BGP_ATTR_BITMAP_SIZE
);
3440 /* End pointer of BGP attribute. */
3441 endp
= BGP_INPUT_PNT(peer
) + size
;
3443 /* Get attributes to the end of attribute length. */
3444 while (BGP_INPUT_PNT(peer
) < endp
) {
3445 /* Check remaining length check.*/
3446 if (endp
- BGP_INPUT_PNT(peer
) < BGP_ATTR_MIN_LEN
) {
3447 /* XXX warning: long int format, int arg (arg 5) */
3449 EC_BGP_ATTRIBUTE_TOO_SMALL
,
3450 "%s: error BGP attribute length %lu is smaller than min len",
3452 (unsigned long)(endp
3453 - stream_pnt(BGP_INPUT(peer
))));
3455 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3456 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3457 ret
= BGP_ATTR_PARSE_ERROR
;
3461 /* Fetch attribute flag and type. */
3462 startp
= BGP_INPUT_PNT(peer
);
3463 /* "The lower-order four bits of the Attribute Flags octet are
3464 unused. They MUST be zero when sent and MUST be ignored when
3466 flag
= 0xF0 & stream_getc(BGP_INPUT(peer
));
3467 type
= stream_getc(BGP_INPUT(peer
));
3469 /* Check whether Extended-Length applies and is in bounds */
3470 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
)
3471 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1))) {
3473 EC_BGP_EXT_ATTRIBUTE_TOO_SMALL
,
3474 "%s: Extended length set, but just %lu bytes of attr header",
3476 (unsigned long)(endp
3477 - stream_pnt(BGP_INPUT(peer
))));
3479 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3480 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3481 ret
= BGP_ATTR_PARSE_ERROR
;
3485 /* Check extended attribue length bit. */
3486 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
))
3487 length
= stream_getw(BGP_INPUT(peer
));
3489 length
= stream_getc(BGP_INPUT(peer
));
3491 /* If any attribute appears more than once in the UPDATE
3492 message, then the Error Subcode is set to Malformed Attribute
3495 if (CHECK_BITMAP(seen
, type
)) {
3497 EC_BGP_ATTRIBUTE_REPEATED
,
3498 "%s: error BGP attribute type %d appears twice in a message",
3501 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3502 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3503 ret
= BGP_ATTR_PARSE_ERROR
;
3507 /* Set type to bitmap to check duplicate attribute. `type' is
3508 unsigned char so it never overflow bitmap range. */
3510 SET_BITMAP(seen
, type
);
3512 /* Overflow check. */
3513 attr_endp
= BGP_INPUT_PNT(peer
) + length
;
3515 if (attr_endp
> endp
) {
3517 EC_BGP_ATTRIBUTE_TOO_LARGE
,
3518 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
3519 peer
->host
, type
, length
, size
, attr_endp
,
3523 * If any recognized attribute has an Attribute
3524 * Length that conflicts with the expected length
3525 * (based on the attribute type code), then the
3526 * Error Subcode MUST be set to Attribute Length
3527 * Error. The Data field MUST contain the erroneous
3528 * attribute (type, length, and value).
3530 * We do not currently have a good way to determine the
3531 * length of the attribute independent of the length
3532 * received in the message. Instead we send the
3533 * minimum between the amount of data we have and the
3534 * amount specified by the attribute length field.
3536 * Instead of directly passing in the packet buffer and
3537 * offset we use the stream_get* functions to read into
3538 * a stack buffer, since they perform bounds checking
3539 * and we are working with untrusted data.
3541 unsigned char ndata
[peer
->max_packet_size
];
3542 memset(ndata
, 0x00, sizeof(ndata
));
3544 CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 2 : 1;
3545 /* Rewind to end of flag field */
3546 stream_rewind_getp(BGP_INPUT(peer
), (1 + lfl
));
3548 stream_get(&ndata
[0], BGP_INPUT(peer
), 1);
3550 stream_get(&ndata
[1], BGP_INPUT(peer
), lfl
);
3552 size_t atl
= attr_endp
- startp
;
3553 size_t ndl
= MIN(atl
, STREAM_READABLE(BGP_INPUT(peer
)));
3554 stream_get(&ndata
[lfl
+ 1], BGP_INPUT(peer
), ndl
);
3556 bgp_notify_send_with_data(
3557 peer
, BGP_NOTIFY_UPDATE_ERR
,
3558 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
, ndata
,
3561 ret
= BGP_ATTR_PARSE_ERROR
;
3565 struct bgp_attr_parser_args attr_args
= {
3572 .total
= attr_endp
- startp
,
3576 /* If any recognized attribute has Attribute Flags that conflict
3577 with the Attribute Type Code, then the Error Subcode is set
3579 Attribute Flags Error. The Data field contains the erroneous
3580 attribute (type, length and value). */
3581 if (bgp_attr_flag_invalid(&attr_args
)) {
3582 ret
= bgp_attr_malformed(
3583 &attr_args
, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
3585 if (ret
== BGP_ATTR_PARSE_PROCEED
)
3590 /* OK check attribute and store it's value. */
3592 case BGP_ATTR_ORIGIN
:
3593 ret
= bgp_attr_origin(&attr_args
);
3595 case BGP_ATTR_AS_PATH
:
3596 ret
= bgp_attr_aspath(&attr_args
);
3598 case BGP_ATTR_AS4_PATH
:
3599 ret
= bgp_attr_as4_path(&attr_args
, &as4_path
);
3601 case BGP_ATTR_NEXT_HOP
:
3602 ret
= bgp_attr_nexthop(&attr_args
);
3604 case BGP_ATTR_MULTI_EXIT_DISC
:
3605 ret
= bgp_attr_med(&attr_args
);
3607 case BGP_ATTR_LOCAL_PREF
:
3608 ret
= bgp_attr_local_pref(&attr_args
);
3610 case BGP_ATTR_ATOMIC_AGGREGATE
:
3611 ret
= bgp_attr_atomic(&attr_args
);
3613 case BGP_ATTR_AGGREGATOR
:
3614 ret
= bgp_attr_aggregator(&attr_args
);
3616 case BGP_ATTR_AS4_AGGREGATOR
:
3617 ret
= bgp_attr_as4_aggregator(&attr_args
,
3619 &as4_aggregator_addr
);
3621 case BGP_ATTR_COMMUNITIES
:
3622 ret
= bgp_attr_community(&attr_args
);
3624 case BGP_ATTR_LARGE_COMMUNITIES
:
3625 ret
= bgp_attr_large_community(&attr_args
);
3627 case BGP_ATTR_ORIGINATOR_ID
:
3628 ret
= bgp_attr_originator_id(&attr_args
);
3630 case BGP_ATTR_CLUSTER_LIST
:
3631 ret
= bgp_attr_cluster_list(&attr_args
);
3633 case BGP_ATTR_MP_REACH_NLRI
:
3634 ret
= bgp_mp_reach_parse(&attr_args
, mp_update
);
3636 case BGP_ATTR_MP_UNREACH_NLRI
:
3637 ret
= bgp_mp_unreach_parse(&attr_args
, mp_withdraw
);
3639 case BGP_ATTR_EXT_COMMUNITIES
:
3640 ret
= bgp_attr_ext_communities(&attr_args
);
3642 #ifdef ENABLE_BGP_VNC_ATTR
3645 case BGP_ATTR_ENCAP
:
3646 ret
= bgp_attr_encap(type
, peer
, length
, attr
, flag
,
3649 case BGP_ATTR_PREFIX_SID
:
3650 ret
= bgp_attr_prefix_sid(&attr_args
);
3652 case BGP_ATTR_PMSI_TUNNEL
:
3653 ret
= bgp_attr_pmsi_tunnel(&attr_args
);
3655 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
3656 ret
= bgp_attr_ipv6_ext_communities(&attr_args
);
3659 ret
= bgp_attr_otc(&attr_args
);
3662 ret
= bgp_attr_aigp(&attr_args
);
3665 ret
= bgp_attr_unknown(&attr_args
);
3669 if (ret
== BGP_ATTR_PARSE_ERROR_NOTIFYPLS
) {
3670 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3671 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3672 ret
= BGP_ATTR_PARSE_ERROR
;
3676 if (ret
== BGP_ATTR_PARSE_EOR
) {
3680 if (ret
== BGP_ATTR_PARSE_ERROR
) {
3681 flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR
,
3682 "%s: Attribute %s, parse error", peer
->host
,
3683 lookup_msg(attr_str
, type
, NULL
));
3686 if (ret
== BGP_ATTR_PARSE_WITHDRAW
) {
3688 EC_BGP_ATTRIBUTE_PARSE_WITHDRAW
,
3689 "%s: Attribute %s, parse error - treating as withdrawal",
3690 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3694 /* Check the fetched length. */
3695 if (BGP_INPUT_PNT(peer
) != attr_endp
) {
3696 flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR
,
3697 "%s: BGP attribute %s, fetch error",
3698 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3699 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3700 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3701 ret
= BGP_ATTR_PARSE_ERROR
;
3707 * draft-ietf-idr-bgp-prefix-sid-27#section-3:
3708 * About Prefix-SID path attribute,
3709 * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
3710 * may only appear in a BGP Prefix-SID attribute attached to
3711 * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
3712 * It MUST be ignored when received for other BGP AFI/SAFI combinations.
3714 if (!attr
->mp_nexthop_len
|| mp_update
->safi
!= SAFI_LABELED_UNICAST
)
3715 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
3717 /* Check final read pointer is same as end pointer. */
3718 if (BGP_INPUT_PNT(peer
) != endp
) {
3719 flog_warn(EC_BGP_ATTRIBUTES_MISMATCH
,
3720 "%s: BGP attribute %s, length mismatch", peer
->host
,
3721 lookup_msg(attr_str
, type
, NULL
));
3722 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3723 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3725 ret
= BGP_ATTR_PARSE_ERROR
;
3730 * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
3731 * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
3732 * This is implemented below and will result in a NOTIFICATION. If the
3733 * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
3734 * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
3735 * message SHOULD NOT be sent. This is implemented elsewhere.
3737 * RFC4760: An UPDATE message that carries no NLRI, other than the one
3738 * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
3739 * attribute. If such a message contains the NEXT_HOP attribute, the BGP
3740 * speaker that receives the message SHOULD ignore this attribute.
3742 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3743 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
))) {
3744 if (bgp_attr_nexthop_valid(peer
, attr
) < 0) {
3745 ret
= BGP_ATTR_PARSE_ERROR
;
3750 /* Check all mandatory well-known attributes are present */
3751 ret
= bgp_attr_check(peer
, attr
);
3756 * At this place we can see whether we got AS4_PATH and/or
3757 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
3758 * We can not do this before we've read all attributes because
3759 * the as4 handling does not say whether AS4_PATH has to be sent
3760 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
3761 * in relationship to AGGREGATOR.
3762 * So, to be defensive, we are not relying on any order and read
3763 * all attributes first, including these 32bit ones, and now,
3764 * afterwards, we look what and if something is to be done for as4.
3766 * It is possible to not have AS_PATH, e.g. GR EoR and sole
3769 /* actually... this doesn't ever return failure currently, but
3770 * better safe than sorry */
3771 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))
3772 && bgp_attr_munge_as4_attrs(peer
, attr
, as4_path
, as4_aggregator
,
3773 &as4_aggregator_addr
)) {
3774 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3775 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3776 ret
= BGP_ATTR_PARSE_ERROR
;
3781 * Finally do the checks on the aspath we did not do yet
3782 * because we waited for a potentially synthesized aspath.
3784 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))) {
3785 ret
= bgp_attr_aspath_check(peer
, attr
);
3786 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3790 ret
= BGP_ATTR_PARSE_PROCEED
;
3794 * At this stage, we have done all fiddling with as4, and the
3795 * resulting info is in attr->aggregator resp. attr->aspath so
3796 * we can chuck as4_aggregator and as4_path alltogether in order
3800 * unintern - it is in the hash
3801 * The flag that we got this is still there, but that
3802 * does not do any trouble
3804 aspath_unintern(&as4_path
);
3806 transit
= bgp_attr_get_transit(attr
);
3807 if (ret
!= BGP_ATTR_PARSE_ERROR
) {
3808 /* Finally intern unknown attribute. */
3810 bgp_attr_set_transit(attr
, transit_intern(transit
));
3811 if (attr
->encap_subtlvs
)
3812 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
3814 #ifdef ENABLE_BGP_VNC
3815 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3816 bgp_attr_get_vnc_subtlvs(attr
);
3819 bgp_attr_set_vnc_subtlvs(
3821 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
3825 transit_free(transit
);
3826 bgp_attr_set_transit(attr
, NULL
);
3829 bgp_attr_flush_encap(attr
);
3833 transit
= bgp_attr_get_transit(attr
);
3835 assert(transit
->refcnt
> 0);
3836 if (attr
->encap_subtlvs
)
3837 assert(attr
->encap_subtlvs
->refcnt
> 0);
3838 #ifdef ENABLE_BGP_VNC
3839 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3840 bgp_attr_get_vnc_subtlvs(attr
);
3843 assert(vnc_subtlvs
->refcnt
> 0);
3850 * Extract the tunnel type from extended community
3852 void bgp_attr_extcom_tunnel_type(struct attr
*attr
,
3853 bgp_encap_types
*tunnel_type
)
3855 struct ecommunity
*ecom
;
3861 ecom
= bgp_attr_get_ecommunity(attr
);
3862 if (!ecom
|| !ecom
->size
)
3865 for (i
= 0; i
< ecom
->size
; i
++) {
3867 uint8_t type
, sub_type
;
3869 pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
3872 if (!(type
== ECOMMUNITY_ENCODE_OPAQUE
&&
3873 sub_type
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
))
3875 *tunnel_type
= ((pnt
[6] << 8) | pnt
[7]);
3882 size_t bgp_packet_mpattr_start(struct stream
*s
, struct peer
*peer
, afi_t afi
,
3883 safi_t safi
, struct bpacket_attr_vec_arr
*vecarr
,
3887 iana_afi_t pkt_afi
= IANA_AFI_IPV4
;
3888 iana_safi_t pkt_safi
= IANA_SAFI_UNICAST
;
3891 /* Set extended bit always to encode the attribute length as 2 bytes */
3892 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
3893 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
3894 sizep
= stream_get_endp(s
);
3895 stream_putw(s
, 0); /* Marker: Attribute length. */
3898 /* Convert AFI, SAFI to values for packet. */
3899 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
3901 stream_putw(s
, pkt_afi
); /* AFI */
3902 stream_putc(s
, pkt_safi
); /* SAFI */
3906 && (safi
== SAFI_UNICAST
|| safi
== SAFI_LABELED_UNICAST
3907 || safi
== SAFI_MPLS_VPN
|| safi
== SAFI_MULTICAST
))
3908 nh_afi
= peer_cap_enhe(peer
, afi
, safi
) ? AFI_IP6
: AFI_IP
;
3909 else if (safi
== SAFI_FLOWSPEC
)
3912 nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
3915 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
3920 case SAFI_MULTICAST
:
3921 case SAFI_LABELED_UNICAST
:
3923 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3927 stream_putl(s
, 0); /* RD = 0, per RFC */
3929 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3934 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3937 if (attr
->mp_nexthop_len
== 0)
3938 stream_putc(s
, 0); /* no nexthop for flowspec */
3940 stream_putc(s
, attr
->mp_nexthop_len
);
3941 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3946 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
3953 case SAFI_MULTICAST
:
3954 case SAFI_LABELED_UNICAST
:
3956 if (attr
->mp_nexthop_len
3957 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3959 BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
);
3960 stream_put(s
, &attr
->mp_nexthop_global
,
3962 stream_put(s
, &attr
->mp_nexthop_local
,
3965 stream_putc(s
, IPV6_MAX_BYTELEN
);
3966 stream_put(s
, &attr
->mp_nexthop_global
,
3970 case SAFI_MPLS_VPN
: {
3971 if (attr
->mp_nexthop_len
==
3972 BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
3974 stream_putl(s
, 0); /* RD = 0, per RFC */
3976 stream_put(s
, &attr
->mp_nexthop_global
,
3978 stream_putl(s
, 0); /* RD = 0, per RFC */
3980 stream_put(s
, &attr
->mp_nexthop_local
,
3984 stream_putl(s
, 0); /* RD = 0, per RFC */
3986 stream_put(s
, &attr
->mp_nexthop_global
,
3991 stream_putc(s
, IPV6_MAX_BYTELEN
);
3992 stream_put(s
, &attr
->mp_nexthop_global
,
3996 stream_putc(s
, 0); /* no nexthop for flowspec */
4000 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
4005 if (safi
!= SAFI_FLOWSPEC
)
4007 EC_BGP_ATTR_NH_SEND_LEN
,
4008 "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
4009 peer
->host
, afi
, safi
, attr
->mp_nexthop_len
);
4013 assert(!"DEV ESCAPE: AFI_UNSPEC or AFI_MAX should not be used here");
4022 void bgp_packet_mpattr_prefix(struct stream
*s
, afi_t afi
, safi_t safi
,
4023 const struct prefix
*p
,
4024 const struct prefix_rd
*prd
, mpls_label_t
*label
,
4025 uint32_t num_labels
, bool addpath_capable
,
4026 uint32_t addpath_tx_id
, struct attr
*attr
)
4031 assert(!"Dev escape usage of SAFI_UNSPEC or MAX");
4034 if (addpath_capable
)
4035 stream_putl(s
, addpath_tx_id
);
4036 /* Label, RD, Prefix write. */
4037 stream_putc(s
, p
->prefixlen
+ 88);
4038 stream_put(s
, label
, BGP_LABEL_BYTES
);
4039 stream_put(s
, prd
->val
, 8);
4040 stream_put(s
, &p
->u
.prefix
, PSIZE(p
->prefixlen
));
4043 if (afi
== AFI_L2VPN
)
4044 /* EVPN prefix - contents depend on type */
4045 bgp_evpn_encode_prefix(s
, p
, prd
, label
, num_labels
,
4046 attr
, addpath_capable
,
4049 assert(!"Add encoding bits here for other AFI's");
4051 case SAFI_LABELED_UNICAST
:
4052 /* Prefix write with label. */
4053 stream_put_labeled_prefix(s
, p
, label
, addpath_capable
,
4057 stream_putc(s
, p
->u
.prefix_flowspec
.prefixlen
);
4058 stream_put(s
, (const void *)p
->u
.prefix_flowspec
.ptr
,
4059 p
->u
.prefix_flowspec
.prefixlen
);
4063 case SAFI_MULTICAST
:
4064 stream_put_prefix_addpath(s
, p
, addpath_capable
, addpath_tx_id
);
4067 assert(!"Please add proper encoding of SAFI_ENCAP");
4072 size_t bgp_packet_mpattr_prefix_size(afi_t afi
, safi_t safi
,
4073 const struct prefix
*p
)
4075 int size
= PSIZE(p
->prefixlen
);
4080 assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE");
4083 case SAFI_MULTICAST
:
4089 /* This has to be wrong, but I don't know what to put here */
4090 assert(!"Do we try to use this?");
4092 case SAFI_LABELED_UNICAST
:
4093 size
+= BGP_LABEL_BYTES
;
4097 * TODO: Maximum possible for type-2, type-3 and type-5
4099 if (afi
== AFI_L2VPN
)
4102 assert(!"Attempting to figure size for SAFI_EVPN and !AFI_L2VPN and FRR will not have the proper values");
4105 size
= ((struct prefix_fs
*)p
)->prefix
.prefixlen
;
4113 * Encodes the tunnel encapsulation attribute,
4114 * and with ENABLE_BGP_VNC the VNC attribute which uses
4115 * almost the same TLV format
4117 static void bgp_packet_mpattr_tea(struct bgp
*bgp
, struct peer
*peer
,
4118 struct stream
*s
, struct attr
*attr
,
4121 unsigned int attrlenfield
= 0;
4122 unsigned int attrhdrlen
= 0;
4123 struct bgp_attr_encap_subtlv
*subtlvs
;
4124 struct bgp_attr_encap_subtlv
*st
;
4125 const char *attrname
;
4127 if (!attr
|| (attrtype
== BGP_ATTR_ENCAP
4128 && (!attr
->encap_tunneltype
4129 || attr
->encap_tunneltype
== BGP_ENCAP_TYPE_MPLS
)))
4133 case BGP_ATTR_ENCAP
:
4134 attrname
= "Tunnel Encap";
4135 subtlvs
= attr
->encap_subtlvs
;
4136 if (subtlvs
== NULL
) /* nothing to do */
4139 * The tunnel encap attr has an "outer" tlv.
4141 * L = total length of subtlvs,
4142 * V = concatenated subtlvs.
4144 attrlenfield
= 2 + 2; /* T + L */
4145 attrhdrlen
= 1 + 1; /* subTLV T + L */
4148 #ifdef ENABLE_BGP_VNC_ATTR
4151 subtlvs
= bgp_attr_get_vnc_subtlvs(attr
);
4152 if (subtlvs
== NULL
) /* nothing to do */
4154 attrlenfield
= 0; /* no outer T + L */
4155 attrhdrlen
= 2 + 2; /* subTLV T + L */
4163 /* compute attr length */
4164 for (st
= subtlvs
; st
; st
= st
->next
) {
4165 attrlenfield
+= (attrhdrlen
+ st
->length
);
4168 if (attrlenfield
> 0xffff) {
4169 zlog_info("%s attribute is too long (length=%d), can't send it",
4170 attrname
, attrlenfield
);
4174 if (attrlenfield
> 0xff) {
4175 /* 2-octet length field */
4177 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4178 | BGP_ATTR_FLAG_EXTLEN
);
4179 stream_putc(s
, attrtype
);
4180 stream_putw(s
, attrlenfield
& 0xffff);
4182 /* 1-octet length field */
4183 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
);
4184 stream_putc(s
, attrtype
);
4185 stream_putc(s
, attrlenfield
& 0xff);
4188 if (attrtype
== BGP_ATTR_ENCAP
) {
4189 /* write outer T+L */
4190 stream_putw(s
, attr
->encap_tunneltype
);
4191 stream_putw(s
, attrlenfield
- 4);
4194 /* write each sub-tlv */
4195 for (st
= subtlvs
; st
; st
= st
->next
) {
4196 if (attrtype
== BGP_ATTR_ENCAP
) {
4197 stream_putc(s
, st
->type
);
4198 stream_putc(s
, st
->length
);
4199 #ifdef ENABLE_BGP_VNC
4201 stream_putw(s
, st
->type
);
4202 stream_putw(s
, st
->length
);
4205 stream_put(s
, st
->value
, st
->length
);
4209 void bgp_packet_mpattr_end(struct stream
*s
, size_t sizep
)
4211 /* Set MP attribute length. Don't count the (2) bytes used to encode
4213 stream_putw_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 2);
4216 static bool bgp_append_local_as(struct peer
*peer
, afi_t afi
, safi_t safi
)
4218 if (!BGP_AS_IS_PRIVATE(peer
->local_as
)
4219 || (BGP_AS_IS_PRIVATE(peer
->local_as
)
4220 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4221 PEER_FLAG_REMOVE_PRIVATE_AS
)
4222 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4223 PEER_FLAG_REMOVE_PRIVATE_AS_ALL
)
4224 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4225 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE
)
4226 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4227 PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE
)))
4232 /* Make attribute packet. */
4233 bgp_size_t
bgp_packet_attribute(struct bgp
*bgp
, struct peer
*peer
,
4234 struct stream
*s
, struct attr
*attr
,
4235 struct bpacket_attr_vec_arr
*vecarr
,
4236 struct prefix
*p
, afi_t afi
, safi_t safi
,
4237 struct peer
*from
, struct prefix_rd
*prd
,
4238 mpls_label_t
*label
, uint32_t num_labels
,
4239 bool addpath_capable
, uint32_t addpath_tx_id
,
4240 struct bgp_path_info
*bpi
)
4243 size_t aspath_sizep
;
4244 struct aspath
*aspath
;
4245 int send_as4_path
= 0;
4246 int send_as4_aggregator
= 0;
4247 bool use32bit
= CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
4248 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
);
4253 /* Remember current pointer. */
4254 cp
= stream_get_endp(s
);
4257 && !((afi
== AFI_IP
&& safi
== SAFI_UNICAST
)
4258 && !peer_cap_enhe(peer
, afi
, safi
))) {
4259 size_t mpattrlen_pos
= 0;
4261 mpattrlen_pos
= bgp_packet_mpattr_start(s
, peer
, afi
, safi
,
4263 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
,
4264 num_labels
, addpath_capable
,
4265 addpath_tx_id
, attr
);
4266 bgp_packet_mpattr_end(s
, mpattrlen_pos
);
4269 /* Origin attribute. */
4270 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4271 stream_putc(s
, BGP_ATTR_ORIGIN
);
4273 stream_putc(s
, attr
->origin
);
4275 /* AS path attribute. */
4277 /* If remote-peer is EBGP */
4278 if (peer
->sort
== BGP_PEER_EBGP
4279 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4280 PEER_FLAG_AS_PATH_UNCHANGED
)
4281 || attr
->aspath
->segments
== NULL
)
4282 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4283 PEER_FLAG_RSERVER_CLIENT
))) {
4284 aspath
= aspath_dup(attr
->aspath
);
4286 /* Even though we may not be configured for confederations we
4288 * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
4289 aspath
= aspath_delete_confed_seq(aspath
);
4291 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
)) {
4292 /* Stuff our path CONFED_ID on the front */
4293 aspath
= aspath_add_seq(aspath
, bgp
->confed_id
);
4295 if (peer
->change_local_as
) {
4296 /* If replace-as is specified, we only use the
4297 change_local_as when
4298 advertising routes. */
4299 if (!CHECK_FLAG(peer
->flags
,
4300 PEER_FLAG_LOCAL_AS_REPLACE_AS
))
4301 if (bgp_append_local_as(peer
, afi
,
4303 aspath
= aspath_add_seq(
4304 aspath
, peer
->local_as
);
4305 aspath
= aspath_add_seq(aspath
,
4306 peer
->change_local_as
);
4308 aspath
= aspath_add_seq(aspath
, peer
->local_as
);
4311 } else if (peer
->sort
== BGP_PEER_CONFED
) {
4312 /* A confed member, so we need to do the AS_CONFED_SEQUENCE
4314 aspath
= aspath_dup(attr
->aspath
);
4315 aspath
= aspath_add_confed_seq(aspath
, peer
->local_as
);
4317 aspath
= attr
->aspath
;
4319 /* If peer is not AS4 capable, then:
4320 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
4321 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
4323 * types are in it (i.e. exclude them if they are there)
4324 * AND do this only if there is at least one asnum > 65535 in the
4326 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
4328 * all ASnums > 65535 to BGP_AS_TRANS
4331 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4332 stream_putc(s
, BGP_ATTR_AS_PATH
);
4333 aspath_sizep
= stream_get_endp(s
);
4335 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, use32bit
));
4337 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
4340 if (!use32bit
&& aspath_has_as4(aspath
))
4342 1; /* we'll do this later, at the correct place */
4344 /* Nexthop attribute. */
4345 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
4346 && !peer_cap_enhe(peer
, afi
, safi
)) {
4347 afi_t nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
4349 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
)) {
4350 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4351 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4352 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4355 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4356 } else if (peer_cap_enhe(from
, afi
, safi
)
4357 || (nh_afi
== AFI_IP6
)) {
4359 * Likely this is the case when an IPv4 prefix was
4360 * received with Extended Next-hop capability in this
4361 * or another vrf and is now being advertised to
4362 * non-ENHE peers. Since peer_cap_enhe only checks
4363 * peers in this vrf, also check the nh_afi to catch
4364 * the case where the originator was in another vrf.
4365 * Setting the mandatory (ipv4) next-hop attribute here
4366 * to enable implicit next-hop self with correct A-F
4367 * (ipv4 address family).
4369 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4370 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4371 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4374 stream_put_ipv4(s
, 0);
4378 /* MED attribute. */
4379 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)
4380 || bgp
->maxmed_active
) {
4381 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4382 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4384 stream_putl(s
, (bgp
->maxmed_active
? bgp
->maxmed_value
4388 /* Local preference. */
4389 if (peer
->sort
== BGP_PEER_IBGP
|| peer
->sort
== BGP_PEER_CONFED
) {
4390 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4391 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4393 stream_putl(s
, attr
->local_pref
);
4396 /* Atomic aggregate. */
4397 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4398 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4399 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4404 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4405 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
4406 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4407 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4410 /* AS4 capable peer */
4412 stream_putl(s
, attr
->aggregator_as
);
4414 /* 2-byte AS peer */
4417 /* Is ASN representable in 2-bytes? Or must AS_TRANS be
4419 if (attr
->aggregator_as
> UINT16_MAX
) {
4420 stream_putw(s
, BGP_AS_TRANS
);
4422 /* we have to send AS4_AGGREGATOR, too.
4423 * we'll do that later in order to send
4424 * attributes in ascending
4427 send_as4_aggregator
= 1;
4429 stream_putw(s
, (uint16_t)attr
->aggregator_as
);
4431 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4434 /* Community attribute. */
4435 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
4436 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
))) {
4437 struct community
*comm
= NULL
;
4439 comm
= bgp_attr_get_community(attr
);
4440 if (comm
->size
* 4 > 255) {
4442 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4443 | BGP_ATTR_FLAG_EXTLEN
);
4444 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4445 stream_putw(s
, comm
->size
* 4);
4448 BGP_ATTR_FLAG_OPTIONAL
4449 | BGP_ATTR_FLAG_TRANS
);
4450 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4451 stream_putc(s
, comm
->size
* 4);
4453 stream_put(s
, comm
->val
, comm
->size
* 4);
4457 * Large Community attribute.
4459 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4460 PEER_FLAG_SEND_LARGE_COMMUNITY
)
4461 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
))) {
4462 if (lcom_length(bgp_attr_get_lcommunity(attr
)) > 255) {
4464 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4465 | BGP_ATTR_FLAG_EXTLEN
);
4466 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4468 lcom_length(bgp_attr_get_lcommunity(attr
)));
4471 BGP_ATTR_FLAG_OPTIONAL
4472 | BGP_ATTR_FLAG_TRANS
);
4473 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4475 lcom_length(bgp_attr_get_lcommunity(attr
)));
4477 stream_put(s
, bgp_attr_get_lcommunity(attr
)->val
,
4478 lcom_length(bgp_attr_get_lcommunity(attr
)));
4481 /* Route Reflector. */
4482 if (peer
->sort
== BGP_PEER_IBGP
&& from
4483 && from
->sort
== BGP_PEER_IBGP
) {
4484 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
4486 /* Originator ID. */
4487 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4488 stream_putc(s
, BGP_ATTR_ORIGINATOR_ID
);
4491 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
4492 stream_put_in_addr(s
, &attr
->originator_id
);
4494 stream_put_in_addr(s
, &from
->remote_id
);
4497 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4498 stream_putc(s
, BGP_ATTR_CLUSTER_LIST
);
4501 stream_putc(s
, cluster
->length
+ 4);
4502 /* If this peer configuration's parent BGP has
4504 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4505 stream_put_in_addr(s
, &bgp
->cluster_id
);
4507 stream_put_in_addr(s
, &bgp
->router_id
);
4508 stream_put(s
, cluster
->list
, cluster
->length
);
4511 /* If this peer configuration's parent BGP has
4513 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4514 stream_put_in_addr(s
, &bgp
->cluster_id
);
4516 stream_put_in_addr(s
, &bgp
->router_id
);
4520 /* Extended Communities attribute. */
4521 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
4522 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
))) {
4523 struct ecommunity
*ecomm
= bgp_attr_get_ecommunity(attr
);
4524 bool transparent
= CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4525 PEER_FLAG_RSERVER_CLIENT
) &&
4527 CHECK_FLAG(from
->af_flags
[afi
][safi
],
4528 PEER_FLAG_RSERVER_CLIENT
);
4530 if (peer
->sort
== BGP_PEER_IBGP
||
4531 peer
->sort
== BGP_PEER_CONFED
|| transparent
) {
4532 if (ecomm
->size
* 8 > 255) {
4534 BGP_ATTR_FLAG_OPTIONAL
4535 | BGP_ATTR_FLAG_TRANS
4536 | BGP_ATTR_FLAG_EXTLEN
);
4537 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4538 stream_putw(s
, ecomm
->size
* 8);
4541 BGP_ATTR_FLAG_OPTIONAL
4542 | BGP_ATTR_FLAG_TRANS
);
4543 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4544 stream_putc(s
, ecomm
->size
* 8);
4546 stream_put(s
, ecomm
->val
, ecomm
->size
* 8);
4550 int ecom_tr_size
= 0;
4553 for (i
= 0; i
< ecomm
->size
; i
++) {
4554 pnt
= ecomm
->val
+ (i
* 8);
4557 if (CHECK_FLAG(tbit
,
4558 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4565 if (ecom_tr_size
* 8 > 255) {
4568 BGP_ATTR_FLAG_OPTIONAL
4569 | BGP_ATTR_FLAG_TRANS
4570 | BGP_ATTR_FLAG_EXTLEN
);
4572 BGP_ATTR_EXT_COMMUNITIES
);
4573 stream_putw(s
, ecom_tr_size
* 8);
4577 BGP_ATTR_FLAG_OPTIONAL
4578 | BGP_ATTR_FLAG_TRANS
);
4580 BGP_ATTR_EXT_COMMUNITIES
);
4581 stream_putc(s
, ecom_tr_size
* 8);
4584 for (i
= 0; i
< ecomm
->size
; i
++) {
4585 pnt
= ecomm
->val
+ (i
* 8);
4590 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4593 stream_put(s
, pnt
, 8);
4599 /* Label index attribute. */
4600 if (safi
== SAFI_LABELED_UNICAST
) {
4601 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4602 uint32_t label_index
;
4604 label_index
= attr
->label_index
;
4606 if (label_index
!= BGP_INVALID_LABEL_INDEX
) {
4608 BGP_ATTR_FLAG_OPTIONAL
4609 | BGP_ATTR_FLAG_TRANS
);
4610 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4612 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4614 BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4615 stream_putc(s
, 0); // reserved
4616 stream_putw(s
, 0); // flags
4617 stream_putl(s
, label_index
);
4622 /* SRv6 Service Information Attribute. */
4623 if ((afi
== AFI_IP
|| afi
== AFI_IP6
) && safi
== SAFI_MPLS_VPN
) {
4624 if (attr
->srv6_l3vpn
) {
4625 uint8_t subtlv_len
=
4626 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
4628 + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
;
4629 uint8_t tlv_len
= subtlv_len
+ BGP_ATTR_MIN_LEN
+ 1;
4630 uint8_t attr_len
= tlv_len
+ BGP_ATTR_MIN_LEN
;
4631 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4632 | BGP_ATTR_FLAG_TRANS
);
4633 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4634 stream_putc(s
, attr_len
);
4635 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE
);
4636 stream_putw(s
, tlv_len
);
4637 stream_putc(s
, 0); /* reserved */
4638 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
);
4639 stream_putw(s
, subtlv_len
);
4640 stream_putc(s
, 0); /* reserved */
4641 stream_put(s
, &attr
->srv6_l3vpn
->sid
,
4642 sizeof(attr
->srv6_l3vpn
->sid
)); /* sid */
4643 stream_putc(s
, 0); /* sid_flags */
4646 ->endpoint_behavior
); /* endpoint */
4647 stream_putc(s
, 0); /* reserved */
4650 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
);
4653 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
);
4654 stream_putc(s
, attr
->srv6_l3vpn
->loc_block_len
);
4655 stream_putc(s
, attr
->srv6_l3vpn
->loc_node_len
);
4656 stream_putc(s
, attr
->srv6_l3vpn
->func_len
);
4657 stream_putc(s
, attr
->srv6_l3vpn
->arg_len
);
4658 stream_putc(s
, attr
->srv6_l3vpn
->transposition_len
);
4659 stream_putc(s
, attr
->srv6_l3vpn
->transposition_offset
);
4660 } else if (attr
->srv6_vpn
) {
4661 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4662 | BGP_ATTR_FLAG_TRANS
);
4663 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4664 stream_putc(s
, 22); /* tlv len */
4665 stream_putc(s
, BGP_PREFIX_SID_VPN_SID
);
4666 stream_putw(s
, 0x13); /* tlv len */
4667 stream_putc(s
, 0x00); /* reserved */
4668 stream_putc(s
, 0x01); /* sid_type */
4669 stream_putc(s
, 0x00); /* sif_flags */
4670 stream_put(s
, &attr
->srv6_vpn
->sid
,
4671 sizeof(attr
->srv6_vpn
->sid
)); /* sid */
4675 if (send_as4_path
) {
4676 /* If the peer is NOT As4 capable, AND */
4677 /* there are ASnums > 65535 in path THEN
4678 * give out AS4_PATH */
4680 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
4682 * Hm, I wonder... confederation things *should* only be at
4683 * the beginning of an aspath, right? Then we should use
4684 * aspath_delete_confed_seq for this, because it is already
4686 * Folks, talk to me: what is reasonable here!?
4688 aspath
= aspath_delete_confed_seq(aspath
);
4691 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4692 | BGP_ATTR_FLAG_EXTLEN
);
4693 stream_putc(s
, BGP_ATTR_AS4_PATH
);
4694 aspath_sizep
= stream_get_endp(s
);
4696 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, 1));
4699 if (aspath
!= attr
->aspath
)
4700 aspath_free(aspath
);
4702 if (send_as4_aggregator
) {
4703 /* send AS4_AGGREGATOR, at this place */
4704 /* this section of code moved here in order to ensure the
4706 * *ascending* order of attributes
4708 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4709 stream_putc(s
, BGP_ATTR_AS4_AGGREGATOR
);
4711 stream_putl(s
, attr
->aggregator_as
);
4712 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4715 if (((afi
== AFI_IP
|| afi
== AFI_IP6
)
4716 && (safi
== SAFI_ENCAP
|| safi
== SAFI_MPLS_VPN
))
4717 || (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)) {
4718 /* Tunnel Encap attribute */
4719 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_ENCAP
);
4721 #ifdef ENABLE_BGP_VNC_ATTR
4723 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_VNC
);
4728 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
)) {
4729 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4730 stream_putc(s
, BGP_ATTR_PMSI_TUNNEL
);
4731 stream_putc(s
, 9); // Length
4732 stream_putc(s
, 0); // Flags
4733 stream_putc(s
, bgp_attr_get_pmsi_tnl_type(attr
));
4734 stream_put(s
, &(attr
->label
),
4735 BGP_LABEL_BYTES
); // MPLS Label / VXLAN VNI
4736 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4737 // Unicast tunnel endpoint IP address
4741 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_OTC
)) {
4742 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4743 stream_putc(s
, BGP_ATTR_OTC
);
4745 stream_putl(s
, attr
->otc
);
4749 if (bpi
&& attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AIGP
) &&
4750 (CHECK_FLAG(peer
->flags
, PEER_FLAG_AIGP
) ||
4751 peer
->sort
!= BGP_PEER_EBGP
)) {
4752 /* At the moment only AIGP Metric TLV exists for AIGP
4753 * attribute. If more comes in, do not forget to update
4754 * attr_len variable to include new ones.
4756 uint8_t attr_len
= BGP_AIGP_TLV_METRIC_LEN
;
4758 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4759 stream_putc(s
, BGP_ATTR_AIGP
);
4760 stream_putc(s
, attr_len
);
4761 stream_put_bgp_aigp_tlv_metric(s
, bpi
);
4764 /* Unknown transit attribute. */
4765 struct transit
*transit
= bgp_attr_get_transit(attr
);
4768 stream_put(s
, transit
->val
, transit
->length
);
4770 /* Return total size of attribute. */
4771 return stream_get_endp(s
) - cp
;
4774 size_t bgp_packet_mpunreach_start(struct stream
*s
, afi_t afi
, safi_t safi
)
4776 unsigned long attrlen_pnt
;
4777 iana_afi_t pkt_afi
= IANA_AFI_IPV4
;
4778 iana_safi_t pkt_safi
= IANA_SAFI_UNICAST
;
4780 /* Set extended bit always to encode the attribute length as 2 bytes */
4781 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
4782 stream_putc(s
, BGP_ATTR_MP_UNREACH_NLRI
);
4784 attrlen_pnt
= stream_get_endp(s
);
4785 stream_putw(s
, 0); /* Length of this attribute. */
4787 /* Convert AFI, SAFI to values for packet. */
4788 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
4790 stream_putw(s
, pkt_afi
);
4791 stream_putc(s
, pkt_safi
);
4796 void bgp_packet_mpunreach_prefix(struct stream
*s
, const struct prefix
*p
,
4797 afi_t afi
, safi_t safi
,
4798 const struct prefix_rd
*prd
,
4799 mpls_label_t
*label
, uint32_t num_labels
,
4800 bool addpath_capable
, uint32_t addpath_tx_id
,
4803 uint8_t wlabel
[4] = {0x80, 0x00, 0x00};
4805 if (safi
== SAFI_LABELED_UNICAST
) {
4806 label
= (mpls_label_t
*)wlabel
;
4810 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
, num_labels
,
4811 addpath_capable
, addpath_tx_id
, attr
);
4814 void bgp_packet_mpunreach_end(struct stream
*s
, size_t attrlen_pnt
)
4816 bgp_packet_mpattr_end(s
, attrlen_pnt
);
4819 /* Initialization of attribute. */
4820 void bgp_attr_init(void)
4833 void bgp_attr_finish(void)
4838 ecommunity_finish();
4839 lcommunity_finish();
4846 /* Make attribute packet. */
4847 void bgp_dump_routes_attr(struct stream
*s
, struct bgp_path_info
*bpi
,
4848 const struct prefix
*prefix
)
4853 struct aspath
*aspath
;
4854 bool addpath_capable
= false;
4855 uint32_t addpath_tx_id
= 0;
4856 struct attr
*attr
= bpi
->attr
;
4858 /* Remember current pointer. */
4859 cp
= stream_get_endp(s
);
4861 /* Place holder of length. */
4864 /* Origin attribute. */
4865 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4866 stream_putc(s
, BGP_ATTR_ORIGIN
);
4868 stream_putc(s
, attr
->origin
);
4870 aspath
= attr
->aspath
;
4872 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4873 stream_putc(s
, BGP_ATTR_AS_PATH
);
4874 aspath_lenp
= stream_get_endp(s
);
4877 stream_putw_at(s
, aspath_lenp
, aspath_put(s
, aspath
, 1));
4879 /* Nexthop attribute. */
4880 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
4881 if (prefix
!= NULL
&& prefix
->family
!= AF_INET6
) {
4882 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4883 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4885 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4888 /* MED attribute. */
4889 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)) {
4890 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4891 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4893 stream_putl(s
, attr
->med
);
4896 /* Local preference. */
4897 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)) {
4898 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4899 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4901 stream_putl(s
, attr
->local_pref
);
4904 /* Atomic aggregate. */
4905 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4906 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4907 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4912 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4913 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4914 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4916 stream_putl(s
, attr
->aggregator_as
);
4917 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4920 /* Community attribute. */
4921 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
)) {
4922 struct community
*comm
= NULL
;
4924 comm
= bgp_attr_get_community(attr
);
4925 if (comm
->size
* 4 > 255) {
4927 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4928 | BGP_ATTR_FLAG_EXTLEN
);
4929 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4930 stream_putw(s
, comm
->size
* 4);
4933 BGP_ATTR_FLAG_OPTIONAL
4934 | BGP_ATTR_FLAG_TRANS
);
4935 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4936 stream_putc(s
, comm
->size
* 4);
4938 stream_put(s
, comm
->val
, comm
->size
* 4);
4941 /* Large Community attribute. */
4942 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
)) {
4943 if (lcom_length(bgp_attr_get_lcommunity(attr
)) > 255) {
4945 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4946 | BGP_ATTR_FLAG_EXTLEN
);
4947 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4949 lcom_length(bgp_attr_get_lcommunity(attr
)));
4952 BGP_ATTR_FLAG_OPTIONAL
4953 | BGP_ATTR_FLAG_TRANS
);
4954 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4956 lcom_length(bgp_attr_get_lcommunity(attr
)));
4959 stream_put(s
, bgp_attr_get_lcommunity(attr
)->val
,
4960 lcom_length(bgp_attr_get_lcommunity(attr
)));
4963 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
4964 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
4965 && (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL
4966 || attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)) {
4969 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4970 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
4971 sizep
= stream_get_endp(s
);
4974 stream_putc(s
, 0); /* Marker: Attribute length. */
4975 stream_putw(s
, AFI_IP6
); /* AFI */
4976 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
4979 stream_putc(s
, attr
->mp_nexthop_len
);
4980 stream_put(s
, &attr
->mp_nexthop_global
, IPV6_MAX_BYTELEN
);
4981 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)
4982 stream_put(s
, &attr
->mp_nexthop_local
,
4989 stream_put_prefix_addpath(s
, prefix
, addpath_capable
,
4992 /* Set MP attribute length. */
4993 stream_putc_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 1);
4997 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4998 if (attr
->label_index
!= BGP_INVALID_LABEL_INDEX
) {
5000 BGP_ATTR_FLAG_OPTIONAL
5001 | BGP_ATTR_FLAG_TRANS
);
5002 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
5004 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
5005 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
5006 stream_putc(s
, 0); // reserved
5007 stream_putw(s
, 0); // flags
5008 stream_putl(s
, attr
->label_index
);
5013 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_OTC
)) {
5014 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
5015 stream_putc(s
, BGP_ATTR_OTC
);
5017 stream_putl(s
, attr
->otc
);
5021 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AIGP
)) {
5022 /* At the moment only AIGP Metric TLV exists for AIGP
5023 * attribute. If more comes in, do not forget to update
5024 * attr_len variable to include new ones.
5026 uint8_t attr_len
= BGP_AIGP_TLV_METRIC_LEN
;
5028 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
5029 stream_putc(s
, BGP_ATTR_AIGP
);
5030 stream_putc(s
, attr_len
);
5031 stream_put_bgp_aigp_tlv_metric(s
, bpi
);
5034 /* Return total size of attribute. */
5035 len
= stream_get_endp(s
) - cp
- 2;
5036 stream_putw_at(s
, cp
, len
);
5039 void bgp_path_attribute_discard_vty(struct vty
*vty
, struct peer
*peer
,
5040 const char *discard_attrs
, bool set
)
5042 int i
, num_attributes
;
5048 /* If `no` command specified without arbitrary attributes,
5051 if (!discard_attrs
) {
5052 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5053 peer
->discard_attrs
[i
] = false;
5054 goto discard_soft_clear
;
5057 if (discard_attrs
) {
5058 frrstr_split(discard_attrs
, " ", &attributes
, &num_attributes
);
5061 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5062 peer
->discard_attrs
[i
] = false;
5064 for (i
= 0; i
< num_attributes
; i
++) {
5065 uint8_t attr_num
= strtoul(attributes
[i
], NULL
, 10);
5067 XFREE(MTYPE_TMP
, attributes
[i
]);
5069 /* Some of the attributes, just can't be ignored. */
5070 if (attr_num
== BGP_ATTR_ORIGIN
||
5071 attr_num
== BGP_ATTR_AS_PATH
||
5072 attr_num
== BGP_ATTR_NEXT_HOP
||
5073 attr_num
== BGP_ATTR_MULTI_EXIT_DISC
||
5074 attr_num
== BGP_ATTR_MP_REACH_NLRI
||
5075 attr_num
== BGP_ATTR_MP_UNREACH_NLRI
||
5076 attr_num
== BGP_ATTR_EXT_COMMUNITIES
) {
5078 "%% Can't discard path-attribute %s, ignoring.\n",
5079 lookup_msg(attr_str
, attr_num
, NULL
));
5083 /* Ignore local-pref, originator-id, cluster-list only
5086 if (peer
->sort
!= BGP_PEER_EBGP
&&
5087 (attr_num
== BGP_ATTR_LOCAL_PREF
||
5088 attr_num
== BGP_ATTR_ORIGINATOR_ID
||
5089 attr_num
== BGP_ATTR_CLUSTER_LIST
)) {
5091 "%% Can discard path-attribute %s only for eBGP, ignoring.\n",
5092 lookup_msg(attr_str
, attr_num
, NULL
));
5096 peer
->discard_attrs
[attr_num
] = set
;
5098 XFREE(MTYPE_TMP
, attributes
);
5100 /* Configuring path attributes to be discarded will trigger
5101 * an inbound Route Refresh to ensure that the routing table
5104 FOREACH_AFI_SAFI (afi
, safi
)
5105 peer_clear_soft(peer
, afi
, safi
, BGP_CLEAR_SOFT_IN
);
5109 void bgp_path_attribute_withdraw_vty(struct vty
*vty
, struct peer
*peer
,
5110 const char *withdraw_attrs
, bool set
)
5112 int i
, num_attributes
;
5117 /* If `no` command specified without arbitrary attributes,
5120 if (!withdraw_attrs
) {
5121 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5122 peer
->withdraw_attrs
[i
] = false;
5123 goto withdraw_soft_clear
;
5126 if (withdraw_attrs
) {
5127 frrstr_split(withdraw_attrs
, " ", &attributes
, &num_attributes
);
5130 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5131 peer
->withdraw_attrs
[i
] = false;
5133 for (i
= 0; i
< num_attributes
; i
++) {
5134 uint8_t attr_num
= strtoul(attributes
[i
], NULL
, 10);
5136 XFREE(MTYPE_TMP
, attributes
[i
]);
5138 /* Some of the attributes, just can't be ignored. */
5139 if (attr_num
== BGP_ATTR_ORIGIN
||
5140 attr_num
== BGP_ATTR_AS_PATH
||
5141 attr_num
== BGP_ATTR_NEXT_HOP
||
5142 attr_num
== BGP_ATTR_MULTI_EXIT_DISC
||
5143 attr_num
== BGP_ATTR_MP_REACH_NLRI
||
5144 attr_num
== BGP_ATTR_MP_UNREACH_NLRI
||
5145 attr_num
== BGP_ATTR_EXT_COMMUNITIES
) {
5147 "%% Can't treat-as-withdraw path-attribute %s, ignoring.\n",
5148 lookup_msg(attr_str
, attr_num
, NULL
));
5152 /* Ignore local-pref, originator-id, cluster-list only
5155 if (peer
->sort
!= BGP_PEER_EBGP
&&
5156 (attr_num
== BGP_ATTR_LOCAL_PREF
||
5157 attr_num
== BGP_ATTR_ORIGINATOR_ID
||
5158 attr_num
== BGP_ATTR_CLUSTER_LIST
)) {
5160 "%% Can treat-as-withdraw path-attribute %s only for eBGP, ignoring.\n",
5161 lookup_msg(attr_str
, attr_num
, NULL
));
5165 peer
->withdraw_attrs
[attr_num
] = set
;
5167 XFREE(MTYPE_TMP
, attributes
);
5168 withdraw_soft_clear
:
5169 /* Configuring path attributes to be treated as withdraw will
5171 * an inbound Route Refresh to ensure that the routing table
5174 FOREACH_AFI_SAFI (afi
, safi
)
5175 peer_clear_soft(peer
, afi
, safi
, BGP_CLEAR_SOFT_IN
);
5179 enum bgp_attr_parse_ret
bgp_attr_ignore(struct peer
*peer
, uint8_t type
)
5181 bool discard
= peer
->discard_attrs
[type
];
5182 bool withdraw
= peer
->withdraw_attrs
[type
];
5184 if (bgp_debug_update(peer
, NULL
, NULL
, 1) && (discard
|| withdraw
))
5185 zlog_debug("%pBP: Ignoring attribute %s (%s)", peer
,
5186 lookup_msg(attr_str
, type
, NULL
),
5187 withdraw
? "treat-as-withdraw" : "discard");
5189 return withdraw
? BGP_ATTR_PARSE_WITHDRAW
: BGP_ATTR_PARSE_PROCEED
;