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
37 #include "bgpd/bgpd.h"
38 #include "bgpd/bgp_attr.h"
39 #include "bgpd/bgp_route.h"
40 #include "bgpd/bgp_aspath.h"
41 #include "bgpd/bgp_community.h"
42 #include "bgpd/bgp_debug.h"
43 #include "bgpd/bgp_errors.h"
44 #include "bgpd/bgp_label.h"
45 #include "bgpd/bgp_packet.h"
46 #include "bgpd/bgp_ecommunity.h"
47 #include "bgpd/bgp_lcommunity.h"
48 #include "bgpd/bgp_updgrp.h"
49 #include "bgpd/bgp_encap_types.h"
51 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
52 #include "bgp_encap_types.h"
53 #include "bgp_vnc_types.h"
56 #include "bgp_flowspec_private.h"
59 /* Attribute strings for logging. */
60 static const struct message attr_str
[] = {
61 {BGP_ATTR_ORIGIN
, "ORIGIN"},
62 {BGP_ATTR_AS_PATH
, "AS_PATH"},
63 {BGP_ATTR_NEXT_HOP
, "NEXT_HOP"},
64 {BGP_ATTR_MULTI_EXIT_DISC
, "MULTI_EXIT_DISC"},
65 {BGP_ATTR_LOCAL_PREF
, "LOCAL_PREF"},
66 {BGP_ATTR_ATOMIC_AGGREGATE
, "ATOMIC_AGGREGATE"},
67 {BGP_ATTR_AGGREGATOR
, "AGGREGATOR"},
68 {BGP_ATTR_COMMUNITIES
, "COMMUNITY"},
69 {BGP_ATTR_ORIGINATOR_ID
, "ORIGINATOR_ID"},
70 {BGP_ATTR_CLUSTER_LIST
, "CLUSTER_LIST"},
71 {BGP_ATTR_MP_REACH_NLRI
, "MP_REACH_NLRI"},
72 {BGP_ATTR_MP_UNREACH_NLRI
, "MP_UNREACH_NLRI"},
73 {BGP_ATTR_EXT_COMMUNITIES
, "EXT_COMMUNITIES"},
74 {BGP_ATTR_AS4_PATH
, "AS4_PATH"},
75 {BGP_ATTR_AS4_AGGREGATOR
, "AS4_AGGREGATOR"},
76 {BGP_ATTR_AS_PATHLIMIT
, "AS_PATHLIMIT"},
77 {BGP_ATTR_PMSI_TUNNEL
, "PMSI_TUNNEL_ATTRIBUTE"},
78 {BGP_ATTR_ENCAP
, "ENCAP"},
79 #ifdef ENABLE_BGP_VNC_ATTR
80 {BGP_ATTR_VNC
, "VNC"},
82 {BGP_ATTR_LARGE_COMMUNITIES
, "LARGE_COMMUNITY"},
83 {BGP_ATTR_PREFIX_SID
, "PREFIX_SID"},
84 {BGP_ATTR_IPV6_EXT_COMMUNITIES
, "IPV6_EXT_COMMUNITIES"},
87 static const struct message attr_flag_str
[] = {
88 {BGP_ATTR_FLAG_OPTIONAL
, "Optional"},
89 {BGP_ATTR_FLAG_TRANS
, "Transitive"},
90 {BGP_ATTR_FLAG_PARTIAL
, "Partial"},
91 /* bgp_attr_flags_diagnose() relies on this bit being last in
93 {BGP_ATTR_FLAG_EXTLEN
, "Extended Length"},
96 static struct hash
*cluster_hash
;
98 static void *cluster_hash_alloc(void *p
)
100 const struct cluster_list
*val
= (const struct cluster_list
*)p
;
101 struct cluster_list
*cluster
;
103 cluster
= XMALLOC(MTYPE_CLUSTER
, sizeof(struct cluster_list
));
104 cluster
->length
= val
->length
;
106 if (cluster
->length
) {
107 cluster
->list
= XMALLOC(MTYPE_CLUSTER_VAL
, val
->length
);
108 memcpy(cluster
->list
, val
->list
, val
->length
);
110 cluster
->list
= NULL
;
117 /* Cluster list related functions. */
118 static struct cluster_list
*cluster_parse(struct in_addr
*pnt
, int length
)
120 struct cluster_list tmp
= {};
121 struct cluster_list
*cluster
;
124 tmp
.list
= length
== 0 ? NULL
: pnt
;
126 cluster
= hash_get(cluster_hash
, &tmp
, cluster_hash_alloc
);
131 bool cluster_loop_check(struct cluster_list
*cluster
, struct in_addr originator
)
135 for (i
= 0; i
< cluster
->length
/ 4; i
++)
136 if (cluster
->list
[i
].s_addr
== originator
.s_addr
)
141 static unsigned int cluster_hash_key_make(const void *p
)
143 const struct cluster_list
*cluster
= p
;
145 return jhash(cluster
->list
, cluster
->length
, 0);
148 static bool cluster_hash_cmp(const void *p1
, const void *p2
)
150 const struct cluster_list
*cluster1
= p1
;
151 const struct cluster_list
*cluster2
= p2
;
153 if (cluster1
->list
== cluster2
->list
)
156 if (!cluster1
->list
|| !cluster2
->list
)
159 if (cluster1
->length
!= cluster2
->length
)
162 return (memcmp(cluster1
->list
, cluster2
->list
, cluster1
->length
) == 0);
165 static void cluster_free(struct cluster_list
*cluster
)
167 XFREE(MTYPE_CLUSTER_VAL
, cluster
->list
);
168 XFREE(MTYPE_CLUSTER
, cluster
);
171 static struct cluster_list
*cluster_intern(struct cluster_list
*cluster
)
173 struct cluster_list
*find
;
175 find
= hash_get(cluster_hash
, cluster
, cluster_hash_alloc
);
181 static void cluster_unintern(struct cluster_list
**cluster
)
183 if ((*cluster
)->refcnt
)
184 (*cluster
)->refcnt
--;
186 if ((*cluster
)->refcnt
== 0) {
187 void *p
= hash_release(cluster_hash
, *cluster
);
188 assert(p
== *cluster
);
189 cluster_free(*cluster
);
194 static void cluster_init(void)
196 cluster_hash
= hash_create(cluster_hash_key_make
, cluster_hash_cmp
,
200 static void cluster_finish(void)
202 hash_clean(cluster_hash
, (void (*)(void *))cluster_free
);
203 hash_free(cluster_hash
);
207 static struct hash
*encap_hash
= NULL
;
208 #ifdef ENABLE_BGP_VNC
209 static struct hash
*vnc_hash
= NULL
;
211 static struct hash
*srv6_l3vpn_hash
;
212 static struct hash
*srv6_vpn_hash
;
214 struct bgp_attr_encap_subtlv
*encap_tlv_dup(struct bgp_attr_encap_subtlv
*orig
)
216 struct bgp_attr_encap_subtlv
*new;
217 struct bgp_attr_encap_subtlv
*tail
;
218 struct bgp_attr_encap_subtlv
*p
;
220 for (p
= orig
, tail
= new = NULL
; p
; p
= p
->next
) {
221 int size
= sizeof(struct bgp_attr_encap_subtlv
) + p
->length
;
223 tail
->next
= XCALLOC(MTYPE_ENCAP_TLV
, size
);
226 tail
= new = XCALLOC(MTYPE_ENCAP_TLV
, size
);
229 memcpy(tail
, p
, size
);
236 static void encap_free(struct bgp_attr_encap_subtlv
*p
)
238 struct bgp_attr_encap_subtlv
*next
;
242 XFREE(MTYPE_ENCAP_TLV
, p
);
247 void bgp_attr_flush_encap(struct attr
*attr
)
252 if (attr
->encap_subtlvs
) {
253 encap_free(attr
->encap_subtlvs
);
254 attr
->encap_subtlvs
= NULL
;
256 #ifdef ENABLE_BGP_VNC
257 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
258 bgp_attr_get_vnc_subtlvs(attr
);
261 encap_free(vnc_subtlvs
);
262 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
268 * Compare encap sub-tlv chains
273 * This algorithm could be made faster if needed
275 static bool encap_same(const struct bgp_attr_encap_subtlv
*h1
,
276 const struct bgp_attr_encap_subtlv
*h2
)
278 const struct bgp_attr_encap_subtlv
*p
;
279 const struct bgp_attr_encap_subtlv
*q
;
283 if (h1
== NULL
|| h2
== NULL
)
286 for (p
= h1
; p
; p
= p
->next
) {
287 for (q
= h2
; q
; q
= q
->next
) {
288 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
289 && !memcmp(p
->value
, q
->value
, p
->length
)) {
298 for (p
= h2
; p
; p
= p
->next
) {
299 for (q
= h1
; q
; q
= q
->next
) {
300 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
301 && !memcmp(p
->value
, q
->value
, p
->length
)) {
313 static void *encap_hash_alloc(void *p
)
315 /* Encap structure is already allocated. */
321 #ifdef ENABLE_BGP_VNC
326 static struct bgp_attr_encap_subtlv
*
327 encap_intern(struct bgp_attr_encap_subtlv
*encap
, encap_subtlv_type type
)
329 struct bgp_attr_encap_subtlv
*find
;
330 struct hash
*hash
= encap_hash
;
331 #ifdef ENABLE_BGP_VNC
332 if (type
== VNC_SUBTLV_TYPE
)
336 find
= hash_get(hash
, encap
, encap_hash_alloc
);
344 static void encap_unintern(struct bgp_attr_encap_subtlv
**encapp
,
345 encap_subtlv_type type
)
347 struct bgp_attr_encap_subtlv
*encap
= *encapp
;
351 if (encap
->refcnt
== 0) {
352 struct hash
*hash
= encap_hash
;
353 #ifdef ENABLE_BGP_VNC
354 if (type
== VNC_SUBTLV_TYPE
)
357 hash_release(hash
, encap
);
363 static unsigned int encap_hash_key_make(const void *p
)
365 const struct bgp_attr_encap_subtlv
*encap
= p
;
367 return jhash(encap
->value
, encap
->length
, 0);
370 static bool encap_hash_cmp(const void *p1
, const void *p2
)
372 return encap_same((const struct bgp_attr_encap_subtlv
*)p1
,
373 (const struct bgp_attr_encap_subtlv
*)p2
);
376 static void encap_init(void)
378 encap_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
380 #ifdef ENABLE_BGP_VNC
381 vnc_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
386 static void encap_finish(void)
388 hash_clean(encap_hash
, (void (*)(void *))encap_free
);
389 hash_free(encap_hash
);
391 #ifdef ENABLE_BGP_VNC
392 hash_clean(vnc_hash
, (void (*)(void *))encap_free
);
398 static bool overlay_index_same(const struct attr
*a1
, const struct attr
*a2
)
407 return bgp_route_evpn_same(bgp_attr_get_evpn_overlay(a1
),
408 bgp_attr_get_evpn_overlay(a2
));
411 /* Unknown transit attribute. */
412 static struct hash
*transit_hash
;
414 static void transit_free(struct transit
*transit
)
416 XFREE(MTYPE_TRANSIT_VAL
, transit
->val
);
417 XFREE(MTYPE_TRANSIT
, transit
);
420 static void *transit_hash_alloc(void *p
)
422 /* Transit structure is already allocated. */
426 static struct transit
*transit_intern(struct transit
*transit
)
428 struct transit
*find
;
430 find
= hash_get(transit_hash
, transit
, transit_hash_alloc
);
432 transit_free(transit
);
438 static void transit_unintern(struct transit
**transit
)
440 if ((*transit
)->refcnt
)
441 (*transit
)->refcnt
--;
443 if ((*transit
)->refcnt
== 0) {
444 hash_release(transit_hash
, *transit
);
445 transit_free(*transit
);
450 static void *srv6_l3vpn_hash_alloc(void *p
)
455 static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn
*l3vpn
)
457 XFREE(MTYPE_BGP_SRV6_L3VPN
, l3vpn
);
460 static struct bgp_attr_srv6_l3vpn
*
461 srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn
*l3vpn
)
463 struct bgp_attr_srv6_l3vpn
*find
;
465 find
= hash_get(srv6_l3vpn_hash
, l3vpn
, srv6_l3vpn_hash_alloc
);
467 srv6_l3vpn_free(l3vpn
);
472 static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn
**l3vpnp
)
474 struct bgp_attr_srv6_l3vpn
*l3vpn
= *l3vpnp
;
479 if (l3vpn
->refcnt
== 0) {
480 hash_release(srv6_l3vpn_hash
, l3vpn
);
481 srv6_l3vpn_free(l3vpn
);
486 static void *srv6_vpn_hash_alloc(void *p
)
491 static void srv6_vpn_free(struct bgp_attr_srv6_vpn
*vpn
)
493 XFREE(MTYPE_BGP_SRV6_VPN
, vpn
);
496 static struct bgp_attr_srv6_vpn
*srv6_vpn_intern(struct bgp_attr_srv6_vpn
*vpn
)
498 struct bgp_attr_srv6_vpn
*find
;
500 find
= hash_get(srv6_vpn_hash
, vpn
, srv6_vpn_hash_alloc
);
507 static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn
**vpnp
)
509 struct bgp_attr_srv6_vpn
*vpn
= *vpnp
;
514 if (vpn
->refcnt
== 0) {
515 hash_release(srv6_vpn_hash
, vpn
);
521 static uint32_t srv6_l3vpn_hash_key_make(const void *p
)
523 const struct bgp_attr_srv6_l3vpn
*l3vpn
= p
;
526 key
= jhash(&l3vpn
->sid
, 16, key
);
527 key
= jhash_1word(l3vpn
->sid_flags
, key
);
528 key
= jhash_1word(l3vpn
->endpoint_behavior
, key
);
529 key
= jhash_1word(l3vpn
->loc_block_len
, key
);
530 key
= jhash_1word(l3vpn
->loc_node_len
, key
);
531 key
= jhash_1word(l3vpn
->func_len
, key
);
532 key
= jhash_1word(l3vpn
->arg_len
, key
);
533 key
= jhash_1word(l3vpn
->transposition_len
, key
);
534 key
= jhash_1word(l3vpn
->transposition_offset
, key
);
538 static bool srv6_l3vpn_hash_cmp(const void *p1
, const void *p2
)
540 const struct bgp_attr_srv6_l3vpn
*l3vpn1
= p1
;
541 const struct bgp_attr_srv6_l3vpn
*l3vpn2
= p2
;
543 return sid_same(&l3vpn1
->sid
, &l3vpn2
->sid
)
544 && l3vpn1
->sid_flags
== l3vpn2
->sid_flags
545 && l3vpn1
->endpoint_behavior
== l3vpn2
->endpoint_behavior
546 && l3vpn1
->loc_block_len
== l3vpn2
->loc_block_len
547 && l3vpn1
->loc_node_len
== l3vpn2
->loc_node_len
548 && l3vpn1
->func_len
== l3vpn2
->func_len
549 && l3vpn1
->arg_len
== l3vpn2
->arg_len
550 && l3vpn1
->transposition_len
== l3vpn2
->transposition_len
551 && l3vpn1
->transposition_offset
== l3vpn2
->transposition_offset
;
554 static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn
*h1
,
555 const struct bgp_attr_srv6_l3vpn
*h2
)
559 else if (h1
== NULL
|| h2
== NULL
)
562 return srv6_l3vpn_hash_cmp((const void *)h1
, (const void *)h2
);
565 static unsigned int srv6_vpn_hash_key_make(const void *p
)
567 const struct bgp_attr_srv6_vpn
*vpn
= p
;
570 key
= jhash(&vpn
->sid
, 16, key
);
571 key
= jhash_1word(vpn
->sid_flags
, key
);
575 static bool srv6_vpn_hash_cmp(const void *p1
, const void *p2
)
577 const struct bgp_attr_srv6_vpn
*vpn1
= p1
;
578 const struct bgp_attr_srv6_vpn
*vpn2
= p2
;
580 return sid_same(&vpn1
->sid
, &vpn2
->sid
)
581 && vpn1
->sid_flags
== vpn2
->sid_flags
;
584 static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn
*h1
,
585 const struct bgp_attr_srv6_vpn
*h2
)
589 else if (h1
== NULL
|| h2
== NULL
)
592 return srv6_vpn_hash_cmp((const void *)h1
, (const void *)h2
);
595 static void srv6_init(void)
598 hash_create(srv6_l3vpn_hash_key_make
, srv6_l3vpn_hash_cmp
,
599 "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
600 srv6_vpn_hash
= hash_create(srv6_vpn_hash_key_make
, srv6_vpn_hash_cmp
,
601 "BGP Prefix-SID SRv6-VPN-Service-TLV");
604 static void srv6_finish(void)
606 hash_clean(srv6_l3vpn_hash
, (void (*)(void *))srv6_l3vpn_free
);
607 hash_free(srv6_l3vpn_hash
);
608 srv6_l3vpn_hash
= NULL
;
609 hash_clean(srv6_vpn_hash
, (void (*)(void *))srv6_vpn_free
);
610 hash_free(srv6_vpn_hash
);
611 srv6_vpn_hash
= NULL
;
614 static unsigned int transit_hash_key_make(const void *p
)
616 const struct transit
*transit
= p
;
618 return jhash(transit
->val
, transit
->length
, 0);
621 static bool transit_hash_cmp(const void *p1
, const void *p2
)
623 const struct transit
*transit1
= p1
;
624 const struct transit
*transit2
= p2
;
626 return (transit1
->length
== transit2
->length
627 && memcmp(transit1
->val
, transit2
->val
, transit1
->length
) == 0);
630 static void transit_init(void)
632 transit_hash
= hash_create(transit_hash_key_make
, transit_hash_cmp
,
636 static void transit_finish(void)
638 hash_clean(transit_hash
, (void (*)(void *))transit_free
);
639 hash_free(transit_hash
);
643 /* Attribute hash routines. */
644 static struct hash
*attrhash
;
646 unsigned long int attr_count(void)
648 return attrhash
->count
;
651 unsigned long int attr_unknown_count(void)
653 return transit_hash
->count
;
656 unsigned int attrhash_key_make(const void *p
)
658 const struct attr
*attr
= (struct attr
*)p
;
660 #define MIX(val) key = jhash_1word(val, key)
661 #define MIX3(a, b, c) key = jhash_3words((a), (b), (c), key)
663 MIX3(attr
->origin
, attr
->nexthop
.s_addr
, attr
->med
);
664 MIX3(attr
->local_pref
, attr
->aggregator_as
,
665 attr
->aggregator_addr
.s_addr
);
666 MIX3(attr
->weight
, attr
->mp_nexthop_global_in
.s_addr
,
667 attr
->originator_id
.s_addr
);
668 MIX3(attr
->tag
, attr
->label
, attr
->label_index
);
671 MIX(aspath_key_make(attr
->aspath
));
673 MIX(community_hash_make(attr
->community
));
675 if (attr
->lcommunity
)
676 MIX(lcommunity_hash_make(attr
->lcommunity
));
677 if (attr
->ecommunity
)
678 MIX(ecommunity_hash_make(attr
->ecommunity
));
679 if (bgp_attr_get_ipv6_ecommunity(attr
))
680 MIX(ecommunity_hash_make(bgp_attr_get_ipv6_ecommunity(attr
)));
681 if (bgp_attr_get_cluster(attr
))
682 MIX(cluster_hash_key_make(bgp_attr_get_cluster(attr
)));
683 if (bgp_attr_get_transit(attr
))
684 MIX(transit_hash_key_make(bgp_attr_get_transit(attr
)));
685 if (attr
->encap_subtlvs
)
686 MIX(encap_hash_key_make(attr
->encap_subtlvs
));
687 if (attr
->srv6_l3vpn
)
688 MIX(srv6_l3vpn_hash_key_make(attr
->srv6_l3vpn
));
690 MIX(srv6_vpn_hash_key_make(attr
->srv6_vpn
));
691 #ifdef ENABLE_BGP_VNC
692 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
693 bgp_attr_get_vnc_subtlvs(attr
);
695 MIX(encap_hash_key_make(vnc_subtlvs
));
697 MIX(attr
->mp_nexthop_len
);
698 key
= jhash(attr
->mp_nexthop_global
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
699 key
= jhash(attr
->mp_nexthop_local
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
700 MIX3(attr
->nh_ifindex
, attr
->nh_lla_ifindex
, attr
->distance
);
701 MIX(attr
->rmap_table_id
);
708 bool attrhash_cmp(const void *p1
, const void *p2
)
710 const struct attr
*attr1
= p1
;
711 const struct attr
*attr2
= p2
;
713 if (attr1
->flag
== attr2
->flag
&& attr1
->origin
== attr2
->origin
714 && attr1
->nexthop
.s_addr
== attr2
->nexthop
.s_addr
715 && attr1
->aspath
== attr2
->aspath
716 && attr1
->community
== attr2
->community
&& attr1
->med
== attr2
->med
717 && attr1
->local_pref
== attr2
->local_pref
718 && attr1
->rmap_change_flags
== attr2
->rmap_change_flags
) {
719 if (attr1
->aggregator_as
== attr2
->aggregator_as
720 && attr1
->aggregator_addr
.s_addr
721 == attr2
->aggregator_addr
.s_addr
722 && attr1
->weight
== attr2
->weight
723 && attr1
->tag
== attr2
->tag
724 && attr1
->label_index
== attr2
->label_index
725 && attr1
->mp_nexthop_len
== attr2
->mp_nexthop_len
726 && attr1
->ecommunity
== attr2
->ecommunity
727 && bgp_attr_get_ipv6_ecommunity(attr1
)
728 == bgp_attr_get_ipv6_ecommunity(attr2
)
729 && attr1
->lcommunity
== attr2
->lcommunity
730 && bgp_attr_get_cluster(attr1
)
731 == bgp_attr_get_cluster(attr2
)
732 && bgp_attr_get_transit(attr1
)
733 == bgp_attr_get_transit(attr2
)
734 && attr1
->rmap_table_id
== attr2
->rmap_table_id
735 && (attr1
->encap_tunneltype
== attr2
->encap_tunneltype
)
736 && encap_same(attr1
->encap_subtlvs
, attr2
->encap_subtlvs
)
737 #ifdef ENABLE_BGP_VNC
738 && encap_same(bgp_attr_get_vnc_subtlvs(attr1
),
739 bgp_attr_get_vnc_subtlvs(attr2
))
741 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_global
,
742 &attr2
->mp_nexthop_global
)
743 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_local
,
744 &attr2
->mp_nexthop_local
)
745 && IPV4_ADDR_SAME(&attr1
->mp_nexthop_global_in
,
746 &attr2
->mp_nexthop_global_in
)
747 && IPV4_ADDR_SAME(&attr1
->originator_id
,
748 &attr2
->originator_id
)
749 && overlay_index_same(attr1
, attr2
)
750 && !memcmp(&attr1
->esi
, &attr2
->esi
, sizeof(esi_t
))
751 && attr1
->es_flags
== attr2
->es_flags
752 && attr1
->mm_sync_seqnum
== attr2
->mm_sync_seqnum
753 && attr1
->df_pref
== attr2
->df_pref
754 && attr1
->df_alg
== attr2
->df_alg
755 && attr1
->nh_ifindex
== attr2
->nh_ifindex
756 && attr1
->nh_lla_ifindex
== attr2
->nh_lla_ifindex
757 && attr1
->distance
== attr2
->distance
758 && srv6_l3vpn_same(attr1
->srv6_l3vpn
, attr2
->srv6_l3vpn
)
759 && srv6_vpn_same(attr1
->srv6_vpn
, attr2
->srv6_vpn
)
760 && attr1
->srte_color
== attr2
->srte_color
761 && attr1
->nh_type
== attr2
->nh_type
762 && attr1
->bh_type
== attr2
->bh_type
)
769 static void attrhash_init(void)
772 hash_create(attrhash_key_make
, attrhash_cmp
, "BGP Attributes");
776 * special for hash_clean below
778 static void attr_vfree(void *attr
)
780 XFREE(MTYPE_ATTR
, attr
);
783 static void attrhash_finish(void)
785 hash_clean(attrhash
, attr_vfree
);
790 static void attr_show_all_iterator(struct hash_bucket
*bucket
, struct vty
*vty
)
792 struct attr
*attr
= bucket
->data
;
793 char sid_str
[BUFSIZ
];
795 vty_out(vty
, "attr[%ld] nexthop %pI4\n", attr
->refcnt
, &attr
->nexthop
);
798 if (attr
->srv6_l3vpn
)
799 inet_ntop(AF_INET6
, &attr
->srv6_l3vpn
->sid
, sid_str
, BUFSIZ
);
800 else if (attr
->srv6_vpn
)
801 inet_ntop(AF_INET6
, &attr
->srv6_vpn
->sid
, sid_str
, BUFSIZ
);
804 "\tflags: %" PRIu64
" distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %s\n",
805 attr
->flag
, attr
->distance
, attr
->med
, attr
->local_pref
,
806 attr
->origin
, attr
->weight
, attr
->label
, sid_str
);
809 void attr_show_all(struct vty
*vty
)
811 hash_iterate(attrhash
, (void (*)(struct hash_bucket
*,
812 void *))attr_show_all_iterator
,
816 static void *bgp_attr_hash_alloc(void *p
)
818 struct attr
*val
= (struct attr
*)p
;
821 attr
= XMALLOC(MTYPE_ATTR
, sizeof(struct attr
));
823 if (val
->encap_subtlvs
) {
824 val
->encap_subtlvs
= NULL
;
826 #ifdef ENABLE_BGP_VNC
827 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
828 bgp_attr_get_vnc_subtlvs(val
);
831 bgp_attr_set_vnc_subtlvs(val
, NULL
);
838 /* Internet argument attribute. */
839 struct attr
*bgp_attr_intern(struct attr
*attr
)
842 struct ecommunity
*ecomm
;
844 /* Intern referenced strucutre. */
846 if (!attr
->aspath
->refcnt
)
847 attr
->aspath
= aspath_intern(attr
->aspath
);
849 attr
->aspath
->refcnt
++;
851 if (attr
->community
) {
852 if (!attr
->community
->refcnt
)
853 attr
->community
= community_intern(attr
->community
);
855 attr
->community
->refcnt
++;
858 if (attr
->ecommunity
) {
859 if (!attr
->ecommunity
->refcnt
)
860 attr
->ecommunity
= ecommunity_intern(attr
->ecommunity
);
862 attr
->ecommunity
->refcnt
++;
865 ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
868 bgp_attr_set_ipv6_ecommunity(attr
,
869 ecommunity_intern(ecomm
));
874 if (attr
->lcommunity
) {
875 if (!attr
->lcommunity
->refcnt
)
876 attr
->lcommunity
= lcommunity_intern(attr
->lcommunity
);
878 attr
->lcommunity
->refcnt
++;
881 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
884 if (!cluster
->refcnt
)
885 bgp_attr_set_cluster(attr
, cluster_intern(cluster
));
890 struct transit
*transit
= bgp_attr_get_transit(attr
);
893 if (!transit
->refcnt
)
894 bgp_attr_set_transit(attr
, transit_intern(transit
));
898 if (attr
->encap_subtlvs
) {
899 if (!attr
->encap_subtlvs
->refcnt
)
900 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
903 attr
->encap_subtlvs
->refcnt
++;
905 if (attr
->srv6_l3vpn
) {
906 if (!attr
->srv6_l3vpn
->refcnt
)
907 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
909 attr
->srv6_l3vpn
->refcnt
++;
911 if (attr
->srv6_vpn
) {
912 if (!attr
->srv6_vpn
->refcnt
)
913 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
915 attr
->srv6_vpn
->refcnt
++;
917 #ifdef ENABLE_BGP_VNC
918 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
919 bgp_attr_get_vnc_subtlvs(attr
);
922 if (!vnc_subtlvs
->refcnt
)
923 bgp_attr_set_vnc_subtlvs(
925 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
927 vnc_subtlvs
->refcnt
++;
931 /* At this point, attr only contains intern'd pointers. that means
932 * if we find it in attrhash, it has all the same pointers and we
933 * correctly updated the refcounts on these.
934 * If we don't find it, we need to allocate a one because in all
935 * cases this returns a new reference to a hashed attr, but the input
937 find
= (struct attr
*)hash_get(attrhash
, attr
, bgp_attr_hash_alloc
);
943 /* Make network statement's attribute. */
944 struct attr
*bgp_attr_default_set(struct attr
*attr
, uint8_t origin
)
946 memset(attr
, 0, sizeof(struct attr
));
948 attr
->origin
= origin
;
949 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
950 attr
->aspath
= aspath_empty();
951 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
952 attr
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
954 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
955 attr
->label
= MPLS_INVALID_LABEL
;
956 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
957 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
962 /* Create the attributes for an aggregate */
963 struct attr
*bgp_attr_aggregate_intern(
964 struct bgp
*bgp
, uint8_t origin
, struct aspath
*aspath
,
965 struct community
*community
, struct ecommunity
*ecommunity
,
966 struct lcommunity
*lcommunity
, struct bgp_aggregate
*aggregate
,
967 uint8_t atomic_aggregate
, const struct prefix
*p
)
973 memset(&attr
, 0, sizeof(struct attr
));
975 /* Origin attribute. */
976 attr
.origin
= origin
;
977 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
979 /* AS path attribute. */
981 attr
.aspath
= aspath_intern(aspath
);
983 attr
.aspath
= aspath_empty();
984 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
986 /* Next hop attribute. */
987 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
990 uint32_t gshut
= COMMUNITY_GSHUT
;
992 /* If we are not shutting down ourselves and we are
993 * aggregating a route that contains the GSHUT community we
994 * need to remove that community when creating the aggregate */
995 if (!bgp_in_graceful_shutdown(bgp
)
996 && community_include(community
, gshut
)) {
997 community_del_val(community
, &gshut
);
1000 attr
.community
= community
;
1001 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
);
1005 attr
.ecommunity
= ecommunity
;
1006 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
1010 attr
.lcommunity
= lcommunity
;
1011 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
);
1014 if (bgp_in_graceful_shutdown(bgp
))
1015 bgp_attr_add_gshut_community(&attr
);
1017 attr
.label_index
= BGP_INVALID_LABEL_INDEX
;
1018 attr
.label
= MPLS_INVALID_LABEL
;
1019 attr
.weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1020 attr
.mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1021 if (!aggregate
->as_set
|| atomic_aggregate
)
1022 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1023 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1024 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
))
1025 attr
.aggregator_as
= bgp
->confed_id
;
1027 attr
.aggregator_as
= bgp
->as
;
1028 attr
.aggregator_addr
= bgp
->router_id
;
1029 attr
.label_index
= BGP_INVALID_LABEL_INDEX
;
1030 attr
.label
= MPLS_INVALID_LABEL
;
1032 /* Apply route-map */
1033 if (aggregate
->rmap
.name
) {
1034 struct attr attr_tmp
= attr
;
1035 struct bgp_path_info rmap_path
;
1037 memset(&rmap_path
, 0, sizeof(struct bgp_path_info
));
1038 rmap_path
.peer
= bgp
->peer_self
;
1039 rmap_path
.attr
= &attr_tmp
;
1041 SET_FLAG(bgp
->peer_self
->rmap_type
, PEER_RMAP_TYPE_AGGREGATE
);
1043 ret
= route_map_apply(aggregate
->rmap
.map
, p
, &rmap_path
);
1045 bgp
->peer_self
->rmap_type
= 0;
1047 if (ret
== RMAP_DENYMATCH
) {
1048 /* Free uninterned attribute. */
1049 bgp_attr_flush(&attr_tmp
);
1051 /* Unintern original. */
1052 aspath_unintern(&attr
.aspath
);
1056 if (bgp_in_graceful_shutdown(bgp
))
1057 bgp_attr_add_gshut_community(&attr_tmp
);
1059 new = bgp_attr_intern(&attr_tmp
);
1062 if (bgp_in_graceful_shutdown(bgp
))
1063 bgp_attr_add_gshut_community(&attr
);
1065 new = bgp_attr_intern(&attr
);
1068 /* Always release the 'intern()'ed AS Path. */
1069 aspath_unintern(&attr
.aspath
);
1074 /* Unintern just the sub-components of the attr, but not the attr */
1075 void bgp_attr_unintern_sub(struct attr
*attr
)
1077 struct ecommunity
*ecomm
;
1078 struct cluster_list
*cluster
;
1080 /* aspath refcount shoud be decrement. */
1082 aspath_unintern(&attr
->aspath
);
1083 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
));
1085 if (attr
->community
)
1086 community_unintern(&attr
->community
);
1087 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
));
1089 ecommunity_unintern(&attr
->ecommunity
);
1090 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
));
1092 ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1093 ecommunity_unintern(&ecomm
);
1094 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES
));
1095 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1097 if (attr
->lcommunity
)
1098 lcommunity_unintern(&attr
->lcommunity
);
1099 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
));
1101 cluster
= bgp_attr_get_cluster(attr
);
1103 cluster_unintern(&cluster
);
1104 bgp_attr_set_cluster(attr
, cluster
);
1106 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
));
1108 struct transit
*transit
= bgp_attr_get_transit(attr
);
1111 transit_unintern(&transit
);
1112 bgp_attr_set_transit(attr
, transit
);
1115 if (attr
->encap_subtlvs
)
1116 encap_unintern(&attr
->encap_subtlvs
, ENCAP_SUBTLV_TYPE
);
1118 #ifdef ENABLE_BGP_VNC
1119 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1120 bgp_attr_get_vnc_subtlvs(attr
);
1123 encap_unintern(&vnc_subtlvs
, VNC_SUBTLV_TYPE
);
1124 bgp_attr_set_vnc_subtlvs(attr
, vnc_subtlvs
);
1128 if (attr
->srv6_l3vpn
)
1129 srv6_l3vpn_unintern(&attr
->srv6_l3vpn
);
1132 srv6_vpn_unintern(&attr
->srv6_vpn
);
1136 * We have some show commands that let you experimentally
1137 * apply a route-map. When we apply the route-map
1138 * we are reseting values but not saving them for
1139 * posterity via intern'ing( because route-maps don't
1140 * do that) but at this point in time we need
1141 * to compare the new attr to the old and if the
1142 * routemap has changed it we need to, as Snoop Dog says,
1143 * Drop it like it's hot
1145 void bgp_attr_undup(struct attr
*new, struct attr
*old
)
1147 if (new->aspath
!= old
->aspath
)
1148 aspath_free(new->aspath
);
1150 if (new->community
!= old
->community
)
1151 community_free(&new->community
);
1153 if (new->ecommunity
!= old
->ecommunity
)
1154 ecommunity_free(&new->ecommunity
);
1156 if (new->lcommunity
!= old
->lcommunity
)
1157 lcommunity_free(&new->lcommunity
);
1159 if (new->srv6_l3vpn
!= old
->srv6_l3vpn
) {
1160 srv6_l3vpn_free(new->srv6_l3vpn
);
1161 new->srv6_l3vpn
= NULL
;
1164 if (new->srv6_vpn
!= old
->srv6_vpn
) {
1165 srv6_vpn_free(new->srv6_vpn
);
1166 new->srv6_vpn
= NULL
;
1170 /* Free bgp attribute and aspath. */
1171 void bgp_attr_unintern(struct attr
**pattr
)
1173 struct attr
*attr
= *pattr
;
1177 /* Decrement attribute reference. */
1182 /* If reference becomes zero then free attribute object. */
1183 if (attr
->refcnt
== 0) {
1184 ret
= hash_release(attrhash
, attr
);
1185 assert(ret
!= NULL
);
1186 XFREE(MTYPE_ATTR
, attr
);
1190 bgp_attr_unintern_sub(&tmp
);
1193 void bgp_attr_flush(struct attr
*attr
)
1195 struct ecommunity
*ecomm
;
1196 struct cluster_list
*cluster
;
1198 if (attr
->aspath
&& !attr
->aspath
->refcnt
) {
1199 aspath_free(attr
->aspath
);
1200 attr
->aspath
= NULL
;
1202 if (attr
->community
&& !attr
->community
->refcnt
)
1203 community_free(&attr
->community
);
1204 if (attr
->ecommunity
&& !attr
->ecommunity
->refcnt
)
1205 ecommunity_free(&attr
->ecommunity
);
1206 ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1207 if (ecomm
&& !ecomm
->refcnt
)
1208 ecommunity_free(&ecomm
);
1209 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1210 if (attr
->lcommunity
&& !attr
->lcommunity
->refcnt
)
1211 lcommunity_free(&attr
->lcommunity
);
1213 cluster
= bgp_attr_get_cluster(attr
);
1214 if (cluster
&& !cluster
->refcnt
) {
1215 cluster_free(cluster
);
1216 bgp_attr_set_cluster(attr
, NULL
);
1219 struct transit
*transit
= bgp_attr_get_transit(attr
);
1221 if (transit
&& !transit
->refcnt
) {
1222 transit_free(transit
);
1223 bgp_attr_set_transit(attr
, NULL
);
1225 if (attr
->encap_subtlvs
&& !attr
->encap_subtlvs
->refcnt
) {
1226 encap_free(attr
->encap_subtlvs
);
1227 attr
->encap_subtlvs
= NULL
;
1229 if (attr
->srv6_l3vpn
&& !attr
->srv6_l3vpn
->refcnt
) {
1230 srv6_l3vpn_free(attr
->srv6_l3vpn
);
1231 attr
->srv6_l3vpn
= NULL
;
1233 if (attr
->srv6_vpn
&& !attr
->srv6_vpn
->refcnt
) {
1234 srv6_vpn_free(attr
->srv6_vpn
);
1235 attr
->srv6_vpn
= NULL
;
1237 #ifdef ENABLE_BGP_VNC
1238 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1239 bgp_attr_get_vnc_subtlvs(attr
);
1241 if (vnc_subtlvs
&& !vnc_subtlvs
->refcnt
) {
1242 encap_free(vnc_subtlvs
);
1243 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
1248 /* Implement draft-scudder-idr-optional-transitive behaviour and
1249 * avoid resetting sessions for malformed attributes which are
1250 * are partial/optional and hence where the error likely was not
1251 * introduced by the sending neighbour.
1253 static bgp_attr_parse_ret_t
1254 bgp_attr_malformed(struct bgp_attr_parser_args
*args
, uint8_t subcode
,
1257 struct peer
*const peer
= args
->peer
;
1258 struct attr
*const attr
= args
->attr
;
1259 const uint8_t flags
= args
->flags
;
1260 /* startp and length must be special-cased, as whether or not to
1261 * send the attribute data with the NOTIFY depends on the error,
1262 * the caller therefore signals this with the seperate length argument
1264 uint8_t *notify_datap
= (length
> 0 ? args
->startp
: NULL
);
1266 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1267 char attr_str
[BUFSIZ
] = {0};
1269 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1271 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1274 /* Only relax error handling for eBGP peers */
1275 if (peer
->sort
!= BGP_PEER_EBGP
) {
1276 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1277 notify_datap
, length
);
1278 return BGP_ATTR_PARSE_ERROR
;
1281 /* Adjust the stream getp to the end of the attribute, in case we can
1282 * still proceed but the caller hasn't read all the attribute.
1284 stream_set_getp(BGP_INPUT(peer
),
1285 (args
->startp
- STREAM_DATA(BGP_INPUT(peer
)))
1288 switch (args
->type
) {
1289 /* where an attribute is relatively inconsequential, e.g. it does not
1290 * affect route selection, and can be safely ignored, then any such
1291 * attributes which are malformed should just be ignored and the route
1292 * processed as normal.
1294 case BGP_ATTR_AS4_AGGREGATOR
:
1295 case BGP_ATTR_AGGREGATOR
:
1296 case BGP_ATTR_ATOMIC_AGGREGATE
:
1297 return BGP_ATTR_PARSE_PROCEED
;
1299 /* Core attributes, particularly ones which may influence route
1300 * selection, should be treat-as-withdraw.
1302 case BGP_ATTR_ORIGIN
:
1303 case BGP_ATTR_AS_PATH
:
1304 case BGP_ATTR_NEXT_HOP
:
1305 case BGP_ATTR_MULTI_EXIT_DISC
:
1306 case BGP_ATTR_LOCAL_PREF
:
1307 case BGP_ATTR_COMMUNITIES
:
1308 case BGP_ATTR_EXT_COMMUNITIES
:
1309 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
1310 case BGP_ATTR_LARGE_COMMUNITIES
:
1311 case BGP_ATTR_ORIGINATOR_ID
:
1312 case BGP_ATTR_CLUSTER_LIST
:
1313 return BGP_ATTR_PARSE_WITHDRAW
;
1314 case BGP_ATTR_MP_REACH_NLRI
:
1315 case BGP_ATTR_MP_UNREACH_NLRI
:
1316 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1317 notify_datap
, length
);
1318 return BGP_ATTR_PARSE_ERROR
;
1321 /* Partial optional attributes that are malformed should not cause
1322 * the whole session to be reset. Instead treat it as a withdrawal
1323 * of the routes, if possible.
1325 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)
1326 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1327 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
))
1328 return BGP_ATTR_PARSE_WITHDRAW
;
1330 /* default to reset */
1331 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1334 /* Find out what is wrong with the path attribute flag bits and log the error.
1335 "Flag bits" here stand for Optional, Transitive and Partial, but not for
1336 Extended Length. Checking O/T/P bits at once implies, that the attribute
1337 being diagnosed is defined by RFC as either a "well-known" or an "optional,
1338 non-transitive" attribute. */
1340 bgp_attr_flags_diagnose(struct bgp_attr_parser_args
*args
,
1341 uint8_t desired_flags
/* how RFC says it must be */
1344 uint8_t seen
= 0, i
;
1345 uint8_t real_flags
= args
->flags
;
1346 const uint8_t attr_code
= args
->type
;
1348 desired_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1349 real_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1350 for (i
= 0; i
<= 2; i
++) /* O,T,P, but not E */
1351 if (CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1352 != CHECK_FLAG(real_flags
, attr_flag_str
[i
].key
)) {
1353 flog_err(EC_BGP_ATTR_FLAG
,
1354 "%s attribute must%s be flagged as \"%s\"",
1355 lookup_msg(attr_str
, attr_code
, NULL
),
1356 CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1359 attr_flag_str
[i
].str
);
1364 "Strange, %s called for attr %s, but no problem found with flags (real flags 0x%x, desired 0x%x)",
1365 __func__
, lookup_msg(attr_str
, attr_code
, NULL
),
1366 real_flags
, desired_flags
);
1370 /* Required flags for attributes. EXTLEN will be masked off when testing,
1371 * as will PARTIAL for optional+transitive attributes.
1373 const uint8_t attr_flags_values
[] = {
1374 [BGP_ATTR_ORIGIN
] = BGP_ATTR_FLAG_TRANS
,
1375 [BGP_ATTR_AS_PATH
] = BGP_ATTR_FLAG_TRANS
,
1376 [BGP_ATTR_NEXT_HOP
] = BGP_ATTR_FLAG_TRANS
,
1377 [BGP_ATTR_MULTI_EXIT_DISC
] = BGP_ATTR_FLAG_OPTIONAL
,
1378 [BGP_ATTR_LOCAL_PREF
] = BGP_ATTR_FLAG_TRANS
,
1379 [BGP_ATTR_ATOMIC_AGGREGATE
] = BGP_ATTR_FLAG_TRANS
,
1380 [BGP_ATTR_AGGREGATOR
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1381 [BGP_ATTR_COMMUNITIES
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1382 [BGP_ATTR_ORIGINATOR_ID
] = BGP_ATTR_FLAG_OPTIONAL
,
1383 [BGP_ATTR_CLUSTER_LIST
] = BGP_ATTR_FLAG_OPTIONAL
,
1384 [BGP_ATTR_MP_REACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1385 [BGP_ATTR_MP_UNREACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1386 [BGP_ATTR_EXT_COMMUNITIES
] =
1387 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1388 [BGP_ATTR_AS4_PATH
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1389 [BGP_ATTR_AS4_AGGREGATOR
] =
1390 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1391 [BGP_ATTR_PMSI_TUNNEL
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1392 [BGP_ATTR_LARGE_COMMUNITIES
] =
1393 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1394 [BGP_ATTR_PREFIX_SID
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1395 [BGP_ATTR_IPV6_EXT_COMMUNITIES
] =
1396 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1398 static const size_t attr_flags_values_max
= array_size(attr_flags_values
) - 1;
1400 static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args
*args
)
1402 uint8_t mask
= BGP_ATTR_FLAG_EXTLEN
;
1403 const uint8_t flags
= args
->flags
;
1404 const uint8_t attr_code
= args
->type
;
1406 /* there may be attributes we don't know about */
1407 if (attr_code
> attr_flags_values_max
)
1409 if (attr_flags_values
[attr_code
] == 0)
1412 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set
1416 if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL
, flags
)
1417 && !CHECK_FLAG(BGP_ATTR_FLAG_TRANS
, flags
)) {
1420 "%s well-known attributes must have transitive flag set (%x)",
1421 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1425 /* "For well-known attributes and for optional non-transitive
1427 * the Partial bit MUST be set to 0."
1429 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
)) {
1430 if (!CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)) {
1431 flog_err(EC_BGP_ATTR_FLAG
,
1432 "%s well-known attribute must NOT have the partial flag set (%x)",
1433 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1436 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1437 && !CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)) {
1438 flog_err(EC_BGP_ATTR_FLAG
,
1439 "%s optional + transitive attribute must NOT have the partial flag set (%x)",
1440 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1445 /* Optional transitive attributes may go through speakers that don't
1446 * reocgnise them and set the Partial bit.
1448 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1449 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
))
1450 SET_FLAG(mask
, BGP_ATTR_FLAG_PARTIAL
);
1452 if ((flags
& ~mask
) == attr_flags_values
[attr_code
])
1455 bgp_attr_flags_diagnose(args
, attr_flags_values
[attr_code
]);
1459 /* Get origin attribute of the update message. */
1460 static bgp_attr_parse_ret_t
bgp_attr_origin(struct bgp_attr_parser_args
*args
)
1462 struct peer
*const peer
= args
->peer
;
1463 struct attr
*const attr
= args
->attr
;
1464 const bgp_size_t length
= args
->length
;
1466 /* If any recognized attribute has Attribute Length that conflicts
1467 with the expected length (based on the attribute type code), then
1468 the Error Subcode is set to Attribute Length Error. The Data
1469 field contains the erroneous attribute (type, length and
1472 flog_err(EC_BGP_ATTR_LEN
,
1473 "Origin attribute length is not one %d", length
);
1474 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1478 /* Fetch origin attribute. */
1479 attr
->origin
= stream_getc(BGP_INPUT(peer
));
1481 /* If the ORIGIN attribute has an undefined value, then the Error
1482 Subcode is set to Invalid Origin Attribute. The Data field
1483 contains the unrecognized attribute (type, length and value). */
1484 if ((attr
->origin
!= BGP_ORIGIN_IGP
) && (attr
->origin
!= BGP_ORIGIN_EGP
)
1485 && (attr
->origin
!= BGP_ORIGIN_INCOMPLETE
)) {
1486 flog_err(EC_BGP_ATTR_ORIGIN
,
1487 "Origin attribute value is invalid %d", attr
->origin
);
1488 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_INVAL_ORIGIN
,
1492 /* Set oring attribute flag. */
1493 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1498 /* Parse AS path information. This function is wrapper of
1500 static int bgp_attr_aspath(struct bgp_attr_parser_args
*args
)
1502 struct attr
*const attr
= args
->attr
;
1503 struct peer
*const peer
= args
->peer
;
1504 const bgp_size_t length
= args
->length
;
1507 * peer with AS4 => will get 4Byte ASnums
1508 * otherwise, will get 16 Bit
1510 attr
->aspath
= aspath_parse(
1512 CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1513 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
));
1515 /* In case of IBGP, length will be zero. */
1516 if (!attr
->aspath
) {
1517 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1518 "Malformed AS path from %s, length is %d", peer
->host
,
1520 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1524 /* Set aspath attribute flag. */
1525 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1527 return BGP_ATTR_PARSE_PROCEED
;
1530 static bgp_attr_parse_ret_t
bgp_attr_aspath_check(struct peer
*const peer
,
1531 struct attr
*const attr
)
1533 /* These checks were part of bgp_attr_aspath, but with
1534 * as4 we should to check aspath things when
1535 * aspath synthesizing with as4_path has already taken place.
1536 * Otherwise we check ASPATH and use the synthesized thing, and that is
1538 * So do the checks later, i.e. here
1540 struct aspath
*aspath
;
1542 /* Confederation sanity check. */
1543 if ((peer
->sort
== BGP_PEER_CONFED
1544 && !aspath_left_confed_check(attr
->aspath
))
1545 || (peer
->sort
== BGP_PEER_EBGP
1546 && aspath_confed_check(attr
->aspath
))) {
1547 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "Malformed AS path from %s",
1549 return BGP_ATTR_PARSE_WITHDRAW
;
1552 /* First AS check for EBGP. */
1553 if (CHECK_FLAG(peer
->flags
, PEER_FLAG_ENFORCE_FIRST_AS
)) {
1554 if (peer
->sort
== BGP_PEER_EBGP
1555 && !aspath_firstas_check(attr
->aspath
, peer
->as
)) {
1556 flog_err(EC_BGP_ATTR_FIRST_AS
,
1557 "%s incorrect first AS (must be %u)",
1558 peer
->host
, peer
->as
);
1559 return BGP_ATTR_PARSE_WITHDRAW
;
1563 /* Codification of AS 0 Processing */
1564 if (peer
->sort
== BGP_PEER_EBGP
&& aspath_check_as_zero(attr
->aspath
)) {
1566 EC_BGP_ATTR_MAL_AS_PATH
,
1567 "Malformed AS path, AS number is 0 in the path from %s",
1569 return BGP_ATTR_PARSE_WITHDRAW
;
1572 /* local-as prepend */
1573 if (peer
->change_local_as
1574 && !CHECK_FLAG(peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
)) {
1575 aspath
= aspath_dup(attr
->aspath
);
1576 aspath
= aspath_add_seq(aspath
, peer
->change_local_as
);
1577 aspath_unintern(&attr
->aspath
);
1578 attr
->aspath
= aspath_intern(aspath
);
1581 return BGP_ATTR_PARSE_PROCEED
;
1584 /* Parse AS4 path information. This function is another wrapper of
1586 static int bgp_attr_as4_path(struct bgp_attr_parser_args
*args
,
1587 struct aspath
**as4_path
)
1589 struct peer
*const peer
= args
->peer
;
1590 struct attr
*const attr
= args
->attr
;
1591 const bgp_size_t length
= args
->length
;
1593 *as4_path
= aspath_parse(peer
->curr
, length
, 1);
1595 /* In case of IBGP, length will be zero. */
1597 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1598 "Malformed AS4 path from %s, length is %d", peer
->host
,
1600 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1604 /* Set aspath attribute flag. */
1605 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
);
1607 return BGP_ATTR_PARSE_PROCEED
;
1611 * Check that the nexthop attribute is valid.
1613 bgp_attr_parse_ret_t
1614 bgp_attr_nexthop_valid(struct peer
*peer
, struct attr
*attr
)
1616 in_addr_t nexthop_h
;
1618 nexthop_h
= ntohl(attr
->nexthop
.s_addr
);
1619 if ((IPV4_NET0(nexthop_h
) || IPV4_NET127(nexthop_h
)
1620 || IPV4_CLASS_DE(nexthop_h
))
1621 && !BGP_DEBUG(allow_martians
, ALLOW_MARTIANS
)) {
1622 uint8_t data
[7]; /* type(2) + length(1) + nhop(4) */
1623 char buf
[INET_ADDRSTRLEN
];
1625 inet_ntop(AF_INET
, &attr
->nexthop
.s_addr
, buf
,
1627 flog_err(EC_BGP_ATTR_MARTIAN_NH
, "Martian nexthop %s",
1629 data
[0] = BGP_ATTR_FLAG_TRANS
;
1630 data
[1] = BGP_ATTR_NEXT_HOP
;
1631 data
[2] = BGP_ATTR_NHLEN_IPV4
;
1632 memcpy(&data
[3], &attr
->nexthop
.s_addr
, BGP_ATTR_NHLEN_IPV4
);
1633 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
1634 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1636 return BGP_ATTR_PARSE_ERROR
;
1639 return BGP_ATTR_PARSE_PROCEED
;
1642 /* Nexthop attribute. */
1643 static bgp_attr_parse_ret_t
bgp_attr_nexthop(struct bgp_attr_parser_args
*args
)
1645 struct peer
*const peer
= args
->peer
;
1646 struct attr
*const attr
= args
->attr
;
1647 const bgp_size_t length
= args
->length
;
1649 /* Check nexthop attribute length. */
1651 flog_err(EC_BGP_ATTR_LEN
,
1652 "Nexthop attribute length isn't four [%d]", length
);
1654 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1658 attr
->nexthop
.s_addr
= stream_get_ipv4(peer
->curr
);
1659 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1661 return BGP_ATTR_PARSE_PROCEED
;
1664 /* MED atrribute. */
1665 static bgp_attr_parse_ret_t
bgp_attr_med(struct bgp_attr_parser_args
*args
)
1667 struct peer
*const peer
= args
->peer
;
1668 struct attr
*const attr
= args
->attr
;
1669 const bgp_size_t length
= args
->length
;
1673 flog_err(EC_BGP_ATTR_LEN
,
1674 "MED attribute length isn't four [%d]", length
);
1676 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1680 attr
->med
= stream_getl(peer
->curr
);
1682 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1684 return BGP_ATTR_PARSE_PROCEED
;
1687 /* Local preference attribute. */
1688 static bgp_attr_parse_ret_t
1689 bgp_attr_local_pref(struct bgp_attr_parser_args
*args
)
1691 struct peer
*const peer
= args
->peer
;
1692 struct attr
*const attr
= args
->attr
;
1693 const bgp_size_t length
= args
->length
;
1695 /* if received from an internal neighbor, it SHALL be considered
1696 * malformed if its length is not equal to 4. If malformed, the
1697 * UPDATE message SHALL be handled using the approach of "treat-as-
1700 if (peer
->sort
== BGP_PEER_IBGP
&& length
!= 4) {
1701 flog_err(EC_BGP_ATTR_LEN
,
1702 "LOCAL_PREF attribute length isn't 4 [%u]", length
);
1703 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1707 /* If it is contained in an UPDATE message that is received from an
1708 external peer, then this attribute MUST be ignored by the
1709 receiving speaker. */
1710 if (peer
->sort
== BGP_PEER_EBGP
) {
1711 STREAM_FORWARD_GETP(peer
->curr
, length
);
1712 return BGP_ATTR_PARSE_PROCEED
;
1715 STREAM_GETL(peer
->curr
, attr
->local_pref
);
1717 /* Set the local-pref flag. */
1718 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
1720 return BGP_ATTR_PARSE_PROCEED
;
1723 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1727 /* Atomic aggregate. */
1728 static int bgp_attr_atomic(struct bgp_attr_parser_args
*args
)
1730 struct attr
*const attr
= args
->attr
;
1731 const bgp_size_t length
= args
->length
;
1735 flog_err(EC_BGP_ATTR_LEN
,
1736 "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1738 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1742 /* Set atomic aggregate flag. */
1743 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1745 return BGP_ATTR_PARSE_PROCEED
;
1748 /* Aggregator attribute */
1749 static int bgp_attr_aggregator(struct bgp_attr_parser_args
*args
)
1751 struct peer
*const peer
= args
->peer
;
1752 struct attr
*const attr
= args
->attr
;
1753 const bgp_size_t length
= args
->length
;
1758 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1759 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1760 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
))
1763 if (length
!= wantedlen
) {
1764 flog_err(EC_BGP_ATTR_LEN
,
1765 "AGGREGATOR attribute length isn't %u [%u]", wantedlen
,
1767 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1771 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
))
1772 aggregator_as
= stream_getl(peer
->curr
);
1774 aggregator_as
= stream_getw(peer
->curr
);
1776 attr
->aggregator_as
= aggregator_as
;
1777 attr
->aggregator_addr
.s_addr
= stream_get_ipv4(peer
->curr
);
1779 /* Codification of AS 0 Processing */
1780 if (aggregator_as
== BGP_AS_ZERO
) {
1781 flog_err(EC_BGP_ATTR_LEN
,
1782 "%s: AGGREGATOR AS number is 0 for aspath: %s",
1783 peer
->host
, aspath_print(attr
->aspath
));
1785 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1786 char attr_str
[BUFSIZ
] = {0};
1788 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1790 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1793 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1796 return BGP_ATTR_PARSE_PROCEED
;
1799 /* New Aggregator attribute */
1800 static bgp_attr_parse_ret_t
1801 bgp_attr_as4_aggregator(struct bgp_attr_parser_args
*args
,
1802 as_t
*as4_aggregator_as
,
1803 struct in_addr
*as4_aggregator_addr
)
1805 struct peer
*const peer
= args
->peer
;
1806 struct attr
*const attr
= args
->attr
;
1807 const bgp_size_t length
= args
->length
;
1811 flog_err(EC_BGP_ATTR_LEN
, "New Aggregator length is not 8 [%d]",
1813 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1817 aggregator_as
= stream_getl(peer
->curr
);
1819 *as4_aggregator_as
= aggregator_as
;
1820 as4_aggregator_addr
->s_addr
= stream_get_ipv4(peer
->curr
);
1822 /* Codification of AS 0 Processing */
1823 if (aggregator_as
== BGP_AS_ZERO
) {
1824 flog_err(EC_BGP_ATTR_LEN
,
1825 "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
1826 peer
->host
, aspath_print(attr
->aspath
));
1828 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1829 char attr_str
[BUFSIZ
] = {0};
1831 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1833 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1836 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
);
1839 return BGP_ATTR_PARSE_PROCEED
;
1842 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1844 static bgp_attr_parse_ret_t
1845 bgp_attr_munge_as4_attrs(struct peer
*const peer
, struct attr
*const attr
,
1846 struct aspath
*as4_path
, as_t as4_aggregator
,
1847 struct in_addr
*as4_aggregator_addr
)
1849 int ignore_as4_path
= 0;
1850 struct aspath
*newpath
;
1852 if (!attr
->aspath
) {
1853 /* NULL aspath shouldn't be possible as bgp_attr_parse should
1855 * checked that all well-known, mandatory attributes were
1858 * Can only be a problem with peer itself - hard error
1860 return BGP_ATTR_PARSE_ERROR
;
1863 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
1864 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1866 * It is worth a warning though, because the peer really
1867 * should not send them
1869 if (BGP_DEBUG(as4
, AS4
)) {
1870 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
1871 zlog_debug("[AS4] %s %s AS4_PATH", peer
->host
,
1872 "AS4 capable peer, yet it sent");
1875 & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
1876 zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
1878 "AS4 capable peer, yet it sent");
1881 return BGP_ATTR_PARSE_PROCEED
;
1884 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1885 * because that may override AS4_PATH
1887 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
))) {
1888 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
))) {
1890 * if the as_number in aggregator is not AS_TRANS,
1891 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1892 * and the Aggregator shall be taken as
1893 * info on the aggregating node, and the AS_PATH
1894 * shall be taken as the AS_PATH
1896 * the Aggregator shall be ignored and the
1897 * AS4_AGGREGATOR shall be taken as the
1898 * Aggregating node and the AS_PATH is to be
1899 * constructed "as in all other cases"
1901 if (attr
->aggregator_as
!= BGP_AS_TRANS
) {
1903 if (BGP_DEBUG(as4
, AS4
))
1905 "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
1907 ignore_as4_path
= 1;
1909 /* "New_aggregator shall be taken as aggregator"
1911 attr
->aggregator_as
= as4_aggregator
;
1912 attr
->aggregator_addr
.s_addr
=
1913 as4_aggregator_addr
->s_addr
;
1916 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1917 * That is bogus - but reading the conditions
1918 * we have to handle AS4_AGGREGATOR as if it were
1919 * AGGREGATOR in that case
1921 if (BGP_DEBUG(as4
, AS4
))
1923 "[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",
1925 attr
->aggregator_as
= as4_aggregator
;
1926 /* sweep it under the carpet and simulate a "good"
1928 attr
->flag
|= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
));
1932 /* need to reconcile NEW_AS_PATH and AS_PATH */
1933 if (!ignore_as4_path
1934 && (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))) {
1935 newpath
= aspath_reconcile_as4(attr
->aspath
, as4_path
);
1937 return BGP_ATTR_PARSE_ERROR
;
1939 aspath_unintern(&attr
->aspath
);
1940 attr
->aspath
= aspath_intern(newpath
);
1942 return BGP_ATTR_PARSE_PROCEED
;
1945 /* Community attribute. */
1946 static bgp_attr_parse_ret_t
1947 bgp_attr_community(struct bgp_attr_parser_args
*args
)
1949 struct peer
*const peer
= args
->peer
;
1950 struct attr
*const attr
= args
->attr
;
1951 const bgp_size_t length
= args
->length
;
1954 attr
->community
= NULL
;
1955 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1960 community_parse((uint32_t *)stream_pnt(peer
->curr
), length
);
1962 /* XXX: fix community_parse to use stream API and remove this */
1963 stream_forward_getp(peer
->curr
, length
);
1965 /* The Community attribute SHALL be considered malformed if its
1966 * length is not a non-zero multiple of 4.
1968 if (!attr
->community
)
1969 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1972 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
);
1974 return BGP_ATTR_PARSE_PROCEED
;
1977 /* Originator ID attribute. */
1978 static bgp_attr_parse_ret_t
1979 bgp_attr_originator_id(struct bgp_attr_parser_args
*args
)
1981 struct peer
*const peer
= args
->peer
;
1982 struct attr
*const attr
= args
->attr
;
1983 const bgp_size_t length
= args
->length
;
1985 /* if received from an internal neighbor, it SHALL be considered
1986 * malformed if its length is not equal to 4. If malformed, the
1987 * UPDATE message SHALL be handled using the approach of "treat-as-
1991 flog_err(EC_BGP_ATTR_LEN
, "Bad originator ID length %d",
1994 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1998 attr
->originator_id
.s_addr
= stream_get_ipv4(peer
->curr
);
2000 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
2002 return BGP_ATTR_PARSE_PROCEED
;
2005 /* Cluster list attribute. */
2006 static bgp_attr_parse_ret_t
2007 bgp_attr_cluster_list(struct bgp_attr_parser_args
*args
)
2009 struct peer
*const peer
= args
->peer
;
2010 struct attr
*const attr
= args
->attr
;
2011 const bgp_size_t length
= args
->length
;
2013 /* if received from an internal neighbor, it SHALL be considered
2014 * malformed if its length is not a non-zero multiple of 4. If
2015 * malformed, the UPDATE message SHALL be handled using the approach
2016 * of "treat-as-withdraw".
2018 if (length
== 0 || length
% 4) {
2019 flog_err(EC_BGP_ATTR_LEN
, "Bad cluster list length %d", length
);
2021 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2025 bgp_attr_set_cluster(
2026 attr
, cluster_parse((struct in_addr
*)stream_pnt(peer
->curr
),
2029 /* XXX: Fix cluster_parse to use stream API and then remove this */
2030 stream_forward_getp(peer
->curr
, length
);
2032 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
);
2034 return BGP_ATTR_PARSE_PROCEED
;
2037 /* Multiprotocol reachability information parse. */
2038 int bgp_mp_reach_parse(struct bgp_attr_parser_args
*args
,
2039 struct bgp_nlri
*mp_update
)
2043 iana_safi_t pkt_safi
;
2045 bgp_size_t nlri_len
;
2048 struct peer
*const peer
= args
->peer
;
2049 struct attr
*const attr
= args
->attr
;
2050 const bgp_size_t length
= args
->length
;
2052 /* Set end of packet. */
2053 s
= BGP_INPUT(peer
);
2054 start
= stream_get_getp(s
);
2056 /* safe to read statically sized header? */
2057 #define BGP_MP_REACH_MIN_SIZE 5
2058 #define LEN_LEFT (length - (stream_get_getp(s) - start))
2059 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
)) {
2060 zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
2061 __func__
, peer
->host
, (unsigned long)length
);
2062 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2065 /* Load AFI, SAFI. */
2066 pkt_afi
= stream_getw(s
);
2067 pkt_safi
= stream_getc(s
);
2069 /* Convert AFI, SAFI to internal values, check. */
2070 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2071 /* Log if AFI or SAFI is unrecognized. This is not an error
2073 * the attribute is otherwise malformed.
2075 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2077 "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
2078 peer
->host
, iana_afi2str(pkt_afi
),
2079 iana_safi2str(pkt_safi
));
2080 return BGP_ATTR_PARSE_ERROR
;
2083 /* Get nexthop length. */
2084 attr
->mp_nexthop_len
= stream_getc(s
);
2086 if (LEN_LEFT
< attr
->mp_nexthop_len
) {
2088 "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
2089 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2090 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2093 /* Nexthop length check. */
2094 switch (attr
->mp_nexthop_len
) {
2096 if (safi
!= SAFI_FLOWSPEC
) {
2097 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2098 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2099 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2102 case BGP_ATTR_NHLEN_VPNV4
:
2103 stream_getl(s
); /* RD high */
2104 stream_getl(s
); /* RD low */
2106 * NOTE: intentional fall through
2107 * - for consistency in rx processing
2109 * The following comment is to signal GCC this intention
2110 * and suppress the warning
2113 case BGP_ATTR_NHLEN_IPV4
:
2114 stream_get(&attr
->mp_nexthop_global_in
, s
, IPV4_MAX_BYTELEN
);
2115 /* Probably needed for RFC 2283 */
2116 if (attr
->nexthop
.s_addr
== INADDR_ANY
)
2117 memcpy(&attr
->nexthop
.s_addr
,
2118 &attr
->mp_nexthop_global_in
, IPV4_MAX_BYTELEN
);
2120 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
2121 case BGP_ATTR_NHLEN_VPNV6_GLOBAL
:
2122 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL
) {
2123 stream_getl(s
); /* RD high */
2124 stream_getl(s
); /* RD low */
2126 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2127 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2128 if (!peer
->nexthop
.ifp
) {
2129 zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2131 return BGP_ATTR_PARSE_WITHDRAW
;
2133 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2136 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
2137 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
:
2138 if (attr
->mp_nexthop_len
2139 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2140 stream_getl(s
); /* RD high */
2141 stream_getl(s
); /* RD low */
2143 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2144 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2145 if (!peer
->nexthop
.ifp
) {
2146 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",
2148 return BGP_ATTR_PARSE_WITHDRAW
;
2150 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2152 if (attr
->mp_nexthop_len
2153 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2154 stream_getl(s
); /* RD high */
2155 stream_getl(s
); /* RD low */
2157 stream_get(&attr
->mp_nexthop_local
, s
, IPV6_MAX_BYTELEN
);
2158 if (!IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_local
)) {
2159 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2161 "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
2162 peer
->host
, &attr
->mp_nexthop_global
,
2163 &attr
->mp_nexthop_local
);
2165 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
2167 if (!peer
->nexthop
.ifp
) {
2168 zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
2170 return BGP_ATTR_PARSE_WITHDRAW
;
2172 attr
->nh_lla_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2175 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2176 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2177 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2181 zlog_info("%s: %s sent SNPA which couldn't be read",
2182 __func__
, peer
->host
);
2183 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2188 if ((val
= stream_getc(s
)))
2190 EC_BGP_DEFUNCT_SNPA_LEN
,
2191 "%s sent non-zero value, %u, for defunct SNPA-length field",
2195 /* must have nrli_len, what is left of the attribute */
2196 nlri_len
= LEN_LEFT
;
2197 if (nlri_len
> STREAM_READABLE(s
)) {
2198 zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
2199 __func__
, peer
->host
);
2200 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2204 zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
2205 __func__
, peer
->host
);
2207 mp_update
->afi
= afi
;
2208 mp_update
->safi
= safi
;
2209 return BGP_ATTR_PARSE_EOR
;
2212 mp_update
->afi
= afi
;
2213 mp_update
->safi
= safi
;
2214 mp_update
->nlri
= stream_pnt(s
);
2215 mp_update
->length
= nlri_len
;
2217 stream_forward_getp(s
, nlri_len
);
2219 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
);
2221 return BGP_ATTR_PARSE_PROCEED
;
2225 /* Multiprotocol unreachable parse */
2226 int bgp_mp_unreach_parse(struct bgp_attr_parser_args
*args
,
2227 struct bgp_nlri
*mp_withdraw
)
2232 iana_safi_t pkt_safi
;
2234 uint16_t withdraw_len
;
2235 struct peer
*const peer
= args
->peer
;
2236 struct attr
*const attr
= args
->attr
;
2237 const bgp_size_t length
= args
->length
;
2241 #define BGP_MP_UNREACH_MIN_SIZE 3
2242 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
2243 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2245 pkt_afi
= stream_getw(s
);
2246 pkt_safi
= stream_getc(s
);
2248 /* Convert AFI, SAFI to internal values, check. */
2249 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2250 /* Log if AFI or SAFI is unrecognized. This is not an error
2252 * the attribute is otherwise malformed.
2254 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2256 "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
2257 peer
->host
, iana_afi2str(pkt_afi
),
2258 iana_safi2str(pkt_safi
));
2259 return BGP_ATTR_PARSE_ERROR
;
2262 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
2264 mp_withdraw
->afi
= afi
;
2265 mp_withdraw
->safi
= safi
;
2266 mp_withdraw
->nlri
= stream_pnt(s
);
2267 mp_withdraw
->length
= withdraw_len
;
2269 stream_forward_getp(s
, withdraw_len
);
2271 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
);
2273 return BGP_ATTR_PARSE_PROCEED
;
2276 /* Large Community attribute. */
2277 static bgp_attr_parse_ret_t
2278 bgp_attr_large_community(struct bgp_attr_parser_args
*args
)
2280 struct peer
*const peer
= args
->peer
;
2281 struct attr
*const attr
= args
->attr
;
2282 const bgp_size_t length
= args
->length
;
2285 * Large community follows new attribute format.
2288 attr
->lcommunity
= NULL
;
2289 /* Empty extcomm doesn't seem to be invalid per se */
2290 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2294 attr
->lcommunity
= lcommunity_parse(stream_pnt(peer
->curr
), length
);
2295 /* XXX: fix ecommunity_parse to use stream API */
2296 stream_forward_getp(peer
->curr
, length
);
2298 if (!attr
->lcommunity
)
2299 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2302 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
);
2304 return BGP_ATTR_PARSE_PROCEED
;
2307 /* Extended Community attribute. */
2308 static bgp_attr_parse_ret_t
2309 bgp_attr_ext_communities(struct bgp_attr_parser_args
*args
)
2311 struct peer
*const peer
= args
->peer
;
2312 struct attr
*const attr
= args
->attr
;
2313 const bgp_size_t length
= args
->length
;
2318 attr
->ecommunity
= NULL
;
2319 /* Empty extcomm doesn't seem to be invalid per se */
2320 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2324 attr
->ecommunity
= ecommunity_parse(
2325 stream_pnt(peer
->curr
), length
,
2326 CHECK_FLAG(peer
->flags
,
2327 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2328 /* XXX: fix ecommunity_parse to use stream API */
2329 stream_forward_getp(peer
->curr
, length
);
2331 /* The Extended Community attribute SHALL be considered malformed if
2332 * its length is not a non-zero multiple of 8.
2334 if (!attr
->ecommunity
)
2335 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2338 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
2340 /* Extract DF election preference and mobility sequence number */
2341 attr
->df_pref
= bgp_attr_df_pref_from_ec(attr
, &attr
->df_alg
);
2343 /* Extract MAC mobility sequence number, if any. */
2344 attr
->mm_seqnum
= bgp_attr_mac_mobility_seqnum(attr
, &sticky
);
2345 attr
->sticky
= sticky
;
2347 /* Check if this is a Gateway MAC-IP advertisement */
2348 attr
->default_gw
= bgp_attr_default_gw(attr
);
2350 /* Handle scenario where router flag ecommunity is not
2351 * set but default gw ext community is present.
2352 * Use default gateway, set and propogate R-bit.
2354 if (attr
->default_gw
)
2355 attr
->router_flag
= 1;
2357 /* Check EVPN Neighbor advertisement flags, R-bit */
2358 bgp_attr_evpn_na_flag(attr
, &attr
->router_flag
, &proxy
);
2360 attr
->es_flags
|= ATTR_ES_PROXY_ADVERT
;
2362 /* Extract the Rmac, if any */
2363 if (bgp_attr_rmac(attr
, &attr
->rmac
)) {
2364 if (bgp_debug_update(peer
, NULL
, NULL
, 1)
2365 && bgp_mac_exist(&attr
->rmac
))
2366 zlog_debug("%s: router mac %pEA is self mac", __func__
,
2370 /* Get the tunnel type from encap extended community */
2371 bgp_attr_extcom_tunnel_type(attr
,
2372 (bgp_encap_types
*)&attr
->encap_tunneltype
);
2374 /* Extract link bandwidth, if any. */
2375 (void)ecommunity_linkbw_present(attr
->ecommunity
, &attr
->link_bw
);
2377 return BGP_ATTR_PARSE_PROCEED
;
2380 /* IPv6 Extended Community attribute. */
2381 static bgp_attr_parse_ret_t
2382 bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args
*args
)
2384 struct peer
*const peer
= args
->peer
;
2385 struct attr
*const attr
= args
->attr
;
2386 const bgp_size_t length
= args
->length
;
2387 struct ecommunity
*ipv6_ecomm
= NULL
;
2390 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2391 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2395 ipv6_ecomm
= ecommunity_parse_ipv6(
2396 stream_pnt(peer
->curr
), length
,
2397 CHECK_FLAG(peer
->flags
,
2398 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE
));
2399 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2401 /* XXX: fix ecommunity_parse to use stream API */
2402 stream_forward_getp(peer
->curr
, length
);
2405 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2408 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES
);
2410 return BGP_ATTR_PARSE_PROCEED
;
2413 /* Parse Tunnel Encap attribute in an UPDATE */
2414 static int bgp_attr_encap(uint8_t type
, struct peer
*peer
, /* IN */
2415 bgp_size_t length
, /* IN: attr's length field */
2416 struct attr
*attr
, /* IN: caller already allocated */
2417 uint8_t flag
, /* IN: attr's flags field */
2421 uint16_t tunneltype
= 0;
2423 total
= length
+ (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
2425 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
)
2426 || !CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
2428 "Tunnel Encap attribute flag isn't optional and transitive %d",
2430 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2431 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
2436 if (BGP_ATTR_ENCAP
== type
) {
2437 /* read outer TLV type and length */
2438 uint16_t tlv_length
;
2442 "Tunnel Encap attribute not long enough to contain outer T,L");
2443 bgp_notify_send_with_data(
2444 peer
, BGP_NOTIFY_UPDATE_ERR
,
2445 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2448 tunneltype
= stream_getw(BGP_INPUT(peer
));
2449 tlv_length
= stream_getw(BGP_INPUT(peer
));
2452 if (tlv_length
!= length
) {
2453 zlog_info("%s: tlv_length(%d) != length(%d)",
2454 __func__
, tlv_length
, length
);
2458 while (length
>= 4) {
2459 uint16_t subtype
= 0;
2460 uint16_t sublength
= 0;
2461 struct bgp_attr_encap_subtlv
*tlv
;
2463 if (BGP_ATTR_ENCAP
== type
) {
2464 subtype
= stream_getc(BGP_INPUT(peer
));
2465 sublength
= stream_getc(BGP_INPUT(peer
));
2467 #ifdef ENABLE_BGP_VNC
2469 subtype
= stream_getw(BGP_INPUT(peer
));
2470 sublength
= stream_getw(BGP_INPUT(peer
));
2475 if (sublength
> length
) {
2477 "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2479 bgp_notify_send_with_data(
2480 peer
, BGP_NOTIFY_UPDATE_ERR
,
2481 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2485 /* alloc and copy sub-tlv */
2486 /* TBD make sure these are freed when attributes are released */
2487 tlv
= XCALLOC(MTYPE_ENCAP_TLV
,
2488 sizeof(struct bgp_attr_encap_subtlv
) + sublength
);
2489 tlv
->type
= subtype
;
2490 tlv
->length
= sublength
;
2491 stream_get(tlv
->value
, peer
->curr
, sublength
);
2492 length
-= sublength
;
2494 /* attach tlv to encap chain */
2495 if (BGP_ATTR_ENCAP
== type
) {
2496 struct bgp_attr_encap_subtlv
*stlv_last
;
2497 for (stlv_last
= attr
->encap_subtlvs
;
2498 stlv_last
&& stlv_last
->next
;
2499 stlv_last
= stlv_last
->next
)
2502 stlv_last
->next
= tlv
;
2504 attr
->encap_subtlvs
= tlv
;
2506 #ifdef ENABLE_BGP_VNC
2508 struct bgp_attr_encap_subtlv
*stlv_last
;
2509 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
2510 bgp_attr_get_vnc_subtlvs(attr
);
2512 for (stlv_last
= vnc_subtlvs
;
2513 stlv_last
&& stlv_last
->next
;
2514 stlv_last
= stlv_last
->next
)
2517 stlv_last
->next
= tlv
;
2519 bgp_attr_set_vnc_subtlvs(attr
, tlv
);
2524 if (BGP_ATTR_ENCAP
== type
) {
2525 attr
->encap_tunneltype
= tunneltype
;
2529 /* spurious leftover data */
2531 "Tunnel Encap attribute length is bad: %d leftover octets",
2533 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2534 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2543 /* SRv6 Service Data Sub-Sub-TLV attribute
2544 * draft-ietf-bess-srv6-services-07
2546 static bgp_attr_parse_ret_t
2547 bgp_attr_srv6_service_data(struct bgp_attr_parser_args
*args
)
2549 struct peer
*const peer
= args
->peer
;
2550 struct attr
*const attr
= args
->attr
;
2551 uint8_t type
, loc_block_len
, loc_node_len
, func_len
, arg_len
,
2552 transposition_len
, transposition_offset
;
2554 size_t headersz
= sizeof(type
) + sizeof(length
);
2556 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2559 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2560 headersz
, STREAM_READABLE(peer
->curr
));
2561 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2565 type
= stream_getc(peer
->curr
);
2566 length
= stream_getw(peer
->curr
);
2568 if (STREAM_READABLE(peer
->curr
) < length
) {
2571 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2572 length
, STREAM_READABLE(peer
->curr
));
2573 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2577 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
) {
2578 loc_block_len
= stream_getc(peer
->curr
);
2579 loc_node_len
= stream_getc(peer
->curr
);
2580 func_len
= stream_getc(peer
->curr
);
2581 arg_len
= stream_getc(peer
->curr
);
2582 transposition_len
= stream_getc(peer
->curr
);
2583 transposition_offset
= stream_getc(peer
->curr
);
2585 /* Log SRv6 Service Data Sub-Sub-TLV */
2586 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2588 "%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",
2589 __func__
, loc_block_len
, loc_node_len
, func_len
,
2590 arg_len
, transposition_len
,
2591 transposition_offset
);
2594 attr
->srv6_l3vpn
->loc_block_len
= loc_block_len
;
2595 attr
->srv6_l3vpn
->loc_node_len
= loc_node_len
;
2596 attr
->srv6_l3vpn
->func_len
= func_len
;
2597 attr
->srv6_l3vpn
->arg_len
= arg_len
;
2598 attr
->srv6_l3vpn
->transposition_len
= transposition_len
;
2599 attr
->srv6_l3vpn
->transposition_offset
= transposition_offset
;
2603 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2605 "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
2608 stream_forward_getp(peer
->curr
, length
);
2611 return BGP_ATTR_PARSE_PROCEED
;
2614 /* SRv6 Service Sub-TLV attribute
2615 * draft-ietf-bess-srv6-services-07
2617 static bgp_attr_parse_ret_t
2618 bgp_attr_srv6_service(struct bgp_attr_parser_args
*args
)
2620 struct peer
*const peer
= args
->peer
;
2621 struct attr
*const attr
= args
->attr
;
2622 struct in6_addr ipv6_sid
;
2623 uint8_t type
, sid_flags
;
2624 uint16_t length
, endpoint_behavior
;
2625 size_t headersz
= sizeof(type
) + sizeof(length
);
2626 bgp_attr_parse_ret_t err
;
2629 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2632 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2633 headersz
, STREAM_READABLE(peer
->curr
));
2634 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2638 type
= stream_getc(peer
->curr
);
2639 length
= stream_getw(peer
->curr
);
2641 if (STREAM_READABLE(peer
->curr
) < length
) {
2644 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2645 length
, STREAM_READABLE(peer
->curr
));
2646 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2650 if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
) {
2651 stream_getc(peer
->curr
);
2652 stream_get(&ipv6_sid
, peer
->curr
, sizeof(ipv6_sid
));
2653 sid_flags
= stream_getc(peer
->curr
);
2654 endpoint_behavior
= stream_getw(peer
->curr
);
2655 stream_getc(peer
->curr
);
2657 /* Log SRv6 Service Sub-TLV */
2658 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2659 inet_ntop(AF_INET6
, &ipv6_sid
, buf
, sizeof(buf
));
2661 "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
2662 __func__
, buf
, sid_flags
, endpoint_behavior
);
2665 /* Configure from Info */
2666 if (attr
->srv6_l3vpn
) {
2667 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2668 "Prefix SID SRv6 L3VPN field repeated");
2669 return bgp_attr_malformed(
2670 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2672 attr
->srv6_l3vpn
= XCALLOC(MTYPE_BGP_SRV6_L3VPN
,
2673 sizeof(struct bgp_attr_srv6_l3vpn
));
2674 sid_copy(&attr
->srv6_l3vpn
->sid
, &ipv6_sid
);
2675 attr
->srv6_l3vpn
->sid_flags
= sid_flags
;
2676 attr
->srv6_l3vpn
->endpoint_behavior
= endpoint_behavior
;
2677 attr
->srv6_l3vpn
->loc_block_len
= 0;
2678 attr
->srv6_l3vpn
->loc_node_len
= 0;
2679 attr
->srv6_l3vpn
->func_len
= 0;
2680 attr
->srv6_l3vpn
->arg_len
= 0;
2681 attr
->srv6_l3vpn
->transposition_len
= 0;
2682 attr
->srv6_l3vpn
->transposition_offset
= 0;
2684 // Sub-Sub-TLV found
2685 if (length
> BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
) {
2686 err
= bgp_attr_srv6_service_data(args
);
2688 if (err
!= BGP_ATTR_PARSE_PROCEED
)
2692 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
2695 /* Placeholder code for unsupported type */
2697 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2699 "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
2702 stream_forward_getp(peer
->curr
, length
);
2705 return BGP_ATTR_PARSE_PROCEED
;
2709 * Read an individual SID value returning how much data we have read
2710 * Returns 0 if there was an error that needs to be passed up the stack
2712 static bgp_attr_parse_ret_t
bgp_attr_psid_sub(uint8_t type
, uint16_t length
,
2713 struct bgp_attr_parser_args
*args
)
2715 struct peer
*const peer
= args
->peer
;
2716 struct attr
*const attr
= args
->attr
;
2717 uint32_t label_index
;
2718 struct in6_addr ipv6_sid
;
2720 uint32_t srgb_range
;
2722 uint8_t sid_type
, sid_flags
;
2725 if (type
== BGP_PREFIX_SID_LABEL_INDEX
) {
2726 if (STREAM_READABLE(peer
->curr
) < length
2727 || length
!= BGP_PREFIX_SID_LABEL_INDEX_LENGTH
) {
2728 flog_err(EC_BGP_ATTR_LEN
,
2729 "Prefix SID label index length is %hu instead of %u",
2730 length
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
2731 return bgp_attr_malformed(args
,
2732 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2736 /* Ignore flags and reserved */
2737 stream_getc(peer
->curr
);
2738 stream_getw(peer
->curr
);
2740 /* Fetch the label index and see if it is valid. */
2741 label_index
= stream_getl(peer
->curr
);
2742 if (label_index
== BGP_INVALID_LABEL_INDEX
)
2743 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2746 /* Store label index; subsequently, we'll check on
2748 attr
->label_index
= label_index
;
2751 /* Placeholder code for the IPv6 SID type */
2752 else if (type
== BGP_PREFIX_SID_IPV6
) {
2753 if (STREAM_READABLE(peer
->curr
) < length
2754 || length
!= BGP_PREFIX_SID_IPV6_LENGTH
) {
2755 flog_err(EC_BGP_ATTR_LEN
,
2756 "Prefix SID IPv6 length is %hu instead of %u",
2757 length
, BGP_PREFIX_SID_IPV6_LENGTH
);
2758 return bgp_attr_malformed(args
,
2759 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2763 /* Ignore reserved */
2764 stream_getc(peer
->curr
);
2765 stream_getw(peer
->curr
);
2767 stream_get(&ipv6_sid
, peer
->curr
, 16);
2770 /* Placeholder code for the Originator SRGB type */
2771 else if (type
== BGP_PREFIX_SID_ORIGINATOR_SRGB
) {
2773 * ietf-idr-bgp-prefix-sid-05:
2774 * Length is the total length of the value portion of the
2775 * TLV: 2 + multiple of 6.
2777 * peer->curr stream readp should be at the beginning of the 16
2778 * bit flag field at this point in the code.
2782 * Check that the TLV length field is sane: at least 2 bytes of
2783 * flag, and at least 1 SRGB (these are 6 bytes each)
2785 if (length
< (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
)) {
2788 "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
2790 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
2791 return bgp_attr_malformed(
2792 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2797 * Check that we actually have at least as much data as
2798 * specified by the length field
2800 if (STREAM_READABLE(peer
->curr
) < length
) {
2801 flog_err(EC_BGP_ATTR_LEN
,
2802 "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain",
2803 length
, STREAM_READABLE(peer
->curr
));
2804 return bgp_attr_malformed(
2805 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2810 * Check that the portion of the TLV containing the sequence of
2811 * SRGBs corresponds to a multiple of the SRGB size; to get
2812 * that length, we skip the 16 bit flags field
2814 stream_getw(peer
->curr
);
2816 if (length
% BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
) {
2819 "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
2820 length
, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
2821 return bgp_attr_malformed(
2822 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2826 srgb_count
= length
/ BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
;
2828 for (int i
= 0; i
< srgb_count
; i
++) {
2829 stream_get(&srgb_base
, peer
->curr
, 3);
2830 stream_get(&srgb_range
, peer
->curr
, 3);
2834 /* Placeholder code for the VPN-SID Service type */
2835 else if (type
== BGP_PREFIX_SID_VPN_SID
) {
2836 if (STREAM_READABLE(peer
->curr
) < length
2837 || length
!= BGP_PREFIX_SID_VPN_SID_LENGTH
) {
2838 flog_err(EC_BGP_ATTR_LEN
,
2839 "Prefix SID VPN SID length is %hu instead of %u",
2840 length
, BGP_PREFIX_SID_VPN_SID_LENGTH
);
2841 return bgp_attr_malformed(args
,
2842 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2846 /* Parse VPN-SID Sub-TLV */
2847 stream_getc(peer
->curr
); /* reserved */
2848 sid_type
= stream_getc(peer
->curr
); /* sid_type */
2849 sid_flags
= stream_getc(peer
->curr
); /* sid_flags */
2850 stream_get(&ipv6_sid
, peer
->curr
,
2851 sizeof(ipv6_sid
)); /* sid_value */
2853 /* Log VPN-SID Sub-TLV */
2854 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2855 inet_ntop(AF_INET6
, &ipv6_sid
, buf
, sizeof(buf
));
2857 "%s: vpn-sid: sid %s, sid-type 0x%02x sid-flags 0x%02x",
2858 __func__
, buf
, sid_type
, sid_flags
);
2861 /* Configure from Info */
2862 if (attr
->srv6_vpn
) {
2863 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2864 "Prefix SID SRv6 VPN field repeated");
2865 return bgp_attr_malformed(
2866 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2868 attr
->srv6_vpn
= XCALLOC(MTYPE_BGP_SRV6_VPN
,
2869 sizeof(struct bgp_attr_srv6_vpn
));
2870 attr
->srv6_vpn
->sid_flags
= sid_flags
;
2871 sid_copy(&attr
->srv6_vpn
->sid
, &ipv6_sid
);
2872 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
2875 /* Placeholder code for the SRv6 L3 Service type */
2876 else if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE
) {
2877 if (STREAM_READABLE(peer
->curr
) < length
) {
2880 "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain",
2881 length
, STREAM_READABLE(peer
->curr
));
2882 return bgp_attr_malformed(args
,
2883 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2887 /* ignore reserved */
2888 stream_getc(peer
->curr
);
2890 return bgp_attr_srv6_service(args
);
2893 /* Placeholder code for Unsupported TLV */
2896 if (STREAM_READABLE(peer
->curr
) < length
) {
2899 "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE",
2900 length
, STREAM_READABLE(peer
->curr
));
2901 return bgp_attr_malformed(
2902 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2906 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2908 "%s attr Prefix-SID sub-type=%u is not supported, skipped",
2911 stream_forward_getp(peer
->curr
, length
);
2914 return BGP_ATTR_PARSE_PROCEED
;
2917 /* Prefix SID attribute
2918 * draft-ietf-idr-bgp-prefix-sid-05
2920 bgp_attr_parse_ret_t
bgp_attr_prefix_sid(struct bgp_attr_parser_args
*args
)
2922 struct peer
*const peer
= args
->peer
;
2923 struct attr
*const attr
= args
->attr
;
2924 bgp_attr_parse_ret_t ret
;
2926 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
);
2930 size_t headersz
= sizeof(type
) + sizeof(length
);
2931 size_t psid_parsed_length
= 0;
2933 while (STREAM_READABLE(peer
->curr
) > 0
2934 && psid_parsed_length
< args
->length
) {
2936 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2939 "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2940 headersz
, STREAM_READABLE(peer
->curr
));
2941 return bgp_attr_malformed(
2942 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2946 type
= stream_getc(peer
->curr
);
2947 length
= stream_getw(peer
->curr
);
2949 if (STREAM_READABLE(peer
->curr
) < length
) {
2952 "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
2953 length
, STREAM_READABLE(peer
->curr
));
2954 return bgp_attr_malformed(args
,
2955 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2959 ret
= bgp_attr_psid_sub(type
, length
, args
);
2961 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
2964 psid_parsed_length
+= length
+ headersz
;
2966 if (psid_parsed_length
> args
->length
) {
2969 "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
2970 length
+ headersz
, psid_parsed_length
- (length
+ headersz
));
2971 return bgp_attr_malformed(
2972 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2977 return BGP_ATTR_PARSE_PROCEED
;
2980 /* PMSI tunnel attribute (RFC 6514)
2981 * Basic validation checks done here.
2983 static bgp_attr_parse_ret_t
2984 bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args
*args
)
2986 struct peer
*const peer
= args
->peer
;
2987 struct attr
*const attr
= args
->attr
;
2988 const bgp_size_t length
= args
->length
;
2990 int attr_parse_len
= 2 + BGP_LABEL_BYTES
;
2992 /* Verify that the receiver is expecting "ingress replication" as we
2993 * can only support that.
2995 if (length
< attr_parse_len
) {
2996 flog_err(EC_BGP_ATTR_LEN
, "Bad PMSI tunnel attribute length %d",
2998 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3001 stream_getc(peer
->curr
); /* Flags */
3002 tnl_type
= stream_getc(peer
->curr
);
3003 if (tnl_type
> PMSI_TNLTYPE_MAX
) {
3004 flog_err(EC_BGP_ATTR_PMSI_TYPE
,
3005 "Invalid PMSI tunnel attribute type %d", tnl_type
);
3006 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
3009 if (tnl_type
== PMSI_TNLTYPE_INGR_REPL
) {
3011 flog_err(EC_BGP_ATTR_PMSI_LEN
,
3012 "Bad PMSI tunnel attribute length %d for IR",
3014 return bgp_attr_malformed(
3015 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
3020 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
);
3021 bgp_attr_set_pmsi_tnl_type(attr
, tnl_type
);
3022 stream_get(&attr
->label
, peer
->curr
, BGP_LABEL_BYTES
);
3024 /* Forward read pointer of input stream. */
3025 stream_forward_getp(peer
->curr
, length
- attr_parse_len
);
3027 return BGP_ATTR_PARSE_PROCEED
;
3030 /* BGP unknown attribute treatment. */
3031 static bgp_attr_parse_ret_t
bgp_attr_unknown(struct bgp_attr_parser_args
*args
)
3033 bgp_size_t total
= args
->total
;
3034 struct transit
*transit
;
3035 struct peer
*const peer
= args
->peer
;
3036 struct attr
*const attr
= args
->attr
;
3037 uint8_t *const startp
= args
->startp
;
3038 const uint8_t type
= args
->type
;
3039 const uint8_t flag
= args
->flags
;
3040 const bgp_size_t length
= args
->length
;
3042 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
3044 "%s Unknown attribute is received (type %d, length %d)",
3045 peer
->host
, type
, length
);
3047 /* Forward read pointer of input stream. */
3048 stream_forward_getp(peer
->curr
, length
);
3050 /* If any of the mandatory well-known attributes are not recognized,
3051 then the Error Subcode is set to Unrecognized Well-known
3052 Attribute. The Data field contains the unrecognized attribute
3053 (type, length and value). */
3054 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
3055 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_UNREC_ATTR
,
3059 /* Unrecognized non-transitive optional attributes must be quietly
3060 ignored and not passed along to other BGP peers. */
3061 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
))
3062 return BGP_ATTR_PARSE_PROCEED
;
3064 /* If a path with recognized transitive optional attribute is
3065 accepted and passed along to other BGP peers and the Partial bit
3066 in the Attribute Flags octet is set to 1 by some previous AS, it
3067 is not set back to 0 by the current AS. */
3068 SET_FLAG(*startp
, BGP_ATTR_FLAG_PARTIAL
);
3070 /* Store transitive attribute to the end of attr->transit. */
3071 transit
= bgp_attr_get_transit(attr
);
3073 transit
= XCALLOC(MTYPE_TRANSIT
, sizeof(struct transit
));
3075 transit
->val
= XREALLOC(MTYPE_TRANSIT_VAL
, transit
->val
,
3076 transit
->length
+ total
);
3078 memcpy(transit
->val
+ transit
->length
, startp
, total
);
3079 transit
->length
+= total
;
3080 bgp_attr_set_transit(attr
, transit
);
3082 return BGP_ATTR_PARSE_PROCEED
;
3085 /* Well-known attribute check. */
3086 static int bgp_attr_check(struct peer
*peer
, struct attr
*attr
)
3090 /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
3092 if (CHECK_FLAG(peer
->cap
, PEER_CAP_RESTART_RCV
) && !attr
->flag
)
3093 return BGP_ATTR_PARSE_PROCEED
;
3095 /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
3096 to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
3097 are present, it should. Check for any other attribute being present
3100 if ((!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)) &&
3101 CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
))))
3102 return BGP_ATTR_PARSE_PROCEED
;
3104 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
)))
3105 type
= BGP_ATTR_ORIGIN
;
3107 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
3108 type
= BGP_ATTR_AS_PATH
;
3110 /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
3112 * NLRI is empty. We can't easily check NLRI empty here though.
3114 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3115 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)))
3116 type
= BGP_ATTR_NEXT_HOP
;
3118 if (peer
->sort
== BGP_PEER_IBGP
3119 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)))
3120 type
= BGP_ATTR_LOCAL_PREF
;
3122 /* If any of the well-known mandatory attributes are not present
3123 * in an UPDATE message, then "treat-as-withdraw" MUST be used.
3126 flog_warn(EC_BGP_MISSING_ATTRIBUTE
,
3127 "%s Missing well-known attribute %s.", peer
->host
,
3128 lookup_msg(attr_str
, type
, NULL
));
3129 return BGP_ATTR_PARSE_WITHDRAW
;
3131 return BGP_ATTR_PARSE_PROCEED
;
3134 /* Read attribute of update packet. This function is called from
3135 bgp_update_receive() in bgp_packet.c. */
3136 bgp_attr_parse_ret_t
bgp_attr_parse(struct peer
*peer
, struct attr
*attr
,
3137 bgp_size_t size
, struct bgp_nlri
*mp_update
,
3138 struct bgp_nlri
*mp_withdraw
)
3140 bgp_attr_parse_ret_t ret
;
3144 uint8_t *startp
, *endp
;
3146 uint8_t seen
[BGP_ATTR_BITMAP_SIZE
];
3147 /* we need the as4_path only until we have synthesized the as_path with
3149 /* same goes for as4_aggregator */
3150 struct aspath
*as4_path
= NULL
;
3151 as_t as4_aggregator
= 0;
3152 struct in_addr as4_aggregator_addr
= {.s_addr
= 0};
3153 struct transit
*transit
;
3155 /* Initialize bitmap. */
3156 memset(seen
, 0, BGP_ATTR_BITMAP_SIZE
);
3158 /* End pointer of BGP attribute. */
3159 endp
= BGP_INPUT_PNT(peer
) + size
;
3161 /* Get attributes to the end of attribute length. */
3162 while (BGP_INPUT_PNT(peer
) < endp
) {
3163 /* Check remaining length check.*/
3164 if (endp
- BGP_INPUT_PNT(peer
) < BGP_ATTR_MIN_LEN
) {
3165 /* XXX warning: long int format, int arg (arg 5) */
3167 EC_BGP_ATTRIBUTE_TOO_SMALL
,
3168 "%s: error BGP attribute length %lu is smaller than min len",
3170 (unsigned long)(endp
3171 - stream_pnt(BGP_INPUT(peer
))));
3173 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3174 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3175 ret
= BGP_ATTR_PARSE_ERROR
;
3179 /* Fetch attribute flag and type. */
3180 startp
= BGP_INPUT_PNT(peer
);
3181 /* "The lower-order four bits of the Attribute Flags octet are
3182 unused. They MUST be zero when sent and MUST be ignored when
3184 flag
= 0xF0 & stream_getc(BGP_INPUT(peer
));
3185 type
= stream_getc(BGP_INPUT(peer
));
3187 /* Check whether Extended-Length applies and is in bounds */
3188 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
)
3189 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1))) {
3191 EC_BGP_EXT_ATTRIBUTE_TOO_SMALL
,
3192 "%s: Extended length set, but just %lu bytes of attr header",
3194 (unsigned long)(endp
3195 - stream_pnt(BGP_INPUT(peer
))));
3197 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3198 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3199 ret
= BGP_ATTR_PARSE_ERROR
;
3203 /* Check extended attribue length bit. */
3204 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
))
3205 length
= stream_getw(BGP_INPUT(peer
));
3207 length
= stream_getc(BGP_INPUT(peer
));
3209 /* If any attribute appears more than once in the UPDATE
3210 message, then the Error Subcode is set to Malformed Attribute
3213 if (CHECK_BITMAP(seen
, type
)) {
3215 EC_BGP_ATTRIBUTE_REPEATED
,
3216 "%s: error BGP attribute type %d appears twice in a message",
3219 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3220 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3221 ret
= BGP_ATTR_PARSE_ERROR
;
3225 /* Set type to bitmap to check duplicate attribute. `type' is
3226 unsigned char so it never overflow bitmap range. */
3228 SET_BITMAP(seen
, type
);
3230 /* Overflow check. */
3231 attr_endp
= BGP_INPUT_PNT(peer
) + length
;
3233 if (attr_endp
> endp
) {
3235 EC_BGP_ATTRIBUTE_TOO_LARGE
,
3236 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
3237 peer
->host
, type
, length
, size
, attr_endp
,
3241 * If any recognized attribute has an Attribute
3242 * Length that conflicts with the expected length
3243 * (based on the attribute type code), then the
3244 * Error Subcode MUST be set to Attribute Length
3245 * Error. The Data field MUST contain the erroneous
3246 * attribute (type, length, and value).
3248 * We do not currently have a good way to determine the
3249 * length of the attribute independent of the length
3250 * received in the message. Instead we send the
3251 * minimum between the amount of data we have and the
3252 * amount specified by the attribute length field.
3254 * Instead of directly passing in the packet buffer and
3255 * offset we use the stream_get* functions to read into
3256 * a stack buffer, since they perform bounds checking
3257 * and we are working with untrusted data.
3259 unsigned char ndata
[peer
->max_packet_size
];
3260 memset(ndata
, 0x00, sizeof(ndata
));
3262 CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 2 : 1;
3263 /* Rewind to end of flag field */
3264 stream_rewind_getp(BGP_INPUT(peer
), (1 + lfl
));
3266 stream_get(&ndata
[0], BGP_INPUT(peer
), 1);
3268 stream_get(&ndata
[1], BGP_INPUT(peer
), lfl
);
3270 size_t atl
= attr_endp
- startp
;
3271 size_t ndl
= MIN(atl
, STREAM_READABLE(BGP_INPUT(peer
)));
3272 stream_get(&ndata
[lfl
+ 1], BGP_INPUT(peer
), ndl
);
3274 bgp_notify_send_with_data(
3275 peer
, BGP_NOTIFY_UPDATE_ERR
,
3276 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
, ndata
,
3279 ret
= BGP_ATTR_PARSE_ERROR
;
3283 struct bgp_attr_parser_args attr_args
= {
3290 .total
= attr_endp
- startp
,
3294 /* If any recognized attribute has Attribute Flags that conflict
3295 with the Attribute Type Code, then the Error Subcode is set
3297 Attribute Flags Error. The Data field contains the erroneous
3298 attribute (type, length and value). */
3299 if (bgp_attr_flag_invalid(&attr_args
)) {
3300 ret
= bgp_attr_malformed(
3301 &attr_args
, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
3303 if (ret
== BGP_ATTR_PARSE_PROCEED
)
3308 /* OK check attribute and store it's value. */
3310 case BGP_ATTR_ORIGIN
:
3311 ret
= bgp_attr_origin(&attr_args
);
3313 case BGP_ATTR_AS_PATH
:
3314 ret
= bgp_attr_aspath(&attr_args
);
3316 case BGP_ATTR_AS4_PATH
:
3317 ret
= bgp_attr_as4_path(&attr_args
, &as4_path
);
3319 case BGP_ATTR_NEXT_HOP
:
3320 ret
= bgp_attr_nexthop(&attr_args
);
3322 case BGP_ATTR_MULTI_EXIT_DISC
:
3323 ret
= bgp_attr_med(&attr_args
);
3325 case BGP_ATTR_LOCAL_PREF
:
3326 ret
= bgp_attr_local_pref(&attr_args
);
3328 case BGP_ATTR_ATOMIC_AGGREGATE
:
3329 ret
= bgp_attr_atomic(&attr_args
);
3331 case BGP_ATTR_AGGREGATOR
:
3332 ret
= bgp_attr_aggregator(&attr_args
);
3334 case BGP_ATTR_AS4_AGGREGATOR
:
3335 ret
= bgp_attr_as4_aggregator(&attr_args
,
3337 &as4_aggregator_addr
);
3339 case BGP_ATTR_COMMUNITIES
:
3340 ret
= bgp_attr_community(&attr_args
);
3342 case BGP_ATTR_LARGE_COMMUNITIES
:
3343 ret
= bgp_attr_large_community(&attr_args
);
3345 case BGP_ATTR_ORIGINATOR_ID
:
3346 ret
= bgp_attr_originator_id(&attr_args
);
3348 case BGP_ATTR_CLUSTER_LIST
:
3349 ret
= bgp_attr_cluster_list(&attr_args
);
3351 case BGP_ATTR_MP_REACH_NLRI
:
3352 ret
= bgp_mp_reach_parse(&attr_args
, mp_update
);
3354 case BGP_ATTR_MP_UNREACH_NLRI
:
3355 ret
= bgp_mp_unreach_parse(&attr_args
, mp_withdraw
);
3357 case BGP_ATTR_EXT_COMMUNITIES
:
3358 ret
= bgp_attr_ext_communities(&attr_args
);
3360 #ifdef ENABLE_BGP_VNC_ATTR
3363 case BGP_ATTR_ENCAP
:
3364 ret
= bgp_attr_encap(type
, peer
, length
, attr
, flag
,
3367 case BGP_ATTR_PREFIX_SID
:
3368 ret
= bgp_attr_prefix_sid(&attr_args
);
3370 case BGP_ATTR_PMSI_TUNNEL
:
3371 ret
= bgp_attr_pmsi_tunnel(&attr_args
);
3373 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
3374 ret
= bgp_attr_ipv6_ext_communities(&attr_args
);
3377 ret
= bgp_attr_unknown(&attr_args
);
3381 if (ret
== BGP_ATTR_PARSE_ERROR_NOTIFYPLS
) {
3382 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3383 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3384 ret
= BGP_ATTR_PARSE_ERROR
;
3388 if (ret
== BGP_ATTR_PARSE_EOR
) {
3392 if (ret
== BGP_ATTR_PARSE_ERROR
) {
3393 flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR
,
3394 "%s: Attribute %s, parse error", peer
->host
,
3395 lookup_msg(attr_str
, type
, NULL
));
3398 if (ret
== BGP_ATTR_PARSE_WITHDRAW
) {
3400 EC_BGP_ATTRIBUTE_PARSE_WITHDRAW
,
3401 "%s: Attribute %s, parse error - treating as withdrawal",
3402 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3406 /* Check the fetched length. */
3407 if (BGP_INPUT_PNT(peer
) != attr_endp
) {
3408 flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR
,
3409 "%s: BGP attribute %s, fetch error",
3410 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3411 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3412 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3413 ret
= BGP_ATTR_PARSE_ERROR
;
3419 * draft-ietf-idr-bgp-prefix-sid-27#section-3:
3420 * About Prefix-SID path attribute,
3421 * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
3422 * may only appear in a BGP Prefix-SID attribute attached to
3423 * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
3424 * It MUST be ignored when received for other BGP AFI/SAFI combinations.
3426 if (!attr
->mp_nexthop_len
|| mp_update
->safi
!= SAFI_LABELED_UNICAST
)
3427 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
3429 /* Check final read pointer is same as end pointer. */
3430 if (BGP_INPUT_PNT(peer
) != endp
) {
3431 flog_warn(EC_BGP_ATTRIBUTES_MISMATCH
,
3432 "%s: BGP attribute %s, length mismatch", peer
->host
,
3433 lookup_msg(attr_str
, type
, NULL
));
3434 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3435 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3437 ret
= BGP_ATTR_PARSE_ERROR
;
3442 * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
3443 * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
3444 * This is implemented below and will result in a NOTIFICATION. If the
3445 * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
3446 * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
3447 * message SHOULD NOT be sent. This is implemented elsewhere.
3449 * RFC4760: An UPDATE message that carries no NLRI, other than the one
3450 * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
3451 * attribute. If such a message contains the NEXT_HOP attribute, the BGP
3452 * speaker that receives the message SHOULD ignore this attribute.
3454 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3455 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
))) {
3456 if (bgp_attr_nexthop_valid(peer
, attr
) < 0) {
3457 ret
= BGP_ATTR_PARSE_ERROR
;
3462 /* Check all mandatory well-known attributes are present */
3463 ret
= bgp_attr_check(peer
, attr
);
3468 * At this place we can see whether we got AS4_PATH and/or
3469 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
3470 * We can not do this before we've read all attributes because
3471 * the as4 handling does not say whether AS4_PATH has to be sent
3472 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
3473 * in relationship to AGGREGATOR.
3474 * So, to be defensive, we are not relying on any order and read
3475 * all attributes first, including these 32bit ones, and now,
3476 * afterwards, we look what and if something is to be done for as4.
3478 * It is possible to not have AS_PATH, e.g. GR EoR and sole
3481 /* actually... this doesn't ever return failure currently, but
3482 * better safe than sorry */
3483 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))
3484 && bgp_attr_munge_as4_attrs(peer
, attr
, as4_path
, as4_aggregator
,
3485 &as4_aggregator_addr
)) {
3486 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3487 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3488 ret
= BGP_ATTR_PARSE_ERROR
;
3493 * Finally do the checks on the aspath we did not do yet
3494 * because we waited for a potentially synthesized aspath.
3496 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))) {
3497 ret
= bgp_attr_aspath_check(peer
, attr
);
3498 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3502 ret
= BGP_ATTR_PARSE_PROCEED
;
3506 * At this stage, we have done all fiddling with as4, and the
3507 * resulting info is in attr->aggregator resp. attr->aspath so
3508 * we can chuck as4_aggregator and as4_path alltogether in order
3513 * unintern - it is in the hash
3514 * The flag that we got this is still there, but that
3515 * does not do any trouble
3517 aspath_unintern(&as4_path
);
3520 transit
= bgp_attr_get_transit(attr
);
3521 if (ret
!= BGP_ATTR_PARSE_ERROR
) {
3522 /* Finally intern unknown attribute. */
3524 bgp_attr_set_transit(attr
, transit_intern(transit
));
3525 if (attr
->encap_subtlvs
)
3526 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
3528 #ifdef ENABLE_BGP_VNC
3529 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3530 bgp_attr_get_vnc_subtlvs(attr
);
3533 bgp_attr_set_vnc_subtlvs(
3535 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
3539 transit_free(transit
);
3540 bgp_attr_set_transit(attr
, NULL
);
3543 bgp_attr_flush_encap(attr
);
3547 transit
= bgp_attr_get_transit(attr
);
3549 assert(transit
->refcnt
> 0);
3550 if (attr
->encap_subtlvs
)
3551 assert(attr
->encap_subtlvs
->refcnt
> 0);
3552 #ifdef ENABLE_BGP_VNC
3553 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3554 bgp_attr_get_vnc_subtlvs(attr
);
3557 assert(vnc_subtlvs
->refcnt
> 0);
3564 * Extract the tunnel type from extended community
3566 void bgp_attr_extcom_tunnel_type(struct attr
*attr
,
3567 bgp_encap_types
*tunnel_type
)
3569 struct ecommunity
*ecom
;
3575 ecom
= attr
->ecommunity
;
3576 if (!ecom
|| !ecom
->size
)
3579 for (i
= 0; i
< ecom
->size
; i
++) {
3581 uint8_t type
, sub_type
;
3583 pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
3586 if (!(type
== ECOMMUNITY_ENCODE_OPAQUE
&&
3587 sub_type
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
))
3589 *tunnel_type
= ((pnt
[6] << 8) | pnt
[7]);
3596 size_t bgp_packet_mpattr_start(struct stream
*s
, struct peer
*peer
, afi_t afi
,
3597 safi_t safi
, struct bpacket_attr_vec_arr
*vecarr
,
3602 iana_safi_t pkt_safi
;
3605 /* Set extended bit always to encode the attribute length as 2 bytes */
3606 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
3607 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
3608 sizep
= stream_get_endp(s
);
3609 stream_putw(s
, 0); /* Marker: Attribute length. */
3612 /* Convert AFI, SAFI to values for packet. */
3613 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
3615 stream_putw(s
, pkt_afi
); /* AFI */
3616 stream_putc(s
, pkt_safi
); /* SAFI */
3620 && (safi
== SAFI_UNICAST
|| safi
== SAFI_LABELED_UNICAST
3621 || safi
== SAFI_MPLS_VPN
|| safi
== SAFI_MULTICAST
))
3622 nh_afi
= peer_cap_enhe(peer
, afi
, safi
) ? AFI_IP6
: AFI_IP
;
3623 else if (safi
== SAFI_FLOWSPEC
)
3626 nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
3629 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
3634 case SAFI_MULTICAST
:
3635 case SAFI_LABELED_UNICAST
:
3637 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3641 stream_putl(s
, 0); /* RD = 0, per RFC */
3643 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3648 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3651 if (attr
->mp_nexthop_len
== 0)
3652 stream_putc(s
, 0); /* no nexthop for flowspec */
3654 stream_putc(s
, attr
->mp_nexthop_len
);
3655 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3664 case SAFI_MULTICAST
:
3665 case SAFI_LABELED_UNICAST
:
3667 if (attr
->mp_nexthop_len
3668 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3670 BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
);
3671 stream_put(s
, &attr
->mp_nexthop_global
,
3673 stream_put(s
, &attr
->mp_nexthop_local
,
3676 stream_putc(s
, IPV6_MAX_BYTELEN
);
3677 stream_put(s
, &attr
->mp_nexthop_global
,
3681 case SAFI_MPLS_VPN
: {
3682 if (attr
->mp_nexthop_len
3683 == BGP_ATTR_NHLEN_IPV6_GLOBAL
) {
3685 stream_putl(s
, 0); /* RD = 0, per RFC */
3687 stream_put(s
, &attr
->mp_nexthop_global
,
3689 } else if (attr
->mp_nexthop_len
3690 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3692 stream_putl(s
, 0); /* RD = 0, per RFC */
3694 stream_put(s
, &attr
->mp_nexthop_global
,
3696 stream_putl(s
, 0); /* RD = 0, per RFC */
3698 stream_put(s
, &attr
->mp_nexthop_local
,
3703 stream_putc(s
, IPV6_MAX_BYTELEN
);
3704 stream_put(s
, &attr
->mp_nexthop_global
,
3708 stream_putc(s
, 0); /* no nexthop for flowspec */
3714 if (safi
!= SAFI_FLOWSPEC
)
3716 EC_BGP_ATTR_NH_SEND_LEN
,
3717 "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
3718 peer
->host
, afi
, safi
, attr
->mp_nexthop_len
);
3727 void bgp_packet_mpattr_prefix(struct stream
*s
, afi_t afi
, safi_t safi
,
3728 const struct prefix
*p
,
3729 const struct prefix_rd
*prd
, mpls_label_t
*label
,
3730 uint32_t num_labels
, bool addpath_capable
,
3731 uint32_t addpath_tx_id
, struct attr
*attr
)
3733 if (safi
== SAFI_MPLS_VPN
) {
3734 if (addpath_capable
)
3735 stream_putl(s
, addpath_tx_id
);
3736 /* Label, RD, Prefix write. */
3737 stream_putc(s
, p
->prefixlen
+ 88);
3738 stream_put(s
, label
, BGP_LABEL_BYTES
);
3739 stream_put(s
, prd
->val
, 8);
3740 stream_put(s
, &p
->u
.prefix
, PSIZE(p
->prefixlen
));
3741 } else if (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
) {
3742 /* EVPN prefix - contents depend on type */
3743 bgp_evpn_encode_prefix(s
, p
, prd
, label
, num_labels
, attr
,
3744 addpath_capable
, addpath_tx_id
);
3745 } else if (safi
== SAFI_LABELED_UNICAST
) {
3746 /* Prefix write with label. */
3747 stream_put_labeled_prefix(s
, p
, label
, addpath_capable
,
3749 } else if (safi
== SAFI_FLOWSPEC
) {
3750 stream_putc(s
, p
->u
.prefix_flowspec
.prefixlen
);
3751 stream_put(s
, (const void *)p
->u
.prefix_flowspec
.ptr
,
3752 p
->u
.prefix_flowspec
.prefixlen
);
3754 stream_put_prefix_addpath(s
, p
, addpath_capable
, addpath_tx_id
);
3757 size_t bgp_packet_mpattr_prefix_size(afi_t afi
, safi_t safi
,
3758 const struct prefix
*p
)
3760 int size
= PSIZE(p
->prefixlen
);
3761 if (safi
== SAFI_MPLS_VPN
)
3763 else if (safi
== SAFI_LABELED_UNICAST
)
3764 size
+= BGP_LABEL_BYTES
;
3765 else if (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)
3766 size
+= 232; // TODO: Maximum possible for type-2, type-3 and
3772 * Encodes the tunnel encapsulation attribute,
3773 * and with ENABLE_BGP_VNC the VNC attribute which uses
3774 * almost the same TLV format
3776 static void bgp_packet_mpattr_tea(struct bgp
*bgp
, struct peer
*peer
,
3777 struct stream
*s
, struct attr
*attr
,
3780 unsigned int attrlenfield
= 0;
3781 unsigned int attrhdrlen
= 0;
3782 struct bgp_attr_encap_subtlv
*subtlvs
;
3783 struct bgp_attr_encap_subtlv
*st
;
3784 const char *attrname
;
3786 if (!attr
|| (attrtype
== BGP_ATTR_ENCAP
3787 && (!attr
->encap_tunneltype
3788 || attr
->encap_tunneltype
== BGP_ENCAP_TYPE_MPLS
)))
3792 case BGP_ATTR_ENCAP
:
3793 attrname
= "Tunnel Encap";
3794 subtlvs
= attr
->encap_subtlvs
;
3795 if (subtlvs
== NULL
) /* nothing to do */
3798 * The tunnel encap attr has an "outer" tlv.
3800 * L = total length of subtlvs,
3801 * V = concatenated subtlvs.
3803 attrlenfield
= 2 + 2; /* T + L */
3804 attrhdrlen
= 1 + 1; /* subTLV T + L */
3807 #ifdef ENABLE_BGP_VNC_ATTR
3810 subtlvs
= bgp_attr_get_vnc_subtlvs(attr
);
3811 if (subtlvs
== NULL
) /* nothing to do */
3813 attrlenfield
= 0; /* no outer T + L */
3814 attrhdrlen
= 2 + 2; /* subTLV T + L */
3822 /* compute attr length */
3823 for (st
= subtlvs
; st
; st
= st
->next
) {
3824 attrlenfield
+= (attrhdrlen
+ st
->length
);
3827 if (attrlenfield
> 0xffff) {
3828 zlog_info("%s attribute is too long (length=%d), can't send it",
3829 attrname
, attrlenfield
);
3833 if (attrlenfield
> 0xff) {
3834 /* 2-octet length field */
3836 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
3837 | BGP_ATTR_FLAG_EXTLEN
);
3838 stream_putc(s
, attrtype
);
3839 stream_putw(s
, attrlenfield
& 0xffff);
3841 /* 1-octet length field */
3842 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
);
3843 stream_putc(s
, attrtype
);
3844 stream_putc(s
, attrlenfield
& 0xff);
3847 if (attrtype
== BGP_ATTR_ENCAP
) {
3848 /* write outer T+L */
3849 stream_putw(s
, attr
->encap_tunneltype
);
3850 stream_putw(s
, attrlenfield
- 4);
3853 /* write each sub-tlv */
3854 for (st
= subtlvs
; st
; st
= st
->next
) {
3855 if (attrtype
== BGP_ATTR_ENCAP
) {
3856 stream_putc(s
, st
->type
);
3857 stream_putc(s
, st
->length
);
3858 #ifdef ENABLE_BGP_VNC
3860 stream_putw(s
, st
->type
);
3861 stream_putw(s
, st
->length
);
3864 stream_put(s
, st
->value
, st
->length
);
3868 void bgp_packet_mpattr_end(struct stream
*s
, size_t sizep
)
3870 /* Set MP attribute length. Don't count the (2) bytes used to encode
3872 stream_putw_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 2);
3875 static bool bgp_append_local_as(struct peer
*peer
, afi_t afi
, safi_t safi
)
3877 if (!BGP_AS_IS_PRIVATE(peer
->local_as
)
3878 || (BGP_AS_IS_PRIVATE(peer
->local_as
)
3879 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3880 PEER_FLAG_REMOVE_PRIVATE_AS
)
3881 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3882 PEER_FLAG_REMOVE_PRIVATE_AS_ALL
)
3883 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3884 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE
)
3885 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3886 PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE
)))
3891 /* Make attribute packet. */
3892 bgp_size_t
bgp_packet_attribute(struct bgp
*bgp
, struct peer
*peer
,
3893 struct stream
*s
, struct attr
*attr
,
3894 struct bpacket_attr_vec_arr
*vecarr
,
3895 struct prefix
*p
, afi_t afi
, safi_t safi
,
3896 struct peer
*from
, struct prefix_rd
*prd
,
3897 mpls_label_t
*label
, uint32_t num_labels
,
3898 bool addpath_capable
, uint32_t addpath_tx_id
)
3901 size_t aspath_sizep
;
3902 struct aspath
*aspath
;
3903 int send_as4_path
= 0;
3904 int send_as4_aggregator
= 0;
3905 bool use32bit
= CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
3906 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
);
3911 /* Remember current pointer. */
3912 cp
= stream_get_endp(s
);
3915 && !((afi
== AFI_IP
&& safi
== SAFI_UNICAST
)
3916 && !peer_cap_enhe(peer
, afi
, safi
))) {
3917 size_t mpattrlen_pos
= 0;
3919 mpattrlen_pos
= bgp_packet_mpattr_start(s
, peer
, afi
, safi
,
3921 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
,
3922 num_labels
, addpath_capable
,
3923 addpath_tx_id
, attr
);
3924 bgp_packet_mpattr_end(s
, mpattrlen_pos
);
3927 /* Origin attribute. */
3928 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3929 stream_putc(s
, BGP_ATTR_ORIGIN
);
3931 stream_putc(s
, attr
->origin
);
3933 /* AS path attribute. */
3935 /* If remote-peer is EBGP */
3936 if (peer
->sort
== BGP_PEER_EBGP
3937 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3938 PEER_FLAG_AS_PATH_UNCHANGED
)
3939 || attr
->aspath
->segments
== NULL
)
3940 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3941 PEER_FLAG_RSERVER_CLIENT
))) {
3942 aspath
= aspath_dup(attr
->aspath
);
3944 /* Even though we may not be configured for confederations we
3946 * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
3947 aspath
= aspath_delete_confed_seq(aspath
);
3949 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
)) {
3950 /* Stuff our path CONFED_ID on the front */
3951 aspath
= aspath_add_seq(aspath
, bgp
->confed_id
);
3953 if (peer
->change_local_as
) {
3954 /* If replace-as is specified, we only use the
3955 change_local_as when
3956 advertising routes. */
3957 if (!CHECK_FLAG(peer
->flags
,
3958 PEER_FLAG_LOCAL_AS_REPLACE_AS
))
3959 if (bgp_append_local_as(peer
, afi
,
3961 aspath
= aspath_add_seq(
3962 aspath
, peer
->local_as
);
3963 aspath
= aspath_add_seq(aspath
,
3964 peer
->change_local_as
);
3966 aspath
= aspath_add_seq(aspath
, peer
->local_as
);
3969 } else if (peer
->sort
== BGP_PEER_CONFED
) {
3970 /* A confed member, so we need to do the AS_CONFED_SEQUENCE
3972 aspath
= aspath_dup(attr
->aspath
);
3973 aspath
= aspath_add_confed_seq(aspath
, peer
->local_as
);
3975 aspath
= attr
->aspath
;
3977 /* If peer is not AS4 capable, then:
3978 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
3979 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
3981 * types are in it (i.e. exclude them if they are there)
3982 * AND do this only if there is at least one asnum > 65535 in the
3984 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
3986 * all ASnums > 65535 to BGP_AS_TRANS
3989 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
3990 stream_putc(s
, BGP_ATTR_AS_PATH
);
3991 aspath_sizep
= stream_get_endp(s
);
3993 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, use32bit
));
3995 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
3998 if (!use32bit
&& aspath_has_as4(aspath
))
4000 1; /* we'll do this later, at the correct place */
4002 /* Nexthop attribute. */
4003 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
4004 && !peer_cap_enhe(peer
, afi
, safi
)) {
4005 afi_t nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
4007 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
)) {
4008 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4009 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4010 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4013 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4014 } else if (peer_cap_enhe(from
, afi
, safi
)
4015 || (nh_afi
== AFI_IP6
)) {
4017 * Likely this is the case when an IPv4 prefix was
4018 * received with Extended Next-hop capability in this
4019 * or another vrf and is now being advertised to
4020 * non-ENHE peers. Since peer_cap_enhe only checks
4021 * peers in this vrf, also check the nh_afi to catch
4022 * the case where the originator was in another vrf.
4023 * Setting the mandatory (ipv4) next-hop attribute here
4024 * to enable implicit next-hop self with correct A-F
4025 * (ipv4 address family).
4027 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4028 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4029 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
4032 stream_put_ipv4(s
, 0);
4036 /* MED attribute. */
4037 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)
4038 || bgp
->maxmed_active
) {
4039 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4040 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4042 stream_putl(s
, (bgp
->maxmed_active
? bgp
->maxmed_value
4046 /* Local preference. */
4047 if (peer
->sort
== BGP_PEER_IBGP
|| peer
->sort
== BGP_PEER_CONFED
) {
4048 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4049 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4051 stream_putl(s
, attr
->local_pref
);
4054 /* Atomic aggregate. */
4055 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4056 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4057 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4062 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4063 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
4064 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4065 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4068 /* AS4 capable peer */
4070 stream_putl(s
, attr
->aggregator_as
);
4072 /* 2-byte AS peer */
4075 /* Is ASN representable in 2-bytes? Or must AS_TRANS be
4077 if (attr
->aggregator_as
> UINT16_MAX
) {
4078 stream_putw(s
, BGP_AS_TRANS
);
4080 /* we have to send AS4_AGGREGATOR, too.
4081 * we'll do that later in order to send
4082 * attributes in ascending
4085 send_as4_aggregator
= 1;
4087 stream_putw(s
, (uint16_t)attr
->aggregator_as
);
4089 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4092 /* Community attribute. */
4093 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
4094 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
))) {
4095 if (attr
->community
->size
* 4 > 255) {
4097 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4098 | BGP_ATTR_FLAG_EXTLEN
);
4099 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4100 stream_putw(s
, attr
->community
->size
* 4);
4103 BGP_ATTR_FLAG_OPTIONAL
4104 | BGP_ATTR_FLAG_TRANS
);
4105 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4106 stream_putc(s
, attr
->community
->size
* 4);
4108 stream_put(s
, attr
->community
->val
, attr
->community
->size
* 4);
4112 * Large Community attribute.
4114 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
4115 PEER_FLAG_SEND_LARGE_COMMUNITY
)
4116 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
))) {
4117 if (lcom_length(attr
->lcommunity
) > 255) {
4119 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4120 | BGP_ATTR_FLAG_EXTLEN
);
4121 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4122 stream_putw(s
, lcom_length(attr
->lcommunity
));
4125 BGP_ATTR_FLAG_OPTIONAL
4126 | BGP_ATTR_FLAG_TRANS
);
4127 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4128 stream_putc(s
, lcom_length(attr
->lcommunity
));
4130 stream_put(s
, attr
->lcommunity
->val
,
4131 lcom_length(attr
->lcommunity
));
4134 /* Route Reflector. */
4135 if (peer
->sort
== BGP_PEER_IBGP
&& from
4136 && from
->sort
== BGP_PEER_IBGP
) {
4137 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
4139 /* Originator ID. */
4140 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4141 stream_putc(s
, BGP_ATTR_ORIGINATOR_ID
);
4144 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
4145 stream_put_in_addr(s
, &attr
->originator_id
);
4147 stream_put_in_addr(s
, &from
->remote_id
);
4150 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4151 stream_putc(s
, BGP_ATTR_CLUSTER_LIST
);
4154 stream_putc(s
, cluster
->length
+ 4);
4155 /* If this peer configuration's parent BGP has
4157 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4158 stream_put_in_addr(s
, &bgp
->cluster_id
);
4160 stream_put_in_addr(s
, &bgp
->router_id
);
4161 stream_put(s
, cluster
->list
, cluster
->length
);
4164 /* If this peer configuration's parent BGP has
4166 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4167 stream_put_in_addr(s
, &bgp
->cluster_id
);
4169 stream_put_in_addr(s
, &bgp
->router_id
);
4173 /* Extended Communities attribute. */
4174 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
4175 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
))) {
4176 if (peer
->sort
== BGP_PEER_IBGP
4177 || peer
->sort
== BGP_PEER_CONFED
) {
4178 if (attr
->ecommunity
->size
* 8 > 255) {
4180 BGP_ATTR_FLAG_OPTIONAL
4181 | BGP_ATTR_FLAG_TRANS
4182 | BGP_ATTR_FLAG_EXTLEN
);
4183 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4184 stream_putw(s
, attr
->ecommunity
->size
* 8);
4187 BGP_ATTR_FLAG_OPTIONAL
4188 | BGP_ATTR_FLAG_TRANS
);
4189 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4190 stream_putc(s
, attr
->ecommunity
->size
* 8);
4192 stream_put(s
, attr
->ecommunity
->val
,
4193 attr
->ecommunity
->size
* 8);
4197 int ecom_tr_size
= 0;
4200 for (i
= 0; i
< attr
->ecommunity
->size
; i
++) {
4201 pnt
= attr
->ecommunity
->val
+ (i
* 8);
4204 if (CHECK_FLAG(tbit
,
4205 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4212 if (ecom_tr_size
* 8 > 255) {
4215 BGP_ATTR_FLAG_OPTIONAL
4216 | BGP_ATTR_FLAG_TRANS
4217 | BGP_ATTR_FLAG_EXTLEN
);
4219 BGP_ATTR_EXT_COMMUNITIES
);
4220 stream_putw(s
, ecom_tr_size
* 8);
4224 BGP_ATTR_FLAG_OPTIONAL
4225 | BGP_ATTR_FLAG_TRANS
);
4227 BGP_ATTR_EXT_COMMUNITIES
);
4228 stream_putc(s
, ecom_tr_size
* 8);
4231 for (i
= 0; i
< attr
->ecommunity
->size
; i
++) {
4232 pnt
= attr
->ecommunity
->val
+ (i
* 8);
4237 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4240 stream_put(s
, pnt
, 8);
4246 /* Label index attribute. */
4247 if (safi
== SAFI_LABELED_UNICAST
) {
4248 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4249 uint32_t label_index
;
4251 label_index
= attr
->label_index
;
4253 if (label_index
!= BGP_INVALID_LABEL_INDEX
) {
4255 BGP_ATTR_FLAG_OPTIONAL
4256 | BGP_ATTR_FLAG_TRANS
);
4257 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4259 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4261 BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4262 stream_putc(s
, 0); // reserved
4263 stream_putw(s
, 0); // flags
4264 stream_putl(s
, label_index
);
4269 /* SRv6 Service Information Attribute. */
4270 if ((afi
== AFI_IP
|| afi
== AFI_IP6
) && safi
== SAFI_MPLS_VPN
) {
4271 if (attr
->srv6_l3vpn
) {
4272 uint8_t subtlv_len
=
4273 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
4275 + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH
;
4276 uint8_t tlv_len
= subtlv_len
+ BGP_ATTR_MIN_LEN
+ 1;
4277 uint8_t attr_len
= tlv_len
+ BGP_ATTR_MIN_LEN
;
4278 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4279 | BGP_ATTR_FLAG_TRANS
);
4280 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4281 stream_putc(s
, attr_len
);
4282 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE
);
4283 stream_putw(s
, tlv_len
);
4284 stream_putc(s
, 0); /* reserved */
4285 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO
);
4286 stream_putw(s
, subtlv_len
);
4287 stream_putc(s
, 0); /* reserved */
4288 stream_put(s
, &attr
->srv6_l3vpn
->sid
,
4289 sizeof(attr
->srv6_l3vpn
->sid
)); /* sid */
4290 stream_putc(s
, 0); /* sid_flags */
4291 stream_putw(s
, 0xffff); /* endpoint */
4292 stream_putc(s
, 0); /* reserved */
4295 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE
);
4298 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
);
4299 stream_putc(s
, attr
->srv6_l3vpn
->loc_block_len
);
4300 stream_putc(s
, attr
->srv6_l3vpn
->loc_node_len
);
4301 stream_putc(s
, attr
->srv6_l3vpn
->func_len
);
4302 stream_putc(s
, attr
->srv6_l3vpn
->arg_len
);
4303 stream_putc(s
, attr
->srv6_l3vpn
->transposition_len
);
4304 stream_putc(s
, attr
->srv6_l3vpn
->transposition_offset
);
4305 } else if (attr
->srv6_vpn
) {
4306 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4307 | BGP_ATTR_FLAG_TRANS
);
4308 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4309 stream_putc(s
, 22); /* tlv len */
4310 stream_putc(s
, BGP_PREFIX_SID_VPN_SID
);
4311 stream_putw(s
, 0x13); /* tlv len */
4312 stream_putc(s
, 0x00); /* reserved */
4313 stream_putc(s
, 0x01); /* sid_type */
4314 stream_putc(s
, 0x00); /* sif_flags */
4315 stream_put(s
, &attr
->srv6_vpn
->sid
,
4316 sizeof(attr
->srv6_vpn
->sid
)); /* sid */
4320 if (send_as4_path
) {
4321 /* If the peer is NOT As4 capable, AND */
4322 /* there are ASnums > 65535 in path THEN
4323 * give out AS4_PATH */
4325 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
4327 * Hm, I wonder... confederation things *should* only be at
4328 * the beginning of an aspath, right? Then we should use
4329 * aspath_delete_confed_seq for this, because it is already
4331 * Folks, talk to me: what is reasonable here!?
4333 aspath
= aspath_delete_confed_seq(aspath
);
4336 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4337 | BGP_ATTR_FLAG_EXTLEN
);
4338 stream_putc(s
, BGP_ATTR_AS4_PATH
);
4339 aspath_sizep
= stream_get_endp(s
);
4341 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, 1));
4344 if (aspath
!= attr
->aspath
)
4345 aspath_free(aspath
);
4347 if (send_as4_aggregator
) {
4348 /* send AS4_AGGREGATOR, at this place */
4349 /* this section of code moved here in order to ensure the
4351 * *ascending* order of attributes
4353 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4354 stream_putc(s
, BGP_ATTR_AS4_AGGREGATOR
);
4356 stream_putl(s
, attr
->aggregator_as
);
4357 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4360 if (((afi
== AFI_IP
|| afi
== AFI_IP6
)
4361 && (safi
== SAFI_ENCAP
|| safi
== SAFI_MPLS_VPN
))
4362 || (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)) {
4363 /* Tunnel Encap attribute */
4364 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_ENCAP
);
4366 #ifdef ENABLE_BGP_VNC_ATTR
4368 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_VNC
);
4373 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
)) {
4374 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4375 stream_putc(s
, BGP_ATTR_PMSI_TUNNEL
);
4376 stream_putc(s
, 9); // Length
4377 stream_putc(s
, 0); // Flags
4378 stream_putc(s
, bgp_attr_get_pmsi_tnl_type(attr
));
4379 stream_put(s
, &(attr
->label
),
4380 BGP_LABEL_BYTES
); // MPLS Label / VXLAN VNI
4381 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4382 // Unicast tunnel endpoint IP address
4385 /* Unknown transit attribute. */
4386 struct transit
*transit
= bgp_attr_get_transit(attr
);
4389 stream_put(s
, transit
->val
, transit
->length
);
4391 /* Return total size of attribute. */
4392 return stream_get_endp(s
) - cp
;
4395 size_t bgp_packet_mpunreach_start(struct stream
*s
, afi_t afi
, safi_t safi
)
4397 unsigned long attrlen_pnt
;
4399 iana_safi_t pkt_safi
;
4401 /* Set extended bit always to encode the attribute length as 2 bytes */
4402 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
4403 stream_putc(s
, BGP_ATTR_MP_UNREACH_NLRI
);
4405 attrlen_pnt
= stream_get_endp(s
);
4406 stream_putw(s
, 0); /* Length of this attribute. */
4408 /* Convert AFI, SAFI to values for packet. */
4409 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
4411 stream_putw(s
, pkt_afi
);
4412 stream_putc(s
, pkt_safi
);
4417 void bgp_packet_mpunreach_prefix(struct stream
*s
, const struct prefix
*p
,
4418 afi_t afi
, safi_t safi
,
4419 const struct prefix_rd
*prd
,
4420 mpls_label_t
*label
, uint32_t num_labels
,
4421 bool addpath_capable
, uint32_t addpath_tx_id
,
4424 uint8_t wlabel
[3] = {0x80, 0x00, 0x00};
4426 if (safi
== SAFI_LABELED_UNICAST
) {
4427 label
= (mpls_label_t
*)wlabel
;
4431 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
, num_labels
,
4432 addpath_capable
, addpath_tx_id
, attr
);
4435 void bgp_packet_mpunreach_end(struct stream
*s
, size_t attrlen_pnt
)
4437 bgp_packet_mpattr_end(s
, attrlen_pnt
);
4440 /* Initialization of attribute. */
4441 void bgp_attr_init(void)
4454 void bgp_attr_finish(void)
4459 ecommunity_finish();
4460 lcommunity_finish();
4467 /* Make attribute packet. */
4468 void bgp_dump_routes_attr(struct stream
*s
, struct attr
*attr
,
4469 const struct prefix
*prefix
)
4474 struct aspath
*aspath
;
4475 bool addpath_capable
= false;
4476 uint32_t addpath_tx_id
= 0;
4478 /* Remember current pointer. */
4479 cp
= stream_get_endp(s
);
4481 /* Place holder of length. */
4484 /* Origin attribute. */
4485 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4486 stream_putc(s
, BGP_ATTR_ORIGIN
);
4488 stream_putc(s
, attr
->origin
);
4490 aspath
= attr
->aspath
;
4492 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4493 stream_putc(s
, BGP_ATTR_AS_PATH
);
4494 aspath_lenp
= stream_get_endp(s
);
4497 stream_putw_at(s
, aspath_lenp
, aspath_put(s
, aspath
, 1));
4499 /* Nexthop attribute. */
4500 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
4501 if (prefix
!= NULL
&& prefix
->family
!= AF_INET6
) {
4502 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4503 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4505 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4508 /* MED attribute. */
4509 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)) {
4510 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4511 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4513 stream_putl(s
, attr
->med
);
4516 /* Local preference. */
4517 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)) {
4518 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4519 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4521 stream_putl(s
, attr
->local_pref
);
4524 /* Atomic aggregate. */
4525 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4526 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4527 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4532 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4533 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4534 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4536 stream_putl(s
, attr
->aggregator_as
);
4537 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4540 /* Community attribute. */
4541 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
)) {
4542 if (attr
->community
->size
* 4 > 255) {
4544 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4545 | BGP_ATTR_FLAG_EXTLEN
);
4546 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4547 stream_putw(s
, attr
->community
->size
* 4);
4550 BGP_ATTR_FLAG_OPTIONAL
4551 | BGP_ATTR_FLAG_TRANS
);
4552 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4553 stream_putc(s
, attr
->community
->size
* 4);
4555 stream_put(s
, attr
->community
->val
, attr
->community
->size
* 4);
4558 /* Large Community attribute. */
4559 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
)) {
4560 if (lcom_length(attr
->lcommunity
) > 255) {
4562 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4563 | BGP_ATTR_FLAG_EXTLEN
);
4564 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4565 stream_putw(s
, lcom_length(attr
->lcommunity
));
4568 BGP_ATTR_FLAG_OPTIONAL
4569 | BGP_ATTR_FLAG_TRANS
);
4570 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4571 stream_putc(s
, lcom_length(attr
->lcommunity
));
4574 stream_put(s
, attr
->lcommunity
->val
,
4575 lcom_length(attr
->lcommunity
));
4578 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
4579 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
4580 && (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL
4581 || attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)) {
4584 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4585 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
4586 sizep
= stream_get_endp(s
);
4589 stream_putc(s
, 0); /* Marker: Attribute length. */
4590 stream_putw(s
, AFI_IP6
); /* AFI */
4591 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
4594 stream_putc(s
, attr
->mp_nexthop_len
);
4595 stream_put(s
, &attr
->mp_nexthop_global
, IPV6_MAX_BYTELEN
);
4596 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)
4597 stream_put(s
, &attr
->mp_nexthop_local
,
4604 stream_put_prefix_addpath(s
, prefix
, addpath_capable
,
4607 /* Set MP attribute length. */
4608 stream_putc_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 1);
4612 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4613 if (attr
->label_index
!= BGP_INVALID_LABEL_INDEX
) {
4615 BGP_ATTR_FLAG_OPTIONAL
4616 | BGP_ATTR_FLAG_TRANS
);
4617 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4619 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4620 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4621 stream_putc(s
, 0); // reserved
4622 stream_putw(s
, 0); // flags
4623 stream_putl(s
, attr
->label_index
);
4627 /* Return total size of attribute. */
4628 len
= stream_get_endp(s
) - cp
- 2;
4629 stream_putw_at(s
, cp
, len
);