2 * bgp_updgrp_packet.c: BGP update group packet handling routines
4 * @copyright Copyright (C) 2014 Cumulus Networks, Inc.
6 * @author Avneesh Sachdev <avneesh@sproute.net>
7 * @author Rajesh Varadarajan <rajesh@sproute.net>
8 * @author Pradosh Mohapatra <pradosh@sproute.net>
10 * This file is part of GNU Zebra.
12 * GNU Zebra is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2, or (at your option) any
17 * GNU Zebra is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; see the file COPYING; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "sockunion.h"
42 #include "workqueue.h"
47 #include "bgpd/bgpd.h"
48 #include "bgpd/bgp_debug.h"
49 #include "bgpd/bgp_errors.h"
50 #include "bgpd/bgp_fsm.h"
51 #include "bgpd/bgp_route.h"
52 #include "bgpd/bgp_packet.h"
53 #include "bgpd/bgp_advertise.h"
54 #include "bgpd/bgp_updgrp.h"
55 #include "bgpd/bgp_nexthop.h"
56 #include "bgpd/bgp_nht.h"
57 #include "bgpd/bgp_mplsvpn.h"
58 #include "bgpd/bgp_label.h"
59 #include "bgpd/bgp_addpath.h"
68 struct bpacket
*bpacket_alloc(void)
72 pkt
= (struct bpacket
*)XCALLOC(MTYPE_BGP_PACKET
,
73 sizeof(struct bpacket
));
78 void bpacket_free(struct bpacket
*pkt
)
81 stream_free(pkt
->buffer
);
83 XFREE(MTYPE_BGP_PACKET
, pkt
);
86 void bpacket_queue_init(struct bpacket_queue
*q
)
88 TAILQ_INIT(&(q
->pkts
));
92 * bpacket_queue_sanity_check
94 void bpacket_queue_sanity_check(struct bpacket_queue
__attribute__((__unused__
))
100 pkt
= bpacket_queue_last (q
);
102 assert (!pkt
->buffer
);
105 * Make sure the count of packets is correct.
109 pkt
= bpacket_queue_first (q
);
114 if (num_pkts
> q
->curr_count
)
117 pkt
= TAILQ_NEXT (pkt
, pkt_train
);
120 assert (num_pkts
== q
->curr_count
);
125 * bpacket_queue_add_packet
127 * Internal function of bpacket_queue - and adds a
128 * packet entry to the end of the list.
130 * Users of bpacket_queue should use bpacket_queue_add instead.
132 static void bpacket_queue_add_packet(struct bpacket_queue
*q
,
135 struct bpacket
*last_pkt
;
137 if (TAILQ_EMPTY(&(q
->pkts
)))
138 TAILQ_INSERT_TAIL(&(q
->pkts
), pkt
, pkt_train
);
140 last_pkt
= bpacket_queue_last(q
);
141 TAILQ_INSERT_AFTER(&(q
->pkts
), last_pkt
, pkt
, pkt_train
);
144 if (q
->hwm_count
< q
->curr_count
)
145 q
->hwm_count
= q
->curr_count
;
149 * Adds a packet to the bpacket_queue.
151 * The stream passed is consumed by this function. So, the caller should
152 * not free or use the stream after
153 * invoking this function.
155 struct bpacket
*bpacket_queue_add(struct bpacket_queue
*q
, struct stream
*s
,
156 struct bpacket_attr_vec_arr
*vecarrp
)
159 struct bpacket
*last_pkt
;
162 pkt
= bpacket_alloc();
163 if (TAILQ_EMPTY(&(q
->pkts
))) {
167 memcpy(&pkt
->arr
, vecarrp
,
168 sizeof(struct bpacket_attr_vec_arr
));
170 bpacket_attr_vec_arr_reset(&pkt
->arr
);
171 bpacket_queue_add_packet(q
, pkt
);
172 bpacket_queue_sanity_check(q
);
177 * Fill in the new information into the current sentinel and create a
180 bpacket_queue_sanity_check(q
);
181 last_pkt
= bpacket_queue_last(q
);
182 assert(last_pkt
->buffer
== NULL
);
183 last_pkt
->buffer
= s
;
185 memcpy(&last_pkt
->arr
, vecarrp
,
186 sizeof(struct bpacket_attr_vec_arr
));
188 bpacket_attr_vec_arr_reset(&last_pkt
->arr
);
190 pkt
->ver
= last_pkt
->ver
;
192 bpacket_queue_add_packet(q
, pkt
);
194 bpacket_queue_sanity_check(q
);
198 struct bpacket
*bpacket_queue_first(struct bpacket_queue
*q
)
200 return (TAILQ_FIRST(&(q
->pkts
)));
203 struct bpacket
*bpacket_queue_last(struct bpacket_queue
*q
)
205 return TAILQ_LAST(&(q
->pkts
), pkt_queue
);
208 struct bpacket
*bpacket_queue_remove(struct bpacket_queue
*q
)
210 struct bpacket
*first
;
212 first
= bpacket_queue_first(q
);
214 TAILQ_REMOVE(&(q
->pkts
), first
, pkt_train
);
220 unsigned int bpacket_queue_length(struct bpacket_queue
*q
)
222 return q
->curr_count
- 1;
225 unsigned int bpacket_queue_hwm_length(struct bpacket_queue
*q
)
227 return q
->hwm_count
- 1;
230 int bpacket_queue_is_full(struct bgp
*bgp
, struct bpacket_queue
*q
)
232 if (q
->curr_count
>= bgp
->default_subgroup_pkt_queue_max
)
237 void bpacket_add_peer(struct bpacket
*pkt
, struct peer_af
*paf
)
242 LIST_INSERT_HEAD(&(pkt
->peers
), paf
, pkt_train
);
243 paf
->next_pkt_to_send
= pkt
;
247 * bpacket_queue_cleanup
249 void bpacket_queue_cleanup(struct bpacket_queue
*q
)
253 while ((pkt
= bpacket_queue_remove(q
))) {
259 * bpacket_queue_compact
261 * Delete packets that do not need to be transmitted to any peer from
264 * @return the number of packets deleted.
266 static int bpacket_queue_compact(struct bpacket_queue
*q
)
269 struct bpacket
*pkt
, *removed_pkt
;
274 pkt
= bpacket_queue_first(q
);
279 * Don't delete the sentinel.
284 if (!LIST_EMPTY(&(pkt
->peers
)))
287 removed_pkt
= bpacket_queue_remove(q
);
288 assert(pkt
== removed_pkt
);
289 bpacket_free(removed_pkt
);
294 bpacket_queue_sanity_check(q
);
298 void bpacket_queue_advance_peer(struct peer_af
*paf
)
301 struct bpacket
*old_pkt
;
303 old_pkt
= paf
->next_pkt_to_send
;
304 if (old_pkt
->buffer
== NULL
)
305 /* Already at end of list */
308 LIST_REMOVE(paf
, pkt_train
);
309 pkt
= TAILQ_NEXT(old_pkt
, pkt_train
);
310 bpacket_add_peer(pkt
, paf
);
312 if (!bpacket_queue_compact(PAF_PKTQ(paf
)))
316 * Deleted one or more packets. Check if we can now merge this
317 * peer's subgroup into another subgroup.
319 update_subgroup_check_merge(paf
->subgroup
, "advanced peer in queue");
323 * bpacket_queue_remove_peer
325 * Remove the peer from the packet queue of the subgroup it belongs
328 void bpacket_queue_remove_peer(struct peer_af
*paf
)
330 struct bpacket_queue
*q
;
337 LIST_REMOVE(paf
, pkt_train
);
338 paf
->next_pkt_to_send
= NULL
;
340 bpacket_queue_compact(q
);
343 unsigned int bpacket_queue_virtual_length(struct peer_af
*paf
)
346 struct bpacket
*last
;
347 struct bpacket_queue
*q
;
349 pkt
= paf
->next_pkt_to_send
;
350 if (!pkt
|| (pkt
->buffer
== NULL
))
351 /* Already at end of list */
355 if (TAILQ_EMPTY(&(q
->pkts
)))
358 last
= TAILQ_LAST(&(q
->pkts
), pkt_queue
);
359 if (last
->ver
>= pkt
->ver
)
360 return last
->ver
- pkt
->ver
;
362 /* sequence # rolled over */
363 return (UINT_MAX
- pkt
->ver
+ 1) + last
->ver
;
367 * Dump the bpacket queue
369 void bpacket_queue_show_vty(struct bpacket_queue
*q
, struct vty
*vty
)
374 pkt
= bpacket_queue_first(q
);
376 vty_out(vty
, " Packet %p ver %u buffer %p\n", pkt
, pkt
->ver
,
379 LIST_FOREACH (paf
, &(pkt
->peers
), pkt_train
) {
380 vty_out(vty
, " - %s\n", paf
->peer
->host
);
382 pkt
= bpacket_next(pkt
);
387 struct stream
*bpacket_reformat_for_peer(struct bpacket
*pkt
,
390 struct stream
*s
= NULL
;
391 bpacket_attr_vec
*vec
;
396 s
= stream_dup(pkt
->buffer
);
397 peer
= PAF_PEER(paf
);
399 vec
= &pkt
->arr
.entries
[BGP_ATTR_VEC_NH
];
400 if (CHECK_FLAG(vec
->flags
, BPKT_ATTRVEC_FLAGS_UPDATED
)) {
403 int route_map_sets_nh
;
404 nhlen
= stream_getc_from(s
, vec
->offset
);
405 if (peer_cap_enhe(peer
, paf
->afi
, paf
->safi
))
408 nhafi
= BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen
);
410 if (nhafi
== AFI_IP
) {
411 struct in_addr v4nh
, *mod_v4nh
;
413 size_t offset_nh
= vec
->offset
+ 1;
418 BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED
)
421 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
));
424 case BGP_ATTR_NHLEN_IPV4
:
426 case BGP_ATTR_NHLEN_VPNV4
:
430 /* TODO: handle IPv6 nexthops */
432 EC_BGP_INVALID_NEXTHOP_LENGTH
,
433 "%s: %s: invalid MP nexthop length (AFI IP): %u",
434 __func__
, peer
->host
, nhlen
);
439 stream_get_from(&v4nh
, s
, offset_nh
, IPV4_MAX_BYTELEN
);
443 * If route-map has set the nexthop, that is always
445 * specified as peer-address, the peering address is
447 * Otherwise, if NH is unavailable from attribute, the
449 * is picked up; the "NH unavailable" case also covers
451 * and some other scenarios -- see
452 * subgroup_announce_check(). In
453 * all other cases, use the nexthop carried in the
455 * it is EBGP non-multiaccess and there is no
456 * next-hop-unchanged setting.
457 * Note: It is assumed route-map cannot set the nexthop
461 if (route_map_sets_nh
) {
464 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
)) {
465 mod_v4nh
= &peer
->nexthop
.v4
;
468 } else if (!v4nh
.s_addr
) {
469 mod_v4nh
= &peer
->nexthop
.v4
;
472 peer
->sort
== BGP_PEER_EBGP
473 && (bgp_multiaccess_check_v4(v4nh
, peer
) == 0)
476 BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED
)
477 && !peer_af_flag_check(
478 peer
, paf
->afi
, paf
->safi
,
479 PEER_FLAG_NEXTHOP_UNCHANGED
)) {
480 /* NOTE: not handling case where NH has new AFI
482 mod_v4nh
= &peer
->nexthop
.v4
;
486 if (nh_modified
) /* allow for VPN RD */
487 stream_put_in_addr_at(s
, offset_nh
, mod_v4nh
);
489 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
490 zlog_debug("u%" PRIu64
":s%" PRIu64
491 " %s send UPDATE w/ nexthop %s%s",
492 PAF_SUBGRP(paf
)->update_group
->id
,
493 PAF_SUBGRP(paf
)->id
, peer
->host
,
494 inet_ntoa(*mod_v4nh
),
495 (nhlen
== 12 ? " and RD" : ""));
496 } else if (nhafi
== AFI_IP6
) {
497 struct in6_addr v6nhglobal
, *mod_v6nhg
;
498 struct in6_addr v6nhlocal
, *mod_v6nhl
;
499 int gnh_modified
, lnh_modified
;
500 size_t offset_nhglobal
= vec
->offset
+ 1;
501 size_t offset_nhlocal
= vec
->offset
+ 1;
503 gnh_modified
= lnh_modified
= 0;
504 mod_v6nhg
= &v6nhglobal
;
505 mod_v6nhl
= &v6nhlocal
;
510 BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED
)
513 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
));
516 * The logic here is rather similar to that for IPv4,
518 * additional work being to handle 1 or 2 nexthops.
520 * party nexthop is not propagated for EBGP right now.
523 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
525 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
526 offset_nhlocal
+= IPV6_MAX_BYTELEN
;
528 case BGP_ATTR_NHLEN_VPNV6_GLOBAL
:
529 offset_nhglobal
+= 8;
531 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
:
532 offset_nhglobal
+= 8;
533 offset_nhlocal
+= 8 * 2 + IPV6_MAX_BYTELEN
;
536 /* TODO: handle IPv4 nexthops */
538 EC_BGP_INVALID_NEXTHOP_LENGTH
,
539 "%s: %s: invalid MP nexthop length (AFI IP6): %u",
540 __func__
, peer
->host
, nhlen
);
545 stream_get_from(&v6nhglobal
, s
, offset_nhglobal
,
547 if (route_map_sets_nh
) {
550 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
)) {
551 mod_v6nhg
= &peer
->nexthop
.v6_global
;
554 } else if (IN6_IS_ADDR_UNSPECIFIED(&v6nhglobal
)) {
555 mod_v6nhg
= &peer
->nexthop
.v6_global
;
558 peer
->sort
== BGP_PEER_EBGP
561 BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED
)
562 && !peer_af_flag_check(
563 peer
, nhafi
, paf
->safi
,
564 PEER_FLAG_NEXTHOP_UNCHANGED
)) {
565 /* NOTE: not handling case where NH has new AFI
567 mod_v6nhg
= &peer
->nexthop
.v6_global
;
572 if (nhlen
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
573 || nhlen
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
) {
574 stream_get_from(&v6nhlocal
, s
, offset_nhlocal
,
576 if (IN6_IS_ADDR_UNSPECIFIED(&v6nhlocal
)) {
577 mod_v6nhl
= &peer
->nexthop
.v6_local
;
583 stream_put_in6_addr_at(s
, offset_nhglobal
,
586 stream_put_in6_addr_at(s
, offset_nhlocal
,
589 if (bgp_debug_update(peer
, NULL
, NULL
, 0)) {
590 if (nhlen
== 32 || nhlen
== 48)
592 "u%" PRIu64
":s%" PRIu64
593 " %s send UPDATE w/ mp_nexthops %s, %s%s",
596 PAF_SUBGRP(paf
)->id
, peer
->host
,
597 inet_ntop(AF_INET6
, mod_v6nhg
,
599 inet_ntop(AF_INET6
, mod_v6nhl
,
601 (nhlen
== 48 ? " and RD" : ""));
604 "u%" PRIu64
":s%" PRIu64
605 " %s send UPDATE w/ mp_nexthop %s%s",
608 PAF_SUBGRP(paf
)->id
, peer
->host
,
609 inet_ntop(AF_INET6
, mod_v6nhg
,
611 (nhlen
== 24 ? " and RD" : ""));
613 } else if (paf
->afi
== AFI_L2VPN
) {
614 struct in_addr v4nh
, *mod_v4nh
;
617 stream_get_from(&v4nh
, s
, vec
->offset
+ 1, 4);
620 /* No route-map changes allowed for EVPN nexthops. */
622 mod_v4nh
= &peer
->nexthop
.v4
;
627 stream_put_in_addr_at(s
, vec
->offset
+ 1,
630 if (bgp_debug_update(peer
, NULL
, NULL
, 0))
631 zlog_debug("u%" PRIu64
":s%" PRIu64
632 " %s send UPDATE w/ nexthop %s",
633 PAF_SUBGRP(paf
)->update_group
->id
,
634 PAF_SUBGRP(paf
)->id
, peer
->host
,
635 inet_ntoa(*mod_v4nh
));
643 * Update the vecarr offsets to go beyond 'pos' bytes, i.e. add 'pos'
646 static void bpacket_attr_vec_arr_update(struct bpacket_attr_vec_arr
*vecarr
,
654 for (i
= 0; i
< BGP_ATTR_VEC_MAX
; i
++)
655 vecarr
->entries
[i
].offset
+= pos
;
659 * Return if there are packets to build for this subgroup.
661 int subgroup_packets_to_build(struct update_subgroup
*subgrp
)
663 struct bgp_advertise
*adv
;
668 adv
= BGP_ADV_FIFO_HEAD(&subgrp
->sync
->withdraw
);
672 adv
= BGP_ADV_FIFO_HEAD(&subgrp
->sync
->update
);
679 /* Make BGP update packet. */
680 struct bpacket
*subgroup_update_packet(struct update_subgroup
*subgrp
)
682 struct bpacket_attr_vec_arr vecarr
;
686 struct stream
*snlri
;
687 struct stream
*packet
;
688 struct bgp_adj_out
*adj
;
689 struct bgp_advertise
*adv
;
690 struct bgp_node
*rn
= NULL
;
691 struct bgp_path_info
*path
= NULL
;
692 bgp_size_t total_attr_len
= 0;
693 unsigned long attrlen_pos
= 0;
694 size_t mpattrlen_pos
= 0;
695 size_t mpattr_pos
= 0;
698 int space_remaining
= 0;
699 int space_needed
= 0;
700 char send_attr_str
[BUFSIZ
];
701 int send_attr_printed
= 0;
703 int addpath_encode
= 0;
704 int addpath_overhead
= 0;
705 uint32_t addpath_tx_id
= 0;
706 struct prefix_rd
*prd
= NULL
;
707 mpls_label_t label
= MPLS_INVALID_LABEL
, *label_pnt
= NULL
;
708 uint32_t num_labels
= 0;
713 if (bpacket_queue_is_full(SUBGRP_INST(subgrp
), SUBGRP_PKTQ(subgrp
)))
716 peer
= SUBGRP_PEER(subgrp
);
717 afi
= SUBGRP_AFI(subgrp
);
718 safi
= SUBGRP_SAFI(subgrp
);
721 snlri
= subgrp
->scratch
;
724 bpacket_attr_vec_arr_reset(&vecarr
);
726 addpath_encode
= bgp_addpath_encode_tx(peer
, afi
, safi
);
727 addpath_overhead
= addpath_encode
? BGP_ADDPATH_ID_LEN
: 0;
729 adv
= BGP_ADV_FIFO_HEAD(&subgrp
->sync
->update
);
734 addpath_tx_id
= adj
->addpath_tx_id
;
737 space_remaining
= STREAM_CONCAT_REMAIN(s
, snlri
, STREAM_SIZE(s
))
738 - BGP_MAX_PACKET_SIZE_OVERFLOW
;
740 BGP_NLRI_LENGTH
+ addpath_overhead
741 + bgp_packet_mpattr_prefix_size(afi
, safi
, &rn
->p
);
743 /* When remaining space can't include NLRI and it's length. */
744 if (space_remaining
< space_needed
)
747 /* If packet is empty, set attribute. */
748 if (stream_empty(s
)) {
749 struct peer
*from
= NULL
;
754 /* 1: Write the BGP message header - 16 bytes marker, 2
756 * one byte message type.
758 bgp_packet_set_marker(s
, BGP_MSG_UPDATE
);
760 /* 2: withdrawn routes length */
763 /* 3: total attributes length - attrlen_pos stores the
765 attrlen_pos
= stream_get_endp(s
);
768 /* 4: if there is MP_REACH_NLRI attribute, that should
770 * attribute, according to
771 * draft-ietf-idr-error-handling. Save the
774 mpattr_pos
= stream_get_endp(s
);
776 /* 5: Encode all the attributes, except MP_REACH_NLRI
778 total_attr_len
= bgp_packet_attribute(
779 NULL
, peer
, s
, adv
->baa
->attr
, &vecarr
, NULL
,
780 afi
, safi
, from
, NULL
, NULL
, 0, 0, 0);
783 STREAM_CONCAT_REMAIN(s
, snlri
, STREAM_SIZE(s
))
784 - BGP_MAX_PACKET_SIZE_OVERFLOW
;
785 space_needed
= BGP_NLRI_LENGTH
+ addpath_overhead
786 + bgp_packet_mpattr_prefix_size(
789 /* If the attributes alone do not leave any room for
792 if (space_remaining
< space_needed
) {
794 EC_BGP_UPDGRP_ATTR_LEN
,
795 "u%" PRIu64
":s%" PRIu64
796 " attributes too long, cannot send UPDATE",
797 subgrp
->update_group
->id
, subgrp
->id
);
799 /* Flush the FIFO update queue */
801 adv
= bgp_advertise_clean_subgroup(
806 if (BGP_DEBUG(update
, UPDATE_OUT
)
807 || BGP_DEBUG(update
, UPDATE_PREFIX
)) {
808 memset(send_attr_str
, 0, BUFSIZ
);
809 send_attr_printed
= 0;
810 bgp_dump_attr(adv
->baa
->attr
, send_attr_str
,
815 if ((afi
== AFI_IP
&& safi
== SAFI_UNICAST
)
816 && !peer_cap_enhe(peer
, afi
, safi
))
817 stream_put_prefix_addpath(s
, &rn
->p
, addpath_encode
,
820 /* Encode the prefix in MP_REACH_NLRI attribute */
822 prd
= (struct prefix_rd
*)&rn
->prn
->p
;
824 if (safi
== SAFI_LABELED_UNICAST
) {
825 label
= bgp_adv_label(rn
, path
, peer
, afi
,
829 } else if (path
&& path
->extra
) {
830 label_pnt
= &path
->extra
->label
[0];
831 num_labels
= path
->extra
->num_labels
;
834 if (stream_empty(snlri
))
835 mpattrlen_pos
= bgp_packet_mpattr_start(
836 snlri
, peer
, afi
, safi
, &vecarr
,
839 bgp_packet_mpattr_prefix(snlri
, afi
, safi
, &rn
->p
, prd
,
840 label_pnt
, num_labels
,
841 addpath_encode
, addpath_tx_id
,
847 if (bgp_debug_update(NULL
, &rn
->p
, subgrp
->update_group
, 0)) {
848 char pfx_buf
[BGP_PRD_PATH_STRLEN
];
850 if (!send_attr_printed
) {
851 zlog_debug("u%" PRIu64
":s%" PRIu64
852 " send UPDATE w/ attr: %s",
853 subgrp
->update_group
->id
, subgrp
->id
,
855 if (!stream_empty(snlri
)) {
857 iana_safi_t pkt_safi
;
859 pkt_afi
= afi_int2iana(afi
);
860 pkt_safi
= safi_int2iana(safi
);
862 "u%" PRIu64
":s%" PRIu64
863 " send MP_REACH for afi/safi %d/%d",
864 subgrp
->update_group
->id
,
865 subgrp
->id
, pkt_afi
, pkt_safi
);
868 send_attr_printed
= 1;
871 bgp_debug_rdpfxpath2str(afi
, safi
, prd
, &rn
->p
,
872 label_pnt
, num_labels
,
873 addpath_encode
, addpath_tx_id
,
874 pfx_buf
, sizeof(pfx_buf
));
875 zlog_debug("u%" PRIu64
":s%" PRIu64
" send UPDATE %s",
876 subgrp
->update_group
->id
, subgrp
->id
,
880 /* Synchnorize attribute. */
882 bgp_attr_unintern(&adj
->attr
);
886 adj
->attr
= bgp_attr_intern(adv
->baa
->attr
);
888 adv
= bgp_advertise_clean_subgroup(subgrp
, adj
);
891 if (!stream_empty(s
)) {
892 if (!stream_empty(snlri
)) {
893 bgp_packet_mpattr_end(snlri
, mpattrlen_pos
);
894 total_attr_len
+= stream_get_endp(snlri
);
897 /* set the total attribute length correctly */
898 stream_putw_at(s
, attrlen_pos
, total_attr_len
);
900 if (!stream_empty(snlri
)) {
901 packet
= stream_dupcat(s
, snlri
, mpattr_pos
);
902 bpacket_attr_vec_arr_update(&vecarr
, mpattr_pos
);
904 packet
= stream_dup(s
);
905 bgp_packet_set_size(packet
);
906 if (bgp_debug_update(NULL
, NULL
, subgrp
->update_group
, 0))
907 zlog_debug("u%" PRIu64
":s%" PRIu64
908 " send UPDATE len %zd numpfx %d",
909 subgrp
->update_group
->id
, subgrp
->id
,
910 (stream_get_endp(packet
)
911 - stream_get_getp(packet
)),
913 pkt
= bpacket_queue_add(SUBGRP_PKTQ(subgrp
), packet
, &vecarr
);
921 /* Make BGP withdraw packet. */
923 16-octet marker | 2-octet length | 1-octet type |
924 2-octet withdrawn route length | withdrawn prefixes | 2-octet attrlen (=0)
926 /* For other afi/safis:
927 16-octet marker | 2-octet length | 1-octet type |
928 2-octet withdrawn route length (=0) | 2-octet attrlen |
929 mp_unreach attr type | attr len | afi | safi | withdrawn prefixes
931 struct bpacket
*subgroup_withdraw_packet(struct update_subgroup
*subgrp
)
935 struct bgp_adj_out
*adj
;
936 struct bgp_advertise
*adv
;
939 bgp_size_t unfeasible_len
;
940 bgp_size_t total_attr_len
;
942 size_t attrlen_pos
= 0;
943 size_t mplen_pos
= 0;
944 uint8_t first_time
= 1;
947 int space_remaining
= 0;
948 int space_needed
= 0;
950 int addpath_encode
= 0;
951 int addpath_overhead
= 0;
952 uint32_t addpath_tx_id
= 0;
953 struct prefix_rd
*prd
= NULL
;
959 if (bpacket_queue_is_full(SUBGRP_INST(subgrp
), SUBGRP_PKTQ(subgrp
)))
962 peer
= SUBGRP_PEER(subgrp
);
963 afi
= SUBGRP_AFI(subgrp
);
964 safi
= SUBGRP_SAFI(subgrp
);
967 addpath_encode
= bgp_addpath_encode_tx(peer
, afi
, safi
);
968 addpath_overhead
= addpath_encode
? BGP_ADDPATH_ID_LEN
: 0;
970 while ((adv
= BGP_ADV_FIFO_HEAD(&subgrp
->sync
->withdraw
)) != NULL
) {
974 addpath_tx_id
= adj
->addpath_tx_id
;
977 STREAM_WRITEABLE(s
) - BGP_MAX_PACKET_SIZE_OVERFLOW
;
979 BGP_NLRI_LENGTH
+ addpath_overhead
+ BGP_TOTAL_ATTR_LEN
980 + bgp_packet_mpattr_prefix_size(afi
, safi
, &rn
->p
);
982 if (space_remaining
< space_needed
)
985 if (stream_empty(s
)) {
986 bgp_packet_set_marker(s
, BGP_MSG_UPDATE
);
987 stream_putw(s
, 0); /* unfeasible routes length */
991 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
992 && !peer_cap_enhe(peer
, afi
, safi
))
993 stream_put_prefix_addpath(s
, &rn
->p
, addpath_encode
,
997 prd
= (struct prefix_rd
*)&rn
->prn
->p
;
999 /* If first time, format the MP_UNREACH header */
1002 iana_safi_t pkt_safi
;
1004 pkt_afi
= afi_int2iana(afi
);
1005 pkt_safi
= safi_int2iana(safi
);
1007 attrlen_pos
= stream_get_endp(s
);
1008 /* total attr length = 0 for now. reevaluate
1011 mp_start
= stream_get_endp(s
);
1012 mplen_pos
= bgp_packet_mpunreach_start(s
, afi
,
1014 if (bgp_debug_update(NULL
, NULL
,
1015 subgrp
->update_group
, 0))
1017 "u%" PRIu64
":s%" PRIu64
1018 " send MP_UNREACH for afi/safi %d/%d",
1019 subgrp
->update_group
->id
,
1020 subgrp
->id
, pkt_afi
, pkt_safi
);
1023 bgp_packet_mpunreach_prefix(s
, &rn
->p
, afi
, safi
, prd
,
1024 NULL
, 0, addpath_encode
,
1025 addpath_tx_id
, NULL
);
1030 if (bgp_debug_update(NULL
, &rn
->p
, subgrp
->update_group
, 0)) {
1031 char pfx_buf
[BGP_PRD_PATH_STRLEN
];
1033 bgp_debug_rdpfxpath2str(afi
, safi
, prd
, &rn
->p
, NULL
, 0,
1034 addpath_encode
, addpath_tx_id
,
1035 pfx_buf
, sizeof(pfx_buf
));
1036 zlog_debug("u%" PRIu64
":s%" PRIu64
1037 " send UPDATE %s -- unreachable",
1038 subgrp
->update_group
->id
, subgrp
->id
,
1044 bgp_adj_out_remove_subgroup(rn
, adj
, subgrp
);
1045 bgp_unlock_node(rn
);
1048 if (!stream_empty(s
)) {
1049 if (afi
== AFI_IP
&& safi
== SAFI_UNICAST
1050 && !peer_cap_enhe(peer
, afi
, safi
)) {
1051 unfeasible_len
= stream_get_endp(s
) - BGP_HEADER_SIZE
1052 - BGP_UNFEASIBLE_LEN
;
1053 stream_putw_at(s
, BGP_HEADER_SIZE
, unfeasible_len
);
1056 /* Set the mp_unreach attr's length */
1057 bgp_packet_mpunreach_end(s
, mplen_pos
);
1059 /* Set total path attribute length. */
1060 total_attr_len
= stream_get_endp(s
) - mp_start
;
1061 stream_putw_at(s
, attrlen_pos
, total_attr_len
);
1063 bgp_packet_set_size(s
);
1064 if (bgp_debug_update(NULL
, NULL
, subgrp
->update_group
, 0))
1065 zlog_debug("u%" PRIu64
":s%" PRIu64
1066 " send UPDATE (withdraw) len %zd numpfx %d",
1067 subgrp
->update_group
->id
, subgrp
->id
,
1068 (stream_get_endp(s
) - stream_get_getp(s
)),
1070 pkt
= bpacket_queue_add(SUBGRP_PKTQ(subgrp
), stream_dup(s
),
1079 void subgroup_default_update_packet(struct update_subgroup
*subgrp
,
1080 struct attr
*attr
, struct peer
*from
)
1086 bgp_size_t total_attr_len
;
1089 struct bpacket_attr_vec_arr vecarr
;
1090 int addpath_encode
= 0;
1092 if (DISABLE_BGP_ANNOUNCE
)
1098 peer
= SUBGRP_PEER(subgrp
);
1099 afi
= SUBGRP_AFI(subgrp
);
1100 safi
= SUBGRP_SAFI(subgrp
);
1101 bpacket_attr_vec_arr_reset(&vecarr
);
1102 addpath_encode
= bgp_addpath_encode_tx(peer
, afi
, safi
);
1104 memset(&p
, 0, sizeof(p
));
1105 p
.family
= afi2family(afi
);
1108 /* Logging the attribute. */
1109 if (bgp_debug_update(NULL
, &p
, subgrp
->update_group
, 0)) {
1110 char attrstr
[BUFSIZ
];
1111 char buf
[PREFIX_STRLEN
];
1112 /* ' with addpath ID ' 17
1113 * max strlen of uint32 + 10
1114 * +/- (just in case) + 1
1115 * null terminator + 1
1116 * ============================ 29 */
1121 bgp_dump_attr(attr
, attrstr
, BUFSIZ
);
1124 snprintf(tx_id_buf
, sizeof(tx_id_buf
),
1125 " with addpath ID %u",
1126 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
);
1128 tx_id_buf
[0] = '\0';
1130 zlog_debug("u%" PRIu64
":s%" PRIu64
" send UPDATE %s%s %s",
1131 (SUBGRP_UPDGRP(subgrp
))->id
, subgrp
->id
,
1132 prefix2str(&p
, buf
, sizeof(buf
)), tx_id_buf
,
1136 s
= stream_new(BGP_MAX_PACKET_SIZE
);
1138 /* Make BGP update packet. */
1139 bgp_packet_set_marker(s
, BGP_MSG_UPDATE
);
1141 /* Unfeasible Routes Length. */
1144 /* Make place for total attribute length. */
1145 pos
= stream_get_endp(s
);
1147 total_attr_len
= bgp_packet_attribute(
1148 NULL
, peer
, s
, attr
, &vecarr
, &p
, afi
, safi
, from
, NULL
, NULL
,
1149 0, addpath_encode
, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
);
1151 /* Set Total Path Attribute Length. */
1152 stream_putw_at(s
, pos
, total_attr_len
);
1155 if (p
.family
== AF_INET
&& safi
== SAFI_UNICAST
1156 && !peer_cap_enhe(peer
, afi
, safi
))
1157 stream_put_prefix_addpath(
1158 s
, &p
, addpath_encode
,
1159 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
);
1162 bgp_packet_set_size(s
);
1164 (void)bpacket_queue_add(SUBGRP_PKTQ(subgrp
), s
, &vecarr
);
1165 subgroup_trigger_write(subgrp
);
1168 void subgroup_default_withdraw_packet(struct update_subgroup
*subgrp
)
1173 unsigned long attrlen_pos
= 0;
1175 bgp_size_t unfeasible_len
;
1176 bgp_size_t total_attr_len
= 0;
1177 size_t mp_start
= 0;
1178 size_t mplen_pos
= 0;
1181 int addpath_encode
= 0;
1183 if (DISABLE_BGP_ANNOUNCE
)
1186 peer
= SUBGRP_PEER(subgrp
);
1187 afi
= SUBGRP_AFI(subgrp
);
1188 safi
= SUBGRP_SAFI(subgrp
);
1189 addpath_encode
= bgp_addpath_encode_tx(peer
, afi
, safi
);
1191 memset(&p
, 0, sizeof(p
));
1192 p
.family
= afi2family(afi
);
1195 if (bgp_debug_update(NULL
, &p
, subgrp
->update_group
, 0)) {
1196 char buf
[PREFIX_STRLEN
];
1197 /* ' with addpath ID ' 17
1198 * max strlen of uint32 + 10
1199 * +/- (just in case) + 1
1200 * null terminator + 1
1201 * ============================ 29 */
1205 snprintf(tx_id_buf
, sizeof(tx_id_buf
),
1206 " with addpath ID %u",
1207 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
);
1209 zlog_debug("u%" PRIu64
":s%" PRIu64
1210 " send UPDATE %s%s -- unreachable",
1211 (SUBGRP_UPDGRP(subgrp
))->id
, subgrp
->id
,
1212 prefix2str(&p
, buf
, sizeof(buf
)), tx_id_buf
);
1215 s
= stream_new(BGP_MAX_PACKET_SIZE
);
1217 /* Make BGP update packet. */
1218 bgp_packet_set_marker(s
, BGP_MSG_UPDATE
);
1220 /* Unfeasible Routes Length. */;
1221 cp
= stream_get_endp(s
);
1224 /* Withdrawn Routes. */
1225 if (p
.family
== AF_INET
&& safi
== SAFI_UNICAST
1226 && !peer_cap_enhe(peer
, afi
, safi
)) {
1227 stream_put_prefix_addpath(
1228 s
, &p
, addpath_encode
,
1229 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
);
1231 unfeasible_len
= stream_get_endp(s
) - cp
- 2;
1233 /* Set unfeasible len. */
1234 stream_putw_at(s
, cp
, unfeasible_len
);
1236 /* Set total path attribute length. */
1239 attrlen_pos
= stream_get_endp(s
);
1241 mp_start
= stream_get_endp(s
);
1242 mplen_pos
= bgp_packet_mpunreach_start(s
, afi
, safi
);
1243 bgp_packet_mpunreach_prefix(
1244 s
, &p
, afi
, safi
, NULL
, NULL
, 0, addpath_encode
,
1245 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE
, NULL
);
1247 /* Set the mp_unreach attr's length */
1248 bgp_packet_mpunreach_end(s
, mplen_pos
);
1250 /* Set total path attribute length. */
1251 total_attr_len
= stream_get_endp(s
) - mp_start
;
1252 stream_putw_at(s
, attrlen_pos
, total_attr_len
);
1255 bgp_packet_set_size(s
);
1257 (void)bpacket_queue_add(SUBGRP_PKTQ(subgrp
), s
, NULL
);
1258 subgroup_trigger_write(subgrp
);
1262 bpacket_vec_arr_inherit_attr_flags(struct bpacket_attr_vec_arr
*vecarr
,
1263 bpacket_attr_vec_type type
,
1266 if (CHECK_FLAG(attr
->rmap_change_flags
,
1267 BATTR_RMAP_NEXTHOP_PEER_ADDRESS
))
1268 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1269 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS
);
1271 if (CHECK_FLAG(attr
->rmap_change_flags
, BATTR_REFLECTED
))
1272 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1273 BPKT_ATTRVEC_FLAGS_REFLECTED
);
1275 if (CHECK_FLAG(attr
->rmap_change_flags
, BATTR_RMAP_NEXTHOP_UNCHANGED
))
1276 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1277 BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED
);
1279 if (CHECK_FLAG(attr
->rmap_change_flags
, BATTR_RMAP_IPV4_NHOP_CHANGED
))
1280 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1281 BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED
);
1283 if (CHECK_FLAG(attr
->rmap_change_flags
,
1284 BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED
))
1285 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1286 BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED
);
1288 if (CHECK_FLAG(attr
->rmap_change_flags
,
1289 BATTR_RMAP_IPV6_LL_NHOP_CHANGED
))
1290 SET_FLAG(vecarr
->entries
[BGP_ATTR_VEC_NH
].flags
,
1291 BPKT_ATTRVEC_FLAGS_RMAP_IPV6_LNH_CHANGED
);
1294 /* Reset the Attributes vector array. The vector array is used to override
1295 * certain output parameters in the packet for a particular peer
1297 void bpacket_attr_vec_arr_reset(struct bpacket_attr_vec_arr
*vecarr
)
1305 while (i
< BGP_ATTR_VEC_MAX
) {
1306 vecarr
->entries
[i
].flags
= 0;
1307 vecarr
->entries
[i
].offset
= 0;
1312 /* Setup a particular node entry in the vecarr */
1313 void bpacket_attr_vec_arr_set_vec(struct bpacket_attr_vec_arr
*vecarr
,
1314 bpacket_attr_vec_type type
, struct stream
*s
,
1319 assert(type
< BGP_ATTR_VEC_MAX
);
1321 SET_FLAG(vecarr
->entries
[type
].flags
, BPKT_ATTRVEC_FLAGS_UPDATED
);
1322 vecarr
->entries
[type
].offset
= stream_get_endp(s
);
1324 bpacket_vec_arr_inherit_attr_flags(vecarr
, type
, attr
);