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_DPA
, "DPA"},
72 {BGP_ATTR_ADVERTISER
, "ADVERTISER"},
73 {BGP_ATTR_RCID_PATH
, "RCID_PATH"},
74 {BGP_ATTR_MP_REACH_NLRI
, "MP_REACH_NLRI"},
75 {BGP_ATTR_MP_UNREACH_NLRI
, "MP_UNREACH_NLRI"},
76 {BGP_ATTR_EXT_COMMUNITIES
, "EXT_COMMUNITIES"},
77 {BGP_ATTR_AS4_PATH
, "AS4_PATH"},
78 {BGP_ATTR_AS4_AGGREGATOR
, "AS4_AGGREGATOR"},
79 {BGP_ATTR_AS_PATHLIMIT
, "AS_PATHLIMIT"},
80 {BGP_ATTR_PMSI_TUNNEL
, "PMSI_TUNNEL_ATTRIBUTE"},
81 {BGP_ATTR_ENCAP
, "ENCAP"},
82 #ifdef ENABLE_BGP_VNC_ATTR
83 {BGP_ATTR_VNC
, "VNC"},
85 {BGP_ATTR_LARGE_COMMUNITIES
, "LARGE_COMMUNITY"},
86 {BGP_ATTR_PREFIX_SID
, "PREFIX_SID"},
87 {BGP_ATTR_IPV6_EXT_COMMUNITIES
, "IPV6_EXT_COMMUNITIES"},
90 static const struct message attr_flag_str
[] = {
91 {BGP_ATTR_FLAG_OPTIONAL
, "Optional"},
92 {BGP_ATTR_FLAG_TRANS
, "Transitive"},
93 {BGP_ATTR_FLAG_PARTIAL
, "Partial"},
94 /* bgp_attr_flags_diagnose() relies on this bit being last in
96 {BGP_ATTR_FLAG_EXTLEN
, "Extended Length"},
99 static struct hash
*cluster_hash
;
101 static void *cluster_hash_alloc(void *p
)
103 const struct cluster_list
*val
= (const struct cluster_list
*)p
;
104 struct cluster_list
*cluster
;
106 cluster
= XMALLOC(MTYPE_CLUSTER
, sizeof(struct cluster_list
));
107 cluster
->length
= val
->length
;
109 if (cluster
->length
) {
110 cluster
->list
= XMALLOC(MTYPE_CLUSTER_VAL
, val
->length
);
111 memcpy(cluster
->list
, val
->list
, val
->length
);
113 cluster
->list
= NULL
;
120 /* Cluster list related functions. */
121 static struct cluster_list
*cluster_parse(struct in_addr
*pnt
, int length
)
123 struct cluster_list tmp
= {};
124 struct cluster_list
*cluster
;
127 tmp
.list
= length
== 0 ? NULL
: pnt
;
129 cluster
= hash_get(cluster_hash
, &tmp
, cluster_hash_alloc
);
134 bool cluster_loop_check(struct cluster_list
*cluster
, struct in_addr originator
)
138 for (i
= 0; i
< cluster
->length
/ 4; i
++)
139 if (cluster
->list
[i
].s_addr
== originator
.s_addr
)
144 static unsigned int cluster_hash_key_make(const void *p
)
146 const struct cluster_list
*cluster
= p
;
148 return jhash(cluster
->list
, cluster
->length
, 0);
151 static bool cluster_hash_cmp(const void *p1
, const void *p2
)
153 const struct cluster_list
*cluster1
= p1
;
154 const struct cluster_list
*cluster2
= p2
;
156 if (cluster1
->list
== cluster2
->list
)
159 if (!cluster1
->list
|| !cluster2
->list
)
162 if (cluster1
->length
!= cluster2
->length
)
165 return (memcmp(cluster1
->list
, cluster2
->list
, cluster1
->length
) == 0);
168 static void cluster_free(struct cluster_list
*cluster
)
170 XFREE(MTYPE_CLUSTER_VAL
, cluster
->list
);
171 XFREE(MTYPE_CLUSTER
, cluster
);
174 static struct cluster_list
*cluster_intern(struct cluster_list
*cluster
)
176 struct cluster_list
*find
;
178 find
= hash_get(cluster_hash
, cluster
, cluster_hash_alloc
);
184 static void cluster_unintern(struct cluster_list
**cluster
)
186 if ((*cluster
)->refcnt
)
187 (*cluster
)->refcnt
--;
189 if ((*cluster
)->refcnt
== 0) {
190 void *p
= hash_release(cluster_hash
, *cluster
);
191 assert(p
== *cluster
);
192 cluster_free(*cluster
);
197 static void cluster_init(void)
199 cluster_hash
= hash_create(cluster_hash_key_make
, cluster_hash_cmp
,
203 static void cluster_finish(void)
205 hash_clean(cluster_hash
, (void (*)(void *))cluster_free
);
206 hash_free(cluster_hash
);
210 static struct hash
*encap_hash
= NULL
;
211 #ifdef ENABLE_BGP_VNC
212 static struct hash
*vnc_hash
= NULL
;
214 static struct hash
*srv6_l3vpn_hash
;
215 static struct hash
*srv6_vpn_hash
;
217 struct bgp_attr_encap_subtlv
*encap_tlv_dup(struct bgp_attr_encap_subtlv
*orig
)
219 struct bgp_attr_encap_subtlv
*new;
220 struct bgp_attr_encap_subtlv
*tail
;
221 struct bgp_attr_encap_subtlv
*p
;
223 for (p
= orig
, tail
= new = NULL
; p
; p
= p
->next
) {
224 int size
= sizeof(struct bgp_attr_encap_subtlv
) + p
->length
;
226 tail
->next
= XCALLOC(MTYPE_ENCAP_TLV
, size
);
229 tail
= new = XCALLOC(MTYPE_ENCAP_TLV
, size
);
232 memcpy(tail
, p
, size
);
239 static void encap_free(struct bgp_attr_encap_subtlv
*p
)
241 struct bgp_attr_encap_subtlv
*next
;
245 XFREE(MTYPE_ENCAP_TLV
, p
);
250 void bgp_attr_flush_encap(struct attr
*attr
)
255 if (attr
->encap_subtlvs
) {
256 encap_free(attr
->encap_subtlvs
);
257 attr
->encap_subtlvs
= NULL
;
259 #ifdef ENABLE_BGP_VNC
260 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
261 bgp_attr_get_vnc_subtlvs(attr
);
264 encap_free(vnc_subtlvs
);
265 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
271 * Compare encap sub-tlv chains
276 * This algorithm could be made faster if needed
278 static bool encap_same(const struct bgp_attr_encap_subtlv
*h1
,
279 const struct bgp_attr_encap_subtlv
*h2
)
281 const struct bgp_attr_encap_subtlv
*p
;
282 const struct bgp_attr_encap_subtlv
*q
;
286 if (h1
== NULL
|| h2
== NULL
)
289 for (p
= h1
; p
; p
= p
->next
) {
290 for (q
= h2
; q
; q
= q
->next
) {
291 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
292 && !memcmp(p
->value
, q
->value
, p
->length
)) {
301 for (p
= h2
; p
; p
= p
->next
) {
302 for (q
= h1
; q
; q
= q
->next
) {
303 if ((p
->type
== q
->type
) && (p
->length
== q
->length
)
304 && !memcmp(p
->value
, q
->value
, p
->length
)) {
316 static void *encap_hash_alloc(void *p
)
318 /* Encap structure is already allocated. */
324 #ifdef ENABLE_BGP_VNC
329 static struct bgp_attr_encap_subtlv
*
330 encap_intern(struct bgp_attr_encap_subtlv
*encap
, encap_subtlv_type type
)
332 struct bgp_attr_encap_subtlv
*find
;
333 struct hash
*hash
= encap_hash
;
334 #ifdef ENABLE_BGP_VNC
335 if (type
== VNC_SUBTLV_TYPE
)
339 find
= hash_get(hash
, encap
, encap_hash_alloc
);
347 static void encap_unintern(struct bgp_attr_encap_subtlv
**encapp
,
348 encap_subtlv_type type
)
350 struct bgp_attr_encap_subtlv
*encap
= *encapp
;
354 if (encap
->refcnt
== 0) {
355 struct hash
*hash
= encap_hash
;
356 #ifdef ENABLE_BGP_VNC
357 if (type
== VNC_SUBTLV_TYPE
)
360 hash_release(hash
, encap
);
366 static unsigned int encap_hash_key_make(const void *p
)
368 const struct bgp_attr_encap_subtlv
*encap
= p
;
370 return jhash(encap
->value
, encap
->length
, 0);
373 static bool encap_hash_cmp(const void *p1
, const void *p2
)
375 return encap_same((const struct bgp_attr_encap_subtlv
*)p1
,
376 (const struct bgp_attr_encap_subtlv
*)p2
);
379 static void encap_init(void)
381 encap_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
383 #ifdef ENABLE_BGP_VNC
384 vnc_hash
= hash_create(encap_hash_key_make
, encap_hash_cmp
,
389 static void encap_finish(void)
391 hash_clean(encap_hash
, (void (*)(void *))encap_free
);
392 hash_free(encap_hash
);
394 #ifdef ENABLE_BGP_VNC
395 hash_clean(vnc_hash
, (void (*)(void *))encap_free
);
401 static bool overlay_index_same(const struct attr
*a1
, const struct attr
*a2
)
410 return !memcmp(bgp_attr_get_evpn_overlay(a1
),
411 bgp_attr_get_evpn_overlay(a2
),
412 sizeof(struct bgp_route_evpn
));
415 /* Unknown transit attribute. */
416 static struct hash
*transit_hash
;
418 static void transit_free(struct transit
*transit
)
420 XFREE(MTYPE_TRANSIT_VAL
, transit
->val
);
421 XFREE(MTYPE_TRANSIT
, transit
);
424 static void *transit_hash_alloc(void *p
)
426 /* Transit structure is already allocated. */
430 static struct transit
*transit_intern(struct transit
*transit
)
432 struct transit
*find
;
434 find
= hash_get(transit_hash
, transit
, transit_hash_alloc
);
436 transit_free(transit
);
442 static void transit_unintern(struct transit
**transit
)
444 if ((*transit
)->refcnt
)
445 (*transit
)->refcnt
--;
447 if ((*transit
)->refcnt
== 0) {
448 hash_release(transit_hash
, *transit
);
449 transit_free(*transit
);
454 static void *srv6_l3vpn_hash_alloc(void *p
)
459 static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn
*l3vpn
)
461 XFREE(MTYPE_BGP_SRV6_L3VPN
, l3vpn
);
464 static struct bgp_attr_srv6_l3vpn
*
465 srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn
*l3vpn
)
467 struct bgp_attr_srv6_l3vpn
*find
;
469 find
= hash_get(srv6_l3vpn_hash
, l3vpn
, srv6_l3vpn_hash_alloc
);
471 srv6_l3vpn_free(l3vpn
);
476 static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn
**l3vpnp
)
478 struct bgp_attr_srv6_l3vpn
*l3vpn
= *l3vpnp
;
483 if (l3vpn
->refcnt
== 0) {
484 hash_release(srv6_l3vpn_hash
, l3vpn
);
485 srv6_l3vpn_free(l3vpn
);
490 static void *srv6_vpn_hash_alloc(void *p
)
495 static void srv6_vpn_free(struct bgp_attr_srv6_vpn
*vpn
)
497 XFREE(MTYPE_BGP_SRV6_VPN
, vpn
);
500 static struct bgp_attr_srv6_vpn
*srv6_vpn_intern(struct bgp_attr_srv6_vpn
*vpn
)
502 struct bgp_attr_srv6_vpn
*find
;
504 find
= hash_get(srv6_vpn_hash
, vpn
, srv6_vpn_hash_alloc
);
511 static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn
**vpnp
)
513 struct bgp_attr_srv6_vpn
*vpn
= *vpnp
;
518 if (vpn
->refcnt
== 0) {
519 hash_release(srv6_vpn_hash
, vpn
);
525 static uint32_t srv6_l3vpn_hash_key_make(const void *p
)
527 const struct bgp_attr_srv6_l3vpn
*l3vpn
= p
;
530 key
= jhash(&l3vpn
->sid
, 16, key
);
531 key
= jhash_1word(l3vpn
->sid_flags
, key
);
532 key
= jhash_1word(l3vpn
->endpoint_behavior
, key
);
536 static bool srv6_l3vpn_hash_cmp(const void *p1
, const void *p2
)
538 const struct bgp_attr_srv6_l3vpn
*l3vpn1
= p1
;
539 const struct bgp_attr_srv6_l3vpn
*l3vpn2
= p2
;
541 return sid_same(&l3vpn1
->sid
, &l3vpn2
->sid
)
542 && l3vpn1
->sid_flags
== l3vpn2
->sid_flags
543 && l3vpn1
->endpoint_behavior
== l3vpn2
->endpoint_behavior
;
546 static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn
*h1
,
547 const struct bgp_attr_srv6_l3vpn
*h2
)
551 else if (h1
== NULL
|| h2
== NULL
)
554 return srv6_l3vpn_hash_cmp((const void *)h1
, (const void *)h2
);
557 static unsigned int srv6_vpn_hash_key_make(const void *p
)
559 const struct bgp_attr_srv6_vpn
*vpn
= p
;
562 key
= jhash(&vpn
->sid
, 16, key
);
563 key
= jhash_1word(vpn
->sid_flags
, key
);
567 static bool srv6_vpn_hash_cmp(const void *p1
, const void *p2
)
569 const struct bgp_attr_srv6_vpn
*vpn1
= p1
;
570 const struct bgp_attr_srv6_vpn
*vpn2
= p2
;
572 return sid_same(&vpn1
->sid
, &vpn2
->sid
)
573 && vpn1
->sid_flags
== vpn2
->sid_flags
;
576 static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn
*h1
,
577 const struct bgp_attr_srv6_vpn
*h2
)
581 else if (h1
== NULL
|| h2
== NULL
)
584 return srv6_vpn_hash_cmp((const void *)h1
, (const void *)h2
);
587 static void srv6_init(void)
590 hash_create(srv6_l3vpn_hash_key_make
, srv6_l3vpn_hash_cmp
,
591 "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
592 srv6_vpn_hash
= hash_create(srv6_vpn_hash_key_make
, srv6_vpn_hash_cmp
,
593 "BGP Prefix-SID SRv6-VPN-Service-TLV");
596 static void srv6_finish(void)
598 hash_clean(srv6_l3vpn_hash
, (void (*)(void *))srv6_l3vpn_free
);
599 hash_free(srv6_l3vpn_hash
);
600 srv6_l3vpn_hash
= NULL
;
601 hash_clean(srv6_vpn_hash
, (void (*)(void *))srv6_vpn_free
);
602 hash_free(srv6_vpn_hash
);
603 srv6_vpn_hash
= NULL
;
606 static unsigned int transit_hash_key_make(const void *p
)
608 const struct transit
*transit
= p
;
610 return jhash(transit
->val
, transit
->length
, 0);
613 static bool transit_hash_cmp(const void *p1
, const void *p2
)
615 const struct transit
*transit1
= p1
;
616 const struct transit
*transit2
= p2
;
618 return (transit1
->length
== transit2
->length
619 && memcmp(transit1
->val
, transit2
->val
, transit1
->length
) == 0);
622 static void transit_init(void)
624 transit_hash
= hash_create(transit_hash_key_make
, transit_hash_cmp
,
628 static void transit_finish(void)
630 hash_clean(transit_hash
, (void (*)(void *))transit_free
);
631 hash_free(transit_hash
);
635 /* Attribute hash routines. */
636 static struct hash
*attrhash
;
638 unsigned long int attr_count(void)
640 return attrhash
->count
;
643 unsigned long int attr_unknown_count(void)
645 return transit_hash
->count
;
648 unsigned int attrhash_key_make(const void *p
)
650 const struct attr
*attr
= (struct attr
*)p
;
652 #define MIX(val) key = jhash_1word(val, key)
653 #define MIX3(a, b, c) key = jhash_3words((a), (b), (c), key)
655 MIX3(attr
->origin
, attr
->nexthop
.s_addr
, attr
->med
);
656 MIX3(attr
->local_pref
, attr
->aggregator_as
,
657 attr
->aggregator_addr
.s_addr
);
658 MIX3(attr
->weight
, attr
->mp_nexthop_global_in
.s_addr
,
659 attr
->originator_id
.s_addr
);
660 MIX3(attr
->tag
, attr
->label
, attr
->label_index
);
663 MIX(aspath_key_make(attr
->aspath
));
665 MIX(community_hash_make(attr
->community
));
667 if (attr
->lcommunity
)
668 MIX(lcommunity_hash_make(attr
->lcommunity
));
669 if (attr
->ecommunity
)
670 MIX(ecommunity_hash_make(attr
->ecommunity
));
671 if (bgp_attr_get_ipv6_ecommunity(attr
))
672 MIX(ecommunity_hash_make(bgp_attr_get_ipv6_ecommunity(attr
)));
673 if (bgp_attr_get_cluster(attr
))
674 MIX(cluster_hash_key_make(bgp_attr_get_cluster(attr
)));
675 if (bgp_attr_get_transit(attr
))
676 MIX(transit_hash_key_make(bgp_attr_get_transit(attr
)));
677 if (attr
->encap_subtlvs
)
678 MIX(encap_hash_key_make(attr
->encap_subtlvs
));
679 if (attr
->srv6_l3vpn
)
680 MIX(srv6_l3vpn_hash_key_make(attr
->srv6_l3vpn
));
682 MIX(srv6_vpn_hash_key_make(attr
->srv6_vpn
));
683 #ifdef ENABLE_BGP_VNC
684 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
685 bgp_attr_get_vnc_subtlvs(attr
);
687 MIX(encap_hash_key_make(vnc_subtlvs
));
689 MIX(attr
->mp_nexthop_len
);
690 key
= jhash(attr
->mp_nexthop_global
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
691 key
= jhash(attr
->mp_nexthop_local
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
692 MIX3(attr
->nh_ifindex
, attr
->nh_lla_ifindex
, attr
->distance
);
693 MIX(attr
->rmap_table_id
);
698 bool attrhash_cmp(const void *p1
, const void *p2
)
700 const struct attr
*attr1
= p1
;
701 const struct attr
*attr2
= p2
;
703 if (attr1
->flag
== attr2
->flag
&& attr1
->origin
== attr2
->origin
704 && attr1
->nexthop
.s_addr
== attr2
->nexthop
.s_addr
705 && attr1
->aspath
== attr2
->aspath
706 && attr1
->community
== attr2
->community
&& attr1
->med
== attr2
->med
707 && attr1
->local_pref
== attr2
->local_pref
708 && attr1
->rmap_change_flags
== attr2
->rmap_change_flags
) {
709 if (attr1
->aggregator_as
== attr2
->aggregator_as
710 && attr1
->aggregator_addr
.s_addr
711 == attr2
->aggregator_addr
.s_addr
712 && attr1
->weight
== attr2
->weight
713 && attr1
->tag
== attr2
->tag
714 && attr1
->label_index
== attr2
->label_index
715 && attr1
->mp_nexthop_len
== attr2
->mp_nexthop_len
716 && attr1
->ecommunity
== attr2
->ecommunity
717 && bgp_attr_get_ipv6_ecommunity(attr1
)
718 == bgp_attr_get_ipv6_ecommunity(attr2
)
719 && attr1
->lcommunity
== attr2
->lcommunity
720 && bgp_attr_get_cluster(attr1
)
721 == bgp_attr_get_cluster(attr2
)
722 && bgp_attr_get_transit(attr1
)
723 == bgp_attr_get_transit(attr2
)
724 && attr1
->rmap_table_id
== attr2
->rmap_table_id
725 && (attr1
->encap_tunneltype
== attr2
->encap_tunneltype
)
726 && encap_same(attr1
->encap_subtlvs
, attr2
->encap_subtlvs
)
727 #ifdef ENABLE_BGP_VNC
728 && encap_same(bgp_attr_get_vnc_subtlvs(attr1
),
729 bgp_attr_get_vnc_subtlvs(attr2
))
731 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_global
,
732 &attr2
->mp_nexthop_global
)
733 && IPV6_ADDR_SAME(&attr1
->mp_nexthop_local
,
734 &attr2
->mp_nexthop_local
)
735 && IPV4_ADDR_SAME(&attr1
->mp_nexthop_global_in
,
736 &attr2
->mp_nexthop_global_in
)
737 && IPV4_ADDR_SAME(&attr1
->originator_id
,
738 &attr2
->originator_id
)
739 && overlay_index_same(attr1
, attr2
)
740 && !memcmp(&attr1
->esi
, &attr2
->esi
, sizeof(esi_t
))
741 && attr1
->es_flags
== attr2
->es_flags
742 && attr1
->mm_sync_seqnum
== attr2
->mm_sync_seqnum
743 && attr1
->df_pref
== attr2
->df_pref
744 && attr1
->df_alg
== attr2
->df_alg
745 && attr1
->nh_ifindex
== attr2
->nh_ifindex
746 && attr1
->nh_lla_ifindex
== attr2
->nh_lla_ifindex
747 && attr1
->distance
== attr2
->distance
748 && srv6_l3vpn_same(attr1
->srv6_l3vpn
, attr2
->srv6_l3vpn
)
749 && srv6_vpn_same(attr1
->srv6_vpn
, attr2
->srv6_vpn
)
750 && attr1
->srte_color
== attr2
->srte_color
)
757 static void attrhash_init(void)
760 hash_create(attrhash_key_make
, attrhash_cmp
, "BGP Attributes");
764 * special for hash_clean below
766 static void attr_vfree(void *attr
)
768 XFREE(MTYPE_ATTR
, attr
);
771 static void attrhash_finish(void)
773 hash_clean(attrhash
, attr_vfree
);
778 static void attr_show_all_iterator(struct hash_bucket
*bucket
, struct vty
*vty
)
780 struct attr
*attr
= bucket
->data
;
781 char sid_str
[BUFSIZ
];
783 vty_out(vty
, "attr[%ld] nexthop %pI4\n", attr
->refcnt
, &attr
->nexthop
);
786 if (attr
->srv6_l3vpn
)
787 inet_ntop(AF_INET6
, &attr
->srv6_l3vpn
->sid
, sid_str
, BUFSIZ
);
788 else if (attr
->srv6_vpn
)
789 inet_ntop(AF_INET6
, &attr
->srv6_vpn
->sid
, sid_str
, BUFSIZ
);
792 "\tflags: %" PRIu64
" distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %s\n",
793 attr
->flag
, attr
->distance
, attr
->med
, attr
->local_pref
,
794 attr
->origin
, attr
->weight
, attr
->label
, sid_str
);
797 void attr_show_all(struct vty
*vty
)
799 hash_iterate(attrhash
, (void (*)(struct hash_bucket
*,
800 void *))attr_show_all_iterator
,
804 static void *bgp_attr_hash_alloc(void *p
)
806 struct attr
*val
= (struct attr
*)p
;
809 attr
= XMALLOC(MTYPE_ATTR
, sizeof(struct attr
));
811 if (val
->encap_subtlvs
) {
812 val
->encap_subtlvs
= NULL
;
814 #ifdef ENABLE_BGP_VNC
815 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
816 bgp_attr_get_vnc_subtlvs(val
);
819 bgp_attr_set_vnc_subtlvs(val
, NULL
);
822 val
->srv6_l3vpn
= NULL
;
824 val
->srv6_vpn
= NULL
;
830 /* Internet argument attribute. */
831 struct attr
*bgp_attr_intern(struct attr
*attr
)
834 struct ecommunity
*ecomm
;
836 /* Intern referenced strucutre. */
838 if (!attr
->aspath
->refcnt
)
839 attr
->aspath
= aspath_intern(attr
->aspath
);
841 attr
->aspath
->refcnt
++;
843 if (attr
->community
) {
844 if (!attr
->community
->refcnt
)
845 attr
->community
= community_intern(attr
->community
);
847 attr
->community
->refcnt
++;
850 if (attr
->ecommunity
) {
851 if (!attr
->ecommunity
->refcnt
)
852 attr
->ecommunity
= ecommunity_intern(attr
->ecommunity
);
854 attr
->ecommunity
->refcnt
++;
857 ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
860 bgp_attr_set_ipv6_ecommunity(attr
,
861 ecommunity_intern(ecomm
));
866 if (attr
->lcommunity
) {
867 if (!attr
->lcommunity
->refcnt
)
868 attr
->lcommunity
= lcommunity_intern(attr
->lcommunity
);
870 attr
->lcommunity
->refcnt
++;
873 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
876 if (!cluster
->refcnt
)
877 bgp_attr_set_cluster(attr
, cluster_intern(cluster
));
882 struct transit
*transit
= bgp_attr_get_transit(attr
);
885 if (!transit
->refcnt
)
886 bgp_attr_set_transit(attr
, transit_intern(transit
));
890 if (attr
->encap_subtlvs
) {
891 if (!attr
->encap_subtlvs
->refcnt
)
892 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
895 attr
->encap_subtlvs
->refcnt
++;
897 if (attr
->srv6_l3vpn
) {
898 if (!attr
->srv6_l3vpn
->refcnt
)
899 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
901 attr
->srv6_l3vpn
->refcnt
++;
903 if (attr
->srv6_vpn
) {
904 if (!attr
->srv6_vpn
->refcnt
)
905 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
907 attr
->srv6_vpn
->refcnt
++;
909 #ifdef ENABLE_BGP_VNC
910 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
911 bgp_attr_get_vnc_subtlvs(attr
);
914 if (!vnc_subtlvs
->refcnt
)
915 bgp_attr_set_vnc_subtlvs(
917 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
919 vnc_subtlvs
->refcnt
++;
923 /* At this point, attr only contains intern'd pointers. that means
924 * if we find it in attrhash, it has all the same pointers and we
925 * correctly updated the refcounts on these.
926 * If we don't find it, we need to allocate a one because in all
927 * cases this returns a new reference to a hashed attr, but the input
929 find
= (struct attr
*)hash_get(attrhash
, attr
, bgp_attr_hash_alloc
);
935 /* Make network statement's attribute. */
936 struct attr
*bgp_attr_default_set(struct attr
*attr
, uint8_t origin
)
938 memset(attr
, 0, sizeof(struct attr
));
940 attr
->origin
= origin
;
941 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
942 attr
->aspath
= aspath_empty();
943 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
944 attr
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
946 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
947 attr
->label
= MPLS_INVALID_LABEL
;
948 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
949 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
954 /* Create the attributes for an aggregate */
955 struct attr
*bgp_attr_aggregate_intern(
956 struct bgp
*bgp
, uint8_t origin
, struct aspath
*aspath
,
957 struct community
*community
, struct ecommunity
*ecommunity
,
958 struct lcommunity
*lcommunity
, struct bgp_aggregate
*aggregate
,
959 uint8_t atomic_aggregate
, const struct prefix
*p
)
965 memset(&attr
, 0, sizeof(struct attr
));
967 /* Origin attribute. */
968 attr
.origin
= origin
;
969 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
971 /* AS path attribute. */
973 attr
.aspath
= aspath_intern(aspath
);
975 attr
.aspath
= aspath_empty();
976 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
978 /* Next hop attribute. */
979 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
982 uint32_t gshut
= COMMUNITY_GSHUT
;
984 /* If we are not shutting down ourselves and we are
985 * aggregating a route that contains the GSHUT community we
986 * need to remove that community when creating the aggregate */
987 if (!bgp_in_graceful_shutdown(bgp
)
988 && community_include(community
, gshut
)) {
989 community_del_val(community
, &gshut
);
992 attr
.community
= community
;
993 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
);
997 attr
.ecommunity
= ecommunity
;
998 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
1002 attr
.lcommunity
= lcommunity
;
1003 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
);
1006 if (bgp_in_graceful_shutdown(bgp
))
1007 bgp_attr_add_gshut_community(&attr
);
1009 attr
.label_index
= BGP_INVALID_LABEL_INDEX
;
1010 attr
.label
= MPLS_INVALID_LABEL
;
1011 attr
.weight
= BGP_ATTR_DEFAULT_WEIGHT
;
1012 attr
.mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1013 if (!aggregate
->as_set
|| atomic_aggregate
)
1014 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1015 attr
.flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1016 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
))
1017 attr
.aggregator_as
= bgp
->confed_id
;
1019 attr
.aggregator_as
= bgp
->as
;
1020 attr
.aggregator_addr
= bgp
->router_id
;
1021 attr
.label_index
= BGP_INVALID_LABEL_INDEX
;
1022 attr
.label
= MPLS_INVALID_LABEL
;
1024 /* Apply route-map */
1025 if (aggregate
->rmap
.name
) {
1026 struct attr attr_tmp
= attr
;
1027 struct bgp_path_info rmap_path
;
1029 memset(&rmap_path
, 0, sizeof(struct bgp_path_info
));
1030 rmap_path
.peer
= bgp
->peer_self
;
1031 rmap_path
.attr
= &attr_tmp
;
1033 SET_FLAG(bgp
->peer_self
->rmap_type
, PEER_RMAP_TYPE_AGGREGATE
);
1035 ret
= route_map_apply(aggregate
->rmap
.map
, p
, &rmap_path
);
1037 bgp
->peer_self
->rmap_type
= 0;
1039 if (ret
== RMAP_DENYMATCH
) {
1040 /* Free uninterned attribute. */
1041 bgp_attr_flush(&attr_tmp
);
1043 /* Unintern original. */
1044 aspath_unintern(&attr
.aspath
);
1048 if (bgp_in_graceful_shutdown(bgp
))
1049 bgp_attr_add_gshut_community(&attr_tmp
);
1051 new = bgp_attr_intern(&attr_tmp
);
1054 if (bgp_in_graceful_shutdown(bgp
))
1055 bgp_attr_add_gshut_community(&attr
);
1057 new = bgp_attr_intern(&attr
);
1060 aspath_unintern(&new->aspath
);
1064 /* Unintern just the sub-components of the attr, but not the attr */
1065 void bgp_attr_unintern_sub(struct attr
*attr
)
1067 struct ecommunity
*ecomm
;
1068 struct cluster_list
*cluster
;
1070 /* aspath refcount shoud be decrement. */
1072 aspath_unintern(&attr
->aspath
);
1073 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
));
1075 if (attr
->community
)
1076 community_unintern(&attr
->community
);
1077 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
));
1079 ecommunity_unintern(&attr
->ecommunity
);
1080 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
));
1082 ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1083 ecommunity_unintern(&ecomm
);
1084 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES
));
1085 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1087 if (attr
->lcommunity
)
1088 lcommunity_unintern(&attr
->lcommunity
);
1089 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
));
1091 cluster
= bgp_attr_get_cluster(attr
);
1093 cluster_unintern(&cluster
);
1094 bgp_attr_set_cluster(attr
, cluster
);
1096 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
));
1098 struct transit
*transit
= bgp_attr_get_transit(attr
);
1101 transit_unintern(&transit
);
1102 bgp_attr_set_transit(attr
, transit
);
1105 if (attr
->encap_subtlvs
)
1106 encap_unintern(&attr
->encap_subtlvs
, ENCAP_SUBTLV_TYPE
);
1108 #ifdef ENABLE_BGP_VNC
1109 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1110 bgp_attr_get_vnc_subtlvs(attr
);
1113 encap_unintern(&vnc_subtlvs
, VNC_SUBTLV_TYPE
);
1114 bgp_attr_set_vnc_subtlvs(attr
, vnc_subtlvs
);
1118 if (attr
->srv6_l3vpn
)
1119 srv6_l3vpn_unintern(&attr
->srv6_l3vpn
);
1122 srv6_vpn_unintern(&attr
->srv6_vpn
);
1126 * We have some show commands that let you experimentally
1127 * apply a route-map. When we apply the route-map
1128 * we are reseting values but not saving them for
1129 * posterity via intern'ing( because route-maps don't
1130 * do that) but at this point in time we need
1131 * to compare the new attr to the old and if the
1132 * routemap has changed it we need to, as Snoop Dog says,
1133 * Drop it like it's hot
1135 void bgp_attr_undup(struct attr
*new, struct attr
*old
)
1137 if (new->aspath
!= old
->aspath
)
1138 aspath_free(new->aspath
);
1140 if (new->community
!= old
->community
)
1141 community_free(&new->community
);
1143 if (new->ecommunity
!= old
->ecommunity
)
1144 ecommunity_free(&new->ecommunity
);
1146 if (new->lcommunity
!= old
->lcommunity
)
1147 lcommunity_free(&new->lcommunity
);
1149 if (new->srv6_l3vpn
!= old
->srv6_l3vpn
) {
1150 srv6_l3vpn_free(new->srv6_l3vpn
);
1151 new->srv6_l3vpn
= NULL
;
1154 if (new->srv6_vpn
!= old
->srv6_vpn
) {
1155 srv6_vpn_free(new->srv6_vpn
);
1156 new->srv6_vpn
= NULL
;
1160 /* Free bgp attribute and aspath. */
1161 void bgp_attr_unintern(struct attr
**pattr
)
1163 struct attr
*attr
= *pattr
;
1167 /* Decrement attribute reference. */
1172 /* If reference becomes zero then free attribute object. */
1173 if (attr
->refcnt
== 0) {
1174 ret
= hash_release(attrhash
, attr
);
1175 assert(ret
!= NULL
);
1176 XFREE(MTYPE_ATTR
, attr
);
1180 bgp_attr_unintern_sub(&tmp
);
1183 void bgp_attr_flush(struct attr
*attr
)
1185 struct ecommunity
*ecomm
;
1186 struct cluster_list
*cluster
;
1188 if (attr
->aspath
&& !attr
->aspath
->refcnt
) {
1189 aspath_free(attr
->aspath
);
1190 attr
->aspath
= NULL
;
1192 if (attr
->community
&& !attr
->community
->refcnt
)
1193 community_free(&attr
->community
);
1194 if (attr
->ecommunity
&& !attr
->ecommunity
->refcnt
)
1195 ecommunity_free(&attr
->ecommunity
);
1196 ecomm
= bgp_attr_get_ipv6_ecommunity(attr
);
1197 if (ecomm
&& !ecomm
->refcnt
)
1198 ecommunity_free(&ecomm
);
1199 bgp_attr_set_ipv6_ecommunity(attr
, NULL
);
1200 if (attr
->lcommunity
&& !attr
->lcommunity
->refcnt
)
1201 lcommunity_free(&attr
->lcommunity
);
1203 cluster
= bgp_attr_get_cluster(attr
);
1204 if (cluster
&& !cluster
->refcnt
) {
1205 cluster_free(cluster
);
1206 bgp_attr_set_cluster(attr
, NULL
);
1209 struct transit
*transit
= bgp_attr_get_transit(attr
);
1211 if (transit
&& !transit
->refcnt
) {
1212 transit_free(transit
);
1213 bgp_attr_set_transit(attr
, NULL
);
1215 if (attr
->encap_subtlvs
&& !attr
->encap_subtlvs
->refcnt
) {
1216 encap_free(attr
->encap_subtlvs
);
1217 attr
->encap_subtlvs
= NULL
;
1219 if (attr
->srv6_l3vpn
&& !attr
->srv6_l3vpn
->refcnt
) {
1220 srv6_l3vpn_free(attr
->srv6_l3vpn
);
1221 attr
->srv6_l3vpn
= NULL
;
1223 if (attr
->srv6_vpn
&& !attr
->srv6_vpn
->refcnt
) {
1224 srv6_vpn_free(attr
->srv6_vpn
);
1225 attr
->srv6_vpn
= NULL
;
1227 #ifdef ENABLE_BGP_VNC
1228 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
1229 bgp_attr_get_vnc_subtlvs(attr
);
1231 if (vnc_subtlvs
&& !vnc_subtlvs
->refcnt
) {
1232 encap_free(vnc_subtlvs
);
1233 bgp_attr_set_vnc_subtlvs(attr
, NULL
);
1238 /* Implement draft-scudder-idr-optional-transitive behaviour and
1239 * avoid resetting sessions for malformed attributes which are
1240 * are partial/optional and hence where the error likely was not
1241 * introduced by the sending neighbour.
1243 static bgp_attr_parse_ret_t
1244 bgp_attr_malformed(struct bgp_attr_parser_args
*args
, uint8_t subcode
,
1247 struct peer
*const peer
= args
->peer
;
1248 struct attr
*const attr
= args
->attr
;
1249 const uint8_t flags
= args
->flags
;
1250 /* startp and length must be special-cased, as whether or not to
1251 * send the attribute data with the NOTIFY depends on the error,
1252 * the caller therefore signals this with the seperate length argument
1254 uint8_t *notify_datap
= (length
> 0 ? args
->startp
: NULL
);
1256 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1257 char attr_str
[BUFSIZ
] = {0};
1259 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1261 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1264 /* Only relax error handling for eBGP peers */
1265 if (peer
->sort
!= BGP_PEER_EBGP
) {
1266 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1267 notify_datap
, length
);
1268 return BGP_ATTR_PARSE_ERROR
;
1271 /* Adjust the stream getp to the end of the attribute, in case we can
1272 * still proceed but the caller hasn't read all the attribute.
1274 stream_set_getp(BGP_INPUT(peer
),
1275 (args
->startp
- STREAM_DATA(BGP_INPUT(peer
)))
1278 switch (args
->type
) {
1279 /* where an attribute is relatively inconsequential, e.g. it does not
1280 * affect route selection, and can be safely ignored, then any such
1281 * attributes which are malformed should just be ignored and the route
1282 * processed as normal.
1284 case BGP_ATTR_AS4_AGGREGATOR
:
1285 case BGP_ATTR_AGGREGATOR
:
1286 case BGP_ATTR_ATOMIC_AGGREGATE
:
1287 return BGP_ATTR_PARSE_PROCEED
;
1289 /* Core attributes, particularly ones which may influence route
1290 * selection, should be treat-as-withdraw.
1292 case BGP_ATTR_ORIGIN
:
1293 case BGP_ATTR_AS_PATH
:
1294 case BGP_ATTR_NEXT_HOP
:
1295 case BGP_ATTR_MULTI_EXIT_DISC
:
1296 case BGP_ATTR_LOCAL_PREF
:
1297 case BGP_ATTR_COMMUNITIES
:
1298 case BGP_ATTR_EXT_COMMUNITIES
:
1299 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
1300 case BGP_ATTR_LARGE_COMMUNITIES
:
1301 case BGP_ATTR_ORIGINATOR_ID
:
1302 case BGP_ATTR_CLUSTER_LIST
:
1303 return BGP_ATTR_PARSE_WITHDRAW
;
1304 case BGP_ATTR_MP_REACH_NLRI
:
1305 case BGP_ATTR_MP_UNREACH_NLRI
:
1306 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
1307 notify_datap
, length
);
1308 return BGP_ATTR_PARSE_ERROR
;
1311 /* Partial optional attributes that are malformed should not cause
1312 * the whole session to be reset. Instead treat it as a withdrawal
1313 * of the routes, if possible.
1315 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)
1316 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1317 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
))
1318 return BGP_ATTR_PARSE_WITHDRAW
;
1320 /* default to reset */
1321 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1324 /* Find out what is wrong with the path attribute flag bits and log the error.
1325 "Flag bits" here stand for Optional, Transitive and Partial, but not for
1326 Extended Length. Checking O/T/P bits at once implies, that the attribute
1327 being diagnosed is defined by RFC as either a "well-known" or an "optional,
1328 non-transitive" attribute. */
1330 bgp_attr_flags_diagnose(struct bgp_attr_parser_args
*args
,
1331 uint8_t desired_flags
/* how RFC says it must be */
1334 uint8_t seen
= 0, i
;
1335 uint8_t real_flags
= args
->flags
;
1336 const uint8_t attr_code
= args
->type
;
1338 desired_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1339 real_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
1340 for (i
= 0; i
<= 2; i
++) /* O,T,P, but not E */
1341 if (CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1342 != CHECK_FLAG(real_flags
, attr_flag_str
[i
].key
)) {
1343 flog_err(EC_BGP_ATTR_FLAG
,
1344 "%s attribute must%s be flagged as \"%s\"",
1345 lookup_msg(attr_str
, attr_code
, NULL
),
1346 CHECK_FLAG(desired_flags
, attr_flag_str
[i
].key
)
1349 attr_flag_str
[i
].str
);
1354 "Strange, %s called for attr %s, but no problem found with flags (real flags 0x%x, desired 0x%x)",
1355 __func__
, lookup_msg(attr_str
, attr_code
, NULL
),
1356 real_flags
, desired_flags
);
1360 /* Required flags for attributes. EXTLEN will be masked off when testing,
1361 * as will PARTIAL for optional+transitive attributes.
1363 const uint8_t attr_flags_values
[] = {
1364 [BGP_ATTR_ORIGIN
] = BGP_ATTR_FLAG_TRANS
,
1365 [BGP_ATTR_AS_PATH
] = BGP_ATTR_FLAG_TRANS
,
1366 [BGP_ATTR_NEXT_HOP
] = BGP_ATTR_FLAG_TRANS
,
1367 [BGP_ATTR_MULTI_EXIT_DISC
] = BGP_ATTR_FLAG_OPTIONAL
,
1368 [BGP_ATTR_LOCAL_PREF
] = BGP_ATTR_FLAG_TRANS
,
1369 [BGP_ATTR_ATOMIC_AGGREGATE
] = BGP_ATTR_FLAG_TRANS
,
1370 [BGP_ATTR_AGGREGATOR
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1371 [BGP_ATTR_COMMUNITIES
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
1372 [BGP_ATTR_ORIGINATOR_ID
] = BGP_ATTR_FLAG_OPTIONAL
,
1373 [BGP_ATTR_CLUSTER_LIST
] = BGP_ATTR_FLAG_OPTIONAL
,
1374 [BGP_ATTR_MP_REACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1375 [BGP_ATTR_MP_UNREACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
1376 [BGP_ATTR_EXT_COMMUNITIES
] =
1377 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1378 [BGP_ATTR_AS4_PATH
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1379 [BGP_ATTR_AS4_AGGREGATOR
] =
1380 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1381 [BGP_ATTR_PMSI_TUNNEL
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1382 [BGP_ATTR_LARGE_COMMUNITIES
] =
1383 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1384 [BGP_ATTR_PREFIX_SID
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1385 [BGP_ATTR_IPV6_EXT_COMMUNITIES
] =
1386 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
1388 static const size_t attr_flags_values_max
= array_size(attr_flags_values
) - 1;
1390 static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args
*args
)
1392 uint8_t mask
= BGP_ATTR_FLAG_EXTLEN
;
1393 const uint8_t flags
= args
->flags
;
1394 const uint8_t attr_code
= args
->type
;
1396 /* there may be attributes we don't know about */
1397 if (attr_code
> attr_flags_values_max
)
1399 if (attr_flags_values
[attr_code
] == 0)
1402 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set
1406 if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL
, flags
)
1407 && !CHECK_FLAG(BGP_ATTR_FLAG_TRANS
, flags
)) {
1410 "%s well-known attributes must have transitive flag set (%x)",
1411 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1415 /* "For well-known attributes and for optional non-transitive
1417 * the Partial bit MUST be set to 0."
1419 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_PARTIAL
)) {
1420 if (!CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)) {
1421 flog_err(EC_BGP_ATTR_FLAG
,
1422 "%s well-known attribute must NOT have the partial flag set (%x)",
1423 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1426 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1427 && !CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
)) {
1428 flog_err(EC_BGP_ATTR_FLAG
,
1429 "%s optional + transitive attribute must NOT have the partial flag set (%x)",
1430 lookup_msg(attr_str
, attr_code
, NULL
), flags
);
1435 /* Optional transitive attributes may go through speakers that don't
1436 * reocgnise them and set the Partial bit.
1438 if (CHECK_FLAG(flags
, BGP_ATTR_FLAG_OPTIONAL
)
1439 && CHECK_FLAG(flags
, BGP_ATTR_FLAG_TRANS
))
1440 SET_FLAG(mask
, BGP_ATTR_FLAG_PARTIAL
);
1442 if ((flags
& ~mask
) == attr_flags_values
[attr_code
])
1445 bgp_attr_flags_diagnose(args
, attr_flags_values
[attr_code
]);
1449 /* Get origin attribute of the update message. */
1450 static bgp_attr_parse_ret_t
bgp_attr_origin(struct bgp_attr_parser_args
*args
)
1452 struct peer
*const peer
= args
->peer
;
1453 struct attr
*const attr
= args
->attr
;
1454 const bgp_size_t length
= args
->length
;
1456 /* If any recognized attribute has Attribute Length that conflicts
1457 with the expected length (based on the attribute type code), then
1458 the Error Subcode is set to Attribute Length Error. The Data
1459 field contains the erroneous attribute (type, length and
1462 flog_err(EC_BGP_ATTR_LEN
,
1463 "Origin attribute length is not one %d", length
);
1464 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1468 /* Fetch origin attribute. */
1469 attr
->origin
= stream_getc(BGP_INPUT(peer
));
1471 /* If the ORIGIN attribute has an undefined value, then the Error
1472 Subcode is set to Invalid Origin Attribute. The Data field
1473 contains the unrecognized attribute (type, length and value). */
1474 if ((attr
->origin
!= BGP_ORIGIN_IGP
) && (attr
->origin
!= BGP_ORIGIN_EGP
)
1475 && (attr
->origin
!= BGP_ORIGIN_INCOMPLETE
)) {
1476 flog_err(EC_BGP_ATTR_ORIGIN
,
1477 "Origin attribute value is invalid %d", attr
->origin
);
1478 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_INVAL_ORIGIN
,
1482 /* Set oring attribute flag. */
1483 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
);
1488 /* Parse AS path information. This function is wrapper of
1490 static int bgp_attr_aspath(struct bgp_attr_parser_args
*args
)
1492 struct attr
*const attr
= args
->attr
;
1493 struct peer
*const peer
= args
->peer
;
1494 const bgp_size_t length
= args
->length
;
1497 * peer with AS4 => will get 4Byte ASnums
1498 * otherwise, will get 16 Bit
1500 attr
->aspath
= aspath_parse(
1502 CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1503 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
));
1505 /* In case of IBGP, length will be zero. */
1506 if (!attr
->aspath
) {
1507 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1508 "Malformed AS path from %s, length is %d", peer
->host
,
1510 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1514 /* Set aspath attribute flag. */
1515 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1517 return BGP_ATTR_PARSE_PROCEED
;
1520 static bgp_attr_parse_ret_t
bgp_attr_aspath_check(struct peer
*const peer
,
1521 struct attr
*const attr
)
1523 /* These checks were part of bgp_attr_aspath, but with
1524 * as4 we should to check aspath things when
1525 * aspath synthesizing with as4_path has already taken place.
1526 * Otherwise we check ASPATH and use the synthesized thing, and that is
1528 * So do the checks later, i.e. here
1530 struct aspath
*aspath
;
1532 /* Confederation sanity check. */
1533 if ((peer
->sort
== BGP_PEER_CONFED
1534 && !aspath_left_confed_check(attr
->aspath
))
1535 || (peer
->sort
== BGP_PEER_EBGP
1536 && aspath_confed_check(attr
->aspath
))) {
1537 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "Malformed AS path from %s",
1539 return BGP_ATTR_PARSE_WITHDRAW
;
1542 /* First AS check for EBGP. */
1543 if (CHECK_FLAG(peer
->flags
, PEER_FLAG_ENFORCE_FIRST_AS
)) {
1544 if (peer
->sort
== BGP_PEER_EBGP
1545 && !aspath_firstas_check(attr
->aspath
, peer
->as
)) {
1546 flog_err(EC_BGP_ATTR_FIRST_AS
,
1547 "%s incorrect first AS (must be %u)",
1548 peer
->host
, peer
->as
);
1549 return BGP_ATTR_PARSE_WITHDRAW
;
1553 /* Codification of AS 0 Processing */
1554 if (peer
->sort
== BGP_PEER_EBGP
&& aspath_check_as_zero(attr
->aspath
)) {
1556 EC_BGP_ATTR_MAL_AS_PATH
,
1557 "Malformed AS path, AS number is 0 in the path from %s",
1559 return BGP_ATTR_PARSE_WITHDRAW
;
1562 /* local-as prepend */
1563 if (peer
->change_local_as
1564 && !CHECK_FLAG(peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
)) {
1565 aspath
= aspath_dup(attr
->aspath
);
1566 aspath
= aspath_add_seq(aspath
, peer
->change_local_as
);
1567 aspath_unintern(&attr
->aspath
);
1568 attr
->aspath
= aspath_intern(aspath
);
1571 return BGP_ATTR_PARSE_PROCEED
;
1574 /* Parse AS4 path information. This function is another wrapper of
1576 static int bgp_attr_as4_path(struct bgp_attr_parser_args
*args
,
1577 struct aspath
**as4_path
)
1579 struct peer
*const peer
= args
->peer
;
1580 struct attr
*const attr
= args
->attr
;
1581 const bgp_size_t length
= args
->length
;
1583 *as4_path
= aspath_parse(peer
->curr
, length
, 1);
1585 /* In case of IBGP, length will be zero. */
1587 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1588 "Malformed AS4 path from %s, length is %d", peer
->host
,
1590 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1594 /* Set aspath attribute flag. */
1595 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
);
1597 return BGP_ATTR_PARSE_PROCEED
;
1601 * Check that the nexthop attribute is valid.
1603 bgp_attr_parse_ret_t
1604 bgp_attr_nexthop_valid(struct peer
*peer
, struct attr
*attr
)
1606 in_addr_t nexthop_h
;
1608 nexthop_h
= ntohl(attr
->nexthop
.s_addr
);
1609 if ((IPV4_NET0(nexthop_h
) || IPV4_NET127(nexthop_h
)
1610 || IPV4_CLASS_DE(nexthop_h
))
1611 && !BGP_DEBUG(allow_martians
, ALLOW_MARTIANS
)) {
1612 uint8_t data
[7]; /* type(2) + length(1) + nhop(4) */
1613 char buf
[INET_ADDRSTRLEN
];
1615 inet_ntop(AF_INET
, &attr
->nexthop
.s_addr
, buf
,
1617 flog_err(EC_BGP_ATTR_MARTIAN_NH
, "Martian nexthop %s",
1619 data
[0] = BGP_ATTR_FLAG_TRANS
;
1620 data
[1] = BGP_ATTR_NEXT_HOP
;
1621 data
[2] = BGP_ATTR_NHLEN_IPV4
;
1622 memcpy(&data
[3], &attr
->nexthop
.s_addr
, BGP_ATTR_NHLEN_IPV4
);
1623 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
1624 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1626 return BGP_ATTR_PARSE_ERROR
;
1629 return BGP_ATTR_PARSE_PROCEED
;
1632 /* Nexthop attribute. */
1633 static bgp_attr_parse_ret_t
bgp_attr_nexthop(struct bgp_attr_parser_args
*args
)
1635 struct peer
*const peer
= args
->peer
;
1636 struct attr
*const attr
= args
->attr
;
1637 const bgp_size_t length
= args
->length
;
1639 /* Check nexthop attribute length. */
1641 flog_err(EC_BGP_ATTR_LEN
,
1642 "Nexthop attribute length isn't four [%d]", length
);
1644 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1648 attr
->nexthop
.s_addr
= stream_get_ipv4(peer
->curr
);
1649 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1651 return BGP_ATTR_PARSE_PROCEED
;
1654 /* MED atrribute. */
1655 static bgp_attr_parse_ret_t
bgp_attr_med(struct bgp_attr_parser_args
*args
)
1657 struct peer
*const peer
= args
->peer
;
1658 struct attr
*const attr
= args
->attr
;
1659 const bgp_size_t length
= args
->length
;
1663 flog_err(EC_BGP_ATTR_LEN
,
1664 "MED attribute length isn't four [%d]", length
);
1666 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1670 attr
->med
= stream_getl(peer
->curr
);
1672 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1674 return BGP_ATTR_PARSE_PROCEED
;
1677 /* Local preference attribute. */
1678 static bgp_attr_parse_ret_t
1679 bgp_attr_local_pref(struct bgp_attr_parser_args
*args
)
1681 struct peer
*const peer
= args
->peer
;
1682 struct attr
*const attr
= args
->attr
;
1683 const bgp_size_t length
= args
->length
;
1685 /* if received from an internal neighbor, it SHALL be considered
1686 * malformed if its length is not equal to 4. If malformed, the
1687 * UPDATE message SHALL be handled using the approach of "treat-as-
1690 if (peer
->sort
== BGP_PEER_IBGP
&& length
!= 4) {
1691 flog_err(EC_BGP_ATTR_LEN
,
1692 "LOCAL_PREF attribute length isn't 4 [%u]", length
);
1693 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1697 /* If it is contained in an UPDATE message that is received from an
1698 external peer, then this attribute MUST be ignored by the
1699 receiving speaker. */
1700 if (peer
->sort
== BGP_PEER_EBGP
) {
1701 STREAM_FORWARD_GETP(peer
->curr
, length
);
1702 return BGP_ATTR_PARSE_PROCEED
;
1705 STREAM_GETL(peer
->curr
, attr
->local_pref
);
1707 /* Set the local-pref flag. */
1708 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
1710 return BGP_ATTR_PARSE_PROCEED
;
1713 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1717 /* Atomic aggregate. */
1718 static int bgp_attr_atomic(struct bgp_attr_parser_args
*args
)
1720 struct attr
*const attr
= args
->attr
;
1721 const bgp_size_t length
= args
->length
;
1725 flog_err(EC_BGP_ATTR_LEN
,
1726 "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1728 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1732 /* Set atomic aggregate flag. */
1733 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1735 return BGP_ATTR_PARSE_PROCEED
;
1738 /* Aggregator attribute */
1739 static int bgp_attr_aggregator(struct bgp_attr_parser_args
*args
)
1741 struct peer
*const peer
= args
->peer
;
1742 struct attr
*const attr
= args
->attr
;
1743 const bgp_size_t length
= args
->length
;
1748 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1749 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1750 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
))
1753 if (length
!= wantedlen
) {
1754 flog_err(EC_BGP_ATTR_LEN
,
1755 "AGGREGATOR attribute length isn't %u [%u]", wantedlen
,
1757 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1761 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
))
1762 aggregator_as
= stream_getl(peer
->curr
);
1764 aggregator_as
= stream_getw(peer
->curr
);
1766 attr
->aggregator_as
= aggregator_as
;
1767 attr
->aggregator_addr
.s_addr
= stream_get_ipv4(peer
->curr
);
1769 /* Codification of AS 0 Processing */
1770 if (aggregator_as
== BGP_AS_ZERO
) {
1771 flog_err(EC_BGP_ATTR_LEN
,
1772 "%s: AGGREGATOR AS number is 0 for aspath: %s",
1773 peer
->host
, aspath_print(attr
->aspath
));
1775 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1776 char attr_str
[BUFSIZ
] = {0};
1778 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1780 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1783 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1786 return BGP_ATTR_PARSE_PROCEED
;
1789 /* New Aggregator attribute */
1790 static bgp_attr_parse_ret_t
1791 bgp_attr_as4_aggregator(struct bgp_attr_parser_args
*args
,
1792 as_t
*as4_aggregator_as
,
1793 struct in_addr
*as4_aggregator_addr
)
1795 struct peer
*const peer
= args
->peer
;
1796 struct attr
*const attr
= args
->attr
;
1797 const bgp_size_t length
= args
->length
;
1801 flog_err(EC_BGP_ATTR_LEN
, "New Aggregator length is not 8 [%d]",
1803 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1807 aggregator_as
= stream_getl(peer
->curr
);
1809 *as4_aggregator_as
= aggregator_as
;
1810 as4_aggregator_addr
->s_addr
= stream_get_ipv4(peer
->curr
);
1812 /* Codification of AS 0 Processing */
1813 if (aggregator_as
== BGP_AS_ZERO
) {
1814 flog_err(EC_BGP_ATTR_LEN
,
1815 "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
1816 peer
->host
, aspath_print(attr
->aspath
));
1818 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1819 char attr_str
[BUFSIZ
] = {0};
1821 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1823 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1826 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
);
1829 return BGP_ATTR_PARSE_PROCEED
;
1832 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1834 static bgp_attr_parse_ret_t
1835 bgp_attr_munge_as4_attrs(struct peer
*const peer
, struct attr
*const attr
,
1836 struct aspath
*as4_path
, as_t as4_aggregator
,
1837 struct in_addr
*as4_aggregator_addr
)
1839 int ignore_as4_path
= 0;
1840 struct aspath
*newpath
;
1842 if (!attr
->aspath
) {
1843 /* NULL aspath shouldn't be possible as bgp_attr_parse should
1845 * checked that all well-known, mandatory attributes were
1848 * Can only be a problem with peer itself - hard error
1850 return BGP_ATTR_PARSE_ERROR
;
1853 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
1854 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1856 * It is worth a warning though, because the peer really
1857 * should not send them
1859 if (BGP_DEBUG(as4
, AS4
)) {
1860 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
1861 zlog_debug("[AS4] %s %s AS4_PATH", peer
->host
,
1862 "AS4 capable peer, yet it sent");
1865 & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
1866 zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
1868 "AS4 capable peer, yet it sent");
1871 return BGP_ATTR_PARSE_PROCEED
;
1874 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1875 * because that may override AS4_PATH
1877 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
))) {
1878 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
))) {
1880 * if the as_number in aggregator is not AS_TRANS,
1881 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1882 * and the Aggregator shall be taken as
1883 * info on the aggregating node, and the AS_PATH
1884 * shall be taken as the AS_PATH
1886 * the Aggregator shall be ignored and the
1887 * AS4_AGGREGATOR shall be taken as the
1888 * Aggregating node and the AS_PATH is to be
1889 * constructed "as in all other cases"
1891 if (attr
->aggregator_as
!= BGP_AS_TRANS
) {
1893 if (BGP_DEBUG(as4
, AS4
))
1895 "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
1897 ignore_as4_path
= 1;
1899 /* "New_aggregator shall be taken as aggregator"
1901 attr
->aggregator_as
= as4_aggregator
;
1902 attr
->aggregator_addr
.s_addr
=
1903 as4_aggregator_addr
->s_addr
;
1906 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1907 * That is bogus - but reading the conditions
1908 * we have to handle AS4_AGGREGATOR as if it were
1909 * AGGREGATOR in that case
1911 if (BGP_DEBUG(as4
, AS4
))
1913 "[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",
1915 attr
->aggregator_as
= as4_aggregator
;
1916 /* sweep it under the carpet and simulate a "good"
1918 attr
->flag
|= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
));
1922 /* need to reconcile NEW_AS_PATH and AS_PATH */
1923 if (!ignore_as4_path
1924 && (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))) {
1925 newpath
= aspath_reconcile_as4(attr
->aspath
, as4_path
);
1927 return BGP_ATTR_PARSE_ERROR
;
1929 aspath_unintern(&attr
->aspath
);
1930 attr
->aspath
= aspath_intern(newpath
);
1932 return BGP_ATTR_PARSE_PROCEED
;
1935 /* Community attribute. */
1936 static bgp_attr_parse_ret_t
1937 bgp_attr_community(struct bgp_attr_parser_args
*args
)
1939 struct peer
*const peer
= args
->peer
;
1940 struct attr
*const attr
= args
->attr
;
1941 const bgp_size_t length
= args
->length
;
1944 attr
->community
= NULL
;
1945 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1950 community_parse((uint32_t *)stream_pnt(peer
->curr
), length
);
1952 /* XXX: fix community_parse to use stream API and remove this */
1953 stream_forward_getp(peer
->curr
, length
);
1955 /* The Community attribute SHALL be considered malformed if its
1956 * length is not a non-zero multiple of 4.
1958 if (!attr
->community
)
1959 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1962 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
);
1964 return BGP_ATTR_PARSE_PROCEED
;
1967 /* Originator ID attribute. */
1968 static bgp_attr_parse_ret_t
1969 bgp_attr_originator_id(struct bgp_attr_parser_args
*args
)
1971 struct peer
*const peer
= args
->peer
;
1972 struct attr
*const attr
= args
->attr
;
1973 const bgp_size_t length
= args
->length
;
1975 /* if received from an internal neighbor, it SHALL be considered
1976 * malformed if its length is not equal to 4. If malformed, the
1977 * UPDATE message SHALL be handled using the approach of "treat-as-
1981 flog_err(EC_BGP_ATTR_LEN
, "Bad originator ID length %d",
1984 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1988 attr
->originator_id
.s_addr
= stream_get_ipv4(peer
->curr
);
1990 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
1992 return BGP_ATTR_PARSE_PROCEED
;
1995 /* Cluster list attribute. */
1996 static bgp_attr_parse_ret_t
1997 bgp_attr_cluster_list(struct bgp_attr_parser_args
*args
)
1999 struct peer
*const peer
= args
->peer
;
2000 struct attr
*const attr
= args
->attr
;
2001 const bgp_size_t length
= args
->length
;
2003 /* if received from an internal neighbor, it SHALL be considered
2004 * malformed if its length is not a non-zero multiple of 4. If
2005 * malformed, the UPDATE message SHALL be handled using the approach
2006 * of "treat-as-withdraw".
2008 if (length
== 0 || length
% 4) {
2009 flog_err(EC_BGP_ATTR_LEN
, "Bad cluster list length %d", length
);
2011 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2015 bgp_attr_set_cluster(
2016 attr
, cluster_parse((struct in_addr
*)stream_pnt(peer
->curr
),
2019 /* XXX: Fix cluster_parse to use stream API and then remove this */
2020 stream_forward_getp(peer
->curr
, length
);
2022 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
);
2024 return BGP_ATTR_PARSE_PROCEED
;
2027 /* Multiprotocol reachability information parse. */
2028 int bgp_mp_reach_parse(struct bgp_attr_parser_args
*args
,
2029 struct bgp_nlri
*mp_update
)
2033 iana_safi_t pkt_safi
;
2035 bgp_size_t nlri_len
;
2038 struct peer
*const peer
= args
->peer
;
2039 struct attr
*const attr
= args
->attr
;
2040 const bgp_size_t length
= args
->length
;
2042 /* Set end of packet. */
2043 s
= BGP_INPUT(peer
);
2044 start
= stream_get_getp(s
);
2046 /* safe to read statically sized header? */
2047 #define BGP_MP_REACH_MIN_SIZE 5
2048 #define LEN_LEFT (length - (stream_get_getp(s) - start))
2049 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
)) {
2050 zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
2051 __func__
, peer
->host
, (unsigned long)length
);
2052 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2055 /* Load AFI, SAFI. */
2056 pkt_afi
= stream_getw(s
);
2057 pkt_safi
= stream_getc(s
);
2059 /* Convert AFI, SAFI to internal values, check. */
2060 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2061 /* Log if AFI or SAFI is unrecognized. This is not an error
2063 * the attribute is otherwise malformed.
2065 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2067 "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
2068 peer
->host
, iana_afi2str(pkt_afi
),
2069 iana_safi2str(pkt_safi
));
2070 return BGP_ATTR_PARSE_ERROR
;
2073 /* Get nexthop length. */
2074 attr
->mp_nexthop_len
= stream_getc(s
);
2076 if (LEN_LEFT
< attr
->mp_nexthop_len
) {
2078 "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
2079 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2080 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2083 /* Nexthop length check. */
2084 switch (attr
->mp_nexthop_len
) {
2086 if (safi
!= SAFI_FLOWSPEC
) {
2087 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2088 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2089 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2092 case BGP_ATTR_NHLEN_VPNV4
:
2093 stream_getl(s
); /* RD high */
2094 stream_getl(s
); /* RD low */
2096 * NOTE: intentional fall through
2097 * - for consistency in rx processing
2099 * The following comment is to signal GCC this intention
2100 * and suppress the warning
2103 case BGP_ATTR_NHLEN_IPV4
:
2104 stream_get(&attr
->mp_nexthop_global_in
, s
, IPV4_MAX_BYTELEN
);
2105 /* Probably needed for RFC 2283 */
2106 if (attr
->nexthop
.s_addr
== INADDR_ANY
)
2107 memcpy(&attr
->nexthop
.s_addr
,
2108 &attr
->mp_nexthop_global_in
, IPV4_MAX_BYTELEN
);
2110 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
2111 case BGP_ATTR_NHLEN_VPNV6_GLOBAL
:
2112 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL
) {
2113 stream_getl(s
); /* RD high */
2114 stream_getl(s
); /* RD low */
2116 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2117 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2118 if (!peer
->nexthop
.ifp
) {
2119 zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2121 return BGP_ATTR_PARSE_WITHDRAW
;
2123 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2126 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
2127 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
:
2128 if (attr
->mp_nexthop_len
2129 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2130 stream_getl(s
); /* RD high */
2131 stream_getl(s
); /* RD low */
2133 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2134 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2135 if (!peer
->nexthop
.ifp
) {
2136 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",
2138 return BGP_ATTR_PARSE_WITHDRAW
;
2140 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2142 if (attr
->mp_nexthop_len
2143 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2144 stream_getl(s
); /* RD high */
2145 stream_getl(s
); /* RD low */
2147 stream_get(&attr
->mp_nexthop_local
, s
, IPV6_MAX_BYTELEN
);
2148 if (!IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_local
)) {
2149 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2151 "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
2152 peer
->host
, &attr
->mp_nexthop_global
,
2153 &attr
->mp_nexthop_local
);
2155 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
2157 if (!peer
->nexthop
.ifp
) {
2158 zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
2160 return BGP_ATTR_PARSE_WITHDRAW
;
2162 attr
->nh_lla_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2165 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2166 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2167 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2171 zlog_info("%s: %s sent SNPA which couldn't be read",
2172 __func__
, peer
->host
);
2173 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2178 if ((val
= stream_getc(s
)))
2180 EC_BGP_DEFUNCT_SNPA_LEN
,
2181 "%s sent non-zero value, %u, for defunct SNPA-length field",
2185 /* must have nrli_len, what is left of the attribute */
2186 nlri_len
= LEN_LEFT
;
2187 if (nlri_len
> STREAM_READABLE(s
)) {
2188 zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
2189 __func__
, peer
->host
);
2190 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2194 zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
2195 __func__
, peer
->host
);
2197 mp_update
->afi
= afi
;
2198 mp_update
->safi
= safi
;
2199 return BGP_ATTR_PARSE_EOR
;
2202 mp_update
->afi
= afi
;
2203 mp_update
->safi
= safi
;
2204 mp_update
->nlri
= stream_pnt(s
);
2205 mp_update
->length
= nlri_len
;
2207 stream_forward_getp(s
, nlri_len
);
2209 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
);
2211 return BGP_ATTR_PARSE_PROCEED
;
2215 /* Multiprotocol unreachable parse */
2216 int bgp_mp_unreach_parse(struct bgp_attr_parser_args
*args
,
2217 struct bgp_nlri
*mp_withdraw
)
2222 iana_safi_t pkt_safi
;
2224 uint16_t withdraw_len
;
2225 struct peer
*const peer
= args
->peer
;
2226 struct attr
*const attr
= args
->attr
;
2227 const bgp_size_t length
= args
->length
;
2231 #define BGP_MP_UNREACH_MIN_SIZE 3
2232 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
2233 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2235 pkt_afi
= stream_getw(s
);
2236 pkt_safi
= stream_getc(s
);
2238 /* Convert AFI, SAFI to internal values, check. */
2239 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2240 /* Log if AFI or SAFI is unrecognized. This is not an error
2242 * the attribute is otherwise malformed.
2244 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2246 "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
2247 peer
->host
, iana_afi2str(pkt_afi
),
2248 iana_safi2str(pkt_safi
));
2249 return BGP_ATTR_PARSE_ERROR
;
2252 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
2254 mp_withdraw
->afi
= afi
;
2255 mp_withdraw
->safi
= safi
;
2256 mp_withdraw
->nlri
= stream_pnt(s
);
2257 mp_withdraw
->length
= withdraw_len
;
2259 stream_forward_getp(s
, withdraw_len
);
2261 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
);
2263 return BGP_ATTR_PARSE_PROCEED
;
2266 /* Large Community attribute. */
2267 static bgp_attr_parse_ret_t
2268 bgp_attr_large_community(struct bgp_attr_parser_args
*args
)
2270 struct peer
*const peer
= args
->peer
;
2271 struct attr
*const attr
= args
->attr
;
2272 const bgp_size_t length
= args
->length
;
2275 * Large community follows new attribute format.
2278 attr
->lcommunity
= NULL
;
2279 /* Empty extcomm doesn't seem to be invalid per se */
2280 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2284 attr
->lcommunity
= lcommunity_parse(stream_pnt(peer
->curr
), length
);
2285 /* XXX: fix ecommunity_parse to use stream API */
2286 stream_forward_getp(peer
->curr
, length
);
2288 if (!attr
->lcommunity
)
2289 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2292 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
);
2294 return BGP_ATTR_PARSE_PROCEED
;
2297 /* Extended Community attribute. */
2298 static bgp_attr_parse_ret_t
2299 bgp_attr_ext_communities(struct bgp_attr_parser_args
*args
)
2301 struct peer
*const peer
= args
->peer
;
2302 struct attr
*const attr
= args
->attr
;
2303 const bgp_size_t length
= args
->length
;
2308 attr
->ecommunity
= NULL
;
2309 /* Empty extcomm doesn't seem to be invalid per se */
2310 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2315 ecommunity_parse(stream_pnt(peer
->curr
), length
);
2316 /* XXX: fix ecommunity_parse to use stream API */
2317 stream_forward_getp(peer
->curr
, length
);
2319 /* The Extended Community attribute SHALL be considered malformed if
2320 * its length is not a non-zero multiple of 8.
2322 if (!attr
->ecommunity
)
2323 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2326 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
2328 /* Extract DF election preference and mobility sequence number */
2329 attr
->df_pref
= bgp_attr_df_pref_from_ec(attr
, &attr
->df_alg
);
2331 /* Extract MAC mobility sequence number, if any. */
2332 attr
->mm_seqnum
= bgp_attr_mac_mobility_seqnum(attr
, &sticky
);
2333 attr
->sticky
= sticky
;
2335 /* Check if this is a Gateway MAC-IP advertisement */
2336 attr
->default_gw
= bgp_attr_default_gw(attr
);
2338 /* Handle scenario where router flag ecommunity is not
2339 * set but default gw ext community is present.
2340 * Use default gateway, set and propogate R-bit.
2342 if (attr
->default_gw
)
2343 attr
->router_flag
= 1;
2345 /* Check EVPN Neighbor advertisement flags, R-bit */
2346 bgp_attr_evpn_na_flag(attr
, &attr
->router_flag
, &proxy
);
2348 attr
->es_flags
|= ATTR_ES_PROXY_ADVERT
;
2350 /* Extract the Rmac, if any */
2351 if (bgp_attr_rmac(attr
, &attr
->rmac
)) {
2352 if (bgp_debug_update(peer
, NULL
, NULL
, 1)
2353 && bgp_mac_exist(&attr
->rmac
))
2354 zlog_debug("%s: router mac %pEA is self mac", __func__
,
2358 /* Get the tunnel type from encap extended community */
2359 bgp_attr_extcom_tunnel_type(attr
,
2360 (bgp_encap_types
*)&attr
->encap_tunneltype
);
2362 /* Extract link bandwidth, if any. */
2363 (void)ecommunity_linkbw_present(attr
->ecommunity
, &attr
->link_bw
);
2365 return BGP_ATTR_PARSE_PROCEED
;
2368 /* IPv6 Extended Community attribute. */
2369 static bgp_attr_parse_ret_t
2370 bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args
*args
)
2372 struct peer
*const peer
= args
->peer
;
2373 struct attr
*const attr
= args
->attr
;
2374 const bgp_size_t length
= args
->length
;
2375 struct ecommunity
*ipv6_ecomm
= NULL
;
2378 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2379 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2383 ipv6_ecomm
= ecommunity_parse_ipv6(stream_pnt(peer
->curr
), length
);
2384 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2386 /* XXX: fix ecommunity_parse to use stream API */
2387 stream_forward_getp(peer
->curr
, length
);
2390 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2393 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES
);
2395 return BGP_ATTR_PARSE_PROCEED
;
2398 /* Parse Tunnel Encap attribute in an UPDATE */
2399 static int bgp_attr_encap(uint8_t type
, struct peer
*peer
, /* IN */
2400 bgp_size_t length
, /* IN: attr's length field */
2401 struct attr
*attr
, /* IN: caller already allocated */
2402 uint8_t flag
, /* IN: attr's flags field */
2406 uint16_t tunneltype
= 0;
2408 total
= length
+ (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
2410 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
)
2411 || !CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
2413 "Tunnel Encap attribute flag isn't optional and transitive %d",
2415 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2416 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
2421 if (BGP_ATTR_ENCAP
== type
) {
2422 /* read outer TLV type and length */
2423 uint16_t tlv_length
;
2427 "Tunnel Encap attribute not long enough to contain outer T,L");
2428 bgp_notify_send_with_data(
2429 peer
, BGP_NOTIFY_UPDATE_ERR
,
2430 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2433 tunneltype
= stream_getw(BGP_INPUT(peer
));
2434 tlv_length
= stream_getw(BGP_INPUT(peer
));
2437 if (tlv_length
!= length
) {
2438 zlog_info("%s: tlv_length(%d) != length(%d)",
2439 __func__
, tlv_length
, length
);
2443 while (length
>= 4) {
2444 uint16_t subtype
= 0;
2445 uint16_t sublength
= 0;
2446 struct bgp_attr_encap_subtlv
*tlv
;
2448 if (BGP_ATTR_ENCAP
== type
) {
2449 subtype
= stream_getc(BGP_INPUT(peer
));
2450 sublength
= stream_getc(BGP_INPUT(peer
));
2452 #ifdef ENABLE_BGP_VNC
2454 subtype
= stream_getw(BGP_INPUT(peer
));
2455 sublength
= stream_getw(BGP_INPUT(peer
));
2460 if (sublength
> length
) {
2462 "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2464 bgp_notify_send_with_data(
2465 peer
, BGP_NOTIFY_UPDATE_ERR
,
2466 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2470 /* alloc and copy sub-tlv */
2471 /* TBD make sure these are freed when attributes are released */
2472 tlv
= XCALLOC(MTYPE_ENCAP_TLV
,
2473 sizeof(struct bgp_attr_encap_subtlv
) + sublength
);
2474 tlv
->type
= subtype
;
2475 tlv
->length
= sublength
;
2476 stream_get(tlv
->value
, peer
->curr
, sublength
);
2477 length
-= sublength
;
2479 /* attach tlv to encap chain */
2480 if (BGP_ATTR_ENCAP
== type
) {
2481 struct bgp_attr_encap_subtlv
*stlv_last
;
2482 for (stlv_last
= attr
->encap_subtlvs
;
2483 stlv_last
&& stlv_last
->next
;
2484 stlv_last
= stlv_last
->next
)
2487 stlv_last
->next
= tlv
;
2489 attr
->encap_subtlvs
= tlv
;
2491 #ifdef ENABLE_BGP_VNC
2493 struct bgp_attr_encap_subtlv
*stlv_last
;
2494 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
2495 bgp_attr_get_vnc_subtlvs(attr
);
2497 for (stlv_last
= vnc_subtlvs
;
2498 stlv_last
&& stlv_last
->next
;
2499 stlv_last
= stlv_last
->next
)
2502 stlv_last
->next
= tlv
;
2504 bgp_attr_set_vnc_subtlvs(attr
, tlv
);
2509 if (BGP_ATTR_ENCAP
== type
) {
2510 attr
->encap_tunneltype
= tunneltype
;
2514 /* spurious leftover data */
2516 "Tunnel Encap attribute length is bad: %d leftover octets",
2518 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2519 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2528 * Read an individual SID value returning how much data we have read
2529 * Returns 0 if there was an error that needs to be passed up the stack
2531 static bgp_attr_parse_ret_t
bgp_attr_psid_sub(uint8_t type
, uint16_t length
,
2532 struct bgp_attr_parser_args
*args
)
2534 struct peer
*const peer
= args
->peer
;
2535 struct attr
*const attr
= args
->attr
;
2536 uint32_t label_index
;
2537 struct in6_addr ipv6_sid
;
2539 uint32_t srgb_range
;
2541 uint8_t sid_type
, sid_flags
;
2542 uint16_t endpoint_behavior
;
2545 if (type
== BGP_PREFIX_SID_LABEL_INDEX
) {
2546 if (STREAM_READABLE(peer
->curr
) < length
2547 || length
!= BGP_PREFIX_SID_LABEL_INDEX_LENGTH
) {
2548 flog_err(EC_BGP_ATTR_LEN
,
2549 "Prefix SID label index length is %hu instead of %u",
2550 length
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
2551 return bgp_attr_malformed(args
,
2552 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2556 /* Ignore flags and reserved */
2557 stream_getc(peer
->curr
);
2558 stream_getw(peer
->curr
);
2560 /* Fetch the label index and see if it is valid. */
2561 label_index
= stream_getl(peer
->curr
);
2562 if (label_index
== BGP_INVALID_LABEL_INDEX
)
2563 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2566 /* Store label index; subsequently, we'll check on
2568 attr
->label_index
= label_index
;
2571 /* Placeholder code for the IPv6 SID type */
2572 else if (type
== BGP_PREFIX_SID_IPV6
) {
2573 if (STREAM_READABLE(peer
->curr
) < length
2574 || length
!= BGP_PREFIX_SID_IPV6_LENGTH
) {
2575 flog_err(EC_BGP_ATTR_LEN
,
2576 "Prefix SID IPv6 length is %hu instead of %u",
2577 length
, BGP_PREFIX_SID_IPV6_LENGTH
);
2578 return bgp_attr_malformed(args
,
2579 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2583 /* Ignore reserved */
2584 stream_getc(peer
->curr
);
2585 stream_getw(peer
->curr
);
2587 stream_get(&ipv6_sid
, peer
->curr
, 16);
2590 /* Placeholder code for the Originator SRGB type */
2591 else if (type
== BGP_PREFIX_SID_ORIGINATOR_SRGB
) {
2593 * ietf-idr-bgp-prefix-sid-05:
2594 * Length is the total length of the value portion of the
2595 * TLV: 2 + multiple of 6.
2597 * peer->curr stream readp should be at the beginning of the 16
2598 * bit flag field at this point in the code.
2602 * Check that the TLV length field is sane: at least 2 bytes of
2603 * flag, and at least 1 SRGB (these are 6 bytes each)
2605 if (length
< (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
)) {
2608 "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
2610 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
2611 return bgp_attr_malformed(
2612 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2617 * Check that we actually have at least as much data as
2618 * specified by the length field
2620 if (STREAM_READABLE(peer
->curr
) < length
) {
2621 flog_err(EC_BGP_ATTR_LEN
,
2622 "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain",
2623 length
, STREAM_READABLE(peer
->curr
));
2624 return bgp_attr_malformed(
2625 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2630 * Check that the portion of the TLV containing the sequence of
2631 * SRGBs corresponds to a multiple of the SRGB size; to get
2632 * that length, we skip the 16 bit flags field
2634 stream_getw(peer
->curr
);
2636 if (length
% BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
) {
2639 "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
2640 length
, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
2641 return bgp_attr_malformed(
2642 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2646 srgb_count
= length
/ BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
;
2648 for (int i
= 0; i
< srgb_count
; i
++) {
2649 stream_get(&srgb_base
, peer
->curr
, 3);
2650 stream_get(&srgb_range
, peer
->curr
, 3);
2654 /* Placeholder code for the VPN-SID Service type */
2655 else if (type
== BGP_PREFIX_SID_VPN_SID
) {
2656 if (STREAM_READABLE(peer
->curr
) < length
2657 || length
!= BGP_PREFIX_SID_VPN_SID_LENGTH
) {
2658 flog_err(EC_BGP_ATTR_LEN
,
2659 "Prefix SID VPN SID length is %hu instead of %u",
2660 length
, BGP_PREFIX_SID_VPN_SID_LENGTH
);
2661 return bgp_attr_malformed(args
,
2662 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2666 /* Parse VPN-SID Sub-TLV */
2667 stream_getc(peer
->curr
); /* reserved */
2668 sid_type
= stream_getc(peer
->curr
); /* sid_type */
2669 sid_flags
= stream_getc(peer
->curr
); /* sid_flags */
2670 stream_get(&ipv6_sid
, peer
->curr
,
2671 sizeof(ipv6_sid
)); /* sid_value */
2673 /* Log VPN-SID Sub-TLV */
2674 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2675 inet_ntop(AF_INET6
, &ipv6_sid
, buf
, sizeof(buf
));
2677 "%s: vpn-sid: sid %s, sid-type 0x%02x sid-flags 0x%02x",
2678 __func__
, buf
, sid_type
, sid_flags
);
2681 /* Configure from Info */
2682 if (attr
->srv6_vpn
) {
2683 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2684 "Prefix SID SRv6 VPN field repeated");
2685 return bgp_attr_malformed(
2686 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2688 attr
->srv6_vpn
= XCALLOC(MTYPE_BGP_SRV6_VPN
,
2689 sizeof(struct bgp_attr_srv6_vpn
));
2690 attr
->srv6_vpn
->sid_flags
= sid_flags
;
2691 sid_copy(&attr
->srv6_vpn
->sid
, &ipv6_sid
);
2692 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
2695 /* Placeholder code for the SRv6 L3 Service type */
2696 else if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE
) {
2697 if (STREAM_READABLE(peer
->curr
) < length
2698 || length
!= BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH
) {
2699 flog_err(EC_BGP_ATTR_LEN
,
2700 "Prefix SID SRv6 L3-Service length is %hu instead of %u",
2701 length
, BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH
);
2702 return bgp_attr_malformed(args
,
2703 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2707 /* Parse L3-SERVICE Sub-TLV */
2708 stream_getc(peer
->curr
); /* reserved */
2709 stream_get(&ipv6_sid
, peer
->curr
,
2710 sizeof(ipv6_sid
)); /* sid_value */
2711 sid_flags
= stream_getc(peer
->curr
); /* sid_flags */
2712 endpoint_behavior
= stream_getw(peer
->curr
); /* endpoint */
2713 stream_getc(peer
->curr
); /* reserved */
2715 /* Log L3-SERVICE Sub-TLV */
2716 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2717 inet_ntop(AF_INET6
, &ipv6_sid
, buf
, sizeof(buf
));
2719 "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
2720 __func__
, buf
, sid_flags
, endpoint_behavior
);
2723 /* Configure from Info */
2724 if (attr
->srv6_l3vpn
) {
2725 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2726 "Prefix SID SRv6 L3VPN field repeated");
2727 return bgp_attr_malformed(
2728 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2730 attr
->srv6_l3vpn
= XCALLOC(MTYPE_BGP_SRV6_L3VPN
,
2731 sizeof(struct bgp_attr_srv6_l3vpn
));
2732 attr
->srv6_l3vpn
->sid_flags
= sid_flags
;
2733 attr
->srv6_l3vpn
->endpoint_behavior
= endpoint_behavior
;
2734 sid_copy(&attr
->srv6_l3vpn
->sid
, &ipv6_sid
);
2735 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
2738 /* Placeholder code for Unsupported TLV */
2741 if (STREAM_READABLE(peer
->curr
) < length
) {
2744 "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE",
2745 length
, STREAM_READABLE(peer
->curr
));
2746 return bgp_attr_malformed(
2747 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2751 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2753 "%s attr Prefix-SID sub-type=%u is not supported, skipped",
2756 stream_forward_getp(peer
->curr
, length
);
2759 return BGP_ATTR_PARSE_PROCEED
;
2762 /* Prefix SID attribute
2763 * draft-ietf-idr-bgp-prefix-sid-05
2765 bgp_attr_parse_ret_t
bgp_attr_prefix_sid(struct bgp_attr_parser_args
*args
)
2767 struct peer
*const peer
= args
->peer
;
2768 struct attr
*const attr
= args
->attr
;
2769 bgp_attr_parse_ret_t ret
;
2771 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
);
2775 size_t headersz
= sizeof(type
) + sizeof(length
);
2776 size_t psid_parsed_length
= 0;
2778 while (STREAM_READABLE(peer
->curr
) > 0
2779 && psid_parsed_length
< args
->length
) {
2781 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2784 "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2785 headersz
, STREAM_READABLE(peer
->curr
));
2786 return bgp_attr_malformed(
2787 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2791 type
= stream_getc(peer
->curr
);
2792 length
= stream_getw(peer
->curr
);
2794 if (STREAM_READABLE(peer
->curr
) < length
) {
2797 "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
2798 length
, STREAM_READABLE(peer
->curr
));
2799 return bgp_attr_malformed(args
,
2800 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2804 ret
= bgp_attr_psid_sub(type
, length
, args
);
2806 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
2809 psid_parsed_length
+= length
+ headersz
;
2811 if (psid_parsed_length
> args
->length
) {
2814 "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
2815 length
+ headersz
, psid_parsed_length
- (length
+ headersz
));
2816 return bgp_attr_malformed(
2817 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2822 return BGP_ATTR_PARSE_PROCEED
;
2825 /* PMSI tunnel attribute (RFC 6514)
2826 * Basic validation checks done here.
2828 static bgp_attr_parse_ret_t
2829 bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args
*args
)
2831 struct peer
*const peer
= args
->peer
;
2832 struct attr
*const attr
= args
->attr
;
2833 const bgp_size_t length
= args
->length
;
2835 int attr_parse_len
= 2 + BGP_LABEL_BYTES
;
2837 /* Verify that the receiver is expecting "ingress replication" as we
2838 * can only support that.
2840 if (length
< attr_parse_len
) {
2841 flog_err(EC_BGP_ATTR_LEN
, "Bad PMSI tunnel attribute length %d",
2843 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2846 stream_getc(peer
->curr
); /* Flags */
2847 tnl_type
= stream_getc(peer
->curr
);
2848 if (tnl_type
> PMSI_TNLTYPE_MAX
) {
2849 flog_err(EC_BGP_ATTR_PMSI_TYPE
,
2850 "Invalid PMSI tunnel attribute type %d", tnl_type
);
2851 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2854 if (tnl_type
== PMSI_TNLTYPE_INGR_REPL
) {
2856 flog_err(EC_BGP_ATTR_PMSI_LEN
,
2857 "Bad PMSI tunnel attribute length %d for IR",
2859 return bgp_attr_malformed(
2860 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2865 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
);
2866 bgp_attr_set_pmsi_tnl_type(attr
, tnl_type
);
2867 stream_get(&attr
->label
, peer
->curr
, BGP_LABEL_BYTES
);
2869 /* Forward read pointer of input stream. */
2870 stream_forward_getp(peer
->curr
, length
- attr_parse_len
);
2872 return BGP_ATTR_PARSE_PROCEED
;
2875 /* BGP unknown attribute treatment. */
2876 static bgp_attr_parse_ret_t
bgp_attr_unknown(struct bgp_attr_parser_args
*args
)
2878 bgp_size_t total
= args
->total
;
2879 struct transit
*transit
;
2880 struct peer
*const peer
= args
->peer
;
2881 struct attr
*const attr
= args
->attr
;
2882 uint8_t *const startp
= args
->startp
;
2883 const uint8_t type
= args
->type
;
2884 const uint8_t flag
= args
->flags
;
2885 const bgp_size_t length
= args
->length
;
2887 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2889 "%s Unknown attribute is received (type %d, length %d)",
2890 peer
->host
, type
, length
);
2892 /* Forward read pointer of input stream. */
2893 stream_forward_getp(peer
->curr
, length
);
2895 /* If any of the mandatory well-known attributes are not recognized,
2896 then the Error Subcode is set to Unrecognized Well-known
2897 Attribute. The Data field contains the unrecognized attribute
2898 (type, length and value). */
2899 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
2900 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_UNREC_ATTR
,
2904 /* Unrecognized non-transitive optional attributes must be quietly
2905 ignored and not passed along to other BGP peers. */
2906 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
))
2907 return BGP_ATTR_PARSE_PROCEED
;
2909 /* If a path with recognized transitive optional attribute is
2910 accepted and passed along to other BGP peers and the Partial bit
2911 in the Attribute Flags octet is set to 1 by some previous AS, it
2912 is not set back to 0 by the current AS. */
2913 SET_FLAG(*startp
, BGP_ATTR_FLAG_PARTIAL
);
2915 /* Store transitive attribute to the end of attr->transit. */
2916 transit
= bgp_attr_get_transit(attr
);
2918 transit
= XCALLOC(MTYPE_TRANSIT
, sizeof(struct transit
));
2920 transit
->val
= XREALLOC(MTYPE_TRANSIT_VAL
, transit
->val
,
2921 transit
->length
+ total
);
2923 memcpy(transit
->val
+ transit
->length
, startp
, total
);
2924 transit
->length
+= total
;
2925 bgp_attr_set_transit(attr
, transit
);
2927 return BGP_ATTR_PARSE_PROCEED
;
2930 /* Well-known attribute check. */
2931 static int bgp_attr_check(struct peer
*peer
, struct attr
*attr
)
2935 /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
2937 if (CHECK_FLAG(peer
->cap
, PEER_CAP_RESTART_RCV
) && !attr
->flag
)
2938 return BGP_ATTR_PARSE_PROCEED
;
2940 /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
2941 to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
2942 are present, it should. Check for any other attribute being present
2945 if ((!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)) &&
2946 CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
))))
2947 return BGP_ATTR_PARSE_PROCEED
;
2949 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
)))
2950 type
= BGP_ATTR_ORIGIN
;
2952 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
2953 type
= BGP_ATTR_AS_PATH
;
2955 /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
2957 * NLRI is empty. We can't easily check NLRI empty here though.
2959 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
2960 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)))
2961 type
= BGP_ATTR_NEXT_HOP
;
2963 if (peer
->sort
== BGP_PEER_IBGP
2964 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)))
2965 type
= BGP_ATTR_LOCAL_PREF
;
2967 /* If any of the well-known mandatory attributes are not present
2968 * in an UPDATE message, then "treat-as-withdraw" MUST be used.
2971 flog_warn(EC_BGP_MISSING_ATTRIBUTE
,
2972 "%s Missing well-known attribute %s.", peer
->host
,
2973 lookup_msg(attr_str
, type
, NULL
));
2974 return BGP_ATTR_PARSE_WITHDRAW
;
2976 return BGP_ATTR_PARSE_PROCEED
;
2979 /* Read attribute of update packet. This function is called from
2980 bgp_update_receive() in bgp_packet.c. */
2981 bgp_attr_parse_ret_t
bgp_attr_parse(struct peer
*peer
, struct attr
*attr
,
2982 bgp_size_t size
, struct bgp_nlri
*mp_update
,
2983 struct bgp_nlri
*mp_withdraw
)
2985 bgp_attr_parse_ret_t ret
;
2989 uint8_t *startp
, *endp
;
2991 uint8_t seen
[BGP_ATTR_BITMAP_SIZE
];
2992 /* we need the as4_path only until we have synthesized the as_path with
2994 /* same goes for as4_aggregator */
2995 struct aspath
*as4_path
= NULL
;
2996 as_t as4_aggregator
= 0;
2997 struct in_addr as4_aggregator_addr
= {.s_addr
= 0};
2998 struct transit
*transit
;
3000 /* Initialize bitmap. */
3001 memset(seen
, 0, BGP_ATTR_BITMAP_SIZE
);
3003 /* End pointer of BGP attribute. */
3004 endp
= BGP_INPUT_PNT(peer
) + size
;
3006 /* Get attributes to the end of attribute length. */
3007 while (BGP_INPUT_PNT(peer
) < endp
) {
3008 /* Check remaining length check.*/
3009 if (endp
- BGP_INPUT_PNT(peer
) < BGP_ATTR_MIN_LEN
) {
3010 /* XXX warning: long int format, int arg (arg 5) */
3012 EC_BGP_ATTRIBUTE_TOO_SMALL
,
3013 "%s: error BGP attribute length %lu is smaller than min len",
3015 (unsigned long)(endp
3016 - stream_pnt(BGP_INPUT(peer
))));
3018 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3019 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3020 ret
= BGP_ATTR_PARSE_ERROR
;
3024 /* Fetch attribute flag and type. */
3025 startp
= BGP_INPUT_PNT(peer
);
3026 /* "The lower-order four bits of the Attribute Flags octet are
3027 unused. They MUST be zero when sent and MUST be ignored when
3029 flag
= 0xF0 & stream_getc(BGP_INPUT(peer
));
3030 type
= stream_getc(BGP_INPUT(peer
));
3032 /* Check whether Extended-Length applies and is in bounds */
3033 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
)
3034 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1))) {
3036 EC_BGP_EXT_ATTRIBUTE_TOO_SMALL
,
3037 "%s: Extended length set, but just %lu bytes of attr header",
3039 (unsigned long)(endp
3040 - stream_pnt(BGP_INPUT(peer
))));
3042 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3043 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3044 ret
= BGP_ATTR_PARSE_ERROR
;
3048 /* Check extended attribue length bit. */
3049 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
))
3050 length
= stream_getw(BGP_INPUT(peer
));
3052 length
= stream_getc(BGP_INPUT(peer
));
3054 /* If any attribute appears more than once in the UPDATE
3055 message, then the Error Subcode is set to Malformed Attribute
3058 if (CHECK_BITMAP(seen
, type
)) {
3060 EC_BGP_ATTRIBUTE_REPEATED
,
3061 "%s: error BGP attribute type %d appears twice in a message",
3064 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3065 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3066 ret
= BGP_ATTR_PARSE_ERROR
;
3070 /* Set type to bitmap to check duplicate attribute. `type' is
3071 unsigned char so it never overflow bitmap range. */
3073 SET_BITMAP(seen
, type
);
3075 /* Overflow check. */
3076 attr_endp
= BGP_INPUT_PNT(peer
) + length
;
3078 if (attr_endp
> endp
) {
3080 EC_BGP_ATTRIBUTE_TOO_LARGE
,
3081 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
3082 peer
->host
, type
, length
, size
, attr_endp
,
3086 * If any recognized attribute has an Attribute
3087 * Length that conflicts with the expected length
3088 * (based on the attribute type code), then the
3089 * Error Subcode MUST be set to Attribute Length
3090 * Error. The Data field MUST contain the erroneous
3091 * attribute (type, length, and value).
3093 * We do not currently have a good way to determine the
3094 * length of the attribute independent of the length
3095 * received in the message. Instead we send the
3096 * minimum between the amount of data we have and the
3097 * amount specified by the attribute length field.
3099 * Instead of directly passing in the packet buffer and
3100 * offset we use the stream_get* functions to read into
3101 * a stack buffer, since they perform bounds checking
3102 * and we are working with untrusted data.
3104 unsigned char ndata
[peer
->max_packet_size
];
3105 memset(ndata
, 0x00, sizeof(ndata
));
3107 CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 2 : 1;
3108 /* Rewind to end of flag field */
3109 stream_rewind_getp(BGP_INPUT(peer
), (1 + lfl
));
3111 stream_get(&ndata
[0], BGP_INPUT(peer
), 1);
3113 stream_get(&ndata
[1], BGP_INPUT(peer
), lfl
);
3115 size_t atl
= attr_endp
- startp
;
3116 size_t ndl
= MIN(atl
, STREAM_READABLE(BGP_INPUT(peer
)));
3117 stream_get(&ndata
[lfl
+ 1], BGP_INPUT(peer
), ndl
);
3119 bgp_notify_send_with_data(
3120 peer
, BGP_NOTIFY_UPDATE_ERR
,
3121 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
, ndata
,
3124 ret
= BGP_ATTR_PARSE_ERROR
;
3128 struct bgp_attr_parser_args attr_args
= {
3135 .total
= attr_endp
- startp
,
3139 /* If any recognized attribute has Attribute Flags that conflict
3140 with the Attribute Type Code, then the Error Subcode is set
3142 Attribute Flags Error. The Data field contains the erroneous
3143 attribute (type, length and value). */
3144 if (bgp_attr_flag_invalid(&attr_args
)) {
3145 ret
= bgp_attr_malformed(
3146 &attr_args
, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
3148 if (ret
== BGP_ATTR_PARSE_PROCEED
)
3153 /* OK check attribute and store it's value. */
3155 case BGP_ATTR_ORIGIN
:
3156 ret
= bgp_attr_origin(&attr_args
);
3158 case BGP_ATTR_AS_PATH
:
3159 ret
= bgp_attr_aspath(&attr_args
);
3161 case BGP_ATTR_AS4_PATH
:
3162 ret
= bgp_attr_as4_path(&attr_args
, &as4_path
);
3164 case BGP_ATTR_NEXT_HOP
:
3165 ret
= bgp_attr_nexthop(&attr_args
);
3167 case BGP_ATTR_MULTI_EXIT_DISC
:
3168 ret
= bgp_attr_med(&attr_args
);
3170 case BGP_ATTR_LOCAL_PREF
:
3171 ret
= bgp_attr_local_pref(&attr_args
);
3173 case BGP_ATTR_ATOMIC_AGGREGATE
:
3174 ret
= bgp_attr_atomic(&attr_args
);
3176 case BGP_ATTR_AGGREGATOR
:
3177 ret
= bgp_attr_aggregator(&attr_args
);
3179 case BGP_ATTR_AS4_AGGREGATOR
:
3180 ret
= bgp_attr_as4_aggregator(&attr_args
,
3182 &as4_aggregator_addr
);
3184 case BGP_ATTR_COMMUNITIES
:
3185 ret
= bgp_attr_community(&attr_args
);
3187 case BGP_ATTR_LARGE_COMMUNITIES
:
3188 ret
= bgp_attr_large_community(&attr_args
);
3190 case BGP_ATTR_ORIGINATOR_ID
:
3191 ret
= bgp_attr_originator_id(&attr_args
);
3193 case BGP_ATTR_CLUSTER_LIST
:
3194 ret
= bgp_attr_cluster_list(&attr_args
);
3196 case BGP_ATTR_MP_REACH_NLRI
:
3197 ret
= bgp_mp_reach_parse(&attr_args
, mp_update
);
3199 case BGP_ATTR_MP_UNREACH_NLRI
:
3200 ret
= bgp_mp_unreach_parse(&attr_args
, mp_withdraw
);
3202 case BGP_ATTR_EXT_COMMUNITIES
:
3203 ret
= bgp_attr_ext_communities(&attr_args
);
3205 #ifdef ENABLE_BGP_VNC_ATTR
3208 case BGP_ATTR_ENCAP
:
3209 ret
= bgp_attr_encap(type
, peer
, length
, attr
, flag
,
3212 case BGP_ATTR_PREFIX_SID
:
3213 ret
= bgp_attr_prefix_sid(&attr_args
);
3215 case BGP_ATTR_PMSI_TUNNEL
:
3216 ret
= bgp_attr_pmsi_tunnel(&attr_args
);
3218 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
3219 ret
= bgp_attr_ipv6_ext_communities(&attr_args
);
3222 ret
= bgp_attr_unknown(&attr_args
);
3226 if (ret
== BGP_ATTR_PARSE_ERROR_NOTIFYPLS
) {
3227 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3228 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3229 ret
= BGP_ATTR_PARSE_ERROR
;
3233 if (ret
== BGP_ATTR_PARSE_EOR
) {
3237 if (ret
== BGP_ATTR_PARSE_ERROR
) {
3238 flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR
,
3239 "%s: Attribute %s, parse error", peer
->host
,
3240 lookup_msg(attr_str
, type
, NULL
));
3243 if (ret
== BGP_ATTR_PARSE_WITHDRAW
) {
3245 EC_BGP_ATTRIBUTE_PARSE_WITHDRAW
,
3246 "%s: Attribute %s, parse error - treating as withdrawal",
3247 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3251 /* Check the fetched length. */
3252 if (BGP_INPUT_PNT(peer
) != attr_endp
) {
3253 flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR
,
3254 "%s: BGP attribute %s, fetch error",
3255 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3256 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3257 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3258 ret
= BGP_ATTR_PARSE_ERROR
;
3264 * draft-ietf-idr-bgp-prefix-sid-27#section-3:
3265 * About Prefix-SID path attribute,
3266 * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
3267 * may only appear in a BGP Prefix-SID attribute attached to
3268 * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
3269 * It MUST be ignored when received for other BGP AFI/SAFI combinations.
3271 if (!attr
->mp_nexthop_len
|| mp_update
->safi
!= SAFI_LABELED_UNICAST
)
3272 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
3274 /* Check final read pointer is same as end pointer. */
3275 if (BGP_INPUT_PNT(peer
) != endp
) {
3276 flog_warn(EC_BGP_ATTRIBUTES_MISMATCH
,
3277 "%s: BGP attribute %s, length mismatch", peer
->host
,
3278 lookup_msg(attr_str
, type
, NULL
));
3279 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3280 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3282 ret
= BGP_ATTR_PARSE_ERROR
;
3287 * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
3288 * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
3289 * This is implemented below and will result in a NOTIFICATION. If the
3290 * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
3291 * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
3292 * message SHOULD NOT be sent. This is implemented elsewhere.
3294 * RFC4760: An UPDATE message that carries no NLRI, other than the one
3295 * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
3296 * attribute. If such a message contains the NEXT_HOP attribute, the BGP
3297 * speaker that receives the message SHOULD ignore this attribute.
3299 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3300 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
))) {
3301 if (bgp_attr_nexthop_valid(peer
, attr
) < 0) {
3302 ret
= BGP_ATTR_PARSE_ERROR
;
3307 /* Check all mandatory well-known attributes are present */
3308 ret
= bgp_attr_check(peer
, attr
);
3313 * At this place we can see whether we got AS4_PATH and/or
3314 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
3315 * We can not do this before we've read all attributes because
3316 * the as4 handling does not say whether AS4_PATH has to be sent
3317 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
3318 * in relationship to AGGREGATOR.
3319 * So, to be defensive, we are not relying on any order and read
3320 * all attributes first, including these 32bit ones, and now,
3321 * afterwards, we look what and if something is to be done for as4.
3323 * It is possible to not have AS_PATH, e.g. GR EoR and sole
3326 /* actually... this doesn't ever return failure currently, but
3327 * better safe than sorry */
3328 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))
3329 && bgp_attr_munge_as4_attrs(peer
, attr
, as4_path
, as4_aggregator
,
3330 &as4_aggregator_addr
)) {
3331 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3332 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3333 ret
= BGP_ATTR_PARSE_ERROR
;
3338 * Finally do the checks on the aspath we did not do yet
3339 * because we waited for a potentially synthesized aspath.
3341 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))) {
3342 ret
= bgp_attr_aspath_check(peer
, attr
);
3343 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3347 ret
= BGP_ATTR_PARSE_PROCEED
;
3351 * At this stage, we have done all fiddling with as4, and the
3352 * resulting info is in attr->aggregator resp. attr->aspath so
3353 * we can chuck as4_aggregator and as4_path alltogether in order
3358 * unintern - it is in the hash
3359 * The flag that we got this is still there, but that
3360 * does not do any trouble
3362 aspath_unintern(&as4_path
);
3365 transit
= bgp_attr_get_transit(attr
);
3366 if (ret
!= BGP_ATTR_PARSE_ERROR
) {
3367 /* Finally intern unknown attribute. */
3369 bgp_attr_set_transit(attr
, transit_intern(transit
));
3370 if (attr
->encap_subtlvs
)
3371 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
3373 #ifdef ENABLE_BGP_VNC
3374 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3375 bgp_attr_get_vnc_subtlvs(attr
);
3378 bgp_attr_set_vnc_subtlvs(
3380 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
3384 transit_free(transit
);
3385 bgp_attr_set_transit(attr
, NULL
);
3388 bgp_attr_flush_encap(attr
);
3392 transit
= bgp_attr_get_transit(attr
);
3394 assert(transit
->refcnt
> 0);
3395 if (attr
->encap_subtlvs
)
3396 assert(attr
->encap_subtlvs
->refcnt
> 0);
3397 #ifdef ENABLE_BGP_VNC
3398 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3399 bgp_attr_get_vnc_subtlvs(attr
);
3402 assert(vnc_subtlvs
->refcnt
> 0);
3409 * Extract the tunnel type from extended community
3411 void bgp_attr_extcom_tunnel_type(struct attr
*attr
,
3412 bgp_encap_types
*tunnel_type
)
3414 struct ecommunity
*ecom
;
3420 ecom
= attr
->ecommunity
;
3421 if (!ecom
|| !ecom
->size
)
3424 for (i
= 0; i
< ecom
->size
; i
++) {
3426 uint8_t type
, sub_type
;
3428 pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
3431 if (!(type
== ECOMMUNITY_ENCODE_OPAQUE
&&
3432 sub_type
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
))
3434 *tunnel_type
= ((pnt
[6] << 8) | pnt
[7]);
3441 size_t bgp_packet_mpattr_start(struct stream
*s
, struct peer
*peer
, afi_t afi
,
3442 safi_t safi
, struct bpacket_attr_vec_arr
*vecarr
,
3447 iana_safi_t pkt_safi
;
3450 /* Set extended bit always to encode the attribute length as 2 bytes */
3451 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
3452 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
3453 sizep
= stream_get_endp(s
);
3454 stream_putw(s
, 0); /* Marker: Attribute length. */
3457 /* Convert AFI, SAFI to values for packet. */
3458 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
3460 stream_putw(s
, pkt_afi
); /* AFI */
3461 stream_putc(s
, pkt_safi
); /* SAFI */
3465 && (safi
== SAFI_UNICAST
|| safi
== SAFI_LABELED_UNICAST
3466 || safi
== SAFI_MPLS_VPN
|| safi
== SAFI_MULTICAST
))
3467 nh_afi
= peer_cap_enhe(peer
, afi
, safi
) ? AFI_IP6
: AFI_IP
;
3468 else if (safi
== SAFI_FLOWSPEC
)
3471 nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
3474 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
3479 case SAFI_MULTICAST
:
3480 case SAFI_LABELED_UNICAST
:
3482 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3486 stream_putl(s
, 0); /* RD = 0, per RFC */
3488 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3493 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3496 if (attr
->mp_nexthop_len
== 0)
3497 stream_putc(s
, 0); /* no nexthop for flowspec */
3499 stream_putc(s
, attr
->mp_nexthop_len
);
3500 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3509 case SAFI_MULTICAST
:
3510 case SAFI_LABELED_UNICAST
:
3512 if (attr
->mp_nexthop_len
3513 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3515 BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
);
3516 stream_put(s
, &attr
->mp_nexthop_global
,
3518 stream_put(s
, &attr
->mp_nexthop_local
,
3521 stream_putc(s
, IPV6_MAX_BYTELEN
);
3522 stream_put(s
, &attr
->mp_nexthop_global
,
3526 case SAFI_MPLS_VPN
: {
3527 if (attr
->mp_nexthop_len
3528 == BGP_ATTR_NHLEN_IPV6_GLOBAL
) {
3530 stream_putl(s
, 0); /* RD = 0, per RFC */
3532 stream_put(s
, &attr
->mp_nexthop_global
,
3534 } else if (attr
->mp_nexthop_len
3535 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3537 stream_putl(s
, 0); /* RD = 0, per RFC */
3539 stream_put(s
, &attr
->mp_nexthop_global
,
3541 stream_putl(s
, 0); /* RD = 0, per RFC */
3543 stream_put(s
, &attr
->mp_nexthop_local
,
3548 stream_putc(s
, IPV6_MAX_BYTELEN
);
3549 stream_put(s
, &attr
->mp_nexthop_global
,
3553 stream_putc(s
, 0); /* no nexthop for flowspec */
3559 if (safi
!= SAFI_FLOWSPEC
)
3561 EC_BGP_ATTR_NH_SEND_LEN
,
3562 "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
3563 peer
->host
, afi
, safi
, attr
->mp_nexthop_len
);
3572 void bgp_packet_mpattr_prefix(struct stream
*s
, afi_t afi
, safi_t safi
,
3573 const struct prefix
*p
,
3574 const struct prefix_rd
*prd
, mpls_label_t
*label
,
3575 uint32_t num_labels
, int addpath_encode
,
3576 uint32_t addpath_tx_id
, struct attr
*attr
)
3578 if (safi
== SAFI_MPLS_VPN
) {
3580 stream_putl(s
, addpath_tx_id
);
3581 /* Label, RD, Prefix write. */
3582 stream_putc(s
, p
->prefixlen
+ 88);
3583 stream_put(s
, label
, BGP_LABEL_BYTES
);
3584 stream_put(s
, prd
->val
, 8);
3585 stream_put(s
, &p
->u
.prefix
, PSIZE(p
->prefixlen
));
3586 } else if (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
) {
3587 /* EVPN prefix - contents depend on type */
3588 bgp_evpn_encode_prefix(s
, p
, prd
, label
, num_labels
, attr
,
3589 addpath_encode
, addpath_tx_id
);
3590 } else if (safi
== SAFI_LABELED_UNICAST
) {
3591 /* Prefix write with label. */
3592 stream_put_labeled_prefix(s
, p
, label
, addpath_encode
,
3594 } else if (safi
== SAFI_FLOWSPEC
) {
3595 stream_putc(s
, p
->u
.prefix_flowspec
.prefixlen
);
3596 stream_put(s
, (const void *)p
->u
.prefix_flowspec
.ptr
,
3597 p
->u
.prefix_flowspec
.prefixlen
);
3599 stream_put_prefix_addpath(s
, p
, addpath_encode
, addpath_tx_id
);
3602 size_t bgp_packet_mpattr_prefix_size(afi_t afi
, safi_t safi
,
3603 const struct prefix
*p
)
3605 int size
= PSIZE(p
->prefixlen
);
3606 if (safi
== SAFI_MPLS_VPN
)
3608 else if (safi
== SAFI_LABELED_UNICAST
)
3609 size
+= BGP_LABEL_BYTES
;
3610 else if (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)
3611 size
+= 232; // TODO: Maximum possible for type-2, type-3 and
3617 * Encodes the tunnel encapsulation attribute,
3618 * and with ENABLE_BGP_VNC the VNC attribute which uses
3619 * almost the same TLV format
3621 static void bgp_packet_mpattr_tea(struct bgp
*bgp
, struct peer
*peer
,
3622 struct stream
*s
, struct attr
*attr
,
3625 unsigned int attrlenfield
= 0;
3626 unsigned int attrhdrlen
= 0;
3627 struct bgp_attr_encap_subtlv
*subtlvs
;
3628 struct bgp_attr_encap_subtlv
*st
;
3629 const char *attrname
;
3631 if (!attr
|| (attrtype
== BGP_ATTR_ENCAP
3632 && (!attr
->encap_tunneltype
3633 || attr
->encap_tunneltype
== BGP_ENCAP_TYPE_MPLS
)))
3637 case BGP_ATTR_ENCAP
:
3638 attrname
= "Tunnel Encap";
3639 subtlvs
= attr
->encap_subtlvs
;
3640 if (subtlvs
== NULL
) /* nothing to do */
3643 * The tunnel encap attr has an "outer" tlv.
3645 * L = total length of subtlvs,
3646 * V = concatenated subtlvs.
3648 attrlenfield
= 2 + 2; /* T + L */
3649 attrhdrlen
= 1 + 1; /* subTLV T + L */
3652 #ifdef ENABLE_BGP_VNC_ATTR
3655 subtlvs
= bgp_attr_get_vnc_subtlvs(attr
);
3656 if (subtlvs
== NULL
) /* nothing to do */
3658 attrlenfield
= 0; /* no outer T + L */
3659 attrhdrlen
= 2 + 2; /* subTLV T + L */
3667 /* compute attr length */
3668 for (st
= subtlvs
; st
; st
= st
->next
) {
3669 attrlenfield
+= (attrhdrlen
+ st
->length
);
3672 if (attrlenfield
> 0xffff) {
3673 zlog_info("%s attribute is too long (length=%d), can't send it",
3674 attrname
, attrlenfield
);
3678 if (attrlenfield
> 0xff) {
3679 /* 2-octet length field */
3681 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
3682 | BGP_ATTR_FLAG_EXTLEN
);
3683 stream_putc(s
, attrtype
);
3684 stream_putw(s
, attrlenfield
& 0xffff);
3686 /* 1-octet length field */
3687 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
);
3688 stream_putc(s
, attrtype
);
3689 stream_putc(s
, attrlenfield
& 0xff);
3692 if (attrtype
== BGP_ATTR_ENCAP
) {
3693 /* write outer T+L */
3694 stream_putw(s
, attr
->encap_tunneltype
);
3695 stream_putw(s
, attrlenfield
- 4);
3698 /* write each sub-tlv */
3699 for (st
= subtlvs
; st
; st
= st
->next
) {
3700 if (attrtype
== BGP_ATTR_ENCAP
) {
3701 stream_putc(s
, st
->type
);
3702 stream_putc(s
, st
->length
);
3703 #ifdef ENABLE_BGP_VNC
3705 stream_putw(s
, st
->type
);
3706 stream_putw(s
, st
->length
);
3709 stream_put(s
, st
->value
, st
->length
);
3713 void bgp_packet_mpattr_end(struct stream
*s
, size_t sizep
)
3715 /* Set MP attribute length. Don't count the (2) bytes used to encode
3717 stream_putw_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 2);
3720 static bool bgp_append_local_as(struct peer
*peer
, afi_t afi
, safi_t safi
)
3722 if (!BGP_AS_IS_PRIVATE(peer
->local_as
)
3723 || (BGP_AS_IS_PRIVATE(peer
->local_as
)
3724 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3725 PEER_FLAG_REMOVE_PRIVATE_AS
)
3726 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3727 PEER_FLAG_REMOVE_PRIVATE_AS_ALL
)
3728 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3729 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE
)
3730 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3731 PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE
)))
3736 /* Make attribute packet. */
3737 bgp_size_t
bgp_packet_attribute(struct bgp
*bgp
, struct peer
*peer
,
3738 struct stream
*s
, struct attr
*attr
,
3739 struct bpacket_attr_vec_arr
*vecarr
,
3740 struct prefix
*p
, afi_t afi
, safi_t safi
,
3741 struct peer
*from
, struct prefix_rd
*prd
,
3742 mpls_label_t
*label
, uint32_t num_labels
,
3743 int addpath_encode
, uint32_t addpath_tx_id
)
3746 size_t aspath_sizep
;
3747 struct aspath
*aspath
;
3748 int send_as4_path
= 0;
3749 int send_as4_aggregator
= 0;
3750 bool use32bit
= CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
3751 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
);
3756 /* Remember current pointer. */
3757 cp
= stream_get_endp(s
);
3760 && !((afi
== AFI_IP
&& safi
== SAFI_UNICAST
)
3761 && !peer_cap_enhe(peer
, afi
, safi
))) {
3762 size_t mpattrlen_pos
= 0;
3764 mpattrlen_pos
= bgp_packet_mpattr_start(s
, peer
, afi
, safi
,
3766 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
,
3767 num_labels
, addpath_encode
,
3768 addpath_tx_id
, attr
);
3769 bgp_packet_mpattr_end(s
, mpattrlen_pos
);
3772 /* Origin attribute. */
3773 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3774 stream_putc(s
, BGP_ATTR_ORIGIN
);
3776 stream_putc(s
, attr
->origin
);
3778 /* AS path attribute. */
3780 /* If remote-peer is EBGP */
3781 if (peer
->sort
== BGP_PEER_EBGP
3782 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3783 PEER_FLAG_AS_PATH_UNCHANGED
)
3784 || attr
->aspath
->segments
== NULL
)
3785 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3786 PEER_FLAG_RSERVER_CLIENT
))) {
3787 aspath
= aspath_dup(attr
->aspath
);
3789 /* Even though we may not be configured for confederations we
3791 * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
3792 aspath
= aspath_delete_confed_seq(aspath
);
3794 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
)) {
3795 /* Stuff our path CONFED_ID on the front */
3796 aspath
= aspath_add_seq(aspath
, bgp
->confed_id
);
3798 if (peer
->change_local_as
) {
3799 /* If replace-as is specified, we only use the
3800 change_local_as when
3801 advertising routes. */
3802 if (!CHECK_FLAG(peer
->flags
,
3803 PEER_FLAG_LOCAL_AS_REPLACE_AS
))
3804 if (bgp_append_local_as(peer
, afi
,
3806 aspath
= aspath_add_seq(
3807 aspath
, peer
->local_as
);
3808 aspath
= aspath_add_seq(aspath
,
3809 peer
->change_local_as
);
3811 aspath
= aspath_add_seq(aspath
, peer
->local_as
);
3814 } else if (peer
->sort
== BGP_PEER_CONFED
) {
3815 /* A confed member, so we need to do the AS_CONFED_SEQUENCE
3817 aspath
= aspath_dup(attr
->aspath
);
3818 aspath
= aspath_add_confed_seq(aspath
, peer
->local_as
);
3820 aspath
= attr
->aspath
;
3822 /* If peer is not AS4 capable, then:
3823 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
3824 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
3826 * types are in it (i.e. exclude them if they are there)
3827 * AND do this only if there is at least one asnum > 65535 in the
3829 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
3831 * all ASnums > 65535 to BGP_AS_TRANS
3834 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
3835 stream_putc(s
, BGP_ATTR_AS_PATH
);
3836 aspath_sizep
= stream_get_endp(s
);
3838 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, use32bit
));
3840 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
3843 if (!use32bit
&& aspath_has_as4(aspath
))
3845 1; /* we'll do this later, at the correct place */
3847 /* Nexthop attribute. */
3848 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
3849 && !peer_cap_enhe(peer
, afi
, safi
)) {
3850 afi_t nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
3852 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
)) {
3853 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3854 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
3855 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
3858 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3859 } else if (peer_cap_enhe(from
, afi
, safi
)
3860 || (nh_afi
== AFI_IP6
)) {
3862 * Likely this is the case when an IPv4 prefix was
3863 * received with Extended Next-hop capability in this
3864 * or another vrf and is now being advertised to
3865 * non-ENHE peers. Since peer_cap_enhe only checks
3866 * peers in this vrf, also check the nh_afi to catch
3867 * the case where the originator was in another vrf.
3868 * Setting the mandatory (ipv4) next-hop attribute here
3869 * to enable implicit next-hop self with correct A-F
3870 * (ipv4 address family).
3872 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3873 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
3874 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
3877 stream_put_ipv4(s
, 0);
3881 /* MED attribute. */
3882 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)
3883 || bgp
->maxmed_active
) {
3884 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
3885 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
3887 stream_putl(s
, (bgp
->maxmed_active
? bgp
->maxmed_value
3891 /* Local preference. */
3892 if (peer
->sort
== BGP_PEER_IBGP
|| peer
->sort
== BGP_PEER_CONFED
) {
3893 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3894 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
3896 stream_putl(s
, attr
->local_pref
);
3899 /* Atomic aggregate. */
3900 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
3901 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3902 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
3907 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
3908 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
3909 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
3910 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
3913 /* AS4 capable peer */
3915 stream_putl(s
, attr
->aggregator_as
);
3917 /* 2-byte AS peer */
3920 /* Is ASN representable in 2-bytes? Or must AS_TRANS be
3922 if (attr
->aggregator_as
> UINT16_MAX
) {
3923 stream_putw(s
, BGP_AS_TRANS
);
3925 /* we have to send AS4_AGGREGATOR, too.
3926 * we'll do that later in order to send
3927 * attributes in ascending
3930 send_as4_aggregator
= 1;
3932 stream_putw(s
, (uint16_t)attr
->aggregator_as
);
3934 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
3937 /* Community attribute. */
3938 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
3939 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
))) {
3940 if (attr
->community
->size
* 4 > 255) {
3942 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
3943 | BGP_ATTR_FLAG_EXTLEN
);
3944 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
3945 stream_putw(s
, attr
->community
->size
* 4);
3948 BGP_ATTR_FLAG_OPTIONAL
3949 | BGP_ATTR_FLAG_TRANS
);
3950 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
3951 stream_putc(s
, attr
->community
->size
* 4);
3953 stream_put(s
, attr
->community
->val
, attr
->community
->size
* 4);
3957 * Large Community attribute.
3959 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3960 PEER_FLAG_SEND_LARGE_COMMUNITY
)
3961 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
))) {
3962 if (lcom_length(attr
->lcommunity
) > 255) {
3964 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
3965 | BGP_ATTR_FLAG_EXTLEN
);
3966 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
3967 stream_putw(s
, lcom_length(attr
->lcommunity
));
3970 BGP_ATTR_FLAG_OPTIONAL
3971 | BGP_ATTR_FLAG_TRANS
);
3972 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
3973 stream_putc(s
, lcom_length(attr
->lcommunity
));
3975 stream_put(s
, attr
->lcommunity
->val
,
3976 lcom_length(attr
->lcommunity
));
3979 /* Route Reflector. */
3980 if (peer
->sort
== BGP_PEER_IBGP
&& from
3981 && from
->sort
== BGP_PEER_IBGP
) {
3982 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
3984 /* Originator ID. */
3985 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
3986 stream_putc(s
, BGP_ATTR_ORIGINATOR_ID
);
3989 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
3990 stream_put_in_addr(s
, &attr
->originator_id
);
3992 stream_put_in_addr(s
, &from
->remote_id
);
3995 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
3996 stream_putc(s
, BGP_ATTR_CLUSTER_LIST
);
3999 stream_putc(s
, cluster
->length
+ 4);
4000 /* If this peer configuration's parent BGP has
4002 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4003 stream_put_in_addr(s
, &bgp
->cluster_id
);
4005 stream_put_in_addr(s
, &bgp
->router_id
);
4006 stream_put(s
, cluster
->list
, cluster
->length
);
4009 /* If this peer configuration's parent BGP has
4011 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4012 stream_put_in_addr(s
, &bgp
->cluster_id
);
4014 stream_put_in_addr(s
, &bgp
->router_id
);
4018 /* Extended Communities attribute. */
4019 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
4020 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
))) {
4021 if (peer
->sort
== BGP_PEER_IBGP
4022 || peer
->sort
== BGP_PEER_CONFED
) {
4023 if (attr
->ecommunity
->size
* 8 > 255) {
4025 BGP_ATTR_FLAG_OPTIONAL
4026 | BGP_ATTR_FLAG_TRANS
4027 | BGP_ATTR_FLAG_EXTLEN
);
4028 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4029 stream_putw(s
, attr
->ecommunity
->size
* 8);
4032 BGP_ATTR_FLAG_OPTIONAL
4033 | BGP_ATTR_FLAG_TRANS
);
4034 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4035 stream_putc(s
, attr
->ecommunity
->size
* 8);
4037 stream_put(s
, attr
->ecommunity
->val
,
4038 attr
->ecommunity
->size
* 8);
4042 int ecom_tr_size
= 0;
4045 for (i
= 0; i
< attr
->ecommunity
->size
; i
++) {
4046 pnt
= attr
->ecommunity
->val
+ (i
* 8);
4049 if (CHECK_FLAG(tbit
,
4050 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4057 if (ecom_tr_size
* 8 > 255) {
4060 BGP_ATTR_FLAG_OPTIONAL
4061 | BGP_ATTR_FLAG_TRANS
4062 | BGP_ATTR_FLAG_EXTLEN
);
4064 BGP_ATTR_EXT_COMMUNITIES
);
4065 stream_putw(s
, ecom_tr_size
* 8);
4069 BGP_ATTR_FLAG_OPTIONAL
4070 | BGP_ATTR_FLAG_TRANS
);
4072 BGP_ATTR_EXT_COMMUNITIES
);
4073 stream_putc(s
, ecom_tr_size
* 8);
4076 for (i
= 0; i
< attr
->ecommunity
->size
; i
++) {
4077 pnt
= attr
->ecommunity
->val
+ (i
* 8);
4082 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4085 stream_put(s
, pnt
, 8);
4091 /* Label index attribute. */
4092 if (safi
== SAFI_LABELED_UNICAST
) {
4093 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4094 uint32_t label_index
;
4096 label_index
= attr
->label_index
;
4098 if (label_index
!= BGP_INVALID_LABEL_INDEX
) {
4100 BGP_ATTR_FLAG_OPTIONAL
4101 | BGP_ATTR_FLAG_TRANS
);
4102 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4104 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4106 BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4107 stream_putc(s
, 0); // reserved
4108 stream_putw(s
, 0); // flags
4109 stream_putl(s
, label_index
);
4114 /* SRv6 Service Information Attribute. */
4115 if ((afi
== AFI_IP
|| afi
== AFI_IP6
) && safi
== SAFI_MPLS_VPN
) {
4116 if (attr
->srv6_l3vpn
) {
4117 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4118 | BGP_ATTR_FLAG_TRANS
);
4119 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4120 stream_putc(s
, 24); /* tlv len */
4121 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE
);
4122 stream_putw(s
, 21); /* sub-tlv len */
4123 stream_putc(s
, 0); /* reserved */
4124 stream_put(s
, &attr
->srv6_l3vpn
->sid
,
4125 sizeof(attr
->srv6_l3vpn
->sid
)); /* sid */
4126 stream_putc(s
, 0); /* sid_flags */
4127 stream_putw(s
, 0xffff); /* endpoint */
4128 stream_putc(s
, 0); /* reserved */
4129 } else if (attr
->srv6_vpn
) {
4130 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4131 | BGP_ATTR_FLAG_TRANS
);
4132 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4133 stream_putc(s
, 22); /* tlv len */
4134 stream_putc(s
, BGP_PREFIX_SID_VPN_SID
);
4135 stream_putw(s
, 0x13); /* tlv len */
4136 stream_putc(s
, 0x00); /* reserved */
4137 stream_putc(s
, 0x01); /* sid_type */
4138 stream_putc(s
, 0x00); /* sif_flags */
4139 stream_put(s
, &attr
->srv6_vpn
->sid
,
4140 sizeof(attr
->srv6_vpn
->sid
)); /* sid */
4144 if (send_as4_path
) {
4145 /* If the peer is NOT As4 capable, AND */
4146 /* there are ASnums > 65535 in path THEN
4147 * give out AS4_PATH */
4149 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
4151 * Hm, I wonder... confederation things *should* only be at
4152 * the beginning of an aspath, right? Then we should use
4153 * aspath_delete_confed_seq for this, because it is already
4155 * Folks, talk to me: what is reasonable here!?
4157 aspath
= aspath_delete_confed_seq(aspath
);
4160 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4161 | BGP_ATTR_FLAG_EXTLEN
);
4162 stream_putc(s
, BGP_ATTR_AS4_PATH
);
4163 aspath_sizep
= stream_get_endp(s
);
4165 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, 1));
4168 if (aspath
!= attr
->aspath
)
4169 aspath_free(aspath
);
4171 if (send_as4_aggregator
) {
4172 /* send AS4_AGGREGATOR, at this place */
4173 /* this section of code moved here in order to ensure the
4175 * *ascending* order of attributes
4177 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4178 stream_putc(s
, BGP_ATTR_AS4_AGGREGATOR
);
4180 stream_putl(s
, attr
->aggregator_as
);
4181 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4184 if (((afi
== AFI_IP
|| afi
== AFI_IP6
)
4185 && (safi
== SAFI_ENCAP
|| safi
== SAFI_MPLS_VPN
))
4186 || (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)) {
4187 /* Tunnel Encap attribute */
4188 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_ENCAP
);
4190 #ifdef ENABLE_BGP_VNC_ATTR
4192 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_VNC
);
4197 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
)) {
4198 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4199 stream_putc(s
, BGP_ATTR_PMSI_TUNNEL
);
4200 stream_putc(s
, 9); // Length
4201 stream_putc(s
, 0); // Flags
4202 stream_putc(s
, bgp_attr_get_pmsi_tnl_type(attr
));
4203 stream_put(s
, &(attr
->label
),
4204 BGP_LABEL_BYTES
); // MPLS Label / VXLAN VNI
4205 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4206 // Unicast tunnel endpoint IP address
4209 /* Unknown transit attribute. */
4210 struct transit
*transit
= bgp_attr_get_transit(attr
);
4213 stream_put(s
, transit
->val
, transit
->length
);
4215 /* Return total size of attribute. */
4216 return stream_get_endp(s
) - cp
;
4219 size_t bgp_packet_mpunreach_start(struct stream
*s
, afi_t afi
, safi_t safi
)
4221 unsigned long attrlen_pnt
;
4223 iana_safi_t pkt_safi
;
4225 /* Set extended bit always to encode the attribute length as 2 bytes */
4226 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
4227 stream_putc(s
, BGP_ATTR_MP_UNREACH_NLRI
);
4229 attrlen_pnt
= stream_get_endp(s
);
4230 stream_putw(s
, 0); /* Length of this attribute. */
4232 /* Convert AFI, SAFI to values for packet. */
4233 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
4235 stream_putw(s
, pkt_afi
);
4236 stream_putc(s
, pkt_safi
);
4241 void bgp_packet_mpunreach_prefix(struct stream
*s
, const struct prefix
*p
,
4242 afi_t afi
, safi_t safi
,
4243 const struct prefix_rd
*prd
,
4244 mpls_label_t
*label
, uint32_t num_labels
,
4245 int addpath_encode
, uint32_t addpath_tx_id
,
4248 uint8_t wlabel
[3] = {0x80, 0x00, 0x00};
4250 if (safi
== SAFI_LABELED_UNICAST
) {
4251 label
= (mpls_label_t
*)wlabel
;
4255 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
, num_labels
,
4256 addpath_encode
, addpath_tx_id
, attr
);
4259 void bgp_packet_mpunreach_end(struct stream
*s
, size_t attrlen_pnt
)
4261 bgp_packet_mpattr_end(s
, attrlen_pnt
);
4264 /* Initialization of attribute. */
4265 void bgp_attr_init(void)
4278 void bgp_attr_finish(void)
4283 ecommunity_finish();
4284 lcommunity_finish();
4291 /* Make attribute packet. */
4292 void bgp_dump_routes_attr(struct stream
*s
, struct attr
*attr
,
4293 const struct prefix
*prefix
)
4298 struct aspath
*aspath
;
4299 int addpath_encode
= 0;
4300 uint32_t addpath_tx_id
= 0;
4302 /* Remember current pointer. */
4303 cp
= stream_get_endp(s
);
4305 /* Place holder of length. */
4308 /* Origin attribute. */
4309 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4310 stream_putc(s
, BGP_ATTR_ORIGIN
);
4312 stream_putc(s
, attr
->origin
);
4314 aspath
= attr
->aspath
;
4316 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4317 stream_putc(s
, BGP_ATTR_AS_PATH
);
4318 aspath_lenp
= stream_get_endp(s
);
4321 stream_putw_at(s
, aspath_lenp
, aspath_put(s
, aspath
, 1));
4323 /* Nexthop attribute. */
4324 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
4325 if (prefix
!= NULL
&& prefix
->family
!= AF_INET6
) {
4326 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4327 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4329 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4332 /* MED attribute. */
4333 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)) {
4334 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4335 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4337 stream_putl(s
, attr
->med
);
4340 /* Local preference. */
4341 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)) {
4342 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4343 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4345 stream_putl(s
, attr
->local_pref
);
4348 /* Atomic aggregate. */
4349 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4350 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4351 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4356 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4357 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4358 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4360 stream_putl(s
, attr
->aggregator_as
);
4361 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4364 /* Community attribute. */
4365 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
)) {
4366 if (attr
->community
->size
* 4 > 255) {
4368 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4369 | BGP_ATTR_FLAG_EXTLEN
);
4370 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4371 stream_putw(s
, attr
->community
->size
* 4);
4374 BGP_ATTR_FLAG_OPTIONAL
4375 | BGP_ATTR_FLAG_TRANS
);
4376 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4377 stream_putc(s
, attr
->community
->size
* 4);
4379 stream_put(s
, attr
->community
->val
, attr
->community
->size
* 4);
4382 /* Large Community attribute. */
4383 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
)) {
4384 if (lcom_length(attr
->lcommunity
) > 255) {
4386 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4387 | BGP_ATTR_FLAG_EXTLEN
);
4388 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4389 stream_putw(s
, lcom_length(attr
->lcommunity
));
4392 BGP_ATTR_FLAG_OPTIONAL
4393 | BGP_ATTR_FLAG_TRANS
);
4394 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4395 stream_putc(s
, lcom_length(attr
->lcommunity
));
4398 stream_put(s
, attr
->lcommunity
->val
,
4399 lcom_length(attr
->lcommunity
));
4402 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
4403 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
4404 && (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL
4405 || attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)) {
4408 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4409 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
4410 sizep
= stream_get_endp(s
);
4413 stream_putc(s
, 0); /* Marker: Attribute length. */
4414 stream_putw(s
, AFI_IP6
); /* AFI */
4415 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
4418 stream_putc(s
, attr
->mp_nexthop_len
);
4419 stream_put(s
, &attr
->mp_nexthop_global
, IPV6_MAX_BYTELEN
);
4420 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)
4421 stream_put(s
, &attr
->mp_nexthop_local
,
4428 stream_put_prefix_addpath(s
, prefix
, addpath_encode
,
4431 /* Set MP attribute length. */
4432 stream_putc_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 1);
4436 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4437 if (attr
->label_index
!= BGP_INVALID_LABEL_INDEX
) {
4439 BGP_ATTR_FLAG_OPTIONAL
4440 | BGP_ATTR_FLAG_TRANS
);
4441 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4443 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4444 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4445 stream_putc(s
, 0); // reserved
4446 stream_putw(s
, 0); // flags
4447 stream_putl(s
, attr
->label_index
);
4451 /* Return total size of attribute. */
4452 len
= stream_get_endp(s
) - cp
- 2;
4453 stream_putw_at(s
, cp
, len
);