Coverage Report

Created: 2026-03-12 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/bgpd/bgp_label.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* BGP carrying label information
3
 * Copyright (C) 2013 Cumulus Networks, Inc.
4
 */
5
6
#include <zebra.h>
7
8
#include "command.h"
9
#include "frrevent.h"
10
#include "prefix.h"
11
#include "zclient.h"
12
#include "stream.h"
13
#include "network.h"
14
#include "log.h"
15
#include "memory.h"
16
#include "nexthop.h"
17
#include "mpls.h"
18
19
#include "bgpd/bgpd.h"
20
#include "bgpd/bgp_table.h"
21
#include "bgpd/bgp_route.h"
22
#include "bgpd/bgp_attr.h"
23
#include "bgpd/bgp_label.h"
24
#include "bgpd/bgp_packet.h"
25
#include "bgpd/bgp_debug.h"
26
#include "bgpd/bgp_errors.h"
27
28
extern struct zclient *zclient;
29
30
int bgp_parse_fec_update(void)
31
0
{
32
0
  struct stream *s;
33
0
  struct bgp_dest *dest;
34
0
  struct bgp *bgp;
35
0
  struct bgp_table *table;
36
0
  struct prefix p;
37
0
  uint32_t label;
38
0
  afi_t afi;
39
0
  safi_t safi;
40
41
0
  s = zclient->ibuf;
42
43
0
  memset(&p, 0, sizeof(p));
44
0
  p.family = stream_getw(s);
45
0
  p.prefixlen = stream_getc(s);
46
0
  stream_get(p.u.val, s, PSIZE(p.prefixlen));
47
0
  label = stream_getl(s);
48
49
  /* hack for the bgp instance & SAFI = have to send/receive it */
50
0
  afi = family2afi(p.family);
51
0
  safi = SAFI_UNICAST;
52
0
  bgp = bgp_get_default();
53
0
  if (!bgp) {
54
0
    zlog_debug("no default bgp instance");
55
0
    return -1;
56
0
  }
57
58
0
  table = bgp->rib[afi][safi];
59
0
  if (!table) {
60
0
    zlog_debug("no %u unicast table", p.family);
61
0
    return -1;
62
0
  }
63
0
  dest = bgp_node_lookup(table, &p);
64
0
  if (!dest) {
65
0
    zlog_debug("no node for the prefix");
66
0
    return -1;
67
0
  }
68
69
  /* treat it as implicit withdraw - the label is invalid */
70
0
  if (label == MPLS_INVALID_LABEL)
71
0
    bgp_unset_valid_label(&dest->local_label);
72
0
  else {
73
0
    dest->local_label = mpls_lse_encode(label, 0, 0, 1);
74
0
    bgp_set_valid_label(&dest->local_label);
75
0
  }
76
0
  SET_FLAG(dest->flags, BGP_NODE_LABEL_CHANGED);
77
0
  bgp_process(bgp, dest, afi, safi);
78
0
  bgp_dest_unlock_node(dest);
79
0
  return 1;
80
0
}
81
82
mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi,
83
         struct peer *to, afi_t afi, safi_t safi)
84
0
{
85
0
  struct peer *from;
86
0
  mpls_label_t remote_label;
87
0
  int reflect;
88
89
0
  if (!dest || !pi || !to)
90
0
    return MPLS_INVALID_LABEL;
91
92
0
  remote_label = pi->extra ? pi->extra->label[0] : MPLS_INVALID_LABEL;
93
0
  from = pi->peer;
94
0
  reflect =
95
0
    ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP));
96
97
0
  if (reflect
98
0
      && !CHECK_FLAG(to->af_flags[afi][safi],
99
0
         PEER_FLAG_FORCE_NEXTHOP_SELF))
100
0
    return remote_label;
101
102
0
  if (CHECK_FLAG(to->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED))
103
0
    return remote_label;
104
105
0
  return dest->local_label;
106
0
}
107
108
static void bgp_send_fec_register_label_msg(struct bgp_dest *dest, bool reg,
109
              uint32_t label_index)
110
0
{
111
0
  struct stream *s;
112
0
  int command;
113
0
  const struct prefix *p;
114
0
  uint16_t flags = 0;
115
0
  size_t flags_pos = 0;
116
0
  mpls_label_t *local_label = &(dest->local_label);
117
0
  uint32_t ttl = 0;
118
0
  uint32_t bos = 0;
119
0
  uint32_t exp = 0;
120
0
  mpls_label_t label = MPLS_INVALID_LABEL;
121
0
  bool have_label_to_reg;
122
123
0
  mpls_lse_decode(*local_label, &label, &ttl, &exp, &bos);
124
125
0
  have_label_to_reg = bgp_is_valid_label(local_label) &&
126
0
          label != MPLS_LABEL_IMPLICIT_NULL;
127
128
0
  p = bgp_dest_get_prefix(dest);
129
130
  /* Check socket. */
131
0
  if (!zclient || zclient->sock < 0)
132
0
    return;
133
134
0
  if (BGP_DEBUG(labelpool, LABELPOOL))
135
0
    zlog_debug("%s: FEC %sregister %pRN label_index=%u label=%u",
136
0
         __func__, reg ? "" : "un", bgp_dest_to_rnode(dest),
137
0
         label_index, label);
138
  /* If the route node has a local_label assigned or the
139
   * path node has an MPLS SR label index allowing zebra to
140
   * derive the label, proceed with registration. */
141
0
  s = zclient->obuf;
142
0
  stream_reset(s);
143
0
  command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
144
0
  zclient_create_header(s, command, VRF_DEFAULT);
145
0
  flags_pos = stream_get_endp(s); /* save position of 'flags' */
146
0
  stream_putw(s, flags);    /* initial flags */
147
0
  stream_putw(s, PREFIX_FAMILY(p));
148
0
  stream_put_prefix(s, p);
149
0
  if (reg) {
150
    /* label index takes precedence over auto-assigned label. */
151
0
    if (label_index != 0) {
152
0
      flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
153
0
      stream_putl(s, label_index);
154
0
    } else if (have_label_to_reg) {
155
0
      flags |= ZEBRA_FEC_REGISTER_LABEL;
156
0
      stream_putl(s, label);
157
0
    }
158
0
    SET_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL);
159
0
  } else
160
0
    UNSET_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL);
161
162
  /* Set length and flags */
163
0
  stream_putw_at(s, 0, stream_get_endp(s));
164
165
  /*
166
   * We only need to write new flags if this is a register
167
   */
168
0
  if (reg)
169
0
    stream_putw_at(s, flags_pos, flags);
170
171
0
  zclient_send_message(zclient);
172
0
}
173
174
/**
175
 * This is passed as the callback function to bgp_labelpool.c:bgp_lp_get()
176
 * by bgp_reg_dereg_for_label() when a label needs to be obtained from
177
 * label pool.
178
 * Note that it will reject the allocated label if a label index is found,
179
 * because the label index supposes predictable labels
180
 */
181
int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
182
             bool allocated)
183
0
{
184
0
  struct bgp_dest *dest;
185
186
0
  dest = labelid;
187
188
  /*
189
   * if the route had been removed or the request has gone then reject
190
   * the allocated label. The requesting code will have done what is
191
   * required to allocate the correct label
192
   */
193
0
  if (!CHECK_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED)) {
194
0
    bgp_dest_unlock_node(dest);
195
0
    return -1;
196
0
  }
197
198
0
  bgp_dest_unlock_node(dest);
199
200
0
  if (BGP_DEBUG(labelpool, LABELPOOL))
201
0
    zlog_debug("%s: FEC %pRN label=%u, allocated=%d", __func__,
202
0
         bgp_dest_to_rnode(dest), new_label, allocated);
203
204
0
  if (!allocated) {
205
    /*
206
     * previously-allocated label is now invalid, set to implicit
207
     * null until new label arrives
208
     */
209
0
    if (CHECK_FLAG(dest->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
210
0
      UNSET_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED);
211
0
      dest->local_label = mpls_lse_encode(
212
0
        MPLS_LABEL_IMPLICIT_NULL, 0, 0, 1);
213
0
      bgp_set_valid_label(&dest->local_label);
214
0
    }
215
0
  }
216
217
0
  dest->local_label = mpls_lse_encode(new_label, 0, 0, 1);
218
0
  bgp_set_valid_label(&dest->local_label);
219
220
  /*
221
   * Get back to registering the FEC
222
   */
223
0
  bgp_send_fec_register_label_msg(dest, true, 0);
224
225
0
  return 0;
226
0
}
227
228
void bgp_reg_dereg_for_label(struct bgp_dest *dest, struct bgp_path_info *pi,
229
           bool reg)
230
0
{
231
0
  bool with_label_index = false;
232
0
  const struct prefix *p;
233
0
  bool have_label_to_reg;
234
0
  uint32_t ttl = 0;
235
0
  uint32_t bos = 0;
236
0
  uint32_t exp = 0;
237
0
  mpls_label_t label = MPLS_INVALID_LABEL;
238
239
0
  mpls_lse_decode(dest->local_label, &label, &ttl, &exp, &bos);
240
241
0
  have_label_to_reg = bgp_is_valid_label(&dest->local_label) &&
242
0
          label != MPLS_LABEL_IMPLICIT_NULL;
243
244
0
  p = bgp_dest_get_prefix(dest);
245
246
0
  if (BGP_DEBUG(labelpool, LABELPOOL))
247
0
    zlog_debug("%s: %pFX: %s ", __func__, p,
248
0
         (reg ? "reg" : "dereg"));
249
250
0
  if (reg) {
251
0
    assert(pi);
252
    /*
253
     * Determine if we will let zebra should derive label from
254
     * label index instead of bgpd requesting from label pool
255
     */
256
0
    if (CHECK_FLAG(pi->attr->flag,
257
0
          ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID))
258
0
      && pi->attr->label_index != BGP_INVALID_LABEL_INDEX) {
259
0
      with_label_index = true;
260
0
      UNSET_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED);
261
0
    } else {
262
      /*
263
       * If no label has been registered -- assume any label
264
       * from label pool will do. This means that label index
265
       * always takes precedence over auto-assigned labels.
266
       */
267
0
      if (!have_label_to_reg) {
268
0
        SET_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED);
269
0
        if (BGP_DEBUG(labelpool, LABELPOOL))
270
0
          zlog_debug(
271
0
            "%s: Requesting label from LP for %pFX",
272
0
            __func__, p);
273
        /* bgp_reg_for_label_callback() will deal with
274
         * fec registration when it gets a label from
275
         * the pool. This means we'll never register
276
         * FECs withoutvalid labels.
277
         */
278
0
        bgp_lp_get(LP_TYPE_BGP_LU, dest,
279
0
             bgp_reg_for_label_callback);
280
0
        return;
281
0
      }
282
0
    }
283
0
  } else {
284
0
    UNSET_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED);
285
0
    bgp_lp_release(LP_TYPE_BGP_LU, dest, label);
286
0
  }
287
288
0
  bgp_send_fec_register_label_msg(
289
0
    dest, reg, with_label_index ? pi->attr->label_index : 0);
290
0
}
291
292
static int bgp_nlri_get_labels(struct peer *peer, uint8_t *pnt, uint8_t plen,
293
             mpls_label_t *label)
294
0
{
295
0
  uint8_t *data = pnt;
296
0
  uint8_t *lim = pnt + plen;
297
0
  uint8_t llen = 0;
298
0
  uint8_t label_depth = 0;
299
300
0
  if (plen < BGP_LABEL_BYTES)
301
0
    return 0;
302
303
0
  for (; data < lim; data += BGP_LABEL_BYTES) {
304
0
    memcpy(label, data, BGP_LABEL_BYTES);
305
0
    llen += BGP_LABEL_BYTES;
306
307
0
    bgp_set_valid_label(label);
308
0
    label_depth += 1;
309
310
0
    if (bgp_is_withdraw_label(label) || label_bos(label))
311
0
      break;
312
0
  }
313
314
  /* If we RX multiple labels we will end up keeping only the last
315
   * one. We do not yet support a label stack greater than 1. */
316
0
  if (label_depth > 1)
317
0
    zlog_info("%pBP rcvd UPDATE with label stack %d deep", peer,
318
0
        label_depth);
319
320
0
  if (!(bgp_is_withdraw_label(label) || label_bos(label)))
321
0
    flog_warn(
322
0
      EC_BGP_INVALID_LABEL_STACK,
323
0
      "%pBP rcvd UPDATE with invalid label stack - no bottom of stack",
324
0
      peer);
325
326
0
  return llen;
327
0
}
328
329
int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
330
       struct bgp_nlri *packet)
331
0
{
332
0
  uint8_t *pnt;
333
0
  uint8_t *lim;
334
0
  struct prefix p;
335
0
  int psize = 0;
336
0
  int prefixlen;
337
0
  afi_t afi;
338
0
  safi_t safi;
339
0
  bool addpath_capable;
340
0
  uint32_t addpath_id;
341
0
  mpls_label_t label = MPLS_INVALID_LABEL;
342
0
  uint8_t llen;
343
344
0
  pnt = packet->nlri;
345
0
  lim = pnt + packet->length;
346
0
  afi = packet->afi;
347
0
  safi = packet->safi;
348
0
  addpath_id = 0;
349
350
0
  addpath_capable = bgp_addpath_encode_rx(peer, afi, safi);
351
352
0
  for (; pnt < lim; pnt += psize) {
353
    /* Clear prefix structure. */
354
0
    memset(&p, 0, sizeof(p));
355
356
0
    if (addpath_capable) {
357
358
      /* When packet overflow occurs return immediately. */
359
0
      if (pnt + BGP_ADDPATH_ID_LEN > lim)
360
0
        return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
361
362
0
      memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN);
363
0
      addpath_id = ntohl(addpath_id);
364
0
      pnt += BGP_ADDPATH_ID_LEN;
365
366
0
      if (pnt >= lim)
367
0
        return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
368
0
    }
369
370
    /* Fetch prefix length. */
371
0
    prefixlen = *pnt++;
372
0
    p.family = afi2family(packet->afi);
373
0
    psize = PSIZE(prefixlen);
374
375
    /* sanity check against packet data */
376
0
    if ((pnt + psize) > lim) {
377
0
      flog_err(
378
0
        EC_BGP_UPDATE_RCV,
379
0
        "%s [Error] Update packet error / L-U (prefix length %d exceeds packet size %u)",
380
0
        peer->host, prefixlen, (uint)(lim - pnt));
381
0
      return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
382
0
    }
383
384
    /* Fill in the labels */
385
0
    llen = bgp_nlri_get_labels(peer, pnt, psize, &label);
386
0
    if (llen == 0) {
387
0
      flog_err(
388
0
        EC_BGP_UPDATE_RCV,
389
0
        "%s [Error] Update packet error (wrong label length 0)",
390
0
        peer->host);
391
0
      return BGP_NLRI_PARSE_ERROR_LABEL_LENGTH;
392
0
    }
393
0
    p.prefixlen = prefixlen - BSIZE(llen);
394
395
    /* There needs to be at least one label */
396
0
    if (prefixlen < 24) {
397
0
      flog_err(EC_BGP_UPDATE_RCV,
398
0
         "%s [Error] Update packet error (wrong label length %d)",
399
0
         peer->host, prefixlen);
400
0
      return BGP_NLRI_PARSE_ERROR_LABEL_LENGTH;
401
0
    }
402
403
0
    if ((afi == AFI_IP && p.prefixlen > IPV4_MAX_BITLEN)
404
0
        || (afi == AFI_IP6 && p.prefixlen > IPV6_MAX_BITLEN))
405
0
      return BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH;
406
407
    /* Fetch prefix from NLRI packet */
408
0
    memcpy(&p.u.prefix, pnt + llen, psize - llen);
409
410
    /* Check address. */
411
0
    if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) {
412
0
      if (IN_CLASSD(ntohl(p.u.prefix4.s_addr))) {
413
        /* From RFC4271 Section 6.3:
414
         *
415
         * If a prefix in the NLRI field is semantically
416
         * incorrect
417
         * (e.g., an unexpected multicast IP address),
418
         * an error SHOULD
419
         * be logged locally, and the prefix SHOULD be
420
         * ignored.
421
          */
422
0
        flog_err(
423
0
          EC_BGP_UPDATE_RCV,
424
0
          "%s: IPv4 labeled-unicast NLRI is multicast address %pI4, ignoring",
425
0
          peer->host, &p.u.prefix4);
426
0
        continue;
427
0
      }
428
0
    }
429
430
    /* Check address. */
431
0
    if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) {
432
0
      if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) {
433
0
        flog_err(
434
0
          EC_BGP_UPDATE_RCV,
435
0
          "%s: IPv6 labeled-unicast NLRI is link-local address %pI6, ignoring",
436
0
          peer->host, &p.u.prefix6);
437
438
0
        continue;
439
0
      }
440
441
0
      if (IN6_IS_ADDR_MULTICAST(&p.u.prefix6)) {
442
0
        flog_err(
443
0
          EC_BGP_UPDATE_RCV,
444
0
          "%s: IPv6 unicast NLRI is multicast address %pI6, ignoring",
445
0
          peer->host, &p.u.prefix6);
446
447
0
        continue;
448
0
      }
449
0
    }
450
451
0
    if (attr) {
452
0
      bgp_update(peer, &p, addpath_id, attr, packet->afi,
453
0
           safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
454
0
           NULL, &label, 1, 0, NULL);
455
0
    } else {
456
0
      bgp_withdraw(peer, &p, addpath_id, packet->afi,
457
0
             SAFI_UNICAST, ZEBRA_ROUTE_BGP,
458
0
             BGP_ROUTE_NORMAL, NULL, &label, 1, NULL);
459
0
    }
460
0
  }
461
462
  /* Packet length consistency check. */
463
0
  if (pnt != lim) {
464
0
    flog_err(
465
0
      EC_BGP_UPDATE_RCV,
466
0
      "%s [Error] Update packet error / L-U (%td data remaining after parsing)",
467
0
      peer->host, lim - pnt);
468
0
    return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
469
0
  }
470
471
0
  return BGP_NLRI_PARSE_OK;
472
0
}