1 /* BGP attributes management routines.
2 * Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
38 #include "bgpd/bgpd.h"
39 #include "bgpd/bgp_attr.h"
40 #include "bgpd/bgp_route.h"
41 #include "bgpd/bgp_aspath.h"
42 #include "bgpd/bgp_community.h"
43 #include "bgpd/bgp_debug.h"
44 #include "bgpd/bgp_errors.h"
45 #include "bgpd/bgp_label.h"
46 #include "bgpd/bgp_packet.h"
47 #include "bgpd/bgp_ecommunity.h"
48 #include "bgpd/bgp_lcommunity.h"
49 #include "bgpd/bgp_updgrp.h"
50 #include "bgpd/bgp_encap_types.h"
52 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
53 #include "bgp_encap_types.h"
54 #include "bgp_vnc_types.h"
57 #include "bgp_flowspec_private.h"
60 /* Attribute strings for logging. */
61 static const struct message attr_str
[] = {
62 {BGP_ATTR_ORIGIN
, "ORIGIN"},
63 {BGP_ATTR_AS_PATH
, "AS_PATH"},
64 {BGP_ATTR_NEXT_HOP
, "NEXT_HOP"},
65 {BGP_ATTR_MULTI_EXIT_DISC
, "MULTI_EXIT_DISC"},
66 {BGP_ATTR_LOCAL_PREF
, "LOCAL_PREF"},
67 {BGP_ATTR_ATOMIC_AGGREGATE
, "ATOMIC_AGGREGATE"},
68 {BGP_ATTR_AGGREGATOR
, "AGGREGATOR"},
69 {BGP_ATTR_COMMUNITIES
, "COMMUNITY"},
70 {BGP_ATTR_ORIGINATOR_ID
, "ORIGINATOR_ID"},
71 {BGP_ATTR_CLUSTER_LIST
, "CLUSTER_LIST"},
72 {BGP_ATTR_MP_REACH_NLRI
, "MP_REACH_NLRI"},
73 {BGP_ATTR_MP_UNREACH_NLRI
, "MP_UNREACH_NLRI"},
74 {BGP_ATTR_EXT_COMMUNITIES
, "EXT_COMMUNITIES"},
75 {BGP_ATTR_AS4_PATH
, "AS4_PATH"},
76 {BGP_ATTR_AS4_AGGREGATOR
, "AS4_AGGREGATOR"},
77 {BGP_ATTR_PMSI_TUNNEL
, "PMSI_TUNNEL_ATTRIBUTE"},
78 {BGP_ATTR_ENCAP
, "ENCAP"},
79 {BGP_ATTR_OTC
, "OTC"},
80 #ifdef ENABLE_BGP_VNC_ATTR
81 {BGP_ATTR_VNC
, "VNC"},
83 {BGP_ATTR_LARGE_COMMUNITIES
, "LARGE_COMMUNITY"},
84 {BGP_ATTR_PREFIX_SID
, "PREFIX_SID"},
85 {BGP_ATTR_IPV6_EXT_COMMUNITIES
, "IPV6_EXT_COMMUNITIES"},
86 {BGP_ATTR_AIGP
, "AIGP"},
89 static const struct message attr_flag_str
[] = {
90 {BGP_ATTR_FLAG_OPTIONAL
, "Optional"},
91 {BGP_ATTR_FLAG_TRANS
, "Transitive"},
92 {BGP_ATTR_FLAG_PARTIAL
, "Partial"},
93 /* bgp_attr_flags_diagnose() relies on this bit being last in
95 {BGP_ATTR_FLAG_EXTLEN
, "Extended Length"},
98 static struct hash
*cluster_hash
;
100 static void *cluster_hash_alloc(void *p
)
102 const struct cluster_list
*val
= (const struct cluster_list
*)p
;
103 struct cluster_list
*cluster
;
105 cluster
= XMALLOC(MTYPE_CLUSTER
, sizeof(struct cluster_list
));
106 cluster
->length
= val
->length
;
108 if (cluster
->length
) {
109 cluster
->list
= XMALLOC(MTYPE_CLUSTER_VAL
, val
->length
);
110 memcpy(cluster
->list
, val
->list
, val
->length
);
112 cluster
->list
= NULL
;
119 /* Cluster list related functions. */
120 static struct cluster_list
*cluster_parse(struct in_addr
*pnt
, int length
)
122 struct cluster_list tmp
= {};
123 struct cluster_list
*cluster
;
126 tmp
.list
= length
== 0 ? NULL
: pnt
;
128 cluster
= hash_get(cluster_hash
, &tmp
, cluster_hash_alloc
);
133 bool cluster_loop_check(struct cluster_list
*cluster
, struct in_addr originator
)
137 for (i
= 0; i
< cluster
->length
/ 4; i
++)
138 if (cluster
->list
[i
].s_addr
== originator
.s_addr
)
143 static unsigned int cluster_hash_key_make(const void *p
)
145 const struct cluster_list
*cluster
= p
;
147 return jhash(cluster
->list
, cluster
->length
, 0);
150 static bool cluster_hash_cmp(const void *p1
, const void *p2
)
152 const struct cluster_list
*cluster1
= p1
;
153 const struct cluster_list
*cluster2
= p2
;
155 if (cluster1
->list
== cluster2
->list
)
158 if (!cluster1
->list
|| !cluster2
->list
)
161 if (cluster1
->length
!= cluster2
->length
)
164 return (memcmp(cluster1
->list
, cluster2
->list
, cluster1
->length
) == 0);
167 static void cluster_free(struct cluster_list
*cluster
)
169 XFREE(MTYPE_CLUSTER_VAL
, cluster
->list
);
170 XFREE(MTYPE_CLUSTER
, cluster
);
173 static struct cluster_list
*cluster_intern(struct cluster_list
*cluster
)
175 struct cluster_list
*find
;
177 find
= hash_get(cluster_hash
, cluster
, cluster_hash_alloc
);
183 static void cluster_unintern(struct cluster_list
**cluster
)
185 if ((*cluster
)->refcnt
)
186 (*cluster
)->refcnt
--;
188 if ((*cluster
)->refcnt
== 0) {
189 void *p
= hash_release(cluster_hash
, *cluster
);
190 assert(p
== *cluster
);
191 cluster_free(*cluster
);
196 static void cluster_init(void)
198 cluster_hash
= hash_create(cluster_hash_key_make
, cluster_hash_cmp
,
202 static void cluster_finish(void)
204 hash_clean(cluster_hash
, (void (*)(void *))cluster_free
);
205 hash_free(cluster_hash
);
209 static struct hash
*encap_hash
= NULL
;
210 #ifdef ENABLE_BGP_VNC
211 static struct hash
*vnc_hash
= NULL
;
213 static struct hash
*srv6_l3vpn_hash
;
214 static struct hash
*srv6_vpn_hash
;
216 struct bgp_attr_encap_subtlv
*encap_tlv_dup(struct bgp_attr_encap_subtlv
*orig
)
218 struct bgp_attr_encap_subtlv
*new;
219 struct bgp_attr_encap_subtlv
*tail
;
220 struct bgp_attr_encap_subtlv
*p
;
222 for (p
= orig
, tail
= new = NULL
; p
; p
= p
->next
) {
223 int size
= sizeof(struct bgp_attr_encap_subtlv
) + p
->length
;
225 tail
->next
= XCALLOC(MTYPE_ENCAP_TLV
, size
);
228 tail
= new = XCALLOC(MTYPE_ENCAP_TLV
, size
);
231 memcpy(tail
, p
, size
);
238 static void encap_free(struct bgp_attr_encap_subtlv
*p
)
240 struct bgp_attr_encap_subtlv
*next
;
244 XFREE(MTYPE_ENCAP_TLV
, p
);
249 void bgp_attr_flush_encap(struct attr
*attr
)
254 if (attr
->encap_subtlvs
) {
255 encap_free(attr
->encap_subtlvs
);
256 attr
->encap_subtlvs
= NULL
;
258 #ifdef ENABLE_BGP_VNC
259 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
260 bgp_attr_get_vnc_subtlvs(attr
);
263 encap_free(vnc_subtlvs
);
264 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
270 * Compare encap sub-tlv chains
275 * This algorithm could be made faster if needed
277 static bool encap_same(const struct bgp_attr_encap_subtlv
*h1
,
278 const struct bgp_attr_encap_subtlv
*h2
)
280 const struct bgp_attr_encap_subtlv
*p
;
281 const struct bgp_attr_encap_subtlv
*q
;
285 if (h1
== NULL
|| h2
== NULL
)
288 for (p
= h1
; p
; p
= p
->next
) {
289 for (q
= h2
; q
; q
= q
->next
) {
290 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
291 && !memcmp(p
->value
, q
->value
, p
->length
)) {
300 for (p
= h2
; p
; p
= p
->next
) {
301 for (q
= h1
; q
; q
= q
->next
) {
302 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
303 && !memcmp(p
->value
, q
->value
, p
->length
)) {
315 static void *encap_hash_alloc(void *p
)
317 /* Encap structure is already allocated. */
323 #ifdef ENABLE_BGP_VNC
328 static struct bgp_attr_encap_subtlv
*
329 encap_intern(struct bgp_attr_encap_subtlv
*encap
, encap_subtlv_type type
)
331 struct bgp_attr_encap_subtlv
*find
;
332 struct hash
*hash
= encap_hash
;
333 #ifdef ENABLE_BGP_VNC
334 if (type
== VNC_SUBTLV_TYPE
)
338 find
= hash_get(hash
, encap
, encap_hash_alloc
);
346 static void encap_unintern(struct bgp_attr_encap_subtlv
**encapp
,
347 encap_subtlv_type type
)
349 struct bgp_attr_encap_subtlv
*encap
= *encapp
;
353 if (encap
->refcnt
== 0) {
354 struct hash
*hash
= encap_hash
;
355 #ifdef ENABLE_BGP_VNC
356 if (type
== VNC_SUBTLV_TYPE
)
359 hash_release(hash
, encap
);
365 static unsigned int encap_hash_key_make(const void *p
)
367 const struct bgp_attr_encap_subtlv
*encap
= p
;
369 return jhash(encap
->value
, encap
->length
, 0);
372 static bool encap_hash_cmp(const void *p1
, const void *p2
)
374 return encap_same((const struct bgp_attr_encap_subtlv
*)p1
,
375 (const struct bgp_attr_encap_subtlv
*)p2
);
378 static void encap_init(void)
380 encap_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
382 #ifdef ENABLE_BGP_VNC
383 vnc_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
388 static void encap_finish(void)
390 hash_clean(encap_hash
, (void (*)(void *))encap_free
);
391 hash_free(encap_hash
);
393 #ifdef ENABLE_BGP_VNC
394 hash_clean(vnc_hash
, (void (*)(void *))encap_free
);
400 static bool overlay_index_same(const struct attr
*a1
, const struct attr
*a2
)
409 return bgp_route_evpn_same(bgp_attr_get_evpn_overlay(a1
),
410 bgp_attr_get_evpn_overlay(a2
));
413 /* Unknown transit attribute. */
414 static struct hash
*transit_hash
;
416 static void transit_free(struct transit
*transit
)
418 XFREE(MTYPE_TRANSIT_VAL
, transit
->val
);
419 XFREE(MTYPE_TRANSIT
, transit
);
422 static void *transit_hash_alloc(void *p
)
424 /* Transit structure is already allocated. */
428 static struct transit
*transit_intern(struct transit
*transit
)
430 struct transit
*find
;
432 find
= hash_get(transit_hash
, transit
, transit_hash_alloc
);
434 transit_free(transit
);
440 static void transit_unintern(struct transit
**transit
)
442 if ((*transit
)->refcnt
)
443 (*transit
)->refcnt
--;
445 if ((*transit
)->refcnt
== 0) {
446 hash_release(transit_hash
, *transit
);
447 transit_free(*transit
);
452 static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt
, int length
,
461 ptr_get_be16(data
+ 1, &tlv_length
);
464 /* The value field of the AIGP TLV is always 8 octets
465 * long and its value is interpreted as an unsigned 64-bit
468 if (tlv_type
== BGP_AIGP_TLV_METRIC
) {
469 (void)ptr_get_be64(data
+ 3, aigp
);
471 /* If an AIGP attribute is received and its first AIGP
472 * TLV contains the maximum value 0xffffffffffffffff,
473 * the attribute SHOULD be considered to be malformed
474 * and SHOULD be discarded as specified in this section.
476 if (*aigp
== BGP_AIGP_TLV_METRIC_MAX
) {
477 zlog_err("Bad AIGP TLV (%s) length: %llu",
478 BGP_AIGP_TLV_METRIC_DESC
,
479 BGP_AIGP_TLV_METRIC_MAX
);
487 length
-= tlv_length
;
493 static uint64_t bgp_aigp_metric_total(struct bgp_path_info
*bpi
)
495 uint64_t aigp
= bgp_attr_get_aigp_metric(bpi
->attr
);
498 return aigp
+ bpi
->nexthop
->metric
;
503 static void stream_put_bgp_aigp_tlv_metric(struct stream
*s
,
504 struct bgp_path_info
*bpi
)
506 stream_putc(s
, BGP_AIGP_TLV_METRIC
);
507 stream_putw(s
, BGP_AIGP_TLV_METRIC_LEN
);
508 stream_putq(s
, bgp_aigp_metric_total(bpi
));
511 static bool bgp_attr_aigp_valid(uint8_t *pnt
, int length
)
518 zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u",
525 ptr_get_be16(data
+ 1, &tlv_length
);
528 if (length
< tlv_length
) {
530 "Bad AIGP attribute length: %u, but TLV length: %u",
535 if (tlv_length
< 3) {
536 zlog_err("Bad AIGP TLV length (MUST be minimum 3): %u",
541 /* AIGP TLV, Length: 11 */
542 if (tlv_type
== BGP_AIGP_TLV_METRIC
&&
543 tlv_length
!= BGP_AIGP_TLV_METRIC_LEN
) {
544 zlog_err("Bad AIGP TLV (%s) length: %u",
545 BGP_AIGP_TLV_METRIC_DESC
, tlv_length
);
550 length
-= tlv_length
;
556 static void *srv6_l3vpn_hash_alloc(void *p
)
561 static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn
*l3vpn
)
563 XFREE(MTYPE_BGP_SRV6_L3VPN
, l3vpn
);
566 static struct bgp_attr_srv6_l3vpn
*
567 srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn
*l3vpn
)
569 struct bgp_attr_srv6_l3vpn
*find
;
571 find
= hash_get(srv6_l3vpn_hash
, l3vpn
, srv6_l3vpn_hash_alloc
);
573 srv6_l3vpn_free(l3vpn
);
578 static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn
**l3vpnp
)
580 struct bgp_attr_srv6_l3vpn
*l3vpn
= *l3vpnp
;
585 if (l3vpn
->refcnt
== 0) {
586 hash_release(srv6_l3vpn_hash
, l3vpn
);
587 srv6_l3vpn_free(l3vpn
);
592 static void *srv6_vpn_hash_alloc(void *p
)
597 static void srv6_vpn_free(struct bgp_attr_srv6_vpn
*vpn
)
599 XFREE(MTYPE_BGP_SRV6_VPN
, vpn
);
602 static struct bgp_attr_srv6_vpn
*srv6_vpn_intern(struct bgp_attr_srv6_vpn
*vpn
)
604 struct bgp_attr_srv6_vpn
*find
;
606 find
= hash_get(srv6_vpn_hash
, vpn
, srv6_vpn_hash_alloc
);
613 static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn
**vpnp
)
615 struct bgp_attr_srv6_vpn
*vpn
= *vpnp
;
620 if (vpn
->refcnt
== 0) {
621 hash_release(srv6_vpn_hash
, vpn
);
627 static uint32_t srv6_l3vpn_hash_key_make(const void *p
)
629 const struct bgp_attr_srv6_l3vpn
*l3vpn
= p
;
632 key
= jhash(&l3vpn
->sid
, 16, key
);
633 key
= jhash_1word(l3vpn
->sid_flags
, key
);
634 key
= jhash_1word(l3vpn
->endpoint_behavior
, key
);
635 key
= jhash_1word(l3vpn
->loc_block_len
, key
);
636 key
= jhash_1word(l3vpn
->loc_node_len
, key
);
637 key
= jhash_1word(l3vpn
->func_len
, key
);
638 key
= jhash_1word(l3vpn
->arg_len
, key
);
639 key
= jhash_1word(l3vpn
->transposition_len
, key
);
640 key
= jhash_1word(l3vpn
->transposition_offset
, key
);
644 static bool srv6_l3vpn_hash_cmp(const void *p1
, const void *p2
)
646 const struct bgp_attr_srv6_l3vpn
*l3vpn1
= p1
;
647 const struct bgp_attr_srv6_l3vpn
*l3vpn2
= p2
;
649 return sid_same(&l3vpn1
->sid
, &l3vpn2
->sid
)
650 && l3vpn1
->sid_flags
== l3vpn2
->sid_flags
651 && l3vpn1
->endpoint_behavior
== l3vpn2
->endpoint_behavior
652 && l3vpn1
->loc_block_len
== l3vpn2
->loc_block_len
653 && l3vpn1
->loc_node_len
== l3vpn2
->loc_node_len
654 && l3vpn1
->func_len
== l3vpn2
->func_len
655 && l3vpn1
->arg_len
== l3vpn2
->arg_len
656 && l3vpn1
->transposition_len
== l3vpn2
->transposition_len
657 && l3vpn1
->transposition_offset
== l3vpn2
->transposition_offset
;
660 static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn
*h1
,
661 const struct bgp_attr_srv6_l3vpn
*h2
)
665 else if (h1
== NULL
|| h2
== NULL
)
668 return srv6_l3vpn_hash_cmp((const void *)h1
, (const void *)h2
);
671 static unsigned int srv6_vpn_hash_key_make(const void *p
)
673 const struct bgp_attr_srv6_vpn
*vpn
= p
;
676 key
= jhash(&vpn
->sid
, 16, key
);
677 key
= jhash_1word(vpn
->sid_flags
, key
);
681 static bool srv6_vpn_hash_cmp(const void *p1
, const void *p2
)
683 const struct bgp_attr_srv6_vpn
*vpn1
= p1
;
684 const struct bgp_attr_srv6_vpn
*vpn2
= p2
;
686 return sid_same(&vpn1
->sid
, &vpn2
->sid
)
687 && vpn1
->sid_flags
== vpn2
->sid_flags
;
690 static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn
*h1
,
691 const struct bgp_attr_srv6_vpn
*h2
)
695 else if (h1
== NULL
|| h2
== NULL
)
698 return srv6_vpn_hash_cmp((const void *)h1
, (const void *)h2
);
701 static void srv6_init(void)
704 hash_create(srv6_l3vpn_hash_key_make
, srv6_l3vpn_hash_cmp
,
705 "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
706 srv6_vpn_hash
= hash_create(srv6_vpn_hash_key_make
, srv6_vpn_hash_cmp
,
707 "BGP Prefix-SID SRv6-VPN-Service-TLV");
710 static void srv6_finish(void)
712 hash_clean(srv6_l3vpn_hash
, (void (*)(void *))srv6_l3vpn_free
);
713 hash_free(srv6_l3vpn_hash
);
714 srv6_l3vpn_hash
= NULL
;
715 hash_clean(srv6_vpn_hash
, (void (*)(void *))srv6_vpn_free
);
716 hash_free(srv6_vpn_hash
);
717 srv6_vpn_hash
= NULL
;
720 static unsigned int transit_hash_key_make(const void *p
)
722 const struct transit
*transit
= p
;
724 return jhash(transit
->val
, transit
->length
, 0);
727 static bool transit_hash_cmp(const void *p1
, const void *p2
)
729 const struct transit
*transit1
= p1
;
730 const struct transit
*transit2
= p2
;
732 return (transit1
->length
== transit2
->length
733 && memcmp(transit1
->val
, transit2
->val
, transit1
->length
) == 0);
736 static void transit_init(void)
738 transit_hash
= hash_create(transit_hash_key_make
, transit_hash_cmp
,
742 static void transit_finish(void)
744 hash_clean(transit_hash
, (void (*)(void *))transit_free
);
745 hash_free(transit_hash
);
749 /* Attribute hash routines. */
750 static struct hash
*attrhash
;
752 unsigned long int attr_count(void)
754 return attrhash
->count
;
757 unsigned long int attr_unknown_count(void)
759 return transit_hash
->count
;
762 unsigned int attrhash_key_make(const void *p
)
764 const struct attr
*attr
= (struct attr
*)p
;
766 #define MIX(val) key = jhash_1word(val, key)
767 #define MIX3(a, b, c) key = jhash_3words((a), (b), (c), key)
769 MIX3(attr
->origin
, attr
->nexthop
.s_addr
, attr
->med
);
770 MIX3(attr
->local_pref
, attr
->aggregator_as
,
771 attr
->aggregator_addr
.s_addr
);
772 MIX3(attr
->weight
, attr
->mp_nexthop_global_in
.s_addr
,
773 attr
->originator_id
.s_addr
);
774 MIX3(attr
->tag
, attr
->label
, attr
->label_index
);
777 MIX(aspath_key_make(attr
->aspath
));
778 if (bgp_attr_get_community(attr
))
779 MIX(community_hash_make(bgp_attr_get_community(attr
)));
780 if (bgp_attr_get_lcommunity(attr
))
781 MIX(lcommunity_hash_make(bgp_attr_get_lcommunity(attr
)));
782 if (bgp_attr_get_ecommunity(attr
))
783 MIX(ecommunity_hash_make(bgp_attr_get_ecommunity(attr
)));
784 if (bgp_attr_get_ipv6_ecommunity(attr
))
785 MIX(ecommunity_hash_make(bgp_attr_get_ipv6_ecommunity(attr
)));
786 if (bgp_attr_get_cluster(attr
))
787 MIX(cluster_hash_key_make(bgp_attr_get_cluster(attr
)));
788 if (bgp_attr_get_transit(attr
))
789 MIX(transit_hash_key_make(bgp_attr_get_transit(attr
)));
790 if (attr
->encap_subtlvs
)
791 MIX(encap_hash_key_make(attr
->encap_subtlvs
));
792 if (attr
->srv6_l3vpn
)
793 MIX(srv6_l3vpn_hash_key_make(attr
->srv6_l3vpn
));
795 MIX(srv6_vpn_hash_key_make(attr
->srv6_vpn
));
796 #ifdef ENABLE_BGP_VNC
797 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
798 bgp_attr_get_vnc_subtlvs(attr
);
800 MIX(encap_hash_key_make(vnc_subtlvs
));
802 MIX(attr
->mp_nexthop_len
);
803 key
= jhash(attr
->mp_nexthop_global
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
804 key
= jhash(attr
->mp_nexthop_local
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
805 MIX3(attr
->nh_ifindex
, attr
->nh_lla_ifindex
, attr
->distance
);
806 MIX(attr
->rmap_table_id
);
810 MIX(bgp_attr_get_aigp_metric(attr
));
815 bool attrhash_cmp(const void *p1
, const void *p2
)
817 const struct attr
*attr1
= p1
;
818 const struct attr
*attr2
= p2
;
820 if (attr1
->flag
== attr2
->flag
&& attr1
->origin
== attr2
->origin
821 && attr1
->nexthop
.s_addr
== attr2
->nexthop
.s_addr
822 && attr1
->aspath
== attr2
->aspath
823 && bgp_attr_get_community(attr1
)
824 == bgp_attr_get_community(attr2
)
825 && attr1
->med
== attr2
->med
826 && attr1
->local_pref
== attr2
->local_pref
827 && attr1
->rmap_change_flags
== attr2
->rmap_change_flags
) {
828 if (attr1
->aggregator_as
== attr2
->aggregator_as
829 && attr1
->aggregator_addr
.s_addr
830 == attr2
->aggregator_addr
.s_addr
831 && attr1
->weight
== attr2
->weight
832 && attr1
->tag
== attr2
->tag
833 && attr1
->label_index
== attr2
->label_index
834 && attr1
->mp_nexthop_len
== attr2
->mp_nexthop_len
835 && bgp_attr_get_ecommunity(attr1
)
836 == bgp_attr_get_ecommunity(attr2
)
837 && bgp_attr_get_ipv6_ecommunity(attr1
)
838 == bgp_attr_get_ipv6_ecommunity(attr2
)
839 && bgp_attr_get_lcommunity(attr1
)
840 == bgp_attr_get_lcommunity(attr2
)
841 && bgp_attr_get_cluster(attr1
)
842 == bgp_attr_get_cluster(attr2
)
843 && bgp_attr_get_transit(attr1
)
844 == bgp_attr_get_transit(attr2
)
845 && bgp_attr_get_aigp_metric(attr1
)
846 == bgp_attr_get_aigp_metric(attr2
)
847 && attr1
->rmap_table_id
== attr2
->rmap_table_id
848 && (attr1
->encap_tunneltype
== attr2
->encap_tunneltype
)
849 && encap_same(attr1
->encap_subtlvs
, attr2
->encap_subtlvs
)
850 #ifdef ENABLE_BGP_VNC
851 && encap_same(bgp_attr_get_vnc_subtlvs(attr1
),
852 bgp_attr_get_vnc_subtlvs(attr2
))
854 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_global
,
855 &attr2
->mp_nexthop_global
)
856 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_local
,
857 &attr2
->mp_nexthop_local
)
858 && IPV4_ADDR_SAME(&attr1
->mp_nexthop_global_in
,
859 &attr2
->mp_nexthop_global_in
)
860 && IPV4_ADDR_SAME(&attr1
->originator_id
,
861 &attr2
->originator_id
)
862 && overlay_index_same(attr1
, attr2
)
863 && !memcmp(&attr1
->esi
, &attr2
->esi
, sizeof(esi_t
))
864 && attr1
->es_flags
== attr2
->es_flags
865 && attr1
->mm_sync_seqnum
== attr2
->mm_sync_seqnum
866 && attr1
->df_pref
== attr2
->df_pref
867 && attr1
->df_alg
== attr2
->df_alg
868 && attr1
->nh_ifindex
== attr2
->nh_ifindex
869 && attr1
->nh_lla_ifindex
== attr2
->nh_lla_ifindex
870 && attr1
->distance
== attr2
->distance
871 && srv6_l3vpn_same(attr1
->srv6_l3vpn
, attr2
->srv6_l3vpn
)
872 && srv6_vpn_same(attr1
->srv6_vpn
, attr2
->srv6_vpn
)
873 && attr1
->srte_color
== attr2
->srte_color
874 && attr1
->nh_type
== attr2
->nh_type
875 && attr1
->bh_type
== attr2
->bh_type
876 && attr1
->otc
== attr2
->otc
)
883 static void attrhash_init(void)
886 hash_create(attrhash_key_make
, attrhash_cmp
, "BGP Attributes");
890 * special for hash_clean below
892 static void attr_vfree(void *attr
)
894 XFREE(MTYPE_ATTR
, attr
);
897 static void attrhash_finish(void)
899 hash_clean(attrhash
, attr_vfree
);
904 static void attr_show_all_iterator(struct hash_bucket
*bucket
, struct vty
*vty
)
906 struct attr
*attr
= bucket
->data
;
907 struct in6_addr
*sid
= NULL
;
909 if (attr
->srv6_l3vpn
)
910 sid
= &attr
->srv6_l3vpn
->sid
;
911 else if (attr
->srv6_vpn
)
912 sid
= &attr
->srv6_vpn
->sid
;
914 vty_out(vty
, "attr[%ld] nexthop %pI4\n", attr
->refcnt
, &attr
->nexthop
);
918 " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n",
919 attr
->flag
, attr
->distance
, attr
->med
, attr
->local_pref
,
920 attr
->origin
, attr
->weight
, attr
->label
, sid
);
923 void attr_show_all(struct vty
*vty
)
925 hash_iterate(attrhash
, (void (*)(struct hash_bucket
*,
926 void *))attr_show_all_iterator
,
930 static void *bgp_attr_hash_alloc(void *p
)
932 struct attr
*val
= (struct attr
*)p
;
935 attr
= XMALLOC(MTYPE_ATTR
, sizeof(struct attr
));
937 if (val
->encap_subtlvs
) {
938 val
->encap_subtlvs
= NULL
;
940 #ifdef ENABLE_BGP_VNC
941 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
942 bgp_attr_get_vnc_subtlvs(val
);
945 bgp_attr_set_vnc_subtlvs(val
, NULL
);
952 /* Internet argument attribute. */
953 struct attr
*bgp_attr_intern(struct attr
*attr
)
956 struct ecommunity
*ecomm
= NULL
;
957 struct ecommunity
*ipv6_ecomm
= NULL
;
958 struct lcommunity
*lcomm
= NULL
;
959 struct community
*comm
= NULL
;
961 /* Intern referenced structure. */
963 if (!attr
->aspath
->refcnt
)
964 attr
->aspath
= aspath_intern(attr
->aspath
);
966 attr
->aspath
->refcnt
++;
969 comm
= bgp_attr_get_community(attr
);
972 bgp_attr_set_community(attr
, community_intern(comm
));
977 ecomm
= bgp_attr_get_ecommunity(attr
);
980 bgp_attr_set_ecommunity(attr
, ecommunity_intern(ecomm
));
985 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
987 if (!ipv6_ecomm
->refcnt
)
988 bgp_attr_set_ipv6_ecommunity(
989 attr
, ecommunity_intern(ipv6_ecomm
));
991 ipv6_ecomm
->refcnt
++;
994 lcomm
= bgp_attr_get_lcommunity(attr
);
997 bgp_attr_set_lcommunity(attr
, lcommunity_intern(lcomm
));
1002 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
1005 if (!cluster
->refcnt
)
1006 bgp_attr_set_cluster(attr
, cluster_intern(cluster
));
1011 struct transit
*transit
= bgp_attr_get_transit(attr
);
1014 if (!transit
->refcnt
)
1015 bgp_attr_set_transit(attr
, transit_intern(transit
));
1019 if (attr
->encap_subtlvs
) {
1020 if (!attr
->encap_subtlvs
->refcnt
)
1021 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
1024 attr
->encap_subtlvs
->refcnt
++;
1026 if (attr
->srv6_l3vpn
) {
1027 if (!attr
->srv6_l3vpn
->refcnt
)
1028 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
1030 attr
->srv6_l3vpn
->refcnt
++;
1032 if (attr
->srv6_vpn
) {
1033 if (!attr
->srv6_vpn
->refcnt
)
1034 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
1036 attr
->srv6_vpn
->refcnt
++;
1038 #ifdef ENABLE_BGP_VNC
1039 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1040 bgp_attr_get_vnc_subtlvs(attr
);
1043 if (!vnc_subtlvs
->refcnt
)
1044 bgp_attr_set_vnc_subtlvs(
1046 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
1048 vnc_subtlvs
->refcnt
++;
1052 /* At this point, attr only contains intern'd pointers. that means
1053 * if we find it in attrhash, it has all the same pointers and we
1054 * correctly updated the refcounts on these.
1055 * If we don't find it, we need to allocate a one because in all
1056 * cases this returns a new reference to a hashed attr, but the input
1057 * wasn't on hash. */
1058 find
= (struct attr
*)hash_get(attrhash
, attr
, bgp_attr_hash_alloc
);
1064 /* Make network statement's attribute. */
1065 struct attr
*bgp_attr_default_set(struct attr
*attr
, struct bgp
*bgp
,
1068 memset(attr
, 0, sizeof(struct attr
));
1070 attr
->origin
= origin
;
1071 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1072 attr
->aspath
= aspath_empty();
1073 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1074 attr
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1076 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
1077 attr
->label
= MPLS_INVALID_LABEL
;
1078 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1079 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1080 attr
->local_pref
= bgp
->default_local_pref
;
1085 /* Create the attributes for an aggregate */
1086 struct attr
*bgp_attr_aggregate_intern(
1087 struct bgp
*bgp
, uint8_t origin
, struct aspath
*aspath
,
1088 struct community
*community
, struct ecommunity
*ecommunity
,
1089 struct lcommunity
*lcommunity
, struct bgp_aggregate
*aggregate
,
1090 uint8_t atomic_aggregate
, const struct prefix
*p
)
1094 route_map_result_t ret
;
1096 memset(&attr
, 0, sizeof(attr
));
1098 /* Origin attribute. */
1099 attr
.origin
= origin
;
1100 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1104 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1106 /* AS path attribute. */
1108 attr
.aspath
= aspath_intern(aspath
);
1110 attr
.aspath
= aspath_empty();
1111 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1113 /* Next hop attribute. */
1114 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1117 uint32_t gshut
= COMMUNITY_GSHUT
;
1119 /* If we are not shutting down ourselves and we are
1120 * aggregating a route that contains the GSHUT community we
1121 * need to remove that community when creating the aggregate */
1122 if (!bgp_in_graceful_shutdown(bgp
)
1123 && community_include(community
, gshut
)) {
1124 community_del_val(community
, &gshut
);
1127 bgp_attr_set_community(&attr
, community
);
1131 bgp_attr_set_ecommunity(&attr
, ecommunity
);
1134 bgp_attr_set_lcommunity(&attr
, lcommunity
);
1136 if (bgp_in_graceful_shutdown(bgp
))
1137 bgp_attr_add_gshut_community(&attr
);
1139 attr
.label_index
= BGP_INVALID_LABEL_INDEX
;
1140 attr
.label
= MPLS_INVALID_LABEL
;
1141 attr
.weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1142 attr
.mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1143 if (!aggregate
->as_set
|| atomic_aggregate
)
1144 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1145 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1146 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
))
1147 attr
.aggregator_as
= bgp
->confed_id
;
1149 attr
.aggregator_as
= bgp
->as
;
1150 attr
.aggregator_addr
= bgp
->router_id
;
1152 /* Apply route-map */
1153 if (aggregate
->rmap
.name
) {
1154 struct attr attr_tmp
= attr
;
1155 struct bgp_path_info rmap_path
;
1157 memset(&rmap_path
, 0, sizeof(rmap_path
));
1158 rmap_path
.peer
= bgp
->peer_self
;
1159 rmap_path
.attr
= &attr_tmp
;
1161 SET_FLAG(bgp
->peer_self
->rmap_type
, PEER_RMAP_TYPE_AGGREGATE
);
1163 ret
= route_map_apply(aggregate
->rmap
.map
, p
, &rmap_path
);
1165 bgp
->peer_self
->rmap_type
= 0;
1167 if (ret
== RMAP_DENYMATCH
) {
1168 /* Free uninterned attribute. */
1169 bgp_attr_flush(&attr_tmp
);
1171 /* Unintern original. */
1172 aspath_unintern(&attr
.aspath
);
1176 if (bgp_in_graceful_shutdown(bgp
))
1177 bgp_attr_add_gshut_community(&attr_tmp
);
1179 new = bgp_attr_intern(&attr_tmp
);
1182 if (bgp_in_graceful_shutdown(bgp
))
1183 bgp_attr_add_gshut_community(&attr
);
1185 new = bgp_attr_intern(&attr
);
1188 /* Always release the 'intern()'ed AS Path. */
1189 aspath_unintern(&attr
.aspath
);
1194 /* Unintern just the sub-components of the attr, but not the attr */
1195 void bgp_attr_unintern_sub(struct attr
*attr
)
1197 struct ecommunity
*ecomm
= NULL
;
1198 struct ecommunity
*ipv6_ecomm
= NULL
;
1199 struct cluster_list
*cluster
;
1200 struct lcommunity
*lcomm
= NULL
;
1201 struct community
*comm
= NULL
;
1203 /* aspath refcount shoud be decrement. */
1204 aspath_unintern(&attr
->aspath
);
1205 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
));
1207 comm
= bgp_attr_get_community(attr
);
1208 community_unintern(&comm
);
1209 bgp_attr_set_community(attr
, NULL
);
1211 ecomm
= bgp_attr_get_ecommunity(attr
);
1212 ecommunity_unintern(&ecomm
);
1213 bgp_attr_set_ecommunity(attr
, NULL
);
1215 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1216 ecommunity_unintern(&ipv6_ecomm
);
1217 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1219 lcomm
= bgp_attr_get_lcommunity(attr
);
1220 lcommunity_unintern(&lcomm
);
1221 bgp_attr_set_lcommunity(attr
, NULL
);
1223 cluster
= bgp_attr_get_cluster(attr
);
1225 cluster_unintern(&cluster
);
1226 bgp_attr_set_cluster(attr
, cluster
);
1228 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
));
1230 struct transit
*transit
= bgp_attr_get_transit(attr
);
1233 transit_unintern(&transit
);
1234 bgp_attr_set_transit(attr
, transit
);
1237 if (attr
->encap_subtlvs
)
1238 encap_unintern(&attr
->encap_subtlvs
, ENCAP_SUBTLV_TYPE
);
1240 #ifdef ENABLE_BGP_VNC
1241 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1242 bgp_attr_get_vnc_subtlvs(attr
);
1245 encap_unintern(&vnc_subtlvs
, VNC_SUBTLV_TYPE
);
1246 bgp_attr_set_vnc_subtlvs(attr
, vnc_subtlvs
);
1250 if (attr
->srv6_l3vpn
)
1251 srv6_l3vpn_unintern(&attr
->srv6_l3vpn
);
1254 srv6_vpn_unintern(&attr
->srv6_vpn
);
1257 /* Free bgp attribute and aspath. */
1258 void bgp_attr_unintern(struct attr
**pattr
)
1260 struct attr
*attr
= *pattr
;
1264 /* Decrement attribute reference. */
1269 /* If reference becomes zero then free attribute object. */
1270 if (attr
->refcnt
== 0) {
1271 ret
= hash_release(attrhash
, attr
);
1272 assert(ret
!= NULL
);
1273 XFREE(MTYPE_ATTR
, attr
);
1277 bgp_attr_unintern_sub(&tmp
);
1280 void bgp_attr_flush(struct attr
*attr
)
1282 struct ecommunity
*ecomm
;
1283 struct ecommunity
*ipv6_ecomm
;
1284 struct cluster_list
*cluster
;
1285 struct lcommunity
*lcomm
;
1286 struct community
*comm
;
1288 if (attr
->aspath
&& !attr
->aspath
->refcnt
) {
1289 aspath_free(attr
->aspath
);
1290 attr
->aspath
= NULL
;
1292 comm
= bgp_attr_get_community(attr
);
1293 if (comm
&& !comm
->refcnt
)
1294 community_free(&comm
);
1295 bgp_attr_set_community(attr
, NULL
);
1297 ecomm
= bgp_attr_get_ecommunity(attr
);
1298 if (ecomm
&& !ecomm
->refcnt
)
1299 ecommunity_free(&ecomm
);
1300 bgp_attr_set_ecommunity(attr
, NULL
);
1302 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1303 if (ipv6_ecomm
&& !ipv6_ecomm
->refcnt
)
1304 ecommunity_free(&ipv6_ecomm
);
1305 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1307 lcomm
= bgp_attr_get_lcommunity(attr
);
1308 if (lcomm
&& !lcomm
->refcnt
)
1309 lcommunity_free(&lcomm
);
1310 bgp_attr_set_lcommunity(attr
, NULL
);
1312 cluster
= bgp_attr_get_cluster(attr
);
1313 if (cluster
&& !cluster
->refcnt
) {
1314 cluster_free(cluster
);
1315 bgp_attr_set_cluster(attr
, NULL
);
1318 struct transit
*transit
= bgp_attr_get_transit(attr
);
1320 if (transit
&& !transit
->refcnt
) {
1321 transit_free(transit
);
1322 bgp_attr_set_transit(attr
, NULL
);
1324 if (attr
->encap_subtlvs
&& !attr
->encap_subtlvs
->refcnt
) {
1325 encap_free(attr
->encap_subtlvs
);
1326 attr
->encap_subtlvs
= NULL
;
1328 if (attr
->srv6_l3vpn
&& !attr
->srv6_l3vpn
->refcnt
) {
1329 srv6_l3vpn_free(attr
->srv6_l3vpn
);
1330 attr
->srv6_l3vpn
= NULL
;
1332 if (attr
->srv6_vpn
&& !attr
->srv6_vpn
->refcnt
) {
1333 srv6_vpn_free(attr
->srv6_vpn
);
1334 attr
->srv6_vpn
= NULL
;
1336 #ifdef ENABLE_BGP_VNC
1337 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1338 bgp_attr_get_vnc_subtlvs(attr
);
1340 if (vnc_subtlvs
&& !vnc_subtlvs
->refcnt
) {
1341 encap_free(vnc_subtlvs
);
1342 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
1347 /* Implement draft-scudder-idr-optional-transitive behaviour and
1348 * avoid resetting sessions for malformed attributes which are
1349 * are partial/optional and hence where the error likely was not
1350 * introduced by the sending neighbour.
1352 static enum bgp_attr_parse_ret
1353 bgp_attr_malformed(struct bgp_attr_parser_args
*args
, uint8_t subcode
,
1356 struct peer
*const peer
= args
->peer
;
1357 struct attr
*const attr
= args
->attr
;
1358 const uint8_t flags
= args
->flags
;
1359 /* startp and length must be special-cased, as whether or not to
1360 * send the attribute data with the NOTIFY depends on the error,
1361 * the caller therefore signals this with the seperate length argument
1363 uint8_t *notify_datap
= (length
> 0 ? args
->startp
: NULL
);
1365 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1366 char attr_str
[BUFSIZ
] = {0};
1368 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1370 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1373 /* Only relax error handling for eBGP peers */
1374 if (peer
->sort
!= BGP_PEER_EBGP
) {
1375 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1376 notify_datap
, length
);
1377 return BGP_ATTR_PARSE_ERROR
;
1380 /* Adjust the stream getp to the end of the attribute, in case we can
1381 * still proceed but the caller hasn't read all the attribute.
1383 stream_set_getp(BGP_INPUT(peer
),
1384 (args
->startp
- STREAM_DATA(BGP_INPUT(peer
)))
1387 switch (args
->type
) {
1388 /* where an attribute is relatively inconsequential, e.g. it does not
1389 * affect route selection, and can be safely ignored, then any such
1390 * attributes which are malformed should just be ignored and the route
1391 * processed as normal.
1393 case BGP_ATTR_AS4_AGGREGATOR
:
1394 case BGP_ATTR_AGGREGATOR
:
1395 case BGP_ATTR_ATOMIC_AGGREGATE
:
1396 return BGP_ATTR_PARSE_PROCEED
;
1398 /* Core attributes, particularly ones which may influence route
1399 * selection, should be treat-as-withdraw.
1401 case BGP_ATTR_ORIGIN
:
1402 case BGP_ATTR_AS_PATH
:
1403 case BGP_ATTR_NEXT_HOP
:
1404 case BGP_ATTR_MULTI_EXIT_DISC
:
1405 case BGP_ATTR_LOCAL_PREF
:
1406 case BGP_ATTR_COMMUNITIES
:
1407 case BGP_ATTR_EXT_COMMUNITIES
:
1408 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
1409 case BGP_ATTR_LARGE_COMMUNITIES
:
1410 case BGP_ATTR_ORIGINATOR_ID
:
1411 case BGP_ATTR_CLUSTER_LIST
:
1413 return BGP_ATTR_PARSE_WITHDRAW
;
1414 case BGP_ATTR_MP_REACH_NLRI
:
1415 case BGP_ATTR_MP_UNREACH_NLRI
:
1416 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1417 notify_datap
, length
);
1418 return BGP_ATTR_PARSE_ERROR
;
1421 /* Partial optional attributes that are malformed should not cause
1422 * the whole session to be reset. Instead treat it as a withdrawal
1423 * of the routes, if possible.
1425 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)
1426 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1427 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
))
1428 return BGP_ATTR_PARSE_WITHDRAW
;
1430 /* default to reset */
1431 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1434 /* Find out what is wrong with the path attribute flag bits and log the error.
1435 "Flag bits" here stand for Optional, Transitive and Partial, but not for
1436 Extended Length. Checking O/T/P bits at once implies, that the attribute
1437 being diagnosed is defined by RFC as either a "well-known" or an "optional,
1438 non-transitive" attribute. */
1440 bgp_attr_flags_diagnose(struct bgp_attr_parser_args
*args
,
1441 uint8_t desired_flags
/* how RFC says it must be */
1444 uint8_t seen
= 0, i
;
1445 uint8_t real_flags
= args
->flags
;
1446 const uint8_t attr_code
= args
->type
;
1448 desired_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1449 real_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1450 for (i
= 0; i
<= 2; i
++) /* O,T,P, but not E */
1451 if (CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1452 != CHECK_FLAG(real_flags
, attr_flag_str
[i
].key
)) {
1453 flog_err(EC_BGP_ATTR_FLAG
,
1454 "%s attribute must%s be flagged as \"%s\"",
1455 lookup_msg(attr_str
, attr_code
, NULL
),
1456 CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1459 attr_flag_str
[i
].str
);
1464 "Strange, %s called for attr %s, but no problem found with flags (real flags 0x%x, desired 0x%x)",
1465 __func__
, lookup_msg(attr_str
, attr_code
, NULL
),
1466 real_flags
, desired_flags
);
1470 /* Required flags for attributes. EXTLEN will be masked off when testing,
1471 * as will PARTIAL for optional+transitive attributes.
1473 const uint8_t attr_flags_values
[] = {
1474 [BGP_ATTR_ORIGIN
] = BGP_ATTR_FLAG_TRANS
,
1475 [BGP_ATTR_AS_PATH
] = BGP_ATTR_FLAG_TRANS
,
1476 [BGP_ATTR_NEXT_HOP
] = BGP_ATTR_FLAG_TRANS
,
1477 [BGP_ATTR_MULTI_EXIT_DISC
] = BGP_ATTR_FLAG_OPTIONAL
,
1478 [BGP_ATTR_LOCAL_PREF
] = BGP_ATTR_FLAG_TRANS
,
1479 [BGP_ATTR_ATOMIC_AGGREGATE
] = BGP_ATTR_FLAG_TRANS
,
1480 [BGP_ATTR_AGGREGATOR
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1481 [BGP_ATTR_COMMUNITIES
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1482 [BGP_ATTR_ORIGINATOR_ID
] = BGP_ATTR_FLAG_OPTIONAL
,
1483 [BGP_ATTR_CLUSTER_LIST
] = BGP_ATTR_FLAG_OPTIONAL
,
1484 [BGP_ATTR_MP_REACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1485 [BGP_ATTR_MP_UNREACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1486 [BGP_ATTR_EXT_COMMUNITIES
] =
1487 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1488 [BGP_ATTR_AS4_PATH
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1489 [BGP_ATTR_AS4_AGGREGATOR
] =
1490 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1491 [BGP_ATTR_PMSI_TUNNEL
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1492 [BGP_ATTR_LARGE_COMMUNITIES
] =
1493 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1494 [BGP_ATTR_OTC
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1495 [BGP_ATTR_PREFIX_SID
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1496 [BGP_ATTR_IPV6_EXT_COMMUNITIES
] =
1497 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1498 [BGP_ATTR_AIGP
] = BGP_ATTR_FLAG_OPTIONAL
,
1500 static const size_t attr_flags_values_max
= array_size(attr_flags_values
) - 1;
1502 static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args
*args
)
1504 uint8_t mask
= BGP_ATTR_FLAG_EXTLEN
;
1505 const uint8_t flags
= args
->flags
;
1506 const uint8_t attr_code
= args
->type
;
1508 /* there may be attributes we don't know about */
1509 if (attr_code
> attr_flags_values_max
)
1511 if (attr_flags_values
[attr_code
] == 0)
1514 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set
1518 if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL
, flags
)
1519 && !CHECK_FLAG(BGP_ATTR_FLAG_TRANS
, flags
)) {
1522 "%s well-known attributes must have transitive flag set (%x)",
1523 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1527 /* "For well-known attributes and for optional non-transitive
1529 * the Partial bit MUST be set to 0."
1531 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
)) {
1532 if (!CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)) {
1533 flog_err(EC_BGP_ATTR_FLAG
,
1534 "%s well-known attribute must NOT have the partial flag set (%x)",
1535 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1538 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1539 && !CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)) {
1540 flog_err(EC_BGP_ATTR_FLAG
,
1541 "%s optional + transitive attribute must NOT have the partial flag set (%x)",
1542 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1547 /* Optional transitive attributes may go through speakers that don't
1548 * reocgnise them and set the Partial bit.
1550 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1551 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
))
1552 SET_FLAG(mask
, BGP_ATTR_FLAG_PARTIAL
);
1554 if ((flags
& ~mask
) == attr_flags_values
[attr_code
])
1557 bgp_attr_flags_diagnose(args
, attr_flags_values
[attr_code
]);
1561 /* Get origin attribute of the update message. */
1562 static enum bgp_attr_parse_ret
1563 bgp_attr_origin(struct bgp_attr_parser_args
*args
)
1565 struct peer
*const peer
= args
->peer
;
1566 struct attr
*const attr
= args
->attr
;
1567 const bgp_size_t length
= args
->length
;
1569 /* If any recognized attribute has Attribute Length that conflicts
1570 with the expected length (based on the attribute type code), then
1571 the Error Subcode is set to Attribute Length Error. The Data
1572 field contains the erroneous attribute (type, length and
1575 flog_err(EC_BGP_ATTR_LEN
,
1576 "Origin attribute length is not one %d", length
);
1577 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1581 /* Fetch origin attribute. */
1582 attr
->origin
= stream_getc(BGP_INPUT(peer
));
1584 /* If the ORIGIN attribute has an undefined value, then the Error
1585 Subcode is set to Invalid Origin Attribute. The Data field
1586 contains the unrecognized attribute (type, length and value). */
1587 if ((attr
->origin
!= BGP_ORIGIN_IGP
) && (attr
->origin
!= BGP_ORIGIN_EGP
)
1588 && (attr
->origin
!= BGP_ORIGIN_INCOMPLETE
)) {
1589 flog_err(EC_BGP_ATTR_ORIGIN
,
1590 "Origin attribute value is invalid %d", attr
->origin
);
1591 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_INVAL_ORIGIN
,
1595 /* Set oring attribute flag. */
1596 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1601 /* Parse AS path information. This function is wrapper of
1603 static int bgp_attr_aspath(struct bgp_attr_parser_args
*args
)
1605 struct attr
*const attr
= args
->attr
;
1606 struct peer
*const peer
= args
->peer
;
1607 const bgp_size_t length
= args
->length
;
1610 * peer with AS4 => will get 4Byte ASnums
1611 * otherwise, will get 16 Bit
1613 attr
->aspath
= aspath_parse(
1615 CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1616 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
));
1618 /* In case of IBGP, length will be zero. */
1619 if (!attr
->aspath
) {
1620 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1621 "Malformed AS path from %s, length is %d", peer
->host
,
1623 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1627 /* Conformant BGP speakers SHOULD NOT send BGP
1628 * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1629 * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1630 * withdraw" error handling behavior as per [RFC7606].
1632 if (peer
->bgp
->reject_as_sets
&& aspath_check_as_sets(attr
->aspath
)) {
1633 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1634 "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1636 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1640 /* Set aspath attribute flag. */
1641 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1643 return BGP_ATTR_PARSE_PROCEED
;
1646 static enum bgp_attr_parse_ret
bgp_attr_aspath_check(struct peer
*const peer
,
1647 struct attr
*const attr
)
1649 /* These checks were part of bgp_attr_aspath, but with
1650 * as4 we should to check aspath things when
1651 * aspath synthesizing with as4_path has already taken place.
1652 * Otherwise we check ASPATH and use the synthesized thing, and that is
1654 * So do the checks later, i.e. here
1656 struct aspath
*aspath
;
1658 /* Refresh peer's type. If we set e.g.: AS_EXTERNAL/AS_INTERNAL,
1659 * then peer->sort remains BGP_PEER_EBGP/IBGP, hence we need to
1660 * have an actual type before checking.
1661 * This is especially a case for BGP confederation peers, to avoid
1662 * receiving and treating AS_PATH as malformed.
1664 (void)peer_sort(peer
);
1666 /* Confederation sanity check. */
1667 if ((peer
->sort
== BGP_PEER_CONFED
1668 && !aspath_left_confed_check(attr
->aspath
))
1669 || (peer
->sort
== BGP_PEER_EBGP
1670 && aspath_confed_check(attr
->aspath
))) {
1671 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "Malformed AS path from %s",
1673 return BGP_ATTR_PARSE_WITHDRAW
;
1676 /* First AS check for EBGP. */
1677 if (CHECK_FLAG(peer
->flags
, PEER_FLAG_ENFORCE_FIRST_AS
)) {
1678 if (peer
->sort
== BGP_PEER_EBGP
1679 && !aspath_firstas_check(attr
->aspath
, peer
->as
)) {
1680 flog_err(EC_BGP_ATTR_FIRST_AS
,
1681 "%s incorrect first AS (must be %u)",
1682 peer
->host
, peer
->as
);
1683 return BGP_ATTR_PARSE_WITHDRAW
;
1687 /* Codification of AS 0 Processing */
1688 if (peer
->sort
== BGP_PEER_EBGP
&& aspath_check_as_zero(attr
->aspath
)) {
1690 EC_BGP_ATTR_MAL_AS_PATH
,
1691 "Malformed AS path, AS number is 0 in the path from %s",
1693 return BGP_ATTR_PARSE_WITHDRAW
;
1696 /* local-as prepend */
1697 if (peer
->change_local_as
1698 && !CHECK_FLAG(peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
)) {
1699 aspath
= aspath_dup(attr
->aspath
);
1700 aspath
= aspath_add_seq(aspath
, peer
->change_local_as
);
1701 aspath_unintern(&attr
->aspath
);
1702 attr
->aspath
= aspath_intern(aspath
);
1705 return BGP_ATTR_PARSE_PROCEED
;
1708 /* Parse AS4 path information. This function is another wrapper of
1710 static int bgp_attr_as4_path(struct bgp_attr_parser_args
*args
,
1711 struct aspath
**as4_path
)
1713 struct peer
*const peer
= args
->peer
;
1714 struct attr
*const attr
= args
->attr
;
1715 const bgp_size_t length
= args
->length
;
1717 *as4_path
= aspath_parse(peer
->curr
, length
, 1);
1719 /* In case of IBGP, length will be zero. */
1721 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1722 "Malformed AS4 path from %s, length is %d", peer
->host
,
1724 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1728 /* Conformant BGP speakers SHOULD NOT send BGP
1729 * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1730 * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1731 * withdraw" error handling behavior as per [RFC7606].
1733 if (peer
->bgp
->reject_as_sets
&& aspath_check_as_sets(attr
->aspath
)) {
1734 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1735 "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1737 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1741 /* Set aspath attribute flag. */
1742 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
);
1744 return BGP_ATTR_PARSE_PROCEED
;
1748 * Check that the nexthop attribute is valid.
1750 enum bgp_attr_parse_ret
bgp_attr_nexthop_valid(struct peer
*peer
,
1753 struct bgp
*bgp
= peer
->bgp
;
1755 if (ipv4_martian(&attr
->nexthop
) && !bgp
->allow_martian
) {
1756 uint8_t data
[7]; /* type(2) + length(1) + nhop(4) */
1758 flog_err(EC_BGP_ATTR_MARTIAN_NH
, "Martian nexthop %pI4",
1760 data
[0] = BGP_ATTR_FLAG_TRANS
;
1761 data
[1] = BGP_ATTR_NEXT_HOP
;
1762 data
[2] = BGP_ATTR_NHLEN_IPV4
;
1763 memcpy(&data
[3], &attr
->nexthop
.s_addr
, BGP_ATTR_NHLEN_IPV4
);
1764 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
1765 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1767 return BGP_ATTR_PARSE_ERROR
;
1770 return BGP_ATTR_PARSE_PROCEED
;
1773 /* Nexthop attribute. */
1774 static enum bgp_attr_parse_ret
1775 bgp_attr_nexthop(struct bgp_attr_parser_args
*args
)
1777 struct peer
*const peer
= args
->peer
;
1778 struct attr
*const attr
= args
->attr
;
1779 const bgp_size_t length
= args
->length
;
1781 /* Check nexthop attribute length. */
1783 flog_err(EC_BGP_ATTR_LEN
,
1784 "Nexthop attribute length isn't four [%d]", length
);
1786 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1790 attr
->nexthop
.s_addr
= stream_get_ipv4(peer
->curr
);
1791 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1793 return BGP_ATTR_PARSE_PROCEED
;
1796 /* MED atrribute. */
1797 static enum bgp_attr_parse_ret
bgp_attr_med(struct bgp_attr_parser_args
*args
)
1799 struct peer
*const peer
= args
->peer
;
1800 struct attr
*const attr
= args
->attr
;
1801 const bgp_size_t length
= args
->length
;
1805 flog_err(EC_BGP_ATTR_LEN
,
1806 "MED attribute length isn't four [%d]", length
);
1808 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1812 attr
->med
= stream_getl(peer
->curr
);
1814 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1816 return BGP_ATTR_PARSE_PROCEED
;
1819 /* Local preference attribute. */
1820 static enum bgp_attr_parse_ret
1821 bgp_attr_local_pref(struct bgp_attr_parser_args
*args
)
1823 struct peer
*const peer
= args
->peer
;
1824 struct attr
*const attr
= args
->attr
;
1825 const bgp_size_t length
= args
->length
;
1827 /* if received from an internal neighbor, it SHALL be considered
1828 * malformed if its length is not equal to 4. If malformed, the
1829 * UPDATE message SHALL be handled using the approach of "treat-as-
1832 if (peer
->sort
== BGP_PEER_IBGP
&& length
!= 4) {
1833 flog_err(EC_BGP_ATTR_LEN
,
1834 "LOCAL_PREF attribute length isn't 4 [%u]", length
);
1835 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1839 /* If it is contained in an UPDATE message that is received from an
1840 external peer, then this attribute MUST be ignored by the
1841 receiving speaker. */
1842 if (peer
->sort
== BGP_PEER_EBGP
) {
1843 STREAM_FORWARD_GETP(peer
->curr
, length
);
1844 return BGP_ATTR_PARSE_PROCEED
;
1847 STREAM_GETL(peer
->curr
, attr
->local_pref
);
1849 /* Set the local-pref flag. */
1850 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
1852 return BGP_ATTR_PARSE_PROCEED
;
1855 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1859 /* Atomic aggregate. */
1860 static int bgp_attr_atomic(struct bgp_attr_parser_args
*args
)
1862 struct peer
*const peer
= args
->peer
;
1863 struct attr
*const attr
= args
->attr
;
1864 const bgp_size_t length
= args
->length
;
1868 flog_err(EC_BGP_ATTR_LEN
,
1869 "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1871 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1875 if (peer
->discard_attrs
[args
->type
])
1878 /* Set atomic aggregate flag. */
1879 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1881 return BGP_ATTR_PARSE_PROCEED
;
1884 stream_forward_getp(peer
->curr
, length
);
1886 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
1887 zlog_debug("%pBP: Ignoring attribute %s", peer
,
1888 lookup_msg(attr_str
, args
->type
, NULL
));
1890 return BGP_ATTR_PARSE_PROCEED
;
1893 /* Aggregator attribute */
1894 static int bgp_attr_aggregator(struct bgp_attr_parser_args
*args
)
1896 struct peer
*const peer
= args
->peer
;
1897 struct attr
*const attr
= args
->attr
;
1898 const bgp_size_t length
= args
->length
;
1903 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1904 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1905 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
))
1908 if (length
!= wantedlen
) {
1909 flog_err(EC_BGP_ATTR_LEN
,
1910 "AGGREGATOR attribute length isn't %u [%u]", wantedlen
,
1912 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1916 if (peer
->discard_attrs
[args
->type
])
1917 goto aggregator_ignore
;
1919 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
))
1920 aggregator_as
= stream_getl(peer
->curr
);
1922 aggregator_as
= stream_getw(peer
->curr
);
1924 attr
->aggregator_as
= aggregator_as
;
1925 attr
->aggregator_addr
.s_addr
= stream_get_ipv4(peer
->curr
);
1927 /* Codification of AS 0 Processing */
1928 if (aggregator_as
== BGP_AS_ZERO
) {
1929 flog_err(EC_BGP_ATTR_LEN
,
1930 "%s: AGGREGATOR AS number is 0 for aspath: %s",
1931 peer
->host
, aspath_print(attr
->aspath
));
1933 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1934 char attr_str
[BUFSIZ
] = {0};
1936 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1938 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1941 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1944 return BGP_ATTR_PARSE_PROCEED
;
1947 stream_forward_getp(peer
->curr
, length
);
1949 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
1950 zlog_debug("%pBP: Ignoring attribute %s", peer
,
1951 lookup_msg(attr_str
, args
->type
, NULL
));
1953 return BGP_ATTR_PARSE_PROCEED
;
1956 /* New Aggregator attribute */
1957 static enum bgp_attr_parse_ret
1958 bgp_attr_as4_aggregator(struct bgp_attr_parser_args
*args
,
1959 as_t
*as4_aggregator_as
,
1960 struct in_addr
*as4_aggregator_addr
)
1962 struct peer
*const peer
= args
->peer
;
1963 struct attr
*const attr
= args
->attr
;
1964 const bgp_size_t length
= args
->length
;
1968 flog_err(EC_BGP_ATTR_LEN
, "New Aggregator length is not 8 [%d]",
1970 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1974 if (peer
->discard_attrs
[args
->type
])
1975 goto as4_aggregator_ignore
;
1977 aggregator_as
= stream_getl(peer
->curr
);
1979 *as4_aggregator_as
= aggregator_as
;
1980 as4_aggregator_addr
->s_addr
= stream_get_ipv4(peer
->curr
);
1982 /* Codification of AS 0 Processing */
1983 if (aggregator_as
== BGP_AS_ZERO
) {
1984 flog_err(EC_BGP_ATTR_LEN
,
1985 "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
1986 peer
->host
, aspath_print(attr
->aspath
));
1988 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1989 char attr_str
[BUFSIZ
] = {0};
1991 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1993 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1996 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
);
1999 return BGP_ATTR_PARSE_PROCEED
;
2001 as4_aggregator_ignore
:
2002 stream_forward_getp(peer
->curr
, length
);
2004 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2005 zlog_debug("%pBP: Ignoring attribute %s", peer
,
2006 lookup_msg(attr_str
, args
->type
, NULL
));
2008 return BGP_ATTR_PARSE_PROCEED
;
2011 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
2013 static enum bgp_attr_parse_ret
2014 bgp_attr_munge_as4_attrs(struct peer
*const peer
, struct attr
*const attr
,
2015 struct aspath
*as4_path
, as_t as4_aggregator
,
2016 struct in_addr
*as4_aggregator_addr
)
2018 int ignore_as4_path
= 0;
2019 struct aspath
*newpath
;
2021 if (!attr
->aspath
) {
2022 /* NULL aspath shouldn't be possible as bgp_attr_parse should
2024 * checked that all well-known, mandatory attributes were
2027 * Can only be a problem with peer itself - hard error
2029 return BGP_ATTR_PARSE_ERROR
;
2032 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
2033 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
2035 * It is worth a warning though, because the peer really
2036 * should not send them
2038 if (BGP_DEBUG(as4
, AS4
)) {
2039 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
2040 zlog_debug("[AS4] %s %s AS4_PATH", peer
->host
,
2041 "AS4 capable peer, yet it sent");
2044 & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
2045 zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
2047 "AS4 capable peer, yet it sent");
2050 return BGP_ATTR_PARSE_PROCEED
;
2053 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
2054 * because that may override AS4_PATH
2056 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
))) {
2057 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
))) {
2059 * if the as_number in aggregator is not AS_TRANS,
2060 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
2061 * and the Aggregator shall be taken as
2062 * info on the aggregating node, and the AS_PATH
2063 * shall be taken as the AS_PATH
2065 * the Aggregator shall be ignored and the
2066 * AS4_AGGREGATOR shall be taken as the
2067 * Aggregating node and the AS_PATH is to be
2068 * constructed "as in all other cases"
2070 if (attr
->aggregator_as
!= BGP_AS_TRANS
) {
2072 if (BGP_DEBUG(as4
, AS4
))
2074 "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
2076 ignore_as4_path
= 1;
2078 /* "New_aggregator shall be taken as aggregator"
2080 attr
->aggregator_as
= as4_aggregator
;
2081 attr
->aggregator_addr
.s_addr
=
2082 as4_aggregator_addr
->s_addr
;
2085 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
2086 * That is bogus - but reading the conditions
2087 * we have to handle AS4_AGGREGATOR as if it were
2088 * AGGREGATOR in that case
2090 if (BGP_DEBUG(as4
, AS4
))
2092 "[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",
2094 attr
->aggregator_as
= as4_aggregator
;
2095 /* sweep it under the carpet and simulate a "good"
2097 attr
->flag
|= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
));
2101 /* need to reconcile NEW_AS_PATH and AS_PATH */
2102 if (!ignore_as4_path
2103 && (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))) {
2104 newpath
= aspath_reconcile_as4(attr
->aspath
, as4_path
);
2106 return BGP_ATTR_PARSE_ERROR
;
2108 aspath_unintern(&attr
->aspath
);
2109 attr
->aspath
= aspath_intern(newpath
);
2111 return BGP_ATTR_PARSE_PROCEED
;
2114 /* Community attribute. */
2115 static enum bgp_attr_parse_ret
2116 bgp_attr_community(struct bgp_attr_parser_args
*args
)
2118 struct peer
*const peer
= args
->peer
;
2119 struct attr
*const attr
= args
->attr
;
2120 const bgp_size_t length
= args
->length
;
2123 bgp_attr_set_community(attr
, NULL
);
2124 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2128 if (peer
->discard_attrs
[args
->type
])
2129 goto community_ignore
;
2131 bgp_attr_set_community(
2133 community_parse((uint32_t *)stream_pnt(peer
->curr
), length
));
2135 /* XXX: fix community_parse to use stream API and remove this */
2136 stream_forward_getp(peer
->curr
, length
);
2138 /* The Community attribute SHALL be considered malformed if its
2139 * length is not a non-zero multiple of 4.
2141 if (!bgp_attr_get_community(attr
))
2142 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2145 return BGP_ATTR_PARSE_PROCEED
;
2148 stream_forward_getp(peer
->curr
, length
);
2150 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2151 zlog_debug("%pBP: Ignoring attribute %s", peer
,
2152 lookup_msg(attr_str
, args
->type
, NULL
));
2154 return BGP_ATTR_PARSE_PROCEED
;
2157 /* Originator ID attribute. */
2158 static enum bgp_attr_parse_ret
2159 bgp_attr_originator_id(struct bgp_attr_parser_args
*args
)
2161 struct peer
*const peer
= args
->peer
;
2162 struct attr
*const attr
= args
->attr
;
2163 const bgp_size_t length
= args
->length
;
2165 /* if received from an internal neighbor, it SHALL be considered
2166 * malformed if its length is not equal to 4. If malformed, the
2167 * UPDATE message SHALL be handled using the approach of "treat-as-
2171 flog_err(EC_BGP_ATTR_LEN
, "Bad originator ID length %d",
2174 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2178 if (peer
->discard_attrs
[args
->type
])
2179 goto originator_id_ignore
;
2181 attr
->originator_id
.s_addr
= stream_get_ipv4(peer
->curr
);
2183 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
2185 return BGP_ATTR_PARSE_PROCEED
;
2187 originator_id_ignore
:
2188 stream_forward_getp(peer
->curr
, length
);
2190 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2191 zlog_debug("%pBP: Ignoring attribute %s", peer
,
2192 lookup_msg(attr_str
, args
->type
, NULL
));
2194 return BGP_ATTR_PARSE_PROCEED
;
2197 /* Cluster list attribute. */
2198 static enum bgp_attr_parse_ret
2199 bgp_attr_cluster_list(struct bgp_attr_parser_args
*args
)
2201 struct peer
*const peer
= args
->peer
;
2202 struct attr
*const attr
= args
->attr
;
2203 const bgp_size_t length
= args
->length
;
2205 /* if received from an internal neighbor, it SHALL be considered
2206 * malformed if its length is not a non-zero multiple of 4. If
2207 * malformed, the UPDATE message SHALL be handled using the approach
2208 * of "treat-as-withdraw".
2210 if (length
== 0 || length
% 4) {
2211 flog_err(EC_BGP_ATTR_LEN
, "Bad cluster list length %d", length
);
2213 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2217 if (peer
->discard_attrs
[args
->type
])
2218 goto cluster_list_ignore
;
2220 bgp_attr_set_cluster(
2221 attr
, cluster_parse((struct in_addr
*)stream_pnt(peer
->curr
),
2224 /* XXX: Fix cluster_parse to use stream API and then remove this */
2225 stream_forward_getp(peer
->curr
, length
);
2227 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
);
2229 return BGP_ATTR_PARSE_PROCEED
;
2231 cluster_list_ignore
:
2232 stream_forward_getp(peer
->curr
, length
);
2234 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2235 zlog_debug("%pBP: Ignoring attribute %s", peer
,
2236 lookup_msg(attr_str
, args
->type
, NULL
));
2238 return BGP_ATTR_PARSE_PROCEED
;
2241 /* Multiprotocol reachability information parse. */
2242 int bgp_mp_reach_parse(struct bgp_attr_parser_args
*args
,
2243 struct bgp_nlri
*mp_update
)
2247 iana_safi_t pkt_safi
;
2249 bgp_size_t nlri_len
;
2252 struct peer
*const peer
= args
->peer
;
2253 struct attr
*const attr
= args
->attr
;
2254 const bgp_size_t length
= args
->length
;
2256 /* Set end of packet. */
2257 s
= BGP_INPUT(peer
);
2258 start
= stream_get_getp(s
);
2260 /* safe to read statically sized header? */
2261 #define BGP_MP_REACH_MIN_SIZE 5
2262 #define LEN_LEFT (length - (stream_get_getp(s) - start))
2263 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
)) {
2264 zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
2265 __func__
, peer
->host
, (unsigned long)length
);
2266 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2269 /* Load AFI, SAFI. */
2270 pkt_afi
= stream_getw(s
);
2271 pkt_safi
= stream_getc(s
);
2273 /* Convert AFI, SAFI to internal values, check. */
2274 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2275 /* Log if AFI or SAFI is unrecognized. This is not an error
2277 * the attribute is otherwise malformed.
2279 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2281 "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
2282 peer
->host
, iana_afi2str(pkt_afi
),
2283 iana_safi2str(pkt_safi
));
2284 return BGP_ATTR_PARSE_ERROR
;
2287 /* Get nexthop length. */
2288 attr
->mp_nexthop_len
= stream_getc(s
);
2290 if (LEN_LEFT
< attr
->mp_nexthop_len
) {
2292 "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
2293 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2294 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2297 /* Nexthop length check. */
2298 switch (attr
->mp_nexthop_len
) {
2300 if (safi
!= SAFI_FLOWSPEC
) {
2301 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2302 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2303 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2306 case BGP_ATTR_NHLEN_VPNV4
:
2307 stream_getl(s
); /* RD high */
2308 stream_getl(s
); /* RD low */
2310 * NOTE: intentional fall through
2311 * - for consistency in rx processing
2313 * The following comment is to signal GCC this intention
2314 * and suppress the warning
2317 case BGP_ATTR_NHLEN_IPV4
:
2318 stream_get(&attr
->mp_nexthop_global_in
, s
, IPV4_MAX_BYTELEN
);
2319 /* Probably needed for RFC 2283 */
2320 if (attr
->nexthop
.s_addr
== INADDR_ANY
)
2321 memcpy(&attr
->nexthop
.s_addr
,
2322 &attr
->mp_nexthop_global_in
, IPV4_MAX_BYTELEN
);
2324 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
2325 case BGP_ATTR_NHLEN_VPNV6_GLOBAL
:
2326 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL
) {
2327 stream_getl(s
); /* RD high */
2328 stream_getl(s
); /* RD low */
2330 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2331 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2332 if (!peer
->nexthop
.ifp
) {
2333 zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2335 return BGP_ATTR_PARSE_WITHDRAW
;
2337 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2340 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
2341 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
:
2342 if (attr
->mp_nexthop_len
2343 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2344 stream_getl(s
); /* RD high */
2345 stream_getl(s
); /* RD low */
2347 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2348 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2349 if (!peer
->nexthop
.ifp
) {
2350 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",
2352 return BGP_ATTR_PARSE_WITHDRAW
;
2354 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2356 if (attr
->mp_nexthop_len
2357 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2358 stream_getl(s
); /* RD high */
2359 stream_getl(s
); /* RD low */
2361 stream_get(&attr
->mp_nexthop_local
, s
, IPV6_MAX_BYTELEN
);
2362 if (!IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_local
)) {
2363 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2365 "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
2366 peer
->host
, &attr
->mp_nexthop_global
,
2367 &attr
->mp_nexthop_local
);
2369 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
2371 if (!peer
->nexthop
.ifp
) {
2372 zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
2374 return BGP_ATTR_PARSE_WITHDRAW
;
2376 attr
->nh_lla_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2379 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2380 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2381 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2385 zlog_info("%s: %s sent SNPA which couldn't be read",
2386 __func__
, peer
->host
);
2387 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2392 if ((val
= stream_getc(s
)))
2394 EC_BGP_DEFUNCT_SNPA_LEN
,
2395 "%s sent non-zero value, %u, for defunct SNPA-length field",
2399 /* must have nrli_len, what is left of the attribute */
2400 nlri_len
= LEN_LEFT
;
2401 if (nlri_len
> STREAM_READABLE(s
)) {
2402 zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
2403 __func__
, peer
->host
);
2404 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2408 zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
2409 __func__
, peer
->host
);
2411 mp_update
->afi
= afi
;
2412 mp_update
->safi
= safi
;
2413 return BGP_ATTR_PARSE_EOR
;
2416 mp_update
->afi
= afi
;
2417 mp_update
->safi
= safi
;
2418 mp_update
->nlri
= stream_pnt(s
);
2419 mp_update
->length
= nlri_len
;
2421 stream_forward_getp(s
, nlri_len
);
2423 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
);
2425 return BGP_ATTR_PARSE_PROCEED
;
2429 /* Multiprotocol unreachable parse */
2430 int bgp_mp_unreach_parse(struct bgp_attr_parser_args
*args
,
2431 struct bgp_nlri
*mp_withdraw
)
2436 iana_safi_t pkt_safi
;
2438 uint16_t withdraw_len
;
2439 struct peer
*const peer
= args
->peer
;
2440 struct attr
*const attr
= args
->attr
;
2441 const bgp_size_t length
= args
->length
;
2445 #define BGP_MP_UNREACH_MIN_SIZE 3
2446 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
2447 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2449 pkt_afi
= stream_getw(s
);
2450 pkt_safi
= stream_getc(s
);
2452 /* Convert AFI, SAFI to internal values, check. */
2453 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2454 /* Log if AFI or SAFI is unrecognized. This is not an error
2456 * the attribute is otherwise malformed.
2458 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2460 "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
2461 peer
->host
, iana_afi2str(pkt_afi
),
2462 iana_safi2str(pkt_safi
));
2463 return BGP_ATTR_PARSE_ERROR
;
2466 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
2468 mp_withdraw
->afi
= afi
;
2469 mp_withdraw
->safi
= safi
;
2470 mp_withdraw
->nlri
= stream_pnt(s
);
2471 mp_withdraw
->length
= withdraw_len
;
2473 stream_forward_getp(s
, withdraw_len
);
2475 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
);
2477 return BGP_ATTR_PARSE_PROCEED
;
2480 /* Large Community attribute. */
2481 static enum bgp_attr_parse_ret
2482 bgp_attr_large_community(struct bgp_attr_parser_args
*args
)
2484 struct peer
*const peer
= args
->peer
;
2485 struct attr
*const attr
= args
->attr
;
2486 const bgp_size_t length
= args
->length
;
2489 * Large community follows new attribute format.
2492 bgp_attr_set_lcommunity(attr
, NULL
);
2493 /* Empty extcomm doesn't seem to be invalid per se */
2494 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2498 if (peer
->discard_attrs
[args
->type
])
2499 goto large_community_ignore
;
2501 bgp_attr_set_lcommunity(
2502 attr
, lcommunity_parse(stream_pnt(peer
->curr
), length
));
2503 /* XXX: fix ecommunity_parse to use stream API */
2504 stream_forward_getp(peer
->curr
, length
);
2506 if (!bgp_attr_get_lcommunity(attr
))
2507 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2510 return BGP_ATTR_PARSE_PROCEED
;
2512 large_community_ignore
:
2513 stream_forward_getp(peer
->curr
, length
);
2515 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2516 zlog_debug("%pBP: Ignoring attribute %s", peer
,
2517 lookup_msg(attr_str
, args
->type
, NULL
));
2519 return BGP_ATTR_PARSE_PROCEED
;
2522 /* Extended Community attribute. */
2523 static enum bgp_attr_parse_ret
2524 bgp_attr_ext_communities(struct bgp_attr_parser_args
*args
)
2526 struct peer
*const peer
= args
->peer
;
2527 struct attr
*const attr
= args
->attr
;
2528 const bgp_size_t length
= args
->length
;
2531 struct ecommunity
*ecomm
;
2534 bgp_attr_set_ecommunity(attr
, NULL
);
2535 /* Empty extcomm doesn't seem to be invalid per se */
2536 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2540 ecomm
= ecommunity_parse(
2541 stream_pnt(peer
->curr
), length
,
2542 CHECK_FLAG(peer
->flags
,
2543 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2544 bgp_attr_set_ecommunity(attr
, ecomm
);
2545 /* XXX: fix ecommunity_parse to use stream API */
2546 stream_forward_getp(peer
->curr
, length
);
2548 /* The Extended Community attribute SHALL be considered malformed if
2549 * its length is not a non-zero multiple of 8.
2551 if (!bgp_attr_get_ecommunity(attr
))
2552 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2555 /* Extract DF election preference and mobility sequence number */
2556 attr
->df_pref
= bgp_attr_df_pref_from_ec(attr
, &attr
->df_alg
);
2558 /* Extract MAC mobility sequence number, if any. */
2559 attr
->mm_seqnum
= bgp_attr_mac_mobility_seqnum(attr
, &sticky
);
2560 attr
->sticky
= sticky
;
2562 /* Check if this is a Gateway MAC-IP advertisement */
2563 attr
->default_gw
= bgp_attr_default_gw(attr
);
2565 /* Handle scenario where router flag ecommunity is not
2566 * set but default gw ext community is present.
2567 * Use default gateway, set and propogate R-bit.
2569 if (attr
->default_gw
)
2570 attr
->router_flag
= 1;
2572 /* Check EVPN Neighbor advertisement flags, R-bit */
2573 bgp_attr_evpn_na_flag(attr
, &attr
->router_flag
, &proxy
);
2575 attr
->es_flags
|= ATTR_ES_PROXY_ADVERT
;
2577 /* Extract the Rmac, if any */
2578 if (bgp_attr_rmac(attr
, &attr
->rmac
)) {
2579 if (bgp_debug_update(peer
, NULL
, NULL
, 1)
2580 && bgp_mac_exist(&attr
->rmac
))
2581 zlog_debug("%s: router mac %pEA is self mac", __func__
,
2585 /* Get the tunnel type from encap extended community */
2586 bgp_attr_extcom_tunnel_type(attr
,
2587 (bgp_encap_types
*)&attr
->encap_tunneltype
);
2589 /* Extract link bandwidth, if any. */
2590 (void)ecommunity_linkbw_present(bgp_attr_get_ecommunity(attr
),
2593 return BGP_ATTR_PARSE_PROCEED
;
2596 /* IPv6 Extended Community attribute. */
2597 static enum bgp_attr_parse_ret
2598 bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args
*args
)
2600 struct peer
*const peer
= args
->peer
;
2601 struct attr
*const attr
= args
->attr
;
2602 const bgp_size_t length
= args
->length
;
2603 struct ecommunity
*ipv6_ecomm
= NULL
;
2606 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2607 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2611 if (peer
->discard_attrs
[args
->type
])
2612 goto ipv6_ext_community_ignore
;
2614 ipv6_ecomm
= ecommunity_parse_ipv6(
2615 stream_pnt(peer
->curr
), length
,
2616 CHECK_FLAG(peer
->flags
,
2617 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2618 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2620 /* XXX: fix ecommunity_parse to use stream API */
2621 stream_forward_getp(peer
->curr
, length
);
2624 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2627 return BGP_ATTR_PARSE_PROCEED
;
2629 ipv6_ext_community_ignore
:
2630 stream_forward_getp(peer
->curr
, length
);
2632 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2633 zlog_debug("%pBP: Ignoring attribute %s", peer
,
2634 lookup_msg(attr_str
, args
->type
, NULL
));
2636 return BGP_ATTR_PARSE_PROCEED
;
2639 /* Parse Tunnel Encap attribute in an UPDATE */
2640 static int bgp_attr_encap(uint8_t type
, struct peer
*peer
, /* IN */
2641 bgp_size_t length
, /* IN: attr's length field */
2642 struct attr
*attr
, /* IN: caller already allocated */
2643 uint8_t flag
, /* IN: attr's flags field */
2647 uint16_t tunneltype
= 0;
2649 total
= length
+ (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
2651 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
)
2652 || !CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
2654 "Tunnel Encap attribute flag isn't optional and transitive %d",
2656 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2657 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
2662 if (BGP_ATTR_ENCAP
== type
) {
2663 /* read outer TLV type and length */
2664 uint16_t tlv_length
;
2668 "Tunnel Encap attribute not long enough to contain outer T,L");
2669 bgp_notify_send_with_data(
2670 peer
, BGP_NOTIFY_UPDATE_ERR
,
2671 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2674 tunneltype
= stream_getw(BGP_INPUT(peer
));
2675 tlv_length
= stream_getw(BGP_INPUT(peer
));
2678 if (tlv_length
!= length
) {
2679 zlog_info("%s: tlv_length(%d) != length(%d)",
2680 __func__
, tlv_length
, length
);
2684 while (length
>= 4) {
2685 uint16_t subtype
= 0;
2686 uint16_t sublength
= 0;
2687 struct bgp_attr_encap_subtlv
*tlv
;
2689 if (BGP_ATTR_ENCAP
== type
) {
2690 subtype
= stream_getc(BGP_INPUT(peer
));
2691 sublength
= stream_getc(BGP_INPUT(peer
));
2693 #ifdef ENABLE_BGP_VNC
2695 subtype
= stream_getw(BGP_INPUT(peer
));
2696 sublength
= stream_getw(BGP_INPUT(peer
));
2701 if (sublength
> length
) {
2703 "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2705 bgp_notify_send_with_data(
2706 peer
, BGP_NOTIFY_UPDATE_ERR
,
2707 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2711 /* alloc and copy sub-tlv */
2712 /* TBD make sure these are freed when attributes are released */
2713 tlv
= XCALLOC(MTYPE_ENCAP_TLV
,
2714 sizeof(struct bgp_attr_encap_subtlv
) + sublength
);
2715 tlv
->type
= subtype
;
2716 tlv
->length
= sublength
;
2717 stream_get(tlv
->value
, peer
->curr
, sublength
);
2718 length
-= sublength
;
2720 /* attach tlv to encap chain */
2721 if (BGP_ATTR_ENCAP
== type
) {
2722 struct bgp_attr_encap_subtlv
*stlv_last
;
2723 for (stlv_last
= attr
->encap_subtlvs
;
2724 stlv_last
&& stlv_last
->next
;
2725 stlv_last
= stlv_last
->next
)
2728 stlv_last
->next
= tlv
;
2730 attr
->encap_subtlvs
= tlv
;
2732 #ifdef ENABLE_BGP_VNC
2734 struct bgp_attr_encap_subtlv
*stlv_last
;
2735 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
2736 bgp_attr_get_vnc_subtlvs(attr
);
2738 for (stlv_last
= vnc_subtlvs
;
2739 stlv_last
&& stlv_last
->next
;
2740 stlv_last
= stlv_last
->next
)
2743 stlv_last
->next
= tlv
;
2745 bgp_attr_set_vnc_subtlvs(attr
, tlv
);
2750 if (BGP_ATTR_ENCAP
== type
) {
2751 attr
->encap_tunneltype
= tunneltype
;
2755 /* spurious leftover data */
2757 "Tunnel Encap attribute length is bad: %d leftover octets",
2759 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2760 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2769 /* SRv6 Service Data Sub-Sub-TLV attribute
2770 * draft-ietf-bess-srv6-services-07
2772 static enum bgp_attr_parse_ret
2773 bgp_attr_srv6_service_data(struct bgp_attr_parser_args
*args
)
2775 struct peer
*const peer
= args
->peer
;
2776 struct attr
*const attr
= args
->attr
;
2777 uint8_t type
, loc_block_len
, loc_node_len
, func_len
, arg_len
,
2778 transposition_len
, transposition_offset
;
2780 size_t headersz
= sizeof(type
) + sizeof(length
);
2782 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2785 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2786 headersz
, STREAM_READABLE(peer
->curr
));
2787 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2791 type
= stream_getc(peer
->curr
);
2792 length
= stream_getw(peer
->curr
);
2794 if (STREAM_READABLE(peer
->curr
) < length
) {
2797 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2798 length
, STREAM_READABLE(peer
->curr
));
2799 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2803 if (length
< BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
) {
2806 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %hu remaining in UPDATE)",
2807 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
,
2809 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2813 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
) {
2814 if (STREAM_READABLE(peer
->curr
) <
2815 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
) {
2818 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %zu remaining in UPDATE)",
2819 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
,
2820 STREAM_READABLE(peer
->curr
));
2821 return bgp_attr_malformed(
2822 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2826 loc_block_len
= stream_getc(peer
->curr
);
2827 loc_node_len
= stream_getc(peer
->curr
);
2828 func_len
= stream_getc(peer
->curr
);
2829 arg_len
= stream_getc(peer
->curr
);
2830 transposition_len
= stream_getc(peer
->curr
);
2831 transposition_offset
= stream_getc(peer
->curr
);
2833 /* Log SRv6 Service Data Sub-Sub-TLV */
2834 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2836 "%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",
2837 __func__
, loc_block_len
, loc_node_len
, func_len
,
2838 arg_len
, transposition_len
,
2839 transposition_offset
);
2842 attr
->srv6_l3vpn
->loc_block_len
= loc_block_len
;
2843 attr
->srv6_l3vpn
->loc_node_len
= loc_node_len
;
2844 attr
->srv6_l3vpn
->func_len
= func_len
;
2845 attr
->srv6_l3vpn
->arg_len
= arg_len
;
2846 attr
->srv6_l3vpn
->transposition_len
= transposition_len
;
2847 attr
->srv6_l3vpn
->transposition_offset
= transposition_offset
;
2851 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2853 "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
2856 stream_forward_getp(peer
->curr
, length
);
2859 return BGP_ATTR_PARSE_PROCEED
;
2862 /* SRv6 Service Sub-TLV attribute
2863 * draft-ietf-bess-srv6-services-07
2865 static enum bgp_attr_parse_ret
2866 bgp_attr_srv6_service(struct bgp_attr_parser_args
*args
)
2868 struct peer
*const peer
= args
->peer
;
2869 struct attr
*const attr
= args
->attr
;
2870 struct in6_addr ipv6_sid
;
2871 uint8_t type
, sid_flags
;
2872 uint16_t length
, endpoint_behavior
;
2873 size_t headersz
= sizeof(type
) + sizeof(length
);
2874 enum bgp_attr_parse_ret err
;
2876 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2879 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2880 headersz
, STREAM_READABLE(peer
->curr
));
2881 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2885 type
= stream_getc(peer
->curr
);
2886 length
= stream_getw(peer
->curr
);
2888 if (STREAM_READABLE(peer
->curr
) < length
) {
2891 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2892 length
, STREAM_READABLE(peer
->curr
));
2893 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2897 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
) {
2898 if (STREAM_READABLE(peer
->curr
) <
2899 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
) {
2902 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %d for attribute data, have %zu remaining in UPDATE)",
2903 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
,
2904 STREAM_READABLE(peer
->curr
));
2905 return bgp_attr_malformed(
2906 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2909 stream_getc(peer
->curr
);
2910 stream_get(&ipv6_sid
, peer
->curr
, sizeof(ipv6_sid
));
2911 sid_flags
= stream_getc(peer
->curr
);
2912 endpoint_behavior
= stream_getw(peer
->curr
);
2913 stream_getc(peer
->curr
);
2915 /* Log SRv6 Service Sub-TLV */
2916 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
))
2918 "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x",
2919 __func__
, &ipv6_sid
, sid_flags
,
2922 /* Configure from Info */
2923 if (attr
->srv6_l3vpn
) {
2924 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2925 "Prefix SID SRv6 L3VPN field repeated");
2926 return bgp_attr_malformed(
2927 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2929 attr
->srv6_l3vpn
= XCALLOC(MTYPE_BGP_SRV6_L3VPN
,
2930 sizeof(struct bgp_attr_srv6_l3vpn
));
2931 sid_copy(&attr
->srv6_l3vpn
->sid
, &ipv6_sid
);
2932 attr
->srv6_l3vpn
->sid_flags
= sid_flags
;
2933 attr
->srv6_l3vpn
->endpoint_behavior
= endpoint_behavior
;
2934 attr
->srv6_l3vpn
->loc_block_len
= 0;
2935 attr
->srv6_l3vpn
->loc_node_len
= 0;
2936 attr
->srv6_l3vpn
->func_len
= 0;
2937 attr
->srv6_l3vpn
->arg_len
= 0;
2938 attr
->srv6_l3vpn
->transposition_len
= 0;
2939 attr
->srv6_l3vpn
->transposition_offset
= 0;
2941 // Sub-Sub-TLV found
2942 if (length
> BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
) {
2943 err
= bgp_attr_srv6_service_data(args
);
2945 if (err
!= BGP_ATTR_PARSE_PROCEED
)
2949 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
2952 /* Placeholder code for unsupported type */
2954 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2956 "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
2959 stream_forward_getp(peer
->curr
, length
);
2962 return BGP_ATTR_PARSE_PROCEED
;
2966 * Read an individual SID value returning how much data we have read
2967 * Returns 0 if there was an error that needs to be passed up the stack
2969 static enum bgp_attr_parse_ret
2970 bgp_attr_psid_sub(uint8_t type
, uint16_t length
,
2971 struct bgp_attr_parser_args
*args
)
2973 struct peer
*const peer
= args
->peer
;
2974 struct attr
*const attr
= args
->attr
;
2975 uint32_t label_index
;
2976 struct in6_addr ipv6_sid
;
2978 uint32_t srgb_range
;
2980 uint8_t sid_type
, sid_flags
;
2983 * Check that we actually have at least as much data as
2984 * specified by the length field
2986 if (STREAM_READABLE(peer
->curr
) < length
) {
2989 "Prefix SID specifies length %hu, but only %zu bytes remain",
2990 length
, STREAM_READABLE(peer
->curr
));
2991 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2995 if (type
== BGP_PREFIX_SID_LABEL_INDEX
) {
2996 if (length
!= BGP_PREFIX_SID_LABEL_INDEX_LENGTH
) {
2997 flog_err(EC_BGP_ATTR_LEN
,
2998 "Prefix SID label index length is %hu instead of %u",
2999 length
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
3000 return bgp_attr_malformed(args
,
3001 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3005 /* Ignore flags and reserved */
3006 stream_getc(peer
->curr
);
3007 stream_getw(peer
->curr
);
3009 /* Fetch the label index and see if it is valid. */
3010 label_index
= stream_getl(peer
->curr
);
3011 if (label_index
== BGP_INVALID_LABEL_INDEX
)
3012 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
3015 /* Store label index; subsequently, we'll check on
3017 attr
->label_index
= label_index
;
3018 } else if (type
== BGP_PREFIX_SID_IPV6
) {
3019 if (length
!= BGP_PREFIX_SID_IPV6_LENGTH
) {
3020 flog_err(EC_BGP_ATTR_LEN
,
3021 "Prefix SID IPv6 length is %hu instead of %u",
3022 length
, BGP_PREFIX_SID_IPV6_LENGTH
);
3023 return bgp_attr_malformed(args
,
3024 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3028 /* Ignore reserved */
3029 stream_getc(peer
->curr
);
3030 stream_getw(peer
->curr
);
3032 stream_get(&ipv6_sid
, peer
->curr
, 16);
3033 } else if (type
== BGP_PREFIX_SID_ORIGINATOR_SRGB
) {
3035 * ietf-idr-bgp-prefix-sid-05:
3036 * Length is the total length of the value portion of the
3037 * TLV: 2 + multiple of 6.
3039 * peer->curr stream readp should be at the beginning of the 16
3040 * bit flag field at this point in the code.
3044 * Check that the TLV length field is sane: at least 2 bytes of
3045 * flag, and at least 1 SRGB (these are 6 bytes each)
3047 if (length
< (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
)) {
3050 "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
3052 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
3053 return bgp_attr_malformed(
3054 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3059 * Check that the portion of the TLV containing the sequence of
3060 * SRGBs corresponds to a multiple of the SRGB size; to get
3061 * that length, we skip the 16 bit flags field
3063 stream_getw(peer
->curr
);
3065 if (length
% BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
) {
3068 "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
3069 length
, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
3070 return bgp_attr_malformed(
3071 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3075 srgb_count
= length
/ BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
;
3077 for (int i
= 0; i
< srgb_count
; i
++) {
3078 stream_get(&srgb_base
, peer
->curr
, 3);
3079 stream_get(&srgb_range
, peer
->curr
, 3);
3081 } else if (type
== BGP_PREFIX_SID_VPN_SID
) {
3082 if (length
!= BGP_PREFIX_SID_VPN_SID_LENGTH
) {
3083 flog_err(EC_BGP_ATTR_LEN
,
3084 "Prefix SID VPN SID length is %hu instead of %u",
3085 length
, BGP_PREFIX_SID_VPN_SID_LENGTH
);
3086 return bgp_attr_malformed(args
,
3087 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3091 /* Parse VPN-SID Sub-TLV */
3092 stream_getc(peer
->curr
); /* reserved */
3093 sid_type
= stream_getc(peer
->curr
); /* sid_type */
3094 sid_flags
= stream_getc(peer
->curr
); /* sid_flags */
3095 stream_get(&ipv6_sid
, peer
->curr
,
3096 sizeof(ipv6_sid
)); /* sid_value */
3098 /* Log VPN-SID Sub-TLV */
3099 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
))
3101 "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x",
3102 __func__
, &ipv6_sid
, sid_type
, sid_flags
);
3104 /* Configure from Info */
3105 if (attr
->srv6_vpn
) {
3106 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
3107 "Prefix SID SRv6 VPN field repeated");
3108 return bgp_attr_malformed(
3109 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
3111 attr
->srv6_vpn
= XCALLOC(MTYPE_BGP_SRV6_VPN
,
3112 sizeof(struct bgp_attr_srv6_vpn
));
3113 attr
->srv6_vpn
->sid_flags
= sid_flags
;
3114 sid_copy(&attr
->srv6_vpn
->sid
, &ipv6_sid
);
3115 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
3116 } else if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE
) {
3117 if (STREAM_READABLE(peer
->curr
) < 1) {
3120 "Prefix SID SRV6 L3 Service not enough data left, it must be at least 1 byte");
3121 return bgp_attr_malformed(
3122 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3125 /* ignore reserved */
3126 stream_getc(peer
->curr
);
3128 return bgp_attr_srv6_service(args
);
3130 /* Placeholder code for Unsupported TLV */
3132 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3134 "%s attr Prefix-SID sub-type=%u is not supported, skipped",
3137 stream_forward_getp(peer
->curr
, length
);
3140 return BGP_ATTR_PARSE_PROCEED
;
3143 /* Prefix SID attribute
3144 * draft-ietf-idr-bgp-prefix-sid-05
3146 enum bgp_attr_parse_ret
bgp_attr_prefix_sid(struct bgp_attr_parser_args
*args
)
3148 struct peer
*const peer
= args
->peer
;
3149 struct attr
*const attr
= args
->attr
;
3150 enum bgp_attr_parse_ret ret
;
3152 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
);
3156 size_t headersz
= sizeof(type
) + sizeof(length
);
3157 size_t psid_parsed_length
= 0;
3159 while (STREAM_READABLE(peer
->curr
) > 0
3160 && psid_parsed_length
< args
->length
) {
3162 if (STREAM_READABLE(peer
->curr
) < headersz
) {
3165 "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
3166 headersz
, STREAM_READABLE(peer
->curr
));
3167 return bgp_attr_malformed(
3168 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3172 type
= stream_getc(peer
->curr
);
3173 length
= stream_getw(peer
->curr
);
3175 if (STREAM_READABLE(peer
->curr
) < length
) {
3178 "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
3179 length
, STREAM_READABLE(peer
->curr
));
3180 return bgp_attr_malformed(args
,
3181 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3185 ret
= bgp_attr_psid_sub(type
, length
, args
);
3187 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3190 psid_parsed_length
+= length
+ headersz
;
3192 if (psid_parsed_length
> args
->length
) {
3195 "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
3196 length
+ headersz
, psid_parsed_length
- (length
+ headersz
));
3197 return bgp_attr_malformed(
3198 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3203 return BGP_ATTR_PARSE_PROCEED
;
3206 /* PMSI tunnel attribute (RFC 6514)
3207 * Basic validation checks done here.
3209 static enum bgp_attr_parse_ret
3210 bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args
*args
)
3212 struct peer
*const peer
= args
->peer
;
3213 struct attr
*const attr
= args
->attr
;
3214 const bgp_size_t length
= args
->length
;
3216 int attr_parse_len
= 2 + BGP_LABEL_BYTES
;
3218 /* Verify that the receiver is expecting "ingress replication" as we
3219 * can only support that.
3221 if (length
< attr_parse_len
) {
3222 flog_err(EC_BGP_ATTR_LEN
, "Bad PMSI tunnel attribute length %d",
3224 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3227 stream_getc(peer
->curr
); /* Flags */
3228 tnl_type
= stream_getc(peer
->curr
);
3229 if (tnl_type
> PMSI_TNLTYPE_MAX
) {
3230 flog_err(EC_BGP_ATTR_PMSI_TYPE
,
3231 "Invalid PMSI tunnel attribute type %d", tnl_type
);
3232 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
3235 if (tnl_type
== PMSI_TNLTYPE_INGR_REPL
) {
3237 flog_err(EC_BGP_ATTR_PMSI_LEN
,
3238 "Bad PMSI tunnel attribute length %d for IR",
3240 return bgp_attr_malformed(
3241 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3246 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
);
3247 bgp_attr_set_pmsi_tnl_type(attr
, tnl_type
);
3248 stream_get(&attr
->label
, peer
->curr
, BGP_LABEL_BYTES
);
3250 /* Forward read pointer of input stream. */
3251 stream_forward_getp(peer
->curr
, length
- attr_parse_len
);
3253 return BGP_ATTR_PARSE_PROCEED
;
3256 /* AIGP attribute (rfc7311) */
3257 static enum bgp_attr_parse_ret
bgp_attr_aigp(struct bgp_attr_parser_args
*args
)
3259 struct peer
*const peer
= args
->peer
;
3260 struct attr
*const attr
= args
->attr
;
3261 const bgp_size_t length
= args
->length
;
3262 uint8_t *s
= stream_pnt(peer
->curr
);
3265 /* If an AIGP attribute is received on a BGP session for which
3266 * AIGP_SESSION is disabled, the attribute MUST be treated exactly
3267 * as if it were an unrecognized non-transitive attribute.
3268 * That is, it "MUST be quietly ignored and not passed along to
3270 * For Internal BGP (IBGP) sessions, and for External BGP (EBGP)
3271 * sessions between members of the same BGP Confederation,
3272 * the default value of AIGP_SESSION SHOULD be "enabled".
3274 if (peer
->sort
== BGP_PEER_EBGP
&&
3275 !CHECK_FLAG(peer
->flags
, PEER_FLAG_AIGP
)) {
3277 "%pBP received AIGP attribute, but eBGP peer do not support it",
3282 if (peer
->discard_attrs
[args
->type
])
3285 if (!bgp_attr_aigp_valid(s
, length
))
3288 /* Extract AIGP Metric TLV */
3289 if (bgp_attr_aigp_get_tlv_metric(s
, length
, &aigp
))
3290 bgp_attr_set_aigp_metric(attr
, aigp
);
3293 stream_forward_getp(peer
->curr
, length
);
3295 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3296 zlog_debug("%pBP: Ignoring attribute %s", peer
,
3297 lookup_msg(attr_str
, args
->type
, NULL
));
3299 return BGP_ATTR_PARSE_PROCEED
;
3302 /* OTC attribute. */
3303 static enum bgp_attr_parse_ret
bgp_attr_otc(struct bgp_attr_parser_args
*args
)
3305 struct peer
*const peer
= args
->peer
;
3306 struct attr
*const attr
= args
->attr
;
3307 const bgp_size_t length
= args
->length
;
3311 flog_err(EC_BGP_ATTR_LEN
, "OTC attribute length isn't 4 [%u]",
3313 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3317 if (peer
->discard_attrs
[args
->type
])
3320 attr
->otc
= stream_getl(peer
->curr
);
3322 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "OTC attribute value is 0");
3323 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
3327 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_OTC
);
3329 return BGP_ATTR_PARSE_PROCEED
;
3332 stream_forward_getp(peer
->curr
, length
);
3334 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3335 zlog_debug("%pBP: Ignoring attribute %s", peer
,
3336 lookup_msg(attr_str
, args
->type
, NULL
));
3338 return BGP_ATTR_PARSE_PROCEED
;
3341 /* BGP unknown attribute treatment. */
3342 static enum bgp_attr_parse_ret
3343 bgp_attr_unknown(struct bgp_attr_parser_args
*args
)
3345 bgp_size_t total
= args
->total
;
3346 struct transit
*transit
;
3347 struct peer
*const peer
= args
->peer
;
3348 struct attr
*const attr
= args
->attr
;
3349 uint8_t *const startp
= args
->startp
;
3350 const uint8_t type
= args
->type
;
3351 const uint8_t flag
= args
->flags
;
3352 const bgp_size_t length
= args
->length
;
3354 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3356 "%s Unknown attribute is received (type %d, length %d)",
3357 peer
->host
, type
, length
);
3359 /* Forward read pointer of input stream. */
3360 stream_forward_getp(peer
->curr
, length
);
3362 if (peer
->discard_attrs
[type
]) {
3363 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3364 zlog_debug("%pBP: Ignoring attribute %s", peer
,
3365 lookup_msg(attr_str
, args
->type
, NULL
));
3367 return BGP_ATTR_PARSE_PROCEED
;
3370 /* If any of the mandatory well-known attributes are not recognized,
3371 then the Error Subcode is set to Unrecognized Well-known
3372 Attribute. The Data field contains the unrecognized attribute
3373 (type, length and value). */
3374 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
3375 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_UNREC_ATTR
,
3379 /* Unrecognized non-transitive optional attributes must be quietly
3380 ignored and not passed along to other BGP peers. */
3381 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
))
3382 return BGP_ATTR_PARSE_PROCEED
;
3384 /* If a path with recognized transitive optional attribute is
3385 accepted and passed along to other BGP peers and the Partial bit
3386 in the Attribute Flags octet is set to 1 by some previous AS, it
3387 is not set back to 0 by the current AS. */
3388 SET_FLAG(*startp
, BGP_ATTR_FLAG_PARTIAL
);
3390 /* Store transitive attribute to the end of attr->transit. */
3391 transit
= bgp_attr_get_transit(attr
);
3393 transit
= XCALLOC(MTYPE_TRANSIT
, sizeof(struct transit
));
3395 transit
->val
= XREALLOC(MTYPE_TRANSIT_VAL
, transit
->val
,
3396 transit
->length
+ total
);
3398 memcpy(transit
->val
+ transit
->length
, startp
, total
);
3399 transit
->length
+= total
;
3400 bgp_attr_set_transit(attr
, transit
);
3402 return BGP_ATTR_PARSE_PROCEED
;
3405 /* Well-known attribute check. */
3406 static int bgp_attr_check(struct peer
*peer
, struct attr
*attr
)
3410 /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
3412 if (CHECK_FLAG(peer
->cap
, PEER_CAP_RESTART_RCV
) && !attr
->flag
)
3413 return BGP_ATTR_PARSE_PROCEED
;
3415 /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
3416 to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
3417 are present, it should. Check for any other attribute being present
3420 if ((!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)) &&
3421 CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
))))
3422 return BGP_ATTR_PARSE_PROCEED
;
3424 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
)))
3425 type
= BGP_ATTR_ORIGIN
;
3427 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
3428 type
= BGP_ATTR_AS_PATH
;
3430 /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
3432 * NLRI is empty. We can't easily check NLRI empty here though.
3434 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3435 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)))
3436 type
= BGP_ATTR_NEXT_HOP
;
3438 if (peer
->sort
== BGP_PEER_IBGP
3439 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)))
3440 type
= BGP_ATTR_LOCAL_PREF
;
3442 /* If any of the well-known mandatory attributes are not present
3443 * in an UPDATE message, then "treat-as-withdraw" MUST be used.
3446 flog_warn(EC_BGP_MISSING_ATTRIBUTE
,
3447 "%s Missing well-known attribute %s.", peer
->host
,
3448 lookup_msg(attr_str
, type
, NULL
));
3449 return BGP_ATTR_PARSE_WITHDRAW
;
3451 return BGP_ATTR_PARSE_PROCEED
;
3454 /* Read attribute of update packet. This function is called from
3455 bgp_update_receive() in bgp_packet.c. */
3456 enum bgp_attr_parse_ret
bgp_attr_parse(struct peer
*peer
, struct attr
*attr
,
3458 struct bgp_nlri
*mp_update
,
3459 struct bgp_nlri
*mp_withdraw
)
3461 enum bgp_attr_parse_ret ret
;
3465 uint8_t *startp
, *endp
;
3467 uint8_t seen
[BGP_ATTR_BITMAP_SIZE
];
3468 /* we need the as4_path only until we have synthesized the as_path with
3470 /* same goes for as4_aggregator */
3471 struct aspath
*as4_path
= NULL
;
3472 as_t as4_aggregator
= 0;
3473 struct in_addr as4_aggregator_addr
= {.s_addr
= 0};
3474 struct transit
*transit
;
3476 /* Initialize bitmap. */
3477 memset(seen
, 0, BGP_ATTR_BITMAP_SIZE
);
3479 /* End pointer of BGP attribute. */
3480 endp
= BGP_INPUT_PNT(peer
) + size
;
3482 /* Get attributes to the end of attribute length. */
3483 while (BGP_INPUT_PNT(peer
) < endp
) {
3484 /* Check remaining length check.*/
3485 if (endp
- BGP_INPUT_PNT(peer
) < BGP_ATTR_MIN_LEN
) {
3486 /* XXX warning: long int format, int arg (arg 5) */
3488 EC_BGP_ATTRIBUTE_TOO_SMALL
,
3489 "%s: error BGP attribute length %lu is smaller than min len",
3491 (unsigned long)(endp
3492 - stream_pnt(BGP_INPUT(peer
))));
3494 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3495 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3496 ret
= BGP_ATTR_PARSE_ERROR
;
3500 /* Fetch attribute flag and type. */
3501 startp
= BGP_INPUT_PNT(peer
);
3502 /* "The lower-order four bits of the Attribute Flags octet are
3503 unused. They MUST be zero when sent and MUST be ignored when
3505 flag
= 0xF0 & stream_getc(BGP_INPUT(peer
));
3506 type
= stream_getc(BGP_INPUT(peer
));
3508 /* Check whether Extended-Length applies and is in bounds */
3509 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
)
3510 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1))) {
3512 EC_BGP_EXT_ATTRIBUTE_TOO_SMALL
,
3513 "%s: Extended length set, but just %lu bytes of attr header",
3515 (unsigned long)(endp
3516 - stream_pnt(BGP_INPUT(peer
))));
3518 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3519 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3520 ret
= BGP_ATTR_PARSE_ERROR
;
3524 /* Check extended attribue length bit. */
3525 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
))
3526 length
= stream_getw(BGP_INPUT(peer
));
3528 length
= stream_getc(BGP_INPUT(peer
));
3530 /* If any attribute appears more than once in the UPDATE
3531 message, then the Error Subcode is set to Malformed Attribute
3534 if (CHECK_BITMAP(seen
, type
)) {
3536 EC_BGP_ATTRIBUTE_REPEATED
,
3537 "%s: error BGP attribute type %d appears twice in a message",
3540 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3541 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3542 ret
= BGP_ATTR_PARSE_ERROR
;
3546 /* Set type to bitmap to check duplicate attribute. `type' is
3547 unsigned char so it never overflow bitmap range. */
3549 SET_BITMAP(seen
, type
);
3551 /* Overflow check. */
3552 attr_endp
= BGP_INPUT_PNT(peer
) + length
;
3554 if (attr_endp
> endp
) {
3556 EC_BGP_ATTRIBUTE_TOO_LARGE
,
3557 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
3558 peer
->host
, type
, length
, size
, attr_endp
,
3562 * If any recognized attribute has an Attribute
3563 * Length that conflicts with the expected length
3564 * (based on the attribute type code), then the
3565 * Error Subcode MUST be set to Attribute Length
3566 * Error. The Data field MUST contain the erroneous
3567 * attribute (type, length, and value).
3569 * We do not currently have a good way to determine the
3570 * length of the attribute independent of the length
3571 * received in the message. Instead we send the
3572 * minimum between the amount of data we have and the
3573 * amount specified by the attribute length field.
3575 * Instead of directly passing in the packet buffer and
3576 * offset we use the stream_get* functions to read into
3577 * a stack buffer, since they perform bounds checking
3578 * and we are working with untrusted data.
3580 unsigned char ndata
[peer
->max_packet_size
];
3581 memset(ndata
, 0x00, sizeof(ndata
));
3583 CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 2 : 1;
3584 /* Rewind to end of flag field */
3585 stream_rewind_getp(BGP_INPUT(peer
), (1 + lfl
));
3587 stream_get(&ndata
[0], BGP_INPUT(peer
), 1);
3589 stream_get(&ndata
[1], BGP_INPUT(peer
), lfl
);
3591 size_t atl
= attr_endp
- startp
;
3592 size_t ndl
= MIN(atl
, STREAM_READABLE(BGP_INPUT(peer
)));
3593 stream_get(&ndata
[lfl
+ 1], BGP_INPUT(peer
), ndl
);
3595 bgp_notify_send_with_data(
3596 peer
, BGP_NOTIFY_UPDATE_ERR
,
3597 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
, ndata
,
3600 ret
= BGP_ATTR_PARSE_ERROR
;
3604 struct bgp_attr_parser_args attr_args
= {
3611 .total
= attr_endp
- startp
,
3615 /* If any recognized attribute has Attribute Flags that conflict
3616 with the Attribute Type Code, then the Error Subcode is set
3618 Attribute Flags Error. The Data field contains the erroneous
3619 attribute (type, length and value). */
3620 if (bgp_attr_flag_invalid(&attr_args
)) {
3621 ret
= bgp_attr_malformed(
3622 &attr_args
, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
3624 if (ret
== BGP_ATTR_PARSE_PROCEED
)
3629 /* OK check attribute and store it's value. */
3631 case BGP_ATTR_ORIGIN
:
3632 ret
= bgp_attr_origin(&attr_args
);
3634 case BGP_ATTR_AS_PATH
:
3635 ret
= bgp_attr_aspath(&attr_args
);
3637 case BGP_ATTR_AS4_PATH
:
3638 ret
= bgp_attr_as4_path(&attr_args
, &as4_path
);
3640 case BGP_ATTR_NEXT_HOP
:
3641 ret
= bgp_attr_nexthop(&attr_args
);
3643 case BGP_ATTR_MULTI_EXIT_DISC
:
3644 ret
= bgp_attr_med(&attr_args
);
3646 case BGP_ATTR_LOCAL_PREF
:
3647 ret
= bgp_attr_local_pref(&attr_args
);
3649 case BGP_ATTR_ATOMIC_AGGREGATE
:
3650 ret
= bgp_attr_atomic(&attr_args
);
3652 case BGP_ATTR_AGGREGATOR
:
3653 ret
= bgp_attr_aggregator(&attr_args
);
3655 case BGP_ATTR_AS4_AGGREGATOR
:
3656 ret
= bgp_attr_as4_aggregator(&attr_args
,
3658 &as4_aggregator_addr
);
3660 case BGP_ATTR_COMMUNITIES
:
3661 ret
= bgp_attr_community(&attr_args
);
3663 case BGP_ATTR_LARGE_COMMUNITIES
:
3664 ret
= bgp_attr_large_community(&attr_args
);
3666 case BGP_ATTR_ORIGINATOR_ID
:
3667 ret
= bgp_attr_originator_id(&attr_args
);
3669 case BGP_ATTR_CLUSTER_LIST
:
3670 ret
= bgp_attr_cluster_list(&attr_args
);
3672 case BGP_ATTR_MP_REACH_NLRI
:
3673 ret
= bgp_mp_reach_parse(&attr_args
, mp_update
);
3675 case BGP_ATTR_MP_UNREACH_NLRI
:
3676 ret
= bgp_mp_unreach_parse(&attr_args
, mp_withdraw
);
3678 case BGP_ATTR_EXT_COMMUNITIES
:
3679 ret
= bgp_attr_ext_communities(&attr_args
);
3681 #ifdef ENABLE_BGP_VNC_ATTR
3684 case BGP_ATTR_ENCAP
:
3685 ret
= bgp_attr_encap(type
, peer
, length
, attr
, flag
,
3688 case BGP_ATTR_PREFIX_SID
:
3689 ret
= bgp_attr_prefix_sid(&attr_args
);
3691 case BGP_ATTR_PMSI_TUNNEL
:
3692 ret
= bgp_attr_pmsi_tunnel(&attr_args
);
3694 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
3695 ret
= bgp_attr_ipv6_ext_communities(&attr_args
);
3698 ret
= bgp_attr_otc(&attr_args
);
3701 ret
= bgp_attr_aigp(&attr_args
);
3704 ret
= bgp_attr_unknown(&attr_args
);
3708 if (ret
== BGP_ATTR_PARSE_ERROR_NOTIFYPLS
) {
3709 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3710 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3711 ret
= BGP_ATTR_PARSE_ERROR
;
3715 if (ret
== BGP_ATTR_PARSE_EOR
) {
3719 if (ret
== BGP_ATTR_PARSE_ERROR
) {
3720 flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR
,
3721 "%s: Attribute %s, parse error", peer
->host
,
3722 lookup_msg(attr_str
, type
, NULL
));
3725 if (ret
== BGP_ATTR_PARSE_WITHDRAW
) {
3727 EC_BGP_ATTRIBUTE_PARSE_WITHDRAW
,
3728 "%s: Attribute %s, parse error - treating as withdrawal",
3729 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3733 /* Check the fetched length. */
3734 if (BGP_INPUT_PNT(peer
) != attr_endp
) {
3735 flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR
,
3736 "%s: BGP attribute %s, fetch error",
3737 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3738 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3739 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3740 ret
= BGP_ATTR_PARSE_ERROR
;
3746 * draft-ietf-idr-bgp-prefix-sid-27#section-3:
3747 * About Prefix-SID path attribute,
3748 * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
3749 * may only appear in a BGP Prefix-SID attribute attached to
3750 * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
3751 * It MUST be ignored when received for other BGP AFI/SAFI combinations.
3753 if (!attr
->mp_nexthop_len
|| mp_update
->safi
!= SAFI_LABELED_UNICAST
)
3754 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
3756 /* Check final read pointer is same as end pointer. */
3757 if (BGP_INPUT_PNT(peer
) != endp
) {
3758 flog_warn(EC_BGP_ATTRIBUTES_MISMATCH
,
3759 "%s: BGP attribute %s, length mismatch", peer
->host
,
3760 lookup_msg(attr_str
, type
, NULL
));
3761 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3762 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3764 ret
= BGP_ATTR_PARSE_ERROR
;
3769 * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
3770 * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
3771 * This is implemented below and will result in a NOTIFICATION. If the
3772 * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
3773 * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
3774 * message SHOULD NOT be sent. This is implemented elsewhere.
3776 * RFC4760: An UPDATE message that carries no NLRI, other than the one
3777 * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
3778 * attribute. If such a message contains the NEXT_HOP attribute, the BGP
3779 * speaker that receives the message SHOULD ignore this attribute.
3781 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3782 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
))) {
3783 if (bgp_attr_nexthop_valid(peer
, attr
) < 0) {
3784 ret
= BGP_ATTR_PARSE_ERROR
;
3789 /* Check all mandatory well-known attributes are present */
3790 ret
= bgp_attr_check(peer
, attr
);
3795 * At this place we can see whether we got AS4_PATH and/or
3796 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
3797 * We can not do this before we've read all attributes because
3798 * the as4 handling does not say whether AS4_PATH has to be sent
3799 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
3800 * in relationship to AGGREGATOR.
3801 * So, to be defensive, we are not relying on any order and read
3802 * all attributes first, including these 32bit ones, and now,
3803 * afterwards, we look what and if something is to be done for as4.
3805 * It is possible to not have AS_PATH, e.g. GR EoR and sole
3808 /* actually... this doesn't ever return failure currently, but
3809 * better safe than sorry */
3810 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))
3811 && bgp_attr_munge_as4_attrs(peer
, attr
, as4_path
, as4_aggregator
,
3812 &as4_aggregator_addr
)) {
3813 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3814 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3815 ret
= BGP_ATTR_PARSE_ERROR
;
3820 * Finally do the checks on the aspath we did not do yet
3821 * because we waited for a potentially synthesized aspath.
3823 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))) {
3824 ret
= bgp_attr_aspath_check(peer
, attr
);
3825 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3829 ret
= BGP_ATTR_PARSE_PROCEED
;
3833 * At this stage, we have done all fiddling with as4, and the
3834 * resulting info is in attr->aggregator resp. attr->aspath so
3835 * we can chuck as4_aggregator and as4_path alltogether in order
3839 * unintern - it is in the hash
3840 * The flag that we got this is still there, but that
3841 * does not do any trouble
3843 aspath_unintern(&as4_path
);
3845 transit
= bgp_attr_get_transit(attr
);
3846 if (ret
!= BGP_ATTR_PARSE_ERROR
) {
3847 /* Finally intern unknown attribute. */
3849 bgp_attr_set_transit(attr
, transit_intern(transit
));
3850 if (attr
->encap_subtlvs
)
3851 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
3853 #ifdef ENABLE_BGP_VNC
3854 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3855 bgp_attr_get_vnc_subtlvs(attr
);
3858 bgp_attr_set_vnc_subtlvs(
3860 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
3864 transit_free(transit
);
3865 bgp_attr_set_transit(attr
, NULL
);
3868 bgp_attr_flush_encap(attr
);
3872 transit
= bgp_attr_get_transit(attr
);
3874 assert(transit
->refcnt
> 0);
3875 if (attr
->encap_subtlvs
)
3876 assert(attr
->encap_subtlvs
->refcnt
> 0);
3877 #ifdef ENABLE_BGP_VNC
3878 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3879 bgp_attr_get_vnc_subtlvs(attr
);
3882 assert(vnc_subtlvs
->refcnt
> 0);
3889 * Extract the tunnel type from extended community
3891 void bgp_attr_extcom_tunnel_type(struct attr
*attr
,
3892 bgp_encap_types
*tunnel_type
)
3894 struct ecommunity
*ecom
;
3900 ecom
= bgp_attr_get_ecommunity(attr
);
3901 if (!ecom
|| !ecom
->size
)
3904 for (i
= 0; i
< ecom
->size
; i
++) {
3906 uint8_t type
, sub_type
;
3908 pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
3911 if (!(type
== ECOMMUNITY_ENCODE_OPAQUE
&&
3912 sub_type
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
))
3914 *tunnel_type
= ((pnt
[6] << 8) | pnt
[7]);
3921 size_t bgp_packet_mpattr_start(struct stream
*s
, struct peer
*peer
, afi_t afi
,
3922 safi_t safi
, struct bpacket_attr_vec_arr
*vecarr
,
3926 iana_afi_t pkt_afi
= IANA_AFI_IPV4
;
3927 iana_safi_t pkt_safi
= IANA_SAFI_UNICAST
;
3930 /* Set extended bit always to encode the attribute length as 2 bytes */
3931 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
3932 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
3933 sizep
= stream_get_endp(s
);
3934 stream_putw(s
, 0); /* Marker: Attribute length. */
3937 /* Convert AFI, SAFI to values for packet. */
3938 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
3940 stream_putw(s
, pkt_afi
); /* AFI */
3941 stream_putc(s
, pkt_safi
); /* SAFI */
3945 && (safi
== SAFI_UNICAST
|| safi
== SAFI_LABELED_UNICAST
3946 || safi
== SAFI_MPLS_VPN
|| safi
== SAFI_MULTICAST
))
3947 nh_afi
= peer_cap_enhe(peer
, afi
, safi
) ? AFI_IP6
: AFI_IP
;
3948 else if (safi
== SAFI_FLOWSPEC
)
3951 nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
3954 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
3959 case SAFI_MULTICAST
:
3960 case SAFI_LABELED_UNICAST
:
3962 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3966 stream_putl(s
, 0); /* RD = 0, per RFC */
3968 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3973 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3976 if (attr
->mp_nexthop_len
== 0)
3977 stream_putc(s
, 0); /* no nexthop for flowspec */
3979 stream_putc(s
, attr
->mp_nexthop_len
);
3980 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3985 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
3992 case SAFI_MULTICAST
:
3993 case SAFI_LABELED_UNICAST
:
3995 if (attr
->mp_nexthop_len
3996 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3998 BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
);
3999 stream_put(s
, &attr
->mp_nexthop_global
,
4001 stream_put(s
, &attr
->mp_nexthop_local
,
4004 stream_putc(s
, IPV6_MAX_BYTELEN
);
4005 stream_put(s
, &attr
->mp_nexthop_global
,
4009 case SAFI_MPLS_VPN
: {
4010 if (attr
->mp_nexthop_len
==
4011 BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
)
4012 stream_putc(s
, attr
->mp_nexthop_len
);
4014 stream_putc(s
, BGP_ATTR_NHLEN_VPNV6_GLOBAL
);
4015 stream_putl(s
, 0); /* RD = 0, per RFC */
4017 stream_put(s
, &attr
->mp_nexthop_global
,
4019 if (attr
->mp_nexthop_len
==
4020 BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
4021 stream_putl(s
, 0); /* RD = 0, per RFC */
4023 stream_put(s
, &attr
->mp_nexthop_local
,
4028 stream_putc(s
, IPV6_MAX_BYTELEN
);
4029 stream_put(s
, &attr
->mp_nexthop_global
,
4033 stream_putc(s
, 0); /* no nexthop for flowspec */
4037 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
4042 if (safi
!= SAFI_FLOWSPEC
)
4044 EC_BGP_ATTR_NH_SEND_LEN
,
4045 "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
4046 peer
->host
, afi
, safi
, attr
->mp_nexthop_len
);
4050 assert(!"DEV ESCAPE: AFI_UNSPEC or AFI_MAX should not be used here");
4059 void bgp_packet_mpattr_prefix(struct stream
*s
, afi_t afi
, safi_t safi
,
4060 const struct prefix
*p
,
4061 const struct prefix_rd
*prd
, mpls_label_t
*label
,
4062 uint32_t num_labels
, bool addpath_capable
,
4063 uint32_t addpath_tx_id
, struct attr
*attr
)
4068 assert(!"Dev escape usage of SAFI_UNSPEC or MAX");
4071 if (addpath_capable
)
4072 stream_putl(s
, addpath_tx_id
);
4073 /* Label, RD, Prefix write. */
4074 stream_putc(s
, p
->prefixlen
+ 88);
4075 stream_put(s
, label
, BGP_LABEL_BYTES
);
4076 stream_put(s
, prd
->val
, 8);
4077 stream_put(s
, &p
->u
.prefix
, PSIZE(p
->prefixlen
));
4080 if (afi
== AFI_L2VPN
)
4081 /* EVPN prefix - contents depend on type */
4082 bgp_evpn_encode_prefix(s
, p
, prd
, label
, num_labels
,
4083 attr
, addpath_capable
,
4086 assert(!"Add encoding bits here for other AFI's");
4088 case SAFI_LABELED_UNICAST
:
4089 /* Prefix write with label. */
4090 stream_put_labeled_prefix(s
, p
, label
, addpath_capable
,
4094 stream_putc(s
, p
->u
.prefix_flowspec
.prefixlen
);
4095 stream_put(s
, (const void *)p
->u
.prefix_flowspec
.ptr
,
4096 p
->u
.prefix_flowspec
.prefixlen
);
4100 case SAFI_MULTICAST
:
4101 stream_put_prefix_addpath(s
, p
, addpath_capable
, addpath_tx_id
);
4104 assert(!"Please add proper encoding of SAFI_ENCAP");
4109 size_t bgp_packet_mpattr_prefix_size(afi_t afi
, safi_t safi
,
4110 const struct prefix
*p
)
4112 int size
= PSIZE(p
->prefixlen
);
4117 assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE");
4120 case SAFI_MULTICAST
:
4126 /* This has to be wrong, but I don't know what to put here */
4127 assert(!"Do we try to use this?");
4129 case SAFI_LABELED_UNICAST
:
4130 size
+= BGP_LABEL_BYTES
;
4134 * TODO: Maximum possible for type-2, type-3 and type-5
4136 if (afi
== AFI_L2VPN
)
4139 assert(!"Attempting to figure size for SAFI_EVPN and !AFI_L2VPN and FRR will not have the proper values");
4142 size
= ((struct prefix_fs
*)p
)->prefix
.prefixlen
;
4150 * Encodes the tunnel encapsulation attribute,
4151 * and with ENABLE_BGP_VNC the VNC attribute which uses
4152 * almost the same TLV format
4154 static void bgp_packet_mpattr_tea(struct bgp
*bgp
, struct peer
*peer
,
4155 struct stream
*s
, struct attr
*attr
,
4158 unsigned int attrlenfield
= 0;
4159 unsigned int attrhdrlen
= 0;
4160 struct bgp_attr_encap_subtlv
*subtlvs
;
4161 struct bgp_attr_encap_subtlv
*st
;
4162 const char *attrname
;
4164 if (!attr
|| (attrtype
== BGP_ATTR_ENCAP
4165 && (!attr
->encap_tunneltype
4166 || attr
->encap_tunneltype
== BGP_ENCAP_TYPE_MPLS
)))
4170 case BGP_ATTR_ENCAP
:
4171 attrname
= "Tunnel Encap";
4172 subtlvs
= attr
->encap_subtlvs
;
4173 if (subtlvs
== NULL
) /* nothing to do */
4176 * The tunnel encap attr has an "outer" tlv.
4178 * L = total length of subtlvs,
4179 * V = concatenated subtlvs.
4181 attrlenfield
= 2 + 2; /* T + L */
4182 attrhdrlen
= 1 + 1; /* subTLV T + L */
4185 #ifdef ENABLE_BGP_VNC_ATTR
4188 subtlvs
= bgp_attr_get_vnc_subtlvs(attr
);
4189 if (subtlvs
== NULL
) /* nothing to do */
4191 attrlenfield
= 0; /* no outer T + L */
4192 attrhdrlen
= 2 + 2; /* subTLV T + L */
4200 /* compute attr length */
4201 for (st
= subtlvs
; st
; st
= st
->next
) {
4202 attrlenfield
+= (attrhdrlen
+ st
->length
);
4205 if (attrlenfield
> 0xffff) {
4206 zlog_info("%s attribute is too long (length=%d), can't send it",
4207 attrname
, attrlenfield
);
4211 if (attrlenfield
> 0xff) {
4212 /* 2-octet length field */
4214 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4215 | BGP_ATTR_FLAG_EXTLEN
);
4216 stream_putc(s
, attrtype
);
4217 stream_putw(s
, attrlenfield
& 0xffff);
4219 /* 1-octet length field */
4220 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
);
4221 stream_putc(s
, attrtype
);
4222 stream_putc(s
, attrlenfield
& 0xff);
4225 if (attrtype
== BGP_ATTR_ENCAP
) {
4226 /* write outer T+L */
4227 stream_putw(s
, attr
->encap_tunneltype
);
4228 stream_putw(s
, attrlenfield
- 4);
4231 /* write each sub-tlv */
4232 for (st
= subtlvs
; st
; st
= st
->next
) {
4233 if (attrtype
== BGP_ATTR_ENCAP
) {
4234 stream_putc(s
, st
->type
);
4235 stream_putc(s
, st
->length
);
4236 #ifdef ENABLE_BGP_VNC
4238 stream_putw(s
, st
->type
);
4239 stream_putw(s
, st
->length
);
4242 stream_put(s
, st
->value
, st
->length
);
4246 void bgp_packet_mpattr_end(struct stream
*s
, size_t sizep
)
4248 /* Set MP attribute length. Don't count the (2) bytes used to encode
4250 stream_putw_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 2);
4253 static bool bgp_append_local_as(struct peer
*peer
, afi_t afi
, safi_t safi
)
4255 if (!BGP_AS_IS_PRIVATE(peer
->local_as
)
4256 || (BGP_AS_IS_PRIVATE(peer
->local_as
)
4257 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4258 PEER_FLAG_REMOVE_PRIVATE_AS
)
4259 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4260 PEER_FLAG_REMOVE_PRIVATE_AS_ALL
)
4261 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4262 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE
)
4263 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4264 PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE
)))
4269 /* Make attribute packet. */
4270 bgp_size_t
bgp_packet_attribute(struct bgp
*bgp
, struct peer
*peer
,
4271 struct stream
*s
, struct attr
*attr
,
4272 struct bpacket_attr_vec_arr
*vecarr
,
4273 struct prefix
*p
, afi_t afi
, safi_t safi
,
4274 struct peer
*from
, struct prefix_rd
*prd
,
4275 mpls_label_t
*label
, uint32_t num_labels
,
4276 bool addpath_capable
, uint32_t addpath_tx_id
,
4277 struct bgp_path_info
*bpi
)
4280 size_t aspath_sizep
;
4281 struct aspath
*aspath
;
4282 int send_as4_path
= 0;
4283 int send_as4_aggregator
= 0;
4284 bool use32bit
= CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
4285 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
);
4290 /* Remember current pointer. */
4291 cp
= stream_get_endp(s
);
4294 && !((afi
== AFI_IP
&& safi
== SAFI_UNICAST
)
4295 && !peer_cap_enhe(peer
, afi
, safi
))) {
4296 size_t mpattrlen_pos
= 0;
4298 mpattrlen_pos
= bgp_packet_mpattr_start(s
, peer
, afi
, safi
,
4300 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
,
4301 num_labels
, addpath_capable
,
4302 addpath_tx_id
, attr
);
4303 bgp_packet_mpattr_end(s
, mpattrlen_pos
);
4306 /* Origin attribute. */
4307 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4308 stream_putc(s
, BGP_ATTR_ORIGIN
);
4310 stream_putc(s
, attr
->origin
);
4312 /* AS path attribute. */
4314 /* If remote-peer is EBGP */
4315 if (peer
->sort
== BGP_PEER_EBGP
4316 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4317 PEER_FLAG_AS_PATH_UNCHANGED
)
4318 || attr
->aspath
->segments
== NULL
)
4319 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4320 PEER_FLAG_RSERVER_CLIENT
))) {
4321 aspath
= aspath_dup(attr
->aspath
);
4323 /* Even though we may not be configured for confederations we
4325 * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
4326 aspath
= aspath_delete_confed_seq(aspath
);
4328 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
)) {
4329 /* A confed member, so we need to do the
4330 * AS_CONFED_SEQUENCE thing if it's outside a common
4332 * Configured confederation peers MUST be validated
4333 * under BGP_PEER_CONFED, but if we have configured
4334 * remote-as as AS_EXTERNAL, we need to check again
4335 * if the peer belongs to us.
4337 if (bgp_confederation_peers_check(bgp
, peer
->as
)) {
4338 aspath
= aspath_add_confed_seq(aspath
,
4341 /* Stuff our path CONFED_ID on the front */
4342 aspath
= aspath_add_seq(aspath
, bgp
->confed_id
);
4345 if (peer
->change_local_as
) {
4346 /* If replace-as is specified, we only use the
4347 change_local_as when
4348 advertising routes. */
4349 if (!CHECK_FLAG(peer
->flags
,
4350 PEER_FLAG_LOCAL_AS_REPLACE_AS
))
4351 if (bgp_append_local_as(peer
, afi
,
4353 aspath
= aspath_add_seq(
4354 aspath
, peer
->local_as
);
4355 aspath
= aspath_add_seq(aspath
,
4356 peer
->change_local_as
);
4358 aspath
= aspath_add_seq(aspath
, peer
->local_as
);
4361 } else if (peer
->sort
== BGP_PEER_CONFED
) {
4362 /* A confed member, so we need to do the AS_CONFED_SEQUENCE
4364 aspath
= aspath_dup(attr
->aspath
);
4365 aspath
= aspath_add_confed_seq(aspath
, peer
->local_as
);
4367 aspath
= attr
->aspath
;
4369 /* If peer is not AS4 capable, then:
4370 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
4371 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
4373 * types are in it (i.e. exclude them if they are there)
4374 * AND do this only if there is at least one asnum > 65535 in the
4376 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
4378 * all ASnums > 65535 to BGP_AS_TRANS
4381 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4382 stream_putc(s
, BGP_ATTR_AS_PATH
);
4383 aspath_sizep
= stream_get_endp(s
);
4385 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, use32bit
));
4387 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
4390 if (!use32bit
&& aspath_has_as4(aspath
))
4392 1; /* we'll do this later, at the correct place */
4394 /* Nexthop attribute. */
4395 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
4396 && !peer_cap_enhe(peer
, afi
, safi
)) {
4397 afi_t nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
4399 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
)) {
4400 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4401 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4402 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4405 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4406 } else if (peer_cap_enhe(from
, afi
, safi
)
4407 || (nh_afi
== AFI_IP6
)) {
4409 * Likely this is the case when an IPv4 prefix was
4410 * received with Extended Next-hop capability in this
4411 * or another vrf and is now being advertised to
4412 * non-ENHE peers. Since peer_cap_enhe only checks
4413 * peers in this vrf, also check the nh_afi to catch
4414 * the case where the originator was in another vrf.
4415 * Setting the mandatory (ipv4) next-hop attribute here
4416 * to enable implicit next-hop self with correct A-F
4417 * (ipv4 address family).
4419 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4420 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4421 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4424 stream_put_ipv4(s
, 0);
4428 /* MED attribute. */
4429 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)
4430 || bgp
->maxmed_active
) {
4431 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4432 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4434 stream_putl(s
, (bgp
->maxmed_active
? bgp
->maxmed_value
4438 /* Local preference. */
4439 if (peer
->sort
== BGP_PEER_IBGP
|| peer
->sort
== BGP_PEER_CONFED
) {
4440 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4441 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4443 stream_putl(s
, attr
->local_pref
);
4446 /* Atomic aggregate. */
4447 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4448 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4449 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4454 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4455 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
4456 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4457 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4460 /* AS4 capable peer */
4462 stream_putl(s
, attr
->aggregator_as
);
4464 /* 2-byte AS peer */
4467 /* Is ASN representable in 2-bytes? Or must AS_TRANS be
4469 if (attr
->aggregator_as
> UINT16_MAX
) {
4470 stream_putw(s
, BGP_AS_TRANS
);
4472 /* we have to send AS4_AGGREGATOR, too.
4473 * we'll do that later in order to send
4474 * attributes in ascending
4477 send_as4_aggregator
= 1;
4479 stream_putw(s
, (uint16_t)attr
->aggregator_as
);
4481 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4484 /* Community attribute. */
4485 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
4486 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
))) {
4487 struct community
*comm
= NULL
;
4489 comm
= bgp_attr_get_community(attr
);
4490 if (comm
->size
* 4 > 255) {
4492 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4493 | BGP_ATTR_FLAG_EXTLEN
);
4494 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4495 stream_putw(s
, comm
->size
* 4);
4498 BGP_ATTR_FLAG_OPTIONAL
4499 | BGP_ATTR_FLAG_TRANS
);
4500 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4501 stream_putc(s
, comm
->size
* 4);
4503 stream_put(s
, comm
->val
, comm
->size
* 4);
4507 * Large Community attribute.
4509 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4510 PEER_FLAG_SEND_LARGE_COMMUNITY
)
4511 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
))) {
4512 if (lcom_length(bgp_attr_get_lcommunity(attr
)) > 255) {
4514 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4515 | BGP_ATTR_FLAG_EXTLEN
);
4516 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4518 lcom_length(bgp_attr_get_lcommunity(attr
)));
4521 BGP_ATTR_FLAG_OPTIONAL
4522 | BGP_ATTR_FLAG_TRANS
);
4523 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4525 lcom_length(bgp_attr_get_lcommunity(attr
)));
4527 stream_put(s
, bgp_attr_get_lcommunity(attr
)->val
,
4528 lcom_length(bgp_attr_get_lcommunity(attr
)));
4531 /* Route Reflector. */
4532 if (peer
->sort
== BGP_PEER_IBGP
&& from
4533 && from
->sort
== BGP_PEER_IBGP
) {
4534 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
4536 /* Originator ID. */
4537 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4538 stream_putc(s
, BGP_ATTR_ORIGINATOR_ID
);
4541 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
4542 stream_put_in_addr(s
, &attr
->originator_id
);
4544 stream_put_in_addr(s
, &from
->remote_id
);
4547 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4548 stream_putc(s
, BGP_ATTR_CLUSTER_LIST
);
4551 stream_putc(s
, cluster
->length
+ 4);
4552 /* If this peer configuration's parent BGP has
4554 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4555 stream_put_in_addr(s
, &bgp
->cluster_id
);
4557 stream_put_in_addr(s
, &bgp
->router_id
);
4558 stream_put(s
, cluster
->list
, cluster
->length
);
4561 /* If this peer configuration's parent BGP has
4563 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4564 stream_put_in_addr(s
, &bgp
->cluster_id
);
4566 stream_put_in_addr(s
, &bgp
->router_id
);
4570 /* Extended Communities attribute. */
4571 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
4572 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
))) {
4573 struct ecommunity
*ecomm
= bgp_attr_get_ecommunity(attr
);
4574 bool transparent
= CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4575 PEER_FLAG_RSERVER_CLIENT
) &&
4577 CHECK_FLAG(from
->af_flags
[afi
][safi
],
4578 PEER_FLAG_RSERVER_CLIENT
);
4580 if (peer
->sort
== BGP_PEER_IBGP
||
4581 peer
->sort
== BGP_PEER_CONFED
|| transparent
) {
4582 if (ecomm
->size
* 8 > 255) {
4584 BGP_ATTR_FLAG_OPTIONAL
4585 | BGP_ATTR_FLAG_TRANS
4586 | BGP_ATTR_FLAG_EXTLEN
);
4587 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4588 stream_putw(s
, ecomm
->size
* 8);
4591 BGP_ATTR_FLAG_OPTIONAL
4592 | BGP_ATTR_FLAG_TRANS
);
4593 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4594 stream_putc(s
, ecomm
->size
* 8);
4596 stream_put(s
, ecomm
->val
, ecomm
->size
* 8);
4600 int ecom_tr_size
= 0;
4603 for (i
= 0; i
< ecomm
->size
; i
++) {
4604 pnt
= ecomm
->val
+ (i
* 8);
4607 if (CHECK_FLAG(tbit
,
4608 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4615 if (ecom_tr_size
* 8 > 255) {
4618 BGP_ATTR_FLAG_OPTIONAL
4619 | BGP_ATTR_FLAG_TRANS
4620 | BGP_ATTR_FLAG_EXTLEN
);
4622 BGP_ATTR_EXT_COMMUNITIES
);
4623 stream_putw(s
, ecom_tr_size
* 8);
4627 BGP_ATTR_FLAG_OPTIONAL
4628 | BGP_ATTR_FLAG_TRANS
);
4630 BGP_ATTR_EXT_COMMUNITIES
);
4631 stream_putc(s
, ecom_tr_size
* 8);
4634 for (i
= 0; i
< ecomm
->size
; i
++) {
4635 pnt
= ecomm
->val
+ (i
* 8);
4640 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4643 stream_put(s
, pnt
, 8);
4649 /* Label index attribute. */
4650 if (safi
== SAFI_LABELED_UNICAST
) {
4651 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4652 uint32_t label_index
;
4654 label_index
= attr
->label_index
;
4656 if (label_index
!= BGP_INVALID_LABEL_INDEX
) {
4658 BGP_ATTR_FLAG_OPTIONAL
4659 | BGP_ATTR_FLAG_TRANS
);
4660 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4662 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4664 BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4665 stream_putc(s
, 0); // reserved
4666 stream_putw(s
, 0); // flags
4667 stream_putl(s
, label_index
);
4672 /* SRv6 Service Information Attribute. */
4673 if ((afi
== AFI_IP
|| afi
== AFI_IP6
) && safi
== SAFI_MPLS_VPN
) {
4674 if (attr
->srv6_l3vpn
) {
4675 uint8_t subtlv_len
=
4676 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
4678 + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
;
4679 uint8_t tlv_len
= subtlv_len
+ BGP_ATTR_MIN_LEN
+ 1;
4680 uint8_t attr_len
= tlv_len
+ BGP_ATTR_MIN_LEN
;
4681 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4682 | BGP_ATTR_FLAG_TRANS
);
4683 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4684 stream_putc(s
, attr_len
);
4685 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE
);
4686 stream_putw(s
, tlv_len
);
4687 stream_putc(s
, 0); /* reserved */
4688 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
);
4689 stream_putw(s
, subtlv_len
);
4690 stream_putc(s
, 0); /* reserved */
4691 stream_put(s
, &attr
->srv6_l3vpn
->sid
,
4692 sizeof(attr
->srv6_l3vpn
->sid
)); /* sid */
4693 stream_putc(s
, 0); /* sid_flags */
4696 ->endpoint_behavior
); /* endpoint */
4697 stream_putc(s
, 0); /* reserved */
4700 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
);
4703 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
);
4704 stream_putc(s
, attr
->srv6_l3vpn
->loc_block_len
);
4705 stream_putc(s
, attr
->srv6_l3vpn
->loc_node_len
);
4706 stream_putc(s
, attr
->srv6_l3vpn
->func_len
);
4707 stream_putc(s
, attr
->srv6_l3vpn
->arg_len
);
4708 stream_putc(s
, attr
->srv6_l3vpn
->transposition_len
);
4709 stream_putc(s
, attr
->srv6_l3vpn
->transposition_offset
);
4710 } else if (attr
->srv6_vpn
) {
4711 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4712 | BGP_ATTR_FLAG_TRANS
);
4713 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4714 stream_putc(s
, 22); /* tlv len */
4715 stream_putc(s
, BGP_PREFIX_SID_VPN_SID
);
4716 stream_putw(s
, 0x13); /* tlv len */
4717 stream_putc(s
, 0x00); /* reserved */
4718 stream_putc(s
, 0x01); /* sid_type */
4719 stream_putc(s
, 0x00); /* sif_flags */
4720 stream_put(s
, &attr
->srv6_vpn
->sid
,
4721 sizeof(attr
->srv6_vpn
->sid
)); /* sid */
4725 if (send_as4_path
) {
4726 /* If the peer is NOT As4 capable, AND */
4727 /* there are ASnums > 65535 in path THEN
4728 * give out AS4_PATH */
4730 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
4732 * Hm, I wonder... confederation things *should* only be at
4733 * the beginning of an aspath, right? Then we should use
4734 * aspath_delete_confed_seq for this, because it is already
4736 * Folks, talk to me: what is reasonable here!?
4739 /* Make sure dup aspath before the modification */
4740 if (aspath
== attr
->aspath
)
4741 aspath
= aspath_dup(attr
->aspath
);
4742 aspath
= aspath_delete_confed_seq(aspath
);
4745 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4746 | BGP_ATTR_FLAG_EXTLEN
);
4747 stream_putc(s
, BGP_ATTR_AS4_PATH
);
4748 aspath_sizep
= stream_get_endp(s
);
4750 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, 1));
4753 if (aspath
!= attr
->aspath
)
4754 aspath_free(aspath
);
4756 if (send_as4_aggregator
) {
4757 /* send AS4_AGGREGATOR, at this place */
4758 /* this section of code moved here in order to ensure the
4760 * *ascending* order of attributes
4762 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4763 stream_putc(s
, BGP_ATTR_AS4_AGGREGATOR
);
4765 stream_putl(s
, attr
->aggregator_as
);
4766 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4769 if (((afi
== AFI_IP
|| afi
== AFI_IP6
)
4770 && (safi
== SAFI_ENCAP
|| safi
== SAFI_MPLS_VPN
))
4771 || (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)) {
4772 /* Tunnel Encap attribute */
4773 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_ENCAP
);
4775 #ifdef ENABLE_BGP_VNC_ATTR
4777 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_VNC
);
4782 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
)) {
4783 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4784 stream_putc(s
, BGP_ATTR_PMSI_TUNNEL
);
4785 stream_putc(s
, 9); // Length
4786 stream_putc(s
, 0); // Flags
4787 stream_putc(s
, bgp_attr_get_pmsi_tnl_type(attr
));
4788 stream_put(s
, &(attr
->label
),
4789 BGP_LABEL_BYTES
); // MPLS Label / VXLAN VNI
4790 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4791 // Unicast tunnel endpoint IP address
4795 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_OTC
)) {
4796 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4797 stream_putc(s
, BGP_ATTR_OTC
);
4799 stream_putl(s
, attr
->otc
);
4803 if (bpi
&& attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AIGP
) &&
4804 (CHECK_FLAG(peer
->flags
, PEER_FLAG_AIGP
) ||
4805 peer
->sort
!= BGP_PEER_EBGP
)) {
4806 /* At the moment only AIGP Metric TLV exists for AIGP
4807 * attribute. If more comes in, do not forget to update
4808 * attr_len variable to include new ones.
4810 uint8_t attr_len
= BGP_AIGP_TLV_METRIC_LEN
;
4812 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4813 stream_putc(s
, BGP_ATTR_AIGP
);
4814 stream_putc(s
, attr_len
);
4815 stream_put_bgp_aigp_tlv_metric(s
, bpi
);
4818 /* Unknown transit attribute. */
4819 struct transit
*transit
= bgp_attr_get_transit(attr
);
4822 stream_put(s
, transit
->val
, transit
->length
);
4824 /* Return total size of attribute. */
4825 return stream_get_endp(s
) - cp
;
4828 size_t bgp_packet_mpunreach_start(struct stream
*s
, afi_t afi
, safi_t safi
)
4830 unsigned long attrlen_pnt
;
4831 iana_afi_t pkt_afi
= IANA_AFI_IPV4
;
4832 iana_safi_t pkt_safi
= IANA_SAFI_UNICAST
;
4834 /* Set extended bit always to encode the attribute length as 2 bytes */
4835 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
4836 stream_putc(s
, BGP_ATTR_MP_UNREACH_NLRI
);
4838 attrlen_pnt
= stream_get_endp(s
);
4839 stream_putw(s
, 0); /* Length of this attribute. */
4841 /* Convert AFI, SAFI to values for packet. */
4842 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
4844 stream_putw(s
, pkt_afi
);
4845 stream_putc(s
, pkt_safi
);
4850 void bgp_packet_mpunreach_prefix(struct stream
*s
, const struct prefix
*p
,
4851 afi_t afi
, safi_t safi
,
4852 const struct prefix_rd
*prd
,
4853 mpls_label_t
*label
, uint32_t num_labels
,
4854 bool addpath_capable
, uint32_t addpath_tx_id
,
4857 uint8_t wlabel
[4] = {0x80, 0x00, 0x00};
4859 if (safi
== SAFI_LABELED_UNICAST
) {
4860 label
= (mpls_label_t
*)wlabel
;
4864 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
, num_labels
,
4865 addpath_capable
, addpath_tx_id
, attr
);
4868 void bgp_packet_mpunreach_end(struct stream
*s
, size_t attrlen_pnt
)
4870 bgp_packet_mpattr_end(s
, attrlen_pnt
);
4873 /* Initialization of attribute. */
4874 void bgp_attr_init(void)
4887 void bgp_attr_finish(void)
4892 ecommunity_finish();
4893 lcommunity_finish();
4900 /* Make attribute packet. */
4901 void bgp_dump_routes_attr(struct stream
*s
, struct bgp_path_info
*bpi
,
4902 const struct prefix
*prefix
)
4907 struct aspath
*aspath
;
4908 bool addpath_capable
= false;
4909 uint32_t addpath_tx_id
= 0;
4910 struct attr
*attr
= bpi
->attr
;
4912 /* Remember current pointer. */
4913 cp
= stream_get_endp(s
);
4915 /* Place holder of length. */
4918 /* Origin attribute. */
4919 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4920 stream_putc(s
, BGP_ATTR_ORIGIN
);
4922 stream_putc(s
, attr
->origin
);
4924 aspath
= attr
->aspath
;
4926 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4927 stream_putc(s
, BGP_ATTR_AS_PATH
);
4928 aspath_lenp
= stream_get_endp(s
);
4931 stream_putw_at(s
, aspath_lenp
, aspath_put(s
, aspath
, 1));
4933 /* Nexthop attribute. */
4934 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
4935 if (prefix
!= NULL
&& prefix
->family
!= AF_INET6
) {
4936 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4937 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4939 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4942 /* MED attribute. */
4943 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)) {
4944 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4945 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4947 stream_putl(s
, attr
->med
);
4950 /* Local preference. */
4951 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)) {
4952 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4953 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4955 stream_putl(s
, attr
->local_pref
);
4958 /* Atomic aggregate. */
4959 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4960 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4961 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4966 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4967 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4968 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4970 stream_putl(s
, attr
->aggregator_as
);
4971 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4974 /* Community attribute. */
4975 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
)) {
4976 struct community
*comm
= NULL
;
4978 comm
= bgp_attr_get_community(attr
);
4979 if (comm
->size
* 4 > 255) {
4981 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4982 | BGP_ATTR_FLAG_EXTLEN
);
4983 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4984 stream_putw(s
, comm
->size
* 4);
4987 BGP_ATTR_FLAG_OPTIONAL
4988 | BGP_ATTR_FLAG_TRANS
);
4989 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4990 stream_putc(s
, comm
->size
* 4);
4992 stream_put(s
, comm
->val
, comm
->size
* 4);
4995 /* Large Community attribute. */
4996 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
)) {
4997 if (lcom_length(bgp_attr_get_lcommunity(attr
)) > 255) {
4999 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
5000 | BGP_ATTR_FLAG_EXTLEN
);
5001 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
5003 lcom_length(bgp_attr_get_lcommunity(attr
)));
5006 BGP_ATTR_FLAG_OPTIONAL
5007 | BGP_ATTR_FLAG_TRANS
);
5008 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
5010 lcom_length(bgp_attr_get_lcommunity(attr
)));
5013 stream_put(s
, bgp_attr_get_lcommunity(attr
)->val
,
5014 lcom_length(bgp_attr_get_lcommunity(attr
)));
5017 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
5018 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
5019 && (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL
5020 || attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)) {
5023 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
5024 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
5025 sizep
= stream_get_endp(s
);
5028 stream_putc(s
, 0); /* Marker: Attribute length. */
5029 stream_putw(s
, AFI_IP6
); /* AFI */
5030 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
5033 stream_putc(s
, attr
->mp_nexthop_len
);
5034 stream_put(s
, &attr
->mp_nexthop_global
, IPV6_MAX_BYTELEN
);
5035 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)
5036 stream_put(s
, &attr
->mp_nexthop_local
,
5043 stream_put_prefix_addpath(s
, prefix
, addpath_capable
,
5046 /* Set MP attribute length. */
5047 stream_putc_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 1);
5051 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
5052 if (attr
->label_index
!= BGP_INVALID_LABEL_INDEX
) {
5054 BGP_ATTR_FLAG_OPTIONAL
5055 | BGP_ATTR_FLAG_TRANS
);
5056 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
5058 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
5059 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
5060 stream_putc(s
, 0); // reserved
5061 stream_putw(s
, 0); // flags
5062 stream_putl(s
, attr
->label_index
);
5067 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_OTC
)) {
5068 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
5069 stream_putc(s
, BGP_ATTR_OTC
);
5071 stream_putl(s
, attr
->otc
);
5075 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AIGP
)) {
5076 /* At the moment only AIGP Metric TLV exists for AIGP
5077 * attribute. If more comes in, do not forget to update
5078 * attr_len variable to include new ones.
5080 uint8_t attr_len
= BGP_AIGP_TLV_METRIC_LEN
;
5082 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
5083 stream_putc(s
, BGP_ATTR_AIGP
);
5084 stream_putc(s
, attr_len
);
5085 stream_put_bgp_aigp_tlv_metric(s
, bpi
);
5088 /* Return total size of attribute. */
5089 len
= stream_get_endp(s
) - cp
- 2;
5090 stream_putw_at(s
, cp
, len
);
5093 void bgp_path_attribute_discard_vty(struct vty
*vty
, struct peer
*peer
,
5094 const char *discard_attrs
, bool set
)
5096 int i
, num_attributes
;
5102 /* If `no` command specified without arbitrary attributes,
5105 if (!discard_attrs
) {
5106 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5107 peer
->discard_attrs
[i
] = false;
5108 goto discard_soft_clear
;
5111 if (discard_attrs
) {
5112 frrstr_split(discard_attrs
, " ", &attributes
, &num_attributes
);
5115 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5116 peer
->discard_attrs
[i
] = false;
5118 for (i
= 0; i
< num_attributes
; i
++) {
5119 uint8_t attr_num
= strtoul(attributes
[i
], NULL
, 10);
5121 XFREE(MTYPE_TMP
, attributes
[i
]);
5123 /* Some of the attributes, just can't be ignored. */
5124 if (attr_num
== BGP_ATTR_ORIGIN
||
5125 attr_num
== BGP_ATTR_AS_PATH
||
5126 attr_num
== BGP_ATTR_NEXT_HOP
||
5127 attr_num
== BGP_ATTR_MULTI_EXIT_DISC
||
5128 attr_num
== BGP_ATTR_MP_REACH_NLRI
||
5129 attr_num
== BGP_ATTR_MP_UNREACH_NLRI
||
5130 attr_num
== BGP_ATTR_EXT_COMMUNITIES
) {
5132 "%% Can't discard path-attribute %s, ignoring.\n",
5133 lookup_msg(attr_str
, attr_num
, NULL
));
5137 /* Ignore local-pref, originator-id, cluster-list only
5140 if (peer
->sort
!= BGP_PEER_EBGP
&&
5141 (attr_num
== BGP_ATTR_LOCAL_PREF
||
5142 attr_num
== BGP_ATTR_ORIGINATOR_ID
||
5143 attr_num
== BGP_ATTR_CLUSTER_LIST
)) {
5145 "%% Can discard path-attribute %s only for eBGP, ignoring.\n",
5146 lookup_msg(attr_str
, attr_num
, NULL
));
5150 peer
->discard_attrs
[attr_num
] = set
;
5152 XFREE(MTYPE_TMP
, attributes
);
5154 /* Configuring path attributes to be discarded will trigger
5155 * an inbound Route Refresh to ensure that the routing table
5158 FOREACH_AFI_SAFI (afi
, safi
)
5159 peer_clear_soft(peer
, afi
, safi
, BGP_CLEAR_SOFT_IN
);