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
" med: %u local_pref: %u origin: %u weight: %u label: %u sid: %s\n",
793 attr
->flag
, attr
->med
, attr
->local_pref
, attr
->origin
,
794 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(peer
->curr
, length
,
1501 CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
));
1503 /* In case of IBGP, length will be zero. */
1504 if (!attr
->aspath
) {
1505 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1506 "Malformed AS path from %s, length is %d", peer
->host
,
1508 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1512 /* Set aspath attribute flag. */
1513 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
);
1515 return BGP_ATTR_PARSE_PROCEED
;
1518 static bgp_attr_parse_ret_t
bgp_attr_aspath_check(struct peer
*const peer
,
1519 struct attr
*const attr
)
1521 /* These checks were part of bgp_attr_aspath, but with
1522 * as4 we should to check aspath things when
1523 * aspath synthesizing with as4_path has already taken place.
1524 * Otherwise we check ASPATH and use the synthesized thing, and that is
1526 * So do the checks later, i.e. here
1528 struct aspath
*aspath
;
1530 /* Confederation sanity check. */
1531 if ((peer
->sort
== BGP_PEER_CONFED
1532 && !aspath_left_confed_check(attr
->aspath
))
1533 || (peer
->sort
== BGP_PEER_EBGP
1534 && aspath_confed_check(attr
->aspath
))) {
1535 flog_err(EC_BGP_ATTR_MAL_AS_PATH
, "Malformed AS path from %s",
1537 return BGP_ATTR_PARSE_WITHDRAW
;
1540 /* First AS check for EBGP. */
1541 if (CHECK_FLAG(peer
->flags
, PEER_FLAG_ENFORCE_FIRST_AS
)) {
1542 if (peer
->sort
== BGP_PEER_EBGP
1543 && !aspath_firstas_check(attr
->aspath
, peer
->as
)) {
1544 flog_err(EC_BGP_ATTR_FIRST_AS
,
1545 "%s incorrect first AS (must be %u)",
1546 peer
->host
, peer
->as
);
1547 return BGP_ATTR_PARSE_WITHDRAW
;
1551 /* Codification of AS 0 Processing */
1552 if (peer
->sort
== BGP_PEER_EBGP
&& aspath_check_as_zero(attr
->aspath
)) {
1554 EC_BGP_ATTR_MAL_AS_PATH
,
1555 "Malformed AS path, AS number is 0 in the path from %s",
1557 return BGP_ATTR_PARSE_WITHDRAW
;
1560 /* local-as prepend */
1561 if (peer
->change_local_as
1562 && !CHECK_FLAG(peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
)) {
1563 aspath
= aspath_dup(attr
->aspath
);
1564 aspath
= aspath_add_seq(aspath
, peer
->change_local_as
);
1565 aspath_unintern(&attr
->aspath
);
1566 attr
->aspath
= aspath_intern(aspath
);
1569 return BGP_ATTR_PARSE_PROCEED
;
1572 /* Parse AS4 path information. This function is another wrapper of
1574 static int bgp_attr_as4_path(struct bgp_attr_parser_args
*args
,
1575 struct aspath
**as4_path
)
1577 struct peer
*const peer
= args
->peer
;
1578 struct attr
*const attr
= args
->attr
;
1579 const bgp_size_t length
= args
->length
;
1581 *as4_path
= aspath_parse(peer
->curr
, length
, 1);
1583 /* In case of IBGP, length will be zero. */
1585 flog_err(EC_BGP_ATTR_MAL_AS_PATH
,
1586 "Malformed AS4 path from %s, length is %d", peer
->host
,
1588 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1592 /* Set aspath attribute flag. */
1593 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
);
1595 return BGP_ATTR_PARSE_PROCEED
;
1599 * Check that the nexthop attribute is valid.
1601 bgp_attr_parse_ret_t
1602 bgp_attr_nexthop_valid(struct peer
*peer
, struct attr
*attr
)
1604 in_addr_t nexthop_h
;
1606 nexthop_h
= ntohl(attr
->nexthop
.s_addr
);
1607 if ((IPV4_NET0(nexthop_h
) || IPV4_NET127(nexthop_h
)
1608 || IPV4_CLASS_DE(nexthop_h
))
1609 && !BGP_DEBUG(allow_martians
, ALLOW_MARTIANS
)) {
1610 uint8_t data
[7]; /* type(2) + length(1) + nhop(4) */
1611 char buf
[INET_ADDRSTRLEN
];
1613 inet_ntop(AF_INET
, &attr
->nexthop
.s_addr
, buf
,
1615 flog_err(EC_BGP_ATTR_MARTIAN_NH
, "Martian nexthop %s",
1617 data
[0] = BGP_ATTR_FLAG_TRANS
;
1618 data
[1] = BGP_ATTR_NEXT_HOP
;
1619 data
[2] = BGP_ATTR_NHLEN_IPV4
;
1620 memcpy(&data
[3], &attr
->nexthop
.s_addr
, BGP_ATTR_NHLEN_IPV4
);
1621 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
1622 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1624 return BGP_ATTR_PARSE_ERROR
;
1627 return BGP_ATTR_PARSE_PROCEED
;
1630 /* Nexthop attribute. */
1631 static bgp_attr_parse_ret_t
bgp_attr_nexthop(struct bgp_attr_parser_args
*args
)
1633 struct peer
*const peer
= args
->peer
;
1634 struct attr
*const attr
= args
->attr
;
1635 const bgp_size_t length
= args
->length
;
1637 /* Check nexthop attribute length. */
1639 flog_err(EC_BGP_ATTR_LEN
,
1640 "Nexthop attribute length isn't four [%d]", length
);
1642 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1646 attr
->nexthop
.s_addr
= stream_get_ipv4(peer
->curr
);
1647 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
);
1649 return BGP_ATTR_PARSE_PROCEED
;
1652 /* MED atrribute. */
1653 static bgp_attr_parse_ret_t
bgp_attr_med(struct bgp_attr_parser_args
*args
)
1655 struct peer
*const peer
= args
->peer
;
1656 struct attr
*const attr
= args
->attr
;
1657 const bgp_size_t length
= args
->length
;
1661 flog_err(EC_BGP_ATTR_LEN
,
1662 "MED attribute length isn't four [%d]", length
);
1664 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1668 attr
->med
= stream_getl(peer
->curr
);
1670 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
);
1672 return BGP_ATTR_PARSE_PROCEED
;
1675 /* Local preference attribute. */
1676 static bgp_attr_parse_ret_t
1677 bgp_attr_local_pref(struct bgp_attr_parser_args
*args
)
1679 struct peer
*const peer
= args
->peer
;
1680 struct attr
*const attr
= args
->attr
;
1681 const bgp_size_t length
= args
->length
;
1683 /* if received from an internal neighbor, it SHALL be considered
1684 * malformed if its length is not equal to 4. If malformed, the
1685 * UPDATE message SHALL be handled using the approach of "treat-as-
1688 if (peer
->sort
== BGP_PEER_IBGP
&& length
!= 4) {
1689 flog_err(EC_BGP_ATTR_LEN
,
1690 "LOCAL_PREF attribute length isn't 4 [%u]", length
);
1691 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1695 /* If it is contained in an UPDATE message that is received from an
1696 external peer, then this attribute MUST be ignored by the
1697 receiving speaker. */
1698 if (peer
->sort
== BGP_PEER_EBGP
) {
1699 STREAM_FORWARD_GETP(peer
->curr
, length
);
1700 return BGP_ATTR_PARSE_PROCEED
;
1703 STREAM_GETL(peer
->curr
, attr
->local_pref
);
1705 /* Set the local-pref flag. */
1706 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
);
1708 return BGP_ATTR_PARSE_PROCEED
;
1711 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1715 /* Atomic aggregate. */
1716 static int bgp_attr_atomic(struct bgp_attr_parser_args
*args
)
1718 struct attr
*const attr
= args
->attr
;
1719 const bgp_size_t length
= args
->length
;
1723 flog_err(EC_BGP_ATTR_LEN
,
1724 "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1726 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1730 /* Set atomic aggregate flag. */
1731 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
);
1733 return BGP_ATTR_PARSE_PROCEED
;
1736 /* Aggregator attribute */
1737 static int bgp_attr_aggregator(struct bgp_attr_parser_args
*args
)
1739 struct peer
*const peer
= args
->peer
;
1740 struct attr
*const attr
= args
->attr
;
1741 const bgp_size_t length
= args
->length
;
1746 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1747 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)
1748 && CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_ADV
))
1751 if (length
!= wantedlen
) {
1752 flog_err(EC_BGP_ATTR_LEN
,
1753 "AGGREGATOR attribute length isn't %u [%u]", wantedlen
,
1755 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1759 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
))
1760 aggregator_as
= stream_getl(peer
->curr
);
1762 aggregator_as
= stream_getw(peer
->curr
);
1764 attr
->aggregator_as
= aggregator_as
;
1765 attr
->aggregator_addr
.s_addr
= stream_get_ipv4(peer
->curr
);
1767 /* Codification of AS 0 Processing */
1768 if (aggregator_as
== BGP_AS_ZERO
) {
1769 flog_err(EC_BGP_ATTR_LEN
,
1770 "%s: AGGREGATOR AS number is 0 for aspath: %s",
1771 peer
->host
, aspath_print(attr
->aspath
));
1773 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1774 char attr_str
[BUFSIZ
] = {0};
1776 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1778 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1781 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
);
1784 return BGP_ATTR_PARSE_PROCEED
;
1787 /* New Aggregator attribute */
1788 static bgp_attr_parse_ret_t
1789 bgp_attr_as4_aggregator(struct bgp_attr_parser_args
*args
,
1790 as_t
*as4_aggregator_as
,
1791 struct in_addr
*as4_aggregator_addr
)
1793 struct peer
*const peer
= args
->peer
;
1794 struct attr
*const attr
= args
->attr
;
1795 const bgp_size_t length
= args
->length
;
1799 flog_err(EC_BGP_ATTR_LEN
, "New Aggregator length is not 8 [%d]",
1801 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1805 aggregator_as
= stream_getl(peer
->curr
);
1807 *as4_aggregator_as
= aggregator_as
;
1808 as4_aggregator_addr
->s_addr
= stream_get_ipv4(peer
->curr
);
1810 /* Codification of AS 0 Processing */
1811 if (aggregator_as
== BGP_AS_ZERO
) {
1812 flog_err(EC_BGP_ATTR_LEN
,
1813 "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
1814 peer
->host
, aspath_print(attr
->aspath
));
1816 if (bgp_debug_update(peer
, NULL
, NULL
, 1)) {
1817 char attr_str
[BUFSIZ
] = {0};
1819 bgp_dump_attr(attr
, attr_str
, sizeof(attr_str
));
1821 zlog_debug("%s: attributes: %s", __func__
, attr_str
);
1824 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
);
1827 return BGP_ATTR_PARSE_PROCEED
;
1830 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1832 static bgp_attr_parse_ret_t
1833 bgp_attr_munge_as4_attrs(struct peer
*const peer
, struct attr
*const attr
,
1834 struct aspath
*as4_path
, as_t as4_aggregator
,
1835 struct in_addr
*as4_aggregator_addr
)
1837 int ignore_as4_path
= 0;
1838 struct aspath
*newpath
;
1840 if (!attr
->aspath
) {
1841 /* NULL aspath shouldn't be possible as bgp_attr_parse should
1843 * checked that all well-known, mandatory attributes were
1846 * Can only be a problem with peer itself - hard error
1848 return BGP_ATTR_PARSE_ERROR
;
1851 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
1852 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1854 * It is worth a warning though, because the peer really
1855 * should not send them
1857 if (BGP_DEBUG(as4
, AS4
)) {
1858 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
1859 zlog_debug("[AS4] %s %s AS4_PATH", peer
->host
,
1860 "AS4 capable peer, yet it sent");
1863 & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
1864 zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
1866 "AS4 capable peer, yet it sent");
1869 return BGP_ATTR_PARSE_PROCEED
;
1872 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1873 * because that may override AS4_PATH
1875 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
))) {
1876 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
))) {
1878 * if the as_number in aggregator is not AS_TRANS,
1879 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1880 * and the Aggregator shall be taken as
1881 * info on the aggregating node, and the AS_PATH
1882 * shall be taken as the AS_PATH
1884 * the Aggregator shall be ignored and the
1885 * AS4_AGGREGATOR shall be taken as the
1886 * Aggregating node and the AS_PATH is to be
1887 * constructed "as in all other cases"
1889 if (attr
->aggregator_as
!= BGP_AS_TRANS
) {
1891 if (BGP_DEBUG(as4
, AS4
))
1893 "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
1895 ignore_as4_path
= 1;
1897 /* "New_aggregator shall be taken as aggregator"
1899 attr
->aggregator_as
= as4_aggregator
;
1900 attr
->aggregator_addr
.s_addr
=
1901 as4_aggregator_addr
->s_addr
;
1904 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1905 * That is bogus - but reading the conditions
1906 * we have to handle AS4_AGGREGATOR as if it were
1907 * AGGREGATOR in that case
1909 if (BGP_DEBUG(as4
, AS4
))
1911 "[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",
1913 attr
->aggregator_as
= as4_aggregator
;
1914 /* sweep it under the carpet and simulate a "good"
1916 attr
->flag
|= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
));
1920 /* need to reconcile NEW_AS_PATH and AS_PATH */
1921 if (!ignore_as4_path
1922 && (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))) {
1923 newpath
= aspath_reconcile_as4(attr
->aspath
, as4_path
);
1925 return BGP_ATTR_PARSE_ERROR
;
1927 aspath_unintern(&attr
->aspath
);
1928 attr
->aspath
= aspath_intern(newpath
);
1930 return BGP_ATTR_PARSE_PROCEED
;
1933 /* Community attribute. */
1934 static bgp_attr_parse_ret_t
1935 bgp_attr_community(struct bgp_attr_parser_args
*args
)
1937 struct peer
*const peer
= args
->peer
;
1938 struct attr
*const attr
= args
->attr
;
1939 const bgp_size_t length
= args
->length
;
1942 attr
->community
= NULL
;
1943 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1948 community_parse((uint32_t *)stream_pnt(peer
->curr
), length
);
1950 /* XXX: fix community_parse to use stream API and remove this */
1951 stream_forward_getp(peer
->curr
, length
);
1953 /* The Community attribute SHALL be considered malformed if its
1954 * length is not a non-zero multiple of 4.
1956 if (!attr
->community
)
1957 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1960 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
);
1962 return BGP_ATTR_PARSE_PROCEED
;
1965 /* Originator ID attribute. */
1966 static bgp_attr_parse_ret_t
1967 bgp_attr_originator_id(struct bgp_attr_parser_args
*args
)
1969 struct peer
*const peer
= args
->peer
;
1970 struct attr
*const attr
= args
->attr
;
1971 const bgp_size_t length
= args
->length
;
1973 /* if received from an internal neighbor, it SHALL be considered
1974 * malformed if its length is not equal to 4. If malformed, the
1975 * UPDATE message SHALL be handled using the approach of "treat-as-
1979 flog_err(EC_BGP_ATTR_LEN
, "Bad originator ID length %d",
1982 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1986 attr
->originator_id
.s_addr
= stream_get_ipv4(peer
->curr
);
1988 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
);
1990 return BGP_ATTR_PARSE_PROCEED
;
1993 /* Cluster list attribute. */
1994 static bgp_attr_parse_ret_t
1995 bgp_attr_cluster_list(struct bgp_attr_parser_args
*args
)
1997 struct peer
*const peer
= args
->peer
;
1998 struct attr
*const attr
= args
->attr
;
1999 const bgp_size_t length
= args
->length
;
2001 /* if received from an internal neighbor, it SHALL be considered
2002 * malformed if its length is not a non-zero multiple of 4. If
2003 * malformed, the UPDATE message SHALL be handled using the approach
2004 * of "treat-as-withdraw".
2006 if (length
== 0 || length
% 4) {
2007 flog_err(EC_BGP_ATTR_LEN
, "Bad cluster list length %d", length
);
2009 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2013 bgp_attr_set_cluster(
2014 attr
, cluster_parse((struct in_addr
*)stream_pnt(peer
->curr
),
2017 /* XXX: Fix cluster_parse to use stream API and then remove this */
2018 stream_forward_getp(peer
->curr
, length
);
2020 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST
);
2022 return BGP_ATTR_PARSE_PROCEED
;
2025 /* Multiprotocol reachability information parse. */
2026 int bgp_mp_reach_parse(struct bgp_attr_parser_args
*args
,
2027 struct bgp_nlri
*mp_update
)
2031 iana_safi_t pkt_safi
;
2033 bgp_size_t nlri_len
;
2036 struct peer
*const peer
= args
->peer
;
2037 struct attr
*const attr
= args
->attr
;
2038 const bgp_size_t length
= args
->length
;
2040 /* Set end of packet. */
2041 s
= BGP_INPUT(peer
);
2042 start
= stream_get_getp(s
);
2044 /* safe to read statically sized header? */
2045 #define BGP_MP_REACH_MIN_SIZE 5
2046 #define LEN_LEFT (length - (stream_get_getp(s) - start))
2047 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
)) {
2048 zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
2049 __func__
, peer
->host
, (unsigned long)length
);
2050 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2053 /* Load AFI, SAFI. */
2054 pkt_afi
= stream_getw(s
);
2055 pkt_safi
= stream_getc(s
);
2057 /* Convert AFI, SAFI to internal values, check. */
2058 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2059 /* Log if AFI or SAFI is unrecognized. This is not an error
2061 * the attribute is otherwise malformed.
2063 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2065 "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
2066 peer
->host
, iana_afi2str(pkt_afi
),
2067 iana_safi2str(pkt_safi
));
2068 return BGP_ATTR_PARSE_ERROR
;
2071 /* Get nexthop length. */
2072 attr
->mp_nexthop_len
= stream_getc(s
);
2074 if (LEN_LEFT
< attr
->mp_nexthop_len
) {
2076 "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
2077 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2078 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2081 /* Nexthop length check. */
2082 switch (attr
->mp_nexthop_len
) {
2084 if (safi
!= SAFI_FLOWSPEC
) {
2085 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2086 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2087 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2090 case BGP_ATTR_NHLEN_VPNV4
:
2091 stream_getl(s
); /* RD high */
2092 stream_getl(s
); /* RD low */
2094 * NOTE: intentional fall through
2095 * - for consistency in rx processing
2097 * The following comment is to signal GCC this intention
2098 * and suppress the warning
2101 case BGP_ATTR_NHLEN_IPV4
:
2102 stream_get(&attr
->mp_nexthop_global_in
, s
, IPV4_MAX_BYTELEN
);
2103 /* Probably needed for RFC 2283 */
2104 if (attr
->nexthop
.s_addr
== INADDR_ANY
)
2105 memcpy(&attr
->nexthop
.s_addr
,
2106 &attr
->mp_nexthop_global_in
, IPV4_MAX_BYTELEN
);
2108 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
2109 case BGP_ATTR_NHLEN_VPNV6_GLOBAL
:
2110 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL
) {
2111 stream_getl(s
); /* RD high */
2112 stream_getl(s
); /* RD low */
2114 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2115 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2116 if (!peer
->nexthop
.ifp
) {
2117 zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2119 return BGP_ATTR_PARSE_WITHDRAW
;
2121 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2124 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
2125 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
:
2126 if (attr
->mp_nexthop_len
2127 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2128 stream_getl(s
); /* RD high */
2129 stream_getl(s
); /* RD low */
2131 stream_get(&attr
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
2132 if (IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_global
)) {
2133 if (!peer
->nexthop
.ifp
) {
2134 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",
2136 return BGP_ATTR_PARSE_WITHDRAW
;
2138 attr
->nh_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2140 if (attr
->mp_nexthop_len
2141 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
2142 stream_getl(s
); /* RD high */
2143 stream_getl(s
); /* RD low */
2145 stream_get(&attr
->mp_nexthop_local
, s
, IPV6_MAX_BYTELEN
);
2146 if (!IN6_IS_ADDR_LINKLOCAL(&attr
->mp_nexthop_local
)) {
2147 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2149 "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
2150 peer
->host
, &attr
->mp_nexthop_global
,
2151 &attr
->mp_nexthop_local
);
2153 attr
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
2155 if (!peer
->nexthop
.ifp
) {
2156 zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
2158 return BGP_ATTR_PARSE_WITHDRAW
;
2160 attr
->nh_lla_ifindex
= peer
->nexthop
.ifp
->ifindex
;
2163 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2164 __func__
, peer
->host
, attr
->mp_nexthop_len
);
2165 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2169 zlog_info("%s: %s sent SNPA which couldn't be read",
2170 __func__
, peer
->host
);
2171 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2176 if ((val
= stream_getc(s
)))
2178 EC_BGP_DEFUNCT_SNPA_LEN
,
2179 "%s sent non-zero value, %u, for defunct SNPA-length field",
2183 /* must have nrli_len, what is left of the attribute */
2184 nlri_len
= LEN_LEFT
;
2185 if (nlri_len
> STREAM_READABLE(s
)) {
2186 zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
2187 __func__
, peer
->host
);
2188 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2192 zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
2193 __func__
, peer
->host
);
2195 mp_update
->afi
= afi
;
2196 mp_update
->safi
= safi
;
2197 return BGP_ATTR_PARSE_EOR
;
2200 mp_update
->afi
= afi
;
2201 mp_update
->safi
= safi
;
2202 mp_update
->nlri
= stream_pnt(s
);
2203 mp_update
->length
= nlri_len
;
2205 stream_forward_getp(s
, nlri_len
);
2207 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
);
2209 return BGP_ATTR_PARSE_PROCEED
;
2213 /* Multiprotocol unreachable parse */
2214 int bgp_mp_unreach_parse(struct bgp_attr_parser_args
*args
,
2215 struct bgp_nlri
*mp_withdraw
)
2220 iana_safi_t pkt_safi
;
2222 uint16_t withdraw_len
;
2223 struct peer
*const peer
= args
->peer
;
2224 struct attr
*const attr
= args
->attr
;
2225 const bgp_size_t length
= args
->length
;
2229 #define BGP_MP_UNREACH_MIN_SIZE 3
2230 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
2231 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
2233 pkt_afi
= stream_getw(s
);
2234 pkt_safi
= stream_getc(s
);
2236 /* Convert AFI, SAFI to internal values, check. */
2237 if (bgp_map_afi_safi_iana2int(pkt_afi
, pkt_safi
, &afi
, &safi
)) {
2238 /* Log if AFI or SAFI is unrecognized. This is not an error
2240 * the attribute is otherwise malformed.
2242 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
2244 "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
2245 peer
->host
, iana_afi2str(pkt_afi
),
2246 iana_safi2str(pkt_safi
));
2247 return BGP_ATTR_PARSE_ERROR
;
2250 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
2252 mp_withdraw
->afi
= afi
;
2253 mp_withdraw
->safi
= safi
;
2254 mp_withdraw
->nlri
= stream_pnt(s
);
2255 mp_withdraw
->length
= withdraw_len
;
2257 stream_forward_getp(s
, withdraw_len
);
2259 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
);
2261 return BGP_ATTR_PARSE_PROCEED
;
2264 /* Large Community attribute. */
2265 static bgp_attr_parse_ret_t
2266 bgp_attr_large_community(struct bgp_attr_parser_args
*args
)
2268 struct peer
*const peer
= args
->peer
;
2269 struct attr
*const attr
= args
->attr
;
2270 const bgp_size_t length
= args
->length
;
2273 * Large community follows new attribute format.
2276 attr
->lcommunity
= NULL
;
2277 /* Empty extcomm doesn't seem to be invalid per se */
2278 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2282 attr
->lcommunity
= lcommunity_parse(stream_pnt(peer
->curr
), length
);
2283 /* XXX: fix ecommunity_parse to use stream API */
2284 stream_forward_getp(peer
->curr
, length
);
2286 if (!attr
->lcommunity
)
2287 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2290 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
);
2292 return BGP_ATTR_PARSE_PROCEED
;
2295 /* Extended Community attribute. */
2296 static bgp_attr_parse_ret_t
2297 bgp_attr_ext_communities(struct bgp_attr_parser_args
*args
)
2299 struct peer
*const peer
= args
->peer
;
2300 struct attr
*const attr
= args
->attr
;
2301 const bgp_size_t length
= args
->length
;
2306 attr
->ecommunity
= NULL
;
2307 /* Empty extcomm doesn't seem to be invalid per se */
2308 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2313 ecommunity_parse(stream_pnt(peer
->curr
), length
);
2314 /* XXX: fix ecommunity_parse to use stream API */
2315 stream_forward_getp(peer
->curr
, length
);
2317 /* The Extended Community attribute SHALL be considered malformed if
2318 * its length is not a non-zero multiple of 8.
2320 if (!attr
->ecommunity
)
2321 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2324 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
2326 /* Extract DF election preference and mobility sequence number */
2327 attr
->df_pref
= bgp_attr_df_pref_from_ec(attr
, &attr
->df_alg
);
2329 /* Extract MAC mobility sequence number, if any. */
2330 attr
->mm_seqnum
= bgp_attr_mac_mobility_seqnum(attr
, &sticky
);
2331 attr
->sticky
= sticky
;
2333 /* Check if this is a Gateway MAC-IP advertisement */
2334 attr
->default_gw
= bgp_attr_default_gw(attr
);
2336 /* Handle scenario where router flag ecommunity is not
2337 * set but default gw ext community is present.
2338 * Use default gateway, set and propogate R-bit.
2340 if (attr
->default_gw
)
2341 attr
->router_flag
= 1;
2343 /* Check EVPN Neighbor advertisement flags, R-bit */
2344 bgp_attr_evpn_na_flag(attr
, &attr
->router_flag
, &proxy
);
2346 attr
->es_flags
|= ATTR_ES_PROXY_ADVERT
;
2348 /* Extract the Rmac, if any */
2349 if (bgp_attr_rmac(attr
, &attr
->rmac
)) {
2350 if (bgp_debug_update(peer
, NULL
, NULL
, 1)
2351 && bgp_mac_exist(&attr
->rmac
))
2352 zlog_debug("%s: router mac %pEA is self mac", __func__
,
2356 /* Get the tunnel type from encap extended community */
2357 bgp_attr_extcom_tunnel_type(attr
,
2358 (bgp_encap_types
*)&attr
->encap_tunneltype
);
2360 /* Extract link bandwidth, if any. */
2361 (void)ecommunity_linkbw_present(attr
->ecommunity
, &attr
->link_bw
);
2363 return BGP_ATTR_PARSE_PROCEED
;
2366 /* IPv6 Extended Community attribute. */
2367 static bgp_attr_parse_ret_t
2368 bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args
*args
)
2370 struct peer
*const peer
= args
->peer
;
2371 struct attr
*const attr
= args
->attr
;
2372 const bgp_size_t length
= args
->length
;
2373 struct ecommunity
*ipv6_ecomm
= NULL
;
2376 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2377 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2381 ipv6_ecomm
= ecommunity_parse_ipv6(stream_pnt(peer
->curr
), length
);
2382 bgp_attr_set_ipv6_ecommunity(attr
, ipv6_ecomm
);
2384 /* XXX: fix ecommunity_parse to use stream API */
2385 stream_forward_getp(peer
->curr
, length
);
2388 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2391 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES
);
2393 return BGP_ATTR_PARSE_PROCEED
;
2396 /* Parse Tunnel Encap attribute in an UPDATE */
2397 static int bgp_attr_encap(uint8_t type
, struct peer
*peer
, /* IN */
2398 bgp_size_t length
, /* IN: attr's length field */
2399 struct attr
*attr
, /* IN: caller already allocated */
2400 uint8_t flag
, /* IN: attr's flags field */
2404 uint16_t tunneltype
= 0;
2406 total
= length
+ (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
2408 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
)
2409 || !CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
2411 "Tunnel Encap attribute flag isn't optional and transitive %d",
2413 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2414 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
2419 if (BGP_ATTR_ENCAP
== type
) {
2420 /* read outer TLV type and length */
2421 uint16_t tlv_length
;
2425 "Tunnel Encap attribute not long enough to contain outer T,L");
2426 bgp_notify_send_with_data(
2427 peer
, BGP_NOTIFY_UPDATE_ERR
,
2428 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2431 tunneltype
= stream_getw(BGP_INPUT(peer
));
2432 tlv_length
= stream_getw(BGP_INPUT(peer
));
2435 if (tlv_length
!= length
) {
2436 zlog_info("%s: tlv_length(%d) != length(%d)",
2437 __func__
, tlv_length
, length
);
2441 while (length
>= 4) {
2442 uint16_t subtype
= 0;
2443 uint16_t sublength
= 0;
2444 struct bgp_attr_encap_subtlv
*tlv
;
2446 if (BGP_ATTR_ENCAP
== type
) {
2447 subtype
= stream_getc(BGP_INPUT(peer
));
2448 sublength
= stream_getc(BGP_INPUT(peer
));
2450 #ifdef ENABLE_BGP_VNC
2452 subtype
= stream_getw(BGP_INPUT(peer
));
2453 sublength
= stream_getw(BGP_INPUT(peer
));
2458 if (sublength
> length
) {
2460 "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2462 bgp_notify_send_with_data(
2463 peer
, BGP_NOTIFY_UPDATE_ERR
,
2464 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
, startp
, total
);
2468 /* alloc and copy sub-tlv */
2469 /* TBD make sure these are freed when attributes are released */
2470 tlv
= XCALLOC(MTYPE_ENCAP_TLV
,
2471 sizeof(struct bgp_attr_encap_subtlv
) + sublength
);
2472 tlv
->type
= subtype
;
2473 tlv
->length
= sublength
;
2474 stream_get(tlv
->value
, peer
->curr
, sublength
);
2475 length
-= sublength
;
2477 /* attach tlv to encap chain */
2478 if (BGP_ATTR_ENCAP
== type
) {
2479 struct bgp_attr_encap_subtlv
*stlv_last
;
2480 for (stlv_last
= attr
->encap_subtlvs
;
2481 stlv_last
&& stlv_last
->next
;
2482 stlv_last
= stlv_last
->next
)
2485 stlv_last
->next
= tlv
;
2487 attr
->encap_subtlvs
= tlv
;
2489 #ifdef ENABLE_BGP_VNC
2491 struct bgp_attr_encap_subtlv
*stlv_last
;
2492 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
2493 bgp_attr_get_vnc_subtlvs(attr
);
2495 for (stlv_last
= vnc_subtlvs
;
2496 stlv_last
&& stlv_last
->next
;
2497 stlv_last
= stlv_last
->next
)
2500 stlv_last
->next
= tlv
;
2502 bgp_attr_set_vnc_subtlvs(attr
, tlv
);
2507 if (BGP_ATTR_ENCAP
== type
) {
2508 attr
->encap_tunneltype
= tunneltype
;
2512 /* spurious leftover data */
2514 "Tunnel Encap attribute length is bad: %d leftover octets",
2516 bgp_notify_send_with_data(peer
, BGP_NOTIFY_UPDATE_ERR
,
2517 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2526 * Read an individual SID value returning how much data we have read
2527 * Returns 0 if there was an error that needs to be passed up the stack
2529 static bgp_attr_parse_ret_t
bgp_attr_psid_sub(uint8_t type
, uint16_t length
,
2530 struct bgp_attr_parser_args
*args
)
2532 struct peer
*const peer
= args
->peer
;
2533 struct attr
*const attr
= args
->attr
;
2534 uint32_t label_index
;
2535 struct in6_addr ipv6_sid
;
2537 uint32_t srgb_range
;
2539 uint8_t sid_type
, sid_flags
;
2540 uint16_t endpoint_behavior
;
2543 if (type
== BGP_PREFIX_SID_LABEL_INDEX
) {
2544 if (STREAM_READABLE(peer
->curr
) < length
2545 || length
!= BGP_PREFIX_SID_LABEL_INDEX_LENGTH
) {
2546 flog_err(EC_BGP_ATTR_LEN
,
2547 "Prefix SID label index length is %hu instead of %u",
2548 length
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
2549 return bgp_attr_malformed(args
,
2550 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2554 /* Ignore flags and reserved */
2555 stream_getc(peer
->curr
);
2556 stream_getw(peer
->curr
);
2558 /* Fetch the label index and see if it is valid. */
2559 label_index
= stream_getl(peer
->curr
);
2560 if (label_index
== BGP_INVALID_LABEL_INDEX
)
2561 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2564 /* Store label index; subsequently, we'll check on
2566 attr
->label_index
= label_index
;
2569 /* Placeholder code for the IPv6 SID type */
2570 else if (type
== BGP_PREFIX_SID_IPV6
) {
2571 if (STREAM_READABLE(peer
->curr
) < length
2572 || length
!= BGP_PREFIX_SID_IPV6_LENGTH
) {
2573 flog_err(EC_BGP_ATTR_LEN
,
2574 "Prefix SID IPv6 length is %hu instead of %u",
2575 length
, BGP_PREFIX_SID_IPV6_LENGTH
);
2576 return bgp_attr_malformed(args
,
2577 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2581 /* Ignore reserved */
2582 stream_getc(peer
->curr
);
2583 stream_getw(peer
->curr
);
2585 stream_get(&ipv6_sid
, peer
->curr
, 16);
2588 /* Placeholder code for the Originator SRGB type */
2589 else if (type
== BGP_PREFIX_SID_ORIGINATOR_SRGB
) {
2591 * ietf-idr-bgp-prefix-sid-05:
2592 * Length is the total length of the value portion of the
2593 * TLV: 2 + multiple of 6.
2595 * peer->curr stream readp should be at the beginning of the 16
2596 * bit flag field at this point in the code.
2600 * Check that the TLV length field is sane: at least 2 bytes of
2601 * flag, and at least 1 SRGB (these are 6 bytes each)
2603 if (length
< (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
)) {
2606 "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
2608 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
2609 return bgp_attr_malformed(
2610 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2615 * Check that we actually have at least as much data as
2616 * specified by the length field
2618 if (STREAM_READABLE(peer
->curr
) < length
) {
2619 flog_err(EC_BGP_ATTR_LEN
,
2620 "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain",
2621 length
, STREAM_READABLE(peer
->curr
));
2622 return bgp_attr_malformed(
2623 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2628 * Check that the portion of the TLV containing the sequence of
2629 * SRGBs corresponds to a multiple of the SRGB size; to get
2630 * that length, we skip the 16 bit flags field
2632 stream_getw(peer
->curr
);
2634 if (length
% BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
) {
2637 "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
2638 length
, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
);
2639 return bgp_attr_malformed(
2640 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2644 srgb_count
= length
/ BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH
;
2646 for (int i
= 0; i
< srgb_count
; i
++) {
2647 stream_get(&srgb_base
, peer
->curr
, 3);
2648 stream_get(&srgb_range
, peer
->curr
, 3);
2652 /* Placeholder code for the VPN-SID Service type */
2653 else if (type
== BGP_PREFIX_SID_VPN_SID
) {
2654 if (STREAM_READABLE(peer
->curr
) < length
2655 || length
!= BGP_PREFIX_SID_VPN_SID_LENGTH
) {
2656 flog_err(EC_BGP_ATTR_LEN
,
2657 "Prefix SID VPN SID length is %hu instead of %u",
2658 length
, BGP_PREFIX_SID_VPN_SID_LENGTH
);
2659 return bgp_attr_malformed(args
,
2660 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2664 /* Parse VPN-SID Sub-TLV */
2665 stream_getc(peer
->curr
); /* reserved */
2666 sid_type
= stream_getc(peer
->curr
); /* sid_type */
2667 sid_flags
= stream_getc(peer
->curr
); /* sid_flags */
2668 stream_get(&ipv6_sid
, peer
->curr
,
2669 sizeof(ipv6_sid
)); /* sid_value */
2671 /* Log VPN-SID Sub-TLV */
2672 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2673 inet_ntop(AF_INET6
, &ipv6_sid
, buf
, sizeof(buf
));
2675 "%s: vpn-sid: sid %s, sid-type 0x%02x sid-flags 0x%02x",
2676 __func__
, buf
, sid_type
, sid_flags
);
2679 /* Configure from Info */
2680 if (attr
->srv6_vpn
) {
2681 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2682 "Prefix SID SRv6 VPN field repeated");
2683 return bgp_attr_malformed(
2684 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2686 attr
->srv6_vpn
= XCALLOC(MTYPE_BGP_SRV6_VPN
,
2687 sizeof(struct bgp_attr_srv6_vpn
));
2688 attr
->srv6_vpn
->sid_flags
= sid_flags
;
2689 sid_copy(&attr
->srv6_vpn
->sid
, &ipv6_sid
);
2690 attr
->srv6_vpn
= srv6_vpn_intern(attr
->srv6_vpn
);
2693 /* Placeholder code for the SRv6 L3 Service type */
2694 else if (type
== BGP_PREFIX_SID_SRV6_L3_SERVICE
) {
2695 if (STREAM_READABLE(peer
->curr
) < length
2696 || length
!= BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH
) {
2697 flog_err(EC_BGP_ATTR_LEN
,
2698 "Prefix SID SRv6 L3-Service length is %hu instead of %u",
2699 length
, BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH
);
2700 return bgp_attr_malformed(args
,
2701 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2705 /* Parse L3-SERVICE Sub-TLV */
2706 stream_getc(peer
->curr
); /* reserved */
2707 stream_get(&ipv6_sid
, peer
->curr
,
2708 sizeof(ipv6_sid
)); /* sid_value */
2709 sid_flags
= stream_getc(peer
->curr
); /* sid_flags */
2710 endpoint_behavior
= stream_getw(peer
->curr
); /* endpoint */
2711 stream_getc(peer
->curr
); /* reserved */
2713 /* Log L3-SERVICE Sub-TLV */
2714 if (BGP_DEBUG(vpn
, VPN_LEAK_LABEL
)) {
2715 inet_ntop(AF_INET6
, &ipv6_sid
, buf
, sizeof(buf
));
2717 "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
2718 __func__
, buf
, sid_flags
, endpoint_behavior
);
2721 /* Configure from Info */
2722 if (attr
->srv6_l3vpn
) {
2723 flog_err(EC_BGP_ATTRIBUTE_REPEATED
,
2724 "Prefix SID SRv6 L3VPN field repeated");
2725 return bgp_attr_malformed(
2726 args
, BGP_NOTIFY_UPDATE_MAL_ATTR
, args
->total
);
2728 attr
->srv6_l3vpn
= XCALLOC(MTYPE_BGP_SRV6_L3VPN
,
2729 sizeof(struct bgp_attr_srv6_l3vpn
));
2730 attr
->srv6_l3vpn
->sid_flags
= sid_flags
;
2731 attr
->srv6_l3vpn
->endpoint_behavior
= endpoint_behavior
;
2732 sid_copy(&attr
->srv6_l3vpn
->sid
, &ipv6_sid
);
2733 attr
->srv6_l3vpn
= srv6_l3vpn_intern(attr
->srv6_l3vpn
);
2736 /* Placeholder code for Unsupported TLV */
2739 if (STREAM_READABLE(peer
->curr
) < length
) {
2742 "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE",
2743 length
, STREAM_READABLE(peer
->curr
));
2744 return bgp_attr_malformed(
2745 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2749 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2751 "%s attr Prefix-SID sub-type=%u is not supported, skipped",
2754 stream_forward_getp(peer
->curr
, length
);
2757 return BGP_ATTR_PARSE_PROCEED
;
2760 /* Prefix SID attribute
2761 * draft-ietf-idr-bgp-prefix-sid-05
2763 bgp_attr_parse_ret_t
bgp_attr_prefix_sid(struct bgp_attr_parser_args
*args
)
2765 struct peer
*const peer
= args
->peer
;
2766 struct attr
*const attr
= args
->attr
;
2767 bgp_attr_parse_ret_t ret
;
2769 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
);
2773 size_t headersz
= sizeof(type
) + sizeof(length
);
2774 size_t psid_parsed_length
= 0;
2776 while (STREAM_READABLE(peer
->curr
) > 0
2777 && psid_parsed_length
< args
->length
) {
2779 if (STREAM_READABLE(peer
->curr
) < headersz
) {
2782 "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2783 headersz
, STREAM_READABLE(peer
->curr
));
2784 return bgp_attr_malformed(
2785 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2789 type
= stream_getc(peer
->curr
);
2790 length
= stream_getw(peer
->curr
);
2792 if (STREAM_READABLE(peer
->curr
) < length
) {
2795 "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
2796 length
, STREAM_READABLE(peer
->curr
));
2797 return bgp_attr_malformed(args
,
2798 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2802 ret
= bgp_attr_psid_sub(type
, length
, args
);
2804 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
2807 psid_parsed_length
+= length
+ headersz
;
2809 if (psid_parsed_length
> args
->length
) {
2812 "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
2813 length
+ headersz
, psid_parsed_length
- (length
+ headersz
));
2814 return bgp_attr_malformed(
2815 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2820 return BGP_ATTR_PARSE_PROCEED
;
2823 /* PMSI tunnel attribute (RFC 6514)
2824 * Basic validation checks done here.
2826 static bgp_attr_parse_ret_t
2827 bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args
*args
)
2829 struct peer
*const peer
= args
->peer
;
2830 struct attr
*const attr
= args
->attr
;
2831 const bgp_size_t length
= args
->length
;
2833 int attr_parse_len
= 2 + BGP_LABEL_BYTES
;
2835 /* Verify that the receiver is expecting "ingress replication" as we
2836 * can only support that.
2838 if (length
< attr_parse_len
) {
2839 flog_err(EC_BGP_ATTR_LEN
, "Bad PMSI tunnel attribute length %d",
2841 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2844 stream_getc(peer
->curr
); /* Flags */
2845 tnl_type
= stream_getc(peer
->curr
);
2846 if (tnl_type
> PMSI_TNLTYPE_MAX
) {
2847 flog_err(EC_BGP_ATTR_PMSI_TYPE
,
2848 "Invalid PMSI tunnel attribute type %d", tnl_type
);
2849 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
2852 if (tnl_type
== PMSI_TNLTYPE_INGR_REPL
) {
2854 flog_err(EC_BGP_ATTR_PMSI_LEN
,
2855 "Bad PMSI tunnel attribute length %d for IR",
2857 return bgp_attr_malformed(
2858 args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
2863 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
);
2864 bgp_attr_set_pmsi_tnl_type(attr
, tnl_type
);
2865 stream_get(&attr
->label
, peer
->curr
, BGP_LABEL_BYTES
);
2867 /* Forward read pointer of input stream. */
2868 stream_forward_getp(peer
->curr
, length
- attr_parse_len
);
2870 return BGP_ATTR_PARSE_PROCEED
;
2873 /* BGP unknown attribute treatment. */
2874 static bgp_attr_parse_ret_t
bgp_attr_unknown(struct bgp_attr_parser_args
*args
)
2876 bgp_size_t total
= args
->total
;
2877 struct transit
*transit
;
2878 struct peer
*const peer
= args
->peer
;
2879 struct attr
*const attr
= args
->attr
;
2880 uint8_t *const startp
= args
->startp
;
2881 const uint8_t type
= args
->type
;
2882 const uint8_t flag
= args
->flags
;
2883 const bgp_size_t length
= args
->length
;
2885 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
2887 "%s Unknown attribute is received (type %d, length %d)",
2888 peer
->host
, type
, length
);
2890 /* Forward read pointer of input stream. */
2891 stream_forward_getp(peer
->curr
, length
);
2893 /* If any of the mandatory well-known attributes are not recognized,
2894 then the Error Subcode is set to Unrecognized Well-known
2895 Attribute. The Data field contains the unrecognized attribute
2896 (type, length and value). */
2897 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_OPTIONAL
)) {
2898 return bgp_attr_malformed(args
, BGP_NOTIFY_UPDATE_UNREC_ATTR
,
2902 /* Unrecognized non-transitive optional attributes must be quietly
2903 ignored and not passed along to other BGP peers. */
2904 if (!CHECK_FLAG(flag
, BGP_ATTR_FLAG_TRANS
))
2905 return BGP_ATTR_PARSE_PROCEED
;
2907 /* If a path with recognized transitive optional attribute is
2908 accepted and passed along to other BGP peers and the Partial bit
2909 in the Attribute Flags octet is set to 1 by some previous AS, it
2910 is not set back to 0 by the current AS. */
2911 SET_FLAG(*startp
, BGP_ATTR_FLAG_PARTIAL
);
2913 /* Store transitive attribute to the end of attr->transit. */
2914 transit
= bgp_attr_get_transit(attr
);
2916 transit
= XCALLOC(MTYPE_TRANSIT
, sizeof(struct transit
));
2918 transit
->val
= XREALLOC(MTYPE_TRANSIT_VAL
, transit
->val
,
2919 transit
->length
+ total
);
2921 memcpy(transit
->val
+ transit
->length
, startp
, total
);
2922 transit
->length
+= total
;
2923 bgp_attr_set_transit(attr
, transit
);
2925 return BGP_ATTR_PARSE_PROCEED
;
2928 /* Well-known attribute check. */
2929 static int bgp_attr_check(struct peer
*peer
, struct attr
*attr
)
2933 /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
2935 if (CHECK_FLAG(peer
->cap
, PEER_CAP_RESTART_RCV
) && !attr
->flag
)
2936 return BGP_ATTR_PARSE_PROCEED
;
2938 /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
2939 to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
2940 are present, it should. Check for any other attribute being present
2943 if ((!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)) &&
2944 CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI
))))
2945 return BGP_ATTR_PARSE_PROCEED
;
2947 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN
)))
2948 type
= BGP_ATTR_ORIGIN
;
2950 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
2951 type
= BGP_ATTR_AS_PATH
;
2953 /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
2955 * NLRI is empty. We can't easily check NLRI empty here though.
2957 if (!CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
2958 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
)))
2959 type
= BGP_ATTR_NEXT_HOP
;
2961 if (peer
->sort
== BGP_PEER_IBGP
2962 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)))
2963 type
= BGP_ATTR_LOCAL_PREF
;
2965 /* If any of the well-known mandatory attributes are not present
2966 * in an UPDATE message, then "treat-as-withdraw" MUST be used.
2969 flog_warn(EC_BGP_MISSING_ATTRIBUTE
,
2970 "%s Missing well-known attribute %s.", peer
->host
,
2971 lookup_msg(attr_str
, type
, NULL
));
2972 return BGP_ATTR_PARSE_WITHDRAW
;
2974 return BGP_ATTR_PARSE_PROCEED
;
2977 /* Read attribute of update packet. This function is called from
2978 bgp_update_receive() in bgp_packet.c. */
2979 bgp_attr_parse_ret_t
bgp_attr_parse(struct peer
*peer
, struct attr
*attr
,
2980 bgp_size_t size
, struct bgp_nlri
*mp_update
,
2981 struct bgp_nlri
*mp_withdraw
)
2983 bgp_attr_parse_ret_t ret
;
2987 uint8_t *startp
, *endp
;
2989 uint8_t seen
[BGP_ATTR_BITMAP_SIZE
];
2990 /* we need the as4_path only until we have synthesized the as_path with
2992 /* same goes for as4_aggregator */
2993 struct aspath
*as4_path
= NULL
;
2994 as_t as4_aggregator
= 0;
2995 struct in_addr as4_aggregator_addr
= {.s_addr
= 0};
2996 struct transit
*transit
;
2998 /* Initialize bitmap. */
2999 memset(seen
, 0, BGP_ATTR_BITMAP_SIZE
);
3001 /* End pointer of BGP attribute. */
3002 endp
= BGP_INPUT_PNT(peer
) + size
;
3004 /* Get attributes to the end of attribute length. */
3005 while (BGP_INPUT_PNT(peer
) < endp
) {
3006 /* Check remaining length check.*/
3007 if (endp
- BGP_INPUT_PNT(peer
) < BGP_ATTR_MIN_LEN
) {
3008 /* XXX warning: long int format, int arg (arg 5) */
3010 EC_BGP_ATTRIBUTE_TOO_SMALL
,
3011 "%s: error BGP attribute length %lu is smaller than min len",
3013 (unsigned long)(endp
3014 - stream_pnt(BGP_INPUT(peer
))));
3016 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3017 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3018 ret
= BGP_ATTR_PARSE_ERROR
;
3022 /* Fetch attribute flag and type. */
3023 startp
= BGP_INPUT_PNT(peer
);
3024 /* "The lower-order four bits of the Attribute Flags octet are
3025 unused. They MUST be zero when sent and MUST be ignored when
3027 flag
= 0xF0 & stream_getc(BGP_INPUT(peer
));
3028 type
= stream_getc(BGP_INPUT(peer
));
3030 /* Check whether Extended-Length applies and is in bounds */
3031 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
)
3032 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1))) {
3034 EC_BGP_EXT_ATTRIBUTE_TOO_SMALL
,
3035 "%s: Extended length set, but just %lu bytes of attr header",
3037 (unsigned long)(endp
3038 - stream_pnt(BGP_INPUT(peer
))));
3040 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3041 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3042 ret
= BGP_ATTR_PARSE_ERROR
;
3046 /* Check extended attribue length bit. */
3047 if (CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
))
3048 length
= stream_getw(BGP_INPUT(peer
));
3050 length
= stream_getc(BGP_INPUT(peer
));
3052 /* If any attribute appears more than once in the UPDATE
3053 message, then the Error Subcode is set to Malformed Attribute
3056 if (CHECK_BITMAP(seen
, type
)) {
3058 EC_BGP_ATTRIBUTE_REPEATED
,
3059 "%s: error BGP attribute type %d appears twice in a message",
3062 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3063 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3064 ret
= BGP_ATTR_PARSE_ERROR
;
3068 /* Set type to bitmap to check duplicate attribute. `type' is
3069 unsigned char so it never overflow bitmap range. */
3071 SET_BITMAP(seen
, type
);
3073 /* Overflow check. */
3074 attr_endp
= BGP_INPUT_PNT(peer
) + length
;
3076 if (attr_endp
> endp
) {
3078 EC_BGP_ATTRIBUTE_TOO_LARGE
,
3079 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
3080 peer
->host
, type
, length
, size
, attr_endp
,
3084 * If any recognized attribute has an Attribute
3085 * Length that conflicts with the expected length
3086 * (based on the attribute type code), then the
3087 * Error Subcode MUST be set to Attribute Length
3088 * Error. The Data field MUST contain the erroneous
3089 * attribute (type, length, and value).
3091 * We do not currently have a good way to determine the
3092 * length of the attribute independent of the length
3093 * received in the message. Instead we send the
3094 * minimum between the amount of data we have and the
3095 * amount specified by the attribute length field.
3097 * Instead of directly passing in the packet buffer and
3098 * offset we use the stream_get* functions to read into
3099 * a stack buffer, since they perform bounds checking
3100 * and we are working with untrusted data.
3102 unsigned char ndata
[peer
->max_packet_size
];
3103 memset(ndata
, 0x00, sizeof(ndata
));
3105 CHECK_FLAG(flag
, BGP_ATTR_FLAG_EXTLEN
) ? 2 : 1;
3106 /* Rewind to end of flag field */
3107 stream_rewind_getp(BGP_INPUT(peer
), (1 + lfl
));
3109 stream_get(&ndata
[0], BGP_INPUT(peer
), 1);
3111 stream_get(&ndata
[1], BGP_INPUT(peer
), lfl
);
3113 size_t atl
= attr_endp
- startp
;
3114 size_t ndl
= MIN(atl
, STREAM_READABLE(BGP_INPUT(peer
)));
3115 stream_get(&ndata
[lfl
+ 1], BGP_INPUT(peer
), ndl
);
3117 bgp_notify_send_with_data(
3118 peer
, BGP_NOTIFY_UPDATE_ERR
,
3119 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
, ndata
,
3122 ret
= BGP_ATTR_PARSE_ERROR
;
3126 struct bgp_attr_parser_args attr_args
= {
3133 .total
= attr_endp
- startp
,
3137 /* If any recognized attribute has Attribute Flags that conflict
3138 with the Attribute Type Code, then the Error Subcode is set
3140 Attribute Flags Error. The Data field contains the erroneous
3141 attribute (type, length and value). */
3142 if (bgp_attr_flag_invalid(&attr_args
)) {
3143 ret
= bgp_attr_malformed(
3144 &attr_args
, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
3146 if (ret
== BGP_ATTR_PARSE_PROCEED
)
3151 /* OK check attribute and store it's value. */
3153 case BGP_ATTR_ORIGIN
:
3154 ret
= bgp_attr_origin(&attr_args
);
3156 case BGP_ATTR_AS_PATH
:
3157 ret
= bgp_attr_aspath(&attr_args
);
3159 case BGP_ATTR_AS4_PATH
:
3160 ret
= bgp_attr_as4_path(&attr_args
, &as4_path
);
3162 case BGP_ATTR_NEXT_HOP
:
3163 ret
= bgp_attr_nexthop(&attr_args
);
3165 case BGP_ATTR_MULTI_EXIT_DISC
:
3166 ret
= bgp_attr_med(&attr_args
);
3168 case BGP_ATTR_LOCAL_PREF
:
3169 ret
= bgp_attr_local_pref(&attr_args
);
3171 case BGP_ATTR_ATOMIC_AGGREGATE
:
3172 ret
= bgp_attr_atomic(&attr_args
);
3174 case BGP_ATTR_AGGREGATOR
:
3175 ret
= bgp_attr_aggregator(&attr_args
);
3177 case BGP_ATTR_AS4_AGGREGATOR
:
3178 ret
= bgp_attr_as4_aggregator(&attr_args
,
3180 &as4_aggregator_addr
);
3182 case BGP_ATTR_COMMUNITIES
:
3183 ret
= bgp_attr_community(&attr_args
);
3185 case BGP_ATTR_LARGE_COMMUNITIES
:
3186 ret
= bgp_attr_large_community(&attr_args
);
3188 case BGP_ATTR_ORIGINATOR_ID
:
3189 ret
= bgp_attr_originator_id(&attr_args
);
3191 case BGP_ATTR_CLUSTER_LIST
:
3192 ret
= bgp_attr_cluster_list(&attr_args
);
3194 case BGP_ATTR_MP_REACH_NLRI
:
3195 ret
= bgp_mp_reach_parse(&attr_args
, mp_update
);
3197 case BGP_ATTR_MP_UNREACH_NLRI
:
3198 ret
= bgp_mp_unreach_parse(&attr_args
, mp_withdraw
);
3200 case BGP_ATTR_EXT_COMMUNITIES
:
3201 ret
= bgp_attr_ext_communities(&attr_args
);
3203 #ifdef ENABLE_BGP_VNC_ATTR
3206 case BGP_ATTR_ENCAP
:
3207 ret
= bgp_attr_encap(type
, peer
, length
, attr
, flag
,
3210 case BGP_ATTR_PREFIX_SID
:
3211 ret
= bgp_attr_prefix_sid(&attr_args
);
3213 case BGP_ATTR_PMSI_TUNNEL
:
3214 ret
= bgp_attr_pmsi_tunnel(&attr_args
);
3216 case BGP_ATTR_IPV6_EXT_COMMUNITIES
:
3217 ret
= bgp_attr_ipv6_ext_communities(&attr_args
);
3220 ret
= bgp_attr_unknown(&attr_args
);
3224 if (ret
== BGP_ATTR_PARSE_ERROR_NOTIFYPLS
) {
3225 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3226 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3227 ret
= BGP_ATTR_PARSE_ERROR
;
3231 if (ret
== BGP_ATTR_PARSE_EOR
) {
3235 if (ret
== BGP_ATTR_PARSE_ERROR
) {
3236 flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR
,
3237 "%s: Attribute %s, parse error", peer
->host
,
3238 lookup_msg(attr_str
, type
, NULL
));
3241 if (ret
== BGP_ATTR_PARSE_WITHDRAW
) {
3243 EC_BGP_ATTRIBUTE_PARSE_WITHDRAW
,
3244 "%s: Attribute %s, parse error - treating as withdrawal",
3245 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3249 /* Check the fetched length. */
3250 if (BGP_INPUT_PNT(peer
) != attr_endp
) {
3251 flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR
,
3252 "%s: BGP attribute %s, fetch error",
3253 peer
->host
, lookup_msg(attr_str
, type
, NULL
));
3254 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3255 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3256 ret
= BGP_ATTR_PARSE_ERROR
;
3262 * draft-ietf-idr-bgp-prefix-sid-27#section-3:
3263 * About Prefix-SID path attribute,
3264 * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
3265 * may only appear in a BGP Prefix-SID attribute attached to
3266 * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
3267 * It MUST be ignored when received for other BGP AFI/SAFI combinations.
3269 if (!attr
->mp_nexthop_len
|| mp_update
->safi
!= SAFI_LABELED_UNICAST
)
3270 attr
->label_index
= BGP_INVALID_LABEL_INDEX
;
3272 /* Check final read pointer is same as end pointer. */
3273 if (BGP_INPUT_PNT(peer
) != endp
) {
3274 flog_warn(EC_BGP_ATTRIBUTES_MISMATCH
,
3275 "%s: BGP attribute %s, length mismatch", peer
->host
,
3276 lookup_msg(attr_str
, type
, NULL
));
3277 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3278 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
3280 ret
= BGP_ATTR_PARSE_ERROR
;
3285 * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
3286 * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
3287 * This is implemented below and will result in a NOTIFICATION. If the
3288 * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
3289 * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
3290 * message SHOULD NOT be sent. This is implemented elsewhere.
3292 * RFC4760: An UPDATE message that carries no NLRI, other than the one
3293 * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
3294 * attribute. If such a message contains the NEXT_HOP attribute, the BGP
3295 * speaker that receives the message SHOULD ignore this attribute.
3297 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
))
3298 && !CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI
))) {
3299 if (bgp_attr_nexthop_valid(peer
, attr
) < 0) {
3300 ret
= BGP_ATTR_PARSE_ERROR
;
3305 /* Check all mandatory well-known attributes are present */
3306 ret
= bgp_attr_check(peer
, attr
);
3311 * At this place we can see whether we got AS4_PATH and/or
3312 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
3313 * We can not do this before we've read all attributes because
3314 * the as4 handling does not say whether AS4_PATH has to be sent
3315 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
3316 * in relationship to AGGREGATOR.
3317 * So, to be defensive, we are not relying on any order and read
3318 * all attributes first, including these 32bit ones, and now,
3319 * afterwards, we look what and if something is to be done for as4.
3321 * It is possible to not have AS_PATH, e.g. GR EoR and sole
3324 /* actually... this doesn't ever return failure currently, but
3325 * better safe than sorry */
3326 if (CHECK_FLAG(attr
->flag
, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))
3327 && bgp_attr_munge_as4_attrs(peer
, attr
, as4_path
, as4_aggregator
,
3328 &as4_aggregator_addr
)) {
3329 bgp_notify_send(peer
, BGP_NOTIFY_UPDATE_ERR
,
3330 BGP_NOTIFY_UPDATE_MAL_ATTR
);
3331 ret
= BGP_ATTR_PARSE_ERROR
;
3336 * Finally do the checks on the aspath we did not do yet
3337 * because we waited for a potentially synthesized aspath.
3339 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
))) {
3340 ret
= bgp_attr_aspath_check(peer
, attr
);
3341 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
3345 ret
= BGP_ATTR_PARSE_PROCEED
;
3349 * At this stage, we have done all fiddling with as4, and the
3350 * resulting info is in attr->aggregator resp. attr->aspath so
3351 * we can chuck as4_aggregator and as4_path alltogether in order
3356 * unintern - it is in the hash
3357 * The flag that we got this is still there, but that
3358 * does not do any trouble
3360 aspath_unintern(&as4_path
);
3363 transit
= bgp_attr_get_transit(attr
);
3364 if (ret
!= BGP_ATTR_PARSE_ERROR
) {
3365 /* Finally intern unknown attribute. */
3367 bgp_attr_set_transit(attr
, transit_intern(transit
));
3368 if (attr
->encap_subtlvs
)
3369 attr
->encap_subtlvs
= encap_intern(attr
->encap_subtlvs
,
3371 #ifdef ENABLE_BGP_VNC
3372 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3373 bgp_attr_get_vnc_subtlvs(attr
);
3376 bgp_attr_set_vnc_subtlvs(
3378 encap_intern(vnc_subtlvs
, VNC_SUBTLV_TYPE
));
3382 transit_free(transit
);
3383 bgp_attr_set_transit(attr
, NULL
);
3386 bgp_attr_flush_encap(attr
);
3390 transit
= bgp_attr_get_transit(attr
);
3392 assert(transit
->refcnt
> 0);
3393 if (attr
->encap_subtlvs
)
3394 assert(attr
->encap_subtlvs
->refcnt
> 0);
3395 #ifdef ENABLE_BGP_VNC
3396 struct bgp_attr_encap_subtlv
*vnc_subtlvs
=
3397 bgp_attr_get_vnc_subtlvs(attr
);
3400 assert(vnc_subtlvs
->refcnt
> 0);
3407 * Extract the tunnel type from extended community
3409 void bgp_attr_extcom_tunnel_type(struct attr
*attr
,
3410 bgp_encap_types
*tunnel_type
)
3412 struct ecommunity
*ecom
;
3418 ecom
= attr
->ecommunity
;
3419 if (!ecom
|| !ecom
->size
)
3422 for (i
= 0; i
< ecom
->size
; i
++) {
3424 uint8_t type
, sub_type
;
3426 pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
3429 if (!(type
== ECOMMUNITY_ENCODE_OPAQUE
&&
3430 sub_type
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
))
3432 *tunnel_type
= ((pnt
[6] << 8) | pnt
[7]);
3439 size_t bgp_packet_mpattr_start(struct stream
*s
, struct peer
*peer
, afi_t afi
,
3440 safi_t safi
, struct bpacket_attr_vec_arr
*vecarr
,
3445 iana_safi_t pkt_safi
;
3448 /* Set extended bit always to encode the attribute length as 2 bytes */
3449 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
3450 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
3451 sizep
= stream_get_endp(s
);
3452 stream_putw(s
, 0); /* Marker: Attribute length. */
3455 /* Convert AFI, SAFI to values for packet. */
3456 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
3458 stream_putw(s
, pkt_afi
); /* AFI */
3459 stream_putc(s
, pkt_safi
); /* SAFI */
3463 && (safi
== SAFI_UNICAST
|| safi
== SAFI_LABELED_UNICAST
3464 || safi
== SAFI_MPLS_VPN
|| safi
== SAFI_MULTICAST
))
3465 nh_afi
= peer_cap_enhe(peer
, afi
, safi
) ? AFI_IP6
: AFI_IP
;
3466 else if (safi
== SAFI_FLOWSPEC
)
3469 nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
3472 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
3477 case SAFI_MULTICAST
:
3478 case SAFI_LABELED_UNICAST
:
3480 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3484 stream_putl(s
, 0); /* RD = 0, per RFC */
3486 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3491 stream_put(s
, &attr
->mp_nexthop_global_in
, 4);
3494 if (attr
->mp_nexthop_len
== 0)
3495 stream_putc(s
, 0); /* no nexthop for flowspec */
3497 stream_putc(s
, attr
->mp_nexthop_len
);
3498 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3507 case SAFI_MULTICAST
:
3508 case SAFI_LABELED_UNICAST
:
3510 if (attr
->mp_nexthop_len
3511 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3513 BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
);
3514 stream_put(s
, &attr
->mp_nexthop_global
,
3516 stream_put(s
, &attr
->mp_nexthop_local
,
3519 stream_putc(s
, IPV6_MAX_BYTELEN
);
3520 stream_put(s
, &attr
->mp_nexthop_global
,
3524 case SAFI_MPLS_VPN
: {
3525 if (attr
->mp_nexthop_len
3526 == BGP_ATTR_NHLEN_IPV6_GLOBAL
) {
3528 stream_putl(s
, 0); /* RD = 0, per RFC */
3530 stream_put(s
, &attr
->mp_nexthop_global
,
3532 } else if (attr
->mp_nexthop_len
3533 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) {
3535 stream_putl(s
, 0); /* RD = 0, per RFC */
3537 stream_put(s
, &attr
->mp_nexthop_global
,
3539 stream_putl(s
, 0); /* RD = 0, per RFC */
3541 stream_put(s
, &attr
->mp_nexthop_local
,
3546 stream_putc(s
, IPV6_MAX_BYTELEN
);
3547 stream_put(s
, &attr
->mp_nexthop_global
,
3551 stream_putc(s
, 0); /* no nexthop for flowspec */
3557 if (safi
!= SAFI_FLOWSPEC
)
3559 EC_BGP_ATTR_NH_SEND_LEN
,
3560 "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
3561 peer
->host
, afi
, safi
, attr
->mp_nexthop_len
);
3570 void bgp_packet_mpattr_prefix(struct stream
*s
, afi_t afi
, safi_t safi
,
3571 const struct prefix
*p
,
3572 const struct prefix_rd
*prd
, mpls_label_t
*label
,
3573 uint32_t num_labels
, int addpath_encode
,
3574 uint32_t addpath_tx_id
, struct attr
*attr
)
3576 if (safi
== SAFI_MPLS_VPN
) {
3578 stream_putl(s
, addpath_tx_id
);
3579 /* Label, RD, Prefix write. */
3580 stream_putc(s
, p
->prefixlen
+ 88);
3581 stream_put(s
, label
, BGP_LABEL_BYTES
);
3582 stream_put(s
, prd
->val
, 8);
3583 stream_put(s
, &p
->u
.prefix
, PSIZE(p
->prefixlen
));
3584 } else if (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
) {
3585 /* EVPN prefix - contents depend on type */
3586 bgp_evpn_encode_prefix(s
, p
, prd
, label
, num_labels
, attr
,
3587 addpath_encode
, addpath_tx_id
);
3588 } else if (safi
== SAFI_LABELED_UNICAST
) {
3589 /* Prefix write with label. */
3590 stream_put_labeled_prefix(s
, p
, label
, addpath_encode
,
3592 } else if (safi
== SAFI_FLOWSPEC
) {
3593 stream_putc(s
, p
->u
.prefix_flowspec
.prefixlen
);
3594 stream_put(s
, (const void *)p
->u
.prefix_flowspec
.ptr
,
3595 p
->u
.prefix_flowspec
.prefixlen
);
3597 stream_put_prefix_addpath(s
, p
, addpath_encode
, addpath_tx_id
);
3600 size_t bgp_packet_mpattr_prefix_size(afi_t afi
, safi_t safi
,
3601 const struct prefix
*p
)
3603 int size
= PSIZE(p
->prefixlen
);
3604 if (safi
== SAFI_MPLS_VPN
)
3606 else if (safi
== SAFI_LABELED_UNICAST
)
3607 size
+= BGP_LABEL_BYTES
;
3608 else if (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)
3609 size
+= 232; // TODO: Maximum possible for type-2, type-3 and
3615 * Encodes the tunnel encapsulation attribute,
3616 * and with ENABLE_BGP_VNC the VNC attribute which uses
3617 * almost the same TLV format
3619 static void bgp_packet_mpattr_tea(struct bgp
*bgp
, struct peer
*peer
,
3620 struct stream
*s
, struct attr
*attr
,
3623 unsigned int attrlenfield
= 0;
3624 unsigned int attrhdrlen
= 0;
3625 struct bgp_attr_encap_subtlv
*subtlvs
;
3626 struct bgp_attr_encap_subtlv
*st
;
3627 const char *attrname
;
3629 if (!attr
|| (attrtype
== BGP_ATTR_ENCAP
3630 && (!attr
->encap_tunneltype
3631 || attr
->encap_tunneltype
== BGP_ENCAP_TYPE_MPLS
)))
3635 case BGP_ATTR_ENCAP
:
3636 attrname
= "Tunnel Encap";
3637 subtlvs
= attr
->encap_subtlvs
;
3638 if (subtlvs
== NULL
) /* nothing to do */
3641 * The tunnel encap attr has an "outer" tlv.
3643 * L = total length of subtlvs,
3644 * V = concatenated subtlvs.
3646 attrlenfield
= 2 + 2; /* T + L */
3647 attrhdrlen
= 1 + 1; /* subTLV T + L */
3650 #ifdef ENABLE_BGP_VNC_ATTR
3653 subtlvs
= bgp_attr_get_vnc_subtlvs(attr
);
3654 if (subtlvs
== NULL
) /* nothing to do */
3656 attrlenfield
= 0; /* no outer T + L */
3657 attrhdrlen
= 2 + 2; /* subTLV T + L */
3665 /* compute attr length */
3666 for (st
= subtlvs
; st
; st
= st
->next
) {
3667 attrlenfield
+= (attrhdrlen
+ st
->length
);
3670 if (attrlenfield
> 0xffff) {
3671 zlog_info("%s attribute is too long (length=%d), can't send it",
3672 attrname
, attrlenfield
);
3676 if (attrlenfield
> 0xff) {
3677 /* 2-octet length field */
3679 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
3680 | BGP_ATTR_FLAG_EXTLEN
);
3681 stream_putc(s
, attrtype
);
3682 stream_putw(s
, attrlenfield
& 0xffff);
3684 /* 1-octet length field */
3685 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
);
3686 stream_putc(s
, attrtype
);
3687 stream_putc(s
, attrlenfield
& 0xff);
3690 if (attrtype
== BGP_ATTR_ENCAP
) {
3691 /* write outer T+L */
3692 stream_putw(s
, attr
->encap_tunneltype
);
3693 stream_putw(s
, attrlenfield
- 4);
3696 /* write each sub-tlv */
3697 for (st
= subtlvs
; st
; st
= st
->next
) {
3698 if (attrtype
== BGP_ATTR_ENCAP
) {
3699 stream_putc(s
, st
->type
);
3700 stream_putc(s
, st
->length
);
3701 #ifdef ENABLE_BGP_VNC
3703 stream_putw(s
, st
->type
);
3704 stream_putw(s
, st
->length
);
3707 stream_put(s
, st
->value
, st
->length
);
3711 void bgp_packet_mpattr_end(struct stream
*s
, size_t sizep
)
3713 /* Set MP attribute length. Don't count the (2) bytes used to encode
3715 stream_putw_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 2);
3718 static bool bgp_append_local_as(struct peer
*peer
, afi_t afi
, safi_t safi
)
3720 if (!BGP_AS_IS_PRIVATE(peer
->local_as
)
3721 || (BGP_AS_IS_PRIVATE(peer
->local_as
)
3722 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3723 PEER_FLAG_REMOVE_PRIVATE_AS
)
3724 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3725 PEER_FLAG_REMOVE_PRIVATE_AS_ALL
)
3726 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3727 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE
)
3728 && !CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3729 PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE
)))
3734 /* Make attribute packet. */
3735 bgp_size_t
bgp_packet_attribute(struct bgp
*bgp
, struct peer
*peer
,
3736 struct stream
*s
, struct attr
*attr
,
3737 struct bpacket_attr_vec_arr
*vecarr
,
3738 struct prefix
*p
, afi_t afi
, safi_t safi
,
3739 struct peer
*from
, struct prefix_rd
*prd
,
3740 mpls_label_t
*label
, uint32_t num_labels
,
3741 int addpath_encode
, uint32_t addpath_tx_id
)
3744 size_t aspath_sizep
;
3745 struct aspath
*aspath
;
3746 int send_as4_path
= 0;
3747 int send_as4_aggregator
= 0;
3748 bool use32bit
= CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
);
3753 /* Remember current pointer. */
3754 cp
= stream_get_endp(s
);
3757 && !((afi
== AFI_IP
&& safi
== SAFI_UNICAST
)
3758 && !peer_cap_enhe(peer
, afi
, safi
))) {
3759 size_t mpattrlen_pos
= 0;
3761 mpattrlen_pos
= bgp_packet_mpattr_start(s
, peer
, afi
, safi
,
3763 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
,
3764 num_labels
, addpath_encode
,
3765 addpath_tx_id
, attr
);
3766 bgp_packet_mpattr_end(s
, mpattrlen_pos
);
3769 /* Origin attribute. */
3770 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3771 stream_putc(s
, BGP_ATTR_ORIGIN
);
3773 stream_putc(s
, attr
->origin
);
3775 /* AS path attribute. */
3777 /* If remote-peer is EBGP */
3778 if (peer
->sort
== BGP_PEER_EBGP
3779 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3780 PEER_FLAG_AS_PATH_UNCHANGED
)
3781 || attr
->aspath
->segments
== NULL
)
3782 && (!CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3783 PEER_FLAG_RSERVER_CLIENT
))) {
3784 aspath
= aspath_dup(attr
->aspath
);
3786 /* Even though we may not be configured for confederations we
3788 * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
3789 aspath
= aspath_delete_confed_seq(aspath
);
3791 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
)) {
3792 /* Stuff our path CONFED_ID on the front */
3793 aspath
= aspath_add_seq(aspath
, bgp
->confed_id
);
3795 if (peer
->change_local_as
) {
3796 /* If replace-as is specified, we only use the
3797 change_local_as when
3798 advertising routes. */
3799 if (!CHECK_FLAG(peer
->flags
,
3800 PEER_FLAG_LOCAL_AS_REPLACE_AS
))
3801 if (bgp_append_local_as(peer
, afi
,
3803 aspath
= aspath_add_seq(
3804 aspath
, peer
->local_as
);
3805 aspath
= aspath_add_seq(aspath
,
3806 peer
->change_local_as
);
3808 aspath
= aspath_add_seq(aspath
, peer
->local_as
);
3811 } else if (peer
->sort
== BGP_PEER_CONFED
) {
3812 /* A confed member, so we need to do the AS_CONFED_SEQUENCE
3814 aspath
= aspath_dup(attr
->aspath
);
3815 aspath
= aspath_add_confed_seq(aspath
, peer
->local_as
);
3817 aspath
= attr
->aspath
;
3819 /* If peer is not AS4 capable, then:
3820 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
3821 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
3823 * types are in it (i.e. exclude them if they are there)
3824 * AND do this only if there is at least one asnum > 65535 in the
3826 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
3828 * all ASnums > 65535 to BGP_AS_TRANS
3831 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
3832 stream_putc(s
, BGP_ATTR_AS_PATH
);
3833 aspath_sizep
= stream_get_endp(s
);
3835 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, use32bit
));
3837 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
3840 if (!use32bit
&& aspath_has_as4(aspath
))
3842 1; /* we'll do this later, at the correct place */
3844 /* Nexthop attribute. */
3845 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
3846 && !peer_cap_enhe(peer
, afi
, safi
)) {
3847 afi_t nh_afi
= BGP_NEXTHOP_AFI_FROM_NHLEN(attr
->mp_nexthop_len
);
3849 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP
)) {
3850 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3851 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
3852 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
3855 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
3856 } else if (peer_cap_enhe(from
, afi
, safi
)
3857 || (nh_afi
== AFI_IP6
)) {
3859 * Likely this is the case when an IPv4 prefix was
3860 * received with Extended Next-hop capability in this
3861 * or another vrf and is now being advertised to
3862 * non-ENHE peers. Since peer_cap_enhe only checks
3863 * peers in this vrf, also check the nh_afi to catch
3864 * the case where the originator was in another vrf.
3865 * Setting the mandatory (ipv4) next-hop attribute here
3866 * to enable implicit next-hop self with correct A-F
3867 * (ipv4 address family).
3869 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3870 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
3871 bpacket_attr_vec_arr_set_vec(vecarr
, BGP_ATTR_VEC_NH
, s
,
3874 stream_put_ipv4(s
, 0);
3878 /* MED attribute. */
3879 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)
3880 || bgp
->maxmed_active
) {
3881 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
3882 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
3884 stream_putl(s
, (bgp
->maxmed_active
? bgp
->maxmed_value
3888 /* Local preference. */
3889 if (peer
->sort
== BGP_PEER_IBGP
|| peer
->sort
== BGP_PEER_CONFED
) {
3890 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3891 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
3893 stream_putl(s
, attr
->local_pref
);
3896 /* Atomic aggregate. */
3897 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
3898 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
3899 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
3904 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
3905 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
3906 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
3907 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
3910 /* AS4 capable peer */
3912 stream_putl(s
, attr
->aggregator_as
);
3914 /* 2-byte AS peer */
3917 /* Is ASN representable in 2-bytes? Or must AS_TRANS be
3919 if (attr
->aggregator_as
> UINT16_MAX
) {
3920 stream_putw(s
, BGP_AS_TRANS
);
3922 /* we have to send AS4_AGGREGATOR, too.
3923 * we'll do that later in order to send
3924 * attributes in ascending
3927 send_as4_aggregator
= 1;
3929 stream_putw(s
, (uint16_t)attr
->aggregator_as
);
3931 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
3934 /* Community attribute. */
3935 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
3936 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
))) {
3937 if (attr
->community
->size
* 4 > 255) {
3939 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
3940 | BGP_ATTR_FLAG_EXTLEN
);
3941 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
3942 stream_putw(s
, attr
->community
->size
* 4);
3945 BGP_ATTR_FLAG_OPTIONAL
3946 | BGP_ATTR_FLAG_TRANS
);
3947 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
3948 stream_putc(s
, attr
->community
->size
* 4);
3950 stream_put(s
, attr
->community
->val
, attr
->community
->size
* 4);
3954 * Large Community attribute.
3956 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
3957 PEER_FLAG_SEND_LARGE_COMMUNITY
)
3958 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
))) {
3959 if (lcom_length(attr
->lcommunity
) > 255) {
3961 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
3962 | BGP_ATTR_FLAG_EXTLEN
);
3963 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
3964 stream_putw(s
, lcom_length(attr
->lcommunity
));
3967 BGP_ATTR_FLAG_OPTIONAL
3968 | BGP_ATTR_FLAG_TRANS
);
3969 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
3970 stream_putc(s
, lcom_length(attr
->lcommunity
));
3972 stream_put(s
, attr
->lcommunity
->val
,
3973 lcom_length(attr
->lcommunity
));
3976 /* Route Reflector. */
3977 if (peer
->sort
== BGP_PEER_IBGP
&& from
3978 && from
->sort
== BGP_PEER_IBGP
) {
3979 struct cluster_list
*cluster
= bgp_attr_get_cluster(attr
);
3981 /* Originator ID. */
3982 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
3983 stream_putc(s
, BGP_ATTR_ORIGINATOR_ID
);
3986 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
3987 stream_put_in_addr(s
, &attr
->originator_id
);
3989 stream_put_in_addr(s
, &from
->remote_id
);
3992 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
3993 stream_putc(s
, BGP_ATTR_CLUSTER_LIST
);
3996 stream_putc(s
, cluster
->length
+ 4);
3997 /* If this peer configuration's parent BGP has
3999 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4000 stream_put_in_addr(s
, &bgp
->cluster_id
);
4002 stream_put_in_addr(s
, &bgp
->router_id
);
4003 stream_put(s
, cluster
->list
, cluster
->length
);
4006 /* If this peer configuration's parent BGP has
4008 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
4009 stream_put_in_addr(s
, &bgp
->cluster_id
);
4011 stream_put_in_addr(s
, &bgp
->router_id
);
4015 /* Extended Communities attribute. */
4016 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
4017 && (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
))) {
4018 if (peer
->sort
== BGP_PEER_IBGP
4019 || peer
->sort
== BGP_PEER_CONFED
) {
4020 if (attr
->ecommunity
->size
* 8 > 255) {
4022 BGP_ATTR_FLAG_OPTIONAL
4023 | BGP_ATTR_FLAG_TRANS
4024 | BGP_ATTR_FLAG_EXTLEN
);
4025 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4026 stream_putw(s
, attr
->ecommunity
->size
* 8);
4029 BGP_ATTR_FLAG_OPTIONAL
4030 | BGP_ATTR_FLAG_TRANS
);
4031 stream_putc(s
, BGP_ATTR_EXT_COMMUNITIES
);
4032 stream_putc(s
, attr
->ecommunity
->size
* 8);
4034 stream_put(s
, attr
->ecommunity
->val
,
4035 attr
->ecommunity
->size
* 8);
4039 int ecom_tr_size
= 0;
4042 for (i
= 0; i
< attr
->ecommunity
->size
; i
++) {
4043 pnt
= attr
->ecommunity
->val
+ (i
* 8);
4046 if (CHECK_FLAG(tbit
,
4047 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4054 if (ecom_tr_size
* 8 > 255) {
4057 BGP_ATTR_FLAG_OPTIONAL
4058 | BGP_ATTR_FLAG_TRANS
4059 | BGP_ATTR_FLAG_EXTLEN
);
4061 BGP_ATTR_EXT_COMMUNITIES
);
4062 stream_putw(s
, ecom_tr_size
* 8);
4066 BGP_ATTR_FLAG_OPTIONAL
4067 | BGP_ATTR_FLAG_TRANS
);
4069 BGP_ATTR_EXT_COMMUNITIES
);
4070 stream_putc(s
, ecom_tr_size
* 8);
4073 for (i
= 0; i
< attr
->ecommunity
->size
; i
++) {
4074 pnt
= attr
->ecommunity
->val
+ (i
* 8);
4079 ECOMMUNITY_FLAG_NON_TRANSITIVE
))
4082 stream_put(s
, pnt
, 8);
4088 /* Label index attribute. */
4089 if (safi
== SAFI_LABELED_UNICAST
) {
4090 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4091 uint32_t label_index
;
4093 label_index
= attr
->label_index
;
4095 if (label_index
!= BGP_INVALID_LABEL_INDEX
) {
4097 BGP_ATTR_FLAG_OPTIONAL
4098 | BGP_ATTR_FLAG_TRANS
);
4099 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4101 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4103 BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4104 stream_putc(s
, 0); // reserved
4105 stream_putw(s
, 0); // flags
4106 stream_putl(s
, label_index
);
4111 /* SRv6 Service Information Attribute. */
4112 if ((afi
== AFI_IP
|| afi
== AFI_IP6
) && safi
== SAFI_MPLS_VPN
) {
4113 if (attr
->srv6_l3vpn
) {
4114 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4115 | BGP_ATTR_FLAG_TRANS
);
4116 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4117 stream_putc(s
, 24); /* tlv len */
4118 stream_putc(s
, BGP_PREFIX_SID_SRV6_L3_SERVICE
);
4119 stream_putw(s
, 21); /* sub-tlv len */
4120 stream_putc(s
, 0); /* reserved */
4121 stream_put(s
, &attr
->srv6_l3vpn
->sid
,
4122 sizeof(attr
->srv6_l3vpn
->sid
)); /* sid */
4123 stream_putc(s
, 0); /* sid_flags */
4124 stream_putw(s
, 0xffff); /* endpoint */
4125 stream_putc(s
, 0); /* reserved */
4126 } else if (attr
->srv6_vpn
) {
4127 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
4128 | BGP_ATTR_FLAG_TRANS
);
4129 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4130 stream_putc(s
, 22); /* tlv len */
4131 stream_putc(s
, BGP_PREFIX_SID_VPN_SID
);
4132 stream_putw(s
, 0x13); /* tlv len */
4133 stream_putc(s
, 0x00); /* reserved */
4134 stream_putc(s
, 0x01); /* sid_type */
4135 stream_putc(s
, 0x00); /* sif_flags */
4136 stream_put(s
, &attr
->srv6_vpn
->sid
,
4137 sizeof(attr
->srv6_vpn
->sid
)); /* sid */
4141 if (send_as4_path
) {
4142 /* If the peer is NOT As4 capable, AND */
4143 /* there are ASnums > 65535 in path THEN
4144 * give out AS4_PATH */
4146 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
4148 * Hm, I wonder... confederation things *should* only be at
4149 * the beginning of an aspath, right? Then we should use
4150 * aspath_delete_confed_seq for this, because it is already
4152 * Folks, talk to me: what is reasonable here!?
4154 aspath
= aspath_delete_confed_seq(aspath
);
4157 BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
4158 | BGP_ATTR_FLAG_EXTLEN
);
4159 stream_putc(s
, BGP_ATTR_AS4_PATH
);
4160 aspath_sizep
= stream_get_endp(s
);
4162 stream_putw_at(s
, aspath_sizep
, aspath_put(s
, aspath
, 1));
4165 if (aspath
!= attr
->aspath
)
4166 aspath_free(aspath
);
4168 if (send_as4_aggregator
) {
4169 /* send AS4_AGGREGATOR, at this place */
4170 /* this section of code moved here in order to ensure the
4172 * *ascending* order of attributes
4174 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4175 stream_putc(s
, BGP_ATTR_AS4_AGGREGATOR
);
4177 stream_putl(s
, attr
->aggregator_as
);
4178 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4181 if (((afi
== AFI_IP
|| afi
== AFI_IP6
)
4182 && (safi
== SAFI_ENCAP
|| safi
== SAFI_MPLS_VPN
))
4183 || (afi
== AFI_L2VPN
&& safi
== SAFI_EVPN
)) {
4184 /* Tunnel Encap attribute */
4185 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_ENCAP
);
4187 #ifdef ENABLE_BGP_VNC_ATTR
4189 bgp_packet_mpattr_tea(bgp
, peer
, s
, attr
, BGP_ATTR_VNC
);
4194 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL
)) {
4195 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4196 stream_putc(s
, BGP_ATTR_PMSI_TUNNEL
);
4197 stream_putc(s
, 9); // Length
4198 stream_putc(s
, 0); // Flags
4199 stream_putc(s
, bgp_attr_get_pmsi_tnl_type(attr
));
4200 stream_put(s
, &(attr
->label
),
4201 BGP_LABEL_BYTES
); // MPLS Label / VXLAN VNI
4202 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4203 // Unicast tunnel endpoint IP address
4206 /* Unknown transit attribute. */
4207 struct transit
*transit
= bgp_attr_get_transit(attr
);
4210 stream_put(s
, transit
->val
, transit
->length
);
4212 /* Return total size of attribute. */
4213 return stream_get_endp(s
) - cp
;
4216 size_t bgp_packet_mpunreach_start(struct stream
*s
, afi_t afi
, safi_t safi
)
4218 unsigned long attrlen_pnt
;
4220 iana_safi_t pkt_safi
;
4222 /* Set extended bit always to encode the attribute length as 2 bytes */
4223 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_EXTLEN
);
4224 stream_putc(s
, BGP_ATTR_MP_UNREACH_NLRI
);
4226 attrlen_pnt
= stream_get_endp(s
);
4227 stream_putw(s
, 0); /* Length of this attribute. */
4229 /* Convert AFI, SAFI to values for packet. */
4230 bgp_map_afi_safi_int2iana(afi
, safi
, &pkt_afi
, &pkt_safi
);
4232 stream_putw(s
, pkt_afi
);
4233 stream_putc(s
, pkt_safi
);
4238 void bgp_packet_mpunreach_prefix(struct stream
*s
, const struct prefix
*p
,
4239 afi_t afi
, safi_t safi
,
4240 const struct prefix_rd
*prd
,
4241 mpls_label_t
*label
, uint32_t num_labels
,
4242 int addpath_encode
, uint32_t addpath_tx_id
,
4245 uint8_t wlabel
[3] = {0x80, 0x00, 0x00};
4247 if (safi
== SAFI_LABELED_UNICAST
) {
4248 label
= (mpls_label_t
*)wlabel
;
4252 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, label
, num_labels
,
4253 addpath_encode
, addpath_tx_id
, attr
);
4256 void bgp_packet_mpunreach_end(struct stream
*s
, size_t attrlen_pnt
)
4258 bgp_packet_mpattr_end(s
, attrlen_pnt
);
4261 /* Initialization of attribute. */
4262 void bgp_attr_init(void)
4275 void bgp_attr_finish(void)
4280 ecommunity_finish();
4281 lcommunity_finish();
4288 /* Make attribute packet. */
4289 void bgp_dump_routes_attr(struct stream
*s
, struct attr
*attr
,
4290 const struct prefix
*prefix
)
4295 struct aspath
*aspath
;
4296 int addpath_encode
= 0;
4297 uint32_t addpath_tx_id
= 0;
4299 /* Remember current pointer. */
4300 cp
= stream_get_endp(s
);
4302 /* Place holder of length. */
4305 /* Origin attribute. */
4306 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4307 stream_putc(s
, BGP_ATTR_ORIGIN
);
4309 stream_putc(s
, attr
->origin
);
4311 aspath
= attr
->aspath
;
4313 stream_putc(s
, BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN
);
4314 stream_putc(s
, BGP_ATTR_AS_PATH
);
4315 aspath_lenp
= stream_get_endp(s
);
4318 stream_putw_at(s
, aspath_lenp
, aspath_put(s
, aspath
, 1));
4320 /* Nexthop attribute. */
4321 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
4322 if (prefix
!= NULL
&& prefix
->family
!= AF_INET6
) {
4323 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4324 stream_putc(s
, BGP_ATTR_NEXT_HOP
);
4326 stream_put_ipv4(s
, attr
->nexthop
.s_addr
);
4329 /* MED attribute. */
4330 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC
)) {
4331 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4332 stream_putc(s
, BGP_ATTR_MULTI_EXIT_DISC
);
4334 stream_putl(s
, attr
->med
);
4337 /* Local preference. */
4338 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)) {
4339 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4340 stream_putc(s
, BGP_ATTR_LOCAL_PREF
);
4342 stream_putl(s
, attr
->local_pref
);
4345 /* Atomic aggregate. */
4346 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE
)) {
4347 stream_putc(s
, BGP_ATTR_FLAG_TRANS
);
4348 stream_putc(s
, BGP_ATTR_ATOMIC_AGGREGATE
);
4353 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR
)) {
4354 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
);
4355 stream_putc(s
, BGP_ATTR_AGGREGATOR
);
4357 stream_putl(s
, attr
->aggregator_as
);
4358 stream_put_ipv4(s
, attr
->aggregator_addr
.s_addr
);
4361 /* Community attribute. */
4362 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES
)) {
4363 if (attr
->community
->size
* 4 > 255) {
4365 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4366 | BGP_ATTR_FLAG_EXTLEN
);
4367 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4368 stream_putw(s
, attr
->community
->size
* 4);
4371 BGP_ATTR_FLAG_OPTIONAL
4372 | BGP_ATTR_FLAG_TRANS
);
4373 stream_putc(s
, BGP_ATTR_COMMUNITIES
);
4374 stream_putc(s
, attr
->community
->size
* 4);
4376 stream_put(s
, attr
->community
->val
, attr
->community
->size
* 4);
4379 /* Large Community attribute. */
4380 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES
)) {
4381 if (lcom_length(attr
->lcommunity
) > 255) {
4383 BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
4384 | BGP_ATTR_FLAG_EXTLEN
);
4385 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4386 stream_putw(s
, lcom_length(attr
->lcommunity
));
4389 BGP_ATTR_FLAG_OPTIONAL
4390 | BGP_ATTR_FLAG_TRANS
);
4391 stream_putc(s
, BGP_ATTR_LARGE_COMMUNITIES
);
4392 stream_putc(s
, lcom_length(attr
->lcommunity
));
4395 stream_put(s
, attr
->lcommunity
->val
,
4396 lcom_length(attr
->lcommunity
));
4399 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
4400 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
4401 && (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL
4402 || attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)) {
4405 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
4406 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
4407 sizep
= stream_get_endp(s
);
4410 stream_putc(s
, 0); /* Marker: Attribute length. */
4411 stream_putw(s
, AFI_IP6
); /* AFI */
4412 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
4415 stream_putc(s
, attr
->mp_nexthop_len
);
4416 stream_put(s
, &attr
->mp_nexthop_global
, IPV6_MAX_BYTELEN
);
4417 if (attr
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)
4418 stream_put(s
, &attr
->mp_nexthop_local
,
4425 stream_put_prefix_addpath(s
, prefix
, addpath_encode
,
4428 /* Set MP attribute length. */
4429 stream_putc_at(s
, sizep
, (stream_get_endp(s
) - sizep
) - 1);
4433 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID
)) {
4434 if (attr
->label_index
!= BGP_INVALID_LABEL_INDEX
) {
4436 BGP_ATTR_FLAG_OPTIONAL
4437 | BGP_ATTR_FLAG_TRANS
);
4438 stream_putc(s
, BGP_ATTR_PREFIX_SID
);
4440 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX
);
4441 stream_putc(s
, BGP_PREFIX_SID_LABEL_INDEX_LENGTH
);
4442 stream_putc(s
, 0); // reserved
4443 stream_putw(s
, 0); // flags
4444 stream_putl(s
, attr
->label_index
);
4448 /* Return total size of attribute. */
4449 len
= stream_get_endp(s
) - cp
- 2;
4450 stream_putw_at(s
, cp
, len
);