Coverage Report

Created: 2026-01-25 06:17

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