1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * bgp_updgrp_packet.c: BGP update group packet handling routines
5 * @copyright Copyright (C) 2014 Cumulus Networks, Inc.
7 * @author Avneesh Sachdev <avneesh@sproute.net>
8 * @author Rajesh Varadarajan <rajesh@sproute.net>
9 * @author Pradosh Mohapatra <pradosh@sproute.net>
19 #include "sockunion.h"
27 #include "workqueue.h"
32 #include "bgpd/bgpd.h"
33 #include "bgpd/bgp_debug.h"
34 #include "bgpd/bgp_errors.h"
35 #include "bgpd/bgp_fsm.h"
36 #include "bgpd/bgp_route.h"
37 #include "bgpd/bgp_packet.h"
38 #include "bgpd/bgp_advertise.h"
39 #include "bgpd/bgp_updgrp.h"
40 #include "bgpd/bgp_nexthop.h"
41 #include "bgpd/bgp_nht.h"
42 #include "bgpd/bgp_mplsvpn.h"
43 #include "bgpd/bgp_label.h"
44 #include "bgpd/bgp_addpath.h"
53 struct bpacket
*bpacket_alloc(void)
57 pkt
= XCALLOC(MTYPE_BGP_PACKET
, sizeof(struct bpacket
));
62 void bpacket_free(struct bpacket
*pkt
)
65 stream_free(pkt
->buffer
);
67 XFREE(MTYPE_BGP_PACKET
, pkt
);
70 void bpacket_queue_init(struct bpacket_queue
*q
)
72 TAILQ_INIT(&(q
->pkts
));
76 * bpacket_queue_add_packet
78 * Internal function of bpacket_queue - and adds a
79 * packet entry to the end of the list.
81 * Users of bpacket_queue should use bpacket_queue_add instead.
83 static void bpacket_queue_add_packet(struct bpacket_queue
*q
,
86 struct bpacket
*last_pkt
;
88 if (TAILQ_EMPTY(&(q
->pkts
)))
89 TAILQ_INSERT_TAIL(&(q
->pkts
), pkt
, pkt_train
);
91 last_pkt
= bpacket_queue_last(q
);
92 TAILQ_INSERT_AFTER(&(q
->pkts
), last_pkt
, pkt
, pkt_train
);
95 if (q
->hwm_count
< q
->curr_count
)
96 q
->hwm_count
= q
->curr_count
;
100 * Adds a packet to the bpacket_queue.
102 * The stream passed is consumed by this function. So, the caller should
103 * not free or use the stream after
104 * invoking this function.
106 struct bpacket
*bpacket_queue_add(struct bpacket_queue
*q
, struct stream
*s
,
107 struct bpacket_attr_vec_arr
*vecarrp
)
110 struct bpacket
*last_pkt
;
113 pkt
= bpacket_alloc();
114 if (TAILQ_EMPTY(&(q
->pkts
))) {
118 memcpy(&pkt
->arr
, vecarrp
,
119 sizeof(struct bpacket_attr_vec_arr
));
121 bpacket_attr_vec_arr_reset(&pkt
->arr
);
122 bpacket_queue_add_packet(q
, pkt
);
127 * Fill in the new information into the current sentinel and create a
130 last_pkt
= bpacket_queue_last(q
);
131 assert(last_pkt
->buffer
== NULL
);
132 last_pkt
->buffer
= s
;
134 memcpy(&last_pkt
->arr
, vecarrp
,
135 sizeof(struct bpacket_attr_vec_arr
));
137 bpacket_attr_vec_arr_reset(&last_pkt
->arr
);
139 pkt
->ver
= last_pkt
->ver
;
141 bpacket_queue_add_packet(q
, pkt
);
146 struct bpacket
*bpacket_queue_first(struct bpacket_queue
*q
)
148 return (TAILQ_FIRST(&(q
->pkts
)));
151 struct bpacket
*bpacket_queue_last(struct bpacket_queue
*q
)
153 return TAILQ_LAST(&(q
->pkts
), pkt_queue
);
156 struct bpacket
*bpacket_queue_remove(struct bpacket_queue
*q
)
158 struct bpacket
*first
;
160 first
= bpacket_queue_first(q
);
162 TAILQ_REMOVE(&(q
->pkts
), first
, pkt_train
);
168 unsigned int bpacket_queue_length(struct bpacket_queue
*q
)
170 return q
->curr_count
- 1;
173 unsigned int bpacket_queue_hwm_length(struct bpacket_queue
*q
)
175 return q
->hwm_count
- 1;
178 bool bpacket_queue_is_full(struct bgp
*bgp
, struct bpacket_queue
*q
)
180 if (q
->curr_count
>= bgp
->default_subgroup_pkt_queue_max
)
185 void bpacket_add_peer(struct bpacket
*pkt
, struct peer_af
*paf
)
190 LIST_INSERT_HEAD(&(pkt
->peers
), paf
, pkt_train
);
191 paf
->next_pkt_to_send
= pkt
;
195 * bpacket_queue_cleanup
197 void bpacket_queue_cleanup(struct bpacket_queue
*q
)
201 while ((pkt
= bpacket_queue_remove(q
))) {
207 * bpacket_queue_compact
209 * Delete packets that do not need to be transmitted to any peer from
212 * @return the number of packets deleted.
214 static int bpacket_queue_compact(struct bpacket_queue
*q
)
217 struct bpacket
*pkt
, *removed_pkt
;
222 pkt
= bpacket_queue_first(q
);
227 * Don't delete the sentinel.
232 if (!LIST_EMPTY(&(pkt
->peers
)))
235 removed_pkt
= bpacket_queue_remove(q
);
236 assert(pkt
== removed_pkt
);
237 bpacket_free(removed_pkt
);
245 void bpacket_queue_advance_peer(struct peer_af
*paf
)
248 struct bpacket
*old_pkt
;
250 old_pkt
= paf
->next_pkt_to_send
;
251 if (old_pkt
->buffer
== NULL
)
252 /* Already at end of list */
255 LIST_REMOVE(paf
, pkt_train
);
256 pkt
= TAILQ_NEXT(old_pkt
, pkt_train
);
257 bpacket_add_peer(pkt
, paf
);
259 if (!bpacket_queue_compact(PAF_PKTQ(paf
)))
263 * Deleted one or more packets. Check if we can now merge this
264 * peer's subgroup into another subgroup.
266 update_subgroup_check_merge(paf
->subgroup
, "advanced peer in queue");
270 * bpacket_queue_remove_peer
272 * Remove the peer from the packet queue of the subgroup it belongs
275 void bpacket_queue_remove_peer(struct peer_af
*paf
)
277 struct bpacket_queue
*q
;
282 LIST_REMOVE(paf
, pkt_train
);
283 paf
->next_pkt_to_send
= NULL
;
285 bpacket_queue_compact(q
);
288 unsigned int bpacket_queue_virtual_length(struct peer_af
*paf
)
291 struct bpacket
*last
;
292 struct bpacket_queue
*q
;
294 pkt
= paf
->next_pkt_to_send
;
295 if (!pkt
|| (pkt
->buffer
== NULL
))
296 /* Already at end of list */
300 if (TAILQ_EMPTY(&(q
->pkts
)))
303 last
= TAILQ_LAST(&(q
->pkts
), pkt_queue
);
304 if (last
->ver
>= pkt
->ver
)
305 return last
->ver
- pkt
->ver
;
307 /* sequence # rolled over */
308 return (UINT_MAX
- pkt
->ver
+ 1) + last
->ver
;
312 * Dump the bpacket queue
314 void bpacket_queue_show_vty(struct bpacket_queue
*q
, struct vty
*vty
)
319 pkt
= bpacket_queue_first(q
);
321 vty_out(vty
, " Packet %p ver %u buffer %p\n", pkt
, pkt
->ver
,
324 LIST_FOREACH (paf
, &(pkt
->peers
), pkt_train
) {
325 vty_out(vty
, " - %s\n", paf
->peer
->host
);
327 pkt
= bpacket_next(pkt
);
332 struct stream
*bpacket_reformat_for_peer(struct bpacket
*pkt
,
335 struct stream
*s
= NULL
;
336 bpacket_attr_vec
*vec
;
338 struct bgp_filter
*filter
;
340 s
= stream_dup(pkt
->buffer
);
341 peer
= PAF_PEER(paf
);
343 vec
= &pkt
->arr
.entries
[BGP_ATTR_VEC_NH
];
345 if (!CHECK_FLAG(vec
->flags
, BPKT_ATTRVEC_FLAGS_UPDATED
))
350 int route_map_sets_nh
;
352 nhlen
= stream_getc_from(s
, vec
->offset
);
353 filter
= &peer
->filter
[paf
->afi
][paf
->safi
];
355 if (peer_cap_enhe(peer
, paf
->afi
, paf
->safi
))
358 nhafi
= BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen
);
360 if (nhafi
== AFI_IP
) {
361 struct in_addr v4nh
, *mod_v4nh
;
363 size_t offset_nh
= vec
->offset
+ 1;
366 (CHECK_FLAG(vec
->flags
,
367 BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED
) ||
368 CHECK_FLAG(vec
->flags
,
369 BPKT_ATTRVEC_FLAGS_RMAP_VPNV4_NH_CHANGED
) ||
370 CHECK_FLAG(vec
->flags
,
371 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
));
374 case BGP_ATTR_NHLEN_IPV4
:
376 case BGP_ATTR_NHLEN_VPNV4
:
380 /* TODO: handle IPv6 nexthops */
382 EC_BGP_INVALID_NEXTHOP_LENGTH
,
383 "%s: %s: invalid MP nexthop length (AFI IP): %u",
384 __func__
, peer
->host
, nhlen
);
389 stream_get_from(&v4nh
, s
, offset_nh
, IPV4_MAX_BYTELEN
);
393 * If route-map has set the nexthop, that is normally
394 * used; if it is specified as peer-address, the peering
395 * address is picked up. Otherwise, if NH is unavailable
396 * from attribute, the peering addr is picked up; the
397 * "NH unavailable" case also covers next-hop-self and
398 * some other scenarios - see subgroup_announce_check().
399 * In all other cases, use the nexthop carried in the
400 * attribute unless it is EBGP non-multiaccess and there
401 * is no next-hop-unchanged setting or the peer is EBGP
402 * and the route-map that changed the next-hop value
403 * was applied inbound rather than outbound. Updates to
404 * an EBGP peer should only modify the next-hop if it
405 * was set in an outbound route-map to that peer.
406 * Note: It is assumed route-map cannot set the nexthop
407 * to an invalid value.
409 if (route_map_sets_nh
410 && ((peer
->sort
!= BGP_PEER_EBGP
)
411 || ROUTE_MAP_OUT(filter
))) {
414 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
)) {
415 mod_v4nh
= &peer
->nexthop
.v4
;
418 } else if (v4nh
.s_addr
== INADDR_ANY
) {
419 mod_v4nh
= &peer
->nexthop
.v4
;
421 } else if (peer
->sort
== BGP_PEER_EBGP
422 && (bgp_multiaccess_check_v4(v4nh
, peer
) == 0)
423 && !CHECK_FLAG(vec
->flags
,
424 BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED
)
425 && !peer_af_flag_check(
426 peer
, paf
->afi
, paf
->safi
,
427 PEER_FLAG_NEXTHOP_UNCHANGED
)) {
428 /* NOTE: not handling case where NH has new AFI
430 mod_v4nh
= &peer
->nexthop
.v4
;
434 if (nh_modified
) /* allow for VPN RD */
435 stream_put_in_addr_at(s
, offset_nh
, mod_v4nh
);
437 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
438 zlog_debug("u%" PRIu64
":s%" PRIu64
439 " %s send UPDATE w/ nexthop %pI4%s",
440 PAF_SUBGRP(paf
)->update_group
->id
,
441 PAF_SUBGRP(paf
)->id
, peer
->host
, mod_v4nh
,
442 (nhlen
== BGP_ATTR_NHLEN_VPNV4
? " and RD"
444 } else if (nhafi
== AFI_IP6
) {
445 struct in6_addr v6nhglobal
, *mod_v6nhg
;
446 struct in6_addr v6nhlocal
, *mod_v6nhl
;
447 int gnh_modified
, lnh_modified
;
448 size_t offset_nhglobal
= vec
->offset
+ 1;
449 size_t offset_nhlocal
= vec
->offset
+ 1;
451 gnh_modified
= lnh_modified
= 0;
452 mod_v6nhg
= &v6nhglobal
;
453 mod_v6nhl
= &v6nhlocal
;
456 (CHECK_FLAG(vec
->flags
,
457 BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED
) ||
460 BPKT_ATTRVEC_FLAGS_RMAP_VPNV6_GNH_CHANGED
) ||
461 CHECK_FLAG(vec
->flags
,
462 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
));
465 * The logic here is rather similar to that for IPv4, the
466 * additional work being to handle 1 or 2 nexthops.
467 * Also, 3rd party nexthop is not propagated for EBGP
471 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
473 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
474 offset_nhlocal
+= IPV6_MAX_BYTELEN
;
476 case BGP_ATTR_NHLEN_VPNV6_GLOBAL
:
477 offset_nhglobal
+= 8;
479 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
:
480 offset_nhglobal
+= 8;
481 offset_nhlocal
+= 8 * 2 + IPV6_MAX_BYTELEN
;
484 /* TODO: handle IPv4 nexthops */
486 EC_BGP_INVALID_NEXTHOP_LENGTH
,
487 "%s: %s: invalid MP nexthop length (AFI IP6): %u",
488 __func__
, peer
->host
, nhlen
);
493 stream_get_from(&v6nhglobal
, s
, offset_nhglobal
,
497 * Updates to an EBGP peer should only modify the
498 * next-hop if it was set in an outbound route-map
501 if (route_map_sets_nh
502 && ((peer
->sort
!= BGP_PEER_EBGP
)
503 || ROUTE_MAP_OUT(filter
))) {
506 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
)) {
507 mod_v6nhg
= &peer
->nexthop
.v6_global
;
510 } else if (IN6_IS_ADDR_UNSPECIFIED(&v6nhglobal
)) {
511 mod_v6nhg
= &peer
->nexthop
.v6_global
;
513 } else if ((peer
->sort
== BGP_PEER_EBGP
)
514 && (!bgp_multiaccess_check_v6(v6nhglobal
, peer
))
515 && !CHECK_FLAG(vec
->flags
,
516 BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED
)
517 && !peer_af_flag_check(
518 peer
, paf
->afi
, paf
->safi
,
519 PEER_FLAG_NEXTHOP_UNCHANGED
)) {
520 /* NOTE: not handling case where NH has new AFI
522 mod_v6nhg
= &peer
->nexthop
.v6_global
;
526 if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg
)) {
527 if (peer
->nexthop
.v4
.s_addr
!= INADDR_ANY
) {
528 ipv4_to_ipv4_mapped_ipv6(mod_v6nhg
,
533 if (IS_MAPPED_IPV6(&peer
->nexthop
.v6_global
)) {
534 mod_v6nhg
= &peer
->nexthop
.v6_global
;
538 if (nhlen
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
539 || nhlen
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
540 stream_get_from(&v6nhlocal
, s
, offset_nhlocal
,
542 if (IN6_IS_ADDR_UNSPECIFIED(&v6nhlocal
)) {
543 mod_v6nhl
= &peer
->nexthop
.v6_local
;
549 stream_put_in6_addr_at(s
, offset_nhglobal
, mod_v6nhg
);
551 stream_put_in6_addr_at(s
, offset_nhlocal
, mod_v6nhl
);
553 if (bgp_debug_update(peer
, NULL
, NULL
, 0)) {
554 if (nhlen
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
555 || nhlen
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
)
557 "u%" PRIu64
":s%" PRIu64
558 " %s send UPDATE w/ mp_nexthops %pI6, %pI6%s",
559 PAF_SUBGRP(paf
)->update_group
->id
,
560 PAF_SUBGRP(paf
)->id
, peer
->host
,
561 mod_v6nhg
, mod_v6nhl
,
562 (nhlen
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
567 "u%" PRIu64
":s%" PRIu64
568 " %s send UPDATE w/ mp_nexthop %pI6%s",
569 PAF_SUBGRP(paf
)->update_group
->id
,
570 PAF_SUBGRP(paf
)->id
, peer
->host
,
572 (nhlen
== BGP_ATTR_NHLEN_VPNV6_GLOBAL
576 } else if (paf
->afi
== AFI_L2VPN
) {
577 struct in_addr v4nh
, *mod_v4nh
;
580 stream_get_from(&v4nh
, s
, vec
->offset
+ 1, 4);
583 /* No route-map changes allowed for EVPN nexthops. */
584 if (v4nh
.s_addr
== INADDR_ANY
) {
585 mod_v4nh
= &peer
->nexthop
.v4
;
590 stream_put_in_addr_at(s
, vec
->offset
+ 1, mod_v4nh
);
592 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
593 zlog_debug("u%" PRIu64
":s%" PRIu64
594 " %s send UPDATE w/ nexthop %pI4",
595 PAF_SUBGRP(paf
)->update_group
->id
,
596 PAF_SUBGRP(paf
)->id
, peer
->host
, mod_v4nh
);
603 * Update the vecarr offsets to go beyond 'pos' bytes, i.e. add 'pos'
606 static void bpacket_attr_vec_arr_update(struct bpacket_attr_vec_arr
*vecarr
,
614 for (i
= 0; i
< BGP_ATTR_VEC_MAX
; i
++)
615 vecarr
->entries
[i
].offset
+= pos
;
619 * Return if there are packets to build for this subgroup.
621 bool subgroup_packets_to_build(struct update_subgroup
*subgrp
)
623 struct bgp_advertise
*adv
;
628 adv
= bgp_adv_fifo_first(&subgrp
->sync
->withdraw
);
632 adv
= bgp_adv_fifo_first(&subgrp
->sync
->update
);
639 /* Make BGP update packet. */
640 struct bpacket
*subgroup_update_packet(struct update_subgroup
*subgrp
)
642 struct bpacket_attr_vec_arr vecarr
;
646 struct stream
*snlri
;
647 struct stream
*packet
;
648 struct bgp_adj_out
*adj
;
649 struct bgp_advertise
*adv
;
650 struct bgp_dest
*dest
= NULL
;
651 struct bgp_path_info
*path
= NULL
;
652 bgp_size_t total_attr_len
= 0;
653 unsigned long attrlen_pos
= 0;
654 size_t mpattrlen_pos
= 0;
655 size_t mpattr_pos
= 0;
658 int space_remaining
= 0;
659 int space_needed
= 0;
660 char send_attr_str
[BUFSIZ
];
661 int send_attr_printed
= 0;
663 bool addpath_capable
= false;
664 int addpath_overhead
= 0;
665 uint32_t addpath_tx_id
= 0;
666 struct prefix_rd
*prd
= NULL
;
667 mpls_label_t label
= MPLS_INVALID_LABEL
, *label_pnt
= NULL
;
668 uint32_t num_labels
= 0;
673 if (bpacket_queue_is_full(SUBGRP_INST(subgrp
), SUBGRP_PKTQ(subgrp
)))
676 peer
= SUBGRP_PEER(subgrp
);
677 afi
= SUBGRP_AFI(subgrp
);
678 safi
= SUBGRP_SAFI(subgrp
);
681 snlri
= subgrp
->scratch
;
684 bpacket_attr_vec_arr_reset(&vecarr
);
686 addpath_capable
= bgp_addpath_encode_tx(peer
, afi
, safi
);
687 addpath_overhead
= addpath_capable
? BGP_ADDPATH_ID_LEN
: 0;
689 adv
= bgp_adv_fifo_first(&subgrp
->sync
->update
);
691 const struct prefix
*dest_p
;
695 dest_p
= bgp_dest_get_prefix(dest
);
697 addpath_tx_id
= adj
->addpath_tx_id
;
700 space_remaining
= STREAM_CONCAT_REMAIN(s
, snlri
, STREAM_SIZE(s
))
701 - BGP_MAX_PACKET_SIZE_OVERFLOW
;
703 BGP_NLRI_LENGTH
+ addpath_overhead
704 + bgp_packet_mpattr_prefix_size(afi
, safi
, dest_p
);
706 /* When remaining space can't include NLRI and it's length. */
707 if (space_remaining
< space_needed
)
710 /* If packet is empty, set attribute. */
711 if (stream_empty(s
)) {
712 struct peer
*from
= NULL
;
717 /* 1: Write the BGP message header - 16 bytes marker, 2
719 * one byte message type.
721 bgp_packet_set_marker(s
, BGP_MSG_UPDATE
);
723 /* 2: withdrawn routes length */
726 /* 3: total attributes length - attrlen_pos stores the
728 attrlen_pos
= stream_get_endp(s
);
731 /* 4: if there is MP_REACH_NLRI attribute, that should
733 * attribute, according to
734 * draft-ietf-idr-error-handling. Save the
737 mpattr_pos
= stream_get_endp(s
);
739 /* 5: Encode all the attributes, except MP_REACH_NLRI
741 total_attr_len
= bgp_packet_attribute(
742 NULL
, peer
, s
, adv
->baa
->attr
, &vecarr
, NULL
,
743 afi
, safi
, from
, NULL
, NULL
, 0, 0, 0, path
);
746 STREAM_CONCAT_REMAIN(s
, snlri
, STREAM_SIZE(s
))
747 - BGP_MAX_PACKET_SIZE_OVERFLOW
;
748 space_needed
= BGP_NLRI_LENGTH
+ addpath_overhead
749 + bgp_packet_mpattr_prefix_size(
752 /* If the attributes alone do not leave any room for
755 if (space_remaining
< space_needed
) {
757 EC_BGP_UPDGRP_ATTR_LEN
,
758 "u%" PRIu64
":s%" PRIu64
" attributes too long, cannot send UPDATE",
759 subgrp
->update_group
->id
, subgrp
->id
);
761 /* Flush the FIFO update queue */
763 adv
= bgp_advertise_clean_subgroup(
768 if (BGP_DEBUG(update
, UPDATE_OUT
)
769 || BGP_DEBUG(update
, UPDATE_PREFIX
)) {
770 memset(send_attr_str
, 0, BUFSIZ
);
771 send_attr_printed
= 0;
772 bgp_dump_attr(adv
->baa
->attr
, send_attr_str
,
773 sizeof(send_attr_str
));
777 if ((afi
== AFI_IP
&& safi
== SAFI_UNICAST
)
778 && !peer_cap_enhe(peer
, afi
, safi
))
779 stream_put_prefix_addpath(s
, dest_p
, addpath_capable
,
782 /* Encode the prefix in MP_REACH_NLRI attribute */
784 prd
= (struct prefix_rd
*)bgp_dest_get_prefix(
787 if (safi
== SAFI_LABELED_UNICAST
) {
788 label
= bgp_adv_label(dest
, path
, peer
, afi
,
792 } else if (path
&& path
->extra
) {
793 label_pnt
= &path
->extra
->label
[0];
794 num_labels
= path
->extra
->num_labels
;
797 if (stream_empty(snlri
))
798 mpattrlen_pos
= bgp_packet_mpattr_start(
799 snlri
, peer
, afi
, safi
, &vecarr
,
802 bgp_packet_mpattr_prefix(snlri
, afi
, safi
, dest_p
, prd
,
803 label_pnt
, num_labels
,
804 addpath_capable
, addpath_tx_id
,
810 if (bgp_debug_update(NULL
, dest_p
, subgrp
->update_group
, 0)) {
811 char pfx_buf
[BGP_PRD_PATH_STRLEN
];
813 if (!send_attr_printed
) {
814 zlog_debug("u%" PRIu64
":s%" PRIu64
" send UPDATE w/ attr: %s",
815 subgrp
->update_group
->id
, subgrp
->id
,
817 if (!stream_empty(snlri
)) {
819 iana_safi_t pkt_safi
;
821 pkt_afi
= afi_int2iana(afi
);
822 pkt_safi
= safi_int2iana(safi
);
824 "u%" PRIu64
":s%" PRIu64
825 " send MP_REACH for afi/safi %s/%s",
826 subgrp
->update_group
->id
,
828 iana_afi2str(pkt_afi
),
829 iana_safi2str(pkt_safi
));
832 send_attr_printed
= 1;
835 bgp_debug_rdpfxpath2str(afi
, safi
, prd
, dest_p
,
836 label_pnt
, num_labels
,
837 addpath_capable
, addpath_tx_id
,
838 &adv
->baa
->attr
->evpn_overlay
,
839 pfx_buf
, sizeof(pfx_buf
));
840 zlog_debug("u%" PRIu64
":s%" PRIu64
" send UPDATE %s",
841 subgrp
->update_group
->id
, subgrp
->id
,
845 /* Synchnorize attribute. */
847 bgp_attr_unintern(&adj
->attr
);
851 adj
->attr
= bgp_attr_intern(adv
->baa
->attr
);
852 adv
= bgp_advertise_clean_subgroup(subgrp
, adj
);
855 if (!stream_empty(s
)) {
856 if (!stream_empty(snlri
)) {
857 bgp_packet_mpattr_end(snlri
, mpattrlen_pos
);
858 total_attr_len
+= stream_get_endp(snlri
);
861 /* set the total attribute length correctly */
862 stream_putw_at(s
, attrlen_pos
, total_attr_len
);
864 if (!stream_empty(snlri
)) {
865 packet
= stream_dupcat(s
, snlri
, mpattr_pos
);
866 bpacket_attr_vec_arr_update(&vecarr
, mpattr_pos
);
868 packet
= stream_dup(s
);
869 bgp_packet_set_size(packet
);
870 if (bgp_debug_update(NULL
, NULL
, subgrp
->update_group
, 0))
872 "u%" PRIu64
":s%" PRIu64
873 " send UPDATE len %zd (max message len: %hu) numpfx %d",
874 subgrp
->update_group
->id
, subgrp
->id
,
875 (stream_get_endp(packet
)
876 - stream_get_getp(packet
)),
877 peer
->max_packet_size
, num_pfx
);
878 pkt
= bpacket_queue_add(SUBGRP_PKTQ(subgrp
), packet
, &vecarr
);
886 /* Make BGP withdraw packet. */
888 16-octet marker | 2-octet length | 1-octet type |
889 2-octet withdrawn route length | withdrawn prefixes | 2-octet attrlen (=0)
891 /* For other afi/safis:
892 16-octet marker | 2-octet length | 1-octet type |
893 2-octet withdrawn route length (=0) | 2-octet attrlen |
894 mp_unreach attr type | attr len | afi | safi | withdrawn prefixes
896 struct bpacket
*subgroup_withdraw_packet(struct update_subgroup
*subgrp
)
900 struct bgp_adj_out
*adj
;
901 struct bgp_advertise
*adv
;
903 struct bgp_dest
*dest
;
904 bgp_size_t unfeasible_len
;
905 bgp_size_t total_attr_len
;
907 size_t attrlen_pos
= 0;
908 size_t mplen_pos
= 0;
909 uint8_t first_time
= 1;
912 int space_remaining
= 0;
913 int space_needed
= 0;
915 bool addpath_capable
= false;
916 int addpath_overhead
= 0;
917 uint32_t addpath_tx_id
= 0;
918 const struct prefix_rd
*prd
= NULL
;
924 if (bpacket_queue_is_full(SUBGRP_INST(subgrp
), SUBGRP_PKTQ(subgrp
)))
927 peer
= SUBGRP_PEER(subgrp
);
928 afi
= SUBGRP_AFI(subgrp
);
929 safi
= SUBGRP_SAFI(subgrp
);
932 addpath_capable
= bgp_addpath_encode_tx(peer
, afi
, safi
);
933 addpath_overhead
= addpath_capable
? BGP_ADDPATH_ID_LEN
: 0;
935 while ((adv
= bgp_adv_fifo_first(&subgrp
->sync
->withdraw
)) != NULL
) {
936 const struct prefix
*dest_p
;
941 dest_p
= bgp_dest_get_prefix(dest
);
942 addpath_tx_id
= adj
->addpath_tx_id
;
945 STREAM_WRITEABLE(s
) - BGP_MAX_PACKET_SIZE_OVERFLOW
;
947 BGP_NLRI_LENGTH
+ addpath_overhead
+ BGP_TOTAL_ATTR_LEN
948 + bgp_packet_mpattr_prefix_size(afi
, safi
, dest_p
);
950 if (space_remaining
< space_needed
)
953 if (stream_empty(s
)) {
954 bgp_packet_set_marker(s
, BGP_MSG_UPDATE
);
955 stream_putw(s
, 0); /* unfeasible routes length */
959 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
960 && !peer_cap_enhe(peer
, afi
, safi
))
961 stream_put_prefix_addpath(s
, dest_p
, addpath_capable
,
965 prd
= (struct prefix_rd
*)bgp_dest_get_prefix(
968 /* If first time, format the MP_UNREACH header
972 iana_safi_t pkt_safi
;
974 pkt_afi
= afi_int2iana(afi
);
975 pkt_safi
= safi_int2iana(safi
);
977 attrlen_pos
= stream_get_endp(s
);
978 /* total attr length = 0 for now.
979 * reevaluate later */
981 mp_start
= stream_get_endp(s
);
982 mplen_pos
= bgp_packet_mpunreach_start(s
, afi
,
984 if (bgp_debug_update(NULL
, NULL
,
985 subgrp
->update_group
, 0))
987 "u%" PRIu64
":s%" PRIu64
988 " send MP_UNREACH for afi/safi %s/%s",
989 subgrp
->update_group
->id
,
991 iana_afi2str(pkt_afi
),
992 iana_safi2str(pkt_safi
));
995 bgp_packet_mpunreach_prefix(s
, dest_p
, afi
, safi
, prd
,
996 NULL
, 0, addpath_capable
,
997 addpath_tx_id
, NULL
);
1002 if (bgp_debug_update(NULL
, dest_p
, subgrp
->update_group
, 0)) {
1003 char pfx_buf
[BGP_PRD_PATH_STRLEN
];
1005 bgp_debug_rdpfxpath2str(afi
, safi
, prd
, dest_p
, NULL
, 0,
1006 addpath_capable
, addpath_tx_id
,
1007 NULL
, pfx_buf
, sizeof(pfx_buf
));
1008 zlog_debug("u%" PRIu64
":s%" PRIu64
" send UPDATE %s -- unreachable",
1009 subgrp
->update_group
->id
, subgrp
->id
,
1015 bgp_adj_out_remove_subgroup(dest
, adj
, subgrp
);
1018 if (!stream_empty(s
)) {
1019 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
1020 && !peer_cap_enhe(peer
, afi
, safi
)) {
1021 unfeasible_len
= stream_get_endp(s
) - BGP_HEADER_SIZE
1022 - BGP_UNFEASIBLE_LEN
;
1023 stream_putw_at(s
, BGP_HEADER_SIZE
, unfeasible_len
);
1026 /* Set the mp_unreach attr's length */
1027 bgp_packet_mpunreach_end(s
, mplen_pos
);
1029 /* Set total path attribute length. */
1030 total_attr_len
= stream_get_endp(s
) - mp_start
;
1031 stream_putw_at(s
, attrlen_pos
, total_attr_len
);
1033 bgp_packet_set_size(s
);
1034 if (bgp_debug_update(NULL
, NULL
, subgrp
->update_group
, 0))
1035 zlog_debug("u%" PRIu64
":s%" PRIu64
" send UPDATE (withdraw) len %zd numpfx %d",
1036 subgrp
->update_group
->id
, subgrp
->id
,
1037 (stream_get_endp(s
) - stream_get_getp(s
)),
1039 pkt
= bpacket_queue_add(SUBGRP_PKTQ(subgrp
), stream_dup(s
),
1048 void subgroup_default_update_packet(struct update_subgroup
*subgrp
,
1049 struct attr
*attr
, struct peer
*from
)
1055 bgp_size_t total_attr_len
;
1058 struct bpacket_attr_vec_arr vecarr
;
1059 bool addpath_capable
= false;
1060 uint8_t default_originate_label
[4] = {0x80, 0x00, 0x00};
1061 mpls_label_t
*label
= NULL
;
1062 uint32_t num_labels
= 0;
1064 if (DISABLE_BGP_ANNOUNCE
)
1070 peer
= SUBGRP_PEER(subgrp
);
1071 afi
= SUBGRP_AFI(subgrp
);
1072 safi
= SUBGRP_SAFI(subgrp
);
1073 bpacket_attr_vec_arr_reset(&vecarr
);
1074 addpath_capable
= bgp_addpath_encode_tx(peer
, afi
, safi
);
1076 if (safi
== SAFI_LABELED_UNICAST
) {
1077 label
= (mpls_label_t
*)default_originate_label
;
1081 memset(&p
, 0, sizeof(p
));
1082 p
.family
= afi2family(afi
);
1085 /* Logging the attribute. */
1086 if (bgp_debug_update(NULL
, &p
, subgrp
->update_group
, 0)) {
1087 char attrstr
[BUFSIZ
];
1088 /* ' with addpath ID ' 17
1089 * max strlen of uint32 + 10
1090 * +/- (just in case) + 1
1091 * null terminator + 1
1092 * ============================ 29 */
1097 bgp_dump_attr(attr
, attrstr
, sizeof(attrstr
));
1099 if (addpath_capable
)
1100 snprintf(tx_id_buf
, sizeof(tx_id_buf
),
1101 " with addpath ID %u",
1102 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
);
1104 tx_id_buf
[0] = '\0';
1106 zlog_debug("u%" PRIu64
":s%" PRIu64
" send UPDATE %pFX%s %s",
1107 (SUBGRP_UPDGRP(subgrp
))->id
, subgrp
->id
, &p
,
1108 tx_id_buf
, attrstr
);
1111 s
= stream_new(peer
->max_packet_size
);
1113 /* Make BGP update packet. */
1114 bgp_packet_set_marker(s
, BGP_MSG_UPDATE
);
1116 /* Unfeasible Routes Length. */
1119 /* Make place for total attribute length. */
1120 pos
= stream_get_endp(s
);
1122 total_attr_len
= bgp_packet_attribute(
1123 NULL
, peer
, s
, attr
, &vecarr
, &p
, afi
, safi
, from
, NULL
, label
,
1124 num_labels
, addpath_capable
,
1125 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
, NULL
);
1127 /* Set Total Path Attribute Length. */
1128 stream_putw_at(s
, pos
, total_attr_len
);
1131 if (p
.family
== AF_INET
&& safi
== SAFI_UNICAST
1132 && !peer_cap_enhe(peer
, afi
, safi
))
1133 stream_put_prefix_addpath(
1134 s
, &p
, addpath_capable
,
1135 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
);
1138 bgp_packet_set_size(s
);
1140 (void)bpacket_queue_add(SUBGRP_PKTQ(subgrp
), s
, &vecarr
);
1141 subgroup_trigger_write(subgrp
);
1143 if (!CHECK_FLAG(subgrp
->sflags
,
1144 SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED
)) {
1146 SET_FLAG(subgrp
->sflags
, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED
);
1150 void subgroup_default_withdraw_packet(struct update_subgroup
*subgrp
)
1155 unsigned long attrlen_pos
= 0;
1157 bgp_size_t unfeasible_len
;
1158 bgp_size_t total_attr_len
= 0;
1159 size_t mp_start
= 0;
1160 size_t mplen_pos
= 0;
1163 bool addpath_capable
= false;
1165 if (DISABLE_BGP_ANNOUNCE
)
1168 peer
= SUBGRP_PEER(subgrp
);
1169 afi
= SUBGRP_AFI(subgrp
);
1170 safi
= SUBGRP_SAFI(subgrp
);
1171 addpath_capable
= bgp_addpath_encode_tx(peer
, afi
, safi
);
1173 memset(&p
, 0, sizeof(p
));
1174 p
.family
= afi2family(afi
);
1177 if (bgp_debug_update(NULL
, &p
, subgrp
->update_group
, 0)) {
1178 /* ' with addpath ID ' 17
1179 * max strlen of uint32 + 10
1180 * +/- (just in case) + 1
1181 * null terminator + 1
1182 * ============================ 29 */
1185 if (addpath_capable
)
1186 snprintf(tx_id_buf
, sizeof(tx_id_buf
),
1187 " with addpath ID %u",
1188 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
);
1190 zlog_debug("u%" PRIu64
":s%" PRIu64
1191 " send UPDATE %pFX%s -- unreachable",
1192 (SUBGRP_UPDGRP(subgrp
))->id
, subgrp
->id
, &p
,
1196 s
= stream_new(peer
->max_packet_size
);
1198 /* Make BGP update packet. */
1199 bgp_packet_set_marker(s
, BGP_MSG_UPDATE
);
1201 /* Unfeasible Routes Length. */;
1202 cp
= stream_get_endp(s
);
1205 /* Withdrawn Routes. */
1206 if (p
.family
== AF_INET
&& safi
== SAFI_UNICAST
1207 && !peer_cap_enhe(peer
, afi
, safi
)) {
1208 stream_put_prefix_addpath(
1209 s
, &p
, addpath_capable
,
1210 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
);
1212 unfeasible_len
= stream_get_endp(s
) - cp
- 2;
1214 /* Set unfeasible len. */
1215 stream_putw_at(s
, cp
, unfeasible_len
);
1217 /* Set total path attribute length. */
1220 attrlen_pos
= stream_get_endp(s
);
1222 mp_start
= stream_get_endp(s
);
1223 mplen_pos
= bgp_packet_mpunreach_start(s
, afi
, safi
);
1224 bgp_packet_mpunreach_prefix(
1225 s
, &p
, afi
, safi
, NULL
, NULL
, 0, addpath_capable
,
1226 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
, NULL
);
1228 /* Set the mp_unreach attr's length */
1229 bgp_packet_mpunreach_end(s
, mplen_pos
);
1231 /* Set total path attribute length. */
1232 total_attr_len
= stream_get_endp(s
) - mp_start
;
1233 stream_putw_at(s
, attrlen_pos
, total_attr_len
);
1236 bgp_packet_set_size(s
);
1238 (void)bpacket_queue_add(SUBGRP_PKTQ(subgrp
), s
, NULL
);
1239 subgroup_trigger_write(subgrp
);
1241 if (CHECK_FLAG(subgrp
->sflags
, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED
)) {
1243 UNSET_FLAG(subgrp
->sflags
,
1244 SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED
);
1249 bpacket_vec_arr_inherit_attr_flags(struct bpacket_attr_vec_arr
*vecarr
,
1250 enum bpacket_attr_vec_type type
,
1253 if (CHECK_FLAG(attr
->rmap_change_flags
,
1254 BATTR_RMAP_NEXTHOP_PEER_ADDRESS
))
1255 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1256 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
);
1258 if (CHECK_FLAG(attr
->rmap_change_flags
, BATTR_REFLECTED
))
1259 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1260 BPKT_ATTRVEC_FLAGS_REFLECTED
);
1262 if (CHECK_FLAG(attr
->rmap_change_flags
, BATTR_RMAP_NEXTHOP_UNCHANGED
))
1263 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1264 BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED
);
1266 if (CHECK_FLAG(attr
->rmap_change_flags
, BATTR_RMAP_IPV4_NHOP_CHANGED
))
1267 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1268 BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED
);
1270 if (CHECK_FLAG(attr
->rmap_change_flags
,
1271 BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED
))
1272 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1273 BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED
);
1275 if (CHECK_FLAG(attr
->rmap_change_flags
, BATTR_RMAP_VPNV4_NHOP_CHANGED
))
1276 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1277 BPKT_ATTRVEC_FLAGS_RMAP_VPNV4_NH_CHANGED
);
1279 if (CHECK_FLAG(attr
->rmap_change_flags
,
1280 BATTR_RMAP_VPNV6_GLOBAL_NHOP_CHANGED
))
1281 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1282 BPKT_ATTRVEC_FLAGS_RMAP_VPNV6_GNH_CHANGED
);
1284 if (CHECK_FLAG(attr
->rmap_change_flags
,
1285 BATTR_RMAP_IPV6_LL_NHOP_CHANGED
))
1286 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1287 BPKT_ATTRVEC_FLAGS_RMAP_IPV6_LNH_CHANGED
);
1290 /* Reset the Attributes vector array. The vector array is used to override
1291 * certain output parameters in the packet for a particular peer
1293 void bpacket_attr_vec_arr_reset(struct bpacket_attr_vec_arr
*vecarr
)
1301 while (i
< BGP_ATTR_VEC_MAX
) {
1302 vecarr
->entries
[i
].flags
= 0;
1303 vecarr
->entries
[i
].offset
= 0;
1308 /* Setup a particular node entry in the vecarr */
1309 void bpacket_attr_vec_arr_set_vec(struct bpacket_attr_vec_arr
*vecarr
,
1310 enum bpacket_attr_vec_type type
,
1311 struct stream
*s
, struct attr
*attr
)
1315 assert(type
< BGP_ATTR_VEC_MAX
);
1317 SET_FLAG(vecarr
->entries
[type
].flags
, BPKT_ATTRVEC_FLAGS_UPDATED
);
1318 vecarr
->entries
[type
].offset
= stream_get_endp(s
);
1320 bpacket_vec_arr_inherit_attr_flags(vecarr
, type
, attr
);