1 /* BGP attributes management routines.
2 * Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
38 #include "bgpd/bgpd.h"
39 #include "bgpd/bgp_attr.h"
40 #include "bgpd/bgp_route.h"
41 #include "bgpd/bgp_aspath.h"
42 #include "bgpd/bgp_community.h"
43 #include "bgpd/bgp_debug.h"
44 #include "bgpd/bgp_errors.h"
45 #include "bgpd/bgp_label.h"
46 #include "bgpd/bgp_packet.h"
47 #include "bgpd/bgp_ecommunity.h"
48 #include "bgpd/bgp_lcommunity.h"
49 #include "bgpd/bgp_updgrp.h"
50 #include "bgpd/bgp_encap_types.h"
52 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
53 #include "bgp_encap_types.h"
54 #include "bgp_vnc_types.h"
57 #include "bgp_flowspec_private.h"
60 /* Attribute strings for logging. */
61 static const struct message attr_str
[] = {
62 {BGP_ATTR_ORIGIN
, "ORIGIN"},
63 {BGP_ATTR_AS_PATH
, "AS_PATH"},
64 {BGP_ATTR_NEXT_HOP
, "NEXT_HOP"},
65 {BGP_ATTR_MULTI_EXIT_DISC
, "MULTI_EXIT_DISC"},
66 {BGP_ATTR_LOCAL_PREF
, "LOCAL_PREF"},
67 {BGP_ATTR_ATOMIC_AGGREGATE
, "ATOMIC_AGGREGATE"},
68 {BGP_ATTR_AGGREGATOR
, "AGGREGATOR"},
69 {BGP_ATTR_COMMUNITIES
, "COMMUNITY"},
70 {BGP_ATTR_ORIGINATOR_ID
, "ORIGINATOR_ID"},
71 {BGP_ATTR_CLUSTER_LIST
, "CLUSTER_LIST"},
72 {BGP_ATTR_MP_REACH_NLRI
, "MP_REACH_NLRI"},
73 {BGP_ATTR_MP_UNREACH_NLRI
, "MP_UNREACH_NLRI"},
74 {BGP_ATTR_EXT_COMMUNITIES
, "EXT_COMMUNITIES"},
75 {BGP_ATTR_AS4_PATH
, "AS4_PATH"},
76 {BGP_ATTR_AS4_AGGREGATOR
, "AS4_AGGREGATOR"},
77 {BGP_ATTR_PMSI_TUNNEL
, "PMSI_TUNNEL_ATTRIBUTE"},
78 {BGP_ATTR_ENCAP
, "ENCAP"},
79 {BGP_ATTR_OTC
, "OTC"},
80 #ifdef ENABLE_BGP_VNC_ATTR
81 {BGP_ATTR_VNC
, "VNC"},
83 {BGP_ATTR_LARGE_COMMUNITIES
, "LARGE_COMMUNITY"},
84 {BGP_ATTR_PREFIX_SID
, "PREFIX_SID"},
85 {BGP_ATTR_IPV6_EXT_COMMUNITIES
, "IPV6_EXT_COMMUNITIES"},
86 {BGP_ATTR_AIGP
, "AIGP"},
89 static const struct message attr_flag_str
[] = {
90 {BGP_ATTR_FLAG_OPTIONAL
, "Optional"},
91 {BGP_ATTR_FLAG_TRANS
, "Transitive"},
92 {BGP_ATTR_FLAG_PARTIAL
, "Partial"},
93 /* bgp_attr_flags_diagnose() relies on this bit being last in
95 {BGP_ATTR_FLAG_EXTLEN
, "Extended Length"},
98 static struct hash
*cluster_hash
;
100 static void *cluster_hash_alloc(void *p
)
102 const struct cluster_list
*val
= (const struct cluster_list
*)p
;
103 struct cluster_list
*cluster
;
105 cluster
= XMALLOC(MTYPE_CLUSTER
, sizeof(struct cluster_list
));
106 cluster
->length
= val
->length
;
108 if (cluster
->length
) {
109 cluster
->list
= XMALLOC(MTYPE_CLUSTER_VAL
, val
->length
);
110 memcpy(cluster
->list
, val
->list
, val
->length
);
112 cluster
->list
= NULL
;
119 /* Cluster list related functions. */
120 static struct cluster_list
*cluster_parse(struct in_addr
*pnt
, int length
)
122 struct cluster_list tmp
= {};
123 struct cluster_list
*cluster
;
126 tmp
.list
= length
== 0 ? NULL
: pnt
;
128 cluster
= hash_get(cluster_hash
, &tmp
, cluster_hash_alloc
);
133 bool cluster_loop_check(struct cluster_list
*cluster
, struct in_addr originator
)
137 for (i
= 0; i
< cluster
->length
/ 4; i
++)
138 if (cluster
->list
[i
].s_addr
== originator
.s_addr
)
143 static unsigned int cluster_hash_key_make(const void *p
)
145 const struct cluster_list
*cluster
= p
;
147 return jhash(cluster
->list
, cluster
->length
, 0);
150 static bool cluster_hash_cmp(const void *p1
, const void *p2
)
152 const struct cluster_list
*cluster1
= p1
;
153 const struct cluster_list
*cluster2
= p2
;
155 if (cluster1
->list
== cluster2
->list
)
158 if (!cluster1
->list
|| !cluster2
->list
)
161 if (cluster1
->length
!= cluster2
->length
)
164 return (memcmp(cluster1
->list
, cluster2
->list
, cluster1
->length
) == 0);
167 static void cluster_free(struct cluster_list
*cluster
)
169 XFREE(MTYPE_CLUSTER_VAL
, cluster
->list
);
170 XFREE(MTYPE_CLUSTER
, cluster
);
173 static struct cluster_list
*cluster_intern(struct cluster_list
*cluster
)
175 struct cluster_list
*find
;
177 find
= hash_get(cluster_hash
, cluster
, cluster_hash_alloc
);
183 static void cluster_unintern(struct cluster_list
**cluster
)
185 if ((*cluster
)->refcnt
)
186 (*cluster
)->refcnt
--;
188 if ((*cluster
)->refcnt
== 0) {
189 void *p
= hash_release(cluster_hash
, *cluster
);
190 assert(p
== *cluster
);
191 cluster_free(*cluster
);
196 static void cluster_init(void)
198 cluster_hash
= hash_create(cluster_hash_key_make
, cluster_hash_cmp
,
202 static void cluster_finish(void)
204 hash_clean(cluster_hash
, (void (*)(void *))cluster_free
);
205 hash_free(cluster_hash
);
209 static struct hash
*encap_hash
= NULL
;
210 #ifdef ENABLE_BGP_VNC
211 static struct hash
*vnc_hash
= NULL
;
213 static struct hash
*srv6_l3vpn_hash
;
214 static struct hash
*srv6_vpn_hash
;
216 struct bgp_attr_encap_subtlv
*encap_tlv_dup(struct bgp_attr_encap_subtlv
*orig
)
218 struct bgp_attr_encap_subtlv
*new;
219 struct bgp_attr_encap_subtlv
*tail
;
220 struct bgp_attr_encap_subtlv
*p
;
222 for (p
= orig
, tail
= new = NULL
; p
; p
= p
->next
) {
223 int size
= sizeof(struct bgp_attr_encap_subtlv
) + p
->length
;
225 tail
->next
= XCALLOC(MTYPE_ENCAP_TLV
, size
);
228 tail
= new = XCALLOC(MTYPE_ENCAP_TLV
, size
);
231 memcpy(tail
, p
, size
);
238 static void encap_free(struct bgp_attr_encap_subtlv
*p
)
240 struct bgp_attr_encap_subtlv
*next
;
244 XFREE(MTYPE_ENCAP_TLV
, p
);
249 void bgp_attr_flush_encap(struct attr
*attr
)
254 if (attr
->encap_subtlvs
) {
255 encap_free(attr
->encap_subtlvs
);
256 attr
->encap_subtlvs
= NULL
;
258 #ifdef ENABLE_BGP_VNC
259 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
260 bgp_attr_get_vnc_subtlvs(attr
);
263 encap_free(vnc_subtlvs
);
264 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
270 * Compare encap sub-tlv chains
275 * This algorithm could be made faster if needed
277 static bool encap_same(const struct bgp_attr_encap_subtlv
*h1
,
278 const struct bgp_attr_encap_subtlv
*h2
)
280 const struct bgp_attr_encap_subtlv
*p
;
281 const struct bgp_attr_encap_subtlv
*q
;
285 if (h1
== NULL
|| h2
== NULL
)
288 for (p
= h1
; p
; p
= p
->next
) {
289 for (q
= h2
; q
; q
= q
->next
) {
290 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
291 && !memcmp(p
->value
, q
->value
, p
->length
)) {
300 for (p
= h2
; p
; p
= p
->next
) {
301 for (q
= h1
; q
; q
= q
->next
) {
302 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
303 && !memcmp(p
->value
, q
->value
, p
->length
)) {
315 static void *encap_hash_alloc(void *p
)
317 /* Encap structure is already allocated. */
323 #ifdef ENABLE_BGP_VNC
328 static struct bgp_attr_encap_subtlv
*
329 encap_intern(struct bgp_attr_encap_subtlv
*encap
, encap_subtlv_type type
)
331 struct bgp_attr_encap_subtlv
*find
;
332 struct hash
*hash
= encap_hash
;
333 #ifdef ENABLE_BGP_VNC
334 if (type
== VNC_SUBTLV_TYPE
)
338 find
= hash_get(hash
, encap
, encap_hash_alloc
);
346 static void encap_unintern(struct bgp_attr_encap_subtlv
**encapp
,
347 encap_subtlv_type type
)
349 struct bgp_attr_encap_subtlv
*encap
= *encapp
;
353 if (encap
->refcnt
== 0) {
354 struct hash
*hash
= encap_hash
;
355 #ifdef ENABLE_BGP_VNC
356 if (type
== VNC_SUBTLV_TYPE
)
359 hash_release(hash
, encap
);
365 static unsigned int encap_hash_key_make(const void *p
)
367 const struct bgp_attr_encap_subtlv
*encap
= p
;
369 return jhash(encap
->value
, encap
->length
, 0);
372 static bool encap_hash_cmp(const void *p1
, const void *p2
)
374 return encap_same((const struct bgp_attr_encap_subtlv
*)p1
,
375 (const struct bgp_attr_encap_subtlv
*)p2
);
378 static void encap_init(void)
380 encap_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
382 #ifdef ENABLE_BGP_VNC
383 vnc_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
388 static void encap_finish(void)
390 hash_clean(encap_hash
, (void (*)(void *))encap_free
);
391 hash_free(encap_hash
);
393 #ifdef ENABLE_BGP_VNC
394 hash_clean(vnc_hash
, (void (*)(void *))encap_free
);
400 static bool overlay_index_same(const struct attr
*a1
, const struct attr
*a2
)
409 return bgp_route_evpn_same(bgp_attr_get_evpn_overlay(a1
),
410 bgp_attr_get_evpn_overlay(a2
));
413 /* Unknown transit attribute. */
414 static struct hash
*transit_hash
;
416 static void transit_free(struct transit
*transit
)
418 XFREE(MTYPE_TRANSIT_VAL
, transit
->val
);
419 XFREE(MTYPE_TRANSIT
, transit
);
422 static void *transit_hash_alloc(void *p
)
424 /* Transit structure is already allocated. */
428 static struct transit
*transit_intern(struct transit
*transit
)
430 struct transit
*find
;
432 find
= hash_get(transit_hash
, transit
, transit_hash_alloc
);
434 transit_free(transit
);
440 static void transit_unintern(struct transit
**transit
)
442 if ((*transit
)->refcnt
)
443 (*transit
)->refcnt
--;
445 if ((*transit
)->refcnt
== 0) {
446 hash_release(transit_hash
, *transit
);
447 transit_free(*transit
);
452 static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt
, int length
,
461 ptr_get_be16(data
+ 1, &tlv_length
);
464 /* The value field of the AIGP TLV is always 8 octets
465 * long and its value is interpreted as an unsigned 64-bit
468 if (tlv_type
== BGP_AIGP_TLV_METRIC
) {
469 (void)ptr_get_be64(data
+ 3, aigp
);
471 /* If an AIGP attribute is received and its first AIGP
472 * TLV contains the maximum value 0xffffffffffffffff,
473 * the attribute SHOULD be considered to be malformed
474 * and SHOULD be discarded as specified in this section.
476 if (*aigp
== BGP_AIGP_TLV_METRIC_MAX
) {
477 zlog_err("Bad AIGP TLV (%s) length: %llu",
478 BGP_AIGP_TLV_METRIC_DESC
,
479 BGP_AIGP_TLV_METRIC_MAX
);
487 length
-= tlv_length
;
493 static uint64_t bgp_aigp_metric_total(struct bgp_path_info
*bpi
)
495 uint64_t aigp
= bgp_attr_get_aigp_metric(bpi
->attr
);
498 return aigp
+ bpi
->nexthop
->metric
;
503 static void stream_put_bgp_aigp_tlv_metric(struct stream
*s
,
504 struct bgp_path_info
*bpi
)
506 stream_putc(s
, BGP_AIGP_TLV_METRIC
);
507 stream_putw(s
, BGP_AIGP_TLV_METRIC_LEN
);
508 stream_putq(s
, bgp_aigp_metric_total(bpi
));
511 static bool bgp_attr_aigp_valid(uint8_t *pnt
, int length
)
518 zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u",
525 ptr_get_be16(data
+ 1, &tlv_length
);
528 if (length
< tlv_length
) {
530 "Bad AIGP attribute length: %u, but TLV length: %u",
535 if (tlv_length
< 3) {
536 zlog_err("Bad AIGP TLV length (MUST be minimum 3): %u",
541 /* AIGP TLV, Length: 11 */
542 if (tlv_type
== BGP_AIGP_TLV_METRIC
&&
543 tlv_length
!= BGP_AIGP_TLV_METRIC_LEN
) {
544 zlog_err("Bad AIGP TLV (%s) length: %u",
545 BGP_AIGP_TLV_METRIC_DESC
, tlv_length
);
550 length
-= tlv_length
;
556 static void *srv6_l3vpn_hash_alloc(void *p
)
561 static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn
*l3vpn
)
563 XFREE(MTYPE_BGP_SRV6_L3VPN
, l3vpn
);
566 static struct bgp_attr_srv6_l3vpn
*
567 srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn
*l3vpn
)
569 struct bgp_attr_srv6_l3vpn
*find
;
571 find
= hash_get(srv6_l3vpn_hash
, l3vpn
, srv6_l3vpn_hash_alloc
);
573 srv6_l3vpn_free(l3vpn
);
578 static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn
**l3vpnp
)
580 struct bgp_attr_srv6_l3vpn
*l3vpn
= *l3vpnp
;
585 if (l3vpn
->refcnt
== 0) {
586 hash_release(srv6_l3vpn_hash
, l3vpn
);
587 srv6_l3vpn_free(l3vpn
);
592 static void *srv6_vpn_hash_alloc(void *p
)
597 static void srv6_vpn_free(struct bgp_attr_srv6_vpn
*vpn
)
599 XFREE(MTYPE_BGP_SRV6_VPN
, vpn
);
602 static struct bgp_attr_srv6_vpn
*srv6_vpn_intern(struct bgp_attr_srv6_vpn
*vpn
)
604 struct bgp_attr_srv6_vpn
*find
;
606 find
= hash_get(srv6_vpn_hash
, vpn
, srv6_vpn_hash_alloc
);
613 static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn
**vpnp
)
615 struct bgp_attr_srv6_vpn
*vpn
= *vpnp
;
620 if (vpn
->refcnt
== 0) {
621 hash_release(srv6_vpn_hash
, vpn
);
627 static uint32_t srv6_l3vpn_hash_key_make(const void *p
)
629 const struct bgp_attr_srv6_l3vpn
*l3vpn
= p
;
632 key
= jhash(&l3vpn
->sid
, 16, key
);
633 key
= jhash_1word(l3vpn
->sid_flags
, key
);
634 key
= jhash_1word(l3vpn
->endpoint_behavior
, key
);
635 key
= jhash_1word(l3vpn
->loc_block_len
, key
);
636 key
= jhash_1word(l3vpn
->loc_node_len
, key
);
637 key
= jhash_1word(l3vpn
->func_len
, key
);
638 key
= jhash_1word(l3vpn
->arg_len
, key
);
639 key
= jhash_1word(l3vpn
->transposition_len
, key
);
640 key
= jhash_1word(l3vpn
->transposition_offset
, key
);
644 static bool srv6_l3vpn_hash_cmp(const void *p1
, const void *p2
)
646 const struct bgp_attr_srv6_l3vpn
*l3vpn1
= p1
;
647 const struct bgp_attr_srv6_l3vpn
*l3vpn2
= p2
;
649 return sid_same(&l3vpn1
->sid
, &l3vpn2
->sid
)
650 && l3vpn1
->sid_flags
== l3vpn2
->sid_flags
651 && l3vpn1
->endpoint_behavior
== l3vpn2
->endpoint_behavior
652 && l3vpn1
->loc_block_len
== l3vpn2
->loc_block_len
653 && l3vpn1
->loc_node_len
== l3vpn2
->loc_node_len
654 && l3vpn1
->func_len
== l3vpn2
->func_len
655 && l3vpn1
->arg_len
== l3vpn2
->arg_len
656 && l3vpn1
->transposition_len
== l3vpn2
->transposition_len
657 && l3vpn1
->transposition_offset
== l3vpn2
->transposition_offset
;
660 static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn
*h1
,
661 const struct bgp_attr_srv6_l3vpn
*h2
)
665 else if (h1
== NULL
|| h2
== NULL
)
668 return srv6_l3vpn_hash_cmp((const void *)h1
, (const void *)h2
);
671 static unsigned int srv6_vpn_hash_key_make(const void *p
)
673 const struct bgp_attr_srv6_vpn
*vpn
= p
;
676 key
= jhash(&vpn
->sid
, 16, key
);
677 key
= jhash_1word(vpn
->sid_flags
, key
);
681 static bool srv6_vpn_hash_cmp(const void *p1
, const void *p2
)
683 const struct bgp_attr_srv6_vpn
*vpn1
= p1
;
684 const struct bgp_attr_srv6_vpn
*vpn2
= p2
;
686 return sid_same(&vpn1
->sid
, &vpn2
->sid
)
687 && vpn1
->sid_flags
== vpn2
->sid_flags
;
690 static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn
*h1
,
691 const struct bgp_attr_srv6_vpn
*h2
)
695 else if (h1
== NULL
|| h2
== NULL
)
698 return srv6_vpn_hash_cmp((const void *)h1
, (const void *)h2
);
701 static void srv6_init(void)
704 hash_create(srv6_l3vpn_hash_key_make
, srv6_l3vpn_hash_cmp
,
705 "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
706 srv6_vpn_hash
= hash_create(srv6_vpn_hash_key_make
, srv6_vpn_hash_cmp
,
707 "BGP Prefix-SID SRv6-VPN-Service-TLV");
710 static void srv6_finish(void)
712 hash_clean(srv6_l3vpn_hash
, (void (*)(void *))srv6_l3vpn_free
);
713 hash_free(srv6_l3vpn_hash
);
714 srv6_l3vpn_hash
= NULL
;
715 hash_clean(srv6_vpn_hash
, (void (*)(void *))srv6_vpn_free
);
716 hash_free(srv6_vpn_hash
);
717 srv6_vpn_hash
= NULL
;
720 static unsigned int transit_hash_key_make(const void *p
)
722 const struct transit
*transit
= p
;
724 return jhash(transit
->val
, transit
->length
, 0);
727 static bool transit_hash_cmp(const void *p1
, const void *p2
)
729 const struct transit
*transit1
= p1
;
730 const struct transit
*transit2
= p2
;
732 return (transit1
->length
== transit2
->length
733 && memcmp(transit1
->val
, transit2
->val
, transit1
->length
) == 0);
736 static void transit_init(void)
738 transit_hash
= hash_create(transit_hash_key_make
, transit_hash_cmp
,
742 static void transit_finish(void)
744 hash_clean(transit_hash
, (void (*)(void *))transit_free
);
745 hash_free(transit_hash
);
749 /* Attribute hash routines. */
750 static struct hash
*attrhash
;
752 unsigned long int attr_count(void)
754 return attrhash
->count
;
757 unsigned long int attr_unknown_count(void)
759 return transit_hash
->count
;
762 unsigned int attrhash_key_make(const void *p
)
764 const struct attr
*attr
= (struct attr
*)p
;
766 #define MIX(val) key = jhash_1word(val, key)
767 #define MIX3(a, b, c) key = jhash_3words((a), (b), (c), key)
769 MIX3(attr
->origin
, attr
->nexthop
.s_addr
, attr
->med
);
770 MIX3(attr
->local_pref
, attr
->aggregator_as
,
771 attr
->aggregator_addr
.s_addr
);
772 MIX3(attr
->weight
, attr
->mp_nexthop_global_in
.s_addr
,
773 attr
->originator_id
.s_addr
);
774 MIX3(attr
->tag
, attr
->label
, attr
->label_index
);
777 MIX(aspath_key_make(attr
->aspath
));
778 if (bgp_attr_get_community(attr
))
779 MIX(community_hash_make(bgp_attr_get_community(attr
)));
780 if (bgp_attr_get_lcommunity(attr
))
781 MIX(lcommunity_hash_make(bgp_attr_get_lcommunity(attr
)));
782 if (bgp_attr_get_ecommunity(attr
))
783 MIX(ecommunity_hash_make(bgp_attr_get_ecommunity(attr
)));
784 if (bgp_attr_get_ipv6_ecommunity(attr
))
785 MIX(ecommunity_hash_make(bgp_attr_get_ipv6_ecommunity(attr
)));
786 if (bgp_attr_get_cluster(attr
))
787 MIX(cluster_hash_key_make(bgp_attr_get_cluster(attr
)));
788 if (bgp_attr_get_transit(attr
))
789 MIX(transit_hash_key_make(bgp_attr_get_transit(attr
)));
790 if (attr
->encap_subtlvs
)
791 MIX(encap_hash_key_make(attr
->encap_subtlvs
));
792 if (attr
->srv6_l3vpn
)
793 MIX(srv6_l3vpn_hash_key_make(attr
->srv6_l3vpn
));
795 MIX(srv6_vpn_hash_key_make(attr
->srv6_vpn
));
796 #ifdef ENABLE_BGP_VNC
797 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
798 bgp_attr_get_vnc_subtlvs(attr
);
800 MIX(encap_hash_key_make(vnc_subtlvs
));
802 MIX(attr
->mp_nexthop_len
);
803 key
= jhash(attr
->mp_nexthop_global
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
804 key
= jhash(attr
->mp_nexthop_local
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
805 MIX3(attr
->nh_ifindex
, attr
->nh_lla_ifindex
, attr
->distance
);
806 MIX(attr
->rmap_table_id
);
810 MIX(bgp_attr_get_aigp_metric(attr
));
815 bool attrhash_cmp(const void *p1
, const void *p2
)
817 const struct attr
*attr1
= p1
;
818 const struct attr
*attr2
= p2
;
820 if (attr1
->flag
== attr2
->flag
&& attr1
->origin
== attr2
->origin
821 && attr1
->nexthop
.s_addr
== attr2
->nexthop
.s_addr
822 && attr1
->aspath
== attr2
->aspath
823 && bgp_attr_get_community(attr1
)
824 == bgp_attr_get_community(attr2
)
825 && attr1
->med
== attr2
->med
826 && attr1
->local_pref
== attr2
->local_pref
827 && attr1
->rmap_change_flags
== attr2
->rmap_change_flags
) {
828 if (attr1
->aggregator_as
== attr2
->aggregator_as
829 && attr1
->aggregator_addr
.s_addr
830 == attr2
->aggregator_addr
.s_addr
831 && attr1
->weight
== attr2
->weight
832 && attr1
->tag
== attr2
->tag
833 && attr1
->label_index
== attr2
->label_index
834 && attr1
->mp_nexthop_len
== attr2
->mp_nexthop_len
835 && bgp_attr_get_ecommunity(attr1
)
836 == bgp_attr_get_ecommunity(attr2
)
837 && bgp_attr_get_ipv6_ecommunity(attr1
)
838 == bgp_attr_get_ipv6_ecommunity(attr2
)
839 && bgp_attr_get_lcommunity(attr1
)
840 == bgp_attr_get_lcommunity(attr2
)
841 && bgp_attr_get_cluster(attr1
)
842 == bgp_attr_get_cluster(attr2
)
843 && bgp_attr_get_transit(attr1
)
844 == bgp_attr_get_transit(attr2
)
845 && bgp_attr_get_aigp_metric(attr1
)
846 == bgp_attr_get_aigp_metric(attr2
)
847 && attr1
->rmap_table_id
== attr2
->rmap_table_id
848 && (attr1
->encap_tunneltype
== attr2
->encap_tunneltype
)
849 && encap_same(attr1
->encap_subtlvs
, attr2
->encap_subtlvs
)
850 #ifdef ENABLE_BGP_VNC
851 && encap_same(bgp_attr_get_vnc_subtlvs(attr1
),
852 bgp_attr_get_vnc_subtlvs(attr2
))
854 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_global
,
855 &attr2
->mp_nexthop_global
)
856 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_local
,
857 &attr2
->mp_nexthop_local
)
858 && IPV4_ADDR_SAME(&attr1
->mp_nexthop_global_in
,
859 &attr2
->mp_nexthop_global_in
)
860 && IPV4_ADDR_SAME(&attr1
->originator_id
,
861 &attr2
->originator_id
)
862 && overlay_index_same(attr1
, attr2
)
863 && !memcmp(&attr1
->esi
, &attr2
->esi
, sizeof(esi_t
))
864 && attr1
->es_flags
== attr2
->es_flags
865 && attr1
->mm_sync_seqnum
== attr2
->mm_sync_seqnum
866 && attr1
->df_pref
== attr2
->df_pref
867 && attr1
->df_alg
== attr2
->df_alg
868 && attr1
->nh_ifindex
== attr2
->nh_ifindex
869 && attr1
->nh_lla_ifindex
== attr2
->nh_lla_ifindex
870 && attr1
->distance
== attr2
->distance
871 && srv6_l3vpn_same(attr1
->srv6_l3vpn
, attr2
->srv6_l3vpn
)
872 && srv6_vpn_same(attr1
->srv6_vpn
, attr2
->srv6_vpn
)
873 && attr1
->srte_color
== attr2
->srte_color
874 && attr1
->nh_type
== attr2
->nh_type
875 && attr1
->bh_type
== attr2
->bh_type
876 && attr1
->otc
== attr2
->otc
)
883 static void attrhash_init(void)
886 hash_create(attrhash_key_make
, attrhash_cmp
, "BGP Attributes");
890 * special for hash_clean below
892 static void attr_vfree(void *attr
)
894 XFREE(MTYPE_ATTR
, attr
);
897 static void attrhash_finish(void)
899 hash_clean(attrhash
, attr_vfree
);
904 static void attr_show_all_iterator(struct hash_bucket
*bucket
, struct vty
*vty
)
906 struct attr
*attr
= bucket
->data
;
907 struct in6_addr
*sid
= NULL
;
909 if (attr
->srv6_l3vpn
)
910 sid
= &attr
->srv6_l3vpn
->sid
;
911 else if (attr
->srv6_vpn
)
912 sid
= &attr
->srv6_vpn
->sid
;
914 vty_out(vty
, "attr[%ld] nexthop %pI4\n", attr
->refcnt
, &attr
->nexthop
);
918 " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n",
919 attr
->flag
, attr
->distance
, attr
->med
, attr
->local_pref
,
920 attr
->origin
, attr
->weight
, attr
->label
, sid
);
923 void attr_show_all(struct vty
*vty
)
925 hash_iterate(attrhash
, (void (*)(struct hash_bucket
*,
926 void *))attr_show_all_iterator
,
930 static void *bgp_attr_hash_alloc(void *p
)
932 struct attr
*val
= (struct attr
*)p
;
935 attr
= XMALLOC(MTYPE_ATTR
, sizeof(struct attr
));
937 if (val
->encap_subtlvs
) {
938 val
->encap_subtlvs
= NULL
;
940 #ifdef ENABLE_BGP_VNC
941 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
942 bgp_attr_get_vnc_subtlvs(val
);
945 bgp_attr_set_vnc_subtlvs(val
, NULL
);
952 /* Internet argument attribute. */
953 struct attr
*bgp_attr_intern(struct attr
*attr
)
956 struct ecommunity
*ecomm
= NULL
;
957 struct ecommunity
*ipv6_ecomm
= NULL
;
958 struct lcommunity
*lcomm
= NULL
;
959 struct community
*comm
= NULL
;
961 /* Intern referenced structure. */
963 if (!attr
->aspath
->refcnt
)
964 attr
->aspath
= aspath_intern(attr
->aspath
);
966 attr
->aspath
->refcnt
++;
969 comm
= bgp_attr_get_community(attr
);
972 bgp_attr_set_community(attr
, community_intern(comm
));
977 ecomm
= bgp_attr_get_ecommunity(attr
);
980 bgp_attr_set_ecommunity(attr
, ecommunity_intern(ecomm
));
985 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
987 if (!ipv6_ecomm
->refcnt
)
988 bgp_attr_set_ipv6_ecommunity(
989 attr
, ecommunity_intern(ipv6_ecomm
));
991 ipv6_ecomm
->refcnt
++;
994 lcomm
= bgp_attr_get_lcommunity(attr
);
997 bgp_attr_set_lcommunity(attr
, lcommunity_intern(lcomm
));
1002 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
1005 if (!cluster
->refcnt
)
1006 bgp_attr_set_cluster(attr
, cluster_intern(cluster
));
1011 struct transit
*transit
= bgp_attr_get_transit(attr
);
1014 if (!transit
->refcnt
)
1015 bgp_attr_set_transit(attr
, transit_intern(transit
));
1019 if (attr
->encap_subtlvs
) {
1020 if (!attr
->encap_subtlvs
->refcnt
)
1021 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
1024 attr
->encap_subtlvs
->refcnt
++;
1026 if (attr
->srv6_l3vpn
) {
1027 if (!attr
->srv6_l3vpn
->refcnt
)
1028 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
1030 attr
->srv6_l3vpn
->refcnt
++;
1032 if (attr
->srv6_vpn
) {
1033 if (!attr
->srv6_vpn
->refcnt
)
1034 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
1036 attr
->srv6_vpn
->refcnt
++;
1038 #ifdef ENABLE_BGP_VNC
1039 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1040 bgp_attr_get_vnc_subtlvs(attr
);
1043 if (!vnc_subtlvs
->refcnt
)
1044 bgp_attr_set_vnc_subtlvs(
1046 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
1048 vnc_subtlvs
->refcnt
++;
1052 /* At this point, attr only contains intern'd pointers. that means
1053 * if we find it in attrhash, it has all the same pointers and we
1054 * correctly updated the refcounts on these.
1055 * If we don't find it, we need to allocate a one because in all
1056 * cases this returns a new reference to a hashed attr, but the input
1057 * wasn't on hash. */
1058 find
= (struct attr
*)hash_get(attrhash
, attr
, bgp_attr_hash_alloc
);
1064 /* Make network statement's attribute. */
1065 struct attr
*bgp_attr_default_set(struct attr
*attr
, struct bgp
*bgp
,
1068 memset(attr
, 0, sizeof(struct attr
));
1070 attr
->origin
= origin
;
1071 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1072 attr
->aspath
= aspath_empty();
1073 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1074 attr
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1076 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
1077 attr
->label
= MPLS_INVALID_LABEL
;
1078 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1079 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1080 attr
->local_pref
= bgp
->default_local_pref
;
1085 /* Create the attributes for an aggregate */
1086 struct attr
*bgp_attr_aggregate_intern(
1087 struct bgp
*bgp
, uint8_t origin
, struct aspath
*aspath
,
1088 struct community
*community
, struct ecommunity
*ecommunity
,
1089 struct lcommunity
*lcommunity
, struct bgp_aggregate
*aggregate
,
1090 uint8_t atomic_aggregate
, const struct prefix
*p
)
1094 route_map_result_t ret
;
1096 memset(&attr
, 0, sizeof(attr
));
1098 /* Origin attribute. */
1099 attr
.origin
= origin
;
1100 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1104 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1106 /* AS path attribute. */
1108 attr
.aspath
= aspath_intern(aspath
);
1110 attr
.aspath
= aspath_empty();
1111 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1113 /* Next hop attribute. */
1114 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1117 uint32_t gshut
= COMMUNITY_GSHUT
;
1119 /* If we are not shutting down ourselves and we are
1120 * aggregating a route that contains the GSHUT community we
1121 * need to remove that community when creating the aggregate */
1122 if (!bgp_in_graceful_shutdown(bgp
)
1123 && community_include(community
, gshut
)) {
1124 community_del_val(community
, &gshut
);
1127 bgp_attr_set_community(&attr
, community
);
1131 bgp_attr_set_ecommunity(&attr
, ecommunity
);
1134 bgp_attr_set_lcommunity(&attr
, lcommunity
);
1136 if (bgp_in_graceful_shutdown(bgp
))
1137 bgp_attr_add_gshut_community(&attr
);
1139 attr
.label_index
= BGP_INVALID_LABEL_INDEX
;
1140 attr
.label
= MPLS_INVALID_LABEL
;
1141 attr
.weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1142 attr
.mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1143 if (!aggregate
->as_set
|| atomic_aggregate
)
1144 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1145 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1146 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
))
1147 attr
.aggregator_as
= bgp
->confed_id
;
1149 attr
.aggregator_as
= bgp
->as
;
1150 attr
.aggregator_addr
= bgp
->router_id
;
1152 /* Apply route-map */
1153 if (aggregate
->rmap
.name
) {
1154 struct attr attr_tmp
= attr
;
1155 struct bgp_path_info rmap_path
;
1157 memset(&rmap_path
, 0, sizeof(rmap_path
));
1158 rmap_path
.peer
= bgp
->peer_self
;
1159 rmap_path
.attr
= &attr_tmp
;
1161 SET_FLAG(bgp
->peer_self
->rmap_type
, PEER_RMAP_TYPE_AGGREGATE
);
1163 ret
= route_map_apply(aggregate
->rmap
.map
, p
, &rmap_path
);
1165 bgp
->peer_self
->rmap_type
= 0;
1167 if (ret
== RMAP_DENYMATCH
) {
1168 /* Free uninterned attribute. */
1169 bgp_attr_flush(&attr_tmp
);
1171 /* Unintern original. */
1172 aspath_unintern(&attr
.aspath
);
1176 if (bgp_in_graceful_shutdown(bgp
))
1177 bgp_attr_add_gshut_community(&attr_tmp
);
1179 new = bgp_attr_intern(&attr_tmp
);
1182 if (bgp_in_graceful_shutdown(bgp
))
1183 bgp_attr_add_gshut_community(&attr
);
1185 new = bgp_attr_intern(&attr
);
1188 /* Always release the 'intern()'ed AS Path. */
1189 aspath_unintern(&attr
.aspath
);
1194 /* Unintern just the sub-components of the attr, but not the attr */
1195 void bgp_attr_unintern_sub(struct attr
*attr
)
1197 struct ecommunity
*ecomm
= NULL
;
1198 struct ecommunity
*ipv6_ecomm
= NULL
;
1199 struct cluster_list
*cluster
;
1200 struct lcommunity
*lcomm
= NULL
;
1201 struct community
*comm
= NULL
;
1203 /* aspath refcount shoud be decrement. */
1204 aspath_unintern(&attr
->aspath
);
1205 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
));
1207 comm
= bgp_attr_get_community(attr
);
1208 community_unintern(&comm
);
1209 bgp_attr_set_community(attr
, NULL
);
1211 ecomm
= bgp_attr_get_ecommunity(attr
);
1212 ecommunity_unintern(&ecomm
);
1213 bgp_attr_set_ecommunity(attr
, NULL
);
1215 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1216 ecommunity_unintern(&ipv6_ecomm
);
1217 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1219 lcomm
= bgp_attr_get_lcommunity(attr
);
1220 lcommunity_unintern(&lcomm
);
1221 bgp_attr_set_lcommunity(attr
, NULL
);
1223 cluster
= bgp_attr_get_cluster(attr
);
1225 cluster_unintern(&cluster
);
1226 bgp_attr_set_cluster(attr
, cluster
);
1228 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
));
1230 struct transit
*transit
= bgp_attr_get_transit(attr
);
1233 transit_unintern(&transit
);
1234 bgp_attr_set_transit(attr
, transit
);
1237 if (attr
->encap_subtlvs
)
1238 encap_unintern(&attr
->encap_subtlvs
, ENCAP_SUBTLV_TYPE
);
1240 #ifdef ENABLE_BGP_VNC
1241 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1242 bgp_attr_get_vnc_subtlvs(attr
);
1245 encap_unintern(&vnc_subtlvs
, VNC_SUBTLV_TYPE
);
1246 bgp_attr_set_vnc_subtlvs(attr
, vnc_subtlvs
);
1250 if (attr
->srv6_l3vpn
)
1251 srv6_l3vpn_unintern(&attr
->srv6_l3vpn
);
1254 srv6_vpn_unintern(&attr
->srv6_vpn
);
1257 /* Free bgp attribute and aspath. */
1258 void bgp_attr_unintern(struct attr
**pattr
)
1260 struct attr
*attr
= *pattr
;
1264 /* Decrement attribute reference. */
1269 /* If reference becomes zero then free attribute object. */
1270 if (attr
->refcnt
== 0) {
1271 ret
= hash_release(attrhash
, attr
);
1272 assert(ret
!= NULL
);
1273 XFREE(MTYPE_ATTR
, attr
);
1277 bgp_attr_unintern_sub(&tmp
);
1280 void bgp_attr_flush(struct attr
*attr
)
1282 struct ecommunity
*ecomm
;
1283 struct ecommunity
*ipv6_ecomm
;
1284 struct cluster_list
*cluster
;
1285 struct lcommunity
*lcomm
;
1286 struct community
*comm
;
1288 if (attr
->aspath
&& !attr
->aspath
->refcnt
) {
1289 aspath_free(attr
->aspath
);
1290 attr
->aspath
= NULL
;
1292 comm
= bgp_attr_get_community(attr
);
1293 if (comm
&& !comm
->refcnt
)
1294 community_free(&comm
);
1295 bgp_attr_set_community(attr
, NULL
);
1297 ecomm
= bgp_attr_get_ecommunity(attr
);
1298 if (ecomm
&& !ecomm
->refcnt
)
1299 ecommunity_free(&ecomm
);
1300 bgp_attr_set_ecommunity(attr
, NULL
);
1302 ipv6_ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1303 if (ipv6_ecomm
&& !ipv6_ecomm
->refcnt
)
1304 ecommunity_free(&ipv6_ecomm
);
1305 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1307 lcomm
= bgp_attr_get_lcommunity(attr
);
1308 if (lcomm
&& !lcomm
->refcnt
)
1309 lcommunity_free(&lcomm
);
1310 bgp_attr_set_lcommunity(attr
, NULL
);
1312 cluster
= bgp_attr_get_cluster(attr
);
1313 if (cluster
&& !cluster
->refcnt
) {
1314 cluster_free(cluster
);
1315 bgp_attr_set_cluster(attr
, NULL
);
1318 struct transit
*transit
= bgp_attr_get_transit(attr
);
1320 if (transit
&& !transit
->refcnt
) {
1321 transit_free(transit
);
1322 bgp_attr_set_transit(attr
, NULL
);
1324 if (attr
->encap_subtlvs
&& !attr
->encap_subtlvs
->refcnt
) {
1325 encap_free(attr
->encap_subtlvs
);
1326 attr
->encap_subtlvs
= NULL
;
1328 if (attr
->srv6_l3vpn
&& !attr
->srv6_l3vpn
->refcnt
) {
1329 srv6_l3vpn_free(attr
->srv6_l3vpn
);
1330 attr
->srv6_l3vpn
= NULL
;
1332 if (attr
->srv6_vpn
&& !attr
->srv6_vpn
->refcnt
) {
1333 srv6_vpn_free(attr
->srv6_vpn
);
1334 attr
->srv6_vpn
= NULL
;
1336 #ifdef ENABLE_BGP_VNC
1337 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1338 bgp_attr_get_vnc_subtlvs(attr
);
1340 if (vnc_subtlvs
&& !vnc_subtlvs
->refcnt
) {
1341 encap_free(vnc_subtlvs
);
1342 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
1347 /* Implement draft-scudder-idr-optional-transitive behaviour and
1348 * avoid resetting sessions for malformed attributes which are
1349 * are partial/optional and hence where the error likely was not
1350 * introduced by the sending neighbour.
1352 static enum bgp_attr_parse_ret
1353 bgp_attr_malformed(struct bgp_attr_parser_args
*args
, uint8_t subcode
,
1356 struct peer
*const peer
= args
->peer
;
1357 struct attr
*const attr
= args
->attr
;
1358 const uint8_t flags
= args
->flags
;
1359 /* startp and length must be special-cased, as whether or not to
1360 * send the attribute data with the NOTIFY depends on the error,
1361 * the caller therefore signals this with the seperate length argument
1363 uint8_t *notify_datap
= (length
> 0 ? args
->startp
: NULL
);
1365 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1366 char attr_str
[BUFSIZ
] = {0};
1368 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1370 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1373 /* Only relax error handling for eBGP peers */
1374 if (peer
->sort
!= BGP_PEER_EBGP
) {
1375 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1376 notify_datap
, length
);
1377 return BGP_ATTR_PARSE_ERROR
;
1380 /* Adjust the stream getp to the end of the attribute, in case we can
1381 * still proceed but the caller hasn't read all the attribute.
1383 stream_set_getp(BGP_INPUT(peer
),
1384 (args
->startp
- STREAM_DATA(BGP_INPUT(peer
)))
1387 switch (args
->type
) {
1388 /* where an attribute is relatively inconsequential, e.g. it does not
1389 * affect route selection, and can be safely ignored, then any such
1390 * attributes which are malformed should just be ignored and the route
1391 * processed as normal.
1393 case BGP_ATTR_AS4_AGGREGATOR
:
1394 case BGP_ATTR_AGGREGATOR
:
1395 case BGP_ATTR_ATOMIC_AGGREGATE
:
1396 return BGP_ATTR_PARSE_PROCEED
;
1398 /* Core attributes, particularly ones which may influence route
1399 * selection, should be treat-as-withdraw.
1401 case BGP_ATTR_ORIGIN
:
1402 case BGP_ATTR_AS_PATH
:
1403 case BGP_ATTR_NEXT_HOP
:
1404 case BGP_ATTR_MULTI_EXIT_DISC
:
1405 case BGP_ATTR_LOCAL_PREF
:
1406 case BGP_ATTR_COMMUNITIES
:
1407 case BGP_ATTR_EXT_COMMUNITIES
:
1408 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
1409 case BGP_ATTR_LARGE_COMMUNITIES
:
1410 case BGP_ATTR_ORIGINATOR_ID
:
1411 case BGP_ATTR_CLUSTER_LIST
:
1413 return BGP_ATTR_PARSE_WITHDRAW
;
1414 case BGP_ATTR_MP_REACH_NLRI
:
1415 case BGP_ATTR_MP_UNREACH_NLRI
:
1416 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1417 notify_datap
, length
);
1418 return BGP_ATTR_PARSE_ERROR
;
1421 /* Partial optional attributes that are malformed should not cause
1422 * the whole session to be reset. Instead treat it as a withdrawal
1423 * of the routes, if possible.
1425 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)
1426 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1427 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
))
1428 return BGP_ATTR_PARSE_WITHDRAW
;
1430 /* default to reset */
1431 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1434 /* Find out what is wrong with the path attribute flag bits and log the error.
1435 "Flag bits" here stand for Optional, Transitive and Partial, but not for
1436 Extended Length. Checking O/T/P bits at once implies, that the attribute
1437 being diagnosed is defined by RFC as either a "well-known" or an "optional,
1438 non-transitive" attribute. */
1440 bgp_attr_flags_diagnose(struct bgp_attr_parser_args
*args
,
1441 uint8_t desired_flags
/* how RFC says it must be */
1444 uint8_t seen
= 0, i
;
1445 uint8_t real_flags
= args
->flags
;
1446 const uint8_t attr_code
= args
->type
;
1448 desired_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1449 real_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1450 for (i
= 0; i
<= 2; i
++) /* O,T,P, but not E */
1451 if (CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1452 != CHECK_FLAG(real_flags
, attr_flag_str
[i
].key
)) {
1453 flog_err(EC_BGP_ATTR_FLAG
,
1454 "%s attribute must%s be flagged as \"%s\"",
1455 lookup_msg(attr_str
, attr_code
, NULL
),
1456 CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1459 attr_flag_str
[i
].str
);
1464 "Strange, %s called for attr %s, but no problem found with flags (real flags 0x%x, desired 0x%x)",
1465 __func__
, lookup_msg(attr_str
, attr_code
, NULL
),
1466 real_flags
, desired_flags
);
1470 /* Required flags for attributes. EXTLEN will be masked off when testing,
1471 * as will PARTIAL for optional+transitive attributes.
1473 const uint8_t attr_flags_values
[] = {
1474 [BGP_ATTR_ORIGIN
] = BGP_ATTR_FLAG_TRANS
,
1475 [BGP_ATTR_AS_PATH
] = BGP_ATTR_FLAG_TRANS
,
1476 [BGP_ATTR_NEXT_HOP
] = BGP_ATTR_FLAG_TRANS
,
1477 [BGP_ATTR_MULTI_EXIT_DISC
] = BGP_ATTR_FLAG_OPTIONAL
,
1478 [BGP_ATTR_LOCAL_PREF
] = BGP_ATTR_FLAG_TRANS
,
1479 [BGP_ATTR_ATOMIC_AGGREGATE
] = BGP_ATTR_FLAG_TRANS
,
1480 [BGP_ATTR_AGGREGATOR
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1481 [BGP_ATTR_COMMUNITIES
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1482 [BGP_ATTR_ORIGINATOR_ID
] = BGP_ATTR_FLAG_OPTIONAL
,
1483 [BGP_ATTR_CLUSTER_LIST
] = BGP_ATTR_FLAG_OPTIONAL
,
1484 [BGP_ATTR_MP_REACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1485 [BGP_ATTR_MP_UNREACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1486 [BGP_ATTR_EXT_COMMUNITIES
] =
1487 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1488 [BGP_ATTR_AS4_PATH
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1489 [BGP_ATTR_AS4_AGGREGATOR
] =
1490 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1491 [BGP_ATTR_PMSI_TUNNEL
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1492 [BGP_ATTR_LARGE_COMMUNITIES
] =
1493 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1494 [BGP_ATTR_OTC
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1495 [BGP_ATTR_PREFIX_SID
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1496 [BGP_ATTR_IPV6_EXT_COMMUNITIES
] =
1497 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1498 [BGP_ATTR_AIGP
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1500 static const size_t attr_flags_values_max
= array_size(attr_flags_values
) - 1;
1502 static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args
*args
)
1504 uint8_t mask
= BGP_ATTR_FLAG_EXTLEN
;
1505 const uint8_t flags
= args
->flags
;
1506 const uint8_t attr_code
= args
->type
;
1508 /* there may be attributes we don't know about */
1509 if (attr_code
> attr_flags_values_max
)
1511 if (attr_flags_values
[attr_code
] == 0)
1514 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set
1518 if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL
, flags
)
1519 && !CHECK_FLAG(BGP_ATTR_FLAG_TRANS
, flags
)) {
1522 "%s well-known attributes must have transitive flag set (%x)",
1523 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1527 /* "For well-known attributes and for optional non-transitive
1529 * the Partial bit MUST be set to 0."
1531 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
)) {
1532 if (!CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)) {
1533 flog_err(EC_BGP_ATTR_FLAG
,
1534 "%s well-known attribute must NOT have the partial flag set (%x)",
1535 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1538 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1539 && !CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)) {
1540 flog_err(EC_BGP_ATTR_FLAG
,
1541 "%s optional + transitive attribute must NOT have the partial flag set (%x)",
1542 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1547 /* Optional transitive attributes may go through speakers that don't
1548 * reocgnise them and set the Partial bit.
1550 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1551 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
))
1552 SET_FLAG(mask
, BGP_ATTR_FLAG_PARTIAL
);
1554 if ((flags
& ~mask
) == attr_flags_values
[attr_code
])
1557 bgp_attr_flags_diagnose(args
, attr_flags_values
[attr_code
]);
1561 /* Get origin attribute of the update message. */
1562 static enum bgp_attr_parse_ret
1563 bgp_attr_origin(struct bgp_attr_parser_args
*args
)
1565 struct peer
*const peer
= args
->peer
;
1566 struct attr
*const attr
= args
->attr
;
1567 const bgp_size_t length
= args
->length
;
1569 /* If any recognized attribute has Attribute Length that conflicts
1570 with the expected length (based on the attribute type code), then
1571 the Error Subcode is set to Attribute Length Error. The Data
1572 field contains the erroneous attribute (type, length and
1575 flog_err(EC_BGP_ATTR_LEN
,
1576 "Origin attribute length is not one %d", length
);
1577 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1581 /* Fetch origin attribute. */
1582 attr
->origin
= stream_getc(BGP_INPUT(peer
));
1584 /* If the ORIGIN attribute has an undefined value, then the Error
1585 Subcode is set to Invalid Origin Attribute. The Data field
1586 contains the unrecognized attribute (type, length and value). */
1587 if ((attr
->origin
!= BGP_ORIGIN_IGP
) && (attr
->origin
!= BGP_ORIGIN_EGP
)
1588 && (attr
->origin
!= BGP_ORIGIN_INCOMPLETE
)) {
1589 flog_err(EC_BGP_ATTR_ORIGIN
,
1590 "Origin attribute value is invalid %d", attr
->origin
);
1591 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_INVAL_ORIGIN
,
1595 /* Set oring attribute flag. */
1596 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1601 /* Parse AS path information. This function is wrapper of
1603 static int bgp_attr_aspath(struct bgp_attr_parser_args
*args
)
1605 struct attr
*const attr
= args
->attr
;
1606 struct peer
*const peer
= args
->peer
;
1607 const bgp_size_t length
= args
->length
;
1610 * peer with AS4 => will get 4Byte ASnums
1611 * otherwise, will get 16 Bit
1613 attr
->aspath
= aspath_parse(
1615 CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1616 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
));
1618 /* In case of IBGP, length will be zero. */
1619 if (!attr
->aspath
) {
1620 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1621 "Malformed AS path from %s, length is %d", peer
->host
,
1623 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1627 /* Conformant BGP speakers SHOULD NOT send BGP
1628 * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1629 * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1630 * withdraw" error handling behavior as per [RFC7606].
1632 if (peer
->bgp
->reject_as_sets
&& aspath_check_as_sets(attr
->aspath
)) {
1633 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1634 "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1636 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1640 /* Set aspath attribute flag. */
1641 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1643 return BGP_ATTR_PARSE_PROCEED
;
1646 static enum bgp_attr_parse_ret
bgp_attr_aspath_check(struct peer
*const peer
,
1647 struct attr
*const attr
)
1649 /* These checks were part of bgp_attr_aspath, but with
1650 * as4 we should to check aspath things when
1651 * aspath synthesizing with as4_path has already taken place.
1652 * Otherwise we check ASPATH and use the synthesized thing, and that is
1654 * So do the checks later, i.e. here
1656 struct aspath
*aspath
;
1658 /* Confederation sanity check. */
1659 if ((peer
->sort
== BGP_PEER_CONFED
1660 && !aspath_left_confed_check(attr
->aspath
))
1661 || (peer
->sort
== BGP_PEER_EBGP
1662 && aspath_confed_check(attr
->aspath
))) {
1663 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "Malformed AS path from %s",
1665 return BGP_ATTR_PARSE_WITHDRAW
;
1668 /* First AS check for EBGP. */
1669 if (CHECK_FLAG(peer
->flags
, PEER_FLAG_ENFORCE_FIRST_AS
)) {
1670 if (peer
->sort
== BGP_PEER_EBGP
1671 && !aspath_firstas_check(attr
->aspath
, peer
->as
)) {
1672 flog_err(EC_BGP_ATTR_FIRST_AS
,
1673 "%s incorrect first AS (must be %u)",
1674 peer
->host
, peer
->as
);
1675 return BGP_ATTR_PARSE_WITHDRAW
;
1679 /* Codification of AS 0 Processing */
1680 if (peer
->sort
== BGP_PEER_EBGP
&& aspath_check_as_zero(attr
->aspath
)) {
1682 EC_BGP_ATTR_MAL_AS_PATH
,
1683 "Malformed AS path, AS number is 0 in the path from %s",
1685 return BGP_ATTR_PARSE_WITHDRAW
;
1688 /* local-as prepend */
1689 if (peer
->change_local_as
1690 && !CHECK_FLAG(peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
)) {
1691 aspath
= aspath_dup(attr
->aspath
);
1692 aspath
= aspath_add_seq(aspath
, peer
->change_local_as
);
1693 aspath_unintern(&attr
->aspath
);
1694 attr
->aspath
= aspath_intern(aspath
);
1697 return BGP_ATTR_PARSE_PROCEED
;
1700 /* Parse AS4 path information. This function is another wrapper of
1702 static int bgp_attr_as4_path(struct bgp_attr_parser_args
*args
,
1703 struct aspath
**as4_path
)
1705 struct peer
*const peer
= args
->peer
;
1706 struct attr
*const attr
= args
->attr
;
1707 const bgp_size_t length
= args
->length
;
1709 *as4_path
= aspath_parse(peer
->curr
, length
, 1);
1711 /* In case of IBGP, length will be zero. */
1713 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1714 "Malformed AS4 path from %s, length is %d", peer
->host
,
1716 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1720 /* Conformant BGP speakers SHOULD NOT send BGP
1721 * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1722 * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1723 * withdraw" error handling behavior as per [RFC7606].
1725 if (peer
->bgp
->reject_as_sets
&& aspath_check_as_sets(attr
->aspath
)) {
1726 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1727 "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1729 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1733 /* Set aspath attribute flag. */
1734 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
);
1736 return BGP_ATTR_PARSE_PROCEED
;
1740 * Check that the nexthop attribute is valid.
1742 enum bgp_attr_parse_ret
bgp_attr_nexthop_valid(struct peer
*peer
,
1745 struct bgp
*bgp
= peer
->bgp
;
1747 if (ipv4_martian(&attr
->nexthop
) && !bgp
->allow_martian
) {
1748 uint8_t data
[7]; /* type(2) + length(1) + nhop(4) */
1750 flog_err(EC_BGP_ATTR_MARTIAN_NH
, "Martian nexthop %pI4",
1752 data
[0] = BGP_ATTR_FLAG_TRANS
;
1753 data
[1] = BGP_ATTR_NEXT_HOP
;
1754 data
[2] = BGP_ATTR_NHLEN_IPV4
;
1755 memcpy(&data
[3], &attr
->nexthop
.s_addr
, BGP_ATTR_NHLEN_IPV4
);
1756 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
1757 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1759 return BGP_ATTR_PARSE_ERROR
;
1762 return BGP_ATTR_PARSE_PROCEED
;
1765 /* Nexthop attribute. */
1766 static enum bgp_attr_parse_ret
1767 bgp_attr_nexthop(struct bgp_attr_parser_args
*args
)
1769 struct peer
*const peer
= args
->peer
;
1770 struct attr
*const attr
= args
->attr
;
1771 const bgp_size_t length
= args
->length
;
1773 /* Check nexthop attribute length. */
1775 flog_err(EC_BGP_ATTR_LEN
,
1776 "Nexthop attribute length isn't four [%d]", length
);
1778 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1782 attr
->nexthop
.s_addr
= stream_get_ipv4(peer
->curr
);
1783 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1785 return BGP_ATTR_PARSE_PROCEED
;
1788 /* MED atrribute. */
1789 static enum bgp_attr_parse_ret
bgp_attr_med(struct bgp_attr_parser_args
*args
)
1791 struct peer
*const peer
= args
->peer
;
1792 struct attr
*const attr
= args
->attr
;
1793 const bgp_size_t length
= args
->length
;
1797 flog_err(EC_BGP_ATTR_LEN
,
1798 "MED attribute length isn't four [%d]", length
);
1800 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1804 attr
->med
= stream_getl(peer
->curr
);
1806 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1808 return BGP_ATTR_PARSE_PROCEED
;
1811 /* Local preference attribute. */
1812 static enum bgp_attr_parse_ret
1813 bgp_attr_local_pref(struct bgp_attr_parser_args
*args
)
1815 struct peer
*const peer
= args
->peer
;
1816 struct attr
*const attr
= args
->attr
;
1817 const bgp_size_t length
= args
->length
;
1819 /* if received from an internal neighbor, it SHALL be considered
1820 * malformed if its length is not equal to 4. If malformed, the
1821 * UPDATE message SHALL be handled using the approach of "treat-as-
1824 if (peer
->sort
== BGP_PEER_IBGP
&& length
!= 4) {
1825 flog_err(EC_BGP_ATTR_LEN
,
1826 "LOCAL_PREF attribute length isn't 4 [%u]", length
);
1827 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1831 /* If it is contained in an UPDATE message that is received from an
1832 external peer, then this attribute MUST be ignored by the
1833 receiving speaker. */
1834 if (peer
->sort
== BGP_PEER_EBGP
) {
1835 STREAM_FORWARD_GETP(peer
->curr
, length
);
1836 return BGP_ATTR_PARSE_PROCEED
;
1839 STREAM_GETL(peer
->curr
, attr
->local_pref
);
1841 /* Set the local-pref flag. */
1842 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
1844 return BGP_ATTR_PARSE_PROCEED
;
1847 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1851 /* Atomic aggregate. */
1852 static int bgp_attr_atomic(struct bgp_attr_parser_args
*args
)
1854 struct peer
*const peer
= args
->peer
;
1855 struct attr
*const attr
= args
->attr
;
1856 const bgp_size_t length
= args
->length
;
1860 flog_err(EC_BGP_ATTR_LEN
,
1861 "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1863 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1867 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
1870 /* Set atomic aggregate flag. */
1871 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1873 return BGP_ATTR_PARSE_PROCEED
;
1876 stream_forward_getp(peer
->curr
, length
);
1878 return bgp_attr_ignore(peer
, args
->type
);
1881 /* Aggregator attribute */
1882 static int bgp_attr_aggregator(struct bgp_attr_parser_args
*args
)
1884 struct peer
*const peer
= args
->peer
;
1885 struct attr
*const attr
= args
->attr
;
1886 const bgp_size_t length
= args
->length
;
1891 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1892 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1893 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
))
1896 if (length
!= wantedlen
) {
1897 flog_err(EC_BGP_ATTR_LEN
,
1898 "AGGREGATOR attribute length isn't %u [%u]", wantedlen
,
1900 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1904 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
1905 goto aggregator_ignore
;
1907 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
))
1908 aggregator_as
= stream_getl(peer
->curr
);
1910 aggregator_as
= stream_getw(peer
->curr
);
1912 attr
->aggregator_as
= aggregator_as
;
1913 attr
->aggregator_addr
.s_addr
= stream_get_ipv4(peer
->curr
);
1915 /* Codification of AS 0 Processing */
1916 if (aggregator_as
== BGP_AS_ZERO
) {
1917 flog_err(EC_BGP_ATTR_LEN
,
1918 "%s: AGGREGATOR AS number is 0 for aspath: %s",
1919 peer
->host
, aspath_print(attr
->aspath
));
1921 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1922 char attr_str
[BUFSIZ
] = {0};
1924 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1926 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1929 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1932 return BGP_ATTR_PARSE_PROCEED
;
1935 stream_forward_getp(peer
->curr
, length
);
1937 return bgp_attr_ignore(peer
, args
->type
);
1940 /* New Aggregator attribute */
1941 static enum bgp_attr_parse_ret
1942 bgp_attr_as4_aggregator(struct bgp_attr_parser_args
*args
,
1943 as_t
*as4_aggregator_as
,
1944 struct in_addr
*as4_aggregator_addr
)
1946 struct peer
*const peer
= args
->peer
;
1947 struct attr
*const attr
= args
->attr
;
1948 const bgp_size_t length
= args
->length
;
1952 flog_err(EC_BGP_ATTR_LEN
, "New Aggregator length is not 8 [%d]",
1954 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1958 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
1959 goto as4_aggregator_ignore
;
1961 aggregator_as
= stream_getl(peer
->curr
);
1963 *as4_aggregator_as
= aggregator_as
;
1964 as4_aggregator_addr
->s_addr
= stream_get_ipv4(peer
->curr
);
1966 /* Codification of AS 0 Processing */
1967 if (aggregator_as
== BGP_AS_ZERO
) {
1968 flog_err(EC_BGP_ATTR_LEN
,
1969 "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
1970 peer
->host
, aspath_print(attr
->aspath
));
1972 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1973 char attr_str
[BUFSIZ
] = {0};
1975 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1977 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1980 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
);
1983 return BGP_ATTR_PARSE_PROCEED
;
1985 as4_aggregator_ignore
:
1986 stream_forward_getp(peer
->curr
, length
);
1988 return bgp_attr_ignore(peer
, args
->type
);
1991 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1993 static enum bgp_attr_parse_ret
1994 bgp_attr_munge_as4_attrs(struct peer
*const peer
, struct attr
*const attr
,
1995 struct aspath
*as4_path
, as_t as4_aggregator
,
1996 struct in_addr
*as4_aggregator_addr
)
1998 int ignore_as4_path
= 0;
1999 struct aspath
*newpath
;
2001 if (!attr
->aspath
) {
2002 /* NULL aspath shouldn't be possible as bgp_attr_parse should
2004 * checked that all well-known, mandatory attributes were
2007 * Can only be a problem with peer itself - hard error
2009 return BGP_ATTR_PARSE_ERROR
;
2012 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
2013 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
2015 * It is worth a warning though, because the peer really
2016 * should not send them
2018 if (BGP_DEBUG(as4
, AS4
)) {
2019 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
2020 zlog_debug("[AS4] %s %s AS4_PATH", peer
->host
,
2021 "AS4 capable peer, yet it sent");
2024 & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
2025 zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
2027 "AS4 capable peer, yet it sent");
2030 return BGP_ATTR_PARSE_PROCEED
;
2033 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
2034 * because that may override AS4_PATH
2036 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
))) {
2037 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
))) {
2039 * if the as_number in aggregator is not AS_TRANS,
2040 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
2041 * and the Aggregator shall be taken as
2042 * info on the aggregating node, and the AS_PATH
2043 * shall be taken as the AS_PATH
2045 * the Aggregator shall be ignored and the
2046 * AS4_AGGREGATOR shall be taken as the
2047 * Aggregating node and the AS_PATH is to be
2048 * constructed "as in all other cases"
2050 if (attr
->aggregator_as
!= BGP_AS_TRANS
) {
2052 if (BGP_DEBUG(as4
, AS4
))
2054 "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
2056 ignore_as4_path
= 1;
2058 /* "New_aggregator shall be taken as aggregator"
2060 attr
->aggregator_as
= as4_aggregator
;
2061 attr
->aggregator_addr
.s_addr
=
2062 as4_aggregator_addr
->s_addr
;
2065 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
2066 * That is bogus - but reading the conditions
2067 * we have to handle AS4_AGGREGATOR as if it were
2068 * AGGREGATOR in that case
2070 if (BGP_DEBUG(as4
, AS4
))
2072 "[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",
2074 attr
->aggregator_as
= as4_aggregator
;
2075 /* sweep it under the carpet and simulate a "good"
2077 attr
->flag
|= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
));
2081 /* need to reconcile NEW_AS_PATH and AS_PATH */
2082 if (!ignore_as4_path
2083 && (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))) {
2084 newpath
= aspath_reconcile_as4(attr
->aspath
, as4_path
);
2086 return BGP_ATTR_PARSE_ERROR
;
2088 aspath_unintern(&attr
->aspath
);
2089 attr
->aspath
= aspath_intern(newpath
);
2091 return BGP_ATTR_PARSE_PROCEED
;
2094 /* Community attribute. */
2095 static enum bgp_attr_parse_ret
2096 bgp_attr_community(struct bgp_attr_parser_args
*args
)
2098 struct peer
*const peer
= args
->peer
;
2099 struct attr
*const attr
= args
->attr
;
2100 const bgp_size_t length
= args
->length
;
2103 bgp_attr_set_community(attr
, NULL
);
2104 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2108 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2109 goto community_ignore
;
2111 bgp_attr_set_community(
2113 community_parse((uint32_t *)stream_pnt(peer
->curr
), length
));
2115 /* XXX: fix community_parse to use stream API and remove this */
2116 stream_forward_getp(peer
->curr
, length
);
2118 /* The Community attribute SHALL be considered malformed if its
2119 * length is not a non-zero multiple of 4.
2121 if (!bgp_attr_get_community(attr
))
2122 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2125 return BGP_ATTR_PARSE_PROCEED
;
2128 stream_forward_getp(peer
->curr
, length
);
2130 return bgp_attr_ignore(peer
, args
->type
);
2133 /* Originator ID attribute. */
2134 static enum bgp_attr_parse_ret
2135 bgp_attr_originator_id(struct bgp_attr_parser_args
*args
)
2137 struct peer
*const peer
= args
->peer
;
2138 struct attr
*const attr
= args
->attr
;
2139 const bgp_size_t length
= args
->length
;
2141 /* if received from an internal neighbor, it SHALL be considered
2142 * malformed if its length is not equal to 4. If malformed, the
2143 * UPDATE message SHALL be handled using the approach of "treat-as-
2147 flog_err(EC_BGP_ATTR_LEN
, "Bad originator ID length %d",
2150 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2154 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2155 goto originator_id_ignore
;
2157 attr
->originator_id
.s_addr
= stream_get_ipv4(peer
->curr
);
2159 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
2161 return BGP_ATTR_PARSE_PROCEED
;
2163 originator_id_ignore
:
2164 stream_forward_getp(peer
->curr
, length
);
2166 return bgp_attr_ignore(peer
, args
->type
);
2169 /* Cluster list attribute. */
2170 static enum bgp_attr_parse_ret
2171 bgp_attr_cluster_list(struct bgp_attr_parser_args
*args
)
2173 struct peer
*const peer
= args
->peer
;
2174 struct attr
*const attr
= args
->attr
;
2175 const bgp_size_t length
= args
->length
;
2177 /* if received from an internal neighbor, it SHALL be considered
2178 * malformed if its length is not a non-zero multiple of 4. If
2179 * malformed, the UPDATE message SHALL be handled using the approach
2180 * of "treat-as-withdraw".
2182 if (length
== 0 || length
% 4) {
2183 flog_err(EC_BGP_ATTR_LEN
, "Bad cluster list length %d", length
);
2185 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2189 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2190 goto cluster_list_ignore
;
2192 bgp_attr_set_cluster(
2193 attr
, cluster_parse((struct in_addr
*)stream_pnt(peer
->curr
),
2196 /* XXX: Fix cluster_parse to use stream API and then remove this */
2197 stream_forward_getp(peer
->curr
, length
);
2199 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
);
2201 return BGP_ATTR_PARSE_PROCEED
;
2203 cluster_list_ignore
:
2204 stream_forward_getp(peer
->curr
, length
);
2206 return bgp_attr_ignore(peer
, args
->type
);
2209 /* Multiprotocol reachability information parse. */
2210 int bgp_mp_reach_parse(struct bgp_attr_parser_args
*args
,
2211 struct bgp_nlri
*mp_update
)
2215 iana_safi_t pkt_safi
;
2217 bgp_size_t nlri_len
;
2220 struct peer
*const peer
= args
->peer
;
2221 struct attr
*const attr
= args
->attr
;
2222 const bgp_size_t length
= args
->length
;
2224 /* Set end of packet. */
2225 s
= BGP_INPUT(peer
);
2226 start
= stream_get_getp(s
);
2228 /* safe to read statically sized header? */
2229 #define BGP_MP_REACH_MIN_SIZE 5
2230 #define LEN_LEFT (length - (stream_get_getp(s) - start))
2231 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
)) {
2232 zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
2233 __func__
, peer
->host
, (unsigned long)length
);
2234 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2237 /* Load AFI, SAFI. */
2238 pkt_afi
= stream_getw(s
);
2239 pkt_safi
= stream_getc(s
);
2241 /* Convert AFI, SAFI to internal values, check. */
2242 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2243 /* Log if AFI or SAFI is unrecognized. This is not an error
2245 * the attribute is otherwise malformed.
2247 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2249 "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
2250 peer
->host
, iana_afi2str(pkt_afi
),
2251 iana_safi2str(pkt_safi
));
2252 return BGP_ATTR_PARSE_ERROR
;
2255 /* Get nexthop length. */
2256 attr
->mp_nexthop_len
= stream_getc(s
);
2258 if (LEN_LEFT
< attr
->mp_nexthop_len
) {
2260 "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
2261 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2262 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2265 /* Nexthop length check. */
2266 switch (attr
->mp_nexthop_len
) {
2268 if (safi
!= SAFI_FLOWSPEC
) {
2269 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2270 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2271 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2274 case BGP_ATTR_NHLEN_VPNV4
:
2275 stream_getl(s
); /* RD high */
2276 stream_getl(s
); /* RD low */
2278 * NOTE: intentional fall through
2279 * - for consistency in rx processing
2281 * The following comment is to signal GCC this intention
2282 * and suppress the warning
2285 case BGP_ATTR_NHLEN_IPV4
:
2286 stream_get(&attr
->mp_nexthop_global_in
, s
, IPV4_MAX_BYTELEN
);
2287 /* Probably needed for RFC 2283 */
2288 if (attr
->nexthop
.s_addr
== INADDR_ANY
)
2289 memcpy(&attr
->nexthop
.s_addr
,
2290 &attr
->mp_nexthop_global_in
, IPV4_MAX_BYTELEN
);
2292 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
2293 case BGP_ATTR_NHLEN_VPNV6_GLOBAL
:
2294 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL
) {
2295 stream_getl(s
); /* RD high */
2296 stream_getl(s
); /* RD low */
2298 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2299 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2300 if (!peer
->nexthop
.ifp
) {
2301 zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2303 return BGP_ATTR_PARSE_WITHDRAW
;
2305 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2308 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
2309 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
:
2310 if (attr
->mp_nexthop_len
2311 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2312 stream_getl(s
); /* RD high */
2313 stream_getl(s
); /* RD low */
2315 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2316 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2317 if (!peer
->nexthop
.ifp
) {
2318 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",
2320 return BGP_ATTR_PARSE_WITHDRAW
;
2322 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2324 if (attr
->mp_nexthop_len
2325 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2326 stream_getl(s
); /* RD high */
2327 stream_getl(s
); /* RD low */
2329 stream_get(&attr
->mp_nexthop_local
, s
, IPV6_MAX_BYTELEN
);
2330 if (!IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_local
)) {
2331 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2333 "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
2334 peer
->host
, &attr
->mp_nexthop_global
,
2335 &attr
->mp_nexthop_local
);
2337 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
2339 if (!peer
->nexthop
.ifp
) {
2340 zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
2342 return BGP_ATTR_PARSE_WITHDRAW
;
2344 attr
->nh_lla_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2347 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2348 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2349 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2353 zlog_info("%s: %s sent SNPA which couldn't be read",
2354 __func__
, peer
->host
);
2355 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2360 if ((val
= stream_getc(s
)))
2362 EC_BGP_DEFUNCT_SNPA_LEN
,
2363 "%s sent non-zero value, %u, for defunct SNPA-length field",
2367 /* must have nrli_len, what is left of the attribute */
2368 nlri_len
= LEN_LEFT
;
2369 if (nlri_len
> STREAM_READABLE(s
)) {
2370 zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
2371 __func__
, peer
->host
);
2372 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2376 zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
2377 __func__
, peer
->host
);
2379 mp_update
->afi
= afi
;
2380 mp_update
->safi
= safi
;
2381 return BGP_ATTR_PARSE_EOR
;
2384 mp_update
->afi
= afi
;
2385 mp_update
->safi
= safi
;
2386 mp_update
->nlri
= stream_pnt(s
);
2387 mp_update
->length
= nlri_len
;
2389 stream_forward_getp(s
, nlri_len
);
2391 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
);
2393 return BGP_ATTR_PARSE_PROCEED
;
2397 /* Multiprotocol unreachable parse */
2398 int bgp_mp_unreach_parse(struct bgp_attr_parser_args
*args
,
2399 struct bgp_nlri
*mp_withdraw
)
2404 iana_safi_t pkt_safi
;
2406 uint16_t withdraw_len
;
2407 struct peer
*const peer
= args
->peer
;
2408 struct attr
*const attr
= args
->attr
;
2409 const bgp_size_t length
= args
->length
;
2413 #define BGP_MP_UNREACH_MIN_SIZE 3
2414 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
2415 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2417 pkt_afi
= stream_getw(s
);
2418 pkt_safi
= stream_getc(s
);
2420 /* Convert AFI, SAFI to internal values, check. */
2421 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2422 /* Log if AFI or SAFI is unrecognized. This is not an error
2424 * the attribute is otherwise malformed.
2426 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2428 "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
2429 peer
->host
, iana_afi2str(pkt_afi
),
2430 iana_safi2str(pkt_safi
));
2431 return BGP_ATTR_PARSE_ERROR
;
2434 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
2436 mp_withdraw
->afi
= afi
;
2437 mp_withdraw
->safi
= safi
;
2438 mp_withdraw
->nlri
= stream_pnt(s
);
2439 mp_withdraw
->length
= withdraw_len
;
2441 stream_forward_getp(s
, withdraw_len
);
2443 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
);
2445 return BGP_ATTR_PARSE_PROCEED
;
2448 /* Large Community attribute. */
2449 static enum bgp_attr_parse_ret
2450 bgp_attr_large_community(struct bgp_attr_parser_args
*args
)
2452 struct peer
*const peer
= args
->peer
;
2453 struct attr
*const attr
= args
->attr
;
2454 const bgp_size_t length
= args
->length
;
2457 * Large community follows new attribute format.
2460 bgp_attr_set_lcommunity(attr
, NULL
);
2461 /* Empty extcomm doesn't seem to be invalid per se */
2462 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2466 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2467 goto large_community_ignore
;
2469 bgp_attr_set_lcommunity(
2470 attr
, lcommunity_parse(stream_pnt(peer
->curr
), length
));
2471 /* XXX: fix ecommunity_parse to use stream API */
2472 stream_forward_getp(peer
->curr
, length
);
2474 if (!bgp_attr_get_lcommunity(attr
))
2475 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2478 return BGP_ATTR_PARSE_PROCEED
;
2480 large_community_ignore
:
2481 stream_forward_getp(peer
->curr
, length
);
2483 return bgp_attr_ignore(peer
, args
->type
);
2486 /* Extended Community attribute. */
2487 static enum bgp_attr_parse_ret
2488 bgp_attr_ext_communities(struct bgp_attr_parser_args
*args
)
2490 struct peer
*const peer
= args
->peer
;
2491 struct attr
*const attr
= args
->attr
;
2492 const bgp_size_t length
= args
->length
;
2495 struct ecommunity
*ecomm
;
2498 bgp_attr_set_ecommunity(attr
, NULL
);
2499 /* Empty extcomm doesn't seem to be invalid per se */
2500 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2504 ecomm
= ecommunity_parse(
2505 stream_pnt(peer
->curr
), length
,
2506 CHECK_FLAG(peer
->flags
,
2507 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2508 bgp_attr_set_ecommunity(attr
, ecomm
);
2509 /* XXX: fix ecommunity_parse to use stream API */
2510 stream_forward_getp(peer
->curr
, length
);
2512 /* The Extended Community attribute SHALL be considered malformed if
2513 * its length is not a non-zero multiple of 8.
2515 if (!bgp_attr_get_ecommunity(attr
))
2516 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2519 /* Extract DF election preference and mobility sequence number */
2520 attr
->df_pref
= bgp_attr_df_pref_from_ec(attr
, &attr
->df_alg
);
2522 /* Extract MAC mobility sequence number, if any. */
2523 attr
->mm_seqnum
= bgp_attr_mac_mobility_seqnum(attr
, &sticky
);
2524 attr
->sticky
= sticky
;
2526 /* Check if this is a Gateway MAC-IP advertisement */
2527 attr
->default_gw
= bgp_attr_default_gw(attr
);
2529 /* Handle scenario where router flag ecommunity is not
2530 * set but default gw ext community is present.
2531 * Use default gateway, set and propogate R-bit.
2533 if (attr
->default_gw
)
2534 attr
->router_flag
= 1;
2536 /* Check EVPN Neighbor advertisement flags, R-bit */
2537 bgp_attr_evpn_na_flag(attr
, &attr
->router_flag
, &proxy
);
2539 attr
->es_flags
|= ATTR_ES_PROXY_ADVERT
;
2541 /* Extract the Rmac, if any */
2542 if (bgp_attr_rmac(attr
, &attr
->rmac
)) {
2543 if (bgp_debug_update(peer
, NULL
, NULL
, 1)
2544 && bgp_mac_exist(&attr
->rmac
))
2545 zlog_debug("%s: router mac %pEA is self mac", __func__
,
2549 /* Get the tunnel type from encap extended community */
2550 bgp_attr_extcom_tunnel_type(attr
,
2551 (bgp_encap_types
*)&attr
->encap_tunneltype
);
2553 /* Extract link bandwidth, if any. */
2554 (void)ecommunity_linkbw_present(bgp_attr_get_ecommunity(attr
),
2557 return BGP_ATTR_PARSE_PROCEED
;
2560 /* IPv6 Extended Community attribute. */
2561 static enum bgp_attr_parse_ret
2562 bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args
*args
)
2564 struct peer
*const peer
= args
->peer
;
2565 struct attr
*const attr
= args
->attr
;
2566 const bgp_size_t length
= args
->length
;
2567 struct ecommunity
*ipv6_ecomm
= NULL
;
2570 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2571 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2575 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
2576 goto ipv6_ext_community_ignore
;
2578 ipv6_ecomm
= ecommunity_parse_ipv6(
2579 stream_pnt(peer
->curr
), length
,
2580 CHECK_FLAG(peer
->flags
,
2581 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2582 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2584 /* XXX: fix ecommunity_parse to use stream API */
2585 stream_forward_getp(peer
->curr
, length
);
2588 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2591 return BGP_ATTR_PARSE_PROCEED
;
2593 ipv6_ext_community_ignore
:
2594 stream_forward_getp(peer
->curr
, length
);
2596 return bgp_attr_ignore(peer
, args
->type
);
2599 /* Parse Tunnel Encap attribute in an UPDATE */
2600 static int bgp_attr_encap(uint8_t type
, struct peer
*peer
, /* IN */
2601 bgp_size_t length
, /* IN: attr's length field */
2602 struct attr
*attr
, /* IN: caller already allocated */
2603 uint8_t flag
, /* IN: attr's flags field */
2607 uint16_t tunneltype
= 0;
2609 total
= length
+ (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
2611 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
)
2612 || !CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
2614 "Tunnel Encap attribute flag isn't optional and transitive %d",
2616 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2617 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
2622 if (BGP_ATTR_ENCAP
== type
) {
2623 /* read outer TLV type and length */
2624 uint16_t tlv_length
;
2628 "Tunnel Encap attribute not long enough to contain outer T,L");
2629 bgp_notify_send_with_data(
2630 peer
, BGP_NOTIFY_UPDATE_ERR
,
2631 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2634 tunneltype
= stream_getw(BGP_INPUT(peer
));
2635 tlv_length
= stream_getw(BGP_INPUT(peer
));
2638 if (tlv_length
!= length
) {
2639 zlog_info("%s: tlv_length(%d) != length(%d)",
2640 __func__
, tlv_length
, length
);
2644 while (length
>= 4) {
2645 uint16_t subtype
= 0;
2646 uint16_t sublength
= 0;
2647 struct bgp_attr_encap_subtlv
*tlv
;
2649 if (BGP_ATTR_ENCAP
== type
) {
2650 subtype
= stream_getc(BGP_INPUT(peer
));
2651 sublength
= stream_getc(BGP_INPUT(peer
));
2653 #ifdef ENABLE_BGP_VNC
2655 subtype
= stream_getw(BGP_INPUT(peer
));
2656 sublength
= stream_getw(BGP_INPUT(peer
));
2661 if (sublength
> length
) {
2663 "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2665 bgp_notify_send_with_data(
2666 peer
, BGP_NOTIFY_UPDATE_ERR
,
2667 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2671 /* alloc and copy sub-tlv */
2672 /* TBD make sure these are freed when attributes are released */
2673 tlv
= XCALLOC(MTYPE_ENCAP_TLV
,
2674 sizeof(struct bgp_attr_encap_subtlv
) + sublength
);
2675 tlv
->type
= subtype
;
2676 tlv
->length
= sublength
;
2677 stream_get(tlv
->value
, peer
->curr
, sublength
);
2678 length
-= sublength
;
2680 /* attach tlv to encap chain */
2681 if (BGP_ATTR_ENCAP
== type
) {
2682 struct bgp_attr_encap_subtlv
*stlv_last
;
2683 for (stlv_last
= attr
->encap_subtlvs
;
2684 stlv_last
&& stlv_last
->next
;
2685 stlv_last
= stlv_last
->next
)
2688 stlv_last
->next
= tlv
;
2690 attr
->encap_subtlvs
= tlv
;
2692 #ifdef ENABLE_BGP_VNC
2694 struct bgp_attr_encap_subtlv
*stlv_last
;
2695 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
2696 bgp_attr_get_vnc_subtlvs(attr
);
2698 for (stlv_last
= vnc_subtlvs
;
2699 stlv_last
&& stlv_last
->next
;
2700 stlv_last
= stlv_last
->next
)
2703 stlv_last
->next
= tlv
;
2705 bgp_attr_set_vnc_subtlvs(attr
, tlv
);
2710 if (BGP_ATTR_ENCAP
== type
) {
2711 attr
->encap_tunneltype
= tunneltype
;
2715 /* spurious leftover data */
2717 "Tunnel Encap attribute length is bad: %d leftover octets",
2719 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2720 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2729 /* SRv6 Service Data Sub-Sub-TLV attribute
2730 * draft-ietf-bess-srv6-services-07
2732 static enum bgp_attr_parse_ret
2733 bgp_attr_srv6_service_data(struct bgp_attr_parser_args
*args
)
2735 struct peer
*const peer
= args
->peer
;
2736 struct attr
*const attr
= args
->attr
;
2737 uint8_t type
, loc_block_len
, loc_node_len
, func_len
, arg_len
,
2738 transposition_len
, transposition_offset
;
2740 size_t headersz
= sizeof(type
) + sizeof(length
);
2742 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2745 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2746 headersz
, STREAM_READABLE(peer
->curr
));
2747 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2751 type
= stream_getc(peer
->curr
);
2752 length
= stream_getw(peer
->curr
);
2754 if (STREAM_READABLE(peer
->curr
) < length
) {
2757 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2758 length
, STREAM_READABLE(peer
->curr
));
2759 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2763 if (length
< BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
) {
2766 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %hu remaining in UPDATE)",
2767 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
,
2769 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2773 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
) {
2774 if (STREAM_READABLE(peer
->curr
) <
2775 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
) {
2778 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %zu remaining in UPDATE)",
2779 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
,
2780 STREAM_READABLE(peer
->curr
));
2781 return bgp_attr_malformed(
2782 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2786 loc_block_len
= stream_getc(peer
->curr
);
2787 loc_node_len
= stream_getc(peer
->curr
);
2788 func_len
= stream_getc(peer
->curr
);
2789 arg_len
= stream_getc(peer
->curr
);
2790 transposition_len
= stream_getc(peer
->curr
);
2791 transposition_offset
= stream_getc(peer
->curr
);
2793 /* Log SRv6 Service Data Sub-Sub-TLV */
2794 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2796 "%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",
2797 __func__
, loc_block_len
, loc_node_len
, func_len
,
2798 arg_len
, transposition_len
,
2799 transposition_offset
);
2802 attr
->srv6_l3vpn
->loc_block_len
= loc_block_len
;
2803 attr
->srv6_l3vpn
->loc_node_len
= loc_node_len
;
2804 attr
->srv6_l3vpn
->func_len
= func_len
;
2805 attr
->srv6_l3vpn
->arg_len
= arg_len
;
2806 attr
->srv6_l3vpn
->transposition_len
= transposition_len
;
2807 attr
->srv6_l3vpn
->transposition_offset
= transposition_offset
;
2811 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2813 "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
2816 stream_forward_getp(peer
->curr
, length
);
2819 return BGP_ATTR_PARSE_PROCEED
;
2822 /* SRv6 Service Sub-TLV attribute
2823 * draft-ietf-bess-srv6-services-07
2825 static enum bgp_attr_parse_ret
2826 bgp_attr_srv6_service(struct bgp_attr_parser_args
*args
)
2828 struct peer
*const peer
= args
->peer
;
2829 struct attr
*const attr
= args
->attr
;
2830 struct in6_addr ipv6_sid
;
2831 uint8_t type
, sid_flags
;
2832 uint16_t length
, endpoint_behavior
;
2833 size_t headersz
= sizeof(type
) + sizeof(length
);
2834 enum bgp_attr_parse_ret err
;
2836 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2839 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2840 headersz
, STREAM_READABLE(peer
->curr
));
2841 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2845 type
= stream_getc(peer
->curr
);
2846 length
= stream_getw(peer
->curr
);
2848 if (STREAM_READABLE(peer
->curr
) < length
) {
2851 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2852 length
, STREAM_READABLE(peer
->curr
));
2853 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2857 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
) {
2858 if (STREAM_READABLE(peer
->curr
) <
2859 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
) {
2862 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %d for attribute data, have %zu remaining in UPDATE)",
2863 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
,
2864 STREAM_READABLE(peer
->curr
));
2865 return bgp_attr_malformed(
2866 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2869 stream_getc(peer
->curr
);
2870 stream_get(&ipv6_sid
, peer
->curr
, sizeof(ipv6_sid
));
2871 sid_flags
= stream_getc(peer
->curr
);
2872 endpoint_behavior
= stream_getw(peer
->curr
);
2873 stream_getc(peer
->curr
);
2875 /* Log SRv6 Service Sub-TLV */
2876 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
))
2878 "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x",
2879 __func__
, &ipv6_sid
, sid_flags
,
2882 /* Configure from Info */
2883 if (attr
->srv6_l3vpn
) {
2884 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2885 "Prefix SID SRv6 L3VPN field repeated");
2886 return bgp_attr_malformed(
2887 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2889 attr
->srv6_l3vpn
= XCALLOC(MTYPE_BGP_SRV6_L3VPN
,
2890 sizeof(struct bgp_attr_srv6_l3vpn
));
2891 sid_copy(&attr
->srv6_l3vpn
->sid
, &ipv6_sid
);
2892 attr
->srv6_l3vpn
->sid_flags
= sid_flags
;
2893 attr
->srv6_l3vpn
->endpoint_behavior
= endpoint_behavior
;
2894 attr
->srv6_l3vpn
->loc_block_len
= 0;
2895 attr
->srv6_l3vpn
->loc_node_len
= 0;
2896 attr
->srv6_l3vpn
->func_len
= 0;
2897 attr
->srv6_l3vpn
->arg_len
= 0;
2898 attr
->srv6_l3vpn
->transposition_len
= 0;
2899 attr
->srv6_l3vpn
->transposition_offset
= 0;
2901 // Sub-Sub-TLV found
2902 if (length
> BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
) {
2903 err
= bgp_attr_srv6_service_data(args
);
2905 if (err
!= BGP_ATTR_PARSE_PROCEED
)
2909 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
2912 /* Placeholder code for unsupported type */
2914 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2916 "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
2919 stream_forward_getp(peer
->curr
, length
);
2922 return BGP_ATTR_PARSE_PROCEED
;
2926 * Read an individual SID value returning how much data we have read
2927 * Returns 0 if there was an error that needs to be passed up the stack
2929 static enum bgp_attr_parse_ret
2930 bgp_attr_psid_sub(uint8_t type
, uint16_t length
,
2931 struct bgp_attr_parser_args
*args
)
2933 struct peer
*const peer
= args
->peer
;
2934 struct attr
*const attr
= args
->attr
;
2935 uint32_t label_index
;
2936 struct in6_addr ipv6_sid
;
2938 uint32_t srgb_range
;
2940 uint8_t sid_type
, sid_flags
;
2942 if (type
== BGP_PREFIX_SID_LABEL_INDEX
) {
2943 if (STREAM_READABLE(peer
->curr
) < length
2944 || length
!= BGP_PREFIX_SID_LABEL_INDEX_LENGTH
) {
2945 flog_err(EC_BGP_ATTR_LEN
,
2946 "Prefix SID label index length is %hu instead of %u",
2947 length
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
2948 return bgp_attr_malformed(args
,
2949 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2953 /* Ignore flags and reserved */
2954 stream_getc(peer
->curr
);
2955 stream_getw(peer
->curr
);
2957 /* Fetch the label index and see if it is valid. */
2958 label_index
= stream_getl(peer
->curr
);
2959 if (label_index
== BGP_INVALID_LABEL_INDEX
)
2960 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2963 /* Store label index; subsequently, we'll check on
2965 attr
->label_index
= label_index
;
2968 /* Placeholder code for the IPv6 SID type */
2969 else if (type
== BGP_PREFIX_SID_IPV6
) {
2970 if (STREAM_READABLE(peer
->curr
) < length
2971 || length
!= BGP_PREFIX_SID_IPV6_LENGTH
) {
2972 flog_err(EC_BGP_ATTR_LEN
,
2973 "Prefix SID IPv6 length is %hu instead of %u",
2974 length
, BGP_PREFIX_SID_IPV6_LENGTH
);
2975 return bgp_attr_malformed(args
,
2976 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2980 /* Ignore reserved */
2981 stream_getc(peer
->curr
);
2982 stream_getw(peer
->curr
);
2984 stream_get(&ipv6_sid
, peer
->curr
, 16);
2987 /* Placeholder code for the Originator SRGB type */
2988 else if (type
== BGP_PREFIX_SID_ORIGINATOR_SRGB
) {
2990 * ietf-idr-bgp-prefix-sid-05:
2991 * Length is the total length of the value portion of the
2992 * TLV: 2 + multiple of 6.
2994 * peer->curr stream readp should be at the beginning of the 16
2995 * bit flag field at this point in the code.
2999 * Check that the TLV length field is sane: at least 2 bytes of
3000 * flag, and at least 1 SRGB (these are 6 bytes each)
3002 if (length
< (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
)) {
3005 "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
3007 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
3008 return bgp_attr_malformed(
3009 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3014 * Check that we actually have at least as much data as
3015 * specified by the length field
3017 if (STREAM_READABLE(peer
->curr
) < length
) {
3018 flog_err(EC_BGP_ATTR_LEN
,
3019 "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain",
3020 length
, STREAM_READABLE(peer
->curr
));
3021 return bgp_attr_malformed(
3022 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3027 * Check that the portion of the TLV containing the sequence of
3028 * SRGBs corresponds to a multiple of the SRGB size; to get
3029 * that length, we skip the 16 bit flags field
3031 stream_getw(peer
->curr
);
3033 if (length
% BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
) {
3036 "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
3037 length
, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
3038 return bgp_attr_malformed(
3039 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3043 srgb_count
= length
/ BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
;
3045 for (int i
= 0; i
< srgb_count
; i
++) {
3046 stream_get(&srgb_base
, peer
->curr
, 3);
3047 stream_get(&srgb_range
, peer
->curr
, 3);
3051 /* Placeholder code for the VPN-SID Service type */
3052 else if (type
== BGP_PREFIX_SID_VPN_SID
) {
3053 if (STREAM_READABLE(peer
->curr
) < length
3054 || length
!= BGP_PREFIX_SID_VPN_SID_LENGTH
) {
3055 flog_err(EC_BGP_ATTR_LEN
,
3056 "Prefix SID VPN SID length is %hu instead of %u",
3057 length
, BGP_PREFIX_SID_VPN_SID_LENGTH
);
3058 return bgp_attr_malformed(args
,
3059 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3063 /* Parse VPN-SID Sub-TLV */
3064 stream_getc(peer
->curr
); /* reserved */
3065 sid_type
= stream_getc(peer
->curr
); /* sid_type */
3066 sid_flags
= stream_getc(peer
->curr
); /* sid_flags */
3067 stream_get(&ipv6_sid
, peer
->curr
,
3068 sizeof(ipv6_sid
)); /* sid_value */
3070 /* Log VPN-SID Sub-TLV */
3071 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
))
3073 "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x",
3074 __func__
, &ipv6_sid
, sid_type
, sid_flags
);
3076 /* Configure from Info */
3077 if (attr
->srv6_vpn
) {
3078 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
3079 "Prefix SID SRv6 VPN field repeated");
3080 return bgp_attr_malformed(
3081 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
3083 attr
->srv6_vpn
= XCALLOC(MTYPE_BGP_SRV6_VPN
,
3084 sizeof(struct bgp_attr_srv6_vpn
));
3085 attr
->srv6_vpn
->sid_flags
= sid_flags
;
3086 sid_copy(&attr
->srv6_vpn
->sid
, &ipv6_sid
);
3087 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
3090 /* Placeholder code for the SRv6 L3 Service type */
3091 else if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE
) {
3092 if (STREAM_READABLE(peer
->curr
) < length
) {
3095 "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain",
3096 length
, STREAM_READABLE(peer
->curr
));
3097 return bgp_attr_malformed(args
,
3098 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3102 /* ignore reserved */
3103 stream_getc(peer
->curr
);
3105 return bgp_attr_srv6_service(args
);
3108 /* Placeholder code for Unsupported TLV */
3111 if (STREAM_READABLE(peer
->curr
) < length
) {
3114 "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE",
3115 length
, STREAM_READABLE(peer
->curr
));
3116 return bgp_attr_malformed(
3117 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3121 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3123 "%s attr Prefix-SID sub-type=%u is not supported, skipped",
3126 stream_forward_getp(peer
->curr
, length
);
3129 return BGP_ATTR_PARSE_PROCEED
;
3132 /* Prefix SID attribute
3133 * draft-ietf-idr-bgp-prefix-sid-05
3135 enum bgp_attr_parse_ret
bgp_attr_prefix_sid(struct bgp_attr_parser_args
*args
)
3137 struct peer
*const peer
= args
->peer
;
3138 struct attr
*const attr
= args
->attr
;
3139 enum bgp_attr_parse_ret ret
;
3141 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
);
3145 size_t headersz
= sizeof(type
) + sizeof(length
);
3146 size_t psid_parsed_length
= 0;
3148 while (STREAM_READABLE(peer
->curr
) > 0
3149 && psid_parsed_length
< args
->length
) {
3151 if (STREAM_READABLE(peer
->curr
) < headersz
) {
3154 "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
3155 headersz
, STREAM_READABLE(peer
->curr
));
3156 return bgp_attr_malformed(
3157 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3161 type
= stream_getc(peer
->curr
);
3162 length
= stream_getw(peer
->curr
);
3164 if (STREAM_READABLE(peer
->curr
) < length
) {
3167 "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
3168 length
, STREAM_READABLE(peer
->curr
));
3169 return bgp_attr_malformed(args
,
3170 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3174 ret
= bgp_attr_psid_sub(type
, length
, args
);
3176 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3179 psid_parsed_length
+= length
+ headersz
;
3181 if (psid_parsed_length
> args
->length
) {
3184 "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
3185 length
+ headersz
, psid_parsed_length
- (length
+ headersz
));
3186 return bgp_attr_malformed(
3187 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3192 return BGP_ATTR_PARSE_PROCEED
;
3195 /* PMSI tunnel attribute (RFC 6514)
3196 * Basic validation checks done here.
3198 static enum bgp_attr_parse_ret
3199 bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args
*args
)
3201 struct peer
*const peer
= args
->peer
;
3202 struct attr
*const attr
= args
->attr
;
3203 const bgp_size_t length
= args
->length
;
3205 int attr_parse_len
= 2 + BGP_LABEL_BYTES
;
3207 /* Verify that the receiver is expecting "ingress replication" as we
3208 * can only support that.
3210 if (length
< attr_parse_len
) {
3211 flog_err(EC_BGP_ATTR_LEN
, "Bad PMSI tunnel attribute length %d",
3213 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3216 stream_getc(peer
->curr
); /* Flags */
3217 tnl_type
= stream_getc(peer
->curr
);
3218 if (tnl_type
> PMSI_TNLTYPE_MAX
) {
3219 flog_err(EC_BGP_ATTR_PMSI_TYPE
,
3220 "Invalid PMSI tunnel attribute type %d", tnl_type
);
3221 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
3224 if (tnl_type
== PMSI_TNLTYPE_INGR_REPL
) {
3226 flog_err(EC_BGP_ATTR_PMSI_LEN
,
3227 "Bad PMSI tunnel attribute length %d for IR",
3229 return bgp_attr_malformed(
3230 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3235 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
);
3236 bgp_attr_set_pmsi_tnl_type(attr
, tnl_type
);
3237 stream_get(&attr
->label
, peer
->curr
, BGP_LABEL_BYTES
);
3239 /* Forward read pointer of input stream. */
3240 stream_forward_getp(peer
->curr
, length
- attr_parse_len
);
3242 return BGP_ATTR_PARSE_PROCEED
;
3245 /* AIGP attribute (rfc7311) */
3246 static enum bgp_attr_parse_ret
bgp_attr_aigp(struct bgp_attr_parser_args
*args
)
3248 struct peer
*const peer
= args
->peer
;
3249 struct attr
*const attr
= args
->attr
;
3250 const bgp_size_t length
= args
->length
;
3251 uint8_t *s
= stream_pnt(peer
->curr
);
3254 /* If an AIGP attribute is received on a BGP session for which
3255 * AIGP_SESSION is disabled, the attribute MUST be treated exactly
3256 * as if it were an unrecognized non-transitive attribute.
3257 * That is, it "MUST be quietly ignored and not passed along to
3259 * For Internal BGP (IBGP) sessions, and for External BGP (EBGP)
3260 * sessions between members of the same BGP Confederation,
3261 * the default value of AIGP_SESSION SHOULD be "enabled".
3263 if (peer
->sort
== BGP_PEER_EBGP
&&
3264 !CHECK_FLAG(peer
->flags
, PEER_FLAG_AIGP
)) {
3266 "%pBP received AIGP attribute, but eBGP peer do not support it",
3271 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
3274 if (!bgp_attr_aigp_valid(s
, length
))
3277 /* Extract AIGP Metric TLV */
3278 if (bgp_attr_aigp_get_tlv_metric(s
, length
, &aigp
))
3279 bgp_attr_set_aigp_metric(attr
, aigp
);
3282 stream_forward_getp(peer
->curr
, length
);
3284 return bgp_attr_ignore(peer
, args
->type
);
3287 /* OTC attribute. */
3288 static enum bgp_attr_parse_ret
bgp_attr_otc(struct bgp_attr_parser_args
*args
)
3290 struct peer
*const peer
= args
->peer
;
3291 struct attr
*const attr
= args
->attr
;
3292 const bgp_size_t length
= args
->length
;
3296 flog_err(EC_BGP_ATTR_LEN
, "OTC attribute length isn't 4 [%u]",
3298 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3302 if (peer
->discard_attrs
[args
->type
] || peer
->withdraw_attrs
[args
->type
])
3305 attr
->otc
= stream_getl(peer
->curr
);
3307 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "OTC attribute value is 0");
3308 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
3312 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_OTC
);
3314 return BGP_ATTR_PARSE_PROCEED
;
3317 stream_forward_getp(peer
->curr
, length
);
3319 return bgp_attr_ignore(peer
, args
->type
);
3322 /* BGP unknown attribute treatment. */
3323 static enum bgp_attr_parse_ret
3324 bgp_attr_unknown(struct bgp_attr_parser_args
*args
)
3326 bgp_size_t total
= args
->total
;
3327 struct transit
*transit
;
3328 struct peer
*const peer
= args
->peer
;
3329 struct attr
*const attr
= args
->attr
;
3330 uint8_t *const startp
= args
->startp
;
3331 const uint8_t type
= args
->type
;
3332 const uint8_t flag
= args
->flags
;
3333 const bgp_size_t length
= args
->length
;
3335 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3337 "%s Unknown attribute is received (type %d, length %d)",
3338 peer
->host
, type
, length
);
3340 /* Forward read pointer of input stream. */
3341 stream_forward_getp(peer
->curr
, length
);
3343 if (peer
->discard_attrs
[type
] || peer
->withdraw_attrs
[type
])
3344 return bgp_attr_ignore(peer
, type
);
3346 /* If any of the mandatory well-known attributes are not recognized,
3347 then the Error Subcode is set to Unrecognized Well-known
3348 Attribute. The Data field contains the unrecognized attribute
3349 (type, length and value). */
3350 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
3351 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_UNREC_ATTR
,
3355 /* Unrecognized non-transitive optional attributes must be quietly
3356 ignored and not passed along to other BGP peers. */
3357 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
))
3358 return BGP_ATTR_PARSE_PROCEED
;
3360 /* If a path with recognized transitive optional attribute is
3361 accepted and passed along to other BGP peers and the Partial bit
3362 in the Attribute Flags octet is set to 1 by some previous AS, it
3363 is not set back to 0 by the current AS. */
3364 SET_FLAG(*startp
, BGP_ATTR_FLAG_PARTIAL
);
3366 /* Store transitive attribute to the end of attr->transit. */
3367 transit
= bgp_attr_get_transit(attr
);
3369 transit
= XCALLOC(MTYPE_TRANSIT
, sizeof(struct transit
));
3371 transit
->val
= XREALLOC(MTYPE_TRANSIT_VAL
, transit
->val
,
3372 transit
->length
+ total
);
3374 memcpy(transit
->val
+ transit
->length
, startp
, total
);
3375 transit
->length
+= total
;
3376 bgp_attr_set_transit(attr
, transit
);
3378 return BGP_ATTR_PARSE_PROCEED
;
3381 /* Well-known attribute check. */
3382 static int bgp_attr_check(struct peer
*peer
, struct attr
*attr
)
3386 /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
3388 if (CHECK_FLAG(peer
->cap
, PEER_CAP_RESTART_RCV
) && !attr
->flag
)
3389 return BGP_ATTR_PARSE_PROCEED
;
3391 /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
3392 to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
3393 are present, it should. Check for any other attribute being present
3396 if ((!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)) &&
3397 CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
))))
3398 return BGP_ATTR_PARSE_PROCEED
;
3400 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
)))
3401 type
= BGP_ATTR_ORIGIN
;
3403 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
3404 type
= BGP_ATTR_AS_PATH
;
3406 /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
3408 * NLRI is empty. We can't easily check NLRI empty here though.
3410 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3411 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)))
3412 type
= BGP_ATTR_NEXT_HOP
;
3414 if (peer
->sort
== BGP_PEER_IBGP
3415 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)))
3416 type
= BGP_ATTR_LOCAL_PREF
;
3418 /* If any of the well-known mandatory attributes are not present
3419 * in an UPDATE message, then "treat-as-withdraw" MUST be used.
3422 flog_warn(EC_BGP_MISSING_ATTRIBUTE
,
3423 "%s Missing well-known attribute %s.", peer
->host
,
3424 lookup_msg(attr_str
, type
, NULL
));
3425 return BGP_ATTR_PARSE_WITHDRAW
;
3427 return BGP_ATTR_PARSE_PROCEED
;
3430 /* Read attribute of update packet. This function is called from
3431 bgp_update_receive() in bgp_packet.c. */
3432 enum bgp_attr_parse_ret
bgp_attr_parse(struct peer
*peer
, struct attr
*attr
,
3434 struct bgp_nlri
*mp_update
,
3435 struct bgp_nlri
*mp_withdraw
)
3437 enum bgp_attr_parse_ret ret
;
3441 uint8_t *startp
, *endp
;
3443 uint8_t seen
[BGP_ATTR_BITMAP_SIZE
];
3444 /* we need the as4_path only until we have synthesized the as_path with
3446 /* same goes for as4_aggregator */
3447 struct aspath
*as4_path
= NULL
;
3448 as_t as4_aggregator
= 0;
3449 struct in_addr as4_aggregator_addr
= {.s_addr
= 0};
3450 struct transit
*transit
;
3452 /* Initialize bitmap. */
3453 memset(seen
, 0, BGP_ATTR_BITMAP_SIZE
);
3455 /* End pointer of BGP attribute. */
3456 endp
= BGP_INPUT_PNT(peer
) + size
;
3458 /* Get attributes to the end of attribute length. */
3459 while (BGP_INPUT_PNT(peer
) < endp
) {
3460 /* Check remaining length check.*/
3461 if (endp
- BGP_INPUT_PNT(peer
) < BGP_ATTR_MIN_LEN
) {
3462 /* XXX warning: long int format, int arg (arg 5) */
3464 EC_BGP_ATTRIBUTE_TOO_SMALL
,
3465 "%s: error BGP attribute length %lu is smaller than min len",
3467 (unsigned long)(endp
3468 - stream_pnt(BGP_INPUT(peer
))));
3470 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3471 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3472 ret
= BGP_ATTR_PARSE_ERROR
;
3476 /* Fetch attribute flag and type. */
3477 startp
= BGP_INPUT_PNT(peer
);
3478 /* "The lower-order four bits of the Attribute Flags octet are
3479 unused. They MUST be zero when sent and MUST be ignored when
3481 flag
= 0xF0 & stream_getc(BGP_INPUT(peer
));
3482 type
= stream_getc(BGP_INPUT(peer
));
3484 /* Check whether Extended-Length applies and is in bounds */
3485 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
)
3486 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1))) {
3488 EC_BGP_EXT_ATTRIBUTE_TOO_SMALL
,
3489 "%s: Extended length set, but just %lu bytes of attr header",
3491 (unsigned long)(endp
3492 - stream_pnt(BGP_INPUT(peer
))));
3494 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3495 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3496 ret
= BGP_ATTR_PARSE_ERROR
;
3500 /* Check extended attribue length bit. */
3501 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
))
3502 length
= stream_getw(BGP_INPUT(peer
));
3504 length
= stream_getc(BGP_INPUT(peer
));
3506 /* If any attribute appears more than once in the UPDATE
3507 message, then the Error Subcode is set to Malformed Attribute
3510 if (CHECK_BITMAP(seen
, type
)) {
3512 EC_BGP_ATTRIBUTE_REPEATED
,
3513 "%s: error BGP attribute type %d appears twice in a message",
3516 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3517 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3518 ret
= BGP_ATTR_PARSE_ERROR
;
3522 /* Set type to bitmap to check duplicate attribute. `type' is
3523 unsigned char so it never overflow bitmap range. */
3525 SET_BITMAP(seen
, type
);
3527 /* Overflow check. */
3528 attr_endp
= BGP_INPUT_PNT(peer
) + length
;
3530 if (attr_endp
> endp
) {
3532 EC_BGP_ATTRIBUTE_TOO_LARGE
,
3533 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
3534 peer
->host
, type
, length
, size
, attr_endp
,
3538 * If any recognized attribute has an Attribute
3539 * Length that conflicts with the expected length
3540 * (based on the attribute type code), then the
3541 * Error Subcode MUST be set to Attribute Length
3542 * Error. The Data field MUST contain the erroneous
3543 * attribute (type, length, and value).
3545 * We do not currently have a good way to determine the
3546 * length of the attribute independent of the length
3547 * received in the message. Instead we send the
3548 * minimum between the amount of data we have and the
3549 * amount specified by the attribute length field.
3551 * Instead of directly passing in the packet buffer and
3552 * offset we use the stream_get* functions to read into
3553 * a stack buffer, since they perform bounds checking
3554 * and we are working with untrusted data.
3556 unsigned char ndata
[peer
->max_packet_size
];
3557 memset(ndata
, 0x00, sizeof(ndata
));
3559 CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 2 : 1;
3560 /* Rewind to end of flag field */
3561 stream_rewind_getp(BGP_INPUT(peer
), (1 + lfl
));
3563 stream_get(&ndata
[0], BGP_INPUT(peer
), 1);
3565 stream_get(&ndata
[1], BGP_INPUT(peer
), lfl
);
3567 size_t atl
= attr_endp
- startp
;
3568 size_t ndl
= MIN(atl
, STREAM_READABLE(BGP_INPUT(peer
)));
3569 stream_get(&ndata
[lfl
+ 1], BGP_INPUT(peer
), ndl
);
3571 bgp_notify_send_with_data(
3572 peer
, BGP_NOTIFY_UPDATE_ERR
,
3573 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
, ndata
,
3576 ret
= BGP_ATTR_PARSE_ERROR
;
3580 struct bgp_attr_parser_args attr_args
= {
3587 .total
= attr_endp
- startp
,
3591 /* If any recognized attribute has Attribute Flags that conflict
3592 with the Attribute Type Code, then the Error Subcode is set
3594 Attribute Flags Error. The Data field contains the erroneous
3595 attribute (type, length and value). */
3596 if (bgp_attr_flag_invalid(&attr_args
)) {
3597 ret
= bgp_attr_malformed(
3598 &attr_args
, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
3600 if (ret
== BGP_ATTR_PARSE_PROCEED
)
3605 /* OK check attribute and store it's value. */
3607 case BGP_ATTR_ORIGIN
:
3608 ret
= bgp_attr_origin(&attr_args
);
3610 case BGP_ATTR_AS_PATH
:
3611 ret
= bgp_attr_aspath(&attr_args
);
3613 case BGP_ATTR_AS4_PATH
:
3614 ret
= bgp_attr_as4_path(&attr_args
, &as4_path
);
3616 case BGP_ATTR_NEXT_HOP
:
3617 ret
= bgp_attr_nexthop(&attr_args
);
3619 case BGP_ATTR_MULTI_EXIT_DISC
:
3620 ret
= bgp_attr_med(&attr_args
);
3622 case BGP_ATTR_LOCAL_PREF
:
3623 ret
= bgp_attr_local_pref(&attr_args
);
3625 case BGP_ATTR_ATOMIC_AGGREGATE
:
3626 ret
= bgp_attr_atomic(&attr_args
);
3628 case BGP_ATTR_AGGREGATOR
:
3629 ret
= bgp_attr_aggregator(&attr_args
);
3631 case BGP_ATTR_AS4_AGGREGATOR
:
3632 ret
= bgp_attr_as4_aggregator(&attr_args
,
3634 &as4_aggregator_addr
);
3636 case BGP_ATTR_COMMUNITIES
:
3637 ret
= bgp_attr_community(&attr_args
);
3639 case BGP_ATTR_LARGE_COMMUNITIES
:
3640 ret
= bgp_attr_large_community(&attr_args
);
3642 case BGP_ATTR_ORIGINATOR_ID
:
3643 ret
= bgp_attr_originator_id(&attr_args
);
3645 case BGP_ATTR_CLUSTER_LIST
:
3646 ret
= bgp_attr_cluster_list(&attr_args
);
3648 case BGP_ATTR_MP_REACH_NLRI
:
3649 ret
= bgp_mp_reach_parse(&attr_args
, mp_update
);
3651 case BGP_ATTR_MP_UNREACH_NLRI
:
3652 ret
= bgp_mp_unreach_parse(&attr_args
, mp_withdraw
);
3654 case BGP_ATTR_EXT_COMMUNITIES
:
3655 ret
= bgp_attr_ext_communities(&attr_args
);
3657 #ifdef ENABLE_BGP_VNC_ATTR
3660 case BGP_ATTR_ENCAP
:
3661 ret
= bgp_attr_encap(type
, peer
, length
, attr
, flag
,
3664 case BGP_ATTR_PREFIX_SID
:
3665 ret
= bgp_attr_prefix_sid(&attr_args
);
3667 case BGP_ATTR_PMSI_TUNNEL
:
3668 ret
= bgp_attr_pmsi_tunnel(&attr_args
);
3670 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
3671 ret
= bgp_attr_ipv6_ext_communities(&attr_args
);
3674 ret
= bgp_attr_otc(&attr_args
);
3677 ret
= bgp_attr_aigp(&attr_args
);
3680 ret
= bgp_attr_unknown(&attr_args
);
3684 if (ret
== BGP_ATTR_PARSE_ERROR_NOTIFYPLS
) {
3685 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3686 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3687 ret
= BGP_ATTR_PARSE_ERROR
;
3691 if (ret
== BGP_ATTR_PARSE_EOR
) {
3695 if (ret
== BGP_ATTR_PARSE_ERROR
) {
3696 flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR
,
3697 "%s: Attribute %s, parse error", peer
->host
,
3698 lookup_msg(attr_str
, type
, NULL
));
3701 if (ret
== BGP_ATTR_PARSE_WITHDRAW
) {
3703 EC_BGP_ATTRIBUTE_PARSE_WITHDRAW
,
3704 "%s: Attribute %s, parse error - treating as withdrawal",
3705 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3709 /* Check the fetched length. */
3710 if (BGP_INPUT_PNT(peer
) != attr_endp
) {
3711 flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR
,
3712 "%s: BGP attribute %s, fetch error",
3713 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3714 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3715 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3716 ret
= BGP_ATTR_PARSE_ERROR
;
3722 * draft-ietf-idr-bgp-prefix-sid-27#section-3:
3723 * About Prefix-SID path attribute,
3724 * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
3725 * may only appear in a BGP Prefix-SID attribute attached to
3726 * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
3727 * It MUST be ignored when received for other BGP AFI/SAFI combinations.
3729 if (!attr
->mp_nexthop_len
|| mp_update
->safi
!= SAFI_LABELED_UNICAST
)
3730 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
3732 /* Check final read pointer is same as end pointer. */
3733 if (BGP_INPUT_PNT(peer
) != endp
) {
3734 flog_warn(EC_BGP_ATTRIBUTES_MISMATCH
,
3735 "%s: BGP attribute %s, length mismatch", peer
->host
,
3736 lookup_msg(attr_str
, type
, NULL
));
3737 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3738 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3740 ret
= BGP_ATTR_PARSE_ERROR
;
3745 * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
3746 * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
3747 * This is implemented below and will result in a NOTIFICATION. If the
3748 * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
3749 * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
3750 * message SHOULD NOT be sent. This is implemented elsewhere.
3752 * RFC4760: An UPDATE message that carries no NLRI, other than the one
3753 * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
3754 * attribute. If such a message contains the NEXT_HOP attribute, the BGP
3755 * speaker that receives the message SHOULD ignore this attribute.
3757 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3758 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
))) {
3759 if (bgp_attr_nexthop_valid(peer
, attr
) < 0) {
3760 ret
= BGP_ATTR_PARSE_ERROR
;
3765 /* Check all mandatory well-known attributes are present */
3766 ret
= bgp_attr_check(peer
, attr
);
3771 * At this place we can see whether we got AS4_PATH and/or
3772 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
3773 * We can not do this before we've read all attributes because
3774 * the as4 handling does not say whether AS4_PATH has to be sent
3775 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
3776 * in relationship to AGGREGATOR.
3777 * So, to be defensive, we are not relying on any order and read
3778 * all attributes first, including these 32bit ones, and now,
3779 * afterwards, we look what and if something is to be done for as4.
3781 * It is possible to not have AS_PATH, e.g. GR EoR and sole
3784 /* actually... this doesn't ever return failure currently, but
3785 * better safe than sorry */
3786 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))
3787 && bgp_attr_munge_as4_attrs(peer
, attr
, as4_path
, as4_aggregator
,
3788 &as4_aggregator_addr
)) {
3789 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3790 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3791 ret
= BGP_ATTR_PARSE_ERROR
;
3796 * Finally do the checks on the aspath we did not do yet
3797 * because we waited for a potentially synthesized aspath.
3799 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))) {
3800 ret
= bgp_attr_aspath_check(peer
, attr
);
3801 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3805 ret
= BGP_ATTR_PARSE_PROCEED
;
3809 * At this stage, we have done all fiddling with as4, and the
3810 * resulting info is in attr->aggregator resp. attr->aspath so
3811 * we can chuck as4_aggregator and as4_path alltogether in order
3815 * unintern - it is in the hash
3816 * The flag that we got this is still there, but that
3817 * does not do any trouble
3819 aspath_unintern(&as4_path
);
3821 transit
= bgp_attr_get_transit(attr
);
3822 if (ret
!= BGP_ATTR_PARSE_ERROR
) {
3823 /* Finally intern unknown attribute. */
3825 bgp_attr_set_transit(attr
, transit_intern(transit
));
3826 if (attr
->encap_subtlvs
)
3827 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
3829 #ifdef ENABLE_BGP_VNC
3830 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3831 bgp_attr_get_vnc_subtlvs(attr
);
3834 bgp_attr_set_vnc_subtlvs(
3836 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
3840 transit_free(transit
);
3841 bgp_attr_set_transit(attr
, NULL
);
3844 bgp_attr_flush_encap(attr
);
3848 transit
= bgp_attr_get_transit(attr
);
3850 assert(transit
->refcnt
> 0);
3851 if (attr
->encap_subtlvs
)
3852 assert(attr
->encap_subtlvs
->refcnt
> 0);
3853 #ifdef ENABLE_BGP_VNC
3854 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3855 bgp_attr_get_vnc_subtlvs(attr
);
3858 assert(vnc_subtlvs
->refcnt
> 0);
3865 * Extract the tunnel type from extended community
3867 void bgp_attr_extcom_tunnel_type(struct attr
*attr
,
3868 bgp_encap_types
*tunnel_type
)
3870 struct ecommunity
*ecom
;
3876 ecom
= bgp_attr_get_ecommunity(attr
);
3877 if (!ecom
|| !ecom
->size
)
3880 for (i
= 0; i
< ecom
->size
; i
++) {
3882 uint8_t type
, sub_type
;
3884 pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
3887 if (!(type
== ECOMMUNITY_ENCODE_OPAQUE
&&
3888 sub_type
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
))
3890 *tunnel_type
= ((pnt
[6] << 8) | pnt
[7]);
3897 size_t bgp_packet_mpattr_start(struct stream
*s
, struct peer
*peer
, afi_t afi
,
3898 safi_t safi
, struct bpacket_attr_vec_arr
*vecarr
,
3902 iana_afi_t pkt_afi
= IANA_AFI_IPV4
;
3903 iana_safi_t pkt_safi
= IANA_SAFI_UNICAST
;
3906 /* Set extended bit always to encode the attribute length as 2 bytes */
3907 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
3908 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
3909 sizep
= stream_get_endp(s
);
3910 stream_putw(s
, 0); /* Marker: Attribute length. */
3913 /* Convert AFI, SAFI to values for packet. */
3914 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
3916 stream_putw(s
, pkt_afi
); /* AFI */
3917 stream_putc(s
, pkt_safi
); /* SAFI */
3921 && (safi
== SAFI_UNICAST
|| safi
== SAFI_LABELED_UNICAST
3922 || safi
== SAFI_MPLS_VPN
|| safi
== SAFI_MULTICAST
))
3923 nh_afi
= peer_cap_enhe(peer
, afi
, safi
) ? AFI_IP6
: AFI_IP
;
3924 else if (safi
== SAFI_FLOWSPEC
)
3927 nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
3930 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
3935 case SAFI_MULTICAST
:
3936 case SAFI_LABELED_UNICAST
:
3938 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3942 stream_putl(s
, 0); /* RD = 0, per RFC */
3944 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3949 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3952 if (attr
->mp_nexthop_len
== 0)
3953 stream_putc(s
, 0); /* no nexthop for flowspec */
3955 stream_putc(s
, attr
->mp_nexthop_len
);
3956 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3961 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
3968 case SAFI_MULTICAST
:
3969 case SAFI_LABELED_UNICAST
:
3971 if (attr
->mp_nexthop_len
3972 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3974 BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
);
3975 stream_put(s
, &attr
->mp_nexthop_global
,
3977 stream_put(s
, &attr
->mp_nexthop_local
,
3980 stream_putc(s
, IPV6_MAX_BYTELEN
);
3981 stream_put(s
, &attr
->mp_nexthop_global
,
3985 case SAFI_MPLS_VPN
: {
3986 if (attr
->mp_nexthop_len
==
3987 BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
3989 stream_putl(s
, 0); /* RD = 0, per RFC */
3991 stream_put(s
, &attr
->mp_nexthop_global
,
3993 stream_putl(s
, 0); /* RD = 0, per RFC */
3995 stream_put(s
, &attr
->mp_nexthop_local
,
3999 stream_putl(s
, 0); /* RD = 0, per RFC */
4001 stream_put(s
, &attr
->mp_nexthop_global
,
4006 stream_putc(s
, IPV6_MAX_BYTELEN
);
4007 stream_put(s
, &attr
->mp_nexthop_global
,
4011 stream_putc(s
, 0); /* no nexthop for flowspec */
4015 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
4020 if (safi
!= SAFI_FLOWSPEC
)
4022 EC_BGP_ATTR_NH_SEND_LEN
,
4023 "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
4024 peer
->host
, afi
, safi
, attr
->mp_nexthop_len
);
4028 assert(!"DEV ESCAPE: AFI_UNSPEC or AFI_MAX should not be used here");
4037 void bgp_packet_mpattr_prefix(struct stream
*s
, afi_t afi
, safi_t safi
,
4038 const struct prefix
*p
,
4039 const struct prefix_rd
*prd
, mpls_label_t
*label
,
4040 uint32_t num_labels
, bool addpath_capable
,
4041 uint32_t addpath_tx_id
, struct attr
*attr
)
4046 assert(!"Dev escape usage of SAFI_UNSPEC or MAX");
4049 if (addpath_capable
)
4050 stream_putl(s
, addpath_tx_id
);
4051 /* Label, RD, Prefix write. */
4052 stream_putc(s
, p
->prefixlen
+ 88);
4053 stream_put(s
, label
, BGP_LABEL_BYTES
);
4054 stream_put(s
, prd
->val
, 8);
4055 stream_put(s
, &p
->u
.prefix
, PSIZE(p
->prefixlen
));
4058 if (afi
== AFI_L2VPN
)
4059 /* EVPN prefix - contents depend on type */
4060 bgp_evpn_encode_prefix(s
, p
, prd
, label
, num_labels
,
4061 attr
, addpath_capable
,
4064 assert(!"Add encoding bits here for other AFI's");
4066 case SAFI_LABELED_UNICAST
:
4067 /* Prefix write with label. */
4068 stream_put_labeled_prefix(s
, p
, label
, addpath_capable
,
4072 stream_putc(s
, p
->u
.prefix_flowspec
.prefixlen
);
4073 stream_put(s
, (const void *)p
->u
.prefix_flowspec
.ptr
,
4074 p
->u
.prefix_flowspec
.prefixlen
);
4078 case SAFI_MULTICAST
:
4079 stream_put_prefix_addpath(s
, p
, addpath_capable
, addpath_tx_id
);
4082 assert(!"Please add proper encoding of SAFI_ENCAP");
4087 size_t bgp_packet_mpattr_prefix_size(afi_t afi
, safi_t safi
,
4088 const struct prefix
*p
)
4090 int size
= PSIZE(p
->prefixlen
);
4095 assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE");
4098 case SAFI_MULTICAST
:
4104 /* This has to be wrong, but I don't know what to put here */
4105 assert(!"Do we try to use this?");
4107 case SAFI_LABELED_UNICAST
:
4108 size
+= BGP_LABEL_BYTES
;
4112 * TODO: Maximum possible for type-2, type-3 and type-5
4114 if (afi
== AFI_L2VPN
)
4117 assert(!"Attempting to figure size for SAFI_EVPN and !AFI_L2VPN and FRR will not have the proper values");
4120 size
= ((struct prefix_fs
*)p
)->prefix
.prefixlen
;
4128 * Encodes the tunnel encapsulation attribute,
4129 * and with ENABLE_BGP_VNC the VNC attribute which uses
4130 * almost the same TLV format
4132 static void bgp_packet_mpattr_tea(struct bgp
*bgp
, struct peer
*peer
,
4133 struct stream
*s
, struct attr
*attr
,
4136 unsigned int attrlenfield
= 0;
4137 unsigned int attrhdrlen
= 0;
4138 struct bgp_attr_encap_subtlv
*subtlvs
;
4139 struct bgp_attr_encap_subtlv
*st
;
4140 const char *attrname
;
4142 if (!attr
|| (attrtype
== BGP_ATTR_ENCAP
4143 && (!attr
->encap_tunneltype
4144 || attr
->encap_tunneltype
== BGP_ENCAP_TYPE_MPLS
)))
4148 case BGP_ATTR_ENCAP
:
4149 attrname
= "Tunnel Encap";
4150 subtlvs
= attr
->encap_subtlvs
;
4151 if (subtlvs
== NULL
) /* nothing to do */
4154 * The tunnel encap attr has an "outer" tlv.
4156 * L = total length of subtlvs,
4157 * V = concatenated subtlvs.
4159 attrlenfield
= 2 + 2; /* T + L */
4160 attrhdrlen
= 1 + 1; /* subTLV T + L */
4163 #ifdef ENABLE_BGP_VNC_ATTR
4166 subtlvs
= bgp_attr_get_vnc_subtlvs(attr
);
4167 if (subtlvs
== NULL
) /* nothing to do */
4169 attrlenfield
= 0; /* no outer T + L */
4170 attrhdrlen
= 2 + 2; /* subTLV T + L */
4178 /* compute attr length */
4179 for (st
= subtlvs
; st
; st
= st
->next
) {
4180 attrlenfield
+= (attrhdrlen
+ st
->length
);
4183 if (attrlenfield
> 0xffff) {
4184 zlog_info("%s attribute is too long (length=%d), can't send it",
4185 attrname
, attrlenfield
);
4189 if (attrlenfield
> 0xff) {
4190 /* 2-octet length field */
4192 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4193 | BGP_ATTR_FLAG_EXTLEN
);
4194 stream_putc(s
, attrtype
);
4195 stream_putw(s
, attrlenfield
& 0xffff);
4197 /* 1-octet length field */
4198 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
);
4199 stream_putc(s
, attrtype
);
4200 stream_putc(s
, attrlenfield
& 0xff);
4203 if (attrtype
== BGP_ATTR_ENCAP
) {
4204 /* write outer T+L */
4205 stream_putw(s
, attr
->encap_tunneltype
);
4206 stream_putw(s
, attrlenfield
- 4);
4209 /* write each sub-tlv */
4210 for (st
= subtlvs
; st
; st
= st
->next
) {
4211 if (attrtype
== BGP_ATTR_ENCAP
) {
4212 stream_putc(s
, st
->type
);
4213 stream_putc(s
, st
->length
);
4214 #ifdef ENABLE_BGP_VNC
4216 stream_putw(s
, st
->type
);
4217 stream_putw(s
, st
->length
);
4220 stream_put(s
, st
->value
, st
->length
);
4224 void bgp_packet_mpattr_end(struct stream
*s
, size_t sizep
)
4226 /* Set MP attribute length. Don't count the (2) bytes used to encode
4228 stream_putw_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 2);
4231 static bool bgp_append_local_as(struct peer
*peer
, afi_t afi
, safi_t safi
)
4233 if (!BGP_AS_IS_PRIVATE(peer
->local_as
)
4234 || (BGP_AS_IS_PRIVATE(peer
->local_as
)
4235 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4236 PEER_FLAG_REMOVE_PRIVATE_AS
)
4237 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4238 PEER_FLAG_REMOVE_PRIVATE_AS_ALL
)
4239 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4240 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE
)
4241 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4242 PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE
)))
4247 /* Make attribute packet. */
4248 bgp_size_t
bgp_packet_attribute(struct bgp
*bgp
, struct peer
*peer
,
4249 struct stream
*s
, struct attr
*attr
,
4250 struct bpacket_attr_vec_arr
*vecarr
,
4251 struct prefix
*p
, afi_t afi
, safi_t safi
,
4252 struct peer
*from
, struct prefix_rd
*prd
,
4253 mpls_label_t
*label
, uint32_t num_labels
,
4254 bool addpath_capable
, uint32_t addpath_tx_id
,
4255 struct bgp_path_info
*bpi
)
4258 size_t aspath_sizep
;
4259 struct aspath
*aspath
;
4260 int send_as4_path
= 0;
4261 int send_as4_aggregator
= 0;
4262 bool use32bit
= CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
4263 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
);
4268 /* Remember current pointer. */
4269 cp
= stream_get_endp(s
);
4272 && !((afi
== AFI_IP
&& safi
== SAFI_UNICAST
)
4273 && !peer_cap_enhe(peer
, afi
, safi
))) {
4274 size_t mpattrlen_pos
= 0;
4276 mpattrlen_pos
= bgp_packet_mpattr_start(s
, peer
, afi
, safi
,
4278 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
,
4279 num_labels
, addpath_capable
,
4280 addpath_tx_id
, attr
);
4281 bgp_packet_mpattr_end(s
, mpattrlen_pos
);
4284 /* Origin attribute. */
4285 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4286 stream_putc(s
, BGP_ATTR_ORIGIN
);
4288 stream_putc(s
, attr
->origin
);
4290 /* AS path attribute. */
4292 /* If remote-peer is EBGP */
4293 if (peer
->sort
== BGP_PEER_EBGP
4294 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4295 PEER_FLAG_AS_PATH_UNCHANGED
)
4296 || attr
->aspath
->segments
== NULL
)
4297 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4298 PEER_FLAG_RSERVER_CLIENT
))) {
4299 aspath
= aspath_dup(attr
->aspath
);
4301 /* Even though we may not be configured for confederations we
4303 * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
4304 aspath
= aspath_delete_confed_seq(aspath
);
4306 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
)) {
4307 /* Stuff our path CONFED_ID on the front */
4308 aspath
= aspath_add_seq(aspath
, bgp
->confed_id
);
4310 if (peer
->change_local_as
) {
4311 /* If replace-as is specified, we only use the
4312 change_local_as when
4313 advertising routes. */
4314 if (!CHECK_FLAG(peer
->flags
,
4315 PEER_FLAG_LOCAL_AS_REPLACE_AS
))
4316 if (bgp_append_local_as(peer
, afi
,
4318 aspath
= aspath_add_seq(
4319 aspath
, peer
->local_as
);
4320 aspath
= aspath_add_seq(aspath
,
4321 peer
->change_local_as
);
4323 aspath
= aspath_add_seq(aspath
, peer
->local_as
);
4326 } else if (peer
->sort
== BGP_PEER_CONFED
) {
4327 /* A confed member, so we need to do the AS_CONFED_SEQUENCE
4329 aspath
= aspath_dup(attr
->aspath
);
4330 aspath
= aspath_add_confed_seq(aspath
, peer
->local_as
);
4332 aspath
= attr
->aspath
;
4334 /* If peer is not AS4 capable, then:
4335 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
4336 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
4338 * types are in it (i.e. exclude them if they are there)
4339 * AND do this only if there is at least one asnum > 65535 in the
4341 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
4343 * all ASnums > 65535 to BGP_AS_TRANS
4346 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4347 stream_putc(s
, BGP_ATTR_AS_PATH
);
4348 aspath_sizep
= stream_get_endp(s
);
4350 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, use32bit
));
4352 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
4355 if (!use32bit
&& aspath_has_as4(aspath
))
4357 1; /* we'll do this later, at the correct place */
4359 /* Nexthop attribute. */
4360 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
4361 && !peer_cap_enhe(peer
, afi
, safi
)) {
4362 afi_t nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
4364 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
)) {
4365 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4366 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4367 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4370 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4371 } else if (peer_cap_enhe(from
, afi
, safi
)
4372 || (nh_afi
== AFI_IP6
)) {
4374 * Likely this is the case when an IPv4 prefix was
4375 * received with Extended Next-hop capability in this
4376 * or another vrf and is now being advertised to
4377 * non-ENHE peers. Since peer_cap_enhe only checks
4378 * peers in this vrf, also check the nh_afi to catch
4379 * the case where the originator was in another vrf.
4380 * Setting the mandatory (ipv4) next-hop attribute here
4381 * to enable implicit next-hop self with correct A-F
4382 * (ipv4 address family).
4384 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4385 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4386 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4389 stream_put_ipv4(s
, 0);
4393 /* MED attribute. */
4394 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)
4395 || bgp
->maxmed_active
) {
4396 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4397 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4399 stream_putl(s
, (bgp
->maxmed_active
? bgp
->maxmed_value
4403 /* Local preference. */
4404 if (peer
->sort
== BGP_PEER_IBGP
|| peer
->sort
== BGP_PEER_CONFED
) {
4405 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4406 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4408 stream_putl(s
, attr
->local_pref
);
4411 /* Atomic aggregate. */
4412 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4413 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4414 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4419 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4420 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
4421 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4422 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4425 /* AS4 capable peer */
4427 stream_putl(s
, attr
->aggregator_as
);
4429 /* 2-byte AS peer */
4432 /* Is ASN representable in 2-bytes? Or must AS_TRANS be
4434 if (attr
->aggregator_as
> UINT16_MAX
) {
4435 stream_putw(s
, BGP_AS_TRANS
);
4437 /* we have to send AS4_AGGREGATOR, too.
4438 * we'll do that later in order to send
4439 * attributes in ascending
4442 send_as4_aggregator
= 1;
4444 stream_putw(s
, (uint16_t)attr
->aggregator_as
);
4446 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4449 /* Community attribute. */
4450 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
4451 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
))) {
4452 struct community
*comm
= NULL
;
4454 comm
= bgp_attr_get_community(attr
);
4455 if (comm
->size
* 4 > 255) {
4457 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4458 | BGP_ATTR_FLAG_EXTLEN
);
4459 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4460 stream_putw(s
, comm
->size
* 4);
4463 BGP_ATTR_FLAG_OPTIONAL
4464 | BGP_ATTR_FLAG_TRANS
);
4465 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4466 stream_putc(s
, comm
->size
* 4);
4468 stream_put(s
, comm
->val
, comm
->size
* 4);
4472 * Large Community attribute.
4474 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4475 PEER_FLAG_SEND_LARGE_COMMUNITY
)
4476 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
))) {
4477 if (lcom_length(bgp_attr_get_lcommunity(attr
)) > 255) {
4479 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4480 | BGP_ATTR_FLAG_EXTLEN
);
4481 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4483 lcom_length(bgp_attr_get_lcommunity(attr
)));
4486 BGP_ATTR_FLAG_OPTIONAL
4487 | BGP_ATTR_FLAG_TRANS
);
4488 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4490 lcom_length(bgp_attr_get_lcommunity(attr
)));
4492 stream_put(s
, bgp_attr_get_lcommunity(attr
)->val
,
4493 lcom_length(bgp_attr_get_lcommunity(attr
)));
4496 /* Route Reflector. */
4497 if (peer
->sort
== BGP_PEER_IBGP
&& from
4498 && from
->sort
== BGP_PEER_IBGP
) {
4499 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
4501 /* Originator ID. */
4502 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4503 stream_putc(s
, BGP_ATTR_ORIGINATOR_ID
);
4506 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
4507 stream_put_in_addr(s
, &attr
->originator_id
);
4509 stream_put_in_addr(s
, &from
->remote_id
);
4512 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4513 stream_putc(s
, BGP_ATTR_CLUSTER_LIST
);
4516 stream_putc(s
, cluster
->length
+ 4);
4517 /* If this peer configuration's parent BGP has
4519 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4520 stream_put_in_addr(s
, &bgp
->cluster_id
);
4522 stream_put_in_addr(s
, &bgp
->router_id
);
4523 stream_put(s
, cluster
->list
, cluster
->length
);
4526 /* If this peer configuration's parent BGP has
4528 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4529 stream_put_in_addr(s
, &bgp
->cluster_id
);
4531 stream_put_in_addr(s
, &bgp
->router_id
);
4535 /* Extended Communities attribute. */
4536 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
4537 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
))) {
4538 struct ecommunity
*ecomm
= bgp_attr_get_ecommunity(attr
);
4539 bool transparent
= CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4540 PEER_FLAG_RSERVER_CLIENT
) &&
4542 CHECK_FLAG(from
->af_flags
[afi
][safi
],
4543 PEER_FLAG_RSERVER_CLIENT
);
4545 if (peer
->sort
== BGP_PEER_IBGP
||
4546 peer
->sort
== BGP_PEER_CONFED
|| transparent
) {
4547 if (ecomm
->size
* 8 > 255) {
4549 BGP_ATTR_FLAG_OPTIONAL
4550 | BGP_ATTR_FLAG_TRANS
4551 | BGP_ATTR_FLAG_EXTLEN
);
4552 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4553 stream_putw(s
, ecomm
->size
* 8);
4556 BGP_ATTR_FLAG_OPTIONAL
4557 | BGP_ATTR_FLAG_TRANS
);
4558 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4559 stream_putc(s
, ecomm
->size
* 8);
4561 stream_put(s
, ecomm
->val
, ecomm
->size
* 8);
4565 int ecom_tr_size
= 0;
4568 for (i
= 0; i
< ecomm
->size
; i
++) {
4569 pnt
= ecomm
->val
+ (i
* 8);
4572 if (CHECK_FLAG(tbit
,
4573 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4580 if (ecom_tr_size
* 8 > 255) {
4583 BGP_ATTR_FLAG_OPTIONAL
4584 | BGP_ATTR_FLAG_TRANS
4585 | BGP_ATTR_FLAG_EXTLEN
);
4587 BGP_ATTR_EXT_COMMUNITIES
);
4588 stream_putw(s
, ecom_tr_size
* 8);
4592 BGP_ATTR_FLAG_OPTIONAL
4593 | BGP_ATTR_FLAG_TRANS
);
4595 BGP_ATTR_EXT_COMMUNITIES
);
4596 stream_putc(s
, ecom_tr_size
* 8);
4599 for (i
= 0; i
< ecomm
->size
; i
++) {
4600 pnt
= ecomm
->val
+ (i
* 8);
4605 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4608 stream_put(s
, pnt
, 8);
4614 /* Label index attribute. */
4615 if (safi
== SAFI_LABELED_UNICAST
) {
4616 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4617 uint32_t label_index
;
4619 label_index
= attr
->label_index
;
4621 if (label_index
!= BGP_INVALID_LABEL_INDEX
) {
4623 BGP_ATTR_FLAG_OPTIONAL
4624 | BGP_ATTR_FLAG_TRANS
);
4625 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4627 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4629 BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4630 stream_putc(s
, 0); // reserved
4631 stream_putw(s
, 0); // flags
4632 stream_putl(s
, label_index
);
4637 /* SRv6 Service Information Attribute. */
4638 if ((afi
== AFI_IP
|| afi
== AFI_IP6
) && safi
== SAFI_MPLS_VPN
) {
4639 if (attr
->srv6_l3vpn
) {
4640 uint8_t subtlv_len
=
4641 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
4643 + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
;
4644 uint8_t tlv_len
= subtlv_len
+ BGP_ATTR_MIN_LEN
+ 1;
4645 uint8_t attr_len
= tlv_len
+ BGP_ATTR_MIN_LEN
;
4646 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4647 | BGP_ATTR_FLAG_TRANS
);
4648 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4649 stream_putc(s
, attr_len
);
4650 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE
);
4651 stream_putw(s
, tlv_len
);
4652 stream_putc(s
, 0); /* reserved */
4653 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
);
4654 stream_putw(s
, subtlv_len
);
4655 stream_putc(s
, 0); /* reserved */
4656 stream_put(s
, &attr
->srv6_l3vpn
->sid
,
4657 sizeof(attr
->srv6_l3vpn
->sid
)); /* sid */
4658 stream_putc(s
, 0); /* sid_flags */
4661 ->endpoint_behavior
); /* endpoint */
4662 stream_putc(s
, 0); /* reserved */
4665 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
);
4668 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
);
4669 stream_putc(s
, attr
->srv6_l3vpn
->loc_block_len
);
4670 stream_putc(s
, attr
->srv6_l3vpn
->loc_node_len
);
4671 stream_putc(s
, attr
->srv6_l3vpn
->func_len
);
4672 stream_putc(s
, attr
->srv6_l3vpn
->arg_len
);
4673 stream_putc(s
, attr
->srv6_l3vpn
->transposition_len
);
4674 stream_putc(s
, attr
->srv6_l3vpn
->transposition_offset
);
4675 } else if (attr
->srv6_vpn
) {
4676 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4677 | BGP_ATTR_FLAG_TRANS
);
4678 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4679 stream_putc(s
, 22); /* tlv len */
4680 stream_putc(s
, BGP_PREFIX_SID_VPN_SID
);
4681 stream_putw(s
, 0x13); /* tlv len */
4682 stream_putc(s
, 0x00); /* reserved */
4683 stream_putc(s
, 0x01); /* sid_type */
4684 stream_putc(s
, 0x00); /* sif_flags */
4685 stream_put(s
, &attr
->srv6_vpn
->sid
,
4686 sizeof(attr
->srv6_vpn
->sid
)); /* sid */
4690 if (send_as4_path
) {
4691 /* If the peer is NOT As4 capable, AND */
4692 /* there are ASnums > 65535 in path THEN
4693 * give out AS4_PATH */
4695 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
4697 * Hm, I wonder... confederation things *should* only be at
4698 * the beginning of an aspath, right? Then we should use
4699 * aspath_delete_confed_seq for this, because it is already
4701 * Folks, talk to me: what is reasonable here!?
4703 aspath
= aspath_delete_confed_seq(aspath
);
4706 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4707 | BGP_ATTR_FLAG_EXTLEN
);
4708 stream_putc(s
, BGP_ATTR_AS4_PATH
);
4709 aspath_sizep
= stream_get_endp(s
);
4711 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, 1));
4714 if (aspath
!= attr
->aspath
)
4715 aspath_free(aspath
);
4717 if (send_as4_aggregator
) {
4718 /* send AS4_AGGREGATOR, at this place */
4719 /* this section of code moved here in order to ensure the
4721 * *ascending* order of attributes
4723 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4724 stream_putc(s
, BGP_ATTR_AS4_AGGREGATOR
);
4726 stream_putl(s
, attr
->aggregator_as
);
4727 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4730 if (((afi
== AFI_IP
|| afi
== AFI_IP6
)
4731 && (safi
== SAFI_ENCAP
|| safi
== SAFI_MPLS_VPN
))
4732 || (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)) {
4733 /* Tunnel Encap attribute */
4734 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_ENCAP
);
4736 #ifdef ENABLE_BGP_VNC_ATTR
4738 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_VNC
);
4743 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
)) {
4744 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4745 stream_putc(s
, BGP_ATTR_PMSI_TUNNEL
);
4746 stream_putc(s
, 9); // Length
4747 stream_putc(s
, 0); // Flags
4748 stream_putc(s
, bgp_attr_get_pmsi_tnl_type(attr
));
4749 stream_put(s
, &(attr
->label
),
4750 BGP_LABEL_BYTES
); // MPLS Label / VXLAN VNI
4751 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4752 // Unicast tunnel endpoint IP address
4756 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_OTC
)) {
4757 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4758 stream_putc(s
, BGP_ATTR_OTC
);
4760 stream_putl(s
, attr
->otc
);
4764 if (bpi
&& attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AIGP
) &&
4765 (CHECK_FLAG(peer
->flags
, PEER_FLAG_AIGP
) ||
4766 peer
->sort
!= BGP_PEER_EBGP
)) {
4767 /* At the moment only AIGP Metric TLV exists for AIGP
4768 * attribute. If more comes in, do not forget to update
4769 * attr_len variable to include new ones.
4771 uint8_t attr_len
= BGP_AIGP_TLV_METRIC_LEN
;
4773 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4774 stream_putc(s
, BGP_ATTR_AIGP
);
4775 stream_putc(s
, attr_len
);
4776 stream_put_bgp_aigp_tlv_metric(s
, bpi
);
4779 /* Unknown transit attribute. */
4780 struct transit
*transit
= bgp_attr_get_transit(attr
);
4783 stream_put(s
, transit
->val
, transit
->length
);
4785 /* Return total size of attribute. */
4786 return stream_get_endp(s
) - cp
;
4789 size_t bgp_packet_mpunreach_start(struct stream
*s
, afi_t afi
, safi_t safi
)
4791 unsigned long attrlen_pnt
;
4792 iana_afi_t pkt_afi
= IANA_AFI_IPV4
;
4793 iana_safi_t pkt_safi
= IANA_SAFI_UNICAST
;
4795 /* Set extended bit always to encode the attribute length as 2 bytes */
4796 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
4797 stream_putc(s
, BGP_ATTR_MP_UNREACH_NLRI
);
4799 attrlen_pnt
= stream_get_endp(s
);
4800 stream_putw(s
, 0); /* Length of this attribute. */
4802 /* Convert AFI, SAFI to values for packet. */
4803 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
4805 stream_putw(s
, pkt_afi
);
4806 stream_putc(s
, pkt_safi
);
4811 void bgp_packet_mpunreach_prefix(struct stream
*s
, const struct prefix
*p
,
4812 afi_t afi
, safi_t safi
,
4813 const struct prefix_rd
*prd
,
4814 mpls_label_t
*label
, uint32_t num_labels
,
4815 bool addpath_capable
, uint32_t addpath_tx_id
,
4818 uint8_t wlabel
[4] = {0x80, 0x00, 0x00};
4820 if (safi
== SAFI_LABELED_UNICAST
) {
4821 label
= (mpls_label_t
*)wlabel
;
4825 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
, num_labels
,
4826 addpath_capable
, addpath_tx_id
, attr
);
4829 void bgp_packet_mpunreach_end(struct stream
*s
, size_t attrlen_pnt
)
4831 bgp_packet_mpattr_end(s
, attrlen_pnt
);
4834 /* Initialization of attribute. */
4835 void bgp_attr_init(void)
4848 void bgp_attr_finish(void)
4853 ecommunity_finish();
4854 lcommunity_finish();
4861 /* Make attribute packet. */
4862 void bgp_dump_routes_attr(struct stream
*s
, struct bgp_path_info
*bpi
,
4863 const struct prefix
*prefix
)
4868 struct aspath
*aspath
;
4869 bool addpath_capable
= false;
4870 uint32_t addpath_tx_id
= 0;
4871 struct attr
*attr
= bpi
->attr
;
4873 /* Remember current pointer. */
4874 cp
= stream_get_endp(s
);
4876 /* Place holder of length. */
4879 /* Origin attribute. */
4880 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4881 stream_putc(s
, BGP_ATTR_ORIGIN
);
4883 stream_putc(s
, attr
->origin
);
4885 aspath
= attr
->aspath
;
4887 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4888 stream_putc(s
, BGP_ATTR_AS_PATH
);
4889 aspath_lenp
= stream_get_endp(s
);
4892 stream_putw_at(s
, aspath_lenp
, aspath_put(s
, aspath
, 1));
4894 /* Nexthop attribute. */
4895 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
4896 if (prefix
!= NULL
&& prefix
->family
!= AF_INET6
) {
4897 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4898 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4900 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4903 /* MED attribute. */
4904 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)) {
4905 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4906 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4908 stream_putl(s
, attr
->med
);
4911 /* Local preference. */
4912 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)) {
4913 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4914 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4916 stream_putl(s
, attr
->local_pref
);
4919 /* Atomic aggregate. */
4920 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4921 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4922 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4927 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4928 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4929 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4931 stream_putl(s
, attr
->aggregator_as
);
4932 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4935 /* Community attribute. */
4936 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
)) {
4937 struct community
*comm
= NULL
;
4939 comm
= bgp_attr_get_community(attr
);
4940 if (comm
->size
* 4 > 255) {
4942 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4943 | BGP_ATTR_FLAG_EXTLEN
);
4944 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4945 stream_putw(s
, comm
->size
* 4);
4948 BGP_ATTR_FLAG_OPTIONAL
4949 | BGP_ATTR_FLAG_TRANS
);
4950 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4951 stream_putc(s
, comm
->size
* 4);
4953 stream_put(s
, comm
->val
, comm
->size
* 4);
4956 /* Large Community attribute. */
4957 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
)) {
4958 if (lcom_length(bgp_attr_get_lcommunity(attr
)) > 255) {
4960 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4961 | BGP_ATTR_FLAG_EXTLEN
);
4962 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4964 lcom_length(bgp_attr_get_lcommunity(attr
)));
4967 BGP_ATTR_FLAG_OPTIONAL
4968 | BGP_ATTR_FLAG_TRANS
);
4969 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4971 lcom_length(bgp_attr_get_lcommunity(attr
)));
4974 stream_put(s
, bgp_attr_get_lcommunity(attr
)->val
,
4975 lcom_length(bgp_attr_get_lcommunity(attr
)));
4978 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
4979 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
4980 && (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL
4981 || attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)) {
4984 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4985 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
4986 sizep
= stream_get_endp(s
);
4989 stream_putc(s
, 0); /* Marker: Attribute length. */
4990 stream_putw(s
, AFI_IP6
); /* AFI */
4991 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
4994 stream_putc(s
, attr
->mp_nexthop_len
);
4995 stream_put(s
, &attr
->mp_nexthop_global
, IPV6_MAX_BYTELEN
);
4996 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)
4997 stream_put(s
, &attr
->mp_nexthop_local
,
5004 stream_put_prefix_addpath(s
, prefix
, addpath_capable
,
5007 /* Set MP attribute length. */
5008 stream_putc_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 1);
5012 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
5013 if (attr
->label_index
!= BGP_INVALID_LABEL_INDEX
) {
5015 BGP_ATTR_FLAG_OPTIONAL
5016 | BGP_ATTR_FLAG_TRANS
);
5017 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
5019 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
5020 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
5021 stream_putc(s
, 0); // reserved
5022 stream_putw(s
, 0); // flags
5023 stream_putl(s
, attr
->label_index
);
5028 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_OTC
)) {
5029 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
5030 stream_putc(s
, BGP_ATTR_OTC
);
5032 stream_putl(s
, attr
->otc
);
5036 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AIGP
)) {
5037 /* At the moment only AIGP Metric TLV exists for AIGP
5038 * attribute. If more comes in, do not forget to update
5039 * attr_len variable to include new ones.
5041 uint8_t attr_len
= BGP_AIGP_TLV_METRIC_LEN
;
5043 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
5044 stream_putc(s
, BGP_ATTR_AIGP
);
5045 stream_putc(s
, attr_len
);
5046 stream_put_bgp_aigp_tlv_metric(s
, bpi
);
5049 /* Return total size of attribute. */
5050 len
= stream_get_endp(s
) - cp
- 2;
5051 stream_putw_at(s
, cp
, len
);
5054 void bgp_path_attribute_discard_vty(struct vty
*vty
, struct peer
*peer
,
5055 const char *discard_attrs
, bool set
)
5057 int i
, num_attributes
;
5063 /* If `no` command specified without arbitrary attributes,
5066 if (!discard_attrs
) {
5067 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5068 peer
->discard_attrs
[i
] = false;
5069 goto discard_soft_clear
;
5072 if (discard_attrs
) {
5073 frrstr_split(discard_attrs
, " ", &attributes
, &num_attributes
);
5076 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5077 peer
->discard_attrs
[i
] = false;
5079 for (i
= 0; i
< num_attributes
; i
++) {
5080 uint8_t attr_num
= strtoul(attributes
[i
], NULL
, 10);
5082 XFREE(MTYPE_TMP
, attributes
[i
]);
5084 /* Some of the attributes, just can't be ignored. */
5085 if (attr_num
== BGP_ATTR_ORIGIN
||
5086 attr_num
== BGP_ATTR_AS_PATH
||
5087 attr_num
== BGP_ATTR_NEXT_HOP
||
5088 attr_num
== BGP_ATTR_MULTI_EXIT_DISC
||
5089 attr_num
== BGP_ATTR_MP_REACH_NLRI
||
5090 attr_num
== BGP_ATTR_MP_UNREACH_NLRI
||
5091 attr_num
== BGP_ATTR_EXT_COMMUNITIES
) {
5093 "%% Can't discard path-attribute %s, ignoring.\n",
5094 lookup_msg(attr_str
, attr_num
, NULL
));
5098 /* Ignore local-pref, originator-id, cluster-list only
5101 if (peer
->sort
!= BGP_PEER_EBGP
&&
5102 (attr_num
== BGP_ATTR_LOCAL_PREF
||
5103 attr_num
== BGP_ATTR_ORIGINATOR_ID
||
5104 attr_num
== BGP_ATTR_CLUSTER_LIST
)) {
5106 "%% Can discard path-attribute %s only for eBGP, ignoring.\n",
5107 lookup_msg(attr_str
, attr_num
, NULL
));
5111 peer
->discard_attrs
[attr_num
] = set
;
5113 XFREE(MTYPE_TMP
, attributes
);
5115 /* Configuring path attributes to be discarded will trigger
5116 * an inbound Route Refresh to ensure that the routing table
5119 FOREACH_AFI_SAFI (afi
, safi
)
5120 peer_clear_soft(peer
, afi
, safi
, BGP_CLEAR_SOFT_IN
);
5124 void bgp_path_attribute_withdraw_vty(struct vty
*vty
, struct peer
*peer
,
5125 const char *withdraw_attrs
, bool set
)
5127 int i
, num_attributes
;
5132 /* If `no` command specified without arbitrary attributes,
5135 if (!withdraw_attrs
) {
5136 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5137 peer
->withdraw_attrs
[i
] = false;
5138 goto withdraw_soft_clear
;
5141 if (withdraw_attrs
) {
5142 frrstr_split(withdraw_attrs
, " ", &attributes
, &num_attributes
);
5145 for (i
= 0; i
< BGP_ATTR_MAX
; i
++)
5146 peer
->withdraw_attrs
[i
] = false;
5148 for (i
= 0; i
< num_attributes
; i
++) {
5149 uint8_t attr_num
= strtoul(attributes
[i
], NULL
, 10);
5151 XFREE(MTYPE_TMP
, attributes
[i
]);
5153 /* Some of the attributes, just can't be ignored. */
5154 if (attr_num
== BGP_ATTR_ORIGIN
||
5155 attr_num
== BGP_ATTR_AS_PATH
||
5156 attr_num
== BGP_ATTR_NEXT_HOP
||
5157 attr_num
== BGP_ATTR_MULTI_EXIT_DISC
||
5158 attr_num
== BGP_ATTR_MP_REACH_NLRI
||
5159 attr_num
== BGP_ATTR_MP_UNREACH_NLRI
||
5160 attr_num
== BGP_ATTR_EXT_COMMUNITIES
) {
5162 "%% Can't treat-as-withdraw path-attribute %s, ignoring.\n",
5163 lookup_msg(attr_str
, attr_num
, NULL
));
5167 /* Ignore local-pref, originator-id, cluster-list only
5170 if (peer
->sort
!= BGP_PEER_EBGP
&&
5171 (attr_num
== BGP_ATTR_LOCAL_PREF
||
5172 attr_num
== BGP_ATTR_ORIGINATOR_ID
||
5173 attr_num
== BGP_ATTR_CLUSTER_LIST
)) {
5175 "%% Can treat-as-withdraw path-attribute %s only for eBGP, ignoring.\n",
5176 lookup_msg(attr_str
, attr_num
, NULL
));
5180 peer
->withdraw_attrs
[attr_num
] = set
;
5182 XFREE(MTYPE_TMP
, attributes
);
5183 withdraw_soft_clear
:
5184 /* Configuring path attributes to be treated as withdraw will
5186 * an inbound Route Refresh to ensure that the routing table
5189 FOREACH_AFI_SAFI (afi
, safi
)
5190 peer_clear_soft(peer
, afi
, safi
, BGP_CLEAR_SOFT_IN
);
5194 enum bgp_attr_parse_ret
bgp_attr_ignore(struct peer
*peer
, uint8_t type
)
5196 bool discard
= peer
->discard_attrs
[type
];
5197 bool withdraw
= peer
->withdraw_attrs
[type
];
5199 if (bgp_debug_update(peer
, NULL
, NULL
, 1) && (discard
|| withdraw
))
5200 zlog_debug("%pBP: Ignoring attribute %s (%s)", peer
,
5201 lookup_msg(attr_str
, type
, NULL
),
5202 withdraw
? "treat-as-withdraw" : "discard");
5204 return withdraw
? BGP_ATTR_PARSE_WITHDRAW
: BGP_ATTR_PARSE_PROCEED
;