1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* BGP attributes management routines.
3 * Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
23 #include "bgpd/bgpd.h"
24 #include "bgpd/bgp_attr.h"
25 #include "bgpd/bgp_route.h"
26 #include "bgpd/bgp_aspath.h"
27 #include "bgpd/bgp_community.h"
28 #include "bgpd/bgp_debug.h"
29 #include "bgpd/bgp_errors.h"
30 #include "bgpd/bgp_label.h"
31 #include "bgpd/bgp_packet.h"
32 #include "bgpd/bgp_ecommunity.h"
33 #include "bgpd/bgp_lcommunity.h"
34 #include "bgpd/bgp_updgrp.h"
35 #include "bgpd/bgp_encap_types.h"
37 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
38 #include "bgp_encap_types.h"
39 #include "bgp_vnc_types.h"
42 #include "bgp_flowspec_private.h"
45 /* Attribute strings for logging. */
46 static const struct message attr_str
[] = {
47 {BGP_ATTR_ORIGIN
, "ORIGIN"},
48 {BGP_ATTR_AS_PATH
, "AS_PATH"},
49 {BGP_ATTR_NEXT_HOP
, "NEXT_HOP"},
50 {BGP_ATTR_MULTI_EXIT_DISC
, "MULTI_EXIT_DISC"},
51 {BGP_ATTR_LOCAL_PREF
, "LOCAL_PREF"},
52 {BGP_ATTR_ATOMIC_AGGREGATE
, "ATOMIC_AGGREGATE"},
53 {BGP_ATTR_AGGREGATOR
, "AGGREGATOR"},
54 {BGP_ATTR_COMMUNITIES
, "COMMUNITY"},
55 {BGP_ATTR_ORIGINATOR_ID
, "ORIGINATOR_ID"},
56 {BGP_ATTR_CLUSTER_LIST
, "CLUSTER_LIST"},
57 {BGP_ATTR_MP_REACH_NLRI
, "MP_REACH_NLRI"},
58 {BGP_ATTR_MP_UNREACH_NLRI
, "MP_UNREACH_NLRI"},
59 {BGP_ATTR_EXT_COMMUNITIES
, "EXT_COMMUNITIES"},
60 {BGP_ATTR_AS4_PATH
, "AS4_PATH"},
61 {BGP_ATTR_AS4_AGGREGATOR
, "AS4_AGGREGATOR"},
62 {BGP_ATTR_PMSI_TUNNEL
, "PMSI_TUNNEL_ATTRIBUTE"},
63 {BGP_ATTR_ENCAP
, "ENCAP"},
64 {BGP_ATTR_OTC
, "OTC"},
65 #ifdef ENABLE_BGP_VNC_ATTR
66 {BGP_ATTR_VNC
, "VNC"},
68 {BGP_ATTR_LARGE_COMMUNITIES
, "LARGE_COMMUNITY"},
69 {BGP_ATTR_PREFIX_SID
, "PREFIX_SID"},
70 {BGP_ATTR_IPV6_EXT_COMMUNITIES
, "IPV6_EXT_COMMUNITIES"},
71 {BGP_ATTR_AIGP
, "AIGP"},
74 static const struct message attr_flag_str
[] = {
75 {BGP_ATTR_FLAG_OPTIONAL
, "Optional"},
76 {BGP_ATTR_FLAG_TRANS
, "Transitive"},
77 {BGP_ATTR_FLAG_PARTIAL
, "Partial"},
78 /* bgp_attr_flags_diagnose() relies on this bit being last in
80 {BGP_ATTR_FLAG_EXTLEN
, "Extended Length"},
83 static struct hash
*cluster_hash
;
85 static void *cluster_hash_alloc(void *p
)
87 const struct cluster_list
*val
= (const struct cluster_list
*)p
;
88 struct cluster_list
*cluster
;
90 cluster
= XMALLOC(MTYPE_CLUSTER
, sizeof(struct cluster_list
));
91 cluster
->length
= val
->length
;
93 if (cluster
->length
) {
94 cluster
->list
= XMALLOC(MTYPE_CLUSTER_VAL
, val
->length
);
95 memcpy(cluster
->list
, val
->list
, val
->length
);
104 /* Cluster list related functions. */
105 static struct cluster_list
*cluster_parse(struct in_addr
*pnt
, int length
)
107 struct cluster_list tmp
= {};
108 struct cluster_list
*cluster
;
111 tmp
.list
= length
== 0 ? NULL
: pnt
;
113 cluster
= hash_get(cluster_hash
, &tmp
, cluster_hash_alloc
);
118 bool cluster_loop_check(struct cluster_list
*cluster
, struct in_addr originator
)
122 for (i
= 0; i
< cluster
->length
/ 4; i
++)
123 if (cluster
->list
[i
].s_addr
== originator
.s_addr
)
128 static unsigned int cluster_hash_key_make(const void *p
)
130 const struct cluster_list
*cluster
= p
;
132 return jhash(cluster
->list
, cluster
->length
, 0);
135 static bool cluster_hash_cmp(const void *p1
, const void *p2
)
137 const struct cluster_list
*cluster1
= p1
;
138 const struct cluster_list
*cluster2
= p2
;
140 if (cluster1
->list
== cluster2
->list
)
143 if (!cluster1
->list
|| !cluster2
->list
)
146 if (cluster1
->length
!= cluster2
->length
)
149 return (memcmp(cluster1
->list
, cluster2
->list
, cluster1
->length
) == 0);
152 static void cluster_free(struct cluster_list
*cluster
)
154 XFREE(MTYPE_CLUSTER_VAL
, cluster
->list
);
155 XFREE(MTYPE_CLUSTER
, cluster
);
158 static struct cluster_list
*cluster_intern(struct cluster_list
*cluster
)
160 struct cluster_list
*find
;
162 find
= hash_get(cluster_hash
, cluster
, cluster_hash_alloc
);
168 static void cluster_unintern(struct cluster_list
**cluster
)
170 if ((*cluster
)->refcnt
)
171 (*cluster
)->refcnt
--;
173 if ((*cluster
)->refcnt
== 0) {
174 void *p
= hash_release(cluster_hash
, *cluster
);
175 assert(p
== *cluster
);
176 cluster_free(*cluster
);
181 static void cluster_init(void)
183 cluster_hash
= hash_create(cluster_hash_key_make
, cluster_hash_cmp
,
187 static void cluster_finish(void)
189 hash_clean_and_free(&cluster_hash
, (void (*)(void *))cluster_free
);
192 static struct hash
*encap_hash
= NULL
;
193 #ifdef ENABLE_BGP_VNC
194 static struct hash
*vnc_hash
= NULL
;
196 static struct hash
*srv6_l3vpn_hash
;
197 static struct hash
*srv6_vpn_hash
;
199 struct bgp_attr_encap_subtlv
*encap_tlv_dup(struct bgp_attr_encap_subtlv
*orig
)
201 struct bgp_attr_encap_subtlv
*new;
202 struct bgp_attr_encap_subtlv
*tail
;
203 struct bgp_attr_encap_subtlv
*p
;
205 for (p
= orig
, tail
= new = NULL
; p
; p
= p
->next
) {
206 int size
= sizeof(struct bgp_attr_encap_subtlv
) + p
->length
;
208 tail
->next
= XCALLOC(MTYPE_ENCAP_TLV
, size
);
211 tail
= new = XCALLOC(MTYPE_ENCAP_TLV
, size
);
214 memcpy(tail
, p
, size
);
221 static void encap_free(struct bgp_attr_encap_subtlv
*p
)
223 struct bgp_attr_encap_subtlv
*next
;
227 XFREE(MTYPE_ENCAP_TLV
, p
);
232 void bgp_attr_flush_encap(struct attr
*attr
)
237 if (attr
->encap_subtlvs
) {
238 encap_free(attr
->encap_subtlvs
);
239 attr
->encap_subtlvs
= NULL
;
241 #ifdef ENABLE_BGP_VNC
242 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
243 bgp_attr_get_vnc_subtlvs(attr
);
246 encap_free(vnc_subtlvs
);
247 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
253 * Compare encap sub-tlv chains
258 * This algorithm could be made faster if needed
260 static bool encap_same(const struct bgp_attr_encap_subtlv
*h1
,
261 const struct bgp_attr_encap_subtlv
*h2
)
263 const struct bgp_attr_encap_subtlv
*p
;
264 const struct bgp_attr_encap_subtlv
*q
;
268 if (h1
== NULL
|| h2
== NULL
)
271 for (p
= h1
; p
; p
= p
->next
) {
272 for (q
= h2
; q
; q
= q
->next
) {
273 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
274 && !memcmp(p
->value
, q
->value
, p
->length
)) {
283 for (p
= h2
; p
; p
= p
->next
) {
284 for (q
= h1
; q
; q
= q
->next
) {
285 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
286 && !memcmp(p
->value
, q
->value
, p
->length
)) {
298 static void *encap_hash_alloc(void *p
)
300 /* Encap structure is already allocated. */
306 #ifdef ENABLE_BGP_VNC
311 static struct bgp_attr_encap_subtlv
*
312 encap_intern(struct bgp_attr_encap_subtlv
*encap
, encap_subtlv_type type
)
314 struct bgp_attr_encap_subtlv
*find
;
315 struct hash
*hash
= encap_hash
;
316 #ifdef ENABLE_BGP_VNC
317 if (type
== VNC_SUBTLV_TYPE
)
321 find
= hash_get(hash
, encap
, encap_hash_alloc
);
329 static void encap_unintern(struct bgp_attr_encap_subtlv
**encapp
,
330 encap_subtlv_type type
)
332 struct bgp_attr_encap_subtlv
*encap
= *encapp
;
336 if (encap
->refcnt
== 0) {
337 struct hash
*hash
= encap_hash
;
338 #ifdef ENABLE_BGP_VNC
339 if (type
== VNC_SUBTLV_TYPE
)
342 hash_release(hash
, encap
);
348 static unsigned int encap_hash_key_make(const void *p
)
350 const struct bgp_attr_encap_subtlv
*encap
= p
;
352 return jhash(encap
->value
, encap
->length
, 0);
355 static bool encap_hash_cmp(const void *p1
, const void *p2
)
357 return encap_same((const struct bgp_attr_encap_subtlv
*)p1
,
358 (const struct bgp_attr_encap_subtlv
*)p2
);
361 static void encap_init(void)
363 encap_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
365 #ifdef ENABLE_BGP_VNC
366 vnc_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
371 static void encap_finish(void)
373 hash_clean_and_free(&encap_hash
, (void (*)(void *))encap_free
);
374 #ifdef ENABLE_BGP_VNC
375 hash_clean_and_free(&vnc_hash
, (void (*)(void *))encap_free
);
379 static bool overlay_index_same(const struct attr
*a1
, const struct attr
*a2
)
388 return bgp_route_evpn_same(bgp_attr_get_evpn_overlay(a1
),
389 bgp_attr_get_evpn_overlay(a2
));
392 /* Unknown transit attribute. */
393 static struct hash
*transit_hash
;
395 static void transit_free(struct transit
*transit
)
397 XFREE(MTYPE_TRANSIT_VAL
, transit
->val
);
398 XFREE(MTYPE_TRANSIT
, transit
);
401 static void *transit_hash_alloc(void *p
)
403 /* Transit structure is already allocated. */
407 static struct transit
*transit_intern(struct transit
*transit
)
409 struct transit
*find
;
411 find
= hash_get(transit_hash
, transit
, transit_hash_alloc
);
413 transit_free(transit
);
419 static void transit_unintern(struct transit
**transit
)
421 if ((*transit
)->refcnt
)
422 (*transit
)->refcnt
--;
424 if ((*transit
)->refcnt
== 0) {
425 hash_release(transit_hash
, *transit
);
426 transit_free(*transit
);
431 static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt
, int length
,
440 ptr_get_be16(data
+ 1, &tlv_length
);
443 /* The value field of the AIGP TLV is always 8 octets
444 * long and its value is interpreted as an unsigned 64-bit
447 if (tlv_type
== BGP_AIGP_TLV_METRIC
) {
448 (void)ptr_get_be64(data
+ 3, aigp
);
450 /* If an AIGP attribute is received and its first AIGP
451 * TLV contains the maximum value 0xffffffffffffffff,
452 * the attribute SHOULD be considered to be malformed
453 * and SHOULD be discarded as specified in this section.
455 if (*aigp
== BGP_AIGP_TLV_METRIC_MAX
) {
456 zlog_err("Bad AIGP TLV (%s) length: %llu",
457 BGP_AIGP_TLV_METRIC_DESC
,
458 BGP_AIGP_TLV_METRIC_MAX
);
466 length
-= tlv_length
;
472 static uint64_t bgp_aigp_metric_total(struct bgp_path_info
*bpi
)
474 uint64_t aigp
= bgp_attr_get_aigp_metric(bpi
->attr
);
477 return aigp
+ bpi
->nexthop
->metric
;
482 static void stream_put_bgp_aigp_tlv_metric(struct stream
*s
,
483 struct bgp_path_info
*bpi
)
485 stream_putc(s
, BGP_AIGP_TLV_METRIC
);
486 stream_putw(s
, BGP_AIGP_TLV_METRIC_LEN
);
487 stream_putq(s
, bgp_aigp_metric_total(bpi
));
490 static bool bgp_attr_aigp_valid(uint8_t *pnt
, int length
)
497 zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u",
504 ptr_get_be16(data
+ 1, &tlv_length
);
507 if (length
< tlv_length
) {
509 "Bad AIGP attribute length: %u, but TLV length: %u",
514 if (tlv_length
< 3) {
515 zlog_err("Bad AIGP TLV length (MUST be minimum 3): %u",
520 /* AIGP TLV, Length: 11 */
521 if (tlv_type
== BGP_AIGP_TLV_METRIC
&&
522 tlv_length
!= BGP_AIGP_TLV_METRIC_LEN
) {
523 zlog_err("Bad AIGP TLV (%s) length: %u",
524 BGP_AIGP_TLV_METRIC_DESC
, tlv_length
);
529 length
-= tlv_length
;
535 static void *srv6_l3vpn_hash_alloc(void *p
)
540 static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn
*l3vpn
)
542 XFREE(MTYPE_BGP_SRV6_L3VPN
, l3vpn
);
545 static struct bgp_attr_srv6_l3vpn
*
546 srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn
*l3vpn
)
548 struct bgp_attr_srv6_l3vpn
*find
;
550 find
= hash_get(srv6_l3vpn_hash
, l3vpn
, srv6_l3vpn_hash_alloc
);
552 srv6_l3vpn_free(l3vpn
);
557 static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn
**l3vpnp
)
559 struct bgp_attr_srv6_l3vpn
*l3vpn
= *l3vpnp
;
564 if (l3vpn
->refcnt
== 0) {
565 hash_release(srv6_l3vpn_hash
, l3vpn
);
566 srv6_l3vpn_free(l3vpn
);
571 static void *srv6_vpn_hash_alloc(void *p
)
576 static void srv6_vpn_free(struct bgp_attr_srv6_vpn
*vpn
)
578 XFREE(MTYPE_BGP_SRV6_VPN
, vpn
);
581 static struct bgp_attr_srv6_vpn
*srv6_vpn_intern(struct bgp_attr_srv6_vpn
*vpn
)
583 struct bgp_attr_srv6_vpn
*find
;
585 find
= hash_get(srv6_vpn_hash
, vpn
, srv6_vpn_hash_alloc
);
592 static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn
**vpnp
)
594 struct bgp_attr_srv6_vpn
*vpn
= *vpnp
;
599 if (vpn
->refcnt
== 0) {
600 hash_release(srv6_vpn_hash
, vpn
);
606 static uint32_t srv6_l3vpn_hash_key_make(const void *p
)
608 const struct bgp_attr_srv6_l3vpn
*l3vpn
= p
;
611 key
= jhash(&l3vpn
->sid
, 16, key
);
612 key
= jhash_1word(l3vpn
->sid_flags
, key
);
613 key
= jhash_1word(l3vpn
->endpoint_behavior
, key
);
614 key
= jhash_1word(l3vpn
->loc_block_len
, key
);
615 key
= jhash_1word(l3vpn
->loc_node_len
, key
);
616 key
= jhash_1word(l3vpn
->func_len
, key
);
617 key
= jhash_1word(l3vpn
->arg_len
, key
);
618 key
= jhash_1word(l3vpn
->transposition_len
, key
);
619 key
= jhash_1word(l3vpn
->transposition_offset
, key
);
623 static bool srv6_l3vpn_hash_cmp(const void *p1
, const void *p2
)
625 const struct bgp_attr_srv6_l3vpn
*l3vpn1
= p1
;
626 const struct bgp_attr_srv6_l3vpn
*l3vpn2
= p2
;
628 return sid_same(&l3vpn1
->sid
, &l3vpn2
->sid
)
629 && l3vpn1
->sid_flags
== l3vpn2
->sid_flags
630 && l3vpn1
->endpoint_behavior
== l3vpn2
->endpoint_behavior
631 && l3vpn1
->loc_block_len
== l3vpn2
->loc_block_len
632 && l3vpn1
->loc_node_len
== l3vpn2
->loc_node_len
633 && l3vpn1
->func_len
== l3vpn2
->func_len
634 && l3vpn1
->arg_len
== l3vpn2
->arg_len
635 && l3vpn1
->transposition_len
== l3vpn2
->transposition_len
636 && l3vpn1
->transposition_offset
== l3vpn2
->transposition_offset
;
639 static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn
*h1
,
640 const struct bgp_attr_srv6_l3vpn
*h2
)
644 else if (h1
== NULL
|| h2
== NULL
)
647 return srv6_l3vpn_hash_cmp((const void *)h1
, (const void *)h2
);
650 static unsigned int srv6_vpn_hash_key_make(const void *p
)
652 const struct bgp_attr_srv6_vpn
*vpn
= p
;
655 key
= jhash(&vpn
->sid
, 16, key
);
656 key
= jhash_1word(vpn
->sid_flags
, key
);
660 static bool srv6_vpn_hash_cmp(const void *p1
, const void *p2
)
662 const struct bgp_attr_srv6_vpn
*vpn1
= p1
;
663 const struct bgp_attr_srv6_vpn
*vpn2
= p2
;
665 return sid_same(&vpn1
->sid
, &vpn2
->sid
)
666 && vpn1
->sid_flags
== vpn2
->sid_flags
;
669 static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn
*h1
,
670 const struct bgp_attr_srv6_vpn
*h2
)
674 else if (h1
== NULL
|| h2
== NULL
)
677 return srv6_vpn_hash_cmp((const void *)h1
, (const void *)h2
);
680 static void srv6_init(void)
683 hash_create(srv6_l3vpn_hash_key_make
, srv6_l3vpn_hash_cmp
,
684 "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
685 srv6_vpn_hash
= hash_create(srv6_vpn_hash_key_make
, srv6_vpn_hash_cmp
,
686 "BGP Prefix-SID SRv6-VPN-Service-TLV");
689 static void srv6_finish(void)
691 hash_clean_and_free(&srv6_l3vpn_hash
,
692 (void (*)(void *))srv6_l3vpn_free
);
693 hash_clean_and_free(&srv6_vpn_hash
, (void (*)(void *))srv6_vpn_free
);
696 static unsigned int transit_hash_key_make(const void *p
)
698 const struct transit
*transit
= p
;
700 return jhash(transit
->val
, transit
->length
, 0);
703 static bool transit_hash_cmp(const void *p1
, const void *p2
)
705 const struct transit
*transit1
= p1
;
706 const struct transit
*transit2
= p2
;
708 return (transit1
->length
== transit2
->length
709 && memcmp(transit1
->val
, transit2
->val
, transit1
->length
) == 0);
712 static void transit_init(void)
714 transit_hash
= hash_create(transit_hash_key_make
, transit_hash_cmp
,
718 static void transit_finish(void)
720 hash_clean_and_free(&transit_hash
, (void (*)(void *))transit_free
);
723 /* Attribute hash routines. */
724 static struct hash
*attrhash
;
726 unsigned long int attr_count(void)
728 return attrhash
->count
;
731 unsigned long int attr_unknown_count(void)
733 return transit_hash
->count
;
736 unsigned int attrhash_key_make(const void *p
)
738 const struct attr
*attr
= (struct attr
*)p
;
740 #define MIX(val) key = jhash_1word(val, key)
741 #define MIX3(a, b, c) key = jhash_3words((a), (b), (c), key)
743 MIX3(attr
->origin
, attr
->nexthop
.s_addr
, attr
->med
);
744 MIX3(attr
->local_pref
, attr
->aggregator_as
,
745 attr
->aggregator_addr
.s_addr
);
746 MIX3(attr
->weight
, attr
->mp_nexthop_global_in
.s_addr
,
747 attr
->originator_id
.s_addr
);
748 MIX3(attr
->tag
, attr
->label
, attr
->label_index
);
751 MIX(aspath_key_make(attr
->aspath
));
752 if (bgp_attr_get_community(attr
))
753 MIX(community_hash_make(bgp_attr_get_community(attr
)));
754 if (bgp_attr_get_lcommunity(attr
))
755 MIX(lcommunity_hash_make(bgp_attr_get_lcommunity(attr
)));
756 if (bgp_attr_get_ecommunity(attr
))
757 MIX(ecommunity_hash_make(bgp_attr_get_ecommunity(attr
)));
758 if (bgp_attr_get_ipv6_ecommunity(attr
))
759 MIX(ecommunity_hash_make(bgp_attr_get_ipv6_ecommunity(attr
)));
760 if (bgp_attr_get_cluster(attr
))
761 MIX(cluster_hash_key_make(bgp_attr_get_cluster(attr
)));
762 if (bgp_attr_get_transit(attr
))
763 MIX(transit_hash_key_make(bgp_attr_get_transit(attr
)));
764 if (attr
->encap_subtlvs
)
765 MIX(encap_hash_key_make(attr
->encap_subtlvs
));
766 if (attr
->srv6_l3vpn
)
767 MIX(srv6_l3vpn_hash_key_make(attr
->srv6_l3vpn
));
769 MIX(srv6_vpn_hash_key_make(attr
->srv6_vpn
));
770 #ifdef ENABLE_BGP_VNC
771 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
772 bgp_attr_get_vnc_subtlvs(attr
);
774 MIX(encap_hash_key_make(vnc_subtlvs
));
776 MIX(attr
->mp_nexthop_len
);
777 key
= jhash(attr
->mp_nexthop_global
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
778 key
= jhash(attr
->mp_nexthop_local
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
779 MIX3(attr
->nh_ifindex
, attr
->nh_lla_ifindex
, attr
->distance
);
780 MIX(attr
->rmap_table_id
);
784 MIX(bgp_attr_get_aigp_metric(attr
));
789 bool attrhash_cmp(const void *p1
, const void *p2
)
791 const struct attr
*attr1
= p1
;
792 const struct attr
*attr2
= p2
;
794 if (attr1
->flag
== attr2
->flag
&& attr1
->origin
== attr2
->origin
795 && attr1
->nexthop
.s_addr
== attr2
->nexthop
.s_addr
796 && attr1
->aspath
== attr2
->aspath
797 && bgp_attr_get_community(attr1
)
798 == bgp_attr_get_community(attr2
)
799 && attr1
->med
== attr2
->med
800 && attr1
->local_pref
== attr2
->local_pref
801 && attr1
->rmap_change_flags
== attr2
->rmap_change_flags
) {
802 if (attr1
->aggregator_as
== attr2
->aggregator_as
&&
803 attr1
->aggregator_addr
.s_addr
==
804 attr2
->aggregator_addr
.s_addr
&&
805 attr1
->weight
== attr2
->weight
&&
806 attr1
->tag
== attr2
->tag
&&
807 attr1
->label_index
== attr2
->label_index
&&
808 attr1
->mp_nexthop_len
== attr2
->mp_nexthop_len
&&
809 bgp_attr_get_ecommunity(attr1
) ==
810 bgp_attr_get_ecommunity(attr2
) &&
811 bgp_attr_get_ipv6_ecommunity(attr1
) ==
812 bgp_attr_get_ipv6_ecommunity(attr2
) &&
813 bgp_attr_get_lcommunity(attr1
) ==
814 bgp_attr_get_lcommunity(attr2
) &&
815 bgp_attr_get_cluster(attr1
) ==
816 bgp_attr_get_cluster(attr2
) &&
817 bgp_attr_get_transit(attr1
) ==
818 bgp_attr_get_transit(attr2
) &&
819 bgp_attr_get_aigp_metric(attr1
) ==
820 bgp_attr_get_aigp_metric(attr2
) &&
821 attr1
->rmap_table_id
== attr2
->rmap_table_id
&&
822 (attr1
->encap_tunneltype
== attr2
->encap_tunneltype
) &&
823 encap_same(attr1
->encap_subtlvs
, attr2
->encap_subtlvs
)
824 #ifdef ENABLE_BGP_VNC
825 && encap_same(bgp_attr_get_vnc_subtlvs(attr1
),
826 bgp_attr_get_vnc_subtlvs(attr2
))
828 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_global
,
829 &attr2
->mp_nexthop_global
) &&
830 IPV6_ADDR_SAME(&attr1
->mp_nexthop_local
,
831 &attr2
->mp_nexthop_local
) &&
832 IPV4_ADDR_SAME(&attr1
->mp_nexthop_global_in
,
833 &attr2
->mp_nexthop_global_in
) &&
834 IPV4_ADDR_SAME(&attr1
->originator_id
,
835 &attr2
->originator_id
) &&
836 overlay_index_same(attr1
, attr2
) &&
837 !memcmp(&attr1
->esi
, &attr2
->esi
, sizeof(esi_t
)) &&
838 attr1
->es_flags
== attr2
->es_flags
&&
839 attr1
->mm_sync_seqnum
== attr2
->mm_sync_seqnum
&&
840 attr1
->df_pref
== attr2
->df_pref
&&
841 attr1
->df_alg
== attr2
->df_alg
&&
842 attr1
->nh_ifindex
== attr2
->nh_ifindex
&&
843 attr1
->nh_lla_ifindex
== attr2
->nh_lla_ifindex
&&
844 attr1
->distance
== attr2
->distance
&&
845 srv6_l3vpn_same(attr1
->srv6_l3vpn
, attr2
->srv6_l3vpn
) &&
846 srv6_vpn_same(attr1
->srv6_vpn
, attr2
->srv6_vpn
) &&
847 attr1
->srte_color
== attr2
->srte_color
&&
848 attr1
->nh_type
== attr2
->nh_type
&&
849 attr1
->bh_type
== attr2
->bh_type
&&
850 attr1
->otc
== attr2
->otc
)
857 static void attrhash_init(void)
860 hash_create(attrhash_key_make
, attrhash_cmp
, "BGP Attributes");
864 * special for hash_clean below
866 static void attr_vfree(void *attr
)
868 XFREE(MTYPE_ATTR
, attr
);
871 static void attrhash_finish(void)
873 hash_clean_and_free(&attrhash
, attr_vfree
);
876 static void attr_show_all_iterator(struct hash_bucket
*bucket
, struct vty
*vty
)
878 struct attr
*attr
= bucket
->data
;
879 struct in6_addr
*sid
= NULL
;
881 if (attr
->srv6_l3vpn
)
882 sid
= &attr
->srv6_l3vpn
->sid
;
883 else if (attr
->srv6_vpn
)
884 sid
= &attr
->srv6_vpn
->sid
;
886 vty_out(vty
, "attr[%ld] nexthop %pI4\n", attr
->refcnt
, &attr
->nexthop
);
890 " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n",
891 attr
->flag
, attr
->distance
, attr
->med
, attr
->local_pref
,
892 attr
->origin
, attr
->weight
, attr
->label
, sid
);
895 void attr_show_all(struct vty
*vty
)
897 hash_iterate(attrhash
, (void (*)(struct hash_bucket
*,
898 void *))attr_show_all_iterator
,
902 static void *bgp_attr_hash_alloc(void *p
)
904 struct attr
*val
= (struct attr
*)p
;
907 attr
= XMALLOC(MTYPE_ATTR
, sizeof(struct attr
));
909 if (val
->encap_subtlvs
) {
910 val
->encap_subtlvs
= NULL
;
912 #ifdef ENABLE_BGP_VNC
913 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
914 bgp_attr_get_vnc_subtlvs(val
);
917 bgp_attr_set_vnc_subtlvs(val
, NULL
);
924 /* Internet argument attribute. */
925 struct attr
*bgp_attr_intern(struct attr
*attr
)
928 struct ecommunity
*ecomm
= NULL
;
929 struct ecommunity
*ipv6_ecomm
= NULL
;
930 struct lcommunity
*lcomm
= NULL
;
931 struct community
*comm
= NULL
;
933 /* Intern referenced structure. */
935 if (!attr
->aspath
->refcnt
)
936 attr
->aspath
= aspath_intern(attr
->aspath
);
938 attr
->aspath
->refcnt
++;
941 comm
= bgp_attr_get_community(attr
);
944 bgp_attr_set_community(attr
, community_intern(comm
));
949 ecomm
= bgp_attr_get_ecommunity(attr
);
952 bgp_attr_set_ecommunity(attr
, ecommunity_intern(ecomm
));
957 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
959 if (!ipv6_ecomm
->refcnt
)
960 bgp_attr_set_ipv6_ecommunity(
961 attr
, ecommunity_intern(ipv6_ecomm
));
963 ipv6_ecomm
->refcnt
++;
966 lcomm
= bgp_attr_get_lcommunity(attr
);
969 bgp_attr_set_lcommunity(attr
, lcommunity_intern(lcomm
));
974 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
977 if (!cluster
->refcnt
)
978 bgp_attr_set_cluster(attr
, cluster_intern(cluster
));
983 struct transit
*transit
= bgp_attr_get_transit(attr
);
986 if (!transit
->refcnt
)
987 bgp_attr_set_transit(attr
, transit_intern(transit
));
991 if (attr
->encap_subtlvs
) {
992 if (!attr
->encap_subtlvs
->refcnt
)
993 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
996 attr
->encap_subtlvs
->refcnt
++;
998 if (attr
->srv6_l3vpn
) {
999 if (!attr
->srv6_l3vpn
->refcnt
)
1000 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
1002 attr
->srv6_l3vpn
->refcnt
++;
1004 if (attr
->srv6_vpn
) {
1005 if (!attr
->srv6_vpn
->refcnt
)
1006 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
1008 attr
->srv6_vpn
->refcnt
++;
1010 #ifdef ENABLE_BGP_VNC
1011 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1012 bgp_attr_get_vnc_subtlvs(attr
);
1015 if (!vnc_subtlvs
->refcnt
)
1016 bgp_attr_set_vnc_subtlvs(
1018 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
1020 vnc_subtlvs
->refcnt
++;
1024 /* At this point, attr only contains intern'd pointers. that means
1025 * if we find it in attrhash, it has all the same pointers and we
1026 * correctly updated the refcounts on these.
1027 * If we don't find it, we need to allocate a one because in all
1028 * cases this returns a new reference to a hashed attr, but the input
1029 * wasn't on hash. */
1030 find
= (struct attr
*)hash_get(attrhash
, attr
, bgp_attr_hash_alloc
);
1036 /* Make network statement's attribute. */
1037 struct attr
*bgp_attr_default_set(struct attr
*attr
, struct bgp
*bgp
,
1040 memset(attr
, 0, sizeof(struct attr
));
1042 attr
->origin
= origin
;
1043 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1044 attr
->aspath
= aspath_empty(bgp
->asnotation
);
1045 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1046 attr
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1048 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
1049 attr
->label
= MPLS_INVALID_LABEL
;
1050 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1051 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1052 attr
->local_pref
= bgp
->default_local_pref
;
1057 /* Create the attributes for an aggregate */
1058 struct attr
*bgp_attr_aggregate_intern(
1059 struct bgp
*bgp
, uint8_t origin
, struct aspath
*aspath
,
1060 struct community
*community
, struct ecommunity
*ecommunity
,
1061 struct lcommunity
*lcommunity
, struct bgp_aggregate
*aggregate
,
1062 uint8_t atomic_aggregate
, const struct prefix
*p
)
1066 route_map_result_t ret
;
1068 memset(&attr
, 0, sizeof(attr
));
1070 /* Origin attribute. */
1071 attr
.origin
= origin
;
1072 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1076 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1078 /* AS path attribute. */
1080 attr
.aspath
= aspath_intern(aspath
);
1082 attr
.aspath
= aspath_empty(bgp
->asnotation
);
1083 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1085 /* Next hop attribute. */
1086 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1089 uint32_t gshut
= COMMUNITY_GSHUT
;
1091 /* If we are not shutting down ourselves and we are
1092 * aggregating a route that contains the GSHUT community we
1093 * need to remove that community when creating the aggregate */
1094 if (!bgp_in_graceful_shutdown(bgp
)
1095 && community_include(community
, gshut
)) {
1096 community_del_val(community
, &gshut
);
1099 bgp_attr_set_community(&attr
, community
);
1103 bgp_attr_set_ecommunity(&attr
, ecommunity
);
1106 bgp_attr_set_lcommunity(&attr
, lcommunity
);
1108 if (bgp_in_graceful_shutdown(bgp
))
1109 bgp_attr_add_gshut_community(&attr
);
1111 attr
.label_index
= BGP_INVALID_LABEL_INDEX
;
1112 attr
.label
= MPLS_INVALID_LABEL
;
1113 attr
.weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1114 attr
.mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1115 if (!aggregate
->as_set
|| atomic_aggregate
)
1116 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1117 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1118 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
))
1119 attr
.aggregator_as
= bgp
->confed_id
;
1121 attr
.aggregator_as
= bgp
->as
;
1122 attr
.aggregator_addr
= bgp
->router_id
;
1124 /* Apply route-map */
1125 if (aggregate
->rmap
.name
) {
1126 struct attr attr_tmp
= attr
;
1127 struct bgp_path_info rmap_path
;
1129 memset(&rmap_path
, 0, sizeof(rmap_path
));
1130 rmap_path
.peer
= bgp
->peer_self
;
1131 rmap_path
.attr
= &attr_tmp
;
1133 SET_FLAG(bgp
->peer_self
->rmap_type
, PEER_RMAP_TYPE_AGGREGATE
);
1135 ret
= route_map_apply(aggregate
->rmap
.map
, p
, &rmap_path
);
1137 bgp
->peer_self
->rmap_type
= 0;
1139 if (ret
== RMAP_DENYMATCH
) {
1140 /* Free uninterned attribute. */
1141 bgp_attr_flush(&attr_tmp
);
1143 /* Unintern original. */
1144 aspath_unintern(&attr
.aspath
);
1148 if (bgp_in_graceful_shutdown(bgp
))
1149 bgp_attr_add_gshut_community(&attr_tmp
);
1151 new = bgp_attr_intern(&attr_tmp
);
1154 if (bgp_in_graceful_shutdown(bgp
))
1155 bgp_attr_add_gshut_community(&attr
);
1157 new = bgp_attr_intern(&attr
);
1160 /* Always release the 'intern()'ed AS Path. */
1161 aspath_unintern(&attr
.aspath
);
1166 /* Unintern just the sub-components of the attr, but not the attr */
1167 void bgp_attr_unintern_sub(struct attr
*attr
)
1169 struct ecommunity
*ecomm
= NULL
;
1170 struct ecommunity
*ipv6_ecomm
= NULL
;
1171 struct cluster_list
*cluster
;
1172 struct lcommunity
*lcomm
= NULL
;
1173 struct community
*comm
= NULL
;
1175 /* aspath refcount shoud be decrement. */
1176 aspath_unintern(&attr
->aspath
);
1177 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
));
1179 comm
= bgp_attr_get_community(attr
);
1180 community_unintern(&comm
);
1181 bgp_attr_set_community(attr
, NULL
);
1183 ecomm
= bgp_attr_get_ecommunity(attr
);
1184 ecommunity_unintern(&ecomm
);
1185 bgp_attr_set_ecommunity(attr
, NULL
);
1187 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1188 ecommunity_unintern(&ipv6_ecomm
);
1189 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1191 lcomm
= bgp_attr_get_lcommunity(attr
);
1192 lcommunity_unintern(&lcomm
);
1193 bgp_attr_set_lcommunity(attr
, NULL
);
1195 cluster
= bgp_attr_get_cluster(attr
);
1197 cluster_unintern(&cluster
);
1198 bgp_attr_set_cluster(attr
, cluster
);
1200 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
));
1202 struct transit
*transit
= bgp_attr_get_transit(attr
);
1205 transit_unintern(&transit
);
1206 bgp_attr_set_transit(attr
, transit
);
1209 if (attr
->encap_subtlvs
)
1210 encap_unintern(&attr
->encap_subtlvs
, ENCAP_SUBTLV_TYPE
);
1212 #ifdef ENABLE_BGP_VNC
1213 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1214 bgp_attr_get_vnc_subtlvs(attr
);
1217 encap_unintern(&vnc_subtlvs
, VNC_SUBTLV_TYPE
);
1218 bgp_attr_set_vnc_subtlvs(attr
, vnc_subtlvs
);
1222 if (attr
->srv6_l3vpn
)
1223 srv6_l3vpn_unintern(&attr
->srv6_l3vpn
);
1226 srv6_vpn_unintern(&attr
->srv6_vpn
);
1229 /* Free bgp attribute and aspath. */
1230 void bgp_attr_unintern(struct attr
**pattr
)
1232 struct attr
*attr
= *pattr
;
1236 /* Decrement attribute reference. */
1241 /* If reference becomes zero then free attribute object. */
1242 if (attr
->refcnt
== 0) {
1243 ret
= hash_release(attrhash
, attr
);
1244 assert(ret
!= NULL
);
1245 XFREE(MTYPE_ATTR
, attr
);
1249 bgp_attr_unintern_sub(&tmp
);
1252 void bgp_attr_flush(struct attr
*attr
)
1254 struct ecommunity
*ecomm
;
1255 struct ecommunity
*ipv6_ecomm
;
1256 struct cluster_list
*cluster
;
1257 struct lcommunity
*lcomm
;
1258 struct community
*comm
;
1260 if (attr
->aspath
&& !attr
->aspath
->refcnt
) {
1261 aspath_free(attr
->aspath
);
1262 attr
->aspath
= NULL
;
1264 comm
= bgp_attr_get_community(attr
);
1265 if (comm
&& !comm
->refcnt
)
1266 community_free(&comm
);
1267 bgp_attr_set_community(attr
, NULL
);
1269 ecomm
= bgp_attr_get_ecommunity(attr
);
1270 if (ecomm
&& !ecomm
->refcnt
)
1271 ecommunity_free(&ecomm
);
1272 bgp_attr_set_ecommunity(attr
, NULL
);
1274 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1275 if (ipv6_ecomm
&& !ipv6_ecomm
->refcnt
)
1276 ecommunity_free(&ipv6_ecomm
);
1277 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1279 lcomm
= bgp_attr_get_lcommunity(attr
);
1280 if (lcomm
&& !lcomm
->refcnt
)
1281 lcommunity_free(&lcomm
);
1282 bgp_attr_set_lcommunity(attr
, NULL
);
1284 cluster
= bgp_attr_get_cluster(attr
);
1285 if (cluster
&& !cluster
->refcnt
) {
1286 cluster_free(cluster
);
1287 bgp_attr_set_cluster(attr
, NULL
);
1290 struct transit
*transit
= bgp_attr_get_transit(attr
);
1292 if (transit
&& !transit
->refcnt
) {
1293 transit_free(transit
);
1294 bgp_attr_set_transit(attr
, NULL
);
1296 if (attr
->encap_subtlvs
&& !attr
->encap_subtlvs
->refcnt
) {
1297 encap_free(attr
->encap_subtlvs
);
1298 attr
->encap_subtlvs
= NULL
;
1300 if (attr
->srv6_l3vpn
&& !attr
->srv6_l3vpn
->refcnt
) {
1301 srv6_l3vpn_free(attr
->srv6_l3vpn
);
1302 attr
->srv6_l3vpn
= NULL
;
1304 if (attr
->srv6_vpn
&& !attr
->srv6_vpn
->refcnt
) {
1305 srv6_vpn_free(attr
->srv6_vpn
);
1306 attr
->srv6_vpn
= NULL
;
1308 #ifdef ENABLE_BGP_VNC
1309 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1310 bgp_attr_get_vnc_subtlvs(attr
);
1312 if (vnc_subtlvs
&& !vnc_subtlvs
->refcnt
) {
1313 encap_free(vnc_subtlvs
);
1314 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
1319 /* Implement draft-scudder-idr-optional-transitive behaviour and
1320 * avoid resetting sessions for malformed attributes which are
1321 * are partial/optional and hence where the error likely was not
1322 * introduced by the sending neighbour.
1324 static enum bgp_attr_parse_ret
1325 bgp_attr_malformed(struct bgp_attr_parser_args
*args
, uint8_t subcode
,
1328 struct peer
*const peer
= args
->peer
;
1329 struct attr
*const attr
= args
->attr
;
1330 const uint8_t flags
= args
->flags
;
1331 /* startp and length must be special-cased, as whether or not to
1332 * send the attribute data with the NOTIFY depends on the error,
1333 * the caller therefore signals this with the seperate length argument
1335 uint8_t *notify_datap
= (length
> 0 ? args
->startp
: NULL
);
1337 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1338 char attr_str
[BUFSIZ
] = {0};
1340 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1342 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1345 /* Only relax error handling for eBGP peers */
1346 if (peer
->sort
!= BGP_PEER_EBGP
) {
1347 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1348 notify_datap
, length
);
1349 return BGP_ATTR_PARSE_ERROR
;
1352 /* Adjust the stream getp to the end of the attribute, in case we can
1353 * still proceed but the caller hasn't read all the attribute.
1355 stream_set_getp(BGP_INPUT(peer
),
1356 (args
->startp
- STREAM_DATA(BGP_INPUT(peer
)))
1359 switch (args
->type
) {
1360 /* where an attribute is relatively inconsequential, e.g. it does not
1361 * affect route selection, and can be safely ignored, then any such
1362 * attributes which are malformed should just be ignored and the route
1363 * processed as normal.
1365 case BGP_ATTR_AS4_AGGREGATOR
:
1366 case BGP_ATTR_AGGREGATOR
:
1367 case BGP_ATTR_ATOMIC_AGGREGATE
:
1368 return BGP_ATTR_PARSE_PROCEED
;
1370 /* Core attributes, particularly ones which may influence route
1371 * selection, should be treat-as-withdraw.
1373 case BGP_ATTR_ORIGIN
:
1374 case BGP_ATTR_AS_PATH
:
1375 case BGP_ATTR_NEXT_HOP
:
1376 case BGP_ATTR_MULTI_EXIT_DISC
:
1377 case BGP_ATTR_LOCAL_PREF
:
1378 case BGP_ATTR_COMMUNITIES
:
1379 case BGP_ATTR_EXT_COMMUNITIES
:
1380 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
1381 case BGP_ATTR_LARGE_COMMUNITIES
:
1382 case BGP_ATTR_ORIGINATOR_ID
:
1383 case BGP_ATTR_CLUSTER_LIST
:
1385 return BGP_ATTR_PARSE_WITHDRAW
;
1386 case BGP_ATTR_MP_REACH_NLRI
:
1387 case BGP_ATTR_MP_UNREACH_NLRI
:
1388 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1389 notify_datap
, length
);
1390 return BGP_ATTR_PARSE_ERROR
;
1393 /* Partial optional attributes that are malformed should not cause
1394 * the whole session to be reset. Instead treat it as a withdrawal
1395 * of the routes, if possible.
1397 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)
1398 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1399 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
))
1400 return BGP_ATTR_PARSE_WITHDRAW
;
1402 /* default to reset */
1403 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1406 /* Find out what is wrong with the path attribute flag bits and log the error.
1407 "Flag bits" here stand for Optional, Transitive and Partial, but not for
1408 Extended Length. Checking O/T/P bits at once implies, that the attribute
1409 being diagnosed is defined by RFC as either a "well-known" or an "optional,
1410 non-transitive" attribute. */
1412 bgp_attr_flags_diagnose(struct bgp_attr_parser_args
*args
,
1413 uint8_t desired_flags
/* how RFC says it must be */
1416 uint8_t seen
= 0, i
;
1417 uint8_t real_flags
= args
->flags
;
1418 const uint8_t attr_code
= args
->type
;
1420 desired_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1421 real_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1422 for (i
= 0; i
<= 2; i
++) /* O,T,P, but not E */
1423 if (CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1424 != CHECK_FLAG(real_flags
, attr_flag_str
[i
].key
)) {
1425 flog_err(EC_BGP_ATTR_FLAG
,
1426 "%s attribute must%s be flagged as \"%s\"",
1427 lookup_msg(attr_str
, attr_code
, NULL
),
1428 CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1431 attr_flag_str
[i
].str
);
1436 "Strange, %s called for attr %s, but no problem found with flags (real flags 0x%x, desired 0x%x)",
1437 __func__
, lookup_msg(attr_str
, attr_code
, NULL
),
1438 real_flags
, desired_flags
);
1442 /* Required flags for attributes. EXTLEN will be masked off when testing,
1443 * as will PARTIAL for optional+transitive attributes.
1445 const uint8_t attr_flags_values
[] = {
1446 [BGP_ATTR_ORIGIN
] = BGP_ATTR_FLAG_TRANS
,
1447 [BGP_ATTR_AS_PATH
] = BGP_ATTR_FLAG_TRANS
,
1448 [BGP_ATTR_NEXT_HOP
] = BGP_ATTR_FLAG_TRANS
,
1449 [BGP_ATTR_MULTI_EXIT_DISC
] = BGP_ATTR_FLAG_OPTIONAL
,
1450 [BGP_ATTR_LOCAL_PREF
] = BGP_ATTR_FLAG_TRANS
,
1451 [BGP_ATTR_ATOMIC_AGGREGATE
] = BGP_ATTR_FLAG_TRANS
,
1452 [BGP_ATTR_AGGREGATOR
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1453 [BGP_ATTR_COMMUNITIES
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1454 [BGP_ATTR_ORIGINATOR_ID
] = BGP_ATTR_FLAG_OPTIONAL
,
1455 [BGP_ATTR_CLUSTER_LIST
] = BGP_ATTR_FLAG_OPTIONAL
,
1456 [BGP_ATTR_MP_REACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1457 [BGP_ATTR_MP_UNREACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1458 [BGP_ATTR_EXT_COMMUNITIES
] =
1459 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1460 [BGP_ATTR_AS4_PATH
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1461 [BGP_ATTR_AS4_AGGREGATOR
] =
1462 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1463 [BGP_ATTR_PMSI_TUNNEL
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1464 [BGP_ATTR_LARGE_COMMUNITIES
] =
1465 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1466 [BGP_ATTR_OTC
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1467 [BGP_ATTR_PREFIX_SID
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1468 [BGP_ATTR_IPV6_EXT_COMMUNITIES
] =
1469 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1470 [BGP_ATTR_AIGP
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1472 static const size_t attr_flags_values_max
= array_size(attr_flags_values
) - 1;
1474 static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args
*args
)
1476 uint8_t mask
= BGP_ATTR_FLAG_EXTLEN
;
1477 const uint8_t flags
= args
->flags
;
1478 const uint8_t attr_code
= args
->type
;
1480 /* there may be attributes we don't know about */
1481 if (attr_code
> attr_flags_values_max
)
1483 if (attr_flags_values
[attr_code
] == 0)
1486 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set
1490 if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL
, flags
)
1491 && !CHECK_FLAG(BGP_ATTR_FLAG_TRANS
, flags
)) {
1494 "%s well-known attributes must have transitive flag set (%x)",
1495 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1499 /* "For well-known attributes and for optional non-transitive
1501 * the Partial bit MUST be set to 0."
1503 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
)) {
1504 if (!CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)) {
1505 flog_err(EC_BGP_ATTR_FLAG
,
1506 "%s well-known attribute must NOT have the partial flag set (%x)",
1507 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1510 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1511 && !CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)) {
1512 flog_err(EC_BGP_ATTR_FLAG
,
1513 "%s optional + transitive attribute must NOT have the partial flag set (%x)",
1514 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1519 /* Optional transitive attributes may go through speakers that don't
1520 * reocgnise them and set the Partial bit.
1522 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1523 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
))
1524 SET_FLAG(mask
, BGP_ATTR_FLAG_PARTIAL
);
1526 if ((flags
& ~mask
) == attr_flags_values
[attr_code
])
1529 bgp_attr_flags_diagnose(args
, attr_flags_values
[attr_code
]);
1533 /* Get origin attribute of the update message. */
1534 static enum bgp_attr_parse_ret
1535 bgp_attr_origin(struct bgp_attr_parser_args
*args
)
1537 struct peer
*const peer
= args
->peer
;
1538 struct attr
*const attr
= args
->attr
;
1539 const bgp_size_t length
= args
->length
;
1541 /* If any recognized attribute has Attribute Length that conflicts
1542 with the expected length (based on the attribute type code), then
1543 the Error Subcode is set to Attribute Length Error. The Data
1544 field contains the erroneous attribute (type, length and
1547 flog_err(EC_BGP_ATTR_LEN
,
1548 "Origin attribute length is not one %d", length
);
1549 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1553 /* Fetch origin attribute. */
1554 attr
->origin
= stream_getc(BGP_INPUT(peer
));
1556 /* If the ORIGIN attribute has an undefined value, then the Error
1557 Subcode is set to Invalid Origin Attribute. The Data field
1558 contains the unrecognized attribute (type, length and value). */
1559 if ((attr
->origin
!= BGP_ORIGIN_IGP
) && (attr
->origin
!= BGP_ORIGIN_EGP
)
1560 && (attr
->origin
!= BGP_ORIGIN_INCOMPLETE
)) {
1561 flog_err(EC_BGP_ATTR_ORIGIN
,
1562 "Origin attribute value is invalid %d", attr
->origin
);
1563 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_INVAL_ORIGIN
,
1567 /* Set oring attribute flag. */
1568 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1573 /* Parse AS path information. This function is wrapper of
1575 static int bgp_attr_aspath(struct bgp_attr_parser_args
*args
)
1577 struct attr
*const attr
= args
->attr
;
1578 struct peer
*const peer
= args
->peer
;
1579 const bgp_size_t length
= args
->length
;
1580 enum asnotation_mode asnotation
;
1582 asnotation
= bgp_get_asnotation(
1583 args
->peer
&& args
->peer
->bgp
? args
->peer
->bgp
: NULL
);
1585 * peer with AS4 => will get 4Byte ASnums
1586 * otherwise, will get 16 Bit
1589 aspath_parse(peer
->curr
, length
,
1590 CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
) &&
1591 CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
),
1594 /* In case of IBGP, length will be zero. */
1595 if (!attr
->aspath
) {
1596 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1597 "Malformed AS path from %s, length is %d", peer
->host
,
1599 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1603 /* Conformant BGP speakers SHOULD NOT send BGP
1604 * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1605 * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1606 * withdraw" error handling behavior as per [RFC7606].
1608 if (peer
->bgp
&& peer
->bgp
->reject_as_sets
&&
1609 aspath_check_as_sets(attr
->aspath
)) {
1610 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1611 "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1613 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1617 /* Set aspath attribute flag. */
1618 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1620 return BGP_ATTR_PARSE_PROCEED
;
1623 static enum bgp_attr_parse_ret
bgp_attr_aspath_check(struct peer
*const peer
,
1624 struct attr
*const attr
)
1626 /* These checks were part of bgp_attr_aspath, but with
1627 * as4 we should to check aspath things when
1628 * aspath synthesizing with as4_path has already taken place.
1629 * Otherwise we check ASPATH and use the synthesized thing, and that is
1631 * So do the checks later, i.e. here
1633 struct aspath
*aspath
;
1635 /* Refresh peer's type. If we set e.g.: AS_EXTERNAL/AS_INTERNAL,
1636 * then peer->sort remains BGP_PEER_EBGP/IBGP, hence we need to
1637 * have an actual type before checking.
1638 * This is especially a case for BGP confederation peers, to avoid
1639 * receiving and treating AS_PATH as malformed.
1641 (void)peer_sort(peer
);
1643 /* Confederation sanity check. */
1644 if ((peer
->sort
== BGP_PEER_CONFED
1645 && !aspath_left_confed_check(attr
->aspath
))
1646 || (peer
->sort
== BGP_PEER_EBGP
1647 && aspath_confed_check(attr
->aspath
))) {
1648 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "Malformed AS path from %s",
1650 return BGP_ATTR_PARSE_WITHDRAW
;
1653 /* First AS check for EBGP. */
1654 if (CHECK_FLAG(peer
->flags
, PEER_FLAG_ENFORCE_FIRST_AS
)) {
1655 if (peer
->sort
== BGP_PEER_EBGP
1656 && !aspath_firstas_check(attr
->aspath
, peer
->as
)) {
1657 flog_err(EC_BGP_ATTR_FIRST_AS
,
1658 "%s incorrect first AS (must be %u)",
1659 peer
->host
, peer
->as
);
1660 return BGP_ATTR_PARSE_WITHDRAW
;
1664 /* Codification of AS 0 Processing */
1665 if (peer
->sort
== BGP_PEER_EBGP
&& aspath_check_as_zero(attr
->aspath
)) {
1667 EC_BGP_ATTR_MAL_AS_PATH
,
1668 "Malformed AS path, AS number is 0 in the path from %s",
1670 return BGP_ATTR_PARSE_WITHDRAW
;
1673 /* local-as prepend */
1674 if (peer
->change_local_as
1675 && !CHECK_FLAG(peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
)) {
1676 aspath
= aspath_dup(attr
->aspath
);
1677 aspath
= aspath_add_seq(aspath
, peer
->change_local_as
);
1678 aspath_unintern(&attr
->aspath
);
1679 attr
->aspath
= aspath_intern(aspath
);
1682 return BGP_ATTR_PARSE_PROCEED
;
1685 /* Parse AS4 path information. This function is another wrapper of
1687 static int bgp_attr_as4_path(struct bgp_attr_parser_args
*args
,
1688 struct aspath
**as4_path
)
1690 struct peer
*const peer
= args
->peer
;
1691 struct attr
*const attr
= args
->attr
;
1692 const bgp_size_t length
= args
->length
;
1693 enum asnotation_mode asnotation
;
1695 asnotation
= bgp_get_asnotation(peer
->bgp
);
1697 *as4_path
= aspath_parse(peer
->curr
, length
, 1, asnotation
);
1699 /* In case of IBGP, length will be zero. */
1701 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1702 "Malformed AS4 path from %s, length is %d", peer
->host
,
1704 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1708 /* Conformant BGP speakers SHOULD NOT send BGP
1709 * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1710 * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1711 * withdraw" error handling behavior as per [RFC7606].
1713 if (peer
->bgp
->reject_as_sets
&& aspath_check_as_sets(attr
->aspath
)) {
1714 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1715 "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1717 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1721 /* Set aspath attribute flag. */
1722 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
);
1724 return BGP_ATTR_PARSE_PROCEED
;
1728 * Check that the nexthop attribute is valid.
1730 enum bgp_attr_parse_ret
bgp_attr_nexthop_valid(struct peer
*peer
,
1733 struct bgp
*bgp
= peer
->bgp
;
1735 if (ipv4_martian(&attr
->nexthop
) && !bgp
->allow_martian
) {
1736 uint8_t data
[7]; /* type(2) + length(1) + nhop(4) */
1738 flog_err(EC_BGP_ATTR_MARTIAN_NH
, "Martian nexthop %pI4",
1740 data
[0] = BGP_ATTR_FLAG_TRANS
;
1741 data
[1] = BGP_ATTR_NEXT_HOP
;
1742 data
[2] = BGP_ATTR_NHLEN_IPV4
;
1743 memcpy(&data
[3], &attr
->nexthop
.s_addr
, BGP_ATTR_NHLEN_IPV4
);
1744 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
1745 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1747 return BGP_ATTR_PARSE_ERROR
;
1750 return BGP_ATTR_PARSE_PROCEED
;
1753 /* Nexthop attribute. */
1754 static enum bgp_attr_parse_ret
1755 bgp_attr_nexthop(struct bgp_attr_parser_args
*args
)
1757 struct peer
*const peer
= args
->peer
;
1758 struct attr
*const attr
= args
->attr
;
1759 const bgp_size_t length
= args
->length
;
1761 /* Check nexthop attribute length. */
1763 flog_err(EC_BGP_ATTR_LEN
,
1764 "Nexthop attribute length isn't four [%d]", length
);
1766 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1770 attr
->nexthop
.s_addr
= stream_get_ipv4(peer
->curr
);
1771 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1773 return BGP_ATTR_PARSE_PROCEED
;
1776 /* MED atrribute. */
1777 static enum bgp_attr_parse_ret
bgp_attr_med(struct bgp_attr_parser_args
*args
)
1779 struct peer
*const peer
= args
->peer
;
1780 struct attr
*const attr
= args
->attr
;
1781 const bgp_size_t length
= args
->length
;
1785 flog_err(EC_BGP_ATTR_LEN
,
1786 "MED attribute length isn't four [%d]", length
);
1788 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1792 attr
->med
= stream_getl(peer
->curr
);
1794 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1796 return BGP_ATTR_PARSE_PROCEED
;
1799 /* Local preference attribute. */
1800 static enum bgp_attr_parse_ret
1801 bgp_attr_local_pref(struct bgp_attr_parser_args
*args
)
1803 struct peer
*const peer
= args
->peer
;
1804 struct attr
*const attr
= args
->attr
;
1805 const bgp_size_t length
= args
->length
;
1807 /* if received from an internal neighbor, it SHALL be considered
1808 * malformed if its length is not equal to 4. If malformed, the
1809 * UPDATE message SHALL be handled using the approach of "treat-as-
1812 if (peer
->sort
== BGP_PEER_IBGP
&& length
!= 4) {
1813 flog_err(EC_BGP_ATTR_LEN
,
1814 "LOCAL_PREF attribute length isn't 4 [%u]", length
);
1815 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1819 /* If it is contained in an UPDATE message that is received from an
1820 external peer, then this attribute MUST be ignored by the
1821 receiving speaker. */
1822 if (peer
->sort
== BGP_PEER_EBGP
) {
1823 STREAM_FORWARD_GETP(peer
->curr
, length
);
1824 return BGP_ATTR_PARSE_PROCEED
;
1827 STREAM_GETL(peer
->curr
, attr
->local_pref
);
1829 /* Set the local-pref flag. */
1830 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
1832 return BGP_ATTR_PARSE_PROCEED
;
1835 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1839 /* Atomic aggregate. */
1840 static int bgp_attr_atomic(struct bgp_attr_parser_args
*args
)
1842 struct peer
*const peer
= args
->peer
;
1843 struct attr
*const attr
= args
->attr
;
1844 const bgp_size_t length
= args
->length
;
1848 flog_err(EC_BGP_ATTR_LEN
,
1849 "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1851 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1855 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
1858 /* Set atomic aggregate flag. */
1859 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1861 return BGP_ATTR_PARSE_PROCEED
;
1864 stream_forward_getp(peer
->curr
, length
);
1866 return bgp_attr_ignore(peer
, args
->type
);
1869 /* Aggregator attribute */
1870 static int bgp_attr_aggregator(struct bgp_attr_parser_args
*args
)
1872 struct peer
*const peer
= args
->peer
;
1873 struct attr
*const attr
= args
->attr
;
1874 const bgp_size_t length
= args
->length
;
1879 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1880 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1881 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
))
1884 if (length
!= wantedlen
) {
1885 flog_err(EC_BGP_ATTR_LEN
,
1886 "AGGREGATOR attribute length isn't %u [%u]", wantedlen
,
1888 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1892 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
1893 goto aggregator_ignore
;
1895 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
))
1896 aggregator_as
= stream_getl(peer
->curr
);
1898 aggregator_as
= stream_getw(peer
->curr
);
1900 attr
->aggregator_as
= aggregator_as
;
1901 attr
->aggregator_addr
.s_addr
= stream_get_ipv4(peer
->curr
);
1903 /* Codification of AS 0 Processing */
1904 if (aggregator_as
== BGP_AS_ZERO
) {
1905 flog_err(EC_BGP_ATTR_LEN
,
1906 "%s: AGGREGATOR AS number is 0 for aspath: %s",
1907 peer
->host
, aspath_print(attr
->aspath
));
1909 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1910 char attr_str
[BUFSIZ
] = {0};
1912 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1914 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1917 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1920 return BGP_ATTR_PARSE_PROCEED
;
1923 stream_forward_getp(peer
->curr
, length
);
1925 return bgp_attr_ignore(peer
, args
->type
);
1928 /* New Aggregator attribute */
1929 static enum bgp_attr_parse_ret
1930 bgp_attr_as4_aggregator(struct bgp_attr_parser_args
*args
,
1931 as_t
*as4_aggregator_as
,
1932 struct in_addr
*as4_aggregator_addr
)
1934 struct peer
*const peer
= args
->peer
;
1935 struct attr
*const attr
= args
->attr
;
1936 const bgp_size_t length
= args
->length
;
1940 flog_err(EC_BGP_ATTR_LEN
, "New Aggregator length is not 8 [%d]",
1942 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1946 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
1947 goto as4_aggregator_ignore
;
1949 aggregator_as
= stream_getl(peer
->curr
);
1951 *as4_aggregator_as
= aggregator_as
;
1952 as4_aggregator_addr
->s_addr
= stream_get_ipv4(peer
->curr
);
1954 /* Codification of AS 0 Processing */
1955 if (aggregator_as
== BGP_AS_ZERO
) {
1956 flog_err(EC_BGP_ATTR_LEN
,
1957 "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
1958 peer
->host
, aspath_print(attr
->aspath
));
1960 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1961 char attr_str
[BUFSIZ
] = {0};
1963 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1965 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1968 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
);
1971 return BGP_ATTR_PARSE_PROCEED
;
1973 as4_aggregator_ignore
:
1974 stream_forward_getp(peer
->curr
, length
);
1976 return bgp_attr_ignore(peer
, args
->type
);
1979 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1981 static enum bgp_attr_parse_ret
1982 bgp_attr_munge_as4_attrs(struct peer
*const peer
, struct attr
*const attr
,
1983 struct aspath
*as4_path
, as_t as4_aggregator
,
1984 struct in_addr
*as4_aggregator_addr
)
1986 int ignore_as4_path
= 0;
1987 struct aspath
*newpath
;
1989 if (!attr
->aspath
) {
1990 /* NULL aspath shouldn't be possible as bgp_attr_parse should
1992 * checked that all well-known, mandatory attributes were
1995 * Can only be a problem with peer itself - hard error
1997 return BGP_ATTR_PARSE_ERROR
;
2000 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
2001 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
2003 * It is worth a warning though, because the peer really
2004 * should not send them
2006 if (BGP_DEBUG(as4
, AS4
)) {
2007 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
2008 zlog_debug("[AS4] %s %s AS4_PATH", peer
->host
,
2009 "AS4 capable peer, yet it sent");
2012 & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
2013 zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
2015 "AS4 capable peer, yet it sent");
2018 return BGP_ATTR_PARSE_PROCEED
;
2021 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
2022 * because that may override AS4_PATH
2024 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
))) {
2025 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
))) {
2027 * if the as_number in aggregator is not AS_TRANS,
2028 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
2029 * and the Aggregator shall be taken as
2030 * info on the aggregating node, and the AS_PATH
2031 * shall be taken as the AS_PATH
2033 * the Aggregator shall be ignored and the
2034 * AS4_AGGREGATOR shall be taken as the
2035 * Aggregating node and the AS_PATH is to be
2036 * constructed "as in all other cases"
2038 if (attr
->aggregator_as
!= BGP_AS_TRANS
) {
2040 if (BGP_DEBUG(as4
, AS4
))
2042 "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
2044 ignore_as4_path
= 1;
2046 /* "New_aggregator shall be taken as aggregator"
2048 attr
->aggregator_as
= as4_aggregator
;
2049 attr
->aggregator_addr
.s_addr
=
2050 as4_aggregator_addr
->s_addr
;
2053 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
2054 * That is bogus - but reading the conditions
2055 * we have to handle AS4_AGGREGATOR as if it were
2056 * AGGREGATOR in that case
2058 if (BGP_DEBUG(as4
, AS4
))
2060 "[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",
2062 attr
->aggregator_as
= as4_aggregator
;
2063 /* sweep it under the carpet and simulate a "good"
2065 attr
->flag
|= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
));
2069 /* need to reconcile NEW_AS_PATH and AS_PATH */
2070 if (!ignore_as4_path
2071 && (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))) {
2072 newpath
= aspath_reconcile_as4(attr
->aspath
, as4_path
);
2074 return BGP_ATTR_PARSE_ERROR
;
2076 aspath_unintern(&attr
->aspath
);
2077 attr
->aspath
= aspath_intern(newpath
);
2079 return BGP_ATTR_PARSE_PROCEED
;
2082 /* Community attribute. */
2083 static enum bgp_attr_parse_ret
2084 bgp_attr_community(struct bgp_attr_parser_args
*args
)
2086 struct peer
*const peer
= args
->peer
;
2087 struct attr
*const attr
= args
->attr
;
2088 const bgp_size_t length
= args
->length
;
2091 bgp_attr_set_community(attr
, NULL
);
2092 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2096 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2097 goto community_ignore
;
2099 bgp_attr_set_community(
2101 community_parse((uint32_t *)stream_pnt(peer
->curr
), length
));
2103 /* XXX: fix community_parse to use stream API and remove this */
2104 stream_forward_getp(peer
->curr
, length
);
2106 /* The Community attribute SHALL be considered malformed if its
2107 * length is not a non-zero multiple of 4.
2109 if (!bgp_attr_get_community(attr
))
2110 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2113 return BGP_ATTR_PARSE_PROCEED
;
2116 stream_forward_getp(peer
->curr
, length
);
2118 return bgp_attr_ignore(peer
, args
->type
);
2121 /* Originator ID attribute. */
2122 static enum bgp_attr_parse_ret
2123 bgp_attr_originator_id(struct bgp_attr_parser_args
*args
)
2125 struct peer
*const peer
= args
->peer
;
2126 struct attr
*const attr
= args
->attr
;
2127 const bgp_size_t length
= args
->length
;
2129 /* if received from an internal neighbor, it SHALL be considered
2130 * malformed if its length is not equal to 4. If malformed, the
2131 * UPDATE message SHALL be handled using the approach of "treat-as-
2135 flog_err(EC_BGP_ATTR_LEN
, "Bad originator ID length %d",
2138 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2142 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2143 goto originator_id_ignore
;
2145 attr
->originator_id
.s_addr
= stream_get_ipv4(peer
->curr
);
2147 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
2149 return BGP_ATTR_PARSE_PROCEED
;
2151 originator_id_ignore
:
2152 stream_forward_getp(peer
->curr
, length
);
2154 return bgp_attr_ignore(peer
, args
->type
);
2157 /* Cluster list attribute. */
2158 static enum bgp_attr_parse_ret
2159 bgp_attr_cluster_list(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 a non-zero multiple of 4. If
2167 * malformed, the UPDATE message SHALL be handled using the approach
2168 * of "treat-as-withdraw".
2170 if (length
== 0 || length
% 4) {
2171 flog_err(EC_BGP_ATTR_LEN
, "Bad cluster list length %d", length
);
2173 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2177 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2178 goto cluster_list_ignore
;
2180 bgp_attr_set_cluster(
2181 attr
, cluster_parse((struct in_addr
*)stream_pnt(peer
->curr
),
2184 /* XXX: Fix cluster_parse to use stream API and then remove this */
2185 stream_forward_getp(peer
->curr
, length
);
2187 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
);
2189 return BGP_ATTR_PARSE_PROCEED
;
2191 cluster_list_ignore
:
2192 stream_forward_getp(peer
->curr
, length
);
2194 return bgp_attr_ignore(peer
, args
->type
);
2197 /* Multiprotocol reachability information parse. */
2198 int bgp_mp_reach_parse(struct bgp_attr_parser_args
*args
,
2199 struct bgp_nlri
*mp_update
)
2203 iana_safi_t pkt_safi
;
2205 bgp_size_t nlri_len
;
2208 struct peer
*const peer
= args
->peer
;
2209 struct attr
*const attr
= args
->attr
;
2210 const bgp_size_t length
= args
->length
;
2212 /* Set end of packet. */
2213 s
= BGP_INPUT(peer
);
2214 start
= stream_get_getp(s
);
2216 /* safe to read statically sized header? */
2217 #define BGP_MP_REACH_MIN_SIZE 5
2218 #define LEN_LEFT (length - (stream_get_getp(s) - start))
2219 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
)) {
2220 zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
2221 __func__
, peer
->host
, (unsigned long)length
);
2222 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2225 /* Load AFI, SAFI. */
2226 pkt_afi
= stream_getw(s
);
2227 pkt_safi
= stream_getc(s
);
2229 /* Convert AFI, SAFI to internal values, check. */
2230 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2231 /* Log if AFI or SAFI is unrecognized. This is not an error
2233 * the attribute is otherwise malformed.
2235 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2237 "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
2238 peer
->host
, iana_afi2str(pkt_afi
),
2239 iana_safi2str(pkt_safi
));
2240 return BGP_ATTR_PARSE_ERROR
;
2243 /* Get nexthop length. */
2244 attr
->mp_nexthop_len
= stream_getc(s
);
2246 if (LEN_LEFT
< attr
->mp_nexthop_len
) {
2248 "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
2249 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2250 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2253 /* Nexthop length check. */
2254 switch (attr
->mp_nexthop_len
) {
2256 if (safi
!= SAFI_FLOWSPEC
) {
2257 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2258 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2259 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2262 case BGP_ATTR_NHLEN_VPNV4
:
2263 stream_getl(s
); /* RD high */
2264 stream_getl(s
); /* RD low */
2266 * NOTE: intentional fall through
2267 * - for consistency in rx processing
2269 * The following comment is to signal GCC this intention
2270 * and suppress the warning
2273 case BGP_ATTR_NHLEN_IPV4
:
2274 stream_get(&attr
->mp_nexthop_global_in
, s
, IPV4_MAX_BYTELEN
);
2275 /* Probably needed for RFC 2283 */
2276 if (attr
->nexthop
.s_addr
== INADDR_ANY
)
2277 memcpy(&attr
->nexthop
.s_addr
,
2278 &attr
->mp_nexthop_global_in
, IPV4_MAX_BYTELEN
);
2280 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
2281 case BGP_ATTR_NHLEN_VPNV6_GLOBAL
:
2282 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL
) {
2283 stream_getl(s
); /* RD high */
2284 stream_getl(s
); /* RD low */
2286 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2287 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2288 if (!peer
->nexthop
.ifp
) {
2289 zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2291 return BGP_ATTR_PARSE_WITHDRAW
;
2293 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2296 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
2297 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
:
2298 if (attr
->mp_nexthop_len
2299 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2300 stream_getl(s
); /* RD high */
2301 stream_getl(s
); /* RD low */
2303 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2304 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2305 if (!peer
->nexthop
.ifp
) {
2306 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",
2308 return BGP_ATTR_PARSE_WITHDRAW
;
2310 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2312 if (attr
->mp_nexthop_len
2313 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2314 stream_getl(s
); /* RD high */
2315 stream_getl(s
); /* RD low */
2317 stream_get(&attr
->mp_nexthop_local
, s
, IPV6_MAX_BYTELEN
);
2318 if (!IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_local
)) {
2319 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2321 "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
2322 peer
->host
, &attr
->mp_nexthop_global
,
2323 &attr
->mp_nexthop_local
);
2325 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
2327 if (!peer
->nexthop
.ifp
) {
2328 zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
2330 return BGP_ATTR_PARSE_WITHDRAW
;
2332 attr
->nh_lla_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2335 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2336 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2337 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2341 zlog_info("%s: %s sent SNPA which couldn't be read",
2342 __func__
, peer
->host
);
2343 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2348 if ((val
= stream_getc(s
)))
2350 EC_BGP_DEFUNCT_SNPA_LEN
,
2351 "%s sent non-zero value, %u, for defunct SNPA-length field",
2355 /* must have nrli_len, what is left of the attribute */
2356 nlri_len
= LEN_LEFT
;
2357 if (nlri_len
> STREAM_READABLE(s
)) {
2358 zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
2359 __func__
, peer
->host
);
2360 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2364 zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
2365 __func__
, peer
->host
);
2367 mp_update
->afi
= afi
;
2368 mp_update
->safi
= safi
;
2369 return BGP_ATTR_PARSE_EOR
;
2372 mp_update
->afi
= afi
;
2373 mp_update
->safi
= safi
;
2374 mp_update
->nlri
= stream_pnt(s
);
2375 mp_update
->length
= nlri_len
;
2377 stream_forward_getp(s
, nlri_len
);
2379 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
);
2381 return BGP_ATTR_PARSE_PROCEED
;
2385 /* Multiprotocol unreachable parse */
2386 int bgp_mp_unreach_parse(struct bgp_attr_parser_args
*args
,
2387 struct bgp_nlri
*mp_withdraw
)
2392 iana_safi_t pkt_safi
;
2394 uint16_t withdraw_len
;
2395 struct peer
*const peer
= args
->peer
;
2396 struct attr
*const attr
= args
->attr
;
2397 const bgp_size_t length
= args
->length
;
2401 #define BGP_MP_UNREACH_MIN_SIZE 3
2402 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
2403 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2405 pkt_afi
= stream_getw(s
);
2406 pkt_safi
= stream_getc(s
);
2408 /* Convert AFI, SAFI to internal values, check. */
2409 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2410 /* Log if AFI or SAFI is unrecognized. This is not an error
2412 * the attribute is otherwise malformed.
2414 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2416 "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
2417 peer
->host
, iana_afi2str(pkt_afi
),
2418 iana_safi2str(pkt_safi
));
2419 return BGP_ATTR_PARSE_ERROR
;
2422 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
2424 mp_withdraw
->afi
= afi
;
2425 mp_withdraw
->safi
= safi
;
2426 mp_withdraw
->nlri
= stream_pnt(s
);
2427 mp_withdraw
->length
= withdraw_len
;
2429 stream_forward_getp(s
, withdraw_len
);
2431 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
);
2433 return BGP_ATTR_PARSE_PROCEED
;
2436 /* Large Community attribute. */
2437 static enum bgp_attr_parse_ret
2438 bgp_attr_large_community(struct bgp_attr_parser_args
*args
)
2440 struct peer
*const peer
= args
->peer
;
2441 struct attr
*const attr
= args
->attr
;
2442 const bgp_size_t length
= args
->length
;
2445 * Large community follows new attribute format.
2448 bgp_attr_set_lcommunity(attr
, NULL
);
2449 /* Empty extcomm doesn't seem to be invalid per se */
2450 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2454 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2455 goto large_community_ignore
;
2457 bgp_attr_set_lcommunity(
2458 attr
, lcommunity_parse(stream_pnt(peer
->curr
), length
));
2459 /* XXX: fix ecommunity_parse to use stream API */
2460 stream_forward_getp(peer
->curr
, length
);
2462 if (!bgp_attr_get_lcommunity(attr
))
2463 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2466 return BGP_ATTR_PARSE_PROCEED
;
2468 large_community_ignore
:
2469 stream_forward_getp(peer
->curr
, length
);
2471 return bgp_attr_ignore(peer
, args
->type
);
2474 /* Extended Community attribute. */
2475 static enum bgp_attr_parse_ret
2476 bgp_attr_ext_communities(struct bgp_attr_parser_args
*args
)
2478 struct peer
*const peer
= args
->peer
;
2479 struct attr
*const attr
= args
->attr
;
2480 const bgp_size_t length
= args
->length
;
2483 struct ecommunity
*ecomm
;
2486 bgp_attr_set_ecommunity(attr
, NULL
);
2487 /* Empty extcomm doesn't seem to be invalid per se */
2488 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2492 ecomm
= ecommunity_parse(
2493 stream_pnt(peer
->curr
), length
,
2494 CHECK_FLAG(peer
->flags
,
2495 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2496 bgp_attr_set_ecommunity(attr
, ecomm
);
2497 /* XXX: fix ecommunity_parse to use stream API */
2498 stream_forward_getp(peer
->curr
, length
);
2500 /* The Extended Community attribute SHALL be considered malformed if
2501 * its length is not a non-zero multiple of 8.
2503 if (!bgp_attr_get_ecommunity(attr
))
2504 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2507 /* Extract DF election preference and mobility sequence number */
2508 attr
->df_pref
= bgp_attr_df_pref_from_ec(attr
, &attr
->df_alg
);
2510 /* Extract MAC mobility sequence number, if any. */
2511 attr
->mm_seqnum
= bgp_attr_mac_mobility_seqnum(attr
, &sticky
);
2512 attr
->sticky
= sticky
;
2514 /* Check if this is a Gateway MAC-IP advertisement */
2515 attr
->default_gw
= bgp_attr_default_gw(attr
);
2517 /* Handle scenario where router flag ecommunity is not
2518 * set but default gw ext community is present.
2519 * Use default gateway, set and propogate R-bit.
2521 if (attr
->default_gw
)
2522 attr
->router_flag
= 1;
2524 /* Check EVPN Neighbor advertisement flags, R-bit */
2525 bgp_attr_evpn_na_flag(attr
, &attr
->router_flag
, &proxy
);
2527 attr
->es_flags
|= ATTR_ES_PROXY_ADVERT
;
2529 /* Extract the Rmac, if any */
2530 if (bgp_attr_rmac(attr
, &attr
->rmac
)) {
2531 if (bgp_debug_update(peer
, NULL
, NULL
, 1)
2532 && bgp_mac_exist(&attr
->rmac
))
2533 zlog_debug("%s: router mac %pEA is self mac", __func__
,
2537 /* Get the tunnel type from encap extended community */
2538 bgp_attr_extcom_tunnel_type(attr
,
2539 (bgp_encap_types
*)&attr
->encap_tunneltype
);
2541 /* Extract link bandwidth, if any. */
2542 (void)ecommunity_linkbw_present(bgp_attr_get_ecommunity(attr
),
2545 return BGP_ATTR_PARSE_PROCEED
;
2548 /* IPv6 Extended Community attribute. */
2549 static enum bgp_attr_parse_ret
2550 bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args
*args
)
2552 struct peer
*const peer
= args
->peer
;
2553 struct attr
*const attr
= args
->attr
;
2554 const bgp_size_t length
= args
->length
;
2555 struct ecommunity
*ipv6_ecomm
= NULL
;
2558 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2559 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2563 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2564 goto ipv6_ext_community_ignore
;
2566 ipv6_ecomm
= ecommunity_parse_ipv6(
2567 stream_pnt(peer
->curr
), length
,
2568 CHECK_FLAG(peer
->flags
,
2569 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2570 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2572 /* XXX: fix ecommunity_parse to use stream API */
2573 stream_forward_getp(peer
->curr
, length
);
2576 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2579 return BGP_ATTR_PARSE_PROCEED
;
2581 ipv6_ext_community_ignore
:
2582 stream_forward_getp(peer
->curr
, length
);
2584 return bgp_attr_ignore(peer
, args
->type
);
2587 /* Parse Tunnel Encap attribute in an UPDATE */
2588 static int bgp_attr_encap(uint8_t type
, struct peer
*peer
, /* IN */
2589 bgp_size_t length
, /* IN: attr's length field */
2590 struct attr
*attr
, /* IN: caller already allocated */
2591 uint8_t flag
, /* IN: attr's flags field */
2595 uint16_t tunneltype
= 0;
2597 total
= length
+ (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
2599 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
)
2600 || !CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
2602 "Tunnel Encap attribute flag isn't optional and transitive %d",
2604 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2605 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
2610 if (BGP_ATTR_ENCAP
== type
) {
2611 /* read outer TLV type and length */
2612 uint16_t tlv_length
;
2616 "Tunnel Encap attribute not long enough to contain outer T,L");
2617 bgp_notify_send_with_data(
2618 peer
, BGP_NOTIFY_UPDATE_ERR
,
2619 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2622 tunneltype
= stream_getw(BGP_INPUT(peer
));
2623 tlv_length
= stream_getw(BGP_INPUT(peer
));
2626 if (tlv_length
!= length
) {
2627 zlog_info("%s: tlv_length(%d) != length(%d)",
2628 __func__
, tlv_length
, length
);
2632 while (length
>= 4) {
2633 uint16_t subtype
= 0;
2634 uint16_t sublength
= 0;
2635 struct bgp_attr_encap_subtlv
*tlv
;
2637 if (BGP_ATTR_ENCAP
== type
) {
2638 subtype
= stream_getc(BGP_INPUT(peer
));
2639 sublength
= stream_getc(BGP_INPUT(peer
));
2641 #ifdef ENABLE_BGP_VNC
2643 subtype
= stream_getw(BGP_INPUT(peer
));
2644 sublength
= stream_getw(BGP_INPUT(peer
));
2649 if (sublength
> length
) {
2651 "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2653 bgp_notify_send_with_data(
2654 peer
, BGP_NOTIFY_UPDATE_ERR
,
2655 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2659 /* alloc and copy sub-tlv */
2660 /* TBD make sure these are freed when attributes are released */
2661 tlv
= XCALLOC(MTYPE_ENCAP_TLV
,
2662 sizeof(struct bgp_attr_encap_subtlv
) + sublength
);
2663 tlv
->type
= subtype
;
2664 tlv
->length
= sublength
;
2665 stream_get(tlv
->value
, peer
->curr
, sublength
);
2666 length
-= sublength
;
2668 /* attach tlv to encap chain */
2669 if (BGP_ATTR_ENCAP
== type
) {
2670 struct bgp_attr_encap_subtlv
*stlv_last
;
2671 for (stlv_last
= attr
->encap_subtlvs
;
2672 stlv_last
&& stlv_last
->next
;
2673 stlv_last
= stlv_last
->next
)
2676 stlv_last
->next
= tlv
;
2678 attr
->encap_subtlvs
= tlv
;
2680 #ifdef ENABLE_BGP_VNC
2682 struct bgp_attr_encap_subtlv
*stlv_last
;
2683 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
2684 bgp_attr_get_vnc_subtlvs(attr
);
2686 for (stlv_last
= vnc_subtlvs
;
2687 stlv_last
&& stlv_last
->next
;
2688 stlv_last
= stlv_last
->next
)
2691 stlv_last
->next
= tlv
;
2693 bgp_attr_set_vnc_subtlvs(attr
, tlv
);
2698 if (BGP_ATTR_ENCAP
== type
) {
2699 attr
->encap_tunneltype
= tunneltype
;
2703 /* spurious leftover data */
2705 "Tunnel Encap attribute length is bad: %d leftover octets",
2707 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2708 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2717 /* SRv6 Service Data Sub-Sub-TLV attribute
2718 * draft-ietf-bess-srv6-services-07
2720 static enum bgp_attr_parse_ret
2721 bgp_attr_srv6_service_data(struct bgp_attr_parser_args
*args
)
2723 struct peer
*const peer
= args
->peer
;
2724 struct attr
*const attr
= args
->attr
;
2725 uint8_t type
, loc_block_len
, loc_node_len
, func_len
, arg_len
,
2726 transposition_len
, transposition_offset
;
2728 size_t headersz
= sizeof(type
) + sizeof(length
);
2730 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2733 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2734 headersz
, STREAM_READABLE(peer
->curr
));
2735 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2739 type
= stream_getc(peer
->curr
);
2740 length
= stream_getw(peer
->curr
);
2742 if (STREAM_READABLE(peer
->curr
) < length
) {
2745 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2746 length
, STREAM_READABLE(peer
->curr
));
2747 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2751 if (length
< BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
) {
2754 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %hu remaining in UPDATE)",
2755 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
,
2757 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2761 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
) {
2762 if (STREAM_READABLE(peer
->curr
) <
2763 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
) {
2766 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %zu remaining in UPDATE)",
2767 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
,
2768 STREAM_READABLE(peer
->curr
));
2769 return bgp_attr_malformed(
2770 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2774 loc_block_len
= stream_getc(peer
->curr
);
2775 loc_node_len
= stream_getc(peer
->curr
);
2776 func_len
= stream_getc(peer
->curr
);
2777 arg_len
= stream_getc(peer
->curr
);
2778 transposition_len
= stream_getc(peer
->curr
);
2779 transposition_offset
= stream_getc(peer
->curr
);
2781 /* Log SRv6 Service Data Sub-Sub-TLV */
2782 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2784 "%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",
2785 __func__
, loc_block_len
, loc_node_len
, func_len
,
2786 arg_len
, transposition_len
,
2787 transposition_offset
);
2790 attr
->srv6_l3vpn
->loc_block_len
= loc_block_len
;
2791 attr
->srv6_l3vpn
->loc_node_len
= loc_node_len
;
2792 attr
->srv6_l3vpn
->func_len
= func_len
;
2793 attr
->srv6_l3vpn
->arg_len
= arg_len
;
2794 attr
->srv6_l3vpn
->transposition_len
= transposition_len
;
2795 attr
->srv6_l3vpn
->transposition_offset
= transposition_offset
;
2799 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2801 "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
2804 stream_forward_getp(peer
->curr
, length
);
2807 return BGP_ATTR_PARSE_PROCEED
;
2810 /* SRv6 Service Sub-TLV attribute
2811 * draft-ietf-bess-srv6-services-07
2813 static enum bgp_attr_parse_ret
2814 bgp_attr_srv6_service(struct bgp_attr_parser_args
*args
)
2816 struct peer
*const peer
= args
->peer
;
2817 struct attr
*const attr
= args
->attr
;
2818 struct in6_addr ipv6_sid
;
2819 uint8_t type
, sid_flags
;
2820 uint16_t length
, endpoint_behavior
;
2821 size_t headersz
= sizeof(type
) + sizeof(length
);
2822 enum bgp_attr_parse_ret err
;
2824 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2827 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2828 headersz
, STREAM_READABLE(peer
->curr
));
2829 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2833 type
= stream_getc(peer
->curr
);
2834 length
= stream_getw(peer
->curr
);
2836 if (STREAM_READABLE(peer
->curr
) < length
) {
2839 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2840 length
, STREAM_READABLE(peer
->curr
));
2841 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2845 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
) {
2846 if (STREAM_READABLE(peer
->curr
) <
2847 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
) {
2850 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %d for attribute data, have %zu remaining in UPDATE)",
2851 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
,
2852 STREAM_READABLE(peer
->curr
));
2853 return bgp_attr_malformed(
2854 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2857 stream_getc(peer
->curr
);
2858 stream_get(&ipv6_sid
, peer
->curr
, sizeof(ipv6_sid
));
2859 sid_flags
= stream_getc(peer
->curr
);
2860 endpoint_behavior
= stream_getw(peer
->curr
);
2861 stream_getc(peer
->curr
);
2863 /* Log SRv6 Service Sub-TLV */
2864 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
))
2866 "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x",
2867 __func__
, &ipv6_sid
, sid_flags
,
2870 /* Configure from Info */
2871 if (attr
->srv6_l3vpn
) {
2872 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2873 "Prefix SID SRv6 L3VPN field repeated");
2874 return bgp_attr_malformed(
2875 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2877 attr
->srv6_l3vpn
= XCALLOC(MTYPE_BGP_SRV6_L3VPN
,
2878 sizeof(struct bgp_attr_srv6_l3vpn
));
2879 sid_copy(&attr
->srv6_l3vpn
->sid
, &ipv6_sid
);
2880 attr
->srv6_l3vpn
->sid_flags
= sid_flags
;
2881 attr
->srv6_l3vpn
->endpoint_behavior
= endpoint_behavior
;
2882 attr
->srv6_l3vpn
->loc_block_len
= 0;
2883 attr
->srv6_l3vpn
->loc_node_len
= 0;
2884 attr
->srv6_l3vpn
->func_len
= 0;
2885 attr
->srv6_l3vpn
->arg_len
= 0;
2886 attr
->srv6_l3vpn
->transposition_len
= 0;
2887 attr
->srv6_l3vpn
->transposition_offset
= 0;
2889 // Sub-Sub-TLV found
2890 if (length
> BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
) {
2891 err
= bgp_attr_srv6_service_data(args
);
2893 if (err
!= BGP_ATTR_PARSE_PROCEED
)
2897 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
2900 /* Placeholder code for unsupported type */
2902 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2904 "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
2907 stream_forward_getp(peer
->curr
, length
);
2910 return BGP_ATTR_PARSE_PROCEED
;
2914 * Read an individual SID value returning how much data we have read
2915 * Returns 0 if there was an error that needs to be passed up the stack
2917 static enum bgp_attr_parse_ret
2918 bgp_attr_psid_sub(uint8_t type
, uint16_t length
,
2919 struct bgp_attr_parser_args
*args
)
2921 struct peer
*const peer
= args
->peer
;
2922 struct attr
*const attr
= args
->attr
;
2923 uint32_t label_index
;
2924 struct in6_addr ipv6_sid
;
2926 uint32_t srgb_range
;
2928 uint8_t sid_type
, sid_flags
;
2930 if (type
== BGP_PREFIX_SID_LABEL_INDEX
) {
2931 if (STREAM_READABLE(peer
->curr
) < length
2932 || length
!= BGP_PREFIX_SID_LABEL_INDEX_LENGTH
) {
2933 flog_err(EC_BGP_ATTR_LEN
,
2934 "Prefix SID label index length is %hu instead of %u",
2935 length
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
2936 return bgp_attr_malformed(args
,
2937 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2941 /* Ignore flags and reserved */
2942 stream_getc(peer
->curr
);
2943 stream_getw(peer
->curr
);
2945 /* Fetch the label index and see if it is valid. */
2946 label_index
= stream_getl(peer
->curr
);
2947 if (label_index
== BGP_INVALID_LABEL_INDEX
)
2948 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2951 /* Store label index; subsequently, we'll check on
2953 attr
->label_index
= label_index
;
2956 /* Placeholder code for the IPv6 SID type */
2957 else if (type
== BGP_PREFIX_SID_IPV6
) {
2958 if (STREAM_READABLE(peer
->curr
) < length
2959 || length
!= BGP_PREFIX_SID_IPV6_LENGTH
) {
2960 flog_err(EC_BGP_ATTR_LEN
,
2961 "Prefix SID IPv6 length is %hu instead of %u",
2962 length
, BGP_PREFIX_SID_IPV6_LENGTH
);
2963 return bgp_attr_malformed(args
,
2964 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2968 /* Ignore reserved */
2969 stream_getc(peer
->curr
);
2970 stream_getw(peer
->curr
);
2972 stream_get(&ipv6_sid
, peer
->curr
, 16);
2975 /* Placeholder code for the Originator SRGB type */
2976 else if (type
== BGP_PREFIX_SID_ORIGINATOR_SRGB
) {
2978 * ietf-idr-bgp-prefix-sid-05:
2979 * Length is the total length of the value portion of the
2980 * TLV: 2 + multiple of 6.
2982 * peer->curr stream readp should be at the beginning of the 16
2983 * bit flag field at this point in the code.
2987 * Check that the TLV length field is sane: at least 2 bytes of
2988 * flag, and at least 1 SRGB (these are 6 bytes each)
2990 if (length
< (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
)) {
2993 "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
2995 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
2996 return bgp_attr_malformed(
2997 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3002 * Check that we actually have at least as much data as
3003 * specified by the length field
3005 if (STREAM_READABLE(peer
->curr
) < length
) {
3006 flog_err(EC_BGP_ATTR_LEN
,
3007 "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain",
3008 length
, STREAM_READABLE(peer
->curr
));
3009 return bgp_attr_malformed(
3010 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3015 * Check that the portion of the TLV containing the sequence of
3016 * SRGBs corresponds to a multiple of the SRGB size; to get
3017 * that length, we skip the 16 bit flags field
3019 stream_getw(peer
->curr
);
3021 if (length
% BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
) {
3024 "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
3025 length
, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
3026 return bgp_attr_malformed(
3027 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3031 srgb_count
= length
/ BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
;
3033 for (int i
= 0; i
< srgb_count
; i
++) {
3034 stream_get(&srgb_base
, peer
->curr
, 3);
3035 stream_get(&srgb_range
, peer
->curr
, 3);
3039 /* Placeholder code for the VPN-SID Service type */
3040 else if (type
== BGP_PREFIX_SID_VPN_SID
) {
3041 if (STREAM_READABLE(peer
->curr
) < length
3042 || length
!= BGP_PREFIX_SID_VPN_SID_LENGTH
) {
3043 flog_err(EC_BGP_ATTR_LEN
,
3044 "Prefix SID VPN SID length is %hu instead of %u",
3045 length
, BGP_PREFIX_SID_VPN_SID_LENGTH
);
3046 return bgp_attr_malformed(args
,
3047 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3051 /* Parse VPN-SID Sub-TLV */
3052 stream_getc(peer
->curr
); /* reserved */
3053 sid_type
= stream_getc(peer
->curr
); /* sid_type */
3054 sid_flags
= stream_getc(peer
->curr
); /* sid_flags */
3055 stream_get(&ipv6_sid
, peer
->curr
,
3056 sizeof(ipv6_sid
)); /* sid_value */
3058 /* Log VPN-SID Sub-TLV */
3059 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
))
3061 "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x",
3062 __func__
, &ipv6_sid
, sid_type
, sid_flags
);
3064 /* Configure from Info */
3065 if (attr
->srv6_vpn
) {
3066 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
3067 "Prefix SID SRv6 VPN field repeated");
3068 return bgp_attr_malformed(
3069 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
3071 attr
->srv6_vpn
= XCALLOC(MTYPE_BGP_SRV6_VPN
,
3072 sizeof(struct bgp_attr_srv6_vpn
));
3073 attr
->srv6_vpn
->sid_flags
= sid_flags
;
3074 sid_copy(&attr
->srv6_vpn
->sid
, &ipv6_sid
);
3075 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
3078 /* Placeholder code for the SRv6 L3 Service type */
3079 else if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE
) {
3080 if (STREAM_READABLE(peer
->curr
) < length
) {
3083 "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain",
3084 length
, STREAM_READABLE(peer
->curr
));
3085 return bgp_attr_malformed(args
,
3086 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3090 /* ignore reserved */
3091 stream_getc(peer
->curr
);
3093 return bgp_attr_srv6_service(args
);
3096 /* Placeholder code for Unsupported TLV */
3099 if (STREAM_READABLE(peer
->curr
) < length
) {
3102 "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE",
3103 length
, STREAM_READABLE(peer
->curr
));
3104 return bgp_attr_malformed(
3105 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3109 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3111 "%s attr Prefix-SID sub-type=%u is not supported, skipped",
3114 stream_forward_getp(peer
->curr
, length
);
3117 return BGP_ATTR_PARSE_PROCEED
;
3120 /* Prefix SID attribute
3121 * draft-ietf-idr-bgp-prefix-sid-05
3123 enum bgp_attr_parse_ret
bgp_attr_prefix_sid(struct bgp_attr_parser_args
*args
)
3125 struct peer
*const peer
= args
->peer
;
3126 struct attr
*const attr
= args
->attr
;
3127 enum bgp_attr_parse_ret ret
;
3129 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
);
3133 size_t headersz
= sizeof(type
) + sizeof(length
);
3134 size_t psid_parsed_length
= 0;
3136 while (STREAM_READABLE(peer
->curr
) > 0
3137 && psid_parsed_length
< args
->length
) {
3139 if (STREAM_READABLE(peer
->curr
) < headersz
) {
3142 "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
3143 headersz
, STREAM_READABLE(peer
->curr
));
3144 return bgp_attr_malformed(
3145 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3149 type
= stream_getc(peer
->curr
);
3150 length
= stream_getw(peer
->curr
);
3152 if (STREAM_READABLE(peer
->curr
) < length
) {
3155 "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
3156 length
, STREAM_READABLE(peer
->curr
));
3157 return bgp_attr_malformed(args
,
3158 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3162 ret
= bgp_attr_psid_sub(type
, length
, args
);
3164 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3167 psid_parsed_length
+= length
+ headersz
;
3169 if (psid_parsed_length
> args
->length
) {
3172 "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
3173 length
+ headersz
, psid_parsed_length
- (length
+ headersz
));
3174 return bgp_attr_malformed(
3175 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3180 return BGP_ATTR_PARSE_PROCEED
;
3183 /* PMSI tunnel attribute (RFC 6514)
3184 * Basic validation checks done here.
3186 static enum bgp_attr_parse_ret
3187 bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args
*args
)
3189 struct peer
*const peer
= args
->peer
;
3190 struct attr
*const attr
= args
->attr
;
3191 const bgp_size_t length
= args
->length
;
3193 int attr_parse_len
= 2 + BGP_LABEL_BYTES
;
3195 /* Verify that the receiver is expecting "ingress replication" as we
3196 * can only support that.
3198 if (length
< attr_parse_len
) {
3199 flog_err(EC_BGP_ATTR_LEN
, "Bad PMSI tunnel attribute length %d",
3201 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3204 stream_getc(peer
->curr
); /* Flags */
3205 tnl_type
= stream_getc(peer
->curr
);
3206 if (tnl_type
> PMSI_TNLTYPE_MAX
) {
3207 flog_err(EC_BGP_ATTR_PMSI_TYPE
,
3208 "Invalid PMSI tunnel attribute type %d", tnl_type
);
3209 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
3212 if (tnl_type
== PMSI_TNLTYPE_INGR_REPL
) {
3214 flog_err(EC_BGP_ATTR_PMSI_LEN
,
3215 "Bad PMSI tunnel attribute length %d for IR",
3217 return bgp_attr_malformed(
3218 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3223 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
);
3224 bgp_attr_set_pmsi_tnl_type(attr
, tnl_type
);
3225 stream_get(&attr
->label
, peer
->curr
, BGP_LABEL_BYTES
);
3227 /* Forward read pointer of input stream. */
3228 stream_forward_getp(peer
->curr
, length
- attr_parse_len
);
3230 return BGP_ATTR_PARSE_PROCEED
;
3233 /* AIGP attribute (rfc7311) */
3234 static enum bgp_attr_parse_ret
bgp_attr_aigp(struct bgp_attr_parser_args
*args
)
3236 struct peer
*const peer
= args
->peer
;
3237 struct attr
*const attr
= args
->attr
;
3238 const bgp_size_t length
= args
->length
;
3239 uint8_t *s
= stream_pnt(peer
->curr
);
3242 /* If an AIGP attribute is received on a BGP session for which
3243 * AIGP_SESSION is disabled, the attribute MUST be treated exactly
3244 * as if it were an unrecognized non-transitive attribute.
3245 * That is, it "MUST be quietly ignored and not passed along to
3247 * For Internal BGP (IBGP) sessions, and for External BGP (EBGP)
3248 * sessions between members of the same BGP Confederation,
3249 * the default value of AIGP_SESSION SHOULD be "enabled".
3251 if (peer
->sort
== BGP_PEER_EBGP
&&
3252 !CHECK_FLAG(peer
->flags
, PEER_FLAG_AIGP
)) {
3254 "%pBP received AIGP attribute, but eBGP peer do not support it",
3259 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
3262 if (!bgp_attr_aigp_valid(s
, length
))
3265 /* Extract AIGP Metric TLV */
3266 if (bgp_attr_aigp_get_tlv_metric(s
, length
, &aigp
))
3267 bgp_attr_set_aigp_metric(attr
, aigp
);
3270 stream_forward_getp(peer
->curr
, length
);
3272 return bgp_attr_ignore(peer
, args
->type
);
3275 /* OTC attribute. */
3276 static enum bgp_attr_parse_ret
bgp_attr_otc(struct bgp_attr_parser_args
*args
)
3278 struct peer
*const peer
= args
->peer
;
3279 struct attr
*const attr
= args
->attr
;
3280 const bgp_size_t length
= args
->length
;
3284 flog_err(EC_BGP_ATTR_LEN
, "OTC attribute length isn't 4 [%u]",
3286 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3290 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
3293 attr
->otc
= stream_getl(peer
->curr
);
3295 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "OTC attribute value is 0");
3296 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
3300 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_OTC
);
3302 return BGP_ATTR_PARSE_PROCEED
;
3305 stream_forward_getp(peer
->curr
, length
);
3307 return bgp_attr_ignore(peer
, args
->type
);
3310 /* BGP unknown attribute treatment. */
3311 static enum bgp_attr_parse_ret
3312 bgp_attr_unknown(struct bgp_attr_parser_args
*args
)
3314 bgp_size_t total
= args
->total
;
3315 struct transit
*transit
;
3316 struct peer
*const peer
= args
->peer
;
3317 struct attr
*const attr
= args
->attr
;
3318 uint8_t *const startp
= args
->startp
;
3319 const uint8_t type
= args
->type
;
3320 const uint8_t flag
= args
->flags
;
3321 const bgp_size_t length
= args
->length
;
3323 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3325 "%s Unknown attribute is received (type %d, length %d)",
3326 peer
->host
, type
, length
);
3328 /* Forward read pointer of input stream. */
3329 stream_forward_getp(peer
->curr
, length
);
3331 if (peer
->discard_attrs
[type
] || peer
->withdraw_attrs
[type
])
3332 return bgp_attr_ignore(peer
, type
);
3334 /* If any of the mandatory well-known attributes are not recognized,
3335 then the Error Subcode is set to Unrecognized Well-known
3336 Attribute. The Data field contains the unrecognized attribute
3337 (type, length and value). */
3338 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
3339 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_UNREC_ATTR
,
3343 /* Unrecognized non-transitive optional attributes must be quietly
3344 ignored and not passed along to other BGP peers. */
3345 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
))
3346 return BGP_ATTR_PARSE_PROCEED
;
3348 /* If a path with recognized transitive optional attribute is
3349 accepted and passed along to other BGP peers and the Partial bit
3350 in the Attribute Flags octet is set to 1 by some previous AS, it
3351 is not set back to 0 by the current AS. */
3352 SET_FLAG(*startp
, BGP_ATTR_FLAG_PARTIAL
);
3354 /* Store transitive attribute to the end of attr->transit. */
3355 transit
= bgp_attr_get_transit(attr
);
3357 transit
= XCALLOC(MTYPE_TRANSIT
, sizeof(struct transit
));
3359 transit
->val
= XREALLOC(MTYPE_TRANSIT_VAL
, transit
->val
,
3360 transit
->length
+ total
);
3362 memcpy(transit
->val
+ transit
->length
, startp
, total
);
3363 transit
->length
+= total
;
3364 bgp_attr_set_transit(attr
, transit
);
3366 return BGP_ATTR_PARSE_PROCEED
;
3369 /* Well-known attribute check. */
3370 static int bgp_attr_check(struct peer
*peer
, struct attr
*attr
)
3374 /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
3376 if (CHECK_FLAG(peer
->cap
, PEER_CAP_RESTART_RCV
) && !attr
->flag
)
3377 return BGP_ATTR_PARSE_PROCEED
;
3379 /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
3380 to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
3381 are present, it should. Check for any other attribute being present
3384 if ((!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)) &&
3385 CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
))))
3386 return BGP_ATTR_PARSE_PROCEED
;
3388 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
)))
3389 type
= BGP_ATTR_ORIGIN
;
3391 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
3392 type
= BGP_ATTR_AS_PATH
;
3394 /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
3396 * NLRI is empty. We can't easily check NLRI empty here though.
3398 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3399 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)))
3400 type
= BGP_ATTR_NEXT_HOP
;
3402 if (peer
->sort
== BGP_PEER_IBGP
3403 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)))
3404 type
= BGP_ATTR_LOCAL_PREF
;
3406 /* If any of the well-known mandatory attributes are not present
3407 * in an UPDATE message, then "treat-as-withdraw" MUST be used.
3410 flog_warn(EC_BGP_MISSING_ATTRIBUTE
,
3411 "%s Missing well-known attribute %s.", peer
->host
,
3412 lookup_msg(attr_str
, type
, NULL
));
3413 return BGP_ATTR_PARSE_WITHDRAW
;
3415 return BGP_ATTR_PARSE_PROCEED
;
3418 /* Read attribute of update packet. This function is called from
3419 bgp_update_receive() in bgp_packet.c. */
3420 enum bgp_attr_parse_ret
bgp_attr_parse(struct peer
*peer
, struct attr
*attr
,
3422 struct bgp_nlri
*mp_update
,
3423 struct bgp_nlri
*mp_withdraw
)
3425 enum bgp_attr_parse_ret ret
;
3429 uint8_t *startp
, *endp
;
3431 uint8_t seen
[BGP_ATTR_BITMAP_SIZE
];
3432 /* we need the as4_path only until we have synthesized the as_path with
3434 /* same goes for as4_aggregator */
3435 struct aspath
*as4_path
= NULL
;
3436 as_t as4_aggregator
= 0;
3437 struct in_addr as4_aggregator_addr
= {.s_addr
= 0};
3438 struct transit
*transit
;
3440 /* Initialize bitmap. */
3441 memset(seen
, 0, BGP_ATTR_BITMAP_SIZE
);
3443 /* End pointer of BGP attribute. */
3444 endp
= BGP_INPUT_PNT(peer
) + size
;
3446 /* Get attributes to the end of attribute length. */
3447 while (BGP_INPUT_PNT(peer
) < endp
) {
3448 /* Check remaining length check.*/
3449 if (endp
- BGP_INPUT_PNT(peer
) < BGP_ATTR_MIN_LEN
) {
3450 /* XXX warning: long int format, int arg (arg 5) */
3452 EC_BGP_ATTRIBUTE_TOO_SMALL
,
3453 "%s: error BGP attribute length %lu is smaller than min len",
3455 (unsigned long)(endp
3456 - stream_pnt(BGP_INPUT(peer
))));
3458 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3459 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3460 ret
= BGP_ATTR_PARSE_ERROR
;
3464 /* Fetch attribute flag and type. */
3465 startp
= BGP_INPUT_PNT(peer
);
3466 /* "The lower-order four bits of the Attribute Flags octet are
3467 unused. They MUST be zero when sent and MUST be ignored when
3469 flag
= 0xF0 & stream_getc(BGP_INPUT(peer
));
3470 type
= stream_getc(BGP_INPUT(peer
));
3472 /* Check whether Extended-Length applies and is in bounds */
3473 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
)
3474 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1))) {
3476 EC_BGP_EXT_ATTRIBUTE_TOO_SMALL
,
3477 "%s: Extended length set, but just %lu bytes of attr header",
3479 (unsigned long)(endp
3480 - stream_pnt(BGP_INPUT(peer
))));
3482 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3483 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3484 ret
= BGP_ATTR_PARSE_ERROR
;
3488 /* Check extended attribue length bit. */
3489 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
))
3490 length
= stream_getw(BGP_INPUT(peer
));
3492 length
= stream_getc(BGP_INPUT(peer
));
3494 /* If any attribute appears more than once in the UPDATE
3495 message, then the Error Subcode is set to Malformed Attribute
3498 if (CHECK_BITMAP(seen
, type
)) {
3500 EC_BGP_ATTRIBUTE_REPEATED
,
3501 "%s: error BGP attribute type %d appears twice in a message",
3504 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3505 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3506 ret
= BGP_ATTR_PARSE_ERROR
;
3510 /* Set type to bitmap to check duplicate attribute. `type' is
3511 unsigned char so it never overflow bitmap range. */
3513 SET_BITMAP(seen
, type
);
3515 /* Overflow check. */
3516 attr_endp
= BGP_INPUT_PNT(peer
) + length
;
3518 if (attr_endp
> endp
) {
3520 EC_BGP_ATTRIBUTE_TOO_LARGE
,
3521 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
3522 peer
->host
, type
, length
, size
, attr_endp
,
3526 * If any recognized attribute has an Attribute
3527 * Length that conflicts with the expected length
3528 * (based on the attribute type code), then the
3529 * Error Subcode MUST be set to Attribute Length
3530 * Error. The Data field MUST contain the erroneous
3531 * attribute (type, length, and value).
3533 * We do not currently have a good way to determine the
3534 * length of the attribute independent of the length
3535 * received in the message. Instead we send the
3536 * minimum between the amount of data we have and the
3537 * amount specified by the attribute length field.
3539 * Instead of directly passing in the packet buffer and
3540 * offset we use the stream_get* functions to read into
3541 * a stack buffer, since they perform bounds checking
3542 * and we are working with untrusted data.
3544 unsigned char ndata
[peer
->max_packet_size
];
3545 memset(ndata
, 0x00, sizeof(ndata
));
3547 CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 2 : 1;
3548 /* Rewind to end of flag field */
3549 stream_rewind_getp(BGP_INPUT(peer
), (1 + lfl
));
3551 stream_get(&ndata
[0], BGP_INPUT(peer
), 1);
3553 stream_get(&ndata
[1], BGP_INPUT(peer
), lfl
);
3555 size_t atl
= attr_endp
- startp
;
3556 size_t ndl
= MIN(atl
, STREAM_READABLE(BGP_INPUT(peer
)));
3557 stream_get(&ndata
[lfl
+ 1], BGP_INPUT(peer
), ndl
);
3559 bgp_notify_send_with_data(
3560 peer
, BGP_NOTIFY_UPDATE_ERR
,
3561 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
, ndata
,
3564 ret
= BGP_ATTR_PARSE_ERROR
;
3568 struct bgp_attr_parser_args attr_args
= {
3575 .total
= attr_endp
- startp
,
3579 /* If any recognized attribute has Attribute Flags that conflict
3580 with the Attribute Type Code, then the Error Subcode is set
3582 Attribute Flags Error. The Data field contains the erroneous
3583 attribute (type, length and value). */
3584 if (bgp_attr_flag_invalid(&attr_args
)) {
3585 ret
= bgp_attr_malformed(
3586 &attr_args
, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
3588 if (ret
== BGP_ATTR_PARSE_PROCEED
)
3593 /* OK check attribute and store it's value. */
3595 case BGP_ATTR_ORIGIN
:
3596 ret
= bgp_attr_origin(&attr_args
);
3598 case BGP_ATTR_AS_PATH
:
3599 ret
= bgp_attr_aspath(&attr_args
);
3601 case BGP_ATTR_AS4_PATH
:
3602 ret
= bgp_attr_as4_path(&attr_args
, &as4_path
);
3604 case BGP_ATTR_NEXT_HOP
:
3605 ret
= bgp_attr_nexthop(&attr_args
);
3607 case BGP_ATTR_MULTI_EXIT_DISC
:
3608 ret
= bgp_attr_med(&attr_args
);
3610 case BGP_ATTR_LOCAL_PREF
:
3611 ret
= bgp_attr_local_pref(&attr_args
);
3613 case BGP_ATTR_ATOMIC_AGGREGATE
:
3614 ret
= bgp_attr_atomic(&attr_args
);
3616 case BGP_ATTR_AGGREGATOR
:
3617 ret
= bgp_attr_aggregator(&attr_args
);
3619 case BGP_ATTR_AS4_AGGREGATOR
:
3620 ret
= bgp_attr_as4_aggregator(&attr_args
,
3622 &as4_aggregator_addr
);
3624 case BGP_ATTR_COMMUNITIES
:
3625 ret
= bgp_attr_community(&attr_args
);
3627 case BGP_ATTR_LARGE_COMMUNITIES
:
3628 ret
= bgp_attr_large_community(&attr_args
);
3630 case BGP_ATTR_ORIGINATOR_ID
:
3631 ret
= bgp_attr_originator_id(&attr_args
);
3633 case BGP_ATTR_CLUSTER_LIST
:
3634 ret
= bgp_attr_cluster_list(&attr_args
);
3636 case BGP_ATTR_MP_REACH_NLRI
:
3637 ret
= bgp_mp_reach_parse(&attr_args
, mp_update
);
3639 case BGP_ATTR_MP_UNREACH_NLRI
:
3640 ret
= bgp_mp_unreach_parse(&attr_args
, mp_withdraw
);
3642 case BGP_ATTR_EXT_COMMUNITIES
:
3643 ret
= bgp_attr_ext_communities(&attr_args
);
3645 #ifdef ENABLE_BGP_VNC_ATTR
3648 case BGP_ATTR_ENCAP
:
3649 ret
= bgp_attr_encap(type
, peer
, length
, attr
, flag
,
3652 case BGP_ATTR_PREFIX_SID
:
3653 ret
= bgp_attr_prefix_sid(&attr_args
);
3655 case BGP_ATTR_PMSI_TUNNEL
:
3656 ret
= bgp_attr_pmsi_tunnel(&attr_args
);
3658 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
3659 ret
= bgp_attr_ipv6_ext_communities(&attr_args
);
3662 ret
= bgp_attr_otc(&attr_args
);
3665 ret
= bgp_attr_aigp(&attr_args
);
3668 ret
= bgp_attr_unknown(&attr_args
);
3672 if (ret
== BGP_ATTR_PARSE_ERROR_NOTIFYPLS
) {
3673 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3674 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3675 ret
= BGP_ATTR_PARSE_ERROR
;
3679 if (ret
== BGP_ATTR_PARSE_EOR
) {
3683 if (ret
== BGP_ATTR_PARSE_ERROR
) {
3684 flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR
,
3685 "%s: Attribute %s, parse error", peer
->host
,
3686 lookup_msg(attr_str
, type
, NULL
));
3689 if (ret
== BGP_ATTR_PARSE_WITHDRAW
) {
3691 EC_BGP_ATTRIBUTE_PARSE_WITHDRAW
,
3692 "%s: Attribute %s, parse error - treating as withdrawal",
3693 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3697 /* Check the fetched length. */
3698 if (BGP_INPUT_PNT(peer
) != attr_endp
) {
3699 flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR
,
3700 "%s: BGP attribute %s, fetch error",
3701 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3702 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3703 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3704 ret
= BGP_ATTR_PARSE_ERROR
;
3710 * draft-ietf-idr-bgp-prefix-sid-27#section-3:
3711 * About Prefix-SID path attribute,
3712 * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
3713 * may only appear in a BGP Prefix-SID attribute attached to
3714 * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
3715 * It MUST be ignored when received for other BGP AFI/SAFI combinations.
3717 if (!attr
->mp_nexthop_len
|| mp_update
->safi
!= SAFI_LABELED_UNICAST
)
3718 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
3720 /* Check final read pointer is same as end pointer. */
3721 if (BGP_INPUT_PNT(peer
) != endp
) {
3722 flog_warn(EC_BGP_ATTRIBUTES_MISMATCH
,
3723 "%s: BGP attribute %s, length mismatch", peer
->host
,
3724 lookup_msg(attr_str
, type
, NULL
));
3725 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3726 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3728 ret
= BGP_ATTR_PARSE_ERROR
;
3733 * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
3734 * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
3735 * This is implemented below and will result in a NOTIFICATION. If the
3736 * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
3737 * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
3738 * message SHOULD NOT be sent. This is implemented elsewhere.
3740 * RFC4760: An UPDATE message that carries no NLRI, other than the one
3741 * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
3742 * attribute. If such a message contains the NEXT_HOP attribute, the BGP
3743 * speaker that receives the message SHOULD ignore this attribute.
3745 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3746 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
))) {
3747 if (bgp_attr_nexthop_valid(peer
, attr
) < 0) {
3748 ret
= BGP_ATTR_PARSE_ERROR
;
3753 /* Check all mandatory well-known attributes are present */
3754 ret
= bgp_attr_check(peer
, attr
);
3759 * At this place we can see whether we got AS4_PATH and/or
3760 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
3761 * We can not do this before we've read all attributes because
3762 * the as4 handling does not say whether AS4_PATH has to be sent
3763 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
3764 * in relationship to AGGREGATOR.
3765 * So, to be defensive, we are not relying on any order and read
3766 * all attributes first, including these 32bit ones, and now,
3767 * afterwards, we look what and if something is to be done for as4.
3769 * It is possible to not have AS_PATH, e.g. GR EoR and sole
3772 /* actually... this doesn't ever return failure currently, but
3773 * better safe than sorry */
3774 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))
3775 && bgp_attr_munge_as4_attrs(peer
, attr
, as4_path
, as4_aggregator
,
3776 &as4_aggregator_addr
)) {
3777 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3778 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3779 ret
= BGP_ATTR_PARSE_ERROR
;
3784 * Finally do the checks on the aspath we did not do yet
3785 * because we waited for a potentially synthesized aspath.
3787 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))) {
3788 ret
= bgp_attr_aspath_check(peer
, attr
);
3789 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3793 ret
= BGP_ATTR_PARSE_PROCEED
;
3797 * At this stage, we have done all fiddling with as4, and the
3798 * resulting info is in attr->aggregator resp. attr->aspath so
3799 * we can chuck as4_aggregator and as4_path alltogether in order
3803 * unintern - it is in the hash
3804 * The flag that we got this is still there, but that
3805 * does not do any trouble
3807 aspath_unintern(&as4_path
);
3809 transit
= bgp_attr_get_transit(attr
);
3810 if (ret
!= BGP_ATTR_PARSE_ERROR
) {
3811 /* Finally intern unknown attribute. */
3813 bgp_attr_set_transit(attr
, transit_intern(transit
));
3814 if (attr
->encap_subtlvs
)
3815 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
3817 #ifdef ENABLE_BGP_VNC
3818 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3819 bgp_attr_get_vnc_subtlvs(attr
);
3822 bgp_attr_set_vnc_subtlvs(
3824 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
3828 transit_free(transit
);
3829 bgp_attr_set_transit(attr
, NULL
);
3832 bgp_attr_flush_encap(attr
);
3836 transit
= bgp_attr_get_transit(attr
);
3838 assert(transit
->refcnt
> 0);
3839 if (attr
->encap_subtlvs
)
3840 assert(attr
->encap_subtlvs
->refcnt
> 0);
3841 #ifdef ENABLE_BGP_VNC
3842 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3843 bgp_attr_get_vnc_subtlvs(attr
);
3846 assert(vnc_subtlvs
->refcnt
> 0);
3853 * Extract the tunnel type from extended community
3855 void bgp_attr_extcom_tunnel_type(struct attr
*attr
,
3856 bgp_encap_types
*tunnel_type
)
3858 struct ecommunity
*ecom
;
3864 ecom
= bgp_attr_get_ecommunity(attr
);
3865 if (!ecom
|| !ecom
->size
)
3868 for (i
= 0; i
< ecom
->size
; i
++) {
3870 uint8_t type
, sub_type
;
3872 pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
3875 if (!(type
== ECOMMUNITY_ENCODE_OPAQUE
&&
3876 sub_type
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
))
3878 *tunnel_type
= ((pnt
[6] << 8) | pnt
[7]);
3885 size_t bgp_packet_mpattr_start(struct stream
*s
, struct peer
*peer
, afi_t afi
,
3886 safi_t safi
, struct bpacket_attr_vec_arr
*vecarr
,
3890 iana_afi_t pkt_afi
= IANA_AFI_IPV4
;
3891 iana_safi_t pkt_safi
= IANA_SAFI_UNICAST
;
3894 /* Set extended bit always to encode the attribute length as 2 bytes */
3895 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
3896 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
3897 sizep
= stream_get_endp(s
);
3898 stream_putw(s
, 0); /* Marker: Attribute length. */
3901 /* Convert AFI, SAFI to values for packet. */
3902 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
3904 stream_putw(s
, pkt_afi
); /* AFI */
3905 stream_putc(s
, pkt_safi
); /* SAFI */
3909 && (safi
== SAFI_UNICAST
|| safi
== SAFI_LABELED_UNICAST
3910 || safi
== SAFI_MPLS_VPN
|| safi
== SAFI_MULTICAST
))
3911 nh_afi
= peer_cap_enhe(peer
, afi
, safi
) ? AFI_IP6
: AFI_IP
;
3912 else if (safi
== SAFI_FLOWSPEC
)
3915 nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
3918 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
3923 case SAFI_MULTICAST
:
3924 case SAFI_LABELED_UNICAST
:
3926 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3930 stream_putl(s
, 0); /* RD = 0, per RFC */
3932 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3937 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3940 if (attr
->mp_nexthop_len
== 0)
3941 stream_putc(s
, 0); /* no nexthop for flowspec */
3943 stream_putc(s
, attr
->mp_nexthop_len
);
3944 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3949 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
3956 case SAFI_MULTICAST
:
3957 case SAFI_LABELED_UNICAST
:
3959 if (attr
->mp_nexthop_len
3960 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3962 BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
);
3963 stream_put(s
, &attr
->mp_nexthop_global
,
3965 stream_put(s
, &attr
->mp_nexthop_local
,
3968 stream_putc(s
, IPV6_MAX_BYTELEN
);
3969 stream_put(s
, &attr
->mp_nexthop_global
,
3973 case SAFI_MPLS_VPN
: {
3974 if (attr
->mp_nexthop_len
==
3975 BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
)
3976 stream_putc(s
, attr
->mp_nexthop_len
);
3978 stream_putc(s
, BGP_ATTR_NHLEN_VPNV6_GLOBAL
);
3979 stream_putl(s
, 0); /* RD = 0, per RFC */
3981 stream_put(s
, &attr
->mp_nexthop_global
,
3983 if (attr
->mp_nexthop_len
==
3984 BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
3985 stream_putl(s
, 0); /* RD = 0, per RFC */
3987 stream_put(s
, &attr
->mp_nexthop_local
,
3992 stream_putc(s
, IPV6_MAX_BYTELEN
);
3993 stream_put(s
, &attr
->mp_nexthop_global
,
3997 stream_putc(s
, 0); /* no nexthop for flowspec */
4001 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
4006 if (safi
!= SAFI_FLOWSPEC
)
4008 EC_BGP_ATTR_NH_SEND_LEN
,
4009 "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
4010 peer
->host
, afi
, safi
, attr
->mp_nexthop_len
);
4014 assert(!"DEV ESCAPE: AFI_UNSPEC or AFI_MAX should not be used here");
4023 void bgp_packet_mpattr_prefix(struct stream
*s
, afi_t afi
, safi_t safi
,
4024 const struct prefix
*p
,
4025 const struct prefix_rd
*prd
, mpls_label_t
*label
,
4026 uint32_t num_labels
, bool addpath_capable
,
4027 uint32_t addpath_tx_id
, struct attr
*attr
)
4032 assert(!"Dev escape usage of SAFI_UNSPEC or MAX");
4035 if (addpath_capable
)
4036 stream_putl(s
, addpath_tx_id
);
4037 /* Label, RD, Prefix write. */
4038 stream_putc(s
, p
->prefixlen
+ 88);
4039 stream_put(s
, label
, BGP_LABEL_BYTES
);
4040 stream_put(s
, prd
->val
, 8);
4041 stream_put(s
, &p
->u
.prefix
, PSIZE(p
->prefixlen
));
4044 if (afi
== AFI_L2VPN
)
4045 /* EVPN prefix - contents depend on type */
4046 bgp_evpn_encode_prefix(s
, p
, prd
, label
, num_labels
,
4047 attr
, addpath_capable
,
4050 assert(!"Add encoding bits here for other AFI's");
4052 case SAFI_LABELED_UNICAST
:
4053 /* Prefix write with label. */
4054 stream_put_labeled_prefix(s
, p
, label
, addpath_capable
,
4058 stream_putc(s
, p
->u
.prefix_flowspec
.prefixlen
);
4059 stream_put(s
, (const void *)p
->u
.prefix_flowspec
.ptr
,
4060 p
->u
.prefix_flowspec
.prefixlen
);
4064 case SAFI_MULTICAST
:
4065 stream_put_prefix_addpath(s
, p
, addpath_capable
, addpath_tx_id
);
4068 assert(!"Please add proper encoding of SAFI_ENCAP");
4073 size_t bgp_packet_mpattr_prefix_size(afi_t afi
, safi_t safi
,
4074 const struct prefix
*p
)
4076 int size
= PSIZE(p
->prefixlen
);
4081 assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE");
4084 case SAFI_MULTICAST
:
4090 /* This has to be wrong, but I don't know what to put here */
4091 assert(!"Do we try to use this?");
4093 case SAFI_LABELED_UNICAST
:
4094 size
+= BGP_LABEL_BYTES
;
4098 * TODO: Maximum possible for type-2, type-3 and type-5
4100 if (afi
== AFI_L2VPN
)
4103 assert(!"Attempting to figure size for SAFI_EVPN and !AFI_L2VPN and FRR will not have the proper values");
4106 size
= ((struct prefix_fs
*)p
)->prefix
.prefixlen
;
4114 * Encodes the tunnel encapsulation attribute,
4115 * and with ENABLE_BGP_VNC the VNC attribute which uses
4116 * almost the same TLV format
4118 static void bgp_packet_mpattr_tea(struct bgp
*bgp
, struct peer
*peer
,
4119 struct stream
*s
, struct attr
*attr
,
4122 unsigned int attrlenfield
= 0;
4123 unsigned int attrhdrlen
= 0;
4124 struct bgp_attr_encap_subtlv
*subtlvs
;
4125 struct bgp_attr_encap_subtlv
*st
;
4126 const char *attrname
;
4128 if (!attr
|| (attrtype
== BGP_ATTR_ENCAP
4129 && (!attr
->encap_tunneltype
4130 || attr
->encap_tunneltype
== BGP_ENCAP_TYPE_MPLS
)))
4134 case BGP_ATTR_ENCAP
:
4135 attrname
= "Tunnel Encap";
4136 subtlvs
= attr
->encap_subtlvs
;
4137 if (subtlvs
== NULL
) /* nothing to do */
4140 * The tunnel encap attr has an "outer" tlv.
4142 * L = total length of subtlvs,
4143 * V = concatenated subtlvs.
4145 attrlenfield
= 2 + 2; /* T + L */
4146 attrhdrlen
= 1 + 1; /* subTLV T + L */
4149 #ifdef ENABLE_BGP_VNC_ATTR
4152 subtlvs
= bgp_attr_get_vnc_subtlvs(attr
);
4153 if (subtlvs
== NULL
) /* nothing to do */
4155 attrlenfield
= 0; /* no outer T + L */
4156 attrhdrlen
= 2 + 2; /* subTLV T + L */
4164 /* compute attr length */
4165 for (st
= subtlvs
; st
; st
= st
->next
) {
4166 attrlenfield
+= (attrhdrlen
+ st
->length
);
4169 if (attrlenfield
> 0xffff) {
4170 zlog_info("%s attribute is too long (length=%d), can't send it",
4171 attrname
, attrlenfield
);
4175 if (attrlenfield
> 0xff) {
4176 /* 2-octet length field */
4178 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4179 | BGP_ATTR_FLAG_EXTLEN
);
4180 stream_putc(s
, attrtype
);
4181 stream_putw(s
, attrlenfield
& 0xffff);
4183 /* 1-octet length field */
4184 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
);
4185 stream_putc(s
, attrtype
);
4186 stream_putc(s
, attrlenfield
& 0xff);
4189 if (attrtype
== BGP_ATTR_ENCAP
) {
4190 /* write outer T+L */
4191 stream_putw(s
, attr
->encap_tunneltype
);
4192 stream_putw(s
, attrlenfield
- 4);
4195 /* write each sub-tlv */
4196 for (st
= subtlvs
; st
; st
= st
->next
) {
4197 if (attrtype
== BGP_ATTR_ENCAP
) {
4198 stream_putc(s
, st
->type
);
4199 stream_putc(s
, st
->length
);
4200 #ifdef ENABLE_BGP_VNC
4202 stream_putw(s
, st
->type
);
4203 stream_putw(s
, st
->length
);
4206 stream_put(s
, st
->value
, st
->length
);
4210 void bgp_packet_mpattr_end(struct stream
*s
, size_t sizep
)
4212 /* Set MP attribute length. Don't count the (2) bytes used to encode
4214 stream_putw_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 2);
4217 static bool bgp_append_local_as(struct peer
*peer
, afi_t afi
, safi_t safi
)
4219 if (!BGP_AS_IS_PRIVATE(peer
->local_as
)
4220 || (BGP_AS_IS_PRIVATE(peer
->local_as
)
4221 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4222 PEER_FLAG_REMOVE_PRIVATE_AS
)
4223 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4224 PEER_FLAG_REMOVE_PRIVATE_AS_ALL
)
4225 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4226 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE
)
4227 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4228 PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE
)))
4233 /* Make attribute packet. */
4234 bgp_size_t
bgp_packet_attribute(struct bgp
*bgp
, struct peer
*peer
,
4235 struct stream
*s
, struct attr
*attr
,
4236 struct bpacket_attr_vec_arr
*vecarr
,
4237 struct prefix
*p
, afi_t afi
, safi_t safi
,
4238 struct peer
*from
, struct prefix_rd
*prd
,
4239 mpls_label_t
*label
, uint32_t num_labels
,
4240 bool addpath_capable
, uint32_t addpath_tx_id
,
4241 struct bgp_path_info
*bpi
)
4244 size_t aspath_sizep
;
4245 struct aspath
*aspath
;
4246 int send_as4_path
= 0;
4247 int send_as4_aggregator
= 0;
4248 bool use32bit
= CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
4249 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
);
4254 /* Remember current pointer. */
4255 cp
= stream_get_endp(s
);
4258 && !((afi
== AFI_IP
&& safi
== SAFI_UNICAST
)
4259 && !peer_cap_enhe(peer
, afi
, safi
))) {
4260 size_t mpattrlen_pos
= 0;
4262 mpattrlen_pos
= bgp_packet_mpattr_start(s
, peer
, afi
, safi
,
4264 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
,
4265 num_labels
, addpath_capable
,
4266 addpath_tx_id
, attr
);
4267 bgp_packet_mpattr_end(s
, mpattrlen_pos
);
4270 /* Origin attribute. */
4271 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4272 stream_putc(s
, BGP_ATTR_ORIGIN
);
4274 stream_putc(s
, attr
->origin
);
4276 /* AS path attribute. */
4278 /* If remote-peer is EBGP */
4279 if (peer
->sort
== BGP_PEER_EBGP
4280 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4281 PEER_FLAG_AS_PATH_UNCHANGED
)
4282 || attr
->aspath
->segments
== NULL
)
4283 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4284 PEER_FLAG_RSERVER_CLIENT
))) {
4285 aspath
= aspath_dup(attr
->aspath
);
4287 /* Even though we may not be configured for confederations we
4289 * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
4290 aspath
= aspath_delete_confed_seq(aspath
);
4292 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
)) {
4293 /* A confed member, so we need to do the
4294 * AS_CONFED_SEQUENCE thing if it's outside a common
4296 * Configured confederation peers MUST be validated
4297 * under BGP_PEER_CONFED, but if we have configured
4298 * remote-as as AS_EXTERNAL, we need to check again
4299 * if the peer belongs to us.
4301 if (bgp_confederation_peers_check(bgp
, peer
->as
)) {
4302 aspath
= aspath_add_confed_seq(aspath
,
4305 /* Stuff our path CONFED_ID on the front */
4306 aspath
= aspath_add_seq(aspath
, bgp
->confed_id
);
4309 if (peer
->change_local_as
) {
4310 /* If replace-as is specified, we only use the
4311 change_local_as when
4312 advertising routes. */
4313 if (!CHECK_FLAG(peer
->flags
,
4314 PEER_FLAG_LOCAL_AS_REPLACE_AS
))
4315 if (bgp_append_local_as(peer
, afi
,
4317 aspath
= aspath_add_seq(
4318 aspath
, peer
->local_as
);
4319 aspath
= aspath_add_seq(aspath
,
4320 peer
->change_local_as
);
4322 aspath
= aspath_add_seq(aspath
, peer
->local_as
);
4325 } else if (peer
->sort
== BGP_PEER_CONFED
) {
4326 /* A confed member, so we need to do the AS_CONFED_SEQUENCE
4328 aspath
= aspath_dup(attr
->aspath
);
4329 aspath
= aspath_add_confed_seq(aspath
, peer
->local_as
);
4331 aspath
= attr
->aspath
;
4333 /* If peer is not AS4 capable, then:
4334 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
4335 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
4337 * types are in it (i.e. exclude them if they are there)
4338 * AND do this only if there is at least one asnum > 65535 in the
4340 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
4342 * all ASnums > 65535 to BGP_AS_TRANS
4345 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4346 stream_putc(s
, BGP_ATTR_AS_PATH
);
4347 aspath_sizep
= stream_get_endp(s
);
4349 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, use32bit
));
4351 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
4354 if (!use32bit
&& aspath_has_as4(aspath
))
4356 1; /* we'll do this later, at the correct place */
4358 /* Nexthop attribute. */
4359 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
4360 && !peer_cap_enhe(peer
, afi
, safi
)) {
4361 afi_t nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
4363 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
)) {
4364 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4365 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4366 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4369 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4370 } else if (peer_cap_enhe(from
, afi
, safi
)
4371 || (nh_afi
== AFI_IP6
)) {
4373 * Likely this is the case when an IPv4 prefix was
4374 * received with Extended Next-hop capability in this
4375 * or another vrf and is now being advertised to
4376 * non-ENHE peers. Since peer_cap_enhe only checks
4377 * peers in this vrf, also check the nh_afi to catch
4378 * the case where the originator was in another vrf.
4379 * Setting the mandatory (ipv4) next-hop attribute here
4380 * to enable implicit next-hop self with correct A-F
4381 * (ipv4 address family).
4383 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4384 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4385 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4388 stream_put_ipv4(s
, 0);
4392 /* MED attribute. */
4393 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)
4394 || bgp
->maxmed_active
) {
4395 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4396 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4398 stream_putl(s
, (bgp
->maxmed_active
? bgp
->maxmed_value
4402 /* Local preference. */
4403 if (peer
->sort
== BGP_PEER_IBGP
|| peer
->sort
== BGP_PEER_CONFED
) {
4404 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4405 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4407 stream_putl(s
, attr
->local_pref
);
4410 /* Atomic aggregate. */
4411 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4412 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4413 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4418 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4419 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
4420 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4421 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4424 /* AS4 capable peer */
4426 stream_putl(s
, attr
->aggregator_as
);
4428 /* 2-byte AS peer */
4431 /* Is ASN representable in 2-bytes? Or must AS_TRANS be
4433 if (attr
->aggregator_as
> UINT16_MAX
) {
4434 stream_putw(s
, BGP_AS_TRANS
);
4436 /* we have to send AS4_AGGREGATOR, too.
4437 * we'll do that later in order to send
4438 * attributes in ascending
4441 send_as4_aggregator
= 1;
4443 stream_putw(s
, (uint16_t)attr
->aggregator_as
);
4445 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4448 /* Community attribute. */
4449 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
4450 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
))) {
4451 struct community
*comm
= NULL
;
4453 comm
= bgp_attr_get_community(attr
);
4454 if (comm
->size
* 4 > 255) {
4456 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4457 | BGP_ATTR_FLAG_EXTLEN
);
4458 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4459 stream_putw(s
, comm
->size
* 4);
4462 BGP_ATTR_FLAG_OPTIONAL
4463 | BGP_ATTR_FLAG_TRANS
);
4464 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4465 stream_putc(s
, comm
->size
* 4);
4467 stream_put(s
, comm
->val
, comm
->size
* 4);
4471 * Large Community attribute.
4473 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4474 PEER_FLAG_SEND_LARGE_COMMUNITY
)
4475 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
))) {
4476 if (lcom_length(bgp_attr_get_lcommunity(attr
)) > 255) {
4478 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4479 | BGP_ATTR_FLAG_EXTLEN
);
4480 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4482 lcom_length(bgp_attr_get_lcommunity(attr
)));
4485 BGP_ATTR_FLAG_OPTIONAL
4486 | BGP_ATTR_FLAG_TRANS
);
4487 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4489 lcom_length(bgp_attr_get_lcommunity(attr
)));
4491 stream_put(s
, bgp_attr_get_lcommunity(attr
)->val
,
4492 lcom_length(bgp_attr_get_lcommunity(attr
)));
4495 /* Route Reflector. */
4496 if (peer
->sort
== BGP_PEER_IBGP
&& from
4497 && from
->sort
== BGP_PEER_IBGP
) {
4498 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
4500 /* Originator ID. */
4501 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4502 stream_putc(s
, BGP_ATTR_ORIGINATOR_ID
);
4505 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
4506 stream_put_in_addr(s
, &attr
->originator_id
);
4508 stream_put_in_addr(s
, &from
->remote_id
);
4511 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4512 stream_putc(s
, BGP_ATTR_CLUSTER_LIST
);
4515 stream_putc(s
, cluster
->length
+ 4);
4516 /* If this peer configuration's parent BGP has
4518 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4519 stream_put_in_addr(s
, &bgp
->cluster_id
);
4521 stream_put_in_addr(s
, &bgp
->router_id
);
4522 stream_put(s
, cluster
->list
, cluster
->length
);
4525 /* If this peer configuration's parent BGP has
4527 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4528 stream_put_in_addr(s
, &bgp
->cluster_id
);
4530 stream_put_in_addr(s
, &bgp
->router_id
);
4534 /* Extended Communities attribute. */
4535 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
4536 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
))) {
4537 struct ecommunity
*ecomm
= bgp_attr_get_ecommunity(attr
);
4538 bool transparent
= CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4539 PEER_FLAG_RSERVER_CLIENT
) &&
4541 CHECK_FLAG(from
->af_flags
[afi
][safi
],
4542 PEER_FLAG_RSERVER_CLIENT
);
4544 if (peer
->sort
== BGP_PEER_IBGP
||
4545 peer
->sort
== BGP_PEER_CONFED
|| transparent
) {
4546 if (ecomm
->size
* 8 > 255) {
4548 BGP_ATTR_FLAG_OPTIONAL
4549 | BGP_ATTR_FLAG_TRANS
4550 | BGP_ATTR_FLAG_EXTLEN
);
4551 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4552 stream_putw(s
, ecomm
->size
* 8);
4555 BGP_ATTR_FLAG_OPTIONAL
4556 | BGP_ATTR_FLAG_TRANS
);
4557 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4558 stream_putc(s
, ecomm
->size
* 8);
4560 stream_put(s
, ecomm
->val
, ecomm
->size
* 8);
4564 int ecom_tr_size
= 0;
4567 for (i
= 0; i
< ecomm
->size
; i
++) {
4568 pnt
= ecomm
->val
+ (i
* 8);
4571 if (CHECK_FLAG(tbit
,
4572 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4579 if (ecom_tr_size
* 8 > 255) {
4582 BGP_ATTR_FLAG_OPTIONAL
4583 | BGP_ATTR_FLAG_TRANS
4584 | BGP_ATTR_FLAG_EXTLEN
);
4586 BGP_ATTR_EXT_COMMUNITIES
);
4587 stream_putw(s
, ecom_tr_size
* 8);
4591 BGP_ATTR_FLAG_OPTIONAL
4592 | BGP_ATTR_FLAG_TRANS
);
4594 BGP_ATTR_EXT_COMMUNITIES
);
4595 stream_putc(s
, ecom_tr_size
* 8);
4598 for (i
= 0; i
< ecomm
->size
; i
++) {
4599 pnt
= ecomm
->val
+ (i
* 8);
4604 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4607 stream_put(s
, pnt
, 8);
4613 /* Label index attribute. */
4614 if (safi
== SAFI_LABELED_UNICAST
) {
4615 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4616 uint32_t label_index
;
4618 label_index
= attr
->label_index
;
4620 if (label_index
!= BGP_INVALID_LABEL_INDEX
) {
4622 BGP_ATTR_FLAG_OPTIONAL
4623 | BGP_ATTR_FLAG_TRANS
);
4624 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4626 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4628 BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4629 stream_putc(s
, 0); // reserved
4630 stream_putw(s
, 0); // flags
4631 stream_putl(s
, label_index
);
4636 /* SRv6 Service Information Attribute. */
4637 if ((afi
== AFI_IP
|| afi
== AFI_IP6
) && safi
== SAFI_MPLS_VPN
) {
4638 if (attr
->srv6_l3vpn
) {
4639 uint8_t subtlv_len
=
4640 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
4642 + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
;
4643 uint8_t tlv_len
= subtlv_len
+ BGP_ATTR_MIN_LEN
+ 1;
4644 uint8_t attr_len
= tlv_len
+ BGP_ATTR_MIN_LEN
;
4645 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4646 | BGP_ATTR_FLAG_TRANS
);
4647 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4648 stream_putc(s
, attr_len
);
4649 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE
);
4650 stream_putw(s
, tlv_len
);
4651 stream_putc(s
, 0); /* reserved */
4652 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
);
4653 stream_putw(s
, subtlv_len
);
4654 stream_putc(s
, 0); /* reserved */
4655 stream_put(s
, &attr
->srv6_l3vpn
->sid
,
4656 sizeof(attr
->srv6_l3vpn
->sid
)); /* sid */
4657 stream_putc(s
, 0); /* sid_flags */
4660 ->endpoint_behavior
); /* endpoint */
4661 stream_putc(s
, 0); /* reserved */
4664 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
);
4667 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
);
4668 stream_putc(s
, attr
->srv6_l3vpn
->loc_block_len
);
4669 stream_putc(s
, attr
->srv6_l3vpn
->loc_node_len
);
4670 stream_putc(s
, attr
->srv6_l3vpn
->func_len
);
4671 stream_putc(s
, attr
->srv6_l3vpn
->arg_len
);
4672 stream_putc(s
, attr
->srv6_l3vpn
->transposition_len
);
4673 stream_putc(s
, attr
->srv6_l3vpn
->transposition_offset
);
4674 } else if (attr
->srv6_vpn
) {
4675 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4676 | BGP_ATTR_FLAG_TRANS
);
4677 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4678 stream_putc(s
, 22); /* tlv len */
4679 stream_putc(s
, BGP_PREFIX_SID_VPN_SID
);
4680 stream_putw(s
, 0x13); /* tlv len */
4681 stream_putc(s
, 0x00); /* reserved */
4682 stream_putc(s
, 0x01); /* sid_type */
4683 stream_putc(s
, 0x00); /* sif_flags */
4684 stream_put(s
, &attr
->srv6_vpn
->sid
,
4685 sizeof(attr
->srv6_vpn
->sid
)); /* sid */
4689 if (send_as4_path
) {
4690 /* If the peer is NOT As4 capable, AND */
4691 /* there are ASnums > 65535 in path THEN
4692 * give out AS4_PATH */
4694 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
4696 * Hm, I wonder... confederation things *should* only be at
4697 * the beginning of an aspath, right? Then we should use
4698 * aspath_delete_confed_seq for this, because it is already
4700 * Folks, talk to me: what is reasonable here!?
4702 aspath
= aspath_delete_confed_seq(aspath
);
4705 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4706 | BGP_ATTR_FLAG_EXTLEN
);
4707 stream_putc(s
, BGP_ATTR_AS4_PATH
);
4708 aspath_sizep
= stream_get_endp(s
);
4710 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, 1));
4713 if (aspath
!= attr
->aspath
)
4714 aspath_free(aspath
);
4716 if (send_as4_aggregator
) {
4717 /* send AS4_AGGREGATOR, at this place */
4718 /* this section of code moved here in order to ensure the
4720 * *ascending* order of attributes
4722 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4723 stream_putc(s
, BGP_ATTR_AS4_AGGREGATOR
);
4725 stream_putl(s
, attr
->aggregator_as
);
4726 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4729 if (((afi
== AFI_IP
|| afi
== AFI_IP6
)
4730 && (safi
== SAFI_ENCAP
|| safi
== SAFI_MPLS_VPN
))
4731 || (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)) {
4732 /* Tunnel Encap attribute */
4733 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_ENCAP
);
4735 #ifdef ENABLE_BGP_VNC_ATTR
4737 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_VNC
);
4742 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
)) {
4743 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4744 stream_putc(s
, BGP_ATTR_PMSI_TUNNEL
);
4745 stream_putc(s
, 9); // Length
4746 stream_putc(s
, 0); // Flags
4747 stream_putc(s
, bgp_attr_get_pmsi_tnl_type(attr
));
4748 stream_put(s
, &(attr
->label
),
4749 BGP_LABEL_BYTES
); // MPLS Label / VXLAN VNI
4750 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4751 // Unicast tunnel endpoint IP address
4755 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_OTC
)) {
4756 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4757 stream_putc(s
, BGP_ATTR_OTC
);
4759 stream_putl(s
, attr
->otc
);
4763 if (bpi
&& attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AIGP
) &&
4764 (CHECK_FLAG(peer
->flags
, PEER_FLAG_AIGP
) ||
4765 peer
->sort
!= BGP_PEER_EBGP
)) {
4766 /* At the moment only AIGP Metric TLV exists for AIGP
4767 * attribute. If more comes in, do not forget to update
4768 * attr_len variable to include new ones.
4770 uint8_t attr_len
= BGP_AIGP_TLV_METRIC_LEN
;
4772 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4773 stream_putc(s
, BGP_ATTR_AIGP
);
4774 stream_putc(s
, attr_len
);
4775 stream_put_bgp_aigp_tlv_metric(s
, bpi
);
4778 /* Unknown transit attribute. */
4779 struct transit
*transit
= bgp_attr_get_transit(attr
);
4782 stream_put(s
, transit
->val
, transit
->length
);
4784 /* Return total size of attribute. */
4785 return stream_get_endp(s
) - cp
;
4788 size_t bgp_packet_mpunreach_start(struct stream
*s
, afi_t afi
, safi_t safi
)
4790 unsigned long attrlen_pnt
;
4791 iana_afi_t pkt_afi
= IANA_AFI_IPV4
;
4792 iana_safi_t pkt_safi
= IANA_SAFI_UNICAST
;
4794 /* Set extended bit always to encode the attribute length as 2 bytes */
4795 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
4796 stream_putc(s
, BGP_ATTR_MP_UNREACH_NLRI
);
4798 attrlen_pnt
= stream_get_endp(s
);
4799 stream_putw(s
, 0); /* Length of this attribute. */
4801 /* Convert AFI, SAFI to values for packet. */
4802 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
4804 stream_putw(s
, pkt_afi
);
4805 stream_putc(s
, pkt_safi
);
4810 void bgp_packet_mpunreach_prefix(struct stream
*s
, const struct prefix
*p
,
4811 afi_t afi
, safi_t safi
,
4812 const struct prefix_rd
*prd
,
4813 mpls_label_t
*label
, uint32_t num_labels
,
4814 bool addpath_capable
, uint32_t addpath_tx_id
,
4817 uint8_t wlabel
[4] = {0x80, 0x00, 0x00};
4819 if (safi
== SAFI_LABELED_UNICAST
) {
4820 label
= (mpls_label_t
*)wlabel
;
4824 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
, num_labels
,
4825 addpath_capable
, addpath_tx_id
, attr
);
4828 void bgp_packet_mpunreach_end(struct stream
*s
, size_t attrlen_pnt
)
4830 bgp_packet_mpattr_end(s
, attrlen_pnt
);
4833 /* Initialization of attribute. */
4834 void bgp_attr_init(void)
4847 void bgp_attr_finish(void)
4852 ecommunity_finish();
4853 lcommunity_finish();
4860 /* Make attribute packet. */
4861 void bgp_dump_routes_attr(struct stream
*s
, struct bgp_path_info
*bpi
,
4862 const struct prefix
*prefix
)
4867 struct aspath
*aspath
;
4868 bool addpath_capable
= false;
4869 uint32_t addpath_tx_id
= 0;
4870 struct attr
*attr
= bpi
->attr
;
4872 /* Remember current pointer. */
4873 cp
= stream_get_endp(s
);
4875 /* Place holder of length. */
4878 /* Origin attribute. */
4879 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4880 stream_putc(s
, BGP_ATTR_ORIGIN
);
4882 stream_putc(s
, attr
->origin
);
4884 aspath
= attr
->aspath
;
4886 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4887 stream_putc(s
, BGP_ATTR_AS_PATH
);
4888 aspath_lenp
= stream_get_endp(s
);
4891 stream_putw_at(s
, aspath_lenp
, aspath_put(s
, aspath
, 1));
4893 /* Nexthop attribute. */
4894 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
4895 if (prefix
!= NULL
&& prefix
->family
!= AF_INET6
) {
4896 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4897 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4899 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4902 /* MED attribute. */
4903 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)) {
4904 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4905 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4907 stream_putl(s
, attr
->med
);
4910 /* Local preference. */
4911 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)) {
4912 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4913 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4915 stream_putl(s
, attr
->local_pref
);
4918 /* Atomic aggregate. */
4919 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4920 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4921 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4926 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4927 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4928 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4930 stream_putl(s
, attr
->aggregator_as
);
4931 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4934 /* Community attribute. */
4935 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
)) {
4936 struct community
*comm
= NULL
;
4938 comm
= bgp_attr_get_community(attr
);
4939 if (comm
->size
* 4 > 255) {
4941 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4942 | BGP_ATTR_FLAG_EXTLEN
);
4943 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4944 stream_putw(s
, comm
->size
* 4);
4947 BGP_ATTR_FLAG_OPTIONAL
4948 | BGP_ATTR_FLAG_TRANS
);
4949 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4950 stream_putc(s
, comm
->size
* 4);
4952 stream_put(s
, comm
->val
, comm
->size
* 4);
4955 /* Large Community attribute. */
4956 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
)) {
4957 if (lcom_length(bgp_attr_get_lcommunity(attr
)) > 255) {
4959 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4960 | BGP_ATTR_FLAG_EXTLEN
);
4961 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4963 lcom_length(bgp_attr_get_lcommunity(attr
)));
4966 BGP_ATTR_FLAG_OPTIONAL
4967 | BGP_ATTR_FLAG_TRANS
);
4968 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4970 lcom_length(bgp_attr_get_lcommunity(attr
)));
4973 stream_put(s
, bgp_attr_get_lcommunity(attr
)->val
,
4974 lcom_length(bgp_attr_get_lcommunity(attr
)));
4977 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
4978 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
4979 && (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL
4980 || attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)) {
4983 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4984 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
4985 sizep
= stream_get_endp(s
);
4988 stream_putc(s
, 0); /* Marker: Attribute length. */
4989 stream_putw(s
, AFI_IP6
); /* AFI */
4990 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
4993 stream_putc(s
, attr
->mp_nexthop_len
);
4994 stream_put(s
, &attr
->mp_nexthop_global
, IPV6_MAX_BYTELEN
);
4995 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)
4996 stream_put(s
, &attr
->mp_nexthop_local
,
5003 stream_put_prefix_addpath(s
, prefix
, addpath_capable
,
5006 /* Set MP attribute length. */
5007 stream_putc_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 1);
5011 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
5012 if (attr
->label_index
!= BGP_INVALID_LABEL_INDEX
) {
5014 BGP_ATTR_FLAG_OPTIONAL
5015 | BGP_ATTR_FLAG_TRANS
);
5016 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
5018 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
5019 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
5020 stream_putc(s
, 0); // reserved
5021 stream_putw(s
, 0); // flags
5022 stream_putl(s
, attr
->label_index
);
5027 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_OTC
)) {
5028 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
5029 stream_putc(s
, BGP_ATTR_OTC
);
5031 stream_putl(s
, attr
->otc
);
5035 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AIGP
)) {
5036 /* At the moment only AIGP Metric TLV exists for AIGP
5037 * attribute. If more comes in, do not forget to update
5038 * attr_len variable to include new ones.
5040 uint8_t attr_len
= BGP_AIGP_TLV_METRIC_LEN
;
5042 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
5043 stream_putc(s
, BGP_ATTR_AIGP
);
5044 stream_putc(s
, attr_len
);
5045 stream_put_bgp_aigp_tlv_metric(s
, bpi
);
5048 /* Return total size of attribute. */
5049 len
= stream_get_endp(s
) - cp
- 2;
5050 stream_putw_at(s
, cp
, len
);
5053 void bgp_path_attribute_discard_vty(struct vty
*vty
, struct peer
*peer
,
5054 const char *discard_attrs
, bool set
)
5056 int i
, num_attributes
;
5062 /* If `no` command specified without arbitrary attributes,
5065 if (!discard_attrs
) {
5066 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5067 peer
->discard_attrs
[i
] = false;
5068 goto discard_soft_clear
;
5071 if (discard_attrs
) {
5072 frrstr_split(discard_attrs
, " ", &attributes
, &num_attributes
);
5075 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5076 peer
->discard_attrs
[i
] = false;
5078 for (i
= 0; i
< num_attributes
; i
++) {
5079 uint8_t attr_num
= strtoul(attributes
[i
], NULL
, 10);
5081 XFREE(MTYPE_TMP
, attributes
[i
]);
5083 /* Some of the attributes, just can't be ignored. */
5084 if (attr_num
== BGP_ATTR_ORIGIN
||
5085 attr_num
== BGP_ATTR_AS_PATH
||
5086 attr_num
== BGP_ATTR_NEXT_HOP
||
5087 attr_num
== BGP_ATTR_MULTI_EXIT_DISC
||
5088 attr_num
== BGP_ATTR_MP_REACH_NLRI
||
5089 attr_num
== BGP_ATTR_MP_UNREACH_NLRI
||
5090 attr_num
== BGP_ATTR_EXT_COMMUNITIES
) {
5092 "%% Can't discard path-attribute %s, ignoring.\n",
5093 lookup_msg(attr_str
, attr_num
, NULL
));
5097 /* Ignore local-pref, originator-id, cluster-list only
5100 if (peer
->sort
!= BGP_PEER_EBGP
&&
5101 (attr_num
== BGP_ATTR_LOCAL_PREF
||
5102 attr_num
== BGP_ATTR_ORIGINATOR_ID
||
5103 attr_num
== BGP_ATTR_CLUSTER_LIST
)) {
5105 "%% Can discard path-attribute %s only for eBGP, ignoring.\n",
5106 lookup_msg(attr_str
, attr_num
, NULL
));
5110 peer
->discard_attrs
[attr_num
] = set
;
5112 XFREE(MTYPE_TMP
, attributes
);
5114 /* Configuring path attributes to be discarded will trigger
5115 * an inbound Route Refresh to ensure that the routing table
5118 FOREACH_AFI_SAFI (afi
, safi
)
5119 peer_clear_soft(peer
, afi
, safi
, BGP_CLEAR_SOFT_IN
);
5123 void bgp_path_attribute_withdraw_vty(struct vty
*vty
, struct peer
*peer
,
5124 const char *withdraw_attrs
, bool set
)
5126 int i
, num_attributes
;
5131 /* If `no` command specified without arbitrary attributes,
5134 if (!withdraw_attrs
) {
5135 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5136 peer
->withdraw_attrs
[i
] = false;
5137 goto withdraw_soft_clear
;
5140 if (withdraw_attrs
) {
5141 frrstr_split(withdraw_attrs
, " ", &attributes
, &num_attributes
);
5144 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5145 peer
->withdraw_attrs
[i
] = false;
5147 for (i
= 0; i
< num_attributes
; i
++) {
5148 uint8_t attr_num
= strtoul(attributes
[i
], NULL
, 10);
5150 XFREE(MTYPE_TMP
, attributes
[i
]);
5152 /* Some of the attributes, just can't be ignored. */
5153 if (attr_num
== BGP_ATTR_ORIGIN
||
5154 attr_num
== BGP_ATTR_AS_PATH
||
5155 attr_num
== BGP_ATTR_NEXT_HOP
||
5156 attr_num
== BGP_ATTR_MULTI_EXIT_DISC
||
5157 attr_num
== BGP_ATTR_MP_REACH_NLRI
||
5158 attr_num
== BGP_ATTR_MP_UNREACH_NLRI
||
5159 attr_num
== BGP_ATTR_EXT_COMMUNITIES
) {
5161 "%% Can't treat-as-withdraw path-attribute %s, ignoring.\n",
5162 lookup_msg(attr_str
, attr_num
, NULL
));
5166 /* Ignore local-pref, originator-id, cluster-list only
5169 if (peer
->sort
!= BGP_PEER_EBGP
&&
5170 (attr_num
== BGP_ATTR_LOCAL_PREF
||
5171 attr_num
== BGP_ATTR_ORIGINATOR_ID
||
5172 attr_num
== BGP_ATTR_CLUSTER_LIST
)) {
5174 "%% Can treat-as-withdraw path-attribute %s only for eBGP, ignoring.\n",
5175 lookup_msg(attr_str
, attr_num
, NULL
));
5179 peer
->withdraw_attrs
[attr_num
] = set
;
5181 XFREE(MTYPE_TMP
, attributes
);
5182 withdraw_soft_clear
:
5183 /* Configuring path attributes to be treated as withdraw will
5185 * an inbound Route Refresh to ensure that the routing table
5188 FOREACH_AFI_SAFI (afi
, safi
)
5189 peer_clear_soft(peer
, afi
, safi
, BGP_CLEAR_SOFT_IN
);
5193 enum bgp_attr_parse_ret
bgp_attr_ignore(struct peer
*peer
, uint8_t type
)
5195 bool discard
= peer
->discard_attrs
[type
];
5196 bool withdraw
= peer
->withdraw_attrs
[type
];
5198 if (bgp_debug_update(peer
, NULL
, NULL
, 1) && (discard
|| withdraw
))
5199 zlog_debug("%pBP: Ignoring attribute %s (%s)", peer
,
5200 lookup_msg(attr_str
, type
, NULL
),
5201 withdraw
? "treat-as-withdraw" : "discard");
5203 return withdraw
? BGP_ATTR_PARSE_WITHDRAW
: BGP_ATTR_PARSE_PROCEED
;