]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_updgrp_packet.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgp_updgrp_packet.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
3f9c7369
DS
2/**
3 * bgp_updgrp_packet.c: BGP update group packet handling routines
4 *
5 * @copyright Copyright (C) 2014 Cumulus Networks, Inc.
6 *
7 * @author Avneesh Sachdev <avneesh@sproute.net>
8 * @author Rajesh Varadarajan <rajesh@sproute.net>
9 * @author Pradosh Mohapatra <pradosh@sproute.net>
3f9c7369
DS
10 */
11
12#include <zebra.h>
13
14#include "prefix.h"
15#include "thread.h"
16#include "buffer.h"
17#include "stream.h"
18#include "command.h"
19#include "sockunion.h"
20#include "network.h"
21#include "memory.h"
22#include "filter.h"
23#include "routemap.h"
3f9c7369
DS
24#include "log.h"
25#include "plist.h"
26#include "linklist.h"
27#include "workqueue.h"
28#include "hash.h"
29#include "queue.h"
cd1964ff 30#include "mpls.h"
3f9c7369
DS
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_debug.h"
14454c9f 34#include "bgpd/bgp_errors.h"
3f9c7369
DS
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"
906ad49b 42#include "bgpd/bgp_mplsvpn.h"
cd1964ff 43#include "bgpd/bgp_label.h"
dcc68b5e 44#include "bgpd/bgp_addpath.h"
3f9c7369
DS
45
46/********************
47 * PRIVATE FUNCTIONS
48 ********************/
49
50/********************
51 * PUBLIC FUNCTIONS
52 ********************/
4d762f26 53struct bpacket *bpacket_alloc(void)
3f9c7369 54{
d62a17ae 55 struct bpacket *pkt;
3f9c7369 56
9f5dc319 57 pkt = XCALLOC(MTYPE_BGP_PACKET, sizeof(struct bpacket));
3f9c7369 58
d62a17ae 59 return pkt;
3f9c7369
DS
60}
61
d62a17ae 62void bpacket_free(struct bpacket *pkt)
3f9c7369 63{
d62a17ae 64 if (pkt->buffer)
65 stream_free(pkt->buffer);
66 pkt->buffer = NULL;
67 XFREE(MTYPE_BGP_PACKET, pkt);
3f9c7369
DS
68}
69
d62a17ae 70void bpacket_queue_init(struct bpacket_queue *q)
3f9c7369 71{
d62a17ae 72 TAILQ_INIT(&(q->pkts));
3f9c7369
DS
73}
74
3f9c7369
DS
75/*
76 * bpacket_queue_add_packet
77 *
78 * Internal function of bpacket_queue - and adds a
79 * packet entry to the end of the list.
80 *
81 * Users of bpacket_queue should use bpacket_queue_add instead.
82 */
d62a17ae 83static void bpacket_queue_add_packet(struct bpacket_queue *q,
84 struct bpacket *pkt)
3f9c7369 85{
d62a17ae 86 struct bpacket *last_pkt;
3f9c7369 87
d62a17ae 88 if (TAILQ_EMPTY(&(q->pkts)))
89 TAILQ_INSERT_TAIL(&(q->pkts), pkt, pkt_train);
90 else {
91 last_pkt = bpacket_queue_last(q);
92 TAILQ_INSERT_AFTER(&(q->pkts), last_pkt, pkt, pkt_train);
93 }
94 q->curr_count++;
95 if (q->hwm_count < q->curr_count)
96 q->hwm_count = q->curr_count;
3f9c7369
DS
97}
98
99/*
100 * Adds a packet to the bpacket_queue.
101 *
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.
105 */
d62a17ae 106struct bpacket *bpacket_queue_add(struct bpacket_queue *q, struct stream *s,
107 struct bpacket_attr_vec_arr *vecarrp)
3f9c7369 108{
d62a17ae 109 struct bpacket *pkt;
110 struct bpacket *last_pkt;
111
112
113 pkt = bpacket_alloc();
114 if (TAILQ_EMPTY(&(q->pkts))) {
115 pkt->ver = 1;
116 pkt->buffer = s;
117 if (vecarrp)
118 memcpy(&pkt->arr, vecarrp,
119 sizeof(struct bpacket_attr_vec_arr));
120 else
121 bpacket_attr_vec_arr_reset(&pkt->arr);
122 bpacket_queue_add_packet(q, pkt);
d62a17ae 123 return pkt;
124 }
3f9c7369 125
d62a17ae 126 /*
127 * Fill in the new information into the current sentinel and create a
128 * new sentinel.
129 */
d62a17ae 130 last_pkt = bpacket_queue_last(q);
131 assert(last_pkt->buffer == NULL);
132 last_pkt->buffer = s;
133 if (vecarrp)
134 memcpy(&last_pkt->arr, vecarrp,
135 sizeof(struct bpacket_attr_vec_arr));
136 else
137 bpacket_attr_vec_arr_reset(&last_pkt->arr);
138
139 pkt->ver = last_pkt->ver;
140 pkt->ver++;
141 bpacket_queue_add_packet(q, pkt);
142
d62a17ae 143 return last_pkt;
3f9c7369
DS
144}
145
d62a17ae 146struct bpacket *bpacket_queue_first(struct bpacket_queue *q)
3f9c7369 147{
d62a17ae 148 return (TAILQ_FIRST(&(q->pkts)));
3f9c7369
DS
149}
150
d62a17ae 151struct bpacket *bpacket_queue_last(struct bpacket_queue *q)
3f9c7369 152{
d62a17ae 153 return TAILQ_LAST(&(q->pkts), pkt_queue);
3f9c7369
DS
154}
155
d62a17ae 156struct bpacket *bpacket_queue_remove(struct bpacket_queue *q)
3f9c7369 157{
d62a17ae 158 struct bpacket *first;
3f9c7369 159
d62a17ae 160 first = bpacket_queue_first(q);
161 if (first) {
162 TAILQ_REMOVE(&(q->pkts), first, pkt_train);
163 q->curr_count--;
164 }
165 return first;
3f9c7369
DS
166}
167
d62a17ae 168unsigned int bpacket_queue_length(struct bpacket_queue *q)
3f9c7369 169{
d62a17ae 170 return q->curr_count - 1;
3f9c7369
DS
171}
172
d62a17ae 173unsigned int bpacket_queue_hwm_length(struct bpacket_queue *q)
3f9c7369 174{
d62a17ae 175 return q->hwm_count - 1;
3f9c7369
DS
176}
177
3dc339cd 178bool bpacket_queue_is_full(struct bgp *bgp, struct bpacket_queue *q)
3f9c7369 179{
d62a17ae 180 if (q->curr_count >= bgp->default_subgroup_pkt_queue_max)
3dc339cd
DA
181 return true;
182 return false;
3f9c7369
DS
183}
184
d62a17ae 185void bpacket_add_peer(struct bpacket *pkt, struct peer_af *paf)
3f9c7369 186{
d62a17ae 187 if (!pkt || !paf)
188 return;
3f9c7369 189
d62a17ae 190 LIST_INSERT_HEAD(&(pkt->peers), paf, pkt_train);
191 paf->next_pkt_to_send = pkt;
3f9c7369
DS
192}
193
194/*
195 * bpacket_queue_cleanup
196 */
d62a17ae 197void bpacket_queue_cleanup(struct bpacket_queue *q)
3f9c7369 198{
d62a17ae 199 struct bpacket *pkt;
3f9c7369 200
d62a17ae 201 while ((pkt = bpacket_queue_remove(q))) {
202 bpacket_free(pkt);
203 }
3f9c7369
DS
204}
205
206/*
207 * bpacket_queue_compact
208 *
209 * Delete packets that do not need to be transmitted to any peer from
210 * the queue.
211 *
212 * @return the number of packets deleted.
213 */
d62a17ae 214static int bpacket_queue_compact(struct bpacket_queue *q)
3f9c7369 215{
d62a17ae 216 int num_deleted;
217 struct bpacket *pkt, *removed_pkt;
3f9c7369 218
d62a17ae 219 num_deleted = 0;
3f9c7369 220
d62a17ae 221 while (1) {
222 pkt = bpacket_queue_first(q);
223 if (!pkt)
224 break;
3f9c7369 225
d62a17ae 226 /*
227 * Don't delete the sentinel.
228 */
229 if (!pkt->buffer)
230 break;
3f9c7369 231
d62a17ae 232 if (!LIST_EMPTY(&(pkt->peers)))
233 break;
3f9c7369 234
d62a17ae 235 removed_pkt = bpacket_queue_remove(q);
236 assert(pkt == removed_pkt);
237 bpacket_free(removed_pkt);
3f9c7369 238
d62a17ae 239 num_deleted++;
240 }
3f9c7369 241
d62a17ae 242 return num_deleted;
3f9c7369
DS
243}
244
d62a17ae 245void bpacket_queue_advance_peer(struct peer_af *paf)
3f9c7369 246{
d62a17ae 247 struct bpacket *pkt;
248 struct bpacket *old_pkt;
249
250 old_pkt = paf->next_pkt_to_send;
251 if (old_pkt->buffer == NULL)
252 /* Already at end of list */
253 return;
254
255 LIST_REMOVE(paf, pkt_train);
256 pkt = TAILQ_NEXT(old_pkt, pkt_train);
257 bpacket_add_peer(pkt, paf);
258
259 if (!bpacket_queue_compact(PAF_PKTQ(paf)))
260 return;
261
262 /*
263 * Deleted one or more packets. Check if we can now merge this
264 * peer's subgroup into another subgroup.
265 */
266 update_subgroup_check_merge(paf->subgroup, "advanced peer in queue");
3f9c7369
DS
267}
268
269/*
270 * bpacket_queue_remove_peer
271 *
272 * Remove the peer from the packet queue of the subgroup it belongs
273 * to.
274 */
d62a17ae 275void bpacket_queue_remove_peer(struct peer_af *paf)
3f9c7369 276{
d62a17ae 277 struct bpacket_queue *q;
3f9c7369 278
d62a17ae 279 q = PAF_PKTQ(paf);
280 assert(q);
3f9c7369 281
d62a17ae 282 LIST_REMOVE(paf, pkt_train);
283 paf->next_pkt_to_send = NULL;
3f9c7369 284
d62a17ae 285 bpacket_queue_compact(q);
3f9c7369
DS
286}
287
d62a17ae 288unsigned int bpacket_queue_virtual_length(struct peer_af *paf)
3f9c7369 289{
d62a17ae 290 struct bpacket *pkt;
291 struct bpacket *last;
292 struct bpacket_queue *q;
3f9c7369 293
d62a17ae 294 pkt = paf->next_pkt_to_send;
295 if (!pkt || (pkt->buffer == NULL))
296 /* Already at end of list */
297 return 0;
3f9c7369 298
d62a17ae 299 q = PAF_PKTQ(paf);
300 if (TAILQ_EMPTY(&(q->pkts)))
301 return 0;
3f9c7369 302
d62a17ae 303 last = TAILQ_LAST(&(q->pkts), pkt_queue);
304 if (last->ver >= pkt->ver)
305 return last->ver - pkt->ver;
3f9c7369 306
d62a17ae 307 /* sequence # rolled over */
308 return (UINT_MAX - pkt->ver + 1) + last->ver;
3f9c7369
DS
309}
310
311/*
312 * Dump the bpacket queue
313 */
d62a17ae 314void bpacket_queue_show_vty(struct bpacket_queue *q, struct vty *vty)
3f9c7369 315{
d62a17ae 316 struct bpacket *pkt;
317 struct peer_af *paf;
318
319 pkt = bpacket_queue_first(q);
320 while (pkt) {
321 vty_out(vty, " Packet %p ver %u buffer %p\n", pkt, pkt->ver,
322 pkt->buffer);
323
a2addae8 324 LIST_FOREACH (paf, &(pkt->peers), pkt_train) {
d62a17ae 325 vty_out(vty, " - %s\n", paf->peer->host);
326 }
327 pkt = bpacket_next(pkt);
328 }
329 return;
3f9c7369
DS
330}
331
d62a17ae 332struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
333 struct peer_af *paf)
3f9c7369 334{
d62a17ae 335 struct stream *s = NULL;
336 bpacket_attr_vec *vec;
337 struct peer *peer;
1c875ddb 338 struct bgp_filter *filter;
d62a17ae 339
340 s = stream_dup(pkt->buffer);
341 peer = PAF_PEER(paf);
342
343 vec = &pkt->arr.entries[BGP_ATTR_VEC_NH];
d62a17ae 344
f041034e
DS
345 if (!CHECK_FLAG(vec->flags, BPKT_ATTRVEC_FLAGS_UPDATED))
346 return s;
347
348 uint8_t nhlen;
349 afi_t nhafi;
350 int route_map_sets_nh;
351
352 nhlen = stream_getc_from(s, vec->offset);
353 filter = &peer->filter[paf->afi][paf->safi];
354
355 if (peer_cap_enhe(peer, paf->afi, paf->safi))
356 nhafi = AFI_IP6;
357 else
358 nhafi = BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen);
359
360 if (nhafi == AFI_IP) {
361 struct in_addr v4nh, *mod_v4nh;
362 int nh_modified = 0;
363 size_t offset_nh = vec->offset + 1;
364
365 route_map_sets_nh =
366 (CHECK_FLAG(vec->flags,
6eeb9255
DA
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));
f041034e
DS
372
373 switch (nhlen) {
374 case BGP_ATTR_NHLEN_IPV4:
375 break;
376 case BGP_ATTR_NHLEN_VPNV4:
377 offset_nh += 8;
378 break;
379 default:
380 /* TODO: handle IPv6 nexthops */
381 flog_warn(
382 EC_BGP_INVALID_NEXTHOP_LENGTH,
383 "%s: %s: invalid MP nexthop length (AFI IP): %u",
384 __func__, peer->host, nhlen);
385 stream_free(s);
386 return NULL;
387 }
388
389 stream_get_from(&v4nh, s, offset_nh, IPV4_MAX_BYTELEN);
390 mod_v4nh = &v4nh;
391
392 /*
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.
408 */
409 if (route_map_sets_nh
410 && ((peer->sort != BGP_PEER_EBGP)
411 || ROUTE_MAP_OUT(filter))) {
412 if (CHECK_FLAG(
413 vec->flags,
414 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) {
d62a17ae 415 mod_v4nh = &peer->nexthop.v4;
416 nh_modified = 1;
417 }
f041034e
DS
418 } else if (v4nh.s_addr == INADDR_ANY) {
419 mod_v4nh = &peer->nexthop.v4;
420 nh_modified = 1;
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
429 */
430 mod_v4nh = &peer->nexthop.v4;
431 nh_modified = 1;
432 }
d62a17ae 433
f041034e
DS
434 if (nh_modified) /* allow for VPN RD */
435 stream_put_in_addr_at(s, offset_nh, mod_v4nh);
436
437 if (bgp_debug_update(peer, NULL, NULL, 0))
23d0a753
DA
438 zlog_debug("u%" PRIu64 ":s%" PRIu64
439 " %s send UPDATE w/ nexthop %pI4%s",
f041034e 440 PAF_SUBGRP(paf)->update_group->id,
23d0a753 441 PAF_SUBGRP(paf)->id, peer->host, mod_v4nh,
3ddd6994
DA
442 (nhlen == BGP_ATTR_NHLEN_VPNV4 ? " and RD"
443 : ""));
f041034e
DS
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;
450
451 gnh_modified = lnh_modified = 0;
452 mod_v6nhg = &v6nhglobal;
453 mod_v6nhl = &v6nhlocal;
454
455 route_map_sets_nh =
456 (CHECK_FLAG(vec->flags,
6eeb9255
DA
457 BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED) ||
458 CHECK_FLAG(
f041034e 459 vec->flags,
6eeb9255
DA
460 BPKT_ATTRVEC_FLAGS_RMAP_VPNV6_GNH_CHANGED) ||
461 CHECK_FLAG(vec->flags,
462 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS));
d62a17ae 463
f041034e
DS
464 /*
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
468 * right now.
469 */
470 switch (nhlen) {
471 case BGP_ATTR_NHLEN_IPV6_GLOBAL:
472 break;
473 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
474 offset_nhlocal += IPV6_MAX_BYTELEN;
475 break;
476 case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
477 offset_nhglobal += 8;
478 break;
479 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL:
480 offset_nhglobal += 8;
481 offset_nhlocal += 8 * 2 + IPV6_MAX_BYTELEN;
482 break;
483 default:
484 /* TODO: handle IPv4 nexthops */
485 flog_warn(
486 EC_BGP_INVALID_NEXTHOP_LENGTH,
487 "%s: %s: invalid MP nexthop length (AFI IP6): %u",
488 __func__, peer->host, nhlen);
489 stream_free(s);
490 return NULL;
491 }
d62a17ae 492
f041034e
DS
493 stream_get_from(&v6nhglobal, s, offset_nhglobal,
494 IPV6_MAX_BYTELEN);
1c875ddb 495
f041034e
DS
496 /*
497 * Updates to an EBGP peer should only modify the
498 * next-hop if it was set in an outbound route-map
499 * to that peer.
500 */
501 if (route_map_sets_nh
502 && ((peer->sort != BGP_PEER_EBGP)
503 || ROUTE_MAP_OUT(filter))) {
504 if (CHECK_FLAG(
505 vec->flags,
506 BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) {
d62a17ae 507 mod_v6nhg = &peer->nexthop.v6_global;
508 gnh_modified = 1;
509 }
f041034e
DS
510 } else if (IN6_IS_ADDR_UNSPECIFIED(&v6nhglobal)) {
511 mod_v6nhg = &peer->nexthop.v6_global;
512 gnh_modified = 1;
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(
5b786189 518 peer, paf->afi, paf->safi,
f041034e
DS
519 PEER_FLAG_NEXTHOP_UNCHANGED)) {
520 /* NOTE: not handling case where NH has new AFI
521 */
522 mod_v6nhg = &peer->nexthop.v6_global;
523 gnh_modified = 1;
524 }
d62a17ae 525
92d6f769 526 if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) {
3a6290bd 527 if (peer->nexthop.v4.s_addr != INADDR_ANY) {
92d6f769
K
528 ipv4_to_ipv4_mapped_ipv6(mod_v6nhg,
529 peer->nexthop.v4);
530 }
531 }
532
533 if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) {
534 mod_v6nhg = &peer->nexthop.v6_global;
535 gnh_modified = 1;
536 }
537
f041034e
DS
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,
541 IPV6_MAX_BYTELEN);
542 if (IN6_IS_ADDR_UNSPECIFIED(&v6nhlocal)) {
543 mod_v6nhl = &peer->nexthop.v6_local;
544 lnh_modified = 1;
d62a17ae 545 }
f041034e 546 }
d62a17ae 547
f041034e
DS
548 if (gnh_modified)
549 stream_put_in6_addr_at(s, offset_nhglobal, mod_v6nhg);
550 if (lnh_modified)
551 stream_put_in6_addr_at(s, offset_nhlocal, mod_v6nhl);
552
553 if (bgp_debug_update(peer, NULL, NULL, 0)) {
3ddd6994
DA
554 if (nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
555 || nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
f041034e 556 zlog_debug(
c0d72166
DS
557 "u%" PRIu64 ":s%" PRIu64
558 " %s send UPDATE w/ mp_nexthops %pI6, %pI6%s",
f041034e
DS
559 PAF_SUBGRP(paf)->update_group->id,
560 PAF_SUBGRP(paf)->id, peer->host,
c0d72166 561 mod_v6nhg, mod_v6nhl,
3ddd6994
DA
562 (nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
563 ? " and RD"
564 : ""));
f041034e 565 else
c0d72166
DS
566 zlog_debug(
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,
571 mod_v6nhg,
572 (nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL
573 ? " and RD"
574 : ""));
f041034e
DS
575 }
576 } else if (paf->afi == AFI_L2VPN) {
577 struct in_addr v4nh, *mod_v4nh;
578 int nh_modified = 0;
579
580 stream_get_from(&v4nh, s, vec->offset + 1, 4);
581 mod_v4nh = &v4nh;
582
583 /* No route-map changes allowed for EVPN nexthops. */
584 if (v4nh.s_addr == INADDR_ANY) {
585 mod_v4nh = &peer->nexthop.v4;
586 nh_modified = 1;
d62a17ae 587 }
f041034e
DS
588
589 if (nh_modified)
590 stream_put_in_addr_at(s, vec->offset + 1, mod_v4nh);
591
592 if (bgp_debug_update(peer, NULL, NULL, 0))
23d0a753
DA
593 zlog_debug("u%" PRIu64 ":s%" PRIu64
594 " %s send UPDATE w/ nexthop %pI4",
f041034e 595 PAF_SUBGRP(paf)->update_group->id,
23d0a753 596 PAF_SUBGRP(paf)->id, peer->host, mod_v4nh);
3f9c7369 597 }
3f9c7369 598
d62a17ae 599 return s;
3f9c7369
DS
600}
601
602/*
603 * Update the vecarr offsets to go beyond 'pos' bytes, i.e. add 'pos'
604 * to each offset.
605 */
d62a17ae 606static void bpacket_attr_vec_arr_update(struct bpacket_attr_vec_arr *vecarr,
607 size_t pos)
3f9c7369 608{
d62a17ae 609 int i;
3f9c7369 610
d62a17ae 611 if (!vecarr)
612 return;
3f9c7369 613
d62a17ae 614 for (i = 0; i < BGP_ATTR_VEC_MAX; i++)
615 vecarr->entries[i].offset += pos;
3f9c7369
DS
616}
617
618/*
619 * Return if there are packets to build for this subgroup.
620 */
3dc339cd 621bool subgroup_packets_to_build(struct update_subgroup *subgrp)
3f9c7369 622{
d62a17ae 623 struct bgp_advertise *adv;
3f9c7369 624
d62a17ae 625 if (!subgrp)
3dc339cd 626 return false;
3f9c7369 627
a274fef8 628 adv = bgp_adv_fifo_first(&subgrp->sync->withdraw);
d62a17ae 629 if (adv)
3dc339cd 630 return true;
3f9c7369 631
a274fef8 632 adv = bgp_adv_fifo_first(&subgrp->sync->update);
d62a17ae 633 if (adv)
3dc339cd 634 return true;
3f9c7369 635
3dc339cd 636 return false;
3f9c7369
DS
637}
638
639/* Make BGP update packet. */
d62a17ae 640struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
3f9c7369 641{
d62a17ae 642 struct bpacket_attr_vec_arr vecarr;
643 struct bpacket *pkt;
644 struct peer *peer;
645 struct stream *s;
646 struct stream *snlri;
647 struct stream *packet;
648 struct bgp_adj_out *adj;
649 struct bgp_advertise *adv;
9bcb3eef 650 struct bgp_dest *dest = NULL;
9b6d8fcf 651 struct bgp_path_info *path = NULL;
d62a17ae 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;
656 afi_t afi;
657 safi_t safi;
658 int space_remaining = 0;
659 int space_needed = 0;
660 char send_attr_str[BUFSIZ];
661 int send_attr_printed = 0;
662 int num_pfx = 0;
be92fc9f 663 bool addpath_capable = false;
e386c1d5 664 int addpath_overhead = 0;
d7c0a89a 665 uint32_t addpath_tx_id = 0;
d62a17ae 666 struct prefix_rd *prd = NULL;
b57ba6d2 667 mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL;
d7c0a89a 668 uint32_t num_labels = 0;
d62a17ae 669
670 if (!subgrp)
671 return NULL;
3f9c7369 672
d62a17ae 673 if (bpacket_queue_is_full(SUBGRP_INST(subgrp), SUBGRP_PKTQ(subgrp)))
674 return NULL;
3f9c7369 675
d62a17ae 676 peer = SUBGRP_PEER(subgrp);
677 afi = SUBGRP_AFI(subgrp);
678 safi = SUBGRP_SAFI(subgrp);
679 s = subgrp->work;
680 stream_reset(s);
681 snlri = subgrp->scratch;
682 stream_reset(snlri);
683
684 bpacket_attr_vec_arr_reset(&vecarr);
685
be92fc9f
DA
686 addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
687 addpath_overhead = addpath_capable ? BGP_ADDPATH_ID_LEN : 0;
d62a17ae 688
a274fef8 689 adv = bgp_adv_fifo_first(&subgrp->sync->update);
d62a17ae 690 while (adv) {
9bcb3eef 691 const struct prefix *dest_p;
b54892e0 692
9bcb3eef
DS
693 assert(adv->dest);
694 dest = adv->dest;
695 dest_p = bgp_dest_get_prefix(dest);
d62a17ae 696 adj = adv->adj;
697 addpath_tx_id = adj->addpath_tx_id;
9b6d8fcf 698 path = adv->pathi;
d62a17ae 699
700 space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
701 - BGP_MAX_PACKET_SIZE_OVERFLOW;
9bcb3eef
DS
702 space_needed =
703 BGP_NLRI_LENGTH + addpath_overhead
704 + bgp_packet_mpattr_prefix_size(afi, safi, dest_p);
d62a17ae 705
706 /* When remaining space can't include NLRI and it's length. */
707 if (space_remaining < space_needed)
708 break;
709
710 /* If packet is empty, set attribute. */
711 if (stream_empty(s)) {
712 struct peer *from = NULL;
713
9b6d8fcf
DS
714 if (path)
715 from = path->peer;
d62a17ae 716
717 /* 1: Write the BGP message header - 16 bytes marker, 2
718 * bytes length,
719 * one byte message type.
720 */
721 bgp_packet_set_marker(s, BGP_MSG_UPDATE);
722
723 /* 2: withdrawn routes length */
724 stream_putw(s, 0);
725
726 /* 3: total attributes length - attrlen_pos stores the
727 * position */
728 attrlen_pos = stream_get_endp(s);
729 stream_putw(s, 0);
730
731 /* 4: if there is MP_REACH_NLRI attribute, that should
732 * be the first
733 * attribute, according to
734 * draft-ietf-idr-error-handling. Save the
735 * position.
736 */
737 mpattr_pos = stream_get_endp(s);
738
739 /* 5: Encode all the attributes, except MP_REACH_NLRI
740 * attr. */
741 total_attr_len = bgp_packet_attribute(
742 NULL, peer, s, adv->baa->attr, &vecarr, NULL,
97a52c82 743 afi, safi, from, NULL, NULL, 0, 0, 0, path);
d62a17ae 744
745 space_remaining =
746 STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
747 - BGP_MAX_PACKET_SIZE_OVERFLOW;
996c9314
LB
748 space_needed = BGP_NLRI_LENGTH + addpath_overhead
749 + bgp_packet_mpattr_prefix_size(
9bcb3eef 750 afi, safi, dest_p);
d62a17ae 751
752 /* If the attributes alone do not leave any room for
753 * NLRI then
754 * return */
755 if (space_remaining < space_needed) {
af4c2728 756 flog_err(
e50f7cfd 757 EC_BGP_UPDGRP_ATTR_LEN,
6cde4b45 758 "u%" PRIu64 ":s%" PRIu64" attributes too long, cannot send UPDATE",
d62a17ae 759 subgrp->update_group->id, subgrp->id);
760
761 /* Flush the FIFO update queue */
762 while (adv)
763 adv = bgp_advertise_clean_subgroup(
764 subgrp, adj);
765 return NULL;
766 }
767
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,
5022c833 773 sizeof(send_attr_str));
d62a17ae 774 }
775 }
776
777 if ((afi == AFI_IP && safi == SAFI_UNICAST)
778 && !peer_cap_enhe(peer, afi, safi))
be92fc9f 779 stream_put_prefix_addpath(s, dest_p, addpath_capable,
d62a17ae 780 addpath_tx_id);
781 else {
782 /* Encode the prefix in MP_REACH_NLRI attribute */
9bcb3eef
DS
783 if (dest->pdest)
784 prd = (struct prefix_rd *)bgp_dest_get_prefix(
785 dest->pdest);
d62a17ae 786
b57ba6d2 787 if (safi == SAFI_LABELED_UNICAST) {
9bcb3eef 788 label = bgp_adv_label(dest, path, peer, afi,
d62a17ae 789 safi);
b57ba6d2
MK
790 label_pnt = &label;
791 num_labels = 1;
9b6d8fcf
DS
792 } else if (path && path->extra) {
793 label_pnt = &path->extra->label[0];
794 num_labels = path->extra->num_labels;
b57ba6d2 795 }
d62a17ae 796
797 if (stream_empty(snlri))
798 mpattrlen_pos = bgp_packet_mpattr_start(
799 snlri, peer, afi, safi, &vecarr,
800 adv->baa->attr);
801
9bcb3eef 802 bgp_packet_mpattr_prefix(snlri, afi, safi, dest_p, prd,
b57ba6d2 803 label_pnt, num_labels,
be92fc9f 804 addpath_capable, addpath_tx_id,
b57ba6d2 805 adv->baa->attr);
d62a17ae 806 }
807
808 num_pfx++;
809
9bcb3eef 810 if (bgp_debug_update(NULL, dest_p, subgrp->update_group, 0)) {
d62a17ae 811 char pfx_buf[BGP_PRD_PATH_STRLEN];
812
813 if (!send_attr_printed) {
6cde4b45 814 zlog_debug("u%" PRIu64 ":s%" PRIu64" send UPDATE w/ attr: %s",
d62a17ae 815 subgrp->update_group->id, subgrp->id,
816 send_attr_str);
817 if (!stream_empty(snlri)) {
818 iana_afi_t pkt_afi;
5c525538 819 iana_safi_t pkt_safi;
d62a17ae 820
821 pkt_afi = afi_int2iana(afi);
822 pkt_safi = safi_int2iana(safi);
823 zlog_debug(
adf086ec
DA
824 "u%" PRIu64 ":s%" PRIu64
825 " send MP_REACH for afi/safi %s/%s",
d62a17ae 826 subgrp->update_group->id,
adf086ec
DA
827 subgrp->id,
828 iana_afi2str(pkt_afi),
829 iana_safi2str(pkt_safi));
d62a17ae 830 }
831
832 send_attr_printed = 1;
833 }
834
9bcb3eef
DS
835 bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p,
836 label_pnt, num_labels,
be92fc9f 837 addpath_capable, addpath_tx_id,
6c995628 838 &adv->baa->attr->evpn_overlay,
9bcb3eef 839 pfx_buf, sizeof(pfx_buf));
d62a17ae 840 zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
841 subgrp->update_group->id, subgrp->id,
842 pfx_buf);
843 }
844
845 /* Synchnorize attribute. */
846 if (adj->attr)
847 bgp_attr_unintern(&adj->attr);
848 else
849 subgrp->scount++;
850
851 adj->attr = bgp_attr_intern(adv->baa->attr);
d62a17ae 852 adv = bgp_advertise_clean_subgroup(subgrp, adj);
3f9c7369
DS
853 }
854
d62a17ae 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);
859 }
860
861 /* set the total attribute length correctly */
862 stream_putw_at(s, attrlen_pos, total_attr_len);
863
864 if (!stream_empty(snlri)) {
865 packet = stream_dupcat(s, snlri, mpattr_pos);
866 bpacket_attr_vec_arr_update(&vecarr, mpattr_pos);
867 } else
868 packet = stream_dup(s);
869 bgp_packet_set_size(packet);
870 if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
ef56aee4
DA
871 zlog_debug(
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);
d62a17ae 878 pkt = bpacket_queue_add(SUBGRP_PKTQ(subgrp), packet, &vecarr);
879 stream_reset(s);
880 stream_reset(snlri);
881 return pkt;
3f9c7369 882 }
d62a17ae 883 return NULL;
3f9c7369
DS
884}
885
886/* Make BGP withdraw packet. */
887/* For ipv4 unicast:
888 16-octet marker | 2-octet length | 1-octet type |
889 2-octet withdrawn route length | withdrawn prefixes | 2-octet attrlen (=0)
890*/
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
895*/
d62a17ae 896struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
3f9c7369 897{
d62a17ae 898 struct bpacket *pkt;
899 struct stream *s;
900 struct bgp_adj_out *adj;
901 struct bgp_advertise *adv;
902 struct peer *peer;
9bcb3eef 903 struct bgp_dest *dest;
d62a17ae 904 bgp_size_t unfeasible_len;
905 bgp_size_t total_attr_len;
906 size_t mp_start = 0;
907 size_t attrlen_pos = 0;
908 size_t mplen_pos = 0;
d7c0a89a 909 uint8_t first_time = 1;
d62a17ae 910 afi_t afi;
911 safi_t safi;
912 int space_remaining = 0;
913 int space_needed = 0;
914 int num_pfx = 0;
be92fc9f 915 bool addpath_capable = false;
e386c1d5 916 int addpath_overhead = 0;
d7c0a89a 917 uint32_t addpath_tx_id = 0;
b54892e0 918 const struct prefix_rd *prd = NULL;
d62a17ae 919
920
921 if (!subgrp)
922 return NULL;
3f9c7369 923
d62a17ae 924 if (bpacket_queue_is_full(SUBGRP_INST(subgrp), SUBGRP_PKTQ(subgrp)))
925 return NULL;
906ad49b 926
d62a17ae 927 peer = SUBGRP_PEER(subgrp);
928 afi = SUBGRP_AFI(subgrp);
929 safi = SUBGRP_SAFI(subgrp);
930 s = subgrp->work;
931 stream_reset(s);
be92fc9f
DA
932 addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
933 addpath_overhead = addpath_capable ? BGP_ADDPATH_ID_LEN : 0;
d62a17ae 934
a274fef8 935 while ((adv = bgp_adv_fifo_first(&subgrp->sync->withdraw)) != NULL) {
9bcb3eef 936 const struct prefix *dest_p;
b54892e0 937
9bcb3eef 938 assert(adv->dest);
d62a17ae 939 adj = adv->adj;
9bcb3eef
DS
940 dest = adv->dest;
941 dest_p = bgp_dest_get_prefix(dest);
d62a17ae 942 addpath_tx_id = adj->addpath_tx_id;
943
944 space_remaining =
2d34fb80 945 STREAM_WRITEABLE(s) - BGP_MAX_PACKET_SIZE_OVERFLOW;
9bcb3eef
DS
946 space_needed =
947 BGP_NLRI_LENGTH + addpath_overhead + BGP_TOTAL_ATTR_LEN
948 + bgp_packet_mpattr_prefix_size(afi, safi, dest_p);
d62a17ae 949
950 if (space_remaining < space_needed)
951 break;
952
953 if (stream_empty(s)) {
954 bgp_packet_set_marker(s, BGP_MSG_UPDATE);
955 stream_putw(s, 0); /* unfeasible routes length */
956 } else
957 first_time = 0;
958
959 if (afi == AFI_IP && safi == SAFI_UNICAST
960 && !peer_cap_enhe(peer, afi, safi))
be92fc9f 961 stream_put_prefix_addpath(s, dest_p, addpath_capable,
d62a17ae 962 addpath_tx_id);
963 else {
9bcb3eef
DS
964 if (dest->pdest)
965 prd = (struct prefix_rd *)bgp_dest_get_prefix(
966 dest->pdest);
d62a17ae 967
b54892e0
DS
968 /* If first time, format the MP_UNREACH header
969 */
d62a17ae 970 if (first_time) {
971 iana_afi_t pkt_afi;
5c525538 972 iana_safi_t pkt_safi;
d62a17ae 973
974 pkt_afi = afi_int2iana(afi);
975 pkt_safi = safi_int2iana(safi);
976
977 attrlen_pos = stream_get_endp(s);
b54892e0
DS
978 /* total attr length = 0 for now.
979 * reevaluate later */
d62a17ae 980 stream_putw(s, 0);
981 mp_start = stream_get_endp(s);
982 mplen_pos = bgp_packet_mpunreach_start(s, afi,
983 safi);
984 if (bgp_debug_update(NULL, NULL,
985 subgrp->update_group, 0))
986 zlog_debug(
adf086ec
DA
987 "u%" PRIu64 ":s%" PRIu64
988 " send MP_UNREACH for afi/safi %s/%s",
d62a17ae 989 subgrp->update_group->id,
adf086ec
DA
990 subgrp->id,
991 iana_afi2str(pkt_afi),
992 iana_safi2str(pkt_safi));
d62a17ae 993 }
994
9bcb3eef 995 bgp_packet_mpunreach_prefix(s, dest_p, afi, safi, prd,
be92fc9f 996 NULL, 0, addpath_capable,
d62a17ae 997 addpath_tx_id, NULL);
998 }
999
1000 num_pfx++;
1001
9bcb3eef 1002 if (bgp_debug_update(NULL, dest_p, subgrp->update_group, 0)) {
d62a17ae 1003 char pfx_buf[BGP_PRD_PATH_STRLEN];
1004
9bcb3eef 1005 bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p, NULL, 0,
be92fc9f 1006 addpath_capable, addpath_tx_id,
6c995628 1007 NULL, pfx_buf, sizeof(pfx_buf));
6cde4b45 1008 zlog_debug("u%" PRIu64 ":s%" PRIu64" send UPDATE %s -- unreachable",
d62a17ae 1009 subgrp->update_group->id, subgrp->id,
1010 pfx_buf);
1011 }
1012
1013 subgrp->scount--;
1014
9bcb3eef 1015 bgp_adj_out_remove_subgroup(dest, adj, subgrp);
3f9c7369
DS
1016 }
1017
d62a17ae 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);
1024 stream_putw(s, 0);
1025 } else {
1026 /* Set the mp_unreach attr's length */
1027 bgp_packet_mpunreach_end(s, mplen_pos);
1028
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);
1032 }
1033 bgp_packet_set_size(s);
1034 if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
6cde4b45 1035 zlog_debug("u%" PRIu64 ":s%" PRIu64" send UPDATE (withdraw) len %zd numpfx %d",
d62a17ae 1036 subgrp->update_group->id, subgrp->id,
1037 (stream_get_endp(s) - stream_get_getp(s)),
1038 num_pfx);
1039 pkt = bpacket_queue_add(SUBGRP_PKTQ(subgrp), stream_dup(s),
1040 NULL);
1041 stream_reset(s);
1042 return pkt;
3f9c7369 1043 }
3f9c7369 1044
d62a17ae 1045 return NULL;
3f9c7369
DS
1046}
1047
d62a17ae 1048void subgroup_default_update_packet(struct update_subgroup *subgrp,
1049 struct attr *attr, struct peer *from)
3f9c7369 1050{
d62a17ae 1051 struct stream *s;
1052 struct peer *peer;
1053 struct prefix p;
1054 unsigned long pos;
1055 bgp_size_t total_attr_len;
1056 afi_t afi;
1057 safi_t safi;
1058 struct bpacket_attr_vec_arr vecarr;
be92fc9f 1059 bool addpath_capable = false;
2de5f5b5
DA
1060 uint8_t default_originate_label[4] = {0x80, 0x00, 0x00};
1061 mpls_label_t *label = NULL;
1062 uint32_t num_labels = 0;
d62a17ae 1063
1064 if (DISABLE_BGP_ANNOUNCE)
1065 return;
1066
1067 if (!subgrp)
1068 return;
1069
1070 peer = SUBGRP_PEER(subgrp);
1071 afi = SUBGRP_AFI(subgrp);
1072 safi = SUBGRP_SAFI(subgrp);
1073 bpacket_attr_vec_arr_reset(&vecarr);
be92fc9f 1074 addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
d62a17ae 1075
2de5f5b5
DA
1076 if (safi == SAFI_LABELED_UNICAST) {
1077 label = (mpls_label_t *)default_originate_label;
1078 num_labels = 1;
1079 }
1080
cbb65f5e
RW
1081 memset(&p, 0, sizeof(p));
1082 p.family = afi2family(afi);
1083 p.prefixlen = 0;
d62a17ae 1084
1085 /* Logging the attribute. */
1086 if (bgp_debug_update(NULL, &p, subgrp->update_group, 0)) {
1087 char attrstr[BUFSIZ];
d62a17ae 1088 /* ' with addpath ID ' 17
1089 * max strlen of uint32 + 10
1090 * +/- (just in case) + 1
1091 * null terminator + 1
1092 * ============================ 29 */
1093 char tx_id_buf[30];
1094
1095 attrstr[0] = '\0';
1096
5022c833 1097 bgp_dump_attr(attr, attrstr, sizeof(attrstr));
d62a17ae 1098
be92fc9f 1099 if (addpath_capable)
d62a17ae 1100 snprintf(tx_id_buf, sizeof(tx_id_buf),
1101 " with addpath ID %u",
1102 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
cbb263cf
DS
1103 else
1104 tx_id_buf[0] = '\0';
d62a17ae 1105
2dbe669b
DA
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);
d62a17ae 1109 }
3f9c7369 1110
ef56aee4 1111 s = stream_new(peer->max_packet_size);
3f9c7369 1112
d62a17ae 1113 /* Make BGP update packet. */
1114 bgp_packet_set_marker(s, BGP_MSG_UPDATE);
3f9c7369 1115
d62a17ae 1116 /* Unfeasible Routes Length. */
1117 stream_putw(s, 0);
3f9c7369 1118
d62a17ae 1119 /* Make place for total attribute length. */
1120 pos = stream_get_endp(s);
1121 stream_putw(s, 0);
1122 total_attr_len = bgp_packet_attribute(
2de5f5b5
DA
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);
3f9c7369 1126
d62a17ae 1127 /* Set Total Path Attribute Length. */
1128 stream_putw_at(s, pos, total_attr_len);
3f9c7369 1129
d62a17ae 1130 /* NLRI set. */
1131 if (p.family == AF_INET && safi == SAFI_UNICAST
1132 && !peer_cap_enhe(peer, afi, safi))
1133 stream_put_prefix_addpath(
be92fc9f 1134 s, &p, addpath_capable,
d62a17ae 1135 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
3f9c7369 1136
d62a17ae 1137 /* Set size. */
1138 bgp_packet_set_size(s);
3f9c7369 1139
d62a17ae 1140 (void)bpacket_queue_add(SUBGRP_PKTQ(subgrp), s, &vecarr);
2fc102e1 1141 subgroup_trigger_write(subgrp);
46c4f05b
IS
1142
1143 if (!CHECK_FLAG(subgrp->sflags,
1144 SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED)) {
1145 subgrp->scount++;
1146 SET_FLAG(subgrp->sflags, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED);
1147 }
3f9c7369
DS
1148}
1149
d62a17ae 1150void subgroup_default_withdraw_packet(struct update_subgroup *subgrp)
3f9c7369 1151{
d62a17ae 1152 struct peer *peer;
1153 struct stream *s;
1154 struct prefix p;
1155 unsigned long attrlen_pos = 0;
1156 unsigned long cp;
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;
1161 afi_t afi;
1162 safi_t safi;
be92fc9f 1163 bool addpath_capable = false;
d62a17ae 1164
1165 if (DISABLE_BGP_ANNOUNCE)
1166 return;
1167
1168 peer = SUBGRP_PEER(subgrp);
1169 afi = SUBGRP_AFI(subgrp);
1170 safi = SUBGRP_SAFI(subgrp);
be92fc9f 1171 addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
d62a17ae 1172
cbb65f5e
RW
1173 memset(&p, 0, sizeof(p));
1174 p.family = afi2family(afi);
1175 p.prefixlen = 0;
d62a17ae 1176
1177 if (bgp_debug_update(NULL, &p, subgrp->update_group, 0)) {
d62a17ae 1178 /* ' with addpath ID ' 17
1179 * max strlen of uint32 + 10
1180 * +/- (just in case) + 1
1181 * null terminator + 1
1182 * ============================ 29 */
1183 char tx_id_buf[30];
1184
be92fc9f 1185 if (addpath_capable)
d62a17ae 1186 snprintf(tx_id_buf, sizeof(tx_id_buf),
1187 " with addpath ID %u",
1188 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
1189
2dbe669b
DA
1190 zlog_debug("u%" PRIu64 ":s%" PRIu64
1191 " send UPDATE %pFX%s -- unreachable",
1192 (SUBGRP_UPDGRP(subgrp))->id, subgrp->id, &p,
1193 tx_id_buf);
d62a17ae 1194 }
3f9c7369 1195
ef56aee4 1196 s = stream_new(peer->max_packet_size);
3f9c7369 1197
d62a17ae 1198 /* Make BGP update packet. */
1199 bgp_packet_set_marker(s, BGP_MSG_UPDATE);
3f9c7369 1200
d62a17ae 1201 /* Unfeasible Routes Length. */;
1202 cp = stream_get_endp(s);
1203 stream_putw(s, 0);
3f9c7369 1204
d62a17ae 1205 /* Withdrawn Routes. */
1206 if (p.family == AF_INET && safi == SAFI_UNICAST
1207 && !peer_cap_enhe(peer, afi, safi)) {
1208 stream_put_prefix_addpath(
be92fc9f 1209 s, &p, addpath_capable,
d62a17ae 1210 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
3f9c7369 1211
d62a17ae 1212 unfeasible_len = stream_get_endp(s) - cp - 2;
3f9c7369 1213
d62a17ae 1214 /* Set unfeasible len. */
1215 stream_putw_at(s, cp, unfeasible_len);
3f9c7369 1216
d62a17ae 1217 /* Set total path attribute length. */
1218 stream_putw(s, 0);
1219 } else {
1220 attrlen_pos = stream_get_endp(s);
1221 stream_putw(s, 0);
1222 mp_start = stream_get_endp(s);
1223 mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
1224 bgp_packet_mpunreach_prefix(
be92fc9f 1225 s, &p, afi, safi, NULL, NULL, 0, addpath_capable,
d62a17ae 1226 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL);
3f9c7369 1227
d62a17ae 1228 /* Set the mp_unreach attr's length */
1229 bgp_packet_mpunreach_end(s, mplen_pos);
3f9c7369 1230
d62a17ae 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);
1234 }
1235
1236 bgp_packet_set_size(s);
1237
1238 (void)bpacket_queue_add(SUBGRP_PKTQ(subgrp), s, NULL);
2fc102e1 1239 subgroup_trigger_write(subgrp);
46c4f05b
IS
1240
1241 if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED)) {
1242 subgrp->scount--;
1243 UNSET_FLAG(subgrp->sflags,
1244 SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED);
1245 }
3f9c7369
DS
1246}
1247
1248static void
d62a17ae 1249bpacket_vec_arr_inherit_attr_flags(struct bpacket_attr_vec_arr *vecarr,
e8e36ff3 1250 enum bpacket_attr_vec_type type,
d62a17ae 1251 struct attr *attr)
3f9c7369 1252{
d62a17ae 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);
1257
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);
1261
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);
1265
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);
1269
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);
6eeb9255
DA
1274
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);
1278
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);
d62a17ae 1283
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);
3f9c7369
DS
1288}
1289
1290/* Reset the Attributes vector array. The vector array is used to override
1291 * certain output parameters in the packet for a particular peer
1292 */
d62a17ae 1293void bpacket_attr_vec_arr_reset(struct bpacket_attr_vec_arr *vecarr)
3f9c7369 1294{
d62a17ae 1295 int i;
3f9c7369 1296
d62a17ae 1297 if (!vecarr)
1298 return;
3f9c7369 1299
d62a17ae 1300 i = 0;
1301 while (i < BGP_ATTR_VEC_MAX) {
1302 vecarr->entries[i].flags = 0;
1303 vecarr->entries[i].offset = 0;
1304 i++;
1305 }
3f9c7369
DS
1306}
1307
1308/* Setup a particular node entry in the vecarr */
d62a17ae 1309void bpacket_attr_vec_arr_set_vec(struct bpacket_attr_vec_arr *vecarr,
e8e36ff3
DA
1310 enum bpacket_attr_vec_type type,
1311 struct stream *s, struct attr *attr)
3f9c7369 1312{
d62a17ae 1313 if (!vecarr)
1314 return;
1315 assert(type < BGP_ATTR_VEC_MAX);
1316
1317 SET_FLAG(vecarr->entries[type].flags, BPKT_ATTRVEC_FLAGS_UPDATED);
1318 vecarr->entries[type].offset = stream_get_endp(s);
1319 if (attr)
1320 bpacket_vec_arr_inherit_attr_flags(vecarr, type, attr);
3f9c7369 1321}