Coverage Report

Created: 2025-12-12 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/zebra/zebra_mpls.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Zebra MPLS code
3
 * Copyright (C) 2013 Cumulus Networks, Inc.
4
 */
5
6
#include <zebra.h>
7
8
#include "prefix.h"
9
#include "table.h"
10
#include "memory.h"
11
#include "command.h"
12
#include "if.h"
13
#include "log.h"
14
#include "sockunion.h"
15
#include "linklist.h"
16
#include "frrevent.h"
17
#include "workqueue.h"
18
#include "prefix.h"
19
#include "routemap.h"
20
#include "stream.h"
21
#include "nexthop.h"
22
#include "termtable.h"
23
#include "lib/json.h"
24
25
#include "zebra/rib.h"
26
#include "zebra/rt.h"
27
#include "zebra/interface.h"
28
#include "zebra/zserv.h"
29
#include "zebra/zebra_router.h"
30
#include "zebra/redistribute.h"
31
#include "zebra/debug.h"
32
#include "zebra/zebra_vrf.h"
33
#include "zebra/zebra_mpls.h"
34
#include "zebra/zebra_srte.h"
35
#include "zebra/zebra_errors.h"
36
37
2
DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object");
38
2
DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object");
39
2
DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object");
40
2
41
2
bool mpls_enabled;
42
2
bool mpls_pw_reach_strict; /* Strict reachability checking */
43
2
44
2
/* static function declarations */
45
2
46
2
static void fec_evaluate(struct zebra_vrf *zvrf);
47
2
static uint32_t fec_derive_label_from_index(struct zebra_vrf *vrf,
48
2
              struct zebra_fec *fec);
49
2
static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
50
2
           struct route_node *rn, struct route_entry *re);
51
2
static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label);
52
2
static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
53
2
         mpls_label_t old_label);
54
2
static int fec_send(struct zebra_fec *fec, struct zserv *client);
55
2
static void fec_update_clients(struct zebra_fec *fec);
56
2
static void fec_print(struct zebra_fec *fec, struct vty *vty);
57
2
static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p);
58
2
static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
59
2
         mpls_label_t label, uint32_t flags,
60
2
         uint32_t label_index);
61
2
static int fec_del(struct zebra_fec *fec);
62
2
63
2
static unsigned int label_hash(const void *p);
64
2
static bool label_cmp(const void *p1, const void *p2);
65
2
static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
66
2
             struct nexthop *nexthop);
67
2
static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
68
2
             struct nexthop *nexthop);
69
2
static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe);
70
2
71
2
static void lsp_select_best_nhlfe(struct zebra_lsp *lsp);
72
2
static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt);
73
2
static void lsp_schedule(struct hash_bucket *bucket, void *ctxt);
74
2
static wq_item_status lsp_process(struct work_queue *wq, void *data);
75
2
static void lsp_processq_del(struct work_queue *wq, void *data);
76
2
static void lsp_processq_complete(struct work_queue *wq);
77
2
static int lsp_processq_add(struct zebra_lsp *lsp);
78
2
static void *lsp_alloc(void *p);
79
2
80
2
/* Check whether lsp can be freed - no nhlfes, e.g., and call free api */
81
2
static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp);
82
2
83
2
/* Free lsp; sets caller's pointer to NULL */
84
2
static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp);
85
2
86
2
static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size);
87
2
static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
88
2
            int size);
89
2
static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
90
2
          enum nexthop_types_t gtype,
91
2
          const union g_addr *gate, ifindex_t ifindex);
92
2
static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
93
2
              enum lsp_types_t lsp_type,
94
2
              enum nexthop_types_t gtype,
95
2
              const union g_addr *gate,
96
2
              ifindex_t ifindex);
97
2
static struct zebra_nhlfe *
98
2
nhlfe_add(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
99
2
    enum nexthop_types_t gtype, const union g_addr *gate,
100
2
    ifindex_t ifindex, vrf_id_t vrf_id, uint8_t num_labels,
101
2
    const mpls_label_t *labels, bool is_backup);
102
2
static int nhlfe_del(struct zebra_nhlfe *nhlfe);
103
2
static void nhlfe_free(struct zebra_nhlfe *nhlfe);
104
2
static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
105
2
           struct mpls_label_stack *nh_label);
106
2
static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
107
2
          enum lsp_types_t type);
108
2
static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
109
2
           mpls_label_t in_label);
110
2
static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
111
2
      const char *indent);
112
2
static void lsp_print(struct vty *vty, struct zebra_lsp *lsp);
113
2
static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt);
114
2
static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
115
2
           int afi, enum lsp_types_t lsp_type);
116
2
static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
117
2
         const struct zapi_nexthop *znh);
118
2
static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
119
2
          const struct zapi_nexthop *znh);
120
2
121
2
/* Static functions */
122
2
123
2
/*
124
2
 * Handle failure in LSP install, clear flags for NHLFE.
125
2
 */
126
2
static void clear_nhlfe_installed(struct zebra_lsp *lsp)
127
2
{
128
0
  struct zebra_nhlfe *nhlfe;
129
0
  struct nexthop *nexthop;
130
131
0
  frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
132
0
    nexthop = nhlfe->nexthop;
133
0
    if (!nexthop)
134
0
      continue;
135
136
0
    UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
137
0
    UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
138
0
  }
139
140
0
  frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
141
0
    nexthop = nhlfe->nexthop;
142
0
    if (!nexthop)
143
0
      continue;
144
145
0
    UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
146
0
    UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
147
0
  }
148
0
}
149
150
/*
151
 * Install label forwarding entry based on labeled-route entry.
152
 */
153
static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
154
           struct route_node *rn, struct route_entry *re)
155
0
{
156
0
  struct hash *lsp_table;
157
0
  struct zebra_ile tmp_ile;
158
0
  struct zebra_lsp *lsp;
159
0
  struct zebra_nhlfe *nhlfe;
160
0
  struct nexthop *nexthop;
161
0
  enum lsp_types_t lsp_type;
162
0
  char buf[BUFSIZ];
163
0
  int added, changed;
164
165
  /* Lookup table. */
166
0
  lsp_table = zvrf->lsp_table;
167
0
  if (!lsp_table)
168
0
    return -1;
169
170
0
  lsp_type = lsp_type_from_re_type(re->type);
171
0
  added = changed = 0;
172
173
  /* Locate or allocate LSP entry. */
174
0
  tmp_ile.in_label = label;
175
0
  lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
176
177
  /* For each active nexthop, create NHLFE. Note that we deliberately skip
178
   * recursive nexthops right now, because intermediate hops won't
179
   * understand
180
   * the label advertised by the recursive nexthop (plus we don't have the
181
   * logic yet to push multiple labels).
182
   */
183
0
  for (nexthop = re->nhe->nhg.nexthop;
184
0
       nexthop; nexthop = nexthop->next) {
185
    /* Skip inactive and recursive entries. */
186
0
    if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
187
0
      continue;
188
0
    if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
189
0
      continue;
190
191
0
    nhlfe = nhlfe_find(&lsp->nhlfe_list, lsp_type,
192
0
           nexthop->type, &nexthop->gate,
193
0
           nexthop->ifindex);
194
0
    if (nhlfe) {
195
      /* Clear deleted flag (in case it was set) */
196
0
      UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
197
0
      if (nexthop_labels_match(nhlfe->nexthop, nexthop))
198
        /* No change */
199
0
        continue;
200
201
202
0
      if (IS_ZEBRA_DEBUG_MPLS) {
203
0
        nhlfe2str(nhlfe, buf, BUFSIZ);
204
0
        zlog_debug(
205
0
          "LSP in-label %u type %d nexthop %s out-label changed",
206
0
          lsp->ile.in_label, lsp_type, buf);
207
0
      }
208
209
      /* Update out label, trigger processing. */
210
0
      nhlfe_out_label_update(nhlfe, nexthop->nh_label);
211
0
      SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
212
0
      changed++;
213
0
    } else {
214
      /* Add LSP entry to this nexthop */
215
0
      nhlfe = nhlfe_add(
216
0
        lsp, lsp_type, nexthop->type, &nexthop->gate,
217
0
        nexthop->ifindex, nexthop->vrf_id,
218
0
        nexthop->nh_label->num_labels,
219
0
        nexthop->nh_label->label, false /*backup*/);
220
0
      if (!nhlfe)
221
0
        return -1;
222
223
0
      if (IS_ZEBRA_DEBUG_MPLS) {
224
0
        nhlfe2str(nhlfe, buf, BUFSIZ);
225
0
        zlog_debug(
226
0
          "Add LSP in-label %u type %d nexthop %s out-label %u",
227
0
          lsp->ile.in_label, lsp_type, buf,
228
0
          nexthop->nh_label->label[0]);
229
0
      }
230
231
0
      lsp->addr_family = NHLFE_FAMILY(nhlfe);
232
233
      /* Mark NHLFE as changed. */
234
0
      SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
235
0
      added++;
236
0
    }
237
0
  }
238
239
  /* Queue LSP for processing if necessary. If no NHLFE got added (special
240
   * case), delete the LSP entry; this case results in somewhat ugly
241
   * logging.
242
   */
243
0
  if (added || changed) {
244
0
    if (lsp_processq_add(lsp))
245
0
      return -1;
246
0
  } else {
247
0
    lsp_check_free(lsp_table, &lsp);
248
0
  }
249
250
0
  return 0;
251
0
}
252
253
/*
254
 * Uninstall all non-static NHLFEs of a label forwarding entry. If all
255
 * NHLFEs are removed, the entire entry is deleted.
256
 */
257
static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label)
258
1.19k
{
259
1.19k
  struct hash *lsp_table;
260
1.19k
  struct zebra_ile tmp_ile;
261
1.19k
  struct zebra_lsp *lsp;
262
1.19k
  struct zebra_nhlfe *nhlfe;
263
1.19k
  char buf[BUFSIZ];
264
265
  /* Lookup table. */
266
1.19k
  lsp_table = zvrf->lsp_table;
267
1.19k
  if (!lsp_table)
268
0
    return -1;
269
270
  /* If entry is not present, exit. */
271
1.19k
  tmp_ile.in_label = label;
272
1.19k
  lsp = hash_lookup(lsp_table, &tmp_ile);
273
1.19k
  if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
274
1.19k
    return 0;
275
276
  /* Mark NHLFEs for delete or directly delete, as appropriate. */
277
0
  frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
278
279
    /* Skip static NHLFEs */
280
0
    if (nhlfe->type == ZEBRA_LSP_STATIC)
281
0
      continue;
282
283
0
    if (IS_ZEBRA_DEBUG_MPLS) {
284
0
      nhlfe2str(nhlfe, buf, BUFSIZ);
285
0
      zlog_debug(
286
0
        "Del LSP in-label %u type %d nexthop %s flags 0x%x",
287
0
        label, nhlfe->type, buf, nhlfe->flags);
288
0
    }
289
290
0
    if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)) {
291
0
      UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
292
0
      SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
293
0
    } else {
294
0
      nhlfe_del(nhlfe);
295
0
    }
296
0
  }
297
298
  /* Queue LSP for processing, if needed, else delete. */
299
0
  if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
300
0
    if (lsp_processq_add(lsp))
301
0
      return -1;
302
0
  } else {
303
0
    lsp_check_free(lsp_table, &lsp);
304
0
  }
305
306
0
  return 0;
307
0
}
308
309
/*
310
 * This function is invoked upon change to label block configuration; it
311
 * will walk all registered FECs with label-index and appropriately update
312
 * their local labels and trigger client updates.
313
 */
314
static void fec_evaluate(struct zebra_vrf *zvrf)
315
0
{
316
0
  struct route_node *rn;
317
0
  struct zebra_fec *fec;
318
0
  uint32_t old_label, new_label;
319
0
  int af;
320
321
0
  for (af = AFI_IP; af < AFI_MAX; af++) {
322
0
    if (zvrf->fec_table[af] == NULL)
323
0
      continue;
324
325
0
    for (rn = route_top(zvrf->fec_table[af]); rn;
326
0
         rn = route_next(rn)) {
327
0
      if ((fec = rn->info) == NULL)
328
0
        continue;
329
330
      /* Skip configured FECs and those without a label index.
331
       */
332
0
      if (fec->flags & FEC_FLAG_CONFIGURED
333
0
          || fec->label_index == MPLS_INVALID_LABEL_INDEX)
334
0
        continue;
335
336
      /* Save old label, determine new label. */
337
0
      old_label = fec->label;
338
0
      new_label =
339
0
        zvrf->mpls_srgb.start_label + fec->label_index;
340
0
      if (new_label >= zvrf->mpls_srgb.end_label)
341
0
        new_label = MPLS_INVALID_LABEL;
342
343
      /* If label has changed, update FEC and clients. */
344
0
      if (new_label == old_label)
345
0
        continue;
346
347
0
      if (IS_ZEBRA_DEBUG_MPLS)
348
0
        zlog_debug(
349
0
          "Update fec %pRN new label %u upon label block",
350
0
          rn, new_label);
351
352
0
      fec->label = new_label;
353
0
      fec_update_clients(fec);
354
355
      /* Update label forwarding entries appropriately */
356
0
      fec_change_update_lsp(zvrf, fec, old_label);
357
0
    }
358
0
  }
359
0
}
360
361
/*
362
 * Derive (if possible) and update the local label for the FEC based on
363
 * its label index. The index is "acceptable" if it falls within the
364
 * globally configured label block (SRGB).
365
 */
366
static uint32_t fec_derive_label_from_index(struct zebra_vrf *zvrf,
367
              struct zebra_fec *fec)
368
823
{
369
823
  uint32_t label;
370
371
823
  if (fec->label_index != MPLS_INVALID_LABEL_INDEX
372
823
      && zvrf->mpls_srgb.start_label
373
823
      && ((label = zvrf->mpls_srgb.start_label + fec->label_index)
374
823
    < zvrf->mpls_srgb.end_label))
375
637
    fec->label = label;
376
186
  else
377
186
    fec->label = MPLS_INVALID_LABEL;
378
379
823
  return fec->label;
380
823
}
381
382
/*
383
 * There is a change for this FEC. Install or uninstall label forwarding
384
 * entries, as appropriate.
385
 */
386
static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
387
         mpls_label_t old_label)
388
1.60k
{
389
1.60k
  struct route_table *table;
390
1.60k
  struct route_node *rn;
391
1.60k
  struct route_entry *re;
392
1.60k
  afi_t afi;
393
394
  /* Uninstall label forwarding entry, if previously installed. */
395
1.60k
  if (old_label != MPLS_INVALID_LABEL
396
1.32k
      && old_label != MPLS_LABEL_IMPLICIT_NULL)
397
1.19k
    lsp_uninstall(zvrf, old_label);
398
399
  /* Install label forwarding entry corr. to new label, if needed. */
400
1.60k
  if (fec->label == MPLS_INVALID_LABEL
401
1.49k
      || fec->label == MPLS_LABEL_IMPLICIT_NULL)
402
251
    return 0;
403
404
1.35k
  afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
405
1.35k
  table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
406
1.35k
  if (!table)
407
0
    return 0;
408
409
  /* See if labeled route exists. */
410
1.35k
  rn = route_node_lookup(table, &fec->rn->p);
411
1.35k
  if (!rn)
412
1.14k
    return 0;
413
414
210
  RNODE_FOREACH_RE (rn, re) {
415
0
    if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
416
0
      break;
417
0
  }
418
419
210
  if (!re || !zebra_rib_labeled_unicast(re))
420
210
    return 0;
421
422
0
  if (lsp_install(zvrf, fec->label, rn, re))
423
0
    return -1;
424
425
0
  return 0;
426
0
}
427
428
/*
429
 * Inform about FEC to a registered client.
430
 */
431
static int fec_send(struct zebra_fec *fec, struct zserv *client)
432
1.60k
{
433
1.60k
  struct stream *s;
434
1.60k
  struct route_node *rn;
435
436
1.60k
  rn = fec->rn;
437
438
  /* Get output stream. */
439
1.60k
  s = stream_new(ZEBRA_MAX_PACKET_SIZ);
440
441
1.60k
  zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
442
443
1.60k
  stream_putw(s, rn->p.family);
444
1.60k
  stream_put_prefix(s, &rn->p);
445
1.60k
  stream_putl(s, fec->label);
446
1.60k
  stream_putw_at(s, 0, stream_get_endp(s));
447
1.60k
  return zserv_send_message(client, s);
448
1.60k
}
449
450
/*
451
 * Update all registered clients about this FEC. Caller should've updated
452
 * FEC and ensure no duplicate updates.
453
 */
454
static void fec_update_clients(struct zebra_fec *fec)
455
0
{
456
0
  struct listnode *node;
457
0
  struct zserv *client;
458
459
0
  for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) {
460
0
    if (IS_ZEBRA_DEBUG_MPLS)
461
0
      zlog_debug("Update client %s",
462
0
           zebra_route_string(client->proto));
463
0
    fec_send(fec, client);
464
0
  }
465
0
}
466
467
468
/*
469
 * Print a FEC-label binding entry.
470
 */
471
static void fec_print(struct zebra_fec *fec, struct vty *vty)
472
0
{
473
0
  struct route_node *rn;
474
0
  struct listnode *node;
475
0
  struct zserv *client;
476
0
  char buf[BUFSIZ];
477
478
0
  rn = fec->rn;
479
0
  vty_out(vty, "%pRN\n", rn);
480
0
  vty_out(vty, "  Label: %s", label2str(fec->label, 0, buf, BUFSIZ));
481
0
  if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
482
0
    vty_out(vty, ", Label Index: %u", fec->label_index);
483
0
  vty_out(vty, "\n");
484
0
  if (!list_isempty(fec->client_list)) {
485
0
    vty_out(vty, "  Client list:");
486
0
    for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
487
0
      vty_out(vty, " %s(fd %d)",
488
0
        zebra_route_string(client->proto),
489
0
        client->sock);
490
0
    vty_out(vty, "\n");
491
0
  }
492
0
}
493
494
/*
495
 * Locate FEC-label binding that matches with passed info.
496
 */
497
static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p)
498
3.13k
{
499
3.13k
  struct route_node *rn;
500
501
3.13k
  apply_mask(p);
502
3.13k
  rn = route_node_lookup(table, p);
503
3.13k
  if (!rn)
504
215
    return NULL;
505
506
2.92k
  route_unlock_node(rn);
507
2.92k
  return (rn->info);
508
3.13k
}
509
510
/*
511
 * Add a FEC. This may be upon a client registering for a binding
512
 * or when a binding is configured.
513
 */
514
static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
515
         mpls_label_t label, uint32_t flags,
516
         uint32_t label_index)
517
215
{
518
215
  struct route_node *rn;
519
215
  struct zebra_fec *fec;
520
521
215
  apply_mask(p);
522
523
  /* Lookup (or add) route node.*/
524
215
  rn = route_node_get(table, p);
525
215
  if (!rn)
526
0
    return NULL;
527
528
215
  fec = rn->info;
529
530
215
  if (!fec) {
531
215
    fec = XCALLOC(MTYPE_FEC, sizeof(struct zebra_fec));
532
533
215
    rn->info = fec;
534
215
    fec->rn = rn;
535
215
    fec->label = label;
536
215
    fec->client_list = list_new();
537
215
  } else
538
0
    route_unlock_node(rn); /* for the route_node_get */
539
540
215
  fec->label_index = label_index;
541
215
  fec->flags = flags;
542
543
215
  return fec;
544
215
}
545
546
/*
547
 * Delete a FEC. This may be upon the last client deregistering for
548
 * a FEC and no binding exists or when the binding is deleted and there
549
 * are no registered clients.
550
 */
551
static int fec_del(struct zebra_fec *fec)
552
0
{
553
0
  list_delete(&fec->client_list);
554
0
  fec->rn->info = NULL;
555
0
  route_unlock_node(fec->rn);
556
0
  XFREE(MTYPE_FEC, fec);
557
0
  return 0;
558
0
}
559
560
/*
561
 * Hash function for label.
562
 */
563
static unsigned int label_hash(const void *p)
564
0
{
565
0
  const struct zebra_ile *ile = p;
566
567
0
  return (jhash_1word(ile->in_label, 0));
568
0
}
569
570
/*
571
 * Compare 2 LSP hash entries based on in-label.
572
 */
573
static bool label_cmp(const void *p1, const void *p2)
574
0
{
575
0
  const struct zebra_ile *ile1 = p1;
576
0
  const struct zebra_ile *ile2 = p2;
577
578
0
  return (ile1->in_label == ile2->in_label);
579
0
}
580
581
/*
582
 * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
583
 * the passed flag.
584
 * NOTE: Looking only for connected routes right now.
585
 */
586
static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
587
             struct nexthop *nexthop)
588
0
{
589
0
  struct route_table *table;
590
0
  struct prefix_ipv4 p;
591
0
  struct route_node *rn;
592
0
  struct route_entry *match;
593
0
  struct nexthop *match_nh;
594
595
0
  table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, nexthop->vrf_id);
596
0
  if (!table)
597
0
    return 0;
598
599
  /* Lookup nexthop in IPv4 routing table. */
600
0
  memset(&p, 0, sizeof(p));
601
0
  p.family = AF_INET;
602
0
  p.prefixlen = IPV4_MAX_BITLEN;
603
0
  p.prefix = nexthop->gate.ipv4;
604
605
0
  rn = route_node_match(table, (struct prefix *)&p);
606
0
  if (!rn)
607
0
    return 0;
608
609
0
  route_unlock_node(rn);
610
611
  /* Locate a valid connected route. */
612
0
  RNODE_FOREACH_RE (rn, match) {
613
0
    if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
614
0
        || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
615
0
      continue;
616
617
0
    for (match_nh = match->nhe->nhg.nexthop; match_nh;
618
0
         match_nh = match_nh->next) {
619
0
      if (match->type == ZEBRA_ROUTE_CONNECT
620
0
          || nexthop->ifindex == match_nh->ifindex) {
621
0
        nexthop->ifindex = match_nh->ifindex;
622
0
        return 1;
623
0
      }
624
0
    }
625
0
  }
626
627
0
  return 0;
628
0
}
629
630
631
/*
632
 * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
633
 * the passed flag.
634
 * NOTE: Looking only for connected routes right now.
635
 */
636
static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
637
             struct nexthop *nexthop)
638
0
{
639
0
  struct route_table *table;
640
0
  struct prefix_ipv6 p;
641
0
  struct route_node *rn;
642
0
  struct route_entry *match;
643
644
0
  table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
645
0
  if (!table)
646
0
    return 0;
647
648
  /* Lookup nexthop in IPv6 routing table. */
649
0
  memset(&p, 0, sizeof(p));
650
0
  p.family = AF_INET6;
651
0
  p.prefixlen = IPV6_MAX_BITLEN;
652
0
  p.prefix = nexthop->gate.ipv6;
653
654
0
  rn = route_node_match(table, (struct prefix *)&p);
655
0
  if (!rn)
656
0
    return 0;
657
658
0
  route_unlock_node(rn);
659
660
  /* Locate a valid connected route. */
661
0
  RNODE_FOREACH_RE (rn, match) {
662
0
    if ((match->type == ZEBRA_ROUTE_CONNECT)
663
0
        && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
664
0
        && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
665
0
      break;
666
0
  }
667
668
0
  if (!match || !match->nhe->nhg.nexthop)
669
0
    return 0;
670
671
0
  nexthop->ifindex = match->nhe->nhg.nexthop->ifindex;
672
0
  return 1;
673
0
}
674
675
676
/*
677
 * Check the nexthop reachability for a NHLFE and return if valid (reachable)
678
 * or not.
679
 * NOTE: Each NHLFE points to only 1 nexthop.
680
 */
681
static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe)
682
0
{
683
0
  struct nexthop *nexthop;
684
0
  struct interface *ifp;
685
0
  struct zebra_ns *zns;
686
687
0
  nexthop = nhlfe->nexthop;
688
0
  if (!nexthop) // unexpected
689
0
    return 0;
690
691
  /* Check on nexthop based on type. */
692
0
  switch (nexthop->type) {
693
0
  case NEXTHOP_TYPE_IFINDEX:
694
    /*
695
     * Lookup if this type is special.  The
696
     * NEXTHOP_TYPE_IFINDEX is a pop and
697
     * forward into a different table for
698
     * processing.  As such this ifindex
699
     * passed to us may be a VRF device
700
     * which will not be in the default
701
     * VRF.  So let's look in all of them
702
     */
703
0
    zns = zebra_ns_lookup(NS_DEFAULT);
704
0
    ifp = if_lookup_by_index_per_ns(zns, nexthop->ifindex);
705
0
    if (ifp && if_is_operative(ifp))
706
0
      SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
707
0
    else
708
0
      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
709
0
    break;
710
0
  case NEXTHOP_TYPE_IPV4:
711
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
712
0
    if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop))
713
0
      SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
714
0
    else
715
0
      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
716
0
    break;
717
718
0
  case NEXTHOP_TYPE_IPV6:
719
0
    if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
720
0
      SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
721
0
    else
722
0
      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
723
0
    break;
724
725
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
726
0
    if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
727
0
      ifp = if_lookup_by_index(nexthop->ifindex,
728
0
             nexthop->vrf_id);
729
0
      if (ifp && if_is_operative(ifp))
730
0
        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
731
0
      else
732
0
        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
733
0
    } else {
734
0
      if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
735
0
        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
736
0
      else
737
0
        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
738
0
    }
739
0
    break;
740
741
0
  case NEXTHOP_TYPE_BLACKHOLE:
742
0
    break;
743
0
  }
744
745
0
  return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
746
0
}
747
748
/*
749
 * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
750
 * reachability and select the best. Multipath entries are also
751
 * marked. This is invoked when an LSP scheduled for processing (due
752
 * to some change) is examined.
753
 */
754
static void lsp_select_best_nhlfe(struct zebra_lsp *lsp)
755
0
{
756
0
  struct zebra_nhlfe *nhlfe;
757
0
  struct zebra_nhlfe *best;
758
0
  struct nexthop *nexthop;
759
0
  int changed = 0;
760
761
0
  if (!lsp)
762
0
    return;
763
764
0
  best = NULL;
765
0
  lsp->num_ecmp = 0;
766
0
  UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
767
768
  /*
769
   * First compute the best path, after checking nexthop status. We are
770
   * only concerned with non-deleted NHLFEs.
771
   */
772
0
  frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
773
    /* Clear selection flags. */
774
0
    UNSET_FLAG(nhlfe->flags,
775
0
         (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
776
777
0
    if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
778
0
        && nhlfe_nexthop_active(nhlfe)) {
779
0
      if (!best || (nhlfe->distance < best->distance))
780
0
        best = nhlfe;
781
0
    }
782
0
  }
783
784
0
  lsp->best_nhlfe = best;
785
0
  if (!lsp->best_nhlfe)
786
0
    return;
787
788
  /*
789
   * Check the active status of backup nhlfes also
790
   */
791
0
  frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
792
0
    if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
793
0
      (void)nhlfe_nexthop_active(nhlfe);
794
0
  }
795
796
  /* Mark best NHLFE as selected. */
797
0
  SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
798
799
  /*
800
   * If best path exists, see if there is ECMP. While doing this, note if
801
   * a
802
   * new (uninstalled) NHLFE has been selected, an installed entry that is
803
   * still selected has a change or an installed entry is to be removed.
804
   */
805
0
  frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
806
0
    int nh_chg, nh_sel, nh_inst;
807
808
0
    nexthop = nhlfe->nexthop;
809
0
    if (!nexthop) // unexpected
810
0
      continue;
811
812
0
    if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
813
0
        && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
814
0
        && (nhlfe->distance == lsp->best_nhlfe->distance)) {
815
0
      SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
816
0
      SET_FLAG(nhlfe->flags, NHLFE_FLAG_MULTIPATH);
817
0
      lsp->num_ecmp++;
818
0
    }
819
820
0
    if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) && !changed) {
821
0
      nh_chg = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
822
0
      nh_sel = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
823
0
      nh_inst =
824
0
        CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
825
826
0
      if ((nh_sel && !nh_inst)
827
0
          || (nh_sel && nh_inst && nh_chg)
828
0
          || (nh_inst && !nh_sel))
829
0
        changed = 1;
830
0
    }
831
832
    /* We have finished examining, clear changed flag. */
833
0
    UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
834
0
  }
835
836
0
  if (changed)
837
0
    SET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
838
0
}
839
840
/*
841
 * Delete LSP forwarding entry from kernel, if installed. Called upon
842
 * process exit.
843
 */
844
static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt)
845
0
{
846
0
  struct zebra_lsp *lsp;
847
848
0
  lsp = (struct zebra_lsp *)bucket->data;
849
0
  if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
850
0
    (void)dplane_lsp_delete(lsp);
851
0
}
852
853
/*
854
 * Schedule LSP forwarding entry for processing. Called upon changes
855
 * that may impact LSPs such as nexthop / connected route changes.
856
 */
857
static void lsp_schedule(struct hash_bucket *bucket, void *ctxt)
858
0
{
859
0
  struct zebra_lsp *lsp;
860
861
0
  lsp = (struct zebra_lsp *)bucket->data;
862
863
  /* In the common flow, this is used when external events occur. For
864
   * LSPs with backup nhlfes, we'll assume that the forwarding
865
   * plane will use the backups to handle these events, until the
866
   * owning protocol can react.
867
   */
868
0
  if (ctxt == NULL) {
869
    /* Skip LSPs with backups */
870
0
    if (nhlfe_list_first(&lsp->backup_nhlfe_list) != NULL) {
871
0
      if (IS_ZEBRA_DEBUG_MPLS_DETAIL)
872
0
        zlog_debug("%s: skip LSP in-label %u",
873
0
             __func__, lsp->ile.in_label);
874
0
      return;
875
0
    }
876
0
  }
877
878
0
  (void)lsp_processq_add(lsp);
879
0
}
880
881
/*
882
 * Process a LSP entry that is in the queue. Recalculate best NHLFE and
883
 * any multipaths and update or delete from the kernel, as needed.
884
 */
885
static wq_item_status lsp_process(struct work_queue *wq, void *data)
886
0
{
887
0
  struct zebra_lsp *lsp;
888
0
  struct zebra_nhlfe *oldbest, *newbest;
889
0
  char buf[BUFSIZ], buf2[BUFSIZ];
890
0
  struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
891
0
  enum zebra_dplane_result res;
892
893
0
  lsp = (struct zebra_lsp *)data;
894
0
  if (!lsp) // unexpected
895
0
    return WQ_SUCCESS;
896
897
0
  oldbest = lsp->best_nhlfe;
898
899
  /* Select best NHLFE(s) */
900
0
  lsp_select_best_nhlfe(lsp);
901
902
0
  newbest = lsp->best_nhlfe;
903
904
0
  if (IS_ZEBRA_DEBUG_MPLS) {
905
0
    if (oldbest)
906
0
      nhlfe2str(oldbest, buf, sizeof(buf));
907
0
    if (newbest)
908
0
      nhlfe2str(newbest, buf2, sizeof(buf2));
909
0
    zlog_debug(
910
0
      "Process LSP in-label %u oldbest %s newbest %s flags 0x%x ecmp# %d",
911
0
      lsp->ile.in_label, oldbest ? buf : "NULL",
912
0
      newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
913
0
  }
914
915
0
  if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
916
    /* Not already installed */
917
0
    if (newbest) {
918
919
0
      UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
920
921
0
      switch (dplane_lsp_add(lsp)) {
922
0
      case ZEBRA_DPLANE_REQUEST_QUEUED:
923
        /* Set 'installed' flag so we will know
924
         * that an install is in-flight.
925
         */
926
0
        SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
927
928
0
        zvrf->lsp_installs_queued++;
929
0
        break;
930
0
      case ZEBRA_DPLANE_REQUEST_FAILURE:
931
0
        flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
932
0
            "LSP Install Failure: %u",
933
0
            lsp->ile.in_label);
934
0
        break;
935
0
      case ZEBRA_DPLANE_REQUEST_SUCCESS:
936
0
        zvrf->lsp_installs++;
937
0
        break;
938
0
      }
939
0
    }
940
0
  } else {
941
    /* Installed, may need an update and/or delete. */
942
0
    if (!newbest) {
943
0
      res = dplane_lsp_delete(lsp);
944
945
      /* We do some of the lsp cleanup immediately for
946
       * deletes.
947
       */
948
0
      UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
949
0
      clear_nhlfe_installed(lsp);
950
951
0
      switch (res) {
952
0
      case ZEBRA_DPLANE_REQUEST_QUEUED:
953
0
        zvrf->lsp_removals_queued++;
954
0
        break;
955
0
      case ZEBRA_DPLANE_REQUEST_FAILURE:
956
0
        flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
957
0
            "LSP Deletion Failure: %u",
958
0
            lsp->ile.in_label);
959
0
        break;
960
0
      case ZEBRA_DPLANE_REQUEST_SUCCESS:
961
0
        zvrf->lsp_removals++;
962
0
        break;
963
0
      }
964
0
    } else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) {
965
0
      struct zebra_nhlfe *nhlfe;
966
0
      struct nexthop *nexthop;
967
968
0
      UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
969
970
      /* We leave the INSTALLED flag set here
971
       * so we know an update is in-flight.
972
       */
973
974
      /*
975
       * Any NHLFE that was installed but is not
976
       * selected now needs to have its flags updated.
977
       */
978
0
      frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
979
0
        nexthop = nhlfe->nexthop;
980
0
        if (!nexthop)
981
0
          continue;
982
983
0
        if (CHECK_FLAG(nhlfe->flags,
984
0
                 NHLFE_FLAG_INSTALLED)
985
0
            && !CHECK_FLAG(nhlfe->flags,
986
0
               NHLFE_FLAG_SELECTED)) {
987
0
          UNSET_FLAG(nhlfe->flags,
988
0
               NHLFE_FLAG_INSTALLED);
989
0
          UNSET_FLAG(nexthop->flags,
990
0
               NEXTHOP_FLAG_FIB);
991
0
        }
992
0
      }
993
994
0
      switch (dplane_lsp_update(lsp)) {
995
0
      case ZEBRA_DPLANE_REQUEST_QUEUED:
996
0
        zvrf->lsp_installs_queued++;
997
0
        break;
998
0
      case ZEBRA_DPLANE_REQUEST_FAILURE:
999
0
        flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1000
0
            "LSP Update Failure: %u",
1001
0
            lsp->ile.in_label);
1002
0
        break;
1003
0
      case ZEBRA_DPLANE_REQUEST_SUCCESS:
1004
0
        zvrf->lsp_installs++;
1005
0
        break;
1006
0
      }
1007
0
    }
1008
0
  }
1009
1010
0
  return WQ_SUCCESS;
1011
0
}
1012
1013
1014
/*
1015
 * Callback upon processing completion of a LSP forwarding entry.
1016
 */
1017
static void lsp_processq_del(struct work_queue *wq, void *data)
1018
0
{
1019
0
  struct zebra_vrf *zvrf;
1020
0
  struct zebra_lsp *lsp;
1021
0
  struct hash *lsp_table;
1022
0
  struct zebra_nhlfe *nhlfe;
1023
1024
  /* If zebra is shutting down, don't delete any structs,
1025
   * just ignore this callback. The LSPs will be cleaned up
1026
   * during the shutdown processing.
1027
   */
1028
0
  if (zebra_router_in_shutdown())
1029
0
    return;
1030
1031
0
  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
1032
0
  assert(zvrf);
1033
1034
0
  lsp_table = zvrf->lsp_table;
1035
0
  if (!lsp_table) // unexpected
1036
0
    return;
1037
1038
0
  lsp = (struct zebra_lsp *)data;
1039
0
  if (!lsp) // unexpected
1040
0
    return;
1041
1042
  /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
1043
   * exist,
1044
   * delete LSP entry also.
1045
   */
1046
0
  UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1047
1048
0
  frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1049
0
    if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1050
0
      nhlfe_del(nhlfe);
1051
0
  }
1052
1053
0
  frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1054
0
    if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
1055
0
      nhlfe_del(nhlfe);
1056
0
  }
1057
1058
0
  lsp_check_free(lsp_table, &lsp);
1059
0
}
1060
1061
/*
1062
 * Callback upon finishing the processing of all scheduled
1063
 * LSP forwarding entries.
1064
 */
1065
static void lsp_processq_complete(struct work_queue *wq)
1066
0
{
1067
  /* Nothing to do for now. */
1068
0
}
1069
1070
/*
1071
 * Add LSP forwarding entry to queue for subsequent processing.
1072
 */
1073
static int lsp_processq_add(struct zebra_lsp *lsp)
1074
0
{
1075
  /* If already scheduled, exit. */
1076
0
  if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1077
0
    return 0;
1078
1079
0
  if (zrouter.lsp_process_q == NULL) {
1080
0
    flog_err(EC_ZEBRA_WQ_NONEXISTENT,
1081
0
       "%s: work_queue does not exist!", __func__);
1082
0
    return -1;
1083
0
  }
1084
1085
0
  work_queue_add(zrouter.lsp_process_q, lsp);
1086
0
  SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
1087
0
  return 0;
1088
0
}
1089
1090
/*
1091
 * Callback to allocate LSP forwarding table entry.
1092
 */
1093
static void *lsp_alloc(void *p)
1094
0
{
1095
0
  const struct zebra_ile *ile = p;
1096
0
  struct zebra_lsp *lsp;
1097
1098
0
  lsp = XCALLOC(MTYPE_LSP, sizeof(struct zebra_lsp));
1099
0
  lsp->ile = *ile;
1100
0
  nhlfe_list_init(&lsp->nhlfe_list);
1101
0
  nhlfe_list_init(&lsp->backup_nhlfe_list);
1102
1103
0
  if (IS_ZEBRA_DEBUG_MPLS)
1104
0
    zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label);
1105
1106
0
  return ((void *)lsp);
1107
0
}
1108
1109
/*
1110
 * Check whether lsp can be freed - no nhlfes, e.g., and call free api
1111
 */
1112
static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp)
1113
0
{
1114
0
  struct zebra_lsp *lsp;
1115
1116
0
  if (plsp == NULL || *plsp == NULL)
1117
0
    return;
1118
1119
0
  lsp = *plsp;
1120
1121
0
  if ((nhlfe_list_first(&lsp->nhlfe_list) == NULL) &&
1122
0
      (nhlfe_list_first(&lsp->backup_nhlfe_list) == NULL) &&
1123
0
      !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
1124
0
    lsp_free(lsp_table, plsp);
1125
0
}
1126
1127
static void lsp_free_nhlfe(struct zebra_lsp *lsp)
1128
0
{
1129
0
  struct zebra_nhlfe *nhlfe;
1130
1131
0
  while ((nhlfe = nhlfe_list_first(&lsp->nhlfe_list))) {
1132
0
    nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
1133
0
    nhlfe_free(nhlfe);
1134
0
  }
1135
1136
0
  while ((nhlfe = nhlfe_list_first(&lsp->backup_nhlfe_list))) {
1137
0
    nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
1138
0
    nhlfe_free(nhlfe);
1139
0
  }
1140
0
}
1141
1142
/*
1143
 * Dtor for an LSP: remove from ile hash, release any internal allocations,
1144
 * free LSP object.
1145
 */
1146
static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp)
1147
0
{
1148
0
  struct zebra_lsp *lsp;
1149
1150
0
  if (plsp == NULL || *plsp == NULL)
1151
0
    return;
1152
1153
0
  lsp = *plsp;
1154
1155
0
  if (IS_ZEBRA_DEBUG_MPLS)
1156
0
    zlog_debug("Free LSP in-label %u flags 0x%x",
1157
0
         lsp->ile.in_label, lsp->flags);
1158
1159
0
  lsp_free_nhlfe(lsp);
1160
1161
0
  hash_release(lsp_table, &lsp->ile);
1162
0
  XFREE(MTYPE_LSP, lsp);
1163
1164
0
  *plsp = NULL;
1165
0
}
1166
1167
/*
1168
 * Create printable string for NHLFE entry.
1169
 */
1170
static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size)
1171
0
{
1172
0
  const struct nexthop *nexthop;
1173
1174
0
  buf[0] = '\0';
1175
0
  nexthop = nhlfe->nexthop;
1176
0
  switch (nexthop->type) {
1177
0
  case NEXTHOP_TYPE_IPV4:
1178
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1179
0
    inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
1180
0
    break;
1181
0
  case NEXTHOP_TYPE_IPV6:
1182
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1183
0
    inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
1184
0
    break;
1185
0
  case NEXTHOP_TYPE_IFINDEX:
1186
0
    snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
1187
0
  case NEXTHOP_TYPE_BLACKHOLE:
1188
0
    break;
1189
0
  }
1190
1191
0
  return buf;
1192
0
}
1193
1194
/*
1195
 * Check if NHLFE matches with search info passed.
1196
 */
1197
static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
1198
          enum nexthop_types_t gtype,
1199
          const union g_addr *gate, ifindex_t ifindex)
1200
0
{
1201
0
  struct nexthop *nhop;
1202
0
  int cmp = 1;
1203
1204
0
  nhop = nhlfe->nexthop;
1205
0
  if (!nhop)
1206
0
    return 1;
1207
1208
0
  if (nhop->type != gtype)
1209
0
    return 1;
1210
1211
0
  switch (nhop->type) {
1212
0
  case NEXTHOP_TYPE_IPV4:
1213
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1214
0
    cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
1215
0
           sizeof(struct in_addr));
1216
0
    if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1217
0
      cmp = !(nhop->ifindex == ifindex);
1218
0
    break;
1219
0
  case NEXTHOP_TYPE_IPV6:
1220
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1221
0
    cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
1222
0
           sizeof(struct in6_addr));
1223
0
    if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1224
0
      cmp = !(nhop->ifindex == ifindex);
1225
0
    break;
1226
0
  case NEXTHOP_TYPE_IFINDEX:
1227
0
    cmp = !(nhop->ifindex == ifindex);
1228
0
    break;
1229
0
  case NEXTHOP_TYPE_BLACKHOLE:
1230
0
    break;
1231
0
  }
1232
1233
0
  return cmp;
1234
0
}
1235
1236
1237
/*
1238
 * Locate NHLFE that matches with passed info.
1239
 * TODO: handle vrf_id if vrf backend is netns based
1240
 */
1241
static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
1242
              enum lsp_types_t lsp_type,
1243
              enum nexthop_types_t gtype,
1244
              const union g_addr *gate,
1245
              ifindex_t ifindex)
1246
0
{
1247
0
  struct zebra_nhlfe *nhlfe;
1248
1249
0
  frr_each_safe(nhlfe_list, list, nhlfe) {
1250
0
    if (nhlfe->type != lsp_type)
1251
0
      continue;
1252
0
    if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex))
1253
0
      break;
1254
0
  }
1255
1256
0
  return nhlfe;
1257
0
}
1258
1259
/*
1260
 * Allocate and init new NHLFE.
1261
 */
1262
static struct zebra_nhlfe *
1263
nhlfe_alloc(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
1264
      enum nexthop_types_t gtype, const union g_addr *gate,
1265
      ifindex_t ifindex, vrf_id_t vrf_id, uint8_t num_labels,
1266
      const mpls_label_t *labels)
1267
0
{
1268
0
  struct zebra_nhlfe *nhlfe;
1269
0
  struct nexthop *nexthop;
1270
1271
0
  assert(lsp);
1272
1273
0
  nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(struct zebra_nhlfe));
1274
1275
0
  nhlfe->lsp = lsp;
1276
0
  nhlfe->type = lsp_type;
1277
0
  nhlfe->distance = lsp_distance(lsp_type);
1278
1279
0
  nexthop = nexthop_new();
1280
1281
0
  nexthop_add_labels(nexthop, lsp_type, num_labels, labels);
1282
1283
0
  nexthop->vrf_id = vrf_id;
1284
0
  nexthop->type = gtype;
1285
0
  switch (nexthop->type) {
1286
0
  case NEXTHOP_TYPE_IPV4:
1287
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1288
0
    nexthop->gate.ipv4 = gate->ipv4;
1289
0
    if (ifindex)
1290
0
      nexthop->ifindex = ifindex;
1291
0
    break;
1292
0
  case NEXTHOP_TYPE_IPV6:
1293
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1294
0
    nexthop->gate.ipv6 = gate->ipv6;
1295
0
    if (ifindex)
1296
0
      nexthop->ifindex = ifindex;
1297
0
    break;
1298
0
  case NEXTHOP_TYPE_IFINDEX:
1299
0
    nexthop->ifindex = ifindex;
1300
0
    break;
1301
0
  case NEXTHOP_TYPE_BLACKHOLE:
1302
0
    if (IS_ZEBRA_DEBUG_MPLS)
1303
0
      zlog_debug("%s: invalid: blackhole nexthop", __func__);
1304
1305
0
    nexthop_free(nexthop);
1306
0
    XFREE(MTYPE_NHLFE, nhlfe);
1307
0
    return NULL;
1308
0
  }
1309
0
  nhlfe->nexthop = nexthop;
1310
1311
0
  return nhlfe;
1312
0
}
1313
1314
/*
1315
 * Add primary or backup NHLFE. Base entry must have been created and
1316
 * duplicate check done.
1317
 */
1318
static struct zebra_nhlfe *
1319
nhlfe_add(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
1320
    enum nexthop_types_t gtype, const union g_addr *gate,
1321
    ifindex_t ifindex, vrf_id_t vrf_id, uint8_t num_labels,
1322
    const mpls_label_t *labels, bool is_backup)
1323
0
{
1324
0
  struct zebra_nhlfe *nhlfe;
1325
1326
0
  if (!lsp)
1327
0
    return NULL;
1328
1329
  /* Allocate new object */
1330
0
  nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, vrf_id,
1331
0
          num_labels, labels);
1332
1333
0
  if (!nhlfe)
1334
0
    return NULL;
1335
1336
  /* Enqueue to LSP: primaries at head of list, backups at tail */
1337
0
  if (is_backup) {
1338
0
    SET_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP);
1339
0
    nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe);
1340
0
  } else
1341
0
    nhlfe_list_add_head(&lsp->nhlfe_list, nhlfe);
1342
1343
0
  return nhlfe;
1344
0
}
1345
1346
/*
1347
 * Common delete for NHLFEs.
1348
 */
1349
static void nhlfe_free(struct zebra_nhlfe *nhlfe)
1350
0
{
1351
0
  if (!nhlfe)
1352
0
    return;
1353
1354
  /* Free nexthop. */
1355
0
  if (nhlfe->nexthop)
1356
0
    nexthop_free(nhlfe->nexthop);
1357
1358
0
  nhlfe->nexthop = NULL;
1359
1360
0
  XFREE(MTYPE_NHLFE, nhlfe);
1361
0
}
1362
1363
1364
/*
1365
 * Disconnect NHLFE from LSP, and free. Entry must be present on LSP's list.
1366
 */
1367
static int nhlfe_del(struct zebra_nhlfe *nhlfe)
1368
0
{
1369
0
  struct zebra_lsp *lsp;
1370
1371
0
  if (!nhlfe)
1372
0
    return -1;
1373
1374
0
  lsp = nhlfe->lsp;
1375
0
  if (!lsp)
1376
0
    return -1;
1377
1378
0
  if (nhlfe == lsp->best_nhlfe)
1379
0
    lsp->best_nhlfe = NULL;
1380
1381
  /* Unlink from LSP */
1382
0
  if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP))
1383
0
    nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
1384
0
  else
1385
0
    nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
1386
1387
0
  nhlfe->lsp = NULL;
1388
1389
0
  nhlfe_free(nhlfe);
1390
1391
0
  return 0;
1392
0
}
1393
1394
/*
1395
 * Update label for NHLFE entry.
1396
 */
1397
static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
1398
           struct mpls_label_stack *nh_label)
1399
0
{
1400
0
  nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
1401
0
}
1402
1403
static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
1404
          enum lsp_types_t type)
1405
0
{
1406
0
  struct zebra_nhlfe *nhlfe;
1407
0
  int schedule_lsp = 0;
1408
0
  char buf[BUFSIZ];
1409
1410
0
  if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1411
0
    schedule_lsp = 1;
1412
1413
  /* Mark NHLFEs for delete or directly delete, as appropriate. */
1414
0
  frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1415
    /* Skip non-static NHLFEs */
1416
0
    if (nhlfe->type != type)
1417
0
      continue;
1418
1419
0
    if (IS_ZEBRA_DEBUG_MPLS) {
1420
0
      nhlfe2str(nhlfe, buf, sizeof(buf));
1421
0
      zlog_debug(
1422
0
        "Del LSP in-label %u type %d nexthop %s flags 0x%x",
1423
0
        lsp->ile.in_label, type, buf, nhlfe->flags);
1424
0
    }
1425
1426
0
    if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1427
0
      UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1428
0
      SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1429
0
      schedule_lsp = 1;
1430
0
    } else {
1431
0
      nhlfe_del(nhlfe);
1432
0
    }
1433
0
  }
1434
1435
0
  frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1436
    /* Skip non-static NHLFEs */
1437
0
    if (nhlfe->type != type)
1438
0
      continue;
1439
1440
0
    if (IS_ZEBRA_DEBUG_MPLS) {
1441
0
      nhlfe2str(nhlfe, buf, sizeof(buf));
1442
0
      zlog_debug(
1443
0
        "Del backup LSP in-label %u type %d nexthop %s flags 0x%x",
1444
0
        lsp->ile.in_label, type, buf, nhlfe->flags);
1445
0
    }
1446
1447
0
    if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
1448
0
      UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
1449
0
      SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
1450
0
      schedule_lsp = 1;
1451
0
    } else {
1452
0
      nhlfe_del(nhlfe);
1453
0
    }
1454
0
  }
1455
1456
  /* Queue LSP for processing, if needed, else delete. */
1457
0
  if (schedule_lsp) {
1458
0
    if (IS_ZEBRA_DEBUG_MPLS) {
1459
0
      zlog_debug("Schedule LSP in-label %u flags 0x%x",
1460
0
           lsp->ile.in_label, lsp->flags);
1461
0
    }
1462
0
    if (lsp_processq_add(lsp))
1463
0
      return -1;
1464
0
  } else {
1465
0
    lsp_check_free(lsp_table, &lsp);
1466
0
  }
1467
1468
0
  return 0;
1469
0
}
1470
1471
/*
1472
 * Uninstall all static NHLFEs for a particular LSP forwarding entry.
1473
 * If no other NHLFEs exist, the entry would be deleted.
1474
 */
1475
static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
1476
           mpls_label_t in_label)
1477
0
{
1478
0
  struct hash *lsp_table;
1479
0
  struct zebra_ile tmp_ile;
1480
0
  struct zebra_lsp *lsp;
1481
1482
  /* Lookup table. */
1483
0
  lsp_table = zvrf->lsp_table;
1484
0
  if (!lsp_table)
1485
0
    return -1;
1486
1487
  /* If entry is not present, exit. */
1488
0
  tmp_ile.in_label = in_label;
1489
0
  lsp = hash_lookup(lsp_table, &tmp_ile);
1490
0
  if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
1491
0
    return 0;
1492
1493
0
  return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC);
1494
0
}
1495
1496
static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe)
1497
0
{
1498
0
  json_object *json_nhlfe = NULL;
1499
0
  json_object *json_backups = NULL;
1500
0
  json_object *json_label_stack;
1501
0
  struct nexthop *nexthop = nhlfe->nexthop;
1502
0
  int i;
1503
1504
0
  json_nhlfe = json_object_new_object();
1505
0
  json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
1506
0
  if (nexthop->nh_label) {
1507
0
    json_object_int_add(json_nhlfe, "outLabel",
1508
0
            nexthop->nh_label->label[0]);
1509
0
    json_label_stack = json_object_new_array();
1510
0
    json_object_object_add(json_nhlfe, "outLabelStack",
1511
0
               json_label_stack);
1512
0
    for (i = 0; i < nexthop->nh_label->num_labels; i++)
1513
0
      json_object_array_add(
1514
0
        json_label_stack,
1515
0
        json_object_new_int(
1516
0
          nexthop->nh_label->label[i]));
1517
0
  }
1518
0
  json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
1519
1520
0
  if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
1521
0
    json_object_boolean_true_add(json_nhlfe, "installed");
1522
1523
0
  switch (nexthop->type) {
1524
0
  case NEXTHOP_TYPE_IPV4:
1525
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1526
0
    json_object_string_addf(json_nhlfe, "nexthop", "%pI4",
1527
0
          &nexthop->gate.ipv4);
1528
0
    if (nexthop->ifindex)
1529
0
      json_object_string_add(json_nhlfe, "interface",
1530
0
                 ifindex2ifname(nexthop->ifindex,
1531
0
                    nexthop->vrf_id));
1532
0
    break;
1533
0
  case NEXTHOP_TYPE_IPV6:
1534
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1535
0
    json_object_string_addf(json_nhlfe, "nexthop", "%pI6",
1536
0
          &nexthop->gate.ipv6);
1537
1538
0
    if (nexthop->ifindex)
1539
0
      json_object_string_add(json_nhlfe, "interface",
1540
0
                 ifindex2ifname(nexthop->ifindex,
1541
0
                    nexthop->vrf_id));
1542
0
    break;
1543
0
  case NEXTHOP_TYPE_IFINDEX:
1544
0
    if (nexthop->ifindex)
1545
0
      json_object_string_add(json_nhlfe, "interface",
1546
0
                 ifindex2ifname(nexthop->ifindex,
1547
0
                    nexthop->vrf_id));
1548
0
    break;
1549
0
  case NEXTHOP_TYPE_BLACKHOLE:
1550
0
    break;
1551
0
  }
1552
1553
0
  if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
1554
0
    json_backups = json_object_new_array();
1555
0
    for (i = 0; i < nexthop->backup_num; i++) {
1556
0
      json_object_array_add(
1557
0
        json_backups,
1558
0
        json_object_new_int(nexthop->backup_idx[i]));
1559
0
    }
1560
1561
0
    json_object_object_add(json_nhlfe, "backupIndex",
1562
0
               json_backups);
1563
0
  }
1564
1565
0
  return json_nhlfe;
1566
0
}
1567
1568
/*
1569
 * Print the NHLFE for a LSP forwarding entry.
1570
 */
1571
static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
1572
      const char *indent)
1573
0
{
1574
0
  struct nexthop *nexthop;
1575
0
  char buf[MPLS_LABEL_STRLEN];
1576
1577
0
  nexthop = nhlfe->nexthop;
1578
0
  if (!nexthop || !nexthop->nh_label) // unexpected
1579
0
    return;
1580
1581
0
  vty_out(vty, " type: %s remote label: %s distance: %d\n",
1582
0
    nhlfe_type2str(nhlfe->type),
1583
0
    mpls_label2str(nexthop->nh_label->num_labels,
1584
0
             nexthop->nh_label->label, buf, sizeof(buf),
1585
0
             nexthop->nh_label_type, 0),
1586
0
    nhlfe->distance);
1587
1588
0
  if (indent)
1589
0
    vty_out(vty, "%s", indent);
1590
1591
0
  switch (nexthop->type) {
1592
0
  case NEXTHOP_TYPE_IPV4:
1593
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1594
0
    vty_out(vty, "  via %pI4", &nexthop->gate.ipv4);
1595
0
    if (nexthop->ifindex)
1596
0
      vty_out(vty, " dev %s",
1597
0
        ifindex2ifname(nexthop->ifindex,
1598
0
                 nexthop->vrf_id));
1599
0
    break;
1600
0
  case NEXTHOP_TYPE_IPV6:
1601
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1602
0
    vty_out(vty, "  via %s",
1603
0
      inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
1604
0
          sizeof(buf)));
1605
0
    if (nexthop->ifindex)
1606
0
      vty_out(vty, " dev %s",
1607
0
        ifindex2ifname(nexthop->ifindex,
1608
0
                 nexthop->vrf_id));
1609
0
    break;
1610
0
  case NEXTHOP_TYPE_IFINDEX:
1611
0
    if (nexthop->ifindex)
1612
0
      vty_out(vty, "  dev %s",
1613
0
        ifindex2ifname(nexthop->ifindex,
1614
0
                 nexthop->vrf_id));
1615
0
    break;
1616
0
  case NEXTHOP_TYPE_BLACKHOLE:
1617
0
    break;
1618
0
  }
1619
0
  vty_out(vty, "%s",
1620
0
    CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP) ? " (backup)"
1621
0
                     : "");
1622
0
  vty_out(vty, "%s",
1623
0
    CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
1624
0
                     : "");
1625
0
  vty_out(vty, "\n");
1626
0
}
1627
1628
/*
1629
 * Print an LSP forwarding entry.
1630
 */
1631
static void lsp_print(struct vty *vty, struct zebra_lsp *lsp)
1632
0
{
1633
0
  struct zebra_nhlfe *nhlfe, *backup;
1634
0
  int i, j;
1635
1636
0
  vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label,
1637
0
    CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)"
1638
0
                 : "");
1639
1640
0
  frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1641
0
    nhlfe_print(nhlfe, vty, NULL);
1642
1643
0
    if (nhlfe->nexthop == NULL ||
1644
0
        !CHECK_FLAG(nhlfe->nexthop->flags,
1645
0
        NEXTHOP_FLAG_HAS_BACKUP))
1646
0
      continue;
1647
1648
    /* Backup nhlfes: find backups in backup list */
1649
1650
0
    for (j = 0; j < nhlfe->nexthop->backup_num; j++) {
1651
0
      i = 0;
1652
0
      backup = NULL;
1653
0
      frr_each(nhlfe_list, &lsp->backup_nhlfe_list, backup) {
1654
0
        if (i == nhlfe->nexthop->backup_idx[j])
1655
0
          break;
1656
0
        i++;
1657
0
      }
1658
1659
0
      if (backup) {
1660
0
        vty_out(vty, "   [backup %d]", i);
1661
0
        nhlfe_print(backup, vty, "   ");
1662
0
      }
1663
0
    }
1664
0
  }
1665
0
}
1666
1667
/*
1668
 * JSON objects for an LSP forwarding entry.
1669
 */
1670
static json_object *lsp_json(struct zebra_lsp *lsp)
1671
0
{
1672
0
  struct zebra_nhlfe *nhlfe = NULL;
1673
0
  json_object *json = json_object_new_object();
1674
0
  json_object *json_nhlfe_list = json_object_new_array();
1675
1676
0
  json_object_int_add(json, "inLabel", lsp->ile.in_label);
1677
1678
0
  if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
1679
0
    json_object_boolean_true_add(json, "installed");
1680
1681
0
  frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe)
1682
0
    json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1683
1684
0
  json_object_object_add(json, "nexthops", json_nhlfe_list);
1685
0
  json_nhlfe_list = NULL;
1686
1687
1688
0
  frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
1689
0
    if (json_nhlfe_list == NULL)
1690
0
      json_nhlfe_list = json_object_new_array();
1691
1692
0
    json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
1693
0
  }
1694
1695
0
  if (json_nhlfe_list)
1696
0
    json_object_object_add(json, "backupNexthops", json_nhlfe_list);
1697
1698
0
  return json;
1699
0
}
1700
1701
1702
/* Return a sorted linked list of the hash contents */
1703
static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
1704
0
{
1705
0
  unsigned int i;
1706
0
  struct hash_bucket *hb;
1707
0
  struct list *sorted_list = list_new();
1708
1709
0
  sorted_list->cmp = (int (*)(void *, void *))cmp;
1710
1711
0
  for (i = 0; i < hash->size; i++)
1712
0
    for (hb = hash->index[i]; hb; hb = hb->next)
1713
0
      listnode_add_sort(sorted_list, hb->data);
1714
1715
0
  return sorted_list;
1716
0
}
1717
1718
/*
1719
 * Compare two LSPs based on their label values.
1720
 */
1721
static int lsp_cmp(const struct zebra_lsp *lsp1, const struct zebra_lsp *lsp2)
1722
0
{
1723
0
  if (lsp1->ile.in_label < lsp2->ile.in_label)
1724
0
    return -1;
1725
1726
0
  if (lsp1->ile.in_label > lsp2->ile.in_label)
1727
0
    return 1;
1728
1729
0
  return 0;
1730
0
}
1731
1732
/*
1733
 * Initialize work queue for processing changed LSPs.
1734
 */
1735
static void mpls_processq_init(void)
1736
0
{
1737
0
  zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
1738
1739
0
  zrouter.lsp_process_q->spec.workfunc = &lsp_process;
1740
0
  zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
1741
0
  zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
1742
0
  zrouter.lsp_process_q->spec.max_retries = 0;
1743
0
  zrouter.lsp_process_q->spec.hold = 10;
1744
0
}
1745
1746
1747
/*
1748
 * Process LSP update results from zebra dataplane.
1749
 */
1750
void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
1751
0
{
1752
0
  struct zebra_vrf *zvrf;
1753
0
  mpls_label_t label;
1754
0
  struct zebra_ile tmp_ile;
1755
0
  struct hash *lsp_table;
1756
0
  struct zebra_lsp *lsp;
1757
0
  struct zebra_nhlfe *nhlfe;
1758
0
  struct nexthop *nexthop;
1759
0
  enum dplane_op_e op;
1760
0
  enum zebra_dplane_result status;
1761
0
  enum zebra_sr_policy_update_label_mode update_mode;
1762
1763
0
  op = dplane_ctx_get_op(ctx);
1764
0
  status = dplane_ctx_get_status(ctx);
1765
1766
0
  if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1767
0
    zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
1768
0
         ctx, dplane_op2str(op),
1769
0
         dplane_ctx_get_in_label(ctx),
1770
0
         dplane_res2str(status));
1771
1772
0
  label = dplane_ctx_get_in_label(ctx);
1773
1774
0
  switch (op) {
1775
0
  case DPLANE_OP_LSP_INSTALL:
1776
0
  case DPLANE_OP_LSP_UPDATE:
1777
    /* Look for zebra LSP object */
1778
0
    zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
1779
0
    if (zvrf == NULL)
1780
0
      break;
1781
1782
0
    lsp_table = zvrf->lsp_table;
1783
1784
0
    tmp_ile.in_label = label;
1785
0
    lsp = hash_lookup(lsp_table, &tmp_ile);
1786
0
    if (lsp == NULL) {
1787
0
      if (IS_ZEBRA_DEBUG_DPLANE)
1788
0
        zlog_debug("LSP ctx %p: in-label %u not found",
1789
0
             ctx, dplane_ctx_get_in_label(ctx));
1790
0
      break;
1791
0
    }
1792
1793
    /* TODO -- Confirm that this result is still 'current' */
1794
1795
0
    if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
1796
0
      UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1797
0
      clear_nhlfe_installed(lsp);
1798
0
      flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
1799
0
          "LSP Install Failure: in-label %u",
1800
0
          lsp->ile.in_label);
1801
0
      break;
1802
0
    }
1803
1804
    /* Update zebra object */
1805
0
    SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
1806
0
    frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
1807
0
      nexthop = nhlfe->nexthop;
1808
0
      if (!nexthop)
1809
0
        continue;
1810
1811
0
      if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) &&
1812
0
          CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
1813
0
        SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
1814
0
        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
1815
0
      }
1816
0
    }
1817
1818
0
    update_mode = (op == DPLANE_OP_LSP_INSTALL)
1819
0
              ? ZEBRA_SR_POLICY_LABEL_CREATED
1820
0
              : ZEBRA_SR_POLICY_LABEL_UPDATED;
1821
0
    zebra_sr_policy_label_update(label, update_mode);
1822
0
    break;
1823
1824
0
  case DPLANE_OP_LSP_DELETE:
1825
0
    if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
1826
0
      flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
1827
0
          "LSP Deletion Failure: in-label %u",
1828
0
          dplane_ctx_get_in_label(ctx));
1829
0
      break;
1830
0
    }
1831
0
    zebra_sr_policy_label_update(label,
1832
0
               ZEBRA_SR_POLICY_LABEL_REMOVED);
1833
0
    break;
1834
1835
0
  case DPLANE_OP_LSP_NOTIFY:
1836
0
  case DPLANE_OP_NONE:
1837
0
  case DPLANE_OP_ROUTE_INSTALL:
1838
0
  case DPLANE_OP_ROUTE_UPDATE:
1839
0
  case DPLANE_OP_ROUTE_DELETE:
1840
0
  case DPLANE_OP_ROUTE_NOTIFY:
1841
0
  case DPLANE_OP_NH_INSTALL:
1842
0
  case DPLANE_OP_NH_UPDATE:
1843
0
  case DPLANE_OP_NH_DELETE:
1844
0
  case DPLANE_OP_PW_INSTALL:
1845
0
  case DPLANE_OP_PW_UNINSTALL:
1846
0
  case DPLANE_OP_SYS_ROUTE_ADD:
1847
0
  case DPLANE_OP_SYS_ROUTE_DELETE:
1848
0
  case DPLANE_OP_ADDR_INSTALL:
1849
0
  case DPLANE_OP_ADDR_UNINSTALL:
1850
0
  case DPLANE_OP_MAC_INSTALL:
1851
0
  case DPLANE_OP_MAC_DELETE:
1852
0
  case DPLANE_OP_NEIGH_INSTALL:
1853
0
  case DPLANE_OP_NEIGH_UPDATE:
1854
0
  case DPLANE_OP_NEIGH_DELETE:
1855
0
  case DPLANE_OP_VTEP_ADD:
1856
0
  case DPLANE_OP_VTEP_DELETE:
1857
0
  case DPLANE_OP_RULE_ADD:
1858
0
  case DPLANE_OP_RULE_DELETE:
1859
0
  case DPLANE_OP_RULE_UPDATE:
1860
0
  case DPLANE_OP_NEIGH_DISCOVER:
1861
0
  case DPLANE_OP_BR_PORT_UPDATE:
1862
0
  case DPLANE_OP_IPTABLE_ADD:
1863
0
  case DPLANE_OP_IPTABLE_DELETE:
1864
0
  case DPLANE_OP_IPSET_ADD:
1865
0
  case DPLANE_OP_IPSET_DELETE:
1866
0
  case DPLANE_OP_IPSET_ENTRY_ADD:
1867
0
  case DPLANE_OP_IPSET_ENTRY_DELETE:
1868
0
  case DPLANE_OP_NEIGH_IP_INSTALL:
1869
0
  case DPLANE_OP_NEIGH_IP_DELETE:
1870
0
  case DPLANE_OP_NEIGH_TABLE_UPDATE:
1871
0
  case DPLANE_OP_GRE_SET:
1872
0
  case DPLANE_OP_INTF_ADDR_ADD:
1873
0
  case DPLANE_OP_INTF_ADDR_DEL:
1874
0
  case DPLANE_OP_INTF_NETCONFIG:
1875
0
  case DPLANE_OP_INTF_INSTALL:
1876
0
  case DPLANE_OP_INTF_UPDATE:
1877
0
  case DPLANE_OP_INTF_DELETE:
1878
0
  case DPLANE_OP_TC_QDISC_INSTALL:
1879
0
  case DPLANE_OP_TC_QDISC_UNINSTALL:
1880
0
  case DPLANE_OP_TC_CLASS_ADD:
1881
0
  case DPLANE_OP_TC_CLASS_DELETE:
1882
0
  case DPLANE_OP_TC_CLASS_UPDATE:
1883
0
  case DPLANE_OP_TC_FILTER_ADD:
1884
0
  case DPLANE_OP_TC_FILTER_DELETE:
1885
0
  case DPLANE_OP_TC_FILTER_UPDATE:
1886
0
    break;
1887
1888
0
  } /* Switch */
1889
0
}
1890
1891
/*
1892
 * Process LSP installation info from two sets of nhlfes: a set from
1893
 * a dplane notification, and a set from the zebra LSP object. Update
1894
 * counters of installed nexthops, and return whether the LSP has changed.
1895
 */
1896
static bool compare_notif_nhlfes(const struct nhlfe_list_head *ctx_head,
1897
         struct nhlfe_list_head *nhlfe_head,
1898
         int *start_counter, int *end_counter)
1899
0
{
1900
0
  struct zebra_nhlfe *nhlfe;
1901
0
  const struct zebra_nhlfe *ctx_nhlfe;
1902
0
  struct nexthop *nexthop;
1903
0
  const struct nexthop *ctx_nexthop;
1904
0
  int start_count = 0, end_count = 0;
1905
0
  bool changed_p = false;
1906
0
  bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
1907
1908
0
  frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
1909
0
    char buf[NEXTHOP_STRLEN];
1910
1911
0
    nexthop = nhlfe->nexthop;
1912
0
    if (!nexthop)
1913
0
      continue;
1914
1915
0
    if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
1916
0
      start_count++;
1917
1918
0
    ctx_nhlfe = NULL;
1919
0
    ctx_nexthop = NULL;
1920
0
    frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
1921
0
      ctx_nexthop = ctx_nhlfe->nexthop;
1922
0
      if (!ctx_nexthop)
1923
0
        continue;
1924
1925
0
      if ((ctx_nexthop->type == nexthop->type) &&
1926
0
          nexthop_same(ctx_nexthop, nexthop)) {
1927
        /* Matched */
1928
0
        break;
1929
0
      }
1930
0
    }
1931
1932
0
    if (is_debug)
1933
0
      nexthop2str(nexthop, buf, sizeof(buf));
1934
1935
0
    if (ctx_nhlfe && ctx_nexthop) {
1936
0
      if (is_debug) {
1937
0
        const char *tstr = "";
1938
1939
0
        if (!CHECK_FLAG(ctx_nhlfe->flags,
1940
0
            NHLFE_FLAG_INSTALLED))
1941
0
          tstr = "not ";
1942
1943
0
        zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
1944
0
             buf, tstr);
1945
0
      }
1946
1947
      /* Test zebra nhlfe install state */
1948
0
      if (CHECK_FLAG(ctx_nhlfe->flags,
1949
0
               NHLFE_FLAG_INSTALLED)) {
1950
1951
0
        if (!CHECK_FLAG(nhlfe->flags,
1952
0
            NHLFE_FLAG_INSTALLED))
1953
0
          changed_p = true;
1954
1955
        /* Update counter */
1956
0
        end_count++;
1957
0
      } else {
1958
1959
0
        if (CHECK_FLAG(nhlfe->flags,
1960
0
                 NHLFE_FLAG_INSTALLED))
1961
0
          changed_p = true;
1962
0
      }
1963
1964
0
    } else {
1965
      /* Not mentioned in lfib set -> uninstalled */
1966
0
      if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ||
1967
0
          CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ||
1968
0
          CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
1969
0
        changed_p = true;
1970
0
      }
1971
1972
0
      if (is_debug)
1973
0
        zlog_debug("LSP dplane notif: no match, nh %s",
1974
0
             buf);
1975
0
    }
1976
0
  }
1977
1978
0
  if (start_counter)
1979
0
    *start_counter += start_count;
1980
0
  if (end_counter)
1981
0
    *end_counter += end_count;
1982
1983
0
  return changed_p;
1984
0
}
1985
1986
/*
1987
 * Update an lsp nhlfe list from a dplane context, typically an async
1988
 * notification context. Update the LSP list to match the installed
1989
 * status from the context's list.
1990
 */
1991
static int update_nhlfes_from_ctx(struct nhlfe_list_head *nhlfe_head,
1992
          const struct nhlfe_list_head *ctx_head)
1993
0
{
1994
0
  int ret = 0;
1995
0
  struct zebra_nhlfe *nhlfe;
1996
0
  const struct zebra_nhlfe *ctx_nhlfe;
1997
0
  struct nexthop *nexthop;
1998
0
  const struct nexthop *ctx_nexthop;
1999
0
  bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
2000
2001
0
  frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
2002
0
    char buf[NEXTHOP_STRLEN];
2003
2004
0
    nexthop = nhlfe->nexthop;
2005
0
    if (!nexthop)
2006
0
      continue;
2007
2008
0
    ctx_nhlfe = NULL;
2009
0
    ctx_nexthop = NULL;
2010
0
    frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
2011
0
      ctx_nexthop = ctx_nhlfe->nexthop;
2012
0
      if (!ctx_nexthop)
2013
0
        continue;
2014
2015
0
      if ((ctx_nexthop->type == nexthop->type) &&
2016
0
          nexthop_same(ctx_nexthop, nexthop)) {
2017
        /* Matched */
2018
0
        break;
2019
0
      }
2020
0
    }
2021
2022
0
    if (is_debug)
2023
0
      nexthop2str(nexthop, buf, sizeof(buf));
2024
2025
0
    if (ctx_nhlfe && ctx_nexthop) {
2026
2027
      /* Bring zebra nhlfe install state into sync */
2028
0
      if (CHECK_FLAG(ctx_nhlfe->flags,
2029
0
               NHLFE_FLAG_INSTALLED)) {
2030
0
        if (is_debug)
2031
0
          zlog_debug("%s: matched lsp nhlfe %s (installed)",
2032
0
               __func__, buf);
2033
2034
0
        SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2035
0
        SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2036
2037
0
      } else {
2038
0
        if (is_debug)
2039
0
          zlog_debug("%s: matched lsp nhlfe %s (not installed)",
2040
0
               __func__, buf);
2041
2042
0
        UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2043
0
        UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2044
0
      }
2045
2046
0
      if (CHECK_FLAG(ctx_nhlfe->nexthop->flags,
2047
0
               NEXTHOP_FLAG_FIB)) {
2048
0
        SET_FLAG(nhlfe->nexthop->flags,
2049
0
           NEXTHOP_FLAG_ACTIVE);
2050
0
        SET_FLAG(nhlfe->nexthop->flags,
2051
0
           NEXTHOP_FLAG_FIB);
2052
0
      } else {
2053
0
        UNSET_FLAG(nhlfe->nexthop->flags,
2054
0
           NEXTHOP_FLAG_ACTIVE);
2055
0
        UNSET_FLAG(nhlfe->nexthop->flags,
2056
0
             NEXTHOP_FLAG_FIB);
2057
0
      }
2058
2059
0
    } else {
2060
      /* Not mentioned in lfib set -> uninstalled */
2061
0
      if (is_debug)
2062
0
        zlog_debug("%s: no match for lsp nhlfe %s",
2063
0
             __func__, buf);
2064
0
      UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
2065
0
      UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
2066
0
      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
2067
0
      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2068
0
    }
2069
0
  }
2070
2071
0
  return ret;
2072
0
}
2073
2074
/*
2075
 * Process async dplane notifications.
2076
 */
2077
void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
2078
0
{
2079
0
  struct zebra_vrf *zvrf;
2080
0
  struct zebra_ile tmp_ile;
2081
0
  struct hash *lsp_table;
2082
0
  struct zebra_lsp *lsp;
2083
0
  const struct nhlfe_list_head *ctx_list;
2084
0
  int start_count = 0, end_count = 0; /* Installed counts */
2085
0
  bool changed_p = false;
2086
0
  bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
2087
0
  enum zebra_sr_policy_update_label_mode update_mode;
2088
2089
0
  if (is_debug)
2090
0
    zlog_debug("LSP dplane notif, in-label %u",
2091
0
         dplane_ctx_get_in_label(ctx));
2092
2093
  /* Look for zebra LSP object */
2094
0
  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
2095
0
  if (zvrf == NULL)
2096
0
    return;
2097
2098
0
  lsp_table = zvrf->lsp_table;
2099
2100
0
  tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
2101
0
  lsp = hash_lookup(lsp_table, &tmp_ile);
2102
0
  if (lsp == NULL) {
2103
0
    if (is_debug)
2104
0
      zlog_debug("dplane LSP notif: in-label %u not found",
2105
0
           dplane_ctx_get_in_label(ctx));
2106
0
    return;
2107
0
  }
2108
2109
  /*
2110
   * The dataplane/forwarding plane is notifying zebra about the state
2111
   * of the nexthops associated with this LSP. First, we take a
2112
   * pre-scan pass to determine whether the LSP has transitioned
2113
   * from installed -> uninstalled. In that case, we need to have
2114
   * the existing state of the LSP objects available before making
2115
   * any changes.
2116
   */
2117
0
  ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2118
2119
0
  changed_p = compare_notif_nhlfes(ctx_list, &lsp->nhlfe_list,
2120
0
           &start_count, &end_count);
2121
2122
0
  if (is_debug)
2123
0
    zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
2124
0
         start_count, end_count,
2125
0
         changed_p ? ", changed" : "");
2126
2127
0
  ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2128
2129
0
  if (compare_notif_nhlfes(ctx_list, &lsp->backup_nhlfe_list,
2130
0
         &start_count, &end_count))
2131
    /* Avoid accidentally setting back to 'false' */
2132
0
    changed_p = true;
2133
2134
0
  if (is_debug)
2135
0
    zlog_debug("LSP dplane notif: lfib backups, start_count %d, end_count %d%s",
2136
0
         start_count, end_count,
2137
0
         changed_p ? ", changed" : "");
2138
2139
  /*
2140
   * Has the LSP become uninstalled? We need the existing state of the
2141
   * nexthops/nhlfes at this point so we know what to delete.
2142
   */
2143
0
  if (start_count > 0 && end_count == 0) {
2144
    /* Inform other lfibs */
2145
0
    dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
2146
0
  }
2147
2148
  /*
2149
   * Now we take a second pass and bring the zebra
2150
   * nexthop state into sync with the forwarding-plane state.
2151
   */
2152
0
  ctx_list = dplane_ctx_get_nhlfe_list(ctx);
2153
0
  update_nhlfes_from_ctx(&lsp->nhlfe_list, ctx_list);
2154
2155
0
  ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
2156
0
  update_nhlfes_from_ctx(&lsp->backup_nhlfe_list, ctx_list);
2157
2158
0
  if (end_count > 0) {
2159
0
    SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2160
2161
    /* SR-TE update too */
2162
0
    if (start_count == 0)
2163
0
      update_mode = ZEBRA_SR_POLICY_LABEL_CREATED;
2164
0
    else
2165
0
      update_mode = ZEBRA_SR_POLICY_LABEL_UPDATED;
2166
0
    zebra_sr_policy_label_update(lsp->ile.in_label, update_mode);
2167
2168
0
    if (changed_p)
2169
0
      dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
2170
2171
0
  } else {
2172
    /* SR-TE update too */
2173
0
    zebra_sr_policy_label_update(lsp->ile.in_label,
2174
0
               ZEBRA_SR_POLICY_LABEL_REMOVED);
2175
2176
0
    UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
2177
0
    clear_nhlfe_installed(lsp);
2178
0
  }
2179
0
}
2180
2181
/*
2182
 * Install dynamic LSP entry.
2183
 */
2184
int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
2185
         struct route_entry *re)
2186
0
{
2187
0
  struct route_table *table;
2188
0
  struct zebra_fec *fec;
2189
2190
0
  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2191
0
  if (!table)
2192
0
    return -1;
2193
2194
  /* See if there is a configured label binding for this FEC. */
2195
0
  fec = fec_find(table, &rn->p);
2196
0
  if (!fec || fec->label == MPLS_INVALID_LABEL)
2197
0
    return 0;
2198
2199
  /* We cannot install a label forwarding entry if local label is the
2200
   * implicit-null label.
2201
   */
2202
0
  if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
2203
0
    return 0;
2204
2205
0
  if (lsp_install(zvrf, fec->label, rn, re))
2206
0
    return -1;
2207
2208
0
  return 0;
2209
0
}
2210
2211
/*
2212
 * Uninstall dynamic LSP entry, if any.
2213
 */
2214
int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
2215
           struct route_entry *re)
2216
0
{
2217
0
  struct route_table *table;
2218
0
  struct zebra_fec *fec;
2219
2220
0
  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
2221
0
  if (!table)
2222
0
    return -1;
2223
2224
  /* See if there is a configured label binding for this FEC. */
2225
0
  fec = fec_find(table, &rn->p);
2226
0
  if (!fec || fec->label == MPLS_INVALID_LABEL)
2227
0
    return 0;
2228
2229
  /* Uninstall always removes all dynamic NHLFEs. */
2230
0
  return lsp_uninstall(zvrf, fec->label);
2231
0
}
2232
2233
/*
2234
 * Add an NHLFE to an LSP, return the newly-added object. This path only changes
2235
 * the LSP object - nothing is scheduled for processing, for example.
2236
 */
2237
struct zebra_nhlfe *
2238
zebra_mpls_lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
2239
       enum nexthop_types_t gtype, const union g_addr *gate,
2240
       ifindex_t ifindex, uint8_t num_labels,
2241
       const mpls_label_t *out_labels)
2242
0
{
2243
  /* Just a public pass-through to the internal implementation */
2244
0
  return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, VRF_DEFAULT,
2245
0
       num_labels, out_labels, false /*backup*/);
2246
0
}
2247
2248
/*
2249
 * Add a backup NHLFE to an LSP, return the newly-added object.
2250
 * This path only changes the LSP object - nothing is scheduled for
2251
 * processing, for example.
2252
 */
2253
struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nhlfe(
2254
  struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
2255
  enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex,
2256
  uint8_t num_labels, const mpls_label_t *out_labels)
2257
0
{
2258
  /* Just a public pass-through to the internal implementation */
2259
0
  return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, VRF_DEFAULT,
2260
0
       num_labels, out_labels, true);
2261
0
}
2262
2263
/*
2264
 * Add an NHLFE to an LSP based on a nexthop; return the newly-added object
2265
 */
2266
struct zebra_nhlfe *zebra_mpls_lsp_add_nh(struct zebra_lsp *lsp,
2267
            enum lsp_types_t lsp_type,
2268
            const struct nexthop *nh)
2269
0
{
2270
0
  struct zebra_nhlfe *nhlfe;
2271
2272
0
  nhlfe = nhlfe_add(
2273
0
    lsp, lsp_type, nh->type, &nh->gate, nh->ifindex, nh->vrf_id,
2274
0
    nh->nh_label ? nh->nh_label->num_labels : 0,
2275
0
    nh->nh_label ? nh->nh_label->label : NULL, false /*backup*/);
2276
2277
0
  return nhlfe;
2278
0
}
2279
2280
/*
2281
 * Add a backup NHLFE to an LSP based on a nexthop;
2282
 * return the newly-added object.
2283
 */
2284
struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nh(struct zebra_lsp *lsp,
2285
             enum lsp_types_t lsp_type,
2286
             const struct nexthop *nh)
2287
0
{
2288
0
  struct zebra_nhlfe *nhlfe;
2289
2290
0
  nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, nh->ifindex,
2291
0
        nh->vrf_id,
2292
0
        nh->nh_label ? nh->nh_label->num_labels : 0,
2293
0
        nh->nh_label ? nh->nh_label->label : NULL, true);
2294
2295
0
  return nhlfe;
2296
0
}
2297
2298
/*
2299
 * Free an allocated NHLFE
2300
 */
2301
void zebra_mpls_nhlfe_free(struct zebra_nhlfe *nhlfe)
2302
0
{
2303
  /* Just a pass-through to the internal implementation */
2304
0
  nhlfe_free(nhlfe);
2305
0
}
2306
2307
/*
2308
 * Registration from a client for the label binding for a FEC. If a binding
2309
 * already exists, it is informed to the client.
2310
 * NOTE: If there is a manually configured label binding, that is used.
2311
 * Otherwise, if a label index is specified, it means we have to allocate the
2312
 * label from a locally configured label block (SRGB), if one exists and index
2313
 * is acceptable. If no label index then just register the specified label.
2314
 * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
2315
 * by the calling function. Register requests with both will be rejected.
2316
 */
2317
int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
2318
          uint32_t label, uint32_t label_index,
2319
          struct zserv *client)
2320
3.34k
{
2321
3.34k
  struct route_table *table;
2322
3.34k
  struct zebra_fec *fec;
2323
3.34k
  bool new_client;
2324
3.34k
  bool label_change = false;
2325
3.34k
  uint32_t old_label;
2326
3.34k
  bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
2327
3.34k
  bool is_configured_fec = false; /* indicate statically configured FEC */
2328
2329
3.34k
  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2330
3.34k
  if (!table)
2331
0
    return -1;
2332
2333
3.34k
  if (label != MPLS_INVALID_LABEL && have_label_index) {
2334
210
    flog_err(
2335
210
      EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
2336
210
      "Rejecting FEC register for %pFX with both label %u and Label Index %u specified, client %s",
2337
210
      p, label, label_index,
2338
210
      zebra_route_string(client->proto));
2339
210
    return -1;
2340
210
  }
2341
2342
  /* Locate FEC */
2343
3.13k
  fec = fec_find(table, p);
2344
3.13k
  if (!fec) {
2345
215
    fec = fec_add(table, p, label, 0, label_index);
2346
215
    if (!fec) {
2347
0
      flog_err(
2348
0
        EC_ZEBRA_FEC_ADD_FAILED,
2349
0
        "Failed to add FEC %pFX upon register, client %s",
2350
0
        p, zebra_route_string(client->proto));
2351
0
      return -1;
2352
0
    }
2353
2354
215
    old_label = MPLS_INVALID_LABEL;
2355
215
    new_client = true;
2356
2.92k
  } else {
2357
    /* Check if the FEC has been statically defined in the config */
2358
2.92k
    is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
2359
    /* Client may register same FEC with different label index. */
2360
2.92k
    new_client =
2361
2.92k
      (listnode_lookup(fec->client_list, client) == NULL);
2362
2.92k
    if (!new_client && fec->label_index == label_index
2363
2.55k
        && fec->label == label)
2364
      /* Duplicate register */
2365
844
      return 0;
2366
2367
    /* Save current label, update the FEC */
2368
2.07k
    old_label = fec->label;
2369
2.07k
    fec->label_index = label_index;
2370
2.07k
  }
2371
2372
2.29k
  if (new_client)
2373
361
    listnode_add(fec->client_list, client);
2374
2375
2.29k
  if (IS_ZEBRA_DEBUG_MPLS)
2376
0
    zlog_debug("FEC %pFX label%s %u %s by client %s%s", p,
2377
2.29k
         have_label_index ? " index" : "",
2378
2.29k
         have_label_index ? label_index : label,
2379
2.29k
         new_client ? "registered" : "updated",
2380
2.29k
         zebra_route_string(client->proto),
2381
2.29k
         is_configured_fec
2382
2.29k
           ? ", but using statically configured label"
2383
2.29k
           : "");
2384
2385
  /* If not a statically configured FEC, derive the local label
2386
   * from label index or use the provided label
2387
   */
2388
2.29k
  if (!is_configured_fec) {
2389
2.29k
    if (have_label_index)
2390
823
      fec_derive_label_from_index(zvrf, fec);
2391
1.47k
    else
2392
1.47k
      fec->label = label;
2393
2394
    /* If no label change, exit. */
2395
2.29k
    if (fec->label == old_label)
2396
690
      return 0;
2397
2398
1.60k
    label_change = true;
2399
1.60k
  }
2400
2401
  /* If new client or label change, update client and install or uninstall
2402
   * label forwarding entry as needed.
2403
   */
2404
  /* Inform client of label, if needed. */
2405
1.60k
  if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
2406
1.60k
    if (IS_ZEBRA_DEBUG_MPLS)
2407
0
      zlog_debug("Update client label %u", fec->label);
2408
1.60k
    fec_send(fec, client);
2409
1.60k
  }
2410
2411
1.60k
  if (new_client || label_change)
2412
1.60k
    return fec_change_update_lsp(zvrf, fec, old_label);
2413
2414
0
  return 0;
2415
1.60k
}
2416
2417
/*
2418
 * Deregistration from a client for the label binding for a FEC. The FEC
2419
 * itself is deleted if no other registered clients exist and there is no
2420
 * label bound to the FEC.
2421
 */
2422
int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
2423
            struct zserv *client)
2424
0
{
2425
0
  struct route_table *table;
2426
0
  struct zebra_fec *fec;
2427
2428
0
  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2429
0
  if (!table)
2430
0
    return -1;
2431
2432
0
  fec = fec_find(table, p);
2433
0
  if (!fec) {
2434
0
    flog_err(EC_ZEBRA_FEC_RM_FAILED,
2435
0
       "Failed to find FEC %pFX upon unregister, client %s",
2436
0
       p, zebra_route_string(client->proto));
2437
0
    return -1;
2438
0
  }
2439
2440
0
  listnode_delete(fec->client_list, client);
2441
2442
0
  if (IS_ZEBRA_DEBUG_MPLS)
2443
0
    zlog_debug("FEC %pFX unregistered by client %s", p,
2444
0
         zebra_route_string(client->proto));
2445
2446
  /* If not a configured entry, delete the FEC if no other clients. Before
2447
   * deleting, see if any LSP needs to be uninstalled.
2448
   */
2449
0
  if (!(fec->flags & FEC_FLAG_CONFIGURED)
2450
0
      && list_isempty(fec->client_list)) {
2451
0
    mpls_label_t old_label = fec->label;
2452
0
    fec->label = MPLS_INVALID_LABEL; /* reset */
2453
0
    fec_change_update_lsp(zvrf, fec, old_label);
2454
0
    fec_del(fec);
2455
0
  }
2456
2457
0
  return 0;
2458
0
}
2459
2460
/*
2461
 * Cleanup any FECs registered by this client.
2462
 */
2463
static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
2464
0
{
2465
0
  struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
2466
0
  struct route_node *rn;
2467
0
  struct zebra_fec *fec;
2468
0
  struct listnode *node;
2469
0
  struct zserv *fec_client;
2470
0
  int af;
2471
2472
0
  for (af = AFI_IP; af < AFI_MAX; af++) {
2473
0
    if (zvrf->fec_table[af] == NULL)
2474
0
      continue;
2475
2476
0
    for (rn = route_top(zvrf->fec_table[af]); rn;
2477
0
         rn = route_next(rn)) {
2478
0
      fec = rn->info;
2479
0
      if (!fec || list_isempty(fec->client_list))
2480
0
        continue;
2481
2482
0
      for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
2483
0
              fec_client)) {
2484
0
        if (fec_client == client) {
2485
0
          listnode_delete(fec->client_list,
2486
0
              fec_client);
2487
0
          if (!(fec->flags & FEC_FLAG_CONFIGURED)
2488
0
              && list_isempty(fec->client_list))
2489
0
            fec_del(fec);
2490
0
          break;
2491
0
        }
2492
0
      }
2493
0
    }
2494
0
  }
2495
2496
0
  return 0;
2497
0
}
2498
2499
struct lsp_uninstall_args {
2500
  struct hash *lsp_table;
2501
  enum lsp_types_t type;
2502
};
2503
2504
/*
2505
 * Cleanup MPLS labels registered by this client.
2506
 */
2507
static int zebra_mpls_cleanup_zclient_labels(struct zserv *client)
2508
0
{
2509
0
  struct vrf *vrf;
2510
0
  struct zebra_vrf *zvrf;
2511
2512
0
  RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
2513
0
    struct lsp_uninstall_args args;
2514
2515
0
    zvrf = vrf->info;
2516
0
    if (!zvrf)
2517
0
      continue;
2518
2519
    /* Cleanup LSPs. */
2520
0
    args.lsp_table = zvrf->lsp_table;
2521
0
    args.type = lsp_type_from_re_type(client->proto);
2522
0
    hash_iterate(zvrf->lsp_table, mpls_lsp_uninstall_all_type,
2523
0
           &args);
2524
2525
    /* Cleanup FTNs. */
2526
0
    mpls_ftn_uninstall_all(zvrf, AFI_IP,
2527
0
               lsp_type_from_re_type(client->proto));
2528
0
    mpls_ftn_uninstall_all(zvrf, AFI_IP6,
2529
0
               lsp_type_from_re_type(client->proto));
2530
0
  }
2531
2532
0
  return 0;
2533
0
}
2534
2535
/*
2536
 * Return FEC (if any) to which this label is bound.
2537
 * Note: Only works for per-prefix binding and when the label is not
2538
 * implicit-null.
2539
 * TODO: Currently walks entire table, can optimize later with another
2540
 * hash..
2541
 */
2542
struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
2543
             mpls_label_t label)
2544
0
{
2545
0
  struct route_node *rn;
2546
0
  struct zebra_fec *fec;
2547
0
  int af;
2548
2549
0
  for (af = AFI_IP; af < AFI_MAX; af++) {
2550
0
    if (zvrf->fec_table[af] == NULL)
2551
0
      continue;
2552
2553
0
    for (rn = route_top(zvrf->fec_table[af]); rn;
2554
0
         rn = route_next(rn)) {
2555
0
      if (!rn->info)
2556
0
        continue;
2557
0
      fec = rn->info;
2558
0
      if (fec->label == label)
2559
0
        return fec;
2560
0
    }
2561
0
  }
2562
2563
0
  return NULL;
2564
0
}
2565
2566
/*
2567
 * Inform if specified label is currently bound to a FEC or not.
2568
 */
2569
int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
2570
0
{
2571
0
  return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
2572
0
}
2573
2574
/*
2575
 * Add static FEC to label binding. If there are clients registered for this
2576
 * FEC, notify them. If there are labeled routes for this FEC, install the
2577
 * label forwarding entry.
2578
*/
2579
int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
2580
            mpls_label_t in_label)
2581
0
{
2582
0
  struct route_table *table;
2583
0
  struct zebra_fec *fec;
2584
0
  mpls_label_t old_label;
2585
0
  int ret = 0;
2586
2587
0
  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2588
0
  if (!table)
2589
0
    return -1;
2590
2591
  /* Update existing FEC or create a new one. */
2592
0
  fec = fec_find(table, p);
2593
0
  if (!fec) {
2594
0
    fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
2595
0
            MPLS_INVALID_LABEL_INDEX);
2596
0
    if (!fec) {
2597
0
      flog_err(EC_ZEBRA_FEC_ADD_FAILED,
2598
0
         "Failed to add FEC %pFX upon config", p);
2599
0
      return -1;
2600
0
    }
2601
2602
0
    if (IS_ZEBRA_DEBUG_MPLS)
2603
0
      zlog_debug("Add fec %pFX label %u", p, in_label);
2604
0
  } else {
2605
0
    fec->flags |= FEC_FLAG_CONFIGURED;
2606
0
    if (fec->label == in_label)
2607
      /* Duplicate config */
2608
0
      return 0;
2609
2610
    /* Label change, update clients. */
2611
0
    old_label = fec->label;
2612
0
    if (IS_ZEBRA_DEBUG_MPLS)
2613
0
      zlog_debug("Update fec %pFX new label %u", p, in_label);
2614
2615
0
    fec->label = in_label;
2616
0
    fec_update_clients(fec);
2617
2618
    /* Update label forwarding entries appropriately */
2619
0
    ret = fec_change_update_lsp(zvrf, fec, old_label);
2620
0
  }
2621
2622
0
  return ret;
2623
0
}
2624
2625
/*
2626
 * Remove static FEC to label binding. If there are no clients registered
2627
 * for this FEC, delete the FEC; else notify clients
2628
 * Note: Upon delete of static binding, if label index exists for this FEC,
2629
 * client may need to be updated with derived label.
2630
 */
2631
int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
2632
0
{
2633
0
  struct route_table *table;
2634
0
  struct zebra_fec *fec;
2635
0
  mpls_label_t old_label;
2636
2637
0
  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2638
0
  if (!table)
2639
0
    return -1;
2640
2641
0
  fec = fec_find(table, p);
2642
0
  if (!fec) {
2643
0
    flog_err(EC_ZEBRA_FEC_RM_FAILED,
2644
0
       "Failed to find FEC %pFX upon delete", p);
2645
0
    return -1;
2646
0
  }
2647
2648
0
  if (IS_ZEBRA_DEBUG_MPLS) {
2649
0
    zlog_debug("Delete fec %pFX label %u label index %u", p,
2650
0
         fec->label, fec->label_index);
2651
0
  }
2652
2653
0
  old_label = fec->label;
2654
0
  fec->flags &= ~FEC_FLAG_CONFIGURED;
2655
0
  fec->label = MPLS_INVALID_LABEL;
2656
2657
  /* If no client exists, just delete the FEC. */
2658
0
  if (list_isempty(fec->client_list)) {
2659
0
    fec_del(fec);
2660
0
    return 0;
2661
0
  }
2662
2663
  /* Derive the local label (from label index) or reset it. */
2664
0
  fec_derive_label_from_index(zvrf, fec);
2665
2666
  /* If there is a label change, update clients. */
2667
0
  if (fec->label == old_label)
2668
0
    return 0;
2669
0
  fec_update_clients(fec);
2670
2671
  /* Update label forwarding entries appropriately */
2672
0
  return fec_change_update_lsp(zvrf, fec, old_label);
2673
0
}
2674
2675
/*
2676
 * Display MPLS FEC to label binding configuration (VTY command handler).
2677
 */
2678
int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
2679
0
{
2680
0
  struct route_node *rn;
2681
0
  int af;
2682
0
  struct zebra_fec *fec;
2683
0
  int write = 0;
2684
2685
0
  for (af = AFI_IP; af < AFI_MAX; af++) {
2686
0
    if (zvrf->fec_table[af] == NULL)
2687
0
      continue;
2688
2689
0
    for (rn = route_top(zvrf->fec_table[af]); rn;
2690
0
         rn = route_next(rn)) {
2691
0
      if (!rn->info)
2692
0
        continue;
2693
2694
0
      char lstr[BUFSIZ];
2695
0
      fec = rn->info;
2696
2697
0
      if (!(fec->flags & FEC_FLAG_CONFIGURED))
2698
0
        continue;
2699
2700
0
      write = 1;
2701
0
      vty_out(vty, "mpls label bind %pFX %s\n", &rn->p,
2702
0
        label2str(fec->label, 0, lstr, BUFSIZ));
2703
0
    }
2704
0
  }
2705
2706
0
  return write;
2707
0
}
2708
2709
/*
2710
 * Display MPLS FEC to label binding (VTY command handler).
2711
 */
2712
void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
2713
0
{
2714
0
  struct route_node *rn;
2715
0
  int af;
2716
2717
0
  for (af = AFI_IP; af < AFI_MAX; af++) {
2718
0
    if (zvrf->fec_table[af] == NULL)
2719
0
      continue;
2720
2721
0
    for (rn = route_top(zvrf->fec_table[af]); rn;
2722
0
         rn = route_next(rn)) {
2723
0
      if (!rn->info)
2724
0
        continue;
2725
0
      fec_print(rn->info, vty);
2726
0
    }
2727
0
  }
2728
0
}
2729
2730
/*
2731
 * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
2732
 */
2733
void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
2734
        struct prefix *p)
2735
0
{
2736
0
  struct route_table *table;
2737
0
  struct route_node *rn;
2738
2739
0
  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
2740
0
  if (!table)
2741
0
    return;
2742
2743
0
  apply_mask(p);
2744
0
  rn = route_node_lookup(table, p);
2745
0
  if (!rn)
2746
0
    return;
2747
2748
0
  route_unlock_node(rn);
2749
0
  if (!rn->info)
2750
0
    return;
2751
2752
0
  fec_print(rn->info, vty);
2753
0
}
2754
2755
static void mpls_zebra_nhe_update(struct route_entry *re, afi_t afi,
2756
          struct nhg_hash_entry *new_nhe)
2757
0
{
2758
0
  struct nhg_hash_entry *nhe;
2759
2760
0
  nhe = zebra_nhg_rib_find_nhe(new_nhe, afi);
2761
2762
0
  route_entry_update_nhe(re, nhe);
2763
0
}
2764
2765
static bool ftn_update_nexthop(bool add_p, struct nexthop *nexthop,
2766
             enum lsp_types_t type,
2767
             const struct zapi_nexthop *znh)
2768
0
{
2769
0
  if (add_p && nexthop->nh_label_type == ZEBRA_LSP_NONE)
2770
0
    nexthop_add_labels(nexthop, type, znh->label_num, znh->labels);
2771
0
  else if (!add_p && nexthop->nh_label_type == type)
2772
0
    nexthop_del_labels(nexthop);
2773
0
  else
2774
0
    return false;
2775
2776
0
  return true;
2777
0
}
2778
2779
void zebra_mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
2780
            struct prefix *prefix, uint8_t route_type,
2781
            uint8_t route_instance)
2782
0
{
2783
0
  struct route_table *table;
2784
0
  struct route_node *rn;
2785
0
  struct route_entry *re;
2786
0
  struct nexthop *nexthop;
2787
0
  struct nhg_hash_entry *new_nhe;
2788
0
  afi_t afi = family2afi(prefix->family);
2789
2790
  /* Lookup table.  */
2791
0
  table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2792
0
  if (!table)
2793
0
    return;
2794
2795
  /* Lookup existing route */
2796
0
  rn = route_node_get(table, prefix);
2797
0
  RNODE_FOREACH_RE (rn, re) {
2798
0
    if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2799
0
      continue;
2800
0
    if (re->type == route_type && re->instance == route_instance)
2801
0
      break;
2802
0
  }
2803
0
  if (re == NULL)
2804
0
    return;
2805
2806
  /*
2807
   * Nexthops are now shared by multiple routes, so we have to make
2808
   * a local copy, modify the copy, then update the route.
2809
   */
2810
0
  new_nhe = zebra_nhe_copy(re->nhe, 0);
2811
2812
0
  for (nexthop = new_nhe->nhg.nexthop; nexthop; nexthop = nexthop->next)
2813
0
    nexthop_del_labels(nexthop);
2814
2815
  /* Update backup routes/nexthops also, if present. */
2816
0
  if (zebra_nhg_get_backup_nhg(new_nhe) != NULL) {
2817
0
    for (nexthop = new_nhe->backup_info->nhe->nhg.nexthop; nexthop;
2818
0
         nexthop = nexthop->next)
2819
0
      nexthop_del_labels(nexthop);
2820
0
  }
2821
2822
0
  SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2823
0
  SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
2824
2825
  /* This will create (or ref) a new nhe, so we will discard the local
2826
   * temporary nhe
2827
   */
2828
0
  mpls_zebra_nhe_update(re, afi, new_nhe);
2829
2830
0
  zebra_nhg_free(new_nhe);
2831
2832
0
  rib_queue_add(rn);
2833
0
}
2834
2835
/*
2836
 * Iterate through a list of nexthops, for a match for 'znh'. If found,
2837
 * update its labels according to 'add_p', and return 'true' if successful.
2838
 */
2839
static bool ftn_update_znh(bool add_p, enum lsp_types_t type,
2840
         struct nexthop *head, const struct zapi_nexthop *znh)
2841
0
{
2842
0
  bool found = false, success = false;
2843
0
  struct nexthop *nexthop;
2844
2845
0
  for (nexthop = head; nexthop; nexthop = nexthop->next) {
2846
0
    switch (nexthop->type) {
2847
0
    case NEXTHOP_TYPE_IPV4:
2848
0
    case NEXTHOP_TYPE_IPV4_IFINDEX:
2849
0
      if (znh->type != NEXTHOP_TYPE_IPV4
2850
0
          && znh->type != NEXTHOP_TYPE_IPV4_IFINDEX)
2851
0
        continue;
2852
0
      if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4,
2853
0
              &znh->gate.ipv4))
2854
0
        continue;
2855
0
      if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
2856
0
          && nexthop->ifindex != znh->ifindex)
2857
0
        continue;
2858
2859
0
      found = true;
2860
2861
0
      if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2862
0
        break;
2863
2864
0
      success = true;
2865
0
      break;
2866
0
    case NEXTHOP_TYPE_IPV6:
2867
0
    case NEXTHOP_TYPE_IPV6_IFINDEX:
2868
0
      if (znh->type != NEXTHOP_TYPE_IPV6
2869
0
          && znh->type != NEXTHOP_TYPE_IPV6_IFINDEX)
2870
0
        continue;
2871
0
      if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6,
2872
0
              &znh->gate.ipv6))
2873
0
        continue;
2874
0
      if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
2875
0
          && nexthop->ifindex != znh->ifindex)
2876
0
        continue;
2877
2878
0
      found = true;
2879
2880
0
      if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2881
0
        break;
2882
0
      success = true;
2883
0
      break;
2884
0
    case NEXTHOP_TYPE_IFINDEX:
2885
0
      if (znh->type != NEXTHOP_TYPE_IFINDEX)
2886
0
        continue;
2887
0
      if (nexthop->ifindex != znh->ifindex)
2888
0
        continue;
2889
2890
0
      found = true;
2891
2892
0
      if (!ftn_update_nexthop(add_p, nexthop, type, znh))
2893
0
        break;
2894
0
      success = true;
2895
0
      break;
2896
0
    case NEXTHOP_TYPE_BLACKHOLE:
2897
      /* Not valid */
2898
0
      continue;
2899
0
    }
2900
2901
0
    if (found)
2902
0
      break;
2903
0
  }
2904
2905
0
  return success;
2906
0
}
2907
2908
/*
2909
 * Install/uninstall LSP and (optionally) FEC-To-NHLFE (FTN) bindings,
2910
 * using zapi message info.
2911
 * There are several changes that need to be made, in several zebra
2912
 * data structures, so we want to do all the work required at once.
2913
 */
2914
void zebra_mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
2915
            const struct zapi_labels *zl)
2916
0
{
2917
0
  int i, counter, ret = 0;
2918
0
  char buf[NEXTHOP_STRLEN];
2919
0
  const struct zapi_nexthop *znh;
2920
0
  struct route_table *table;
2921
0
  struct route_node *rn = NULL;
2922
0
  struct route_entry *re = NULL;
2923
0
  struct nhg_hash_entry *new_nhe = NULL;
2924
0
  bool found;
2925
0
  afi_t afi = AFI_IP;
2926
0
  const struct prefix *prefix = NULL;
2927
0
  struct hash *lsp_table;
2928
0
  struct zebra_ile tmp_ile;
2929
0
  struct zebra_lsp *lsp = NULL;
2930
2931
  /* Prep LSP for add case */
2932
0
  if (add_p) {
2933
    /* Lookup table. */
2934
0
    lsp_table = zvrf->lsp_table;
2935
0
    if (!lsp_table)
2936
0
      return;
2937
2938
    /* Find or create LSP object */
2939
0
    tmp_ile.in_label = zl->local_label;
2940
0
    lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
2941
0
  }
2942
2943
  /* Prep for route/FEC update if requested */
2944
0
  if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
2945
0
    prefix = &zl->route.prefix;
2946
2947
0
    afi = family2afi(prefix->family);
2948
2949
    /* Lookup table.  */
2950
0
    table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
2951
0
    if (table) {
2952
      /* Lookup existing route */
2953
0
      rn = route_node_get(table, prefix);
2954
0
      RNODE_FOREACH_RE(rn, re) {
2955
0
        if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2956
0
          continue;
2957
0
        if (re->type == zl->route.type &&
2958
0
            re->instance == zl->route.instance)
2959
0
          break;
2960
0
      }
2961
0
    }
2962
2963
0
    if (re) {
2964
      /*
2965
       * Copy over current nexthops into a temporary group.
2966
       * We can't just change the values here since the nhgs
2967
       * are shared and if the labels change, we'll need
2968
       * to find or create a new nhg. We need to create
2969
       * a whole temporary group, make changes to it,
2970
       * then attach that to the route.
2971
       */
2972
0
      new_nhe = zebra_nhe_copy(re->nhe, 0);
2973
2974
0
    } else {
2975
      /*
2976
       * The old version of the zapi code
2977
       * attempted to manage LSPs before trying to
2978
       * find a route/FEC, so we'll continue that way.
2979
       */
2980
0
      if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS)
2981
0
        zlog_debug(
2982
0
          "%s: FTN update requested: no route for prefix %pFX",
2983
0
          __func__, prefix);
2984
0
    }
2985
0
  }
2986
2987
  /*
2988
   * Use info from the zapi nexthops to add/replace/remove LSP/FECs
2989
   */
2990
2991
0
  counter = 0;
2992
0
  for (i = 0; i < zl->nexthop_num; i++) {
2993
2994
0
    znh = &zl->nexthops[i];
2995
2996
    /* Attempt LSP update */
2997
0
    if (add_p)
2998
0
      ret = lsp_znh_install(lsp, zl->type, znh);
2999
0
    else
3000
0
      ret = mpls_lsp_uninstall(zvrf, zl->type,
3001
0
             zl->local_label, znh->type,
3002
0
             &znh->gate, znh->ifindex,
3003
0
             false);
3004
0
    if (ret < 0) {
3005
0
      if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS) {
3006
0
        zapi_nexthop2str(znh, buf, sizeof(buf));
3007
0
        zlog_debug("%s: Unable to %sinstall LSP: label %u, znh %s",
3008
0
             __func__, (add_p ? "" : "un"),
3009
0
             zl->local_label, buf);
3010
0
      }
3011
0
      continue;
3012
0
    }
3013
3014
    /* Attempt route/FEC update if requested */
3015
0
    if (re == NULL)
3016
0
      continue;
3017
3018
    /* Search the route's nexthops for a match, and update it. */
3019
0
    found = ftn_update_znh(add_p, zl->type, new_nhe->nhg.nexthop,
3020
0
               znh);
3021
0
    if (found) {
3022
0
      counter++;
3023
0
    } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
3024
0
      zapi_nexthop2str(znh, buf, sizeof(buf));
3025
0
      zlog_debug(
3026
0
        "%s: Unable to update FEC: prefix %pFX, label %u, znh %s",
3027
0
        __func__, prefix, zl->local_label, buf);
3028
0
    }
3029
0
  }
3030
3031
  /*
3032
   * Process backup LSPs/nexthop entries also. We associate backup
3033
   * LSP info with backup nexthops.
3034
   */
3035
0
  if (!CHECK_FLAG(zl->message, ZAPI_LABELS_HAS_BACKUPS))
3036
0
    goto znh_done;
3037
3038
0
  for (i = 0; i < zl->backup_nexthop_num; i++) {
3039
3040
0
    znh = &zl->backup_nexthops[i];
3041
3042
0
    if (add_p)
3043
0
      ret = lsp_backup_znh_install(lsp, zl->type, znh);
3044
0
    else
3045
0
      ret = mpls_lsp_uninstall(zvrf, zl->type,
3046
0
             zl->local_label,
3047
0
             znh->type, &znh->gate,
3048
0
             znh->ifindex, true);
3049
3050
0
    if (ret < 0) {
3051
0
      if (IS_ZEBRA_DEBUG_RECV ||
3052
0
          IS_ZEBRA_DEBUG_MPLS) {
3053
0
        zapi_nexthop2str(znh, buf, sizeof(buf));
3054
0
        zlog_debug("%s: Unable to %sinstall backup LSP: label %u, znh %s",
3055
0
             __func__, (add_p ? "" : "un"),
3056
0
             zl->local_label, buf);
3057
0
      }
3058
0
      continue;
3059
0
    }
3060
3061
    /* Attempt backup nexthop/FEC update if requested */
3062
0
    if (re == NULL || zebra_nhg_get_backup_nhg(new_nhe) == NULL)
3063
0
      continue;
3064
3065
    /* Search the route's backup nexthops for a match
3066
     * and update it.
3067
     */
3068
0
    found = ftn_update_znh(add_p, zl->type,
3069
0
               new_nhe->backup_info->nhe->nhg.nexthop,
3070
0
               znh);
3071
0
    if (found) {
3072
0
      counter++;
3073
0
    } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
3074
0
      zapi_nexthop2str(znh, buf, sizeof(buf));
3075
0
      zlog_debug(
3076
0
        "%s: Unable to update backup FEC: prefix %pFX, label %u, znh %s",
3077
0
        __func__, prefix, zl->local_label, buf);
3078
0
    }
3079
0
  }
3080
3081
0
znh_done:
3082
3083
  /*
3084
   * If we made changes, update the route, and schedule it
3085
   * for rib processing
3086
   */
3087
0
  if (re != NULL && counter > 0) {
3088
0
    assert(rn != NULL);
3089
3090
0
    SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
3091
0
    SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
3092
3093
0
    mpls_zebra_nhe_update(re, afi, new_nhe);
3094
3095
0
    rib_queue_add(rn);
3096
0
  }
3097
3098
0
  if (new_nhe)
3099
0
    zebra_nhg_free(new_nhe);
3100
0
}
3101
3102
/*
3103
 * Install/update a NHLFE for an LSP in the forwarding table. This may be
3104
 * a new LSP entry or a new NHLFE for an existing in-label or an update of
3105
 * the out-label for an existing NHLFE (update case).
3106
 */
3107
static struct zebra_nhlfe *
3108
lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type,
3109
        uint8_t num_out_labels, const mpls_label_t *out_labels,
3110
        enum nexthop_types_t gtype, const union g_addr *gate,
3111
        ifindex_t ifindex, vrf_id_t vrf_id, bool is_backup)
3112
0
{
3113
0
  struct zebra_nhlfe *nhlfe;
3114
0
  char buf[MPLS_LABEL_STRLEN];
3115
0
  const char *backup_str;
3116
3117
0
  if (is_backup) {
3118
0
    nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
3119
0
           gate, ifindex);
3120
0
    backup_str = "backup ";
3121
0
  } else {
3122
0
    nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
3123
0
           ifindex);
3124
0
    backup_str = "";
3125
0
  }
3126
3127
0
  if (nhlfe) {
3128
0
    struct nexthop *nh = nhlfe->nexthop;
3129
3130
0
    assert(nh);
3131
3132
    /* Clear deleted flag (in case it was set) */
3133
0
    UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
3134
3135
0
    if (!nh->nh_label || num_out_labels == 0)
3136
      /* No change */
3137
0
      return nhlfe;
3138
3139
0
    if (nh->nh_label &&
3140
0
        nh->nh_label->num_labels == num_out_labels &&
3141
0
        !memcmp(nh->nh_label->label, out_labels,
3142
0
          sizeof(mpls_label_t) * num_out_labels))
3143
      /* No change */
3144
0
      return nhlfe;
3145
3146
0
    if (IS_ZEBRA_DEBUG_MPLS) {
3147
0
      char buf2[MPLS_LABEL_STRLEN];
3148
0
      char buf3[MPLS_LABEL_STRLEN];
3149
3150
0
      nhlfe2str(nhlfe, buf, sizeof(buf));
3151
0
      mpls_label2str(num_out_labels, out_labels, buf2,
3152
0
               sizeof(buf2), 0, 0);
3153
0
      mpls_label2str(nh->nh_label->num_labels,
3154
0
               nh->nh_label->label, buf3, sizeof(buf3),
3155
0
               nh->nh_label_type, 0);
3156
3157
0
      zlog_debug("LSP in-label %u type %d %snexthop %s out-label(s) changed to %s (old %s)",
3158
0
           lsp->ile.in_label, type, backup_str, buf,
3159
0
           buf2, buf3);
3160
0
    }
3161
3162
    /* Update out label(s), trigger processing. */
3163
0
    if (nh->nh_label && nh->nh_label->num_labels == num_out_labels)
3164
0
      memcpy(nh->nh_label->label, out_labels,
3165
0
             sizeof(mpls_label_t) * num_out_labels);
3166
0
    else {
3167
0
      nexthop_del_labels(nh);
3168
0
      nexthop_add_labels(nh, type, num_out_labels,
3169
0
             out_labels);
3170
0
    }
3171
0
  } else {
3172
    /* Add LSP entry to this nexthop */
3173
0
    nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, vrf_id,
3174
0
          num_out_labels, out_labels, is_backup);
3175
0
    if (!nhlfe)
3176
0
      return NULL;
3177
3178
0
    if (IS_ZEBRA_DEBUG_MPLS) {
3179
0
      char buf2[MPLS_LABEL_STRLEN];
3180
3181
0
      nhlfe2str(nhlfe, buf, sizeof(buf));
3182
0
      if (num_out_labels)
3183
0
        mpls_label2str(num_out_labels, out_labels, buf2,
3184
0
                 sizeof(buf2), 0, 0);
3185
0
      else
3186
0
        snprintf(buf2, sizeof(buf2), "-");
3187
3188
0
      zlog_debug("Add LSP in-label %u type %d %snexthop %s out-label(s) %s",
3189
0
           lsp->ile.in_label, type, backup_str, buf,
3190
0
           buf2);
3191
0
    }
3192
3193
0
    lsp->addr_family = NHLFE_FAMILY(nhlfe);
3194
0
  }
3195
3196
  /* Mark NHLFE, queue LSP for processing. */
3197
0
  SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
3198
3199
0
  return nhlfe;
3200
0
}
3201
3202
/*
3203
 * Install an LSP and forwarding entry; used primarily
3204
 * from vrf zapi message processing.
3205
 * TODO: handle vrf_id parameter when mpls API extends to interface or SRTE
3206
 * changes
3207
 */
3208
int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
3209
         mpls_label_t in_label, uint8_t num_out_labels,
3210
         const mpls_label_t *out_labels, enum nexthop_types_t gtype,
3211
         const union g_addr *gate, ifindex_t ifindex)
3212
0
{
3213
0
  struct hash *lsp_table;
3214
0
  struct zebra_ile tmp_ile;
3215
0
  struct zebra_lsp *lsp;
3216
0
  struct zebra_nhlfe *nhlfe;
3217
3218
  /* Lookup table. */
3219
0
  lsp_table = zvrf->lsp_table;
3220
0
  if (!lsp_table)
3221
0
    return -1;
3222
3223
  /* Find or create LSP object */
3224
0
  tmp_ile.in_label = in_label;
3225
0
  lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
3226
3227
0
  nhlfe = lsp_add_nhlfe(lsp, type, num_out_labels, out_labels, gtype,
3228
0
            gate, ifindex, VRF_DEFAULT, false /*backup*/);
3229
0
  if (nhlfe == NULL)
3230
0
    return -1;
3231
3232
  /* Queue LSP for processing. */
3233
0
  if (lsp_processq_add(lsp))
3234
0
    return -1;
3235
3236
0
  return 0;
3237
0
}
3238
3239
/*
3240
 * Install or replace NHLFE, using info from zapi nexthop
3241
 */
3242
static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
3243
         const struct zapi_nexthop *znh)
3244
0
{
3245
0
  struct zebra_nhlfe *nhlfe;
3246
3247
0
  nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels, znh->type,
3248
0
            &znh->gate, znh->ifindex, znh->vrf_id,
3249
0
            false /*backup*/);
3250
0
  if (nhlfe == NULL)
3251
0
    return -1;
3252
3253
  /* Update backup info if present */
3254
0
  if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
3255
0
    if (znh->backup_num > NEXTHOP_MAX_BACKUPS) {
3256
0
      nhlfe_del(nhlfe);
3257
0
      return -1;
3258
0
    }
3259
3260
0
    nhlfe->nexthop->backup_num = znh->backup_num;
3261
0
    memcpy(nhlfe->nexthop->backup_idx, znh->backup_idx,
3262
0
           znh->backup_num);
3263
0
    SET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
3264
0
  } else {
3265
    /* Ensure there's no stale backup info */
3266
0
    UNSET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
3267
0
    nhlfe->nexthop->backup_num = 0;
3268
0
  }
3269
3270
  /* Queue LSP for processing. */
3271
0
  if (lsp_processq_add(lsp))
3272
0
    return -1;
3273
3274
0
  return 0;
3275
0
}
3276
3277
/*
3278
 * Install/update backup NHLFE for an LSP, using info from a zapi message.
3279
 */
3280
static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
3281
          const struct zapi_nexthop *znh)
3282
0
{
3283
0
  struct zebra_nhlfe *nhlfe;
3284
3285
0
  nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels, znh->type,
3286
0
            &znh->gate, znh->ifindex, znh->vrf_id,
3287
0
            true /*backup*/);
3288
0
  if (nhlfe == NULL) {
3289
0
    if (IS_ZEBRA_DEBUG_MPLS)
3290
0
      zlog_debug("%s: unable to add backup nhlfe, label: %u",
3291
0
           __func__, lsp->ile.in_label);
3292
0
    return -1;
3293
0
  }
3294
3295
  /* Queue LSP for processing. */
3296
0
  if (lsp_processq_add(lsp))
3297
0
    return -1;
3298
3299
0
  return 0;
3300
0
}
3301
3302
struct zebra_lsp *mpls_lsp_find(struct zebra_vrf *zvrf, mpls_label_t in_label)
3303
0
{
3304
0
  struct hash *lsp_table;
3305
0
  struct zebra_ile tmp_ile;
3306
3307
  /* Lookup table. */
3308
0
  lsp_table = zvrf->lsp_table;
3309
0
  if (!lsp_table)
3310
0
    return NULL;
3311
3312
  /* If entry is not present, exit. */
3313
0
  tmp_ile.in_label = in_label;
3314
0
  return hash_lookup(lsp_table, &tmp_ile);
3315
0
}
3316
3317
/*
3318
 * Uninstall a particular NHLFE in the forwarding table. If this is
3319
 * the only NHLFE, the entire LSP forwarding entry has to be deleted.
3320
 */
3321
int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
3322
           mpls_label_t in_label, enum nexthop_types_t gtype,
3323
           const union g_addr *gate, ifindex_t ifindex,
3324
           bool backup_p)
3325
0
{
3326
0
  struct hash *lsp_table;
3327
0
  struct zebra_ile tmp_ile;
3328
0
  struct zebra_lsp *lsp;
3329
0
  struct zebra_nhlfe *nhlfe;
3330
0
  char buf[NEXTHOP_STRLEN];
3331
0
  bool schedule_lsp = false;
3332
3333
  /* Lookup table. */
3334
0
  lsp_table = zvrf->lsp_table;
3335
0
  if (!lsp_table)
3336
0
    return -1;
3337
3338
  /* If entry is not present, exit. */
3339
0
  tmp_ile.in_label = in_label;
3340
0
  lsp = hash_lookup(lsp_table, &tmp_ile);
3341
0
  if (!lsp)
3342
0
    return 0;
3343
3344
0
  if (backup_p)
3345
0
    nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
3346
0
           gate, ifindex);
3347
0
  else
3348
0
    nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
3349
0
           ifindex);
3350
0
  if (!nhlfe)
3351
0
    return 0;
3352
3353
0
  if (IS_ZEBRA_DEBUG_MPLS) {
3354
0
    nhlfe2str(nhlfe, buf, sizeof(buf));
3355
0
    zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
3356
0
         in_label, type, buf, nhlfe->flags);
3357
0
  }
3358
3359
0
  if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ||
3360
0
      CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
3361
0
    schedule_lsp = true;
3362
3363
  /* Mark NHLFE for delete or directly delete, as appropriate. */
3364
0
  if (schedule_lsp) {
3365
0
    SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
3366
0
    UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
3367
3368
0
    if (IS_ZEBRA_DEBUG_MPLS)
3369
0
      zlog_debug("Schedule LSP in-label %u flags 0x%x",
3370
0
           lsp->ile.in_label, lsp->flags);
3371
0
    if (lsp_processq_add(lsp))
3372
0
      return -1;
3373
0
  } else {
3374
0
    nhlfe_del(nhlfe);
3375
3376
    /* Free LSP entry if no other NHLFEs and not scheduled. */
3377
0
    lsp_check_free(lsp_table, &lsp);
3378
0
  }
3379
0
  return 0;
3380
0
}
3381
3382
int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
3383
             mpls_label_t in_label)
3384
0
{
3385
0
  struct hash *lsp_table;
3386
0
  struct zebra_ile tmp_ile;
3387
0
  struct zebra_lsp *lsp;
3388
3389
  /* Lookup table. */
3390
0
  lsp_table = zvrf->lsp_table;
3391
0
  if (!lsp_table)
3392
0
    return -1;
3393
3394
  /* If entry is not present, exit. */
3395
0
  tmp_ile.in_label = in_label;
3396
0
  lsp = hash_lookup(lsp_table, &tmp_ile);
3397
0
  if (!lsp)
3398
0
    return 0;
3399
3400
0
  return mpls_lsp_uninstall_all(lsp_table, lsp, type);
3401
0
}
3402
3403
/*
3404
 * Uninstall all NHLFEs for a particular LSP forwarding entry.
3405
 * If no other NHLFEs exist, the entry would be deleted.
3406
 */
3407
static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt)
3408
0
{
3409
0
  struct lsp_uninstall_args *args = ctxt;
3410
0
  struct zebra_lsp *lsp;
3411
0
  struct hash *lsp_table;
3412
3413
0
  lsp = (struct zebra_lsp *)bucket->data;
3414
0
  if (nhlfe_list_first(&lsp->nhlfe_list) == NULL)
3415
0
    return;
3416
3417
0
  lsp_table = args->lsp_table;
3418
0
  if (!lsp_table)
3419
0
    return;
3420
3421
0
  mpls_lsp_uninstall_all(lsp_table, lsp, args->type);
3422
0
}
3423
3424
/*
3425
 * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and
3426
 * LSP type.
3427
 */
3428
static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
3429
           int afi, enum lsp_types_t lsp_type)
3430
0
{
3431
0
  struct route_table *table;
3432
0
  struct route_node *rn;
3433
0
  struct route_entry *re;
3434
0
  struct nexthop *nexthop;
3435
0
  struct nexthop_group *nhg;
3436
0
  bool update;
3437
3438
  /* Process routes of interested address-families. */
3439
0
  table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
3440
0
  if (!table)
3441
0
    return;
3442
3443
0
  for (rn = route_top(table); rn; rn = route_next(rn)) {
3444
0
    update = false;
3445
3446
0
    RNODE_FOREACH_RE (rn, re) {
3447
0
      struct nhg_hash_entry *new_nhe;
3448
3449
0
      new_nhe = zebra_nhe_copy(re->nhe, 0);
3450
3451
0
      nhg = &new_nhe->nhg;
3452
0
      for (nexthop = nhg->nexthop; nexthop;
3453
0
           nexthop = nexthop->next) {
3454
0
        if (nexthop->nh_label_type != lsp_type)
3455
0
          continue;
3456
3457
0
        nexthop_del_labels(nexthop);
3458
0
        SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
3459
0
        SET_FLAG(re->status,
3460
0
           ROUTE_ENTRY_LABELS_CHANGED);
3461
0
        update = true;
3462
0
      }
3463
3464
      /* Check for backup info and update that also */
3465
0
      nhg = zebra_nhg_get_backup_nhg(new_nhe);
3466
0
      if (nhg != NULL) {
3467
0
        for (nexthop = nhg->nexthop; nexthop;
3468
0
             nexthop = nexthop->next) {
3469
0
          if (nexthop->nh_label_type != lsp_type)
3470
0
            continue;
3471
3472
0
          nexthop_del_labels(nexthop);
3473
0
          SET_FLAG(re->status,
3474
0
             ROUTE_ENTRY_CHANGED);
3475
0
          SET_FLAG(re->status,
3476
0
             ROUTE_ENTRY_LABELS_CHANGED);
3477
0
          update = true;
3478
0
        }
3479
0
      }
3480
3481
0
      if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
3482
0
        mpls_zebra_nhe_update(re, afi, new_nhe);
3483
3484
0
      zebra_nhg_free(new_nhe);
3485
0
    }
3486
3487
0
    if (update)
3488
0
      rib_queue_add(rn);
3489
0
  }
3490
0
}
3491
3492
#if defined(HAVE_CUMULUS)
3493
/*
3494
 * Check that the label values used in LSP creation are consistent. The
3495
 * main criteria is that if there is ECMP, the label operation must still
3496
 * be consistent - i.e., all paths either do a swap or do PHP. This is due
3497
 * to current HW restrictions.
3498
 */
3499
int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
3500
            mpls_label_t in_label,
3501
            mpls_label_t out_label,
3502
            enum nexthop_types_t gtype,
3503
            union g_addr *gate, ifindex_t ifindex)
3504
{
3505
  struct hash *slsp_table;
3506
  struct zebra_ile tmp_ile;
3507
  struct zebra_lsp *lsp;
3508
  struct zebra_nhlfe *nhlfe;
3509
  const struct nexthop *nh;
3510
3511
  /* Lookup table. */
3512
  slsp_table = zvrf->slsp_table;
3513
  if (!slsp_table)
3514
    return 0;
3515
3516
  /* If entry is not present, exit. */
3517
  tmp_ile.in_label = in_label;
3518
  lsp = hash_lookup(slsp_table, &tmp_ile);
3519
  if (!lsp)
3520
    return 1;
3521
3522
  nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
3523
         gtype, gate, ifindex);
3524
  if (nhlfe) {
3525
    nh = nhlfe->nexthop;
3526
3527
    if (nh == NULL || nh->nh_label == NULL)
3528
      return 0;
3529
3530
    if (nh->nh_label->label[0] == out_label)
3531
      return 1;
3532
3533
    /* If not only NHLFE, cannot allow label change. */
3534
    if (nhlfe != nhlfe_list_first(&lsp->nhlfe_list) ||
3535
        nhlfe_list_next(&lsp->nhlfe_list, nhlfe) != NULL)
3536
      return 0;
3537
  } else {
3538
    /* If other NHLFEs exist, label operation must match. */
3539
    nhlfe = nhlfe_list_first(&lsp->nhlfe_list);
3540
    if (nhlfe != NULL) {
3541
      int cur_op, new_op;
3542
3543
      nh = nhlfe->nexthop;
3544
3545
      if (nh == NULL || nh->nh_label == NULL)
3546
        return 0;
3547
3548
      cur_op = (nh->nh_label->label[0] ==
3549
          MPLS_LABEL_IMPLICIT_NULL);
3550
      new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
3551
      if (cur_op != new_op)
3552
        return 0;
3553
    }
3554
  }
3555
3556
  /* Label values are good. */
3557
  return 1;
3558
}
3559
#endif /* HAVE_CUMULUS */
3560
3561
/*
3562
 * Add static LSP entry. This may be the first entry for this incoming label
3563
 * or an additional nexthop; an existing entry may also have outgoing label
3564
 * changed.
3565
 * Note: The label operation (swap or PHP) is common for the LSP entry (all
3566
 * NHLFEs).
3567
 */
3568
int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
3569
            mpls_label_t out_label,
3570
            enum nexthop_types_t gtype, union g_addr *gate,
3571
            ifindex_t ifindex)
3572
0
{
3573
0
  struct hash *slsp_table;
3574
0
  struct zebra_ile tmp_ile;
3575
0
  struct zebra_lsp *lsp;
3576
0
  struct zebra_nhlfe *nhlfe;
3577
0
  char buf[BUFSIZ];
3578
3579
  /* Lookup table. */
3580
0
  slsp_table = zvrf->slsp_table;
3581
0
  if (!slsp_table)
3582
0
    return -1;
3583
3584
  /* Find or create LSP. */
3585
0
  tmp_ile.in_label = in_label;
3586
0
  lsp = hash_get(slsp_table, &tmp_ile, lsp_alloc);
3587
3588
0
  nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC, gtype, gate,
3589
0
         ifindex);
3590
0
  if (nhlfe) {
3591
0
    struct nexthop *nh = nhlfe->nexthop;
3592
3593
0
    assert(nh);
3594
0
    assert(nh->nh_label);
3595
3596
    /* Compare existing nexthop */
3597
0
    if (nh->nh_label->num_labels == 1 &&
3598
0
        nh->nh_label->label[0] == out_label)
3599
      /* No change */
3600
0
      return 0;
3601
3602
0
    if (IS_ZEBRA_DEBUG_MPLS) {
3603
0
      nhlfe2str(nhlfe, buf, sizeof(buf));
3604
0
      zlog_debug(
3605
0
        "Upd static LSP in-label %u nexthop %s out-label %u (old %u)",
3606
0
        in_label, buf, out_label,
3607
0
        nh->nh_label->label[0]);
3608
0
    }
3609
0
    if (nh->nh_label->num_labels == 1)
3610
0
      nh->nh_label->label[0] = out_label;
3611
0
    else {
3612
0
      nexthop_del_labels(nh);
3613
0
      nexthop_add_labels(nh, ZEBRA_LSP_STATIC, 1, &out_label);
3614
0
    }
3615
3616
0
  } else {
3617
    /* Add static LSP entry to this nexthop */
3618
0
    nhlfe = nhlfe_add(lsp, ZEBRA_LSP_STATIC, gtype, gate, ifindex,
3619
0
          VRF_DEFAULT, 1, &out_label, false /*backup*/);
3620
0
    if (!nhlfe)
3621
0
      return -1;
3622
3623
0
    if (IS_ZEBRA_DEBUG_MPLS) {
3624
0
      nhlfe2str(nhlfe, buf, sizeof(buf));
3625
0
      zlog_debug(
3626
0
        "Add static LSP in-label %u nexthop %s out-label %u",
3627
0
        in_label, buf, out_label);
3628
0
    }
3629
0
  }
3630
3631
  /* (Re)Install LSP in the main table. */
3632
0
  if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, 1, &out_label,
3633
0
           gtype, gate, ifindex))
3634
0
    return -1;
3635
3636
0
  return 0;
3637
0
}
3638
3639
/*
3640
 * Delete static LSP entry. This may be the delete of one particular
3641
 * NHLFE for this incoming label or the delete of the entire entry (i.e.,
3642
 * all NHLFEs).
3643
 * NOTE: Delete of the only NHLFE will also end up deleting the entire
3644
 * LSP configuration.
3645
 */
3646
int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
3647
            enum nexthop_types_t gtype, union g_addr *gate,
3648
            ifindex_t ifindex)
3649
0
{
3650
0
  struct hash *slsp_table;
3651
0
  struct zebra_ile tmp_ile;
3652
0
  struct zebra_lsp *lsp;
3653
0
  struct zebra_nhlfe *nhlfe;
3654
3655
  /* Lookup table. */
3656
0
  slsp_table = zvrf->slsp_table;
3657
0
  if (!slsp_table)
3658
0
    return -1;
3659
3660
  /* If entry is not present, exit. */
3661
0
  tmp_ile.in_label = in_label;
3662
0
  lsp = hash_lookup(slsp_table, &tmp_ile);
3663
0
  if (!lsp)
3664
0
    return 0;
3665
3666
  /* Is it delete of entire LSP or a specific NHLFE? */
3667
0
  if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
3668
0
    if (IS_ZEBRA_DEBUG_MPLS)
3669
0
      zlog_debug("Del static LSP in-label %u", in_label);
3670
3671
    /* Uninstall entire LSP from the main table. */
3672
0
    mpls_static_lsp_uninstall_all(zvrf, in_label);
3673
3674
    /* Delete all static NHLFEs */
3675
0
    frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3676
0
      nhlfe_del(nhlfe);
3677
0
    }
3678
0
  } else {
3679
    /* Find specific NHLFE, exit if not found. */
3680
0
    nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
3681
0
           gtype, gate, ifindex);
3682
0
    if (!nhlfe)
3683
0
      return 0;
3684
3685
0
    if (IS_ZEBRA_DEBUG_MPLS) {
3686
0
      char buf[BUFSIZ];
3687
0
      nhlfe2str(nhlfe, buf, sizeof(buf));
3688
0
      zlog_debug("Del static LSP in-label %u nexthop %s",
3689
0
           in_label, buf);
3690
0
    }
3691
3692
    /* Uninstall LSP from the main table. */
3693
0
    mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
3694
0
           gate, ifindex, false);
3695
3696
    /* Delete static LSP NHLFE */
3697
0
    nhlfe_del(nhlfe);
3698
0
  }
3699
3700
  /* Remove entire static LSP entry if no NHLFE - valid in either case
3701
   * above.
3702
   */
3703
0
  if (nhlfe_list_first(&lsp->nhlfe_list) == NULL) {
3704
0
    lsp = hash_release(slsp_table, &tmp_ile);
3705
0
    lsp_free_nhlfe(lsp);
3706
0
    XFREE(MTYPE_LSP, lsp);
3707
0
  }
3708
3709
0
  return 0;
3710
0
}
3711
3712
/*
3713
 * Schedule all MPLS label forwarding entries for processing.
3714
 * Called upon changes that may affect one or more of them such as
3715
 * interface or nexthop state changes.
3716
 */
3717
void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
3718
0
{
3719
0
  if (!zvrf)
3720
0
    return;
3721
0
  hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
3722
0
}
3723
3724
/*
3725
 * Display MPLS label forwarding table for a specific LSP
3726
 * (VTY command handler).
3727
 */
3728
void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
3729
        mpls_label_t label, bool use_json)
3730
0
{
3731
0
  struct hash *lsp_table;
3732
0
  struct zebra_lsp *lsp;
3733
0
  struct zebra_ile tmp_ile;
3734
0
  json_object *json = NULL;
3735
3736
  /* Lookup table. */
3737
0
  lsp_table = zvrf->lsp_table;
3738
0
  if (!lsp_table) {
3739
0
    if (use_json)
3740
0
      vty_out(vty, "{}\n");
3741
0
    return;
3742
0
  }
3743
3744
  /* If entry is not present, exit. */
3745
0
  tmp_ile.in_label = label;
3746
0
  lsp = hash_lookup(lsp_table, &tmp_ile);
3747
0
  if (!lsp) {
3748
0
    if (use_json)
3749
0
      vty_out(vty, "{}\n");
3750
0
    return;
3751
0
  }
3752
3753
0
  if (use_json) {
3754
0
    json = lsp_json(lsp);
3755
0
    vty_json(vty, json);
3756
0
  } else
3757
0
    lsp_print(vty, lsp);
3758
0
}
3759
3760
/*
3761
 * Display MPLS label forwarding table (VTY command handler).
3762
 */
3763
void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
3764
        bool use_json)
3765
0
{
3766
0
  char buf[BUFSIZ];
3767
0
  json_object *json = NULL;
3768
0
  struct zebra_lsp *lsp = NULL;
3769
0
  struct zebra_nhlfe *nhlfe = NULL;
3770
0
  struct listnode *node = NULL;
3771
0
  struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
3772
3773
0
  if (use_json) {
3774
0
    json = json_object_new_object();
3775
3776
0
    for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
3777
0
      json_object_object_add(json,
3778
0
                 label2str(lsp->ile.in_label, 0,
3779
0
               buf, sizeof(buf)),
3780
0
                 lsp_json(lsp));
3781
3782
0
    vty_json(vty, json);
3783
0
  } else {
3784
0
    struct ttable *tt;
3785
3786
    /* Prepare table. */
3787
0
    tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3788
0
    ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label");
3789
0
    tt->style.cell.rpad = 2;
3790
0
    tt->style.corner = '+';
3791
0
    ttable_restyle(tt);
3792
0
    ttable_rowseps(tt, 0, BOTTOM, true, '-');
3793
3794
0
    for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
3795
0
      frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3796
0
        struct nexthop *nexthop;
3797
0
        const char *out_label_str;
3798
0
        char nh_buf[NEXTHOP_STRLEN];
3799
3800
0
        nexthop = nhlfe->nexthop;
3801
3802
0
        switch (nexthop->type) {
3803
0
        case NEXTHOP_TYPE_IFINDEX: {
3804
0
          struct zebra_ns *zns;
3805
0
          struct interface *ifp;
3806
3807
0
          zns = zebra_ns_lookup(NS_DEFAULT);
3808
0
          ifp = if_lookup_by_index_per_ns(
3809
0
            zns, nexthop->ifindex);
3810
0
          snprintf(nh_buf, sizeof(nh_buf), "%s",
3811
0
             ifp ? ifp->name : "Null");
3812
0
          break;
3813
0
        }
3814
0
        case NEXTHOP_TYPE_IPV4:
3815
0
        case NEXTHOP_TYPE_IPV4_IFINDEX:
3816
0
          inet_ntop(AF_INET, &nexthop->gate.ipv4,
3817
0
              nh_buf, sizeof(nh_buf));
3818
0
          break;
3819
0
        case NEXTHOP_TYPE_IPV6:
3820
0
        case NEXTHOP_TYPE_IPV6_IFINDEX:
3821
0
          inet_ntop(AF_INET6, &nexthop->gate.ipv6,
3822
0
              nh_buf, sizeof(nh_buf));
3823
0
          break;
3824
0
        case NEXTHOP_TYPE_BLACKHOLE:
3825
0
          break;
3826
0
        }
3827
3828
0
        if (nexthop->type != NEXTHOP_TYPE_IFINDEX &&
3829
0
            nexthop->nh_label)
3830
0
          out_label_str = mpls_label2str(
3831
0
            nexthop->nh_label->num_labels,
3832
0
            &nexthop->nh_label->label[0],
3833
0
            buf, sizeof(buf),
3834
0
            nexthop->nh_label_type, 1);
3835
0
        else
3836
0
          out_label_str = "-";
3837
3838
0
        ttable_add_row(tt, "%u|%s|%s|%s",
3839
0
                 lsp->ile.in_label,
3840
0
                 nhlfe_type2str(nhlfe->type),
3841
0
                 nh_buf, out_label_str);
3842
0
      }
3843
0
    }
3844
3845
    /* Dump the generated table. */
3846
0
    if (tt->nrows > 1) {
3847
0
      char *table = ttable_dump(tt, "\n");
3848
0
      vty_out(vty, "%s\n", table);
3849
0
      XFREE(MTYPE_TMP, table);
3850
0
    }
3851
0
    ttable_del(tt);
3852
0
  }
3853
3854
0
  list_delete(&lsp_list);
3855
0
}
3856
3857
/*
3858
 * Create printable string for static LSP configuration.
3859
 */
3860
static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
3861
            int size)
3862
0
{
3863
0
  const struct nexthop *nh;
3864
3865
0
  nh = nhlfe->nexthop;
3866
3867
0
  buf[0] = '\0';
3868
0
  switch (nh->type) {
3869
0
  case NEXTHOP_TYPE_IPV4:
3870
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
3871
0
    inet_ntop(AF_INET, &nh->gate.ipv4, buf, size);
3872
0
    if (nh->ifindex)
3873
0
      strlcat(buf, ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3874
0
        size);
3875
0
    break;
3876
0
  case NEXTHOP_TYPE_IPV6:
3877
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
3878
0
    inet_ntop(AF_INET6, &nh->gate.ipv6, buf, size);
3879
0
    if (nh->ifindex)
3880
0
      strlcat(buf,
3881
0
        ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3882
0
        size);
3883
0
    break;
3884
0
  case NEXTHOP_TYPE_IFINDEX:
3885
0
    if (nh->ifindex)
3886
0
      strlcat(buf,
3887
0
        ifindex2ifname(nh->ifindex, VRF_DEFAULT),
3888
0
        size);
3889
0
    break;
3890
0
  case NEXTHOP_TYPE_BLACKHOLE:
3891
0
    break;
3892
0
  }
3893
3894
0
  return buf;
3895
0
}
3896
3897
/*
3898
 * Display MPLS LSP configuration of all static LSPs (VTY command handler).
3899
 */
3900
int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
3901
0
{
3902
0
  struct zebra_lsp *lsp;
3903
0
  struct zebra_nhlfe *nhlfe;
3904
0
  struct nexthop *nh;
3905
0
  struct listnode *node;
3906
0
  struct list *slsp_list =
3907
0
    hash_get_sorted_list(zvrf->slsp_table, lsp_cmp);
3908
3909
0
  for (ALL_LIST_ELEMENTS_RO(slsp_list, node, lsp)) {
3910
0
    frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3911
0
      char buf[BUFSIZ];
3912
0
      char lstr[30];
3913
3914
0
      nh = nhlfe->nexthop;
3915
0
      if (nh == NULL || nh->nh_label == NULL)
3916
0
        continue;
3917
3918
0
      nhlfe_config_str(nhlfe, buf, sizeof(buf));
3919
3920
0
      switch (nh->nh_label->label[0]) {
3921
0
      case MPLS_LABEL_IPV4_EXPLICIT_NULL:
3922
0
      case MPLS_LABEL_IPV6_EXPLICIT_NULL:
3923
0
        strlcpy(lstr, "explicit-null", sizeof(lstr));
3924
0
        break;
3925
0
      case MPLS_LABEL_IMPLICIT_NULL:
3926
0
        strlcpy(lstr, "implicit-null", sizeof(lstr));
3927
0
        break;
3928
0
      default:
3929
0
        snprintf(lstr, sizeof(lstr), "%u",
3930
0
           nh->nh_label->label[0]);
3931
0
        break;
3932
0
      }
3933
3934
0
      vty_out(vty, "mpls lsp %u %s %s\n", lsp->ile.in_label,
3935
0
        buf, lstr);
3936
0
    }
3937
0
  }
3938
3939
0
  list_delete(&slsp_list);
3940
0
  return (zvrf->slsp_table->count ? 1 : 0);
3941
0
}
3942
3943
/*
3944
 * Add/update global label block.
3945
 */
3946
int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
3947
             uint32_t end_label)
3948
0
{
3949
0
  zvrf->mpls_srgb.start_label = start_label;
3950
0
  zvrf->mpls_srgb.end_label = end_label;
3951
3952
  /* Evaluate registered FECs to see if any get a label or not. */
3953
0
  fec_evaluate(zvrf);
3954
0
  return 0;
3955
0
}
3956
3957
/*
3958
 * Delete global label block.
3959
 */
3960
int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
3961
0
{
3962
0
  zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
3963
0
  zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
3964
3965
  /* Process registered FECs to clear their local label, if needed. */
3966
0
  fec_evaluate(zvrf);
3967
0
  return 0;
3968
0
}
3969
3970
/*
3971
 * Display MPLS global label block configuration (VTY command handler).
3972
 */
3973
int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
3974
0
{
3975
0
  if (zvrf->mpls_srgb.start_label == 0)
3976
0
    return 0;
3977
3978
0
  if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
3979
0
      || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
3980
0
    vty_out(vty, "mpls label global-block %u %u\n",
3981
0
      zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
3982
0
  }
3983
3984
0
  return 1;
3985
0
}
3986
3987
/*
3988
 * Called when VRF becomes inactive, cleans up information but keeps
3989
 * the table itself.
3990
 */
3991
void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
3992
0
{
3993
0
  struct zebra_vrf *def_zvrf;
3994
0
  afi_t afi;
3995
3996
0
  if (zvrf_id(zvrf) == VRF_DEFAULT)
3997
0
    hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
3998
0
  else {
3999
    /*
4000
     * For other vrfs, we try to remove associated LSPs; we locate
4001
     * the LSPs in the default vrf.
4002
     */
4003
0
    def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
4004
4005
    /* At shutdown, the default may be gone already */
4006
0
    if (def_zvrf == NULL)
4007
0
      return;
4008
4009
0
    for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4010
0
      if (zvrf->label[afi] != MPLS_LABEL_NONE)
4011
0
        lsp_uninstall(def_zvrf, zvrf->label[afi]);
4012
0
    }
4013
0
  }
4014
0
}
4015
4016
/*
4017
 * When a vrf label is assigned and the client goes away
4018
 * we should cleanup the vrf labels associated with
4019
 * that zclient.
4020
 */
4021
void zebra_mpls_client_cleanup_vrf_label(uint8_t proto)
4022
278
{
4023
278
  struct vrf *vrf;
4024
278
  struct zebra_vrf *def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
4025
4026
278
  if (def_zvrf == NULL)
4027
0
    return;
4028
4029
278
  RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
4030
278
    struct zebra_vrf *zvrf = vrf->info;
4031
278
    afi_t afi;
4032
4033
278
    if (!zvrf)
4034
0
      continue;
4035
4036
1.11k
    for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4037
834
      if (zvrf->label_proto[afi] == proto
4038
834
          && zvrf->label[afi] != MPLS_LABEL_NONE)
4039
3
        lsp_uninstall(def_zvrf, zvrf->label[afi]);
4040
4041
      /*
4042
       * Cleanup data structures by fiat
4043
       */
4044
834
      zvrf->label_proto[afi] = 0;
4045
834
      zvrf->label[afi] = MPLS_LABEL_NONE;
4046
834
    }
4047
278
  }
4048
278
}
4049
4050
static void lsp_table_free(void *p)
4051
0
{
4052
0
  struct zebra_lsp *lsp = p;
4053
4054
0
  lsp_free_nhlfe(lsp);
4055
4056
0
  XFREE(MTYPE_LSP, lsp);
4057
0
}
4058
4059
/*
4060
 * Called upon process exiting, need to delete LSP forwarding
4061
 * entries from the kernel.
4062
 * NOTE: Currently supported only for default VRF.
4063
 */
4064
void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
4065
0
{
4066
0
  hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
4067
0
  hash_clean_and_free(&zvrf->lsp_table, lsp_table_free);
4068
0
  hash_clean_and_free(&zvrf->slsp_table, lsp_table_free);
4069
0
  route_table_finish(zvrf->fec_table[AFI_IP]);
4070
0
  route_table_finish(zvrf->fec_table[AFI_IP6]);
4071
0
}
4072
4073
/*
4074
 * Allocate MPLS tables for this VRF and do other initialization.
4075
 * NOTE: Currently supported only for default VRF.
4076
 */
4077
void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
4078
1
{
4079
1
  char buffer[80];
4080
4081
1
  if (!zvrf)
4082
0
    return;
4083
4084
1
  snprintf(buffer, sizeof(buffer), "ZEBRA SLSP table: %s",
4085
1
     zvrf->vrf->name);
4086
1
  zvrf->slsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
4087
4088
1
  snprintf(buffer, sizeof(buffer), "ZEBRA LSP table: %s",
4089
1
     zvrf->vrf->name);
4090
1
  zvrf->lsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
4091
1
  zvrf->fec_table[AFI_IP] = route_table_init();
4092
1
  zvrf->fec_table[AFI_IP6] = route_table_init();
4093
1
  zvrf->mpls_flags = 0;
4094
1
  zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
4095
1
  zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
4096
1
}
4097
4098
void zebra_mpls_turned_on(void)
4099
0
{
4100
0
  if (!mpls_enabled) {
4101
0
    mpls_processq_init();
4102
0
    mpls_enabled = true;
4103
0
  }
4104
4105
0
  hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
4106
0
  hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
4107
0
}
4108
4109
/*
4110
 * Global MPLS initialization.
4111
 */
4112
void zebra_mpls_init(void)
4113
1
{
4114
1
  mpls_enabled = false;
4115
1
  mpls_pw_reach_strict = false;
4116
4117
1
  if (mpls_kernel_init() < 0) {
4118
1
    flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
4119
1
        "Disabling MPLS support (no kernel support)");
4120
1
    return;
4121
1
  }
4122
4123
0
  zebra_mpls_turned_on();
4124
0
}