Coverage Report

Created: 2026-01-25 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/zebra/zebra_nhg.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Zebra Nexthop Group Code.
3
 * Copyright (C) 2019 Cumulus Networks, Inc.
4
 *                    Donald Sharp
5
 *                    Stephen Worley
6
 */
7
#include <zebra.h>
8
9
#include "lib/nexthop.h"
10
#include "lib/nexthop_group_private.h"
11
#include "lib/routemap.h"
12
#include "lib/mpls.h"
13
#include "lib/jhash.h"
14
#include "lib/debug.h"
15
#include "lib/lib_errors.h"
16
17
#include "zebra/connected.h"
18
#include "zebra/debug.h"
19
#include "zebra/zebra_router.h"
20
#include "zebra/zebra_nhg_private.h"
21
#include "zebra/zebra_rnh.h"
22
#include "zebra/zebra_routemap.h"
23
#include "zebra/zebra_srte.h"
24
#include "zebra/zserv.h"
25
#include "zebra/rt.h"
26
#include "zebra_errors.h"
27
#include "zebra_dplane.h"
28
#include "zebra/interface.h"
29
#include "zebra/zapi_msg.h"
30
#include "zebra/rib.h"
31
#include "zebra/zebra_vxlan.h"
32
33
2
DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
34
2
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
35
2
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
36
2
37
2
/* Map backup nexthop indices between two nhes */
38
2
struct backup_nh_map_s {
39
2
  int map_count;
40
2
41
2
  struct {
42
2
    uint8_t orig_idx;
43
2
    uint8_t new_idx;
44
2
  } map[MULTIPATH_NUM];
45
2
};
46
2
47
2
/* id counter to keep in sync with kernel */
48
2
uint32_t id_counter;
49
2
50
2
/* Controlled through ui */
51
2
static bool g_nexthops_enabled = true;
52
2
static bool proto_nexthops_only;
53
2
static bool use_recursive_backups = true;
54
2
55
2
static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
56
2
             int type, bool from_dplane);
57
2
static void depends_add(struct nhg_connected_tree_head *head,
58
2
      struct nhg_hash_entry *depend);
59
2
static struct nhg_hash_entry *
60
2
depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
61
2
     afi_t afi, int type, bool from_dplane);
62
2
static struct nhg_hash_entry *
63
2
depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
64
2
static void depends_decrement_free(struct nhg_connected_tree_head *head);
65
2
66
2
static struct nhg_backup_info *
67
2
nhg_backup_copy(const struct nhg_backup_info *orig);
68
2
69
2
/* Helper function for getting the next allocatable ID */
70
2
static uint32_t nhg_get_next_id(void)
71
2
{
72
0
  while (1) {
73
0
    id_counter++;
74
75
0
    if (IS_ZEBRA_DEBUG_NHG_DETAIL)
76
0
      zlog_debug("%s: ID %u checking", __func__, id_counter);
77
78
0
    if (id_counter == ZEBRA_NHG_PROTO_LOWER) {
79
0
      if (IS_ZEBRA_DEBUG_NHG_DETAIL)
80
0
        zlog_debug("%s: ID counter wrapped", __func__);
81
82
0
      id_counter = 0;
83
0
      continue;
84
0
    }
85
86
0
    if (zebra_nhg_lookup_id(id_counter)) {
87
0
      if (IS_ZEBRA_DEBUG_NHG_DETAIL)
88
0
        zlog_debug("%s: ID already exists", __func__);
89
90
0
      continue;
91
0
    }
92
93
0
    break;
94
0
  }
95
96
0
  return id_counter;
97
0
}
98
99
static void nhg_connected_free(struct nhg_connected *dep)
100
0
{
101
0
  XFREE(MTYPE_NHG_CONNECTED, dep);
102
0
}
103
104
static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
105
0
{
106
0
  struct nhg_connected *new = NULL;
107
108
0
  new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
109
0
  new->nhe = nhe;
110
111
0
  return new;
112
0
}
113
114
void nhg_connected_tree_free(struct nhg_connected_tree_head *head)
115
0
{
116
0
  struct nhg_connected *rb_node_dep = NULL;
117
118
0
  if (!nhg_connected_tree_is_empty(head)) {
119
0
    frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
120
0
      nhg_connected_tree_del(head, rb_node_dep);
121
0
      nhg_connected_free(rb_node_dep);
122
0
    }
123
0
  }
124
0
}
125
126
bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head)
127
0
{
128
0
  return nhg_connected_tree_count(head) ? false : true;
129
0
}
130
131
struct nhg_connected *
132
nhg_connected_tree_root(struct nhg_connected_tree_head *head)
133
0
{
134
0
  return nhg_connected_tree_first(head);
135
0
}
136
137
struct nhg_hash_entry *
138
nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
139
         struct nhg_hash_entry *depend)
140
0
{
141
0
  struct nhg_connected lookup = {};
142
0
  struct nhg_connected *remove = NULL;
143
0
  struct nhg_hash_entry *removed_nhe;
144
145
0
  lookup.nhe = depend;
146
147
  /* Lookup to find the element, then remove it */
148
0
  remove = nhg_connected_tree_find(head, &lookup);
149
0
  if (remove)
150
    /* Re-returning here just in case this API changes..
151
     * the _del list api's are a bit undefined at the moment.
152
     *
153
     * So hopefully returning here will make it fail if the api
154
     * changes to something different than currently expected.
155
     */
156
0
    remove = nhg_connected_tree_del(head, remove);
157
158
  /* If the entry was sucessfully removed, free the 'connected` struct */
159
0
  if (remove) {
160
0
    removed_nhe = remove->nhe;
161
0
    nhg_connected_free(remove);
162
0
    return removed_nhe;
163
0
  }
164
165
0
  return NULL;
166
0
}
167
168
/* Assuming UNIQUE RB tree. If this changes, assumptions here about
169
 * insertion need to change.
170
 */
171
struct nhg_hash_entry *
172
nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
173
         struct nhg_hash_entry *depend)
174
0
{
175
0
  struct nhg_connected *new = NULL;
176
177
0
  new = nhg_connected_new(depend);
178
179
  /* On success, NULL will be returned from the
180
   * RB code.
181
   */
182
0
  if (new && (nhg_connected_tree_add(head, new) == NULL))
183
0
    return NULL;
184
185
  /* If it wasn't successful, it must be a duplicate. We enforce the
186
   * unique property for the `nhg_connected` tree.
187
   */
188
0
  nhg_connected_free(new);
189
190
0
  return depend;
191
0
}
192
193
static void
194
nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head *head)
195
0
{
196
0
  struct nhg_connected *rb_node_dep = NULL;
197
198
0
  frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
199
0
    zebra_nhg_decrement_ref(rb_node_dep->nhe);
200
0
  }
201
0
}
202
203
static void
204
nhg_connected_tree_increment_ref(struct nhg_connected_tree_head *head)
205
0
{
206
0
  struct nhg_connected *rb_node_dep = NULL;
207
208
0
  frr_each(nhg_connected_tree, head, rb_node_dep) {
209
0
    zebra_nhg_increment_ref(rb_node_dep->nhe);
210
0
  }
211
0
}
212
213
struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe)
214
0
{
215
0
  if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)
216
0
      && !zebra_nhg_depends_is_empty(nhe)) {
217
0
    nhe = nhg_connected_tree_root(&nhe->nhg_depends)->nhe;
218
0
    return zebra_nhg_resolve(nhe);
219
0
  }
220
221
0
  return nhe;
222
0
}
223
224
unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
225
0
{
226
0
  return nhg_connected_tree_count(&nhe->nhg_depends);
227
0
}
228
229
bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
230
0
{
231
0
  return nhg_connected_tree_is_empty(&nhe->nhg_depends);
232
0
}
233
234
static void zebra_nhg_depends_del(struct nhg_hash_entry *from,
235
          struct nhg_hash_entry *depend)
236
0
{
237
0
  nhg_connected_tree_del_nhe(&from->nhg_depends, depend);
238
0
}
239
240
static void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
241
0
{
242
0
  nhg_connected_tree_init(&nhe->nhg_depends);
243
0
}
244
245
unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe)
246
0
{
247
0
  return nhg_connected_tree_count(&nhe->nhg_dependents);
248
0
}
249
250
251
bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe)
252
0
{
253
0
  return nhg_connected_tree_is_empty(&nhe->nhg_dependents);
254
0
}
255
256
static void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
257
             struct nhg_hash_entry *dependent)
258
0
{
259
0
  nhg_connected_tree_del_nhe(&from->nhg_dependents, dependent);
260
0
}
261
262
static void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
263
             struct nhg_hash_entry *dependent)
264
0
{
265
0
  nhg_connected_tree_add_nhe(&to->nhg_dependents, dependent);
266
0
}
267
268
static void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe)
269
0
{
270
0
  nhg_connected_tree_init(&nhe->nhg_dependents);
271
0
}
272
273
/* Release this nhe from anything depending on it */
274
static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe)
275
0
{
276
0
  struct nhg_connected *rb_node_dep = NULL;
277
278
0
  frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) {
279
0
    zebra_nhg_depends_del(rb_node_dep->nhe, nhe);
280
    /* recheck validity of the dependent */
281
0
    zebra_nhg_check_valid(rb_node_dep->nhe);
282
0
  }
283
0
}
284
285
/* Release this nhe from anything that it depends on */
286
static void zebra_nhg_depends_release(struct nhg_hash_entry *nhe)
287
0
{
288
0
  if (!zebra_nhg_depends_is_empty(nhe)) {
289
0
    struct nhg_connected *rb_node_dep = NULL;
290
291
0
    frr_each_safe(nhg_connected_tree, &nhe->nhg_depends,
292
0
             rb_node_dep) {
293
0
      zebra_nhg_dependents_del(rb_node_dep->nhe, nhe);
294
0
    }
295
0
  }
296
0
}
297
298
299
struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
300
0
{
301
0
  struct nhg_hash_entry lookup = {};
302
303
0
  lookup.id = id;
304
0
  return hash_lookup(zrouter.nhgs_id, &lookup);
305
0
}
306
307
static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
308
0
{
309
0
  if (hash_lookup(zrouter.nhgs_id, nhe)) {
310
0
    flog_err(
311
0
      EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
312
0
      "Failed inserting NHG %pNG into the ID hash table, entry already exists",
313
0
      nhe);
314
0
    return -1;
315
0
  }
316
317
0
  (void)hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
318
319
0
  return 0;
320
0
}
321
322
static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
323
0
{
324
0
  nhe->ifp = ifp;
325
0
  if_nhg_dependents_add(ifp, nhe);
326
0
}
327
328
static void
329
zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
330
        struct nhg_connected_tree_head *nhg_depends)
331
0
{
332
0
  struct nhg_connected *rb_node_dep = NULL;
333
334
  /* This has been allocated higher above in the stack. Could probably
335
   * re-allocate and free the old stuff but just using the same memory
336
   * for now. Otherwise, their might be a time trade-off for repeated
337
   * alloc/frees as startup.
338
   */
339
0
  nhe->nhg_depends = *nhg_depends;
340
341
  /* Attach backpointer to anything that it depends on */
342
0
  zebra_nhg_dependents_init(nhe);
343
0
  if (!zebra_nhg_depends_is_empty(nhe)) {
344
0
    frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
345
0
      if (IS_ZEBRA_DEBUG_NHG_DETAIL)
346
0
        zlog_debug("%s: nhe %p (%pNG), dep %p (%pNG)",
347
0
             __func__, nhe, nhe, rb_node_dep->nhe,
348
0
             rb_node_dep->nhe);
349
350
0
      zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
351
0
    }
352
0
  }
353
0
}
354
355
/* Init an nhe, for use in a hash lookup for example */
356
void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
357
        const struct nexthop *nh)
358
0
{
359
0
  memset(nhe, 0, sizeof(struct nhg_hash_entry));
360
0
  nhe->vrf_id = VRF_DEFAULT;
361
0
  nhe->type = ZEBRA_ROUTE_NHG;
362
0
  nhe->afi = AFI_UNSPEC;
363
364
  /* There are some special rules that apply to groups representing
365
   * a single nexthop.
366
   */
367
0
  if (nh && (nh->next == NULL)) {
368
0
    switch (nh->type) {
369
0
    case NEXTHOP_TYPE_IFINDEX:
370
0
    case NEXTHOP_TYPE_BLACKHOLE:
371
      /*
372
       * This switch case handles setting the afi different
373
       * for ipv4/v6 routes. Ifindex/blackhole nexthop
374
       * objects cannot be ambiguous, they must be Address
375
       * Family specific. If we get here, we will either use
376
       * the AF of the route, or the one we got passed from
377
       * here from the kernel.
378
       */
379
0
      nhe->afi = afi;
380
0
      break;
381
0
    case NEXTHOP_TYPE_IPV4_IFINDEX:
382
0
    case NEXTHOP_TYPE_IPV4:
383
0
      nhe->afi = AFI_IP;
384
0
      break;
385
0
    case NEXTHOP_TYPE_IPV6_IFINDEX:
386
0
    case NEXTHOP_TYPE_IPV6:
387
0
      nhe->afi = AFI_IP6;
388
0
      break;
389
0
    }
390
0
  }
391
0
}
392
393
struct nhg_hash_entry *zebra_nhg_alloc(void)
394
0
{
395
0
  struct nhg_hash_entry *nhe;
396
397
0
  nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
398
399
0
  return nhe;
400
0
}
401
402
/*
403
 * Allocate new nhe and make shallow copy of 'orig'; no
404
 * recursive info is copied.
405
 */
406
struct nhg_hash_entry *zebra_nhe_copy(const struct nhg_hash_entry *orig,
407
              uint32_t id)
408
0
{
409
0
  struct nhg_hash_entry *nhe;
410
411
0
  nhe = zebra_nhg_alloc();
412
413
0
  nhe->id = id;
414
415
0
  nexthop_group_copy(&(nhe->nhg), &(orig->nhg));
416
417
0
  nhe->vrf_id = orig->vrf_id;
418
0
  nhe->afi = orig->afi;
419
0
  nhe->type = orig->type ? orig->type : ZEBRA_ROUTE_NHG;
420
0
  nhe->refcnt = 0;
421
0
  nhe->dplane_ref = zebra_router_get_next_sequence();
422
423
  /* Copy backup info also, if present */
424
0
  if (orig->backup_info)
425
0
    nhe->backup_info = nhg_backup_copy(orig->backup_info);
426
427
0
  return nhe;
428
0
}
429
430
/* Allocation via hash handler */
431
static void *zebra_nhg_hash_alloc(void *arg)
432
0
{
433
0
  struct nhg_hash_entry *nhe = NULL;
434
0
  struct nhg_hash_entry *copy = arg;
435
436
0
  nhe = zebra_nhe_copy(copy, copy->id);
437
438
  /* Mark duplicate nexthops in a group at creation time. */
439
0
  nexthop_group_mark_duplicates(&(nhe->nhg));
440
441
  /*
442
   * Add the ifp now if it's not a group or recursive and has ifindex.
443
   *
444
   * A proto-owned ID is always a group.
445
   */
446
0
  if (!PROTO_OWNED(nhe) && nhe->nhg.nexthop && !nhe->nhg.nexthop->next
447
0
      && !nhe->nhg.nexthop->resolved && nhe->nhg.nexthop->ifindex) {
448
0
    struct interface *ifp = NULL;
449
450
0
    ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex,
451
0
           nhe->nhg.nexthop->vrf_id);
452
0
    if (ifp)
453
0
      zebra_nhg_set_if(nhe, ifp);
454
0
    else {
455
0
      if (IS_ZEBRA_DEBUG_NHG)
456
0
        zlog_debug(
457
0
          "Failed to lookup an interface with ifindex=%d in vrf=%u for NHE %pNG",
458
0
          nhe->nhg.nexthop->ifindex,
459
0
          nhe->nhg.nexthop->vrf_id, nhe);
460
0
    }
461
0
  }
462
463
0
  return nhe;
464
0
}
465
466
uint32_t zebra_nhg_hash_key(const void *arg)
467
0
{
468
0
  const struct nhg_hash_entry *nhe = arg;
469
0
  uint32_t key = 0x5a351234;
470
0
  uint32_t primary = 0;
471
0
  uint32_t backup = 0;
472
473
0
  primary = nexthop_group_hash(&(nhe->nhg));
474
0
  if (nhe->backup_info)
475
0
    backup = nexthop_group_hash(&(nhe->backup_info->nhe->nhg));
476
477
0
  key = jhash_3words(primary, backup, nhe->type, key);
478
479
0
  key = jhash_2words(nhe->vrf_id, nhe->afi, key);
480
481
0
  return key;
482
0
}
483
484
uint32_t zebra_nhg_id_key(const void *arg)
485
0
{
486
0
  const struct nhg_hash_entry *nhe = arg;
487
488
0
  return nhe->id;
489
0
}
490
491
/* Helper with common nhg/nhe nexthop comparison logic */
492
static bool nhg_compare_nexthops(const struct nexthop *nh1,
493
         const struct nexthop *nh2)
494
0
{
495
0
  assert(nh1 != NULL && nh2 != NULL);
496
497
  /*
498
   * We have to check the active flag of each individual one,
499
   * not just the overall active_num. This solves the special case
500
   * issue of a route with a nexthop group with one nexthop
501
   * resolving to itself and thus marking it inactive. If we
502
   * have two different routes each wanting to mark a different
503
   * nexthop inactive, they need to hash to two different groups.
504
   *
505
   * If we just hashed on num_active, they would hash the same
506
   * which is incorrect.
507
   *
508
   * ex)
509
   *      1.1.1.0/24
510
   *           -> 1.1.1.1 dummy1 (inactive)
511
   *           -> 1.1.2.1 dummy2
512
   *
513
   *      1.1.2.0/24
514
   *           -> 1.1.1.1 dummy1
515
   *           -> 1.1.2.1 dummy2 (inactive)
516
   *
517
   * Without checking each individual one, they would hash to
518
   * the same group and both have 1.1.1.1 dummy1 marked inactive.
519
   *
520
   */
521
0
  if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_ACTIVE)
522
0
      != CHECK_FLAG(nh2->flags, NEXTHOP_FLAG_ACTIVE))
523
0
    return false;
524
525
0
  if (!nexthop_same(nh1, nh2))
526
0
    return false;
527
528
0
  return true;
529
0
}
530
531
bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
532
0
{
533
0
  const struct nhg_hash_entry *nhe1 = arg1;
534
0
  const struct nhg_hash_entry *nhe2 = arg2;
535
0
  struct nexthop *nexthop1;
536
0
  struct nexthop *nexthop2;
537
538
  /* No matter what if they equal IDs, assume equal */
539
0
  if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
540
0
    return true;
541
542
0
  if (nhe1->type != nhe2->type)
543
0
    return false;
544
545
0
  if (nhe1->vrf_id != nhe2->vrf_id)
546
0
    return false;
547
548
0
  if (nhe1->afi != nhe2->afi)
549
0
    return false;
550
551
0
  if (nhe1->nhg.nhgr.buckets != nhe2->nhg.nhgr.buckets)
552
0
    return false;
553
554
0
  if (nhe1->nhg.nhgr.idle_timer != nhe2->nhg.nhgr.idle_timer)
555
0
    return false;
556
557
0
  if (nhe1->nhg.nhgr.unbalanced_timer != nhe2->nhg.nhgr.unbalanced_timer)
558
0
    return false;
559
560
  /* Nexthops should be in-order, so we simply compare them in-place */
561
0
  for (nexthop1 = nhe1->nhg.nexthop, nexthop2 = nhe2->nhg.nexthop;
562
0
       nexthop1 && nexthop2;
563
0
       nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
564
565
0
    if (!nhg_compare_nexthops(nexthop1, nexthop2))
566
0
      return false;
567
0
  }
568
569
  /* Check for unequal list lengths */
570
0
  if (nexthop1 || nexthop2)
571
0
    return false;
572
573
  /* If there's no backup info, comparison is done. */
574
0
  if ((nhe1->backup_info == NULL) && (nhe2->backup_info == NULL))
575
0
    return true;
576
577
  /* Compare backup info also - test the easy things first */
578
0
  if (nhe1->backup_info && (nhe2->backup_info == NULL))
579
0
    return false;
580
0
  if (nhe2->backup_info && (nhe1->backup_info == NULL))
581
0
    return false;
582
583
  /* Compare number of backups before actually comparing any */
584
0
  for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
585
0
       nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
586
0
       nexthop1 && nexthop2;
587
0
       nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
588
0
    ;
589
0
  }
590
591
  /* Did we find the end of one list before the other? */
592
0
  if (nexthop1 || nexthop2)
593
0
    return false;
594
595
  /* Have to compare the backup nexthops */
596
0
  for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
597
0
       nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
598
0
       nexthop1 && nexthop2;
599
0
       nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
600
601
0
    if (!nhg_compare_nexthops(nexthop1, nexthop2))
602
0
      return false;
603
0
  }
604
605
0
  return true;
606
0
}
607
608
bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
609
0
{
610
0
  const struct nhg_hash_entry *nhe1 = arg1;
611
0
  const struct nhg_hash_entry *nhe2 = arg2;
612
613
0
  return nhe1->id == nhe2->id;
614
0
}
615
616
static int zebra_nhg_process_grp(struct nexthop_group *nhg,
617
         struct nhg_connected_tree_head *depends,
618
         struct nh_grp *grp, uint8_t count,
619
         struct nhg_resilience *resilience)
620
0
{
621
0
  nhg_connected_tree_init(depends);
622
623
0
  for (int i = 0; i < count; i++) {
624
0
    struct nhg_hash_entry *depend = NULL;
625
    /* We do not care about nexthop_grp.weight at
626
     * this time. But we should figure out
627
     * how to adapt this to our code in
628
     * the future.
629
     */
630
0
    depend = depends_find_id_add(depends, grp[i].id);
631
632
0
    if (!depend) {
633
0
      flog_err(
634
0
        EC_ZEBRA_NHG_SYNC,
635
0
        "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
636
0
        grp[i].id);
637
0
      return -1;
638
0
    }
639
640
    /*
641
     * If this is a nexthop with its own group
642
     * dependencies, add them as well. Not sure its
643
     * even possible to have a group within a group
644
     * in the kernel.
645
     */
646
647
0
    copy_nexthops(&nhg->nexthop, depend->nhg.nexthop, NULL);
648
0
  }
649
650
0
  if (resilience)
651
0
    nhg->nhgr = *resilience;
652
653
0
  return 0;
654
0
}
655
656
static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
657
            struct nexthop *nh, afi_t afi, int type)
658
0
{
659
0
  struct nhg_hash_entry *depend = NULL;
660
0
  struct nexthop_group resolved_ng = {};
661
662
0
  resolved_ng.nexthop = nh;
663
664
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
665
0
    zlog_debug("%s: head %p, nh %pNHv",
666
0
         __func__, nhg_depends, nh);
667
668
0
  depend = zebra_nhg_rib_find(0, &resolved_ng, afi, type);
669
670
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
671
0
    zlog_debug("%s: nh %pNHv => %p (%u)",
672
0
         __func__, nh, depend,
673
0
         depend ? depend->id : 0);
674
675
0
  if (depend)
676
0
    depends_add(nhg_depends, depend);
677
0
}
678
679
/*
680
 * Lookup an nhe in the global hash, using data from another nhe. If 'lookup'
681
 * has an id value, that's used. Create a new global/shared nhe if not found.
682
 */
683
static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
684
         struct nhg_hash_entry *lookup,
685
         struct nhg_connected_tree_head *nhg_depends,
686
         afi_t afi, bool from_dplane)
687
0
{
688
0
  bool created = false;
689
0
  bool recursive = false;
690
0
  struct nhg_hash_entry *newnhe, *backup_nhe;
691
0
  struct nexthop *nh = NULL;
692
693
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
694
0
    zlog_debug(
695
0
      "%s: id %u, lookup %p, vrf %d, type %d, depends %p%s",
696
0
      __func__, lookup->id, lookup, lookup->vrf_id,
697
0
      lookup->type, nhg_depends,
698
0
      (from_dplane ? " (from dplane)" : ""));
699
700
0
  if (lookup->id)
701
0
    (*nhe) = zebra_nhg_lookup_id(lookup->id);
702
0
  else
703
0
    (*nhe) = hash_lookup(zrouter.nhgs, lookup);
704
705
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
706
0
    zlog_debug("%s: lookup => %p (%pNG)", __func__, *nhe, *nhe);
707
708
  /* If we found an existing object, we're done */
709
0
  if (*nhe)
710
0
    goto done;
711
712
  /* We're going to create/insert a new nhe:
713
   * assign the next global id value if necessary.
714
   */
715
0
  if (lookup->id == 0)
716
0
    lookup->id = nhg_get_next_id();
717
718
0
  if (!from_dplane && lookup->id < ZEBRA_NHG_PROTO_LOWER) {
719
    /*
720
     * This is a zebra hashed/owned NHG.
721
     *
722
     * It goes in HASH and ID table.
723
     */
724
0
    newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
725
0
    zebra_nhg_insert_id(newnhe);
726
0
  } else {
727
    /*
728
     * This is upperproto owned NHG or one we read in from dataplane
729
     * and should not be hashed to.
730
     *
731
     * It goes in ID table.
732
     */
733
0
    newnhe =
734
0
      hash_get(zrouter.nhgs_id, lookup, zebra_nhg_hash_alloc);
735
0
  }
736
737
0
  created = true;
738
739
  /* Mail back the new object */
740
0
  *nhe = newnhe;
741
742
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
743
0
    zlog_debug("%s: => created %p (%pNG)", __func__, newnhe,
744
0
         newnhe);
745
746
  /* Only hash/lookup the depends if the first lookup
747
   * fails to find something. This should hopefully save a
748
   * lot of cycles for larger ecmp sizes.
749
   */
750
0
  if (nhg_depends) {
751
    /* If you don't want to hash on each nexthop in the
752
     * nexthop group struct you can pass the depends
753
     * directly. Kernel-side we do this since it just looks
754
     * them up via IDs.
755
     */
756
0
    zebra_nhg_connect_depends(newnhe, nhg_depends);
757
0
    goto done;
758
0
  }
759
760
  /* Prepare dependency relationships if this is not a
761
   * singleton nexthop. There are two cases: a single
762
   * recursive nexthop, where we need a relationship to the
763
   * resolving nexthop; or a group of nexthops, where we need
764
   * relationships with the corresponding singletons.
765
   */
766
0
  zebra_nhg_depends_init(newnhe);
767
768
0
  nh = newnhe->nhg.nexthop;
769
770
0
  if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE))
771
0
    SET_FLAG(newnhe->flags, NEXTHOP_GROUP_VALID);
772
773
0
  if (nh->next == NULL && newnhe->id < ZEBRA_NHG_PROTO_LOWER) {
774
0
    if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
775
      /* Single recursive nexthop */
776
0
      handle_recursive_depend(&newnhe->nhg_depends,
777
0
            nh->resolved, afi,
778
0
            newnhe->type);
779
0
      recursive = true;
780
0
    }
781
0
  } else {
782
    /* Proto-owned are groups by default */
783
    /* List of nexthops */
784
0
    for (nh = newnhe->nhg.nexthop; nh; nh = nh->next) {
785
0
      if (IS_ZEBRA_DEBUG_NHG_DETAIL)
786
0
        zlog_debug("%s: depends NH %pNHv %s",
787
0
             __func__, nh,
788
0
             CHECK_FLAG(nh->flags,
789
0
                  NEXTHOP_FLAG_RECURSIVE) ?
790
0
             "(R)" : "");
791
792
0
      depends_find_add(&newnhe->nhg_depends, nh, afi,
793
0
           newnhe->type, from_dplane);
794
0
    }
795
0
  }
796
797
0
  if (recursive)
798
0
    SET_FLAG(newnhe->flags, NEXTHOP_GROUP_RECURSIVE);
799
800
  /* Attach dependent backpointers to singletons */
801
0
  zebra_nhg_connect_depends(newnhe, &newnhe->nhg_depends);
802
803
  /**
804
   * Backup Nexthops
805
   */
806
807
0
  if (zebra_nhg_get_backup_nhg(newnhe) == NULL ||
808
0
      zebra_nhg_get_backup_nhg(newnhe)->nexthop == NULL)
809
0
    goto done;
810
811
  /* If there are backup nexthops, add them to the backup
812
   * depends tree. The rules here are a little different.
813
   */
814
0
  recursive = false;
815
0
  backup_nhe = newnhe->backup_info->nhe;
816
817
0
  nh = backup_nhe->nhg.nexthop;
818
819
  /* Singleton recursive NH */
820
0
  if (nh->next == NULL &&
821
0
      CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
822
0
    if (IS_ZEBRA_DEBUG_NHG_DETAIL)
823
0
      zlog_debug("%s: backup depend NH %pNHv (R)",
824
0
           __func__, nh);
825
826
    /* Single recursive nexthop */
827
0
    handle_recursive_depend(&backup_nhe->nhg_depends, nh->resolved,
828
0
          afi, backup_nhe->type);
829
0
    recursive = true;
830
0
  } else {
831
    /* One or more backup NHs */
832
0
    for (; nh; nh = nh->next) {
833
0
      if (IS_ZEBRA_DEBUG_NHG_DETAIL)
834
0
        zlog_debug("%s: backup depend NH %pNHv %s",
835
0
             __func__, nh,
836
0
             CHECK_FLAG(nh->flags,
837
0
                  NEXTHOP_FLAG_RECURSIVE) ?
838
0
             "(R)" : "");
839
840
0
      depends_find_add(&backup_nhe->nhg_depends, nh, afi,
841
0
           backup_nhe->type, from_dplane);
842
0
    }
843
0
  }
844
845
0
  if (recursive)
846
0
    SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE);
847
848
0
done:
849
  /* Reset time since last update */
850
0
  (*nhe)->uptime = monotime(NULL);
851
852
0
  return created;
853
0
}
854
855
/*
856
 * Lookup or create an nhe, based on an nhg or an nhe id.
857
 */
858
static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
859
         struct nexthop_group *nhg,
860
         struct nhg_connected_tree_head *nhg_depends,
861
         vrf_id_t vrf_id, afi_t afi, int type,
862
         bool from_dplane)
863
0
{
864
0
  struct nhg_hash_entry lookup = {};
865
0
  bool created = false;
866
867
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
868
0
    zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p",
869
0
         __func__, id, nhg, vrf_id, type,
870
0
         nhg_depends);
871
872
  /* Use a temporary nhe and call into the superset/common code */
873
0
  lookup.id = id;
874
0
  lookup.type = type ? type : ZEBRA_ROUTE_NHG;
875
0
  lookup.nhg = *nhg;
876
877
0
  lookup.vrf_id = vrf_id;
878
0
  if (nhg_depends || lookup.nhg.nexthop->next) {
879
    /* Groups can have all vrfs and AF's in them */
880
0
    lookup.afi = AFI_UNSPEC;
881
0
  } else {
882
0
    switch (lookup.nhg.nexthop->type) {
883
0
    case (NEXTHOP_TYPE_IFINDEX):
884
0
    case (NEXTHOP_TYPE_BLACKHOLE):
885
      /*
886
       * This switch case handles setting the afi different
887
       * for ipv4/v6 routes. Ifindex/blackhole nexthop
888
       * objects cannot be ambiguous, they must be Address
889
       * Family specific. If we get here, we will either use
890
       * the AF of the route, or the one we got passed from
891
       * here from the kernel.
892
       */
893
0
      lookup.afi = afi;
894
0
      break;
895
0
    case (NEXTHOP_TYPE_IPV4_IFINDEX):
896
0
    case (NEXTHOP_TYPE_IPV4):
897
0
      lookup.afi = AFI_IP;
898
0
      break;
899
0
    case (NEXTHOP_TYPE_IPV6_IFINDEX):
900
0
    case (NEXTHOP_TYPE_IPV6):
901
0
      lookup.afi = AFI_IP6;
902
0
      break;
903
0
    }
904
0
  }
905
906
0
  created = zebra_nhe_find(nhe, &lookup, nhg_depends, afi, from_dplane);
907
908
0
  return created;
909
0
}
910
911
/* Find/create a single nexthop */
912
static struct nhg_hash_entry *zebra_nhg_find_nexthop(uint32_t id,
913
                 struct nexthop *nh,
914
                 afi_t afi, int type,
915
                 bool from_dplane)
916
0
{
917
0
  struct nhg_hash_entry *nhe = NULL;
918
0
  struct nexthop_group nhg = {};
919
0
  vrf_id_t vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nh->vrf_id;
920
921
0
  nexthop_group_add_sorted(&nhg, nh);
922
923
0
  zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type, from_dplane);
924
925
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
926
0
    zlog_debug("%s: nh %pNHv => %p (%pNG)", __func__, nh, nhe, nhe);
927
928
0
  return nhe;
929
0
}
930
931
static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx)
932
0
{
933
0
  return ctx->id;
934
0
}
935
936
static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_status status)
937
0
{
938
0
  ctx->status = status;
939
0
}
940
941
static enum nhg_ctx_status nhg_ctx_get_status(const struct nhg_ctx *ctx)
942
0
{
943
0
  return ctx->status;
944
0
}
945
946
static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op)
947
0
{
948
0
  ctx->op = op;
949
0
}
950
951
static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
952
0
{
953
0
  return ctx->op;
954
0
}
955
956
static vrf_id_t nhg_ctx_get_vrf_id(const struct nhg_ctx *ctx)
957
0
{
958
0
  return ctx->vrf_id;
959
0
}
960
961
static int nhg_ctx_get_type(const struct nhg_ctx *ctx)
962
0
{
963
0
  return ctx->type;
964
0
}
965
966
static int nhg_ctx_get_afi(const struct nhg_ctx *ctx)
967
0
{
968
0
  return ctx->afi;
969
0
}
970
971
static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx)
972
0
{
973
0
  return &ctx->u.nh;
974
0
}
975
976
static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx)
977
0
{
978
0
  return ctx->count;
979
0
}
980
981
static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
982
0
{
983
0
  return ctx->u.grp;
984
0
}
985
986
static struct nhg_resilience *nhg_ctx_get_resilience(struct nhg_ctx *ctx)
987
0
{
988
0
  return &ctx->resilience;
989
0
}
990
991
static struct nhg_ctx *nhg_ctx_new(void)
992
0
{
993
0
  struct nhg_ctx *new;
994
995
0
  new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
996
997
0
  return new;
998
0
}
999
1000
void nhg_ctx_free(struct nhg_ctx **ctx)
1001
0
{
1002
0
  struct nexthop *nh;
1003
1004
0
  if (ctx == NULL)
1005
0
    return;
1006
1007
0
  assert((*ctx) != NULL);
1008
1009
0
  if (nhg_ctx_get_count(*ctx))
1010
0
    goto done;
1011
1012
0
  nh = nhg_ctx_get_nh(*ctx);
1013
1014
0
  nexthop_del_labels(nh);
1015
0
  nexthop_del_srv6_seg6local(nh);
1016
0
  nexthop_del_srv6_seg6(nh);
1017
1018
0
done:
1019
0
  XFREE(MTYPE_NHG_CTX, *ctx);
1020
0
}
1021
1022
static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
1023
            struct nh_grp *grp, vrf_id_t vrf_id,
1024
            afi_t afi, int type, uint8_t count,
1025
            struct nhg_resilience *resilience)
1026
0
{
1027
0
  struct nhg_ctx *ctx = NULL;
1028
1029
0
  ctx = nhg_ctx_new();
1030
1031
0
  ctx->id = id;
1032
0
  ctx->vrf_id = vrf_id;
1033
0
  ctx->afi = afi;
1034
0
  ctx->type = type;
1035
0
  ctx->count = count;
1036
1037
0
  if (resilience)
1038
0
    ctx->resilience = *resilience;
1039
1040
0
  if (count)
1041
    /* Copy over the array */
1042
0
    memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp));
1043
0
  else if (nh)
1044
0
    ctx->u.nh = *nh;
1045
1046
0
  return ctx;
1047
0
}
1048
1049
static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe)
1050
0
{
1051
0
  struct nhg_connected *rb_node_dep;
1052
1053
0
  SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1054
1055
0
  frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
1056
0
    zebra_nhg_set_valid(rb_node_dep->nhe);
1057
0
}
1058
1059
static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
1060
0
{
1061
0
  struct nhg_connected *rb_node_dep;
1062
1063
0
  UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1064
1065
  /* If we're in shutdown, this interface event needs to clean
1066
   * up installed NHGs, so don't clear that flag directly.
1067
   */
1068
0
  if (!zebra_router_in_shutdown())
1069
0
    UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1070
1071
  /* Update validity of nexthops depending on it */
1072
0
  frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
1073
0
    zebra_nhg_check_valid(rb_node_dep->nhe);
1074
0
}
1075
1076
void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
1077
0
{
1078
0
  struct nhg_connected *rb_node_dep = NULL;
1079
0
  bool valid = false;
1080
1081
  /* If anthing else in the group is valid, the group is valid */
1082
0
  frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
1083
0
    if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) {
1084
0
      valid = true;
1085
0
      goto done;
1086
0
    }
1087
0
  }
1088
1089
0
done:
1090
0
  if (valid)
1091
0
    zebra_nhg_set_valid(nhe);
1092
0
  else
1093
0
    zebra_nhg_set_invalid(nhe);
1094
0
}
1095
1096
static void zebra_nhg_release_all_deps(struct nhg_hash_entry *nhe)
1097
0
{
1098
  /* Remove it from any lists it may be on */
1099
0
  zebra_nhg_depends_release(nhe);
1100
0
  zebra_nhg_dependents_release(nhe);
1101
0
  if (nhe->ifp)
1102
0
    if_nhg_dependents_del(nhe->ifp, nhe);
1103
0
}
1104
1105
static void zebra_nhg_release(struct nhg_hash_entry *nhe)
1106
0
{
1107
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1108
0
    zlog_debug("%s: nhe %p (%pNG)", __func__, nhe, nhe);
1109
1110
0
  zebra_nhg_release_all_deps(nhe);
1111
1112
  /*
1113
   * If its not zebra owned, we didn't store it here and have to be
1114
   * sure we don't clear one thats actually being used.
1115
   */
1116
0
  if (nhe->id < ZEBRA_NHG_PROTO_LOWER)
1117
0
    hash_release(zrouter.nhgs, nhe);
1118
1119
0
  hash_release(zrouter.nhgs_id, nhe);
1120
0
}
1121
1122
static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe)
1123
0
{
1124
0
  zebra_nhg_release(nhe);
1125
0
  zebra_nhg_free(nhe);
1126
0
}
1127
1128
static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe, bool install)
1129
0
{
1130
  /* Update validity of groups depending on it */
1131
0
  struct nhg_connected *rb_node_dep;
1132
1133
0
  frr_each_safe (nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) {
1134
0
    zebra_nhg_set_valid(rb_node_dep->nhe);
1135
    /* install dependent NHG into kernel */
1136
0
    if (install) {
1137
0
      if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1138
0
        zlog_debug(
1139
0
          "%s nh id %u (flags 0x%x) associated dependent NHG %pNG install",
1140
0
          __func__, nhe->id, nhe->flags,
1141
0
          rb_node_dep->nhe);
1142
0
      zebra_nhg_install_kernel(rb_node_dep->nhe);
1143
0
    }
1144
0
  }
1145
0
}
1146
1147
/*
1148
 * The kernel/other program has changed the state of a nexthop object we are
1149
 * using.
1150
 */
1151
static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe,
1152
             bool is_delete)
1153
0
{
1154
0
  if (nhe->refcnt) {
1155
0
    flog_err(
1156
0
      EC_ZEBRA_NHG_SYNC,
1157
0
      "Kernel %s a nexthop group with ID (%pNG) that we are still using for a route, sending it back down",
1158
0
      (is_delete ? "deleted" : "updated"), nhe);
1159
1160
0
    UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1161
0
    zebra_nhg_install_kernel(nhe);
1162
0
  } else
1163
0
    zebra_nhg_handle_uninstall(nhe);
1164
0
}
1165
1166
static int nhg_ctx_process_new(struct nhg_ctx *ctx)
1167
0
{
1168
0
  struct nexthop_group *nhg = NULL;
1169
0
  struct nhg_connected_tree_head nhg_depends = {};
1170
0
  struct nhg_hash_entry *lookup = NULL;
1171
0
  struct nhg_hash_entry *nhe = NULL;
1172
1173
0
  uint32_t id = nhg_ctx_get_id(ctx);
1174
0
  uint8_t count = nhg_ctx_get_count(ctx);
1175
0
  vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx);
1176
0
  int type = nhg_ctx_get_type(ctx);
1177
0
  afi_t afi = nhg_ctx_get_afi(ctx);
1178
1179
0
  lookup = zebra_nhg_lookup_id(id);
1180
1181
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1182
0
    zlog_debug("%s: id %u, count %d, lookup => %p",
1183
0
         __func__, id, count, lookup);
1184
1185
0
  if (lookup) {
1186
    /* This is already present in our table, hence an update
1187
     * that we did not initate.
1188
     */
1189
0
    zebra_nhg_handle_kernel_state_change(lookup, false);
1190
0
    return 0;
1191
0
  }
1192
1193
0
  if (nhg_ctx_get_count(ctx)) {
1194
0
    nhg = nexthop_group_new();
1195
0
    if (zebra_nhg_process_grp(nhg, &nhg_depends,
1196
0
            nhg_ctx_get_grp(ctx), count,
1197
0
            nhg_ctx_get_resilience(ctx))) {
1198
0
      depends_decrement_free(&nhg_depends);
1199
0
      nexthop_group_delete(&nhg);
1200
0
      return -ENOENT;
1201
0
    }
1202
1203
0
    if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, afi,
1204
0
            type, true))
1205
0
      depends_decrement_free(&nhg_depends);
1206
1207
    /* These got copied over in zebra_nhg_alloc() */
1208
0
    nexthop_group_delete(&nhg);
1209
0
  } else
1210
0
    nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi, type,
1211
0
               true);
1212
1213
0
  if (!nhe) {
1214
0
    flog_err(
1215
0
      EC_ZEBRA_TABLE_LOOKUP_FAILED,
1216
0
      "Zebra failed to find or create a nexthop hash entry for ID (%u)",
1217
0
      id);
1218
0
    return -1;
1219
0
  }
1220
1221
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1222
0
    zlog_debug("%s: nhe %p (%pNG) is new", __func__, nhe, nhe);
1223
1224
  /*
1225
   * If daemon nhg from the kernel, add a refcnt here to indicate the
1226
   * daemon owns it.
1227
   */
1228
0
  if (PROTO_OWNED(nhe))
1229
0
    zebra_nhg_increment_ref(nhe);
1230
1231
0
  SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1232
0
  SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1233
1234
0
  return 0;
1235
0
}
1236
1237
static int nhg_ctx_process_del(struct nhg_ctx *ctx)
1238
0
{
1239
0
  struct nhg_hash_entry *nhe = NULL;
1240
0
  uint32_t id = nhg_ctx_get_id(ctx);
1241
1242
0
  nhe = zebra_nhg_lookup_id(id);
1243
1244
0
  if (!nhe) {
1245
0
    flog_warn(
1246
0
      EC_ZEBRA_BAD_NHG_MESSAGE,
1247
0
      "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
1248
0
      id);
1249
0
    return -1;
1250
0
  }
1251
1252
0
  zebra_nhg_handle_kernel_state_change(nhe, true);
1253
1254
0
  return 0;
1255
0
}
1256
1257
static void nhg_ctx_fini(struct nhg_ctx **ctx)
1258
0
{
1259
  /*
1260
   * Just freeing for now, maybe do something more in the future
1261
   * based on flag.
1262
   */
1263
1264
0
  nhg_ctx_free(ctx);
1265
0
}
1266
1267
static int queue_add(struct nhg_ctx *ctx)
1268
0
{
1269
  /* If its queued or already processed do nothing */
1270
0
  if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED)
1271
0
    return 0;
1272
1273
0
  if (rib_queue_nhg_ctx_add(ctx)) {
1274
0
    nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
1275
0
    return -1;
1276
0
  }
1277
1278
0
  nhg_ctx_set_status(ctx, NHG_CTX_QUEUED);
1279
1280
0
  return 0;
1281
0
}
1282
1283
int nhg_ctx_process(struct nhg_ctx *ctx)
1284
0
{
1285
0
  int ret = 0;
1286
1287
0
  switch (nhg_ctx_get_op(ctx)) {
1288
0
  case NHG_CTX_OP_NEW:
1289
0
    ret = nhg_ctx_process_new(ctx);
1290
0
    if (nhg_ctx_get_count(ctx) && ret == -ENOENT
1291
0
        && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) {
1292
      /**
1293
       * We have entered a situation where we are
1294
       * processing a group from the kernel
1295
       * that has a contained nexthop which
1296
       * we have not yet processed.
1297
       *
1298
       * Re-enqueue this ctx to be handled exactly one
1299
       * more time (indicated by the flag).
1300
       *
1301
       * By the time we get back to it, we
1302
       * should have processed its depends.
1303
       */
1304
0
      nhg_ctx_set_status(ctx, NHG_CTX_NONE);
1305
0
      if (queue_add(ctx) == 0) {
1306
0
        nhg_ctx_set_status(ctx, NHG_CTX_REQUEUED);
1307
0
        return 0;
1308
0
      }
1309
0
    }
1310
0
    break;
1311
0
  case NHG_CTX_OP_DEL:
1312
0
    ret = nhg_ctx_process_del(ctx);
1313
0
  case NHG_CTX_OP_NONE:
1314
0
    break;
1315
0
  }
1316
1317
0
  nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
1318
1319
0
  nhg_ctx_fini(&ctx);
1320
1321
0
  return ret;
1322
0
}
1323
1324
/* Kernel-side, you either get a single new nexthop or a array of ID's */
1325
int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
1326
        uint8_t count, vrf_id_t vrf_id, afi_t afi, int type,
1327
        int startup, struct nhg_resilience *nhgr)
1328
0
{
1329
0
  struct nhg_ctx *ctx = NULL;
1330
1331
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1332
0
    zlog_debug("%s: nh %pNHv, id %u, count %d",
1333
0
         __func__, nh, id, (int)count);
1334
1335
0
  if (id > id_counter && id < ZEBRA_NHG_PROTO_LOWER)
1336
    /* Increase our counter so we don't try to create
1337
     * an ID that already exists
1338
     */
1339
0
    id_counter = id;
1340
1341
0
  ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count, nhgr);
1342
0
  nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
1343
1344
  /* Under statup conditions, we need to handle them immediately
1345
   * like we do for routes. Otherwise, we are going to get a route
1346
   * with a nhe_id that we have not handled.
1347
   */
1348
0
  if (startup)
1349
0
    return nhg_ctx_process(ctx);
1350
1351
0
  if (queue_add(ctx)) {
1352
0
    nhg_ctx_fini(&ctx);
1353
0
    return -1;
1354
0
  }
1355
1356
0
  return 0;
1357
0
}
1358
1359
/* Kernel-side, received delete message */
1360
int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
1361
0
{
1362
0
  struct nhg_ctx *ctx = NULL;
1363
1364
0
  ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0, NULL);
1365
1366
0
  nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
1367
1368
0
  if (queue_add(ctx)) {
1369
0
    nhg_ctx_fini(&ctx);
1370
0
    return -1;
1371
0
  }
1372
1373
0
  return 0;
1374
0
}
1375
1376
/* Some dependency helper functions */
1377
static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
1378
                 afi_t afi, int type)
1379
0
{
1380
0
  struct nhg_hash_entry *nhe;
1381
0
  struct nexthop *lookup = NULL;
1382
1383
0
  lookup = nexthop_dup(nh, NULL);
1384
1385
0
  nhe = zebra_nhg_find_nexthop(0, lookup, afi, type, false);
1386
1387
0
  nexthops_free(lookup);
1388
1389
0
  return nhe;
1390
0
}
1391
1392
static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
1393
                 afi_t afi, int type,
1394
                 bool from_dplane)
1395
0
{
1396
0
  struct nhg_hash_entry *nhe;
1397
0
  struct nexthop lookup = {};
1398
1399
  /* Capture a snapshot of this single nh; it might be part of a list,
1400
   * so we need to make a standalone copy.
1401
   */
1402
0
  nexthop_copy_no_recurse(&lookup, nh, NULL);
1403
1404
0
  nhe = zebra_nhg_find_nexthop(0, &lookup, afi, type, from_dplane);
1405
1406
  /* The copy may have allocated labels; free them if necessary. */
1407
0
  nexthop_del_labels(&lookup);
1408
0
  nexthop_del_srv6_seg6local(&lookup);
1409
0
  nexthop_del_srv6_seg6(&lookup);
1410
1411
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1412
0
    zlog_debug("%s: nh %pNHv => %p (%pNG)", __func__, nh, nhe, nhe);
1413
1414
0
  return nhe;
1415
0
}
1416
1417
static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
1418
             int type, bool from_dplane)
1419
0
{
1420
0
  struct nhg_hash_entry *nhe = NULL;
1421
1422
0
  if (!nh)
1423
0
    goto done;
1424
1425
  /* We are separating these functions out to increase handling speed
1426
   * in the non-recursive case (by not alloc/freeing)
1427
   */
1428
0
  if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
1429
0
    nhe = depends_find_recursive(nh, afi, type);
1430
0
  else
1431
0
    nhe = depends_find_singleton(nh, afi, type, from_dplane);
1432
1433
1434
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
1435
0
    zlog_debug("%s: nh %pNHv %s => %p (%pNG)", __func__, nh,
1436
0
         CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE) ? "(R)"
1437
0
                   : "",
1438
0
         nhe, nhe);
1439
0
  }
1440
1441
0
done:
1442
0
  return nhe;
1443
0
}
1444
1445
static void depends_add(struct nhg_connected_tree_head *head,
1446
      struct nhg_hash_entry *depend)
1447
0
{
1448
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1449
0
    zlog_debug("%s: head %p nh %pNHv",
1450
0
         __func__, head, depend->nhg.nexthop);
1451
1452
  /* If NULL is returned, it was successfully added and
1453
   * needs to have its refcnt incremented.
1454
   *
1455
   * Else the NHE is already present in the tree and doesn't
1456
   * need to increment the refcnt.
1457
   */
1458
0
  if (nhg_connected_tree_add_nhe(head, depend) == NULL)
1459
0
    zebra_nhg_increment_ref(depend);
1460
0
}
1461
1462
static struct nhg_hash_entry *
1463
depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
1464
     afi_t afi, int type, bool from_dplane)
1465
0
{
1466
0
  struct nhg_hash_entry *depend = NULL;
1467
1468
0
  depend = depends_find(nh, afi, type, from_dplane);
1469
1470
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1471
0
    zlog_debug("%s: nh %pNHv => %p",
1472
0
         __func__, nh, depend);
1473
1474
0
  if (depend)
1475
0
    depends_add(head, depend);
1476
1477
0
  return depend;
1478
0
}
1479
1480
static struct nhg_hash_entry *
1481
depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id)
1482
0
{
1483
0
  struct nhg_hash_entry *depend = NULL;
1484
1485
0
  depend = zebra_nhg_lookup_id(id);
1486
1487
0
  if (depend)
1488
0
    depends_add(head, depend);
1489
1490
0
  return depend;
1491
0
}
1492
1493
static void depends_decrement_free(struct nhg_connected_tree_head *head)
1494
0
{
1495
0
  nhg_connected_tree_decrement_ref(head);
1496
0
  nhg_connected_tree_free(head);
1497
0
}
1498
1499
/* Find an nhe based on a list of nexthops */
1500
struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id,
1501
            struct nexthop_group *nhg,
1502
            afi_t rt_afi, int type)
1503
0
{
1504
0
  struct nhg_hash_entry *nhe = NULL;
1505
0
  vrf_id_t vrf_id;
1506
1507
  /*
1508
   * CLANG SA is complaining that nexthop may be NULL
1509
   * Make it happy but this is ridonc
1510
   */
1511
0
  assert(nhg->nexthop);
1512
0
  vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
1513
1514
0
  zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, type, false);
1515
1516
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1517
0
    zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe);
1518
1519
0
  return nhe;
1520
0
}
1521
1522
/* Find an nhe based on a route's nhe */
1523
struct nhg_hash_entry *
1524
zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi)
1525
0
{
1526
0
  struct nhg_hash_entry *nhe = NULL;
1527
1528
0
  if (!(rt_nhe && rt_nhe->nhg.nexthop)) {
1529
0
    flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
1530
0
       "No nexthop passed to %s", __func__);
1531
0
    return NULL;
1532
0
  }
1533
1534
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1535
0
    zlog_debug("%s: rt_nhe %p (%pNG)", __func__, rt_nhe, rt_nhe);
1536
1537
0
  zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi, false);
1538
1539
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1540
0
    zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe);
1541
1542
0
  return nhe;
1543
0
}
1544
1545
/*
1546
 * Allocate backup nexthop info object. Typically these are embedded in
1547
 * nhg_hash_entry objects.
1548
 */
1549
struct nhg_backup_info *zebra_nhg_backup_alloc(void)
1550
0
{
1551
0
  struct nhg_backup_info *p;
1552
1553
0
  p = XCALLOC(MTYPE_NHG, sizeof(struct nhg_backup_info));
1554
1555
0
  p->nhe = zebra_nhg_alloc();
1556
1557
  /* Identify the embedded group used to hold the list of backups */
1558
0
  SET_FLAG(p->nhe->flags, NEXTHOP_GROUP_BACKUP);
1559
1560
0
  return p;
1561
0
}
1562
1563
/*
1564
 * Free backup nexthop info object, deal with any embedded allocations
1565
 */
1566
void zebra_nhg_backup_free(struct nhg_backup_info **p)
1567
0
{
1568
0
  if (p && *p) {
1569
0
    if ((*p)->nhe)
1570
0
      zebra_nhg_free((*p)->nhe);
1571
1572
0
    XFREE(MTYPE_NHG, (*p));
1573
0
  }
1574
0
}
1575
1576
/* Accessor for backup nexthop group */
1577
struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe)
1578
0
{
1579
0
  struct nexthop_group *p = NULL;
1580
1581
0
  if (nhe) {
1582
0
    if (nhe->backup_info && nhe->backup_info->nhe)
1583
0
      p = &(nhe->backup_info->nhe->nhg);
1584
0
  }
1585
1586
0
  return p;
1587
0
}
1588
1589
/*
1590
 * Helper to return a copy of a backup_info - note that this is a shallow
1591
 * copy, meant to be used when creating a new nhe from info passed in with
1592
 * a route e.g.
1593
 */
1594
static struct nhg_backup_info *
1595
nhg_backup_copy(const struct nhg_backup_info *orig)
1596
0
{
1597
0
  struct nhg_backup_info *b;
1598
1599
0
  b = zebra_nhg_backup_alloc();
1600
1601
  /* Copy list of nexthops */
1602
0
  nexthop_group_copy(&(b->nhe->nhg), &(orig->nhe->nhg));
1603
1604
0
  return b;
1605
0
}
1606
1607
static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
1608
0
{
1609
0
  nexthops_free(nhe->nhg.nexthop);
1610
1611
0
  zebra_nhg_backup_free(&nhe->backup_info);
1612
1613
  /* Decrement to remove connection ref */
1614
0
  nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1615
0
  nhg_connected_tree_free(&nhe->nhg_depends);
1616
0
  nhg_connected_tree_free(&nhe->nhg_dependents);
1617
0
}
1618
1619
void zebra_nhg_free(struct nhg_hash_entry *nhe)
1620
0
{
1621
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
1622
    /* Group or singleton? */
1623
0
    if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
1624
0
      zlog_debug("%s: nhe %p (%pNG), refcnt %d", __func__,
1625
0
           nhe, nhe, nhe->refcnt);
1626
0
    else
1627
0
      zlog_debug("%s: nhe %p (%pNG), refcnt %d, NH %pNHv",
1628
0
           __func__, nhe, nhe, nhe->refcnt,
1629
0
           nhe->nhg.nexthop);
1630
0
  }
1631
1632
0
  EVENT_OFF(nhe->timer);
1633
1634
0
  zebra_nhg_free_members(nhe);
1635
1636
0
  XFREE(MTYPE_NHG, nhe);
1637
0
}
1638
1639
/*
1640
 * Let's just drop the memory associated with each item
1641
 */
1642
void zebra_nhg_hash_free(void *p)
1643
0
{
1644
0
  struct nhg_hash_entry *nhe = p;
1645
1646
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
1647
    /* Group or singleton? */
1648
0
    if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
1649
0
      zlog_debug("%s: nhe %p (%u), refcnt %d", __func__, nhe,
1650
0
           nhe->id, nhe->refcnt);
1651
0
    else
1652
0
      zlog_debug("%s: nhe %p (%pNG), refcnt %d, NH %pNHv",
1653
0
           __func__, nhe, nhe, nhe->refcnt,
1654
0
           nhe->nhg.nexthop);
1655
0
  }
1656
1657
0
  EVENT_OFF(nhe->timer);
1658
1659
0
  nexthops_free(nhe->nhg.nexthop);
1660
1661
0
  XFREE(MTYPE_NHG, nhe);
1662
0
}
1663
1664
/*
1665
 * On cleanup there are nexthop groups that have not
1666
 * been resolved at all( a nhe->id of 0 ).  As such
1667
 * zebra needs to clean up the memory associated with
1668
 * those entries.
1669
 */
1670
void zebra_nhg_hash_free_zero_id(struct hash_bucket *b, void *arg)
1671
0
{
1672
0
  struct nhg_hash_entry *nhe = b->data;
1673
0
  struct nhg_connected *dep;
1674
1675
0
  while ((dep = nhg_connected_tree_pop(&nhe->nhg_depends))) {
1676
0
    if (dep->nhe->id == 0)
1677
0
      zebra_nhg_hash_free(dep->nhe);
1678
1679
0
    nhg_connected_free(dep);
1680
0
  }
1681
1682
0
  while ((dep = nhg_connected_tree_pop(&nhe->nhg_dependents)))
1683
0
    nhg_connected_free(dep);
1684
1685
0
  if (nhe->backup_info && nhe->backup_info->nhe->id == 0) {
1686
0
    while ((dep = nhg_connected_tree_pop(
1687
0
        &nhe->backup_info->nhe->nhg_depends)))
1688
0
      nhg_connected_free(dep);
1689
1690
0
    zebra_nhg_hash_free(nhe->backup_info->nhe);
1691
1692
0
    XFREE(MTYPE_NHG, nhe->backup_info);
1693
0
  }
1694
0
}
1695
1696
static void zebra_nhg_timer(struct event *thread)
1697
0
{
1698
0
  struct nhg_hash_entry *nhe = EVENT_ARG(thread);
1699
0
1700
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1701
0
    zlog_debug("Nexthop Timer for nhe: %pNG", nhe);
1702
0
1703
0
  if (nhe->refcnt == 1)
1704
0
    zebra_nhg_decrement_ref(nhe);
1705
0
}
1706
1707
void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
1708
0
{
1709
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1710
0
    zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__, nhe, nhe,
1711
0
         nhe->refcnt, nhe->refcnt - 1);
1712
1713
0
  nhe->refcnt--;
1714
1715
0
  if (!zebra_router_in_shutdown() && nhe->refcnt <= 0 &&
1716
0
      CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) &&
1717
0
      !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND)) {
1718
0
    nhe->refcnt = 1;
1719
0
    SET_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND);
1720
0
    event_add_timer(zrouter.master, zebra_nhg_timer, nhe,
1721
0
        zrouter.nhg_keep, &nhe->timer);
1722
0
    return;
1723
0
  }
1724
1725
0
  if (!zebra_nhg_depends_is_empty(nhe))
1726
0
    nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1727
1728
0
  if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
1729
0
    zebra_nhg_uninstall_kernel(nhe);
1730
0
}
1731
1732
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
1733
0
{
1734
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1735
0
    zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__, nhe, nhe,
1736
0
         nhe->refcnt, nhe->refcnt + 1);
1737
1738
0
  nhe->refcnt++;
1739
1740
0
  if (event_is_scheduled(nhe->timer)) {
1741
0
    EVENT_OFF(nhe->timer);
1742
0
    nhe->refcnt--;
1743
0
    UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND);
1744
0
  }
1745
1746
0
  if (!zebra_nhg_depends_is_empty(nhe))
1747
0
    nhg_connected_tree_increment_ref(&nhe->nhg_depends);
1748
0
}
1749
1750
static struct nexthop *nexthop_set_resolved(afi_t afi,
1751
              const struct nexthop *newhop,
1752
              struct nexthop *nexthop,
1753
              struct zebra_sr_policy *policy)
1754
0
{
1755
0
  struct nexthop *resolved_hop;
1756
0
  uint8_t num_labels = 0;
1757
0
  mpls_label_t labels[MPLS_MAX_LABELS];
1758
0
  enum lsp_types_t label_type = ZEBRA_LSP_NONE;
1759
0
  int i = 0;
1760
1761
0
  resolved_hop = nexthop_new();
1762
0
  SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
1763
1764
0
  resolved_hop->vrf_id = nexthop->vrf_id;
1765
0
  switch (newhop->type) {
1766
0
  case NEXTHOP_TYPE_IPV4:
1767
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1768
    /* If the resolving route specifies a gateway, use it */
1769
0
    resolved_hop->type = newhop->type;
1770
0
    resolved_hop->gate.ipv4 = newhop->gate.ipv4;
1771
1772
0
    if (newhop->ifindex) {
1773
0
      resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1774
0
      resolved_hop->ifindex = newhop->ifindex;
1775
0
    }
1776
0
    break;
1777
0
  case NEXTHOP_TYPE_IPV6:
1778
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1779
0
    resolved_hop->type = newhop->type;
1780
0
    resolved_hop->gate.ipv6 = newhop->gate.ipv6;
1781
1782
0
    if (newhop->ifindex) {
1783
0
      resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1784
0
      resolved_hop->ifindex = newhop->ifindex;
1785
0
    }
1786
0
    break;
1787
0
  case NEXTHOP_TYPE_IFINDEX:
1788
    /* If the resolving route is an interface route,
1789
     * it means the gateway we are looking up is connected
1790
     * to that interface. (The actual network is _not_ onlink).
1791
     * Therefore, the resolved route should have the original
1792
     * gateway as nexthop as it is directly connected.
1793
     *
1794
     * On Linux, we have to set the onlink netlink flag because
1795
     * otherwise, the kernel won't accept the route.
1796
     */
1797
0
    resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1798
0
    if (afi == AFI_IP) {
1799
0
      resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1800
0
      resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
1801
0
    } else if (afi == AFI_IP6) {
1802
0
      resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1803
0
      resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
1804
0
    }
1805
0
    resolved_hop->ifindex = newhop->ifindex;
1806
0
    break;
1807
0
  case NEXTHOP_TYPE_BLACKHOLE:
1808
0
    resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
1809
0
    resolved_hop->bh_type = newhop->bh_type;
1810
0
    break;
1811
0
  }
1812
1813
0
  if (newhop->flags & NEXTHOP_FLAG_ONLINK)
1814
0
    resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1815
1816
  /* Copy labels of the resolved route and the parent resolving to it */
1817
0
  if (policy) {
1818
0
    int label_num = 0;
1819
1820
    /*
1821
     * Don't push the first SID if the corresponding action in the
1822
     * LFIB is POP.
1823
     */
1824
0
    if (!newhop->nh_label || !newhop->nh_label->num_labels
1825
0
        || newhop->nh_label->label[0] == MPLS_LABEL_IMPLICIT_NULL)
1826
0
      label_num = 1;
1827
1828
0
    for (; label_num < policy->segment_list.label_num; label_num++)
1829
0
      labels[num_labels++] =
1830
0
        policy->segment_list.labels[label_num];
1831
0
    label_type = policy->segment_list.type;
1832
0
  } else if (newhop->nh_label) {
1833
0
    for (i = 0; i < newhop->nh_label->num_labels; i++) {
1834
      /* Be a bit picky about overrunning the local array */
1835
0
      if (num_labels >= MPLS_MAX_LABELS) {
1836
0
        if (IS_ZEBRA_DEBUG_NHG || IS_ZEBRA_DEBUG_RIB)
1837
0
          zlog_debug("%s: too many labels in newhop %pNHv",
1838
0
               __func__, newhop);
1839
0
        break;
1840
0
      }
1841
0
      labels[num_labels++] = newhop->nh_label->label[i];
1842
0
    }
1843
    /* Use the "outer" type */
1844
0
    label_type = newhop->nh_label_type;
1845
0
  }
1846
1847
0
  if (nexthop->nh_label) {
1848
0
    for (i = 0; i < nexthop->nh_label->num_labels; i++) {
1849
      /* Be a bit picky about overrunning the local array */
1850
0
      if (num_labels >= MPLS_MAX_LABELS) {
1851
0
        if (IS_ZEBRA_DEBUG_NHG || IS_ZEBRA_DEBUG_RIB)
1852
0
          zlog_debug("%s: too many labels in nexthop %pNHv",
1853
0
               __func__, nexthop);
1854
0
        break;
1855
0
      }
1856
0
      labels[num_labels++] = nexthop->nh_label->label[i];
1857
0
    }
1858
1859
    /* If the parent has labels, use its type if
1860
     * we don't already have one.
1861
     */
1862
0
    if (label_type == ZEBRA_LSP_NONE)
1863
0
      label_type = nexthop->nh_label_type;
1864
0
  }
1865
1866
0
  if (num_labels)
1867
0
    nexthop_add_labels(resolved_hop, label_type, num_labels,
1868
0
           labels);
1869
1870
0
  if (nexthop->nh_srv6) {
1871
0
    nexthop_add_srv6_seg6local(resolved_hop,
1872
0
             nexthop->nh_srv6->seg6local_action,
1873
0
             &nexthop->nh_srv6->seg6local_ctx);
1874
0
    nexthop_add_srv6_seg6(resolved_hop,
1875
0
              &nexthop->nh_srv6->seg6_segs);
1876
0
  }
1877
1878
0
  resolved_hop->rparent = nexthop;
1879
0
  _nexthop_add(&nexthop->resolved, resolved_hop);
1880
1881
0
  return resolved_hop;
1882
0
}
1883
1884
/* Checks if nexthop we are trying to resolve to is valid */
1885
static bool nexthop_valid_resolve(const struct nexthop *nexthop,
1886
          const struct nexthop *resolved)
1887
0
{
1888
  /* Can't resolve to a recursive nexthop */
1889
0
  if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
1890
0
    return false;
1891
1892
  /* Must be ACTIVE */
1893
0
  if (!CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_ACTIVE))
1894
0
    return false;
1895
1896
  /* Must not be duplicate */
1897
0
  if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_DUPLICATE))
1898
0
    return false;
1899
1900
0
  switch (nexthop->type) {
1901
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1902
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1903
    /* If the nexthop we are resolving to does not match the
1904
     * ifindex for the nexthop the route wanted, its not valid.
1905
     */
1906
0
    if (nexthop->ifindex != resolved->ifindex)
1907
0
      return false;
1908
0
    break;
1909
0
  case NEXTHOP_TYPE_IPV4:
1910
0
  case NEXTHOP_TYPE_IPV6:
1911
0
  case NEXTHOP_TYPE_IFINDEX:
1912
0
  case NEXTHOP_TYPE_BLACKHOLE:
1913
0
    break;
1914
0
  }
1915
1916
0
  return true;
1917
0
}
1918
1919
/*
1920
 * Downstream VNI and Single VXlan device check.
1921
 *
1922
 * If it has nexthop VNI labels at this point it must be D-VNI allocated
1923
 * and all the nexthops have to be on an SVD.
1924
 *
1925
 * If SVD is not available, mark as inactive.
1926
 */
1927
static bool nexthop_set_evpn_dvni_svd(vrf_id_t re_vrf_id,
1928
              struct nexthop *nexthop)
1929
0
{
1930
0
  if (!is_vrf_l3vni_svd_backed(re_vrf_id)) {
1931
0
    if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
1932
0
      struct vrf *vrf = vrf_lookup_by_id(re_vrf_id);
1933
1934
0
      zlog_debug(
1935
0
        "nexthop %pNHv D-VNI but route's vrf %s(%u) doesn't use SVD",
1936
0
        nexthop, VRF_LOGNAME(vrf), re_vrf_id);
1937
0
    }
1938
1939
0
    return false;
1940
0
  }
1941
1942
0
  nexthop->ifindex = get_l3vni_vxlan_ifindex(re_vrf_id);
1943
0
  nexthop->vrf_id = 0;
1944
1945
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1946
0
    zlog_debug("nexthop %pNHv using SVD", nexthop);
1947
1948
0
  return true;
1949
0
}
1950
1951
/*
1952
 * Given a nexthop we need to properly recursively resolve
1953
 * the route.  As such, do a table lookup to find and match
1954
 * if at all possible.  Set the nexthop->ifindex and resolved_id
1955
 * as appropriate
1956
 */
1957
static int resolve_backup_nexthops(const struct nexthop *nexthop,
1958
           const struct nhg_hash_entry *nhe,
1959
           struct nexthop *resolved,
1960
           struct nhg_hash_entry *resolve_nhe,
1961
           struct backup_nh_map_s *map)
1962
0
{
1963
0
  int i, j, idx;
1964
0
  const struct nexthop *bnh;
1965
0
  struct nexthop *nh, *newnh;
1966
0
  mpls_label_t labels[MPLS_MAX_LABELS];
1967
0
  uint8_t num_labels;
1968
1969
0
  assert(nexthop->backup_num <= NEXTHOP_MAX_BACKUPS);
1970
1971
  /* Locate backups from the original nexthop's backup index and nhe */
1972
0
  for (i = 0; i < nexthop->backup_num; i++) {
1973
0
    idx = nexthop->backup_idx[i];
1974
1975
    /* Do we already know about this particular backup? */
1976
0
    for (j = 0; j < map->map_count; j++) {
1977
0
      if (map->map[j].orig_idx == idx)
1978
0
        break;
1979
0
    }
1980
1981
0
    if (j < map->map_count) {
1982
0
      resolved->backup_idx[resolved->backup_num] =
1983
0
        map->map[j].new_idx;
1984
0
      resolved->backup_num++;
1985
1986
0
      SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP);
1987
1988
0
      if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1989
0
        zlog_debug("%s: found map idx orig %d, new %d",
1990
0
             __func__, map->map[j].orig_idx,
1991
0
             map->map[j].new_idx);
1992
1993
0
      continue;
1994
0
    }
1995
1996
    /* We can't handle any new map entries at this point. */
1997
0
    if (map->map_count == MULTIPATH_NUM)
1998
0
      break;
1999
2000
    /* Need to create/copy a new backup */
2001
0
    bnh = nhe->backup_info->nhe->nhg.nexthop;
2002
0
    for (j = 0; j < idx; j++) {
2003
0
      if (bnh == NULL)
2004
0
        break;
2005
0
      bnh = bnh->next;
2006
0
    }
2007
2008
    /* Whoops - bad index in the nexthop? */
2009
0
    if (bnh == NULL)
2010
0
      continue;
2011
2012
0
    if (resolve_nhe->backup_info == NULL)
2013
0
      resolve_nhe->backup_info = zebra_nhg_backup_alloc();
2014
2015
    /* Update backup info in the resolving nexthop and its nhe */
2016
0
    newnh = nexthop_dup_no_recurse(bnh, NULL);
2017
2018
    /* We may need some special handling for mpls labels: the new
2019
     * backup needs to carry the recursive nexthop's labels,
2020
     * if any: they may be vrf labels e.g.
2021
     * The original/inner labels are in the stack of 'resolve_nhe',
2022
     * if that is longer than the stack in 'nexthop'.
2023
     */
2024
0
    if (newnh->nh_label && resolved->nh_label &&
2025
0
        nexthop->nh_label) {
2026
0
      if (resolved->nh_label->num_labels >
2027
0
          nexthop->nh_label->num_labels) {
2028
        /* Prepare new label stack */
2029
0
        num_labels = 0;
2030
0
        for (j = 0; j < newnh->nh_label->num_labels;
2031
0
             j++) {
2032
0
          labels[j] = newnh->nh_label->label[j];
2033
0
          num_labels++;
2034
0
        }
2035
2036
        /* Include inner labels */
2037
0
        for (j = nexthop->nh_label->num_labels;
2038
0
             j < resolved->nh_label->num_labels;
2039
0
             j++) {
2040
0
          labels[num_labels] =
2041
0
            resolved->nh_label->label[j];
2042
0
          num_labels++;
2043
0
        }
2044
2045
        /* Replace existing label stack in the backup */
2046
0
        nexthop_del_labels(newnh);
2047
0
        nexthop_add_labels(newnh, bnh->nh_label_type,
2048
0
               num_labels, labels);
2049
0
      }
2050
0
    }
2051
2052
    /* Need to compute the new backup index in the new
2053
     * backup list, and add to map struct.
2054
     */
2055
0
    j = 0;
2056
0
    nh = resolve_nhe->backup_info->nhe->nhg.nexthop;
2057
0
    if (nh) {
2058
0
      while (nh->next) {
2059
0
        nh = nh->next;
2060
0
        j++;
2061
0
      }
2062
2063
0
      nh->next = newnh;
2064
0
      j++;
2065
2066
0
    } else  /* First one */
2067
0
      resolve_nhe->backup_info->nhe->nhg.nexthop = newnh;
2068
2069
    /* Capture index */
2070
0
    resolved->backup_idx[resolved->backup_num] = j;
2071
0
    resolved->backup_num++;
2072
2073
0
    SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP);
2074
2075
0
    if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2076
0
      zlog_debug("%s: added idx orig %d, new %d",
2077
0
           __func__, idx, j);
2078
2079
    /* Update map/cache */
2080
0
    map->map[map->map_count].orig_idx = idx;
2081
0
    map->map[map->map_count].new_idx = j;
2082
0
    map->map_count++;
2083
0
  }
2084
2085
0
  return 0;
2086
0
}
2087
2088
/*
2089
 * So this nexthop resolution has decided that a connected route
2090
 * is the correct choice.  At this point in time if FRR has multiple
2091
 * connected routes that all point to the same prefix one will be
2092
 * selected, *but* the particular interface may not be the one
2093
 * that the nexthop points at.  Let's look at all the available
2094
 * connected routes on this node and if any of them auto match
2095
 * the routes nexthops ifindex that is good enough for a match
2096
 *
2097
 * This code is depending on the fact that a nexthop->ifindex is 0
2098
 * if it is not known, if this assumption changes, yummy!
2099
 * Additionally a ifindx of 0 means figure it out for us.
2100
 */
2101
static struct route_entry *
2102
zebra_nhg_connected_ifindex(struct route_node *rn, struct route_entry *match,
2103
          int32_t curr_ifindex)
2104
0
{
2105
0
  struct nexthop *newhop = match->nhe->nhg.nexthop;
2106
0
  struct route_entry *re;
2107
2108
0
  assert(newhop); /* What a kick in the patooey */
2109
2110
0
  if (curr_ifindex == 0)
2111
0
    return match;
2112
2113
0
  if (curr_ifindex == newhop->ifindex)
2114
0
    return match;
2115
2116
  /*
2117
   * At this point we know that this route is matching a connected
2118
   * but there are possibly a bunch of connected routes that are
2119
   * alive that should be considered as well.  So let's iterate over
2120
   * all the re's and see if they are connected as well and maybe one
2121
   * of those ifindexes match as well.
2122
   */
2123
0
  RNODE_FOREACH_RE (rn, re) {
2124
0
    if (re->type != ZEBRA_ROUTE_CONNECT)
2125
0
      continue;
2126
2127
0
    if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2128
0
      continue;
2129
2130
    /*
2131
     * zebra has a connected route that is not removed
2132
     * let's test if it is good
2133
     */
2134
0
    newhop = re->nhe->nhg.nexthop;
2135
0
    assert(newhop);
2136
0
    if (curr_ifindex == newhop->ifindex)
2137
0
      return re;
2138
0
  }
2139
2140
0
  return match;
2141
0
}
2142
2143
/*
2144
 * Given a nexthop we need to properly recursively resolve,
2145
 * do a table lookup to find and match if at all possible.
2146
 * Set the nexthop->ifindex and resolution info as appropriate.
2147
 */
2148
static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
2149
        const struct prefix *top, int type, uint32_t flags,
2150
        uint32_t *pmtu, vrf_id_t vrf_id)
2151
0
{
2152
0
  struct prefix p;
2153
0
  struct route_table *table;
2154
0
  struct route_node *rn;
2155
0
  struct route_entry *match = NULL;
2156
0
  int resolved;
2157
0
  struct zebra_nhlfe *nhlfe;
2158
0
  struct nexthop *newhop;
2159
0
  struct interface *ifp;
2160
0
  rib_dest_t *dest;
2161
0
  struct zebra_vrf *zvrf;
2162
0
  struct in_addr local_ipv4;
2163
0
  struct in_addr *ipv4;
2164
0
  afi_t afi = AFI_IP;
2165
2166
  /* Reset some nexthop attributes that we'll recompute if necessary */
2167
0
  if ((nexthop->type == NEXTHOP_TYPE_IPV4)
2168
0
      || (nexthop->type == NEXTHOP_TYPE_IPV6))
2169
0
    nexthop->ifindex = 0;
2170
2171
0
  UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
2172
0
  nexthops_free(nexthop->resolved);
2173
0
  nexthop->resolved = NULL;
2174
2175
  /*
2176
   * Set afi based on nexthop type.
2177
   * Some nexthop types get special handling, possibly skipping
2178
   * the normal processing.
2179
   */
2180
0
  switch (nexthop->type) {
2181
0
  case NEXTHOP_TYPE_IFINDEX:
2182
2183
0
    ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
2184
    /* If the interface exists and its operative, it's active */
2185
0
    if (ifp && (if_is_operative(ifp)))
2186
0
      return 1;
2187
0
    else
2188
0
      return 0;
2189
0
    break;
2190
2191
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
2192
0
    afi = AFI_IP6;
2193
2194
0
    if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
2195
0
      ifp = if_lookup_by_index(nexthop->ifindex,
2196
0
             nexthop->vrf_id);
2197
0
      if (ifp && if_is_operative(ifp))
2198
0
        return 1;
2199
0
      else
2200
0
        return 0;
2201
0
    }
2202
0
    break;
2203
2204
0
  case NEXTHOP_TYPE_IPV4:
2205
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
2206
0
    afi = AFI_IP;
2207
0
    break;
2208
0
  case NEXTHOP_TYPE_IPV6:
2209
0
    afi = AFI_IP6;
2210
0
    break;
2211
2212
0
  case NEXTHOP_TYPE_BLACKHOLE:
2213
0
    return 1;
2214
0
  }
2215
2216
  /*
2217
   * If the nexthop has been marked as 'onlink' we just need to make
2218
   * sure the nexthop's interface is known and is operational.
2219
   */
2220
0
  if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
2221
    /* DVNI/SVD Checks for EVPN routes */
2222
0
    if (nexthop->nh_label &&
2223
0
        nexthop->nh_label_type == ZEBRA_LSP_EVPN &&
2224
0
        !nexthop_set_evpn_dvni_svd(vrf_id, nexthop))
2225
0
      return 0;
2226
2227
0
    ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
2228
0
    if (!ifp) {
2229
0
      if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2230
0
        zlog_debug("nexthop %pNHv marked onlink but nhif %u doesn't exist",
2231
0
             nexthop, nexthop->ifindex);
2232
0
      return 0;
2233
0
    }
2234
0
    if (!if_is_operative(ifp)) {
2235
0
      if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2236
0
        zlog_debug("nexthop %pNHv marked onlink but nhif %s is not operational",
2237
0
             nexthop, ifp->name);
2238
0
      return 0;
2239
0
    }
2240
0
    return 1;
2241
0
  }
2242
2243
0
  if (top &&
2244
0
      ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN &&
2245
0
        nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) ||
2246
0
       (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN &&
2247
0
        memcmp(&nexthop->gate.ipv6, &top->u.prefix6, IPV6_MAX_BYTELEN) ==
2248
0
          0)) &&
2249
0
      nexthop->vrf_id == vrf_id) {
2250
0
    if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2251
0
      zlog_debug(
2252
0
        "        :%s: Attempting to install a max prefixlength route through itself",
2253
0
        __func__);
2254
0
    return 0;
2255
0
  }
2256
2257
  /* Validation for ipv4 mapped ipv6 nexthop. */
2258
0
  if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
2259
0
    afi = AFI_IP;
2260
0
    ipv4 = &local_ipv4;
2261
0
    ipv4_mapped_ipv6_to_ipv4(&nexthop->gate.ipv6, ipv4);
2262
0
  } else {
2263
0
    ipv4 = &nexthop->gate.ipv4;
2264
0
  }
2265
2266
  /* Processing for nexthops with SR 'color' attribute, using
2267
   * the corresponding SR policy object.
2268
   */
2269
0
  if (nexthop->srte_color) {
2270
0
    struct ipaddr endpoint = {0};
2271
0
    struct zebra_sr_policy *policy;
2272
2273
0
    switch (afi) {
2274
0
    case AFI_IP:
2275
0
      endpoint.ipa_type = IPADDR_V4;
2276
0
      endpoint.ipaddr_v4 = *ipv4;
2277
0
      break;
2278
0
    case AFI_IP6:
2279
0
      endpoint.ipa_type = IPADDR_V6;
2280
0
      endpoint.ipaddr_v6 = nexthop->gate.ipv6;
2281
0
      break;
2282
0
    case AFI_UNSPEC:
2283
0
    case AFI_L2VPN:
2284
0
    case AFI_MAX:
2285
0
      flog_err(EC_LIB_DEVELOPMENT,
2286
0
         "%s: unknown address-family: %u", __func__,
2287
0
         afi);
2288
0
      exit(1);
2289
0
    }
2290
2291
0
    policy = zebra_sr_policy_find(nexthop->srte_color, &endpoint);
2292
0
    if (policy && policy->status == ZEBRA_SR_POLICY_UP) {
2293
0
      resolved = 0;
2294
0
      frr_each_safe (nhlfe_list, &policy->lsp->nhlfe_list,
2295
0
               nhlfe) {
2296
0
        if (!CHECK_FLAG(nhlfe->flags,
2297
0
            NHLFE_FLAG_SELECTED)
2298
0
            || CHECK_FLAG(nhlfe->flags,
2299
0
              NHLFE_FLAG_DELETED))
2300
0
          continue;
2301
0
        SET_FLAG(nexthop->flags,
2302
0
           NEXTHOP_FLAG_RECURSIVE);
2303
0
        nexthop_set_resolved(afi, nhlfe->nexthop,
2304
0
                 nexthop, policy);
2305
0
        resolved = 1;
2306
0
      }
2307
0
      if (resolved)
2308
0
        return 1;
2309
0
    }
2310
0
  }
2311
2312
  /* Make lookup prefix. */
2313
0
  memset(&p, 0, sizeof(struct prefix));
2314
0
  switch (afi) {
2315
0
  case AFI_IP:
2316
0
    p.family = AF_INET;
2317
0
    p.prefixlen = IPV4_MAX_BITLEN;
2318
0
    p.u.prefix4 = *ipv4;
2319
0
    break;
2320
0
  case AFI_IP6:
2321
0
    p.family = AF_INET6;
2322
0
    p.prefixlen = IPV6_MAX_BITLEN;
2323
0
    p.u.prefix6 = nexthop->gate.ipv6;
2324
0
    break;
2325
0
  case AFI_UNSPEC:
2326
0
  case AFI_L2VPN:
2327
0
  case AFI_MAX:
2328
0
    assert(afi != AFI_IP && afi != AFI_IP6);
2329
0
    break;
2330
0
  }
2331
  /* Lookup table.  */
2332
0
  table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
2333
  /* get zvrf */
2334
0
  zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
2335
0
  if (!table || !zvrf) {
2336
0
    if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2337
0
      zlog_debug("        %s: Table not found", __func__);
2338
0
    return 0;
2339
0
  }
2340
2341
0
  rn = route_node_match(table, (struct prefix *)&p);
2342
0
  while (rn) {
2343
0
    route_unlock_node(rn);
2344
2345
    /* Lookup should halt if we've matched against ourselves ('top',
2346
     * if specified) - i.e., we cannot have a nexthop NH1 is
2347
     * resolved by a route NH1. The exception is if the route is a
2348
     * host route.
2349
     */
2350
0
    if (prefix_same(&rn->p, top))
2351
0
      if (((afi == AFI_IP)
2352
0
           && (rn->p.prefixlen != IPV4_MAX_BITLEN))
2353
0
          || ((afi == AFI_IP6)
2354
0
        && (rn->p.prefixlen != IPV6_MAX_BITLEN))) {
2355
0
        if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2356
0
          zlog_debug(
2357
0
            "        %s: Matched against ourself and prefix length is not max bit length",
2358
0
            __func__);
2359
0
        return 0;
2360
0
      }
2361
2362
    /* Pick up selected route. */
2363
    /* However, do not resolve over default route unless explicitly
2364
     * allowed.
2365
     */
2366
0
    if (is_default_prefix(&rn->p)
2367
0
        && !rnh_resolve_via_default(zvrf, p.family)) {
2368
0
      if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2369
0
        zlog_debug("        :%s: %pFX Resolved against default route",
2370
0
             __func__, &p);
2371
0
      return 0;
2372
0
    }
2373
2374
0
    dest = rib_dest_from_rnode(rn);
2375
0
    if (dest && dest->selected_fib &&
2376
0
        (!CHECK_FLAG(dest->selected_fib->status,
2377
0
         ROUTE_ENTRY_REMOVED) ||
2378
0
         CHECK_FLAG(dest->selected_fib->status,
2379
0
        ROUTE_ENTRY_ROUTE_REPLACING)) &&
2380
0
        dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
2381
0
      match = dest->selected_fib;
2382
2383
    /* If there is no selected route or matched route is EGP, go up
2384
     * tree.
2385
     */
2386
0
    if (!match) {
2387
0
      do {
2388
0
        rn = rn->parent;
2389
0
      } while (rn && rn->info == NULL);
2390
0
      if (rn)
2391
0
        route_lock_node(rn);
2392
0
      continue;
2393
0
    }
2394
2395
0
    if ((match->type == ZEBRA_ROUTE_CONNECT) ||
2396
0
        (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type))) {
2397
0
      match = zebra_nhg_connected_ifindex(rn, match,
2398
0
                  nexthop->ifindex);
2399
2400
0
      newhop = match->nhe->nhg.nexthop;
2401
0
      if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
2402
0
          nexthop->type == NEXTHOP_TYPE_IPV6)
2403
0
        nexthop->ifindex = newhop->ifindex;
2404
0
      else if (nexthop->ifindex != newhop->ifindex) {
2405
0
        if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2406
0
          zlog_debug(
2407
0
            "%s: %pNHv given ifindex does not match nexthops ifindex found: %pNHv",
2408
0
            __func__, nexthop, newhop);
2409
        /*
2410
         * NEXTHOP_TYPE_*_IFINDEX but ifindex
2411
         * doesn't match what we found.
2412
         */
2413
0
        return 0;
2414
0
      }
2415
2416
0
      if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2417
0
        zlog_debug(
2418
0
          "%s: CONNECT match %p (%pNG), newhop %pNHv",
2419
0
          __func__, match, match->nhe, newhop);
2420
2421
0
      return 1;
2422
0
    } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
2423
0
      struct nexthop_group *nhg;
2424
0
      struct nexthop *resolver;
2425
0
      struct backup_nh_map_s map = {};
2426
2427
0
      resolved = 0;
2428
2429
      /*
2430
       * Only useful if installed or being Route Replacing
2431
       * Why Being Route Replaced as well?
2432
       * Imagine a route A and route B( that depends on A )
2433
       * for recursive resolution and A already exists in the
2434
       * zebra rib.  If zebra receives the routes
2435
       * for resolution at aproximately the same time in the [
2436
       * B, A ] order on the workQ.  If this happens then
2437
       * normal route resolution will happen and B will be
2438
       * resolved successfully and then A will be resolved
2439
       * successfully. Now imagine the reversed order [A, B].
2440
       * A will be resolved and then scheduled for installed
2441
       * (Thus not having the ROUTE_ENTRY_INSTALLED flag ).  B
2442
       * will then get resolved and fail to be installed
2443
       * because the original below test.  Let's `loosen` this
2444
       * up a tiny bit and allow the
2445
       * ROUTE_ENTRY_ROUTE_REPLACING flag ( that is set when a
2446
       * Route Replace operation is being initiated on A now )
2447
       * to now satisfy this situation.  This will allow
2448
       * either order in the workQ to work properly.
2449
       */
2450
0
      if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED) &&
2451
0
          !CHECK_FLAG(match->status,
2452
0
          ROUTE_ENTRY_ROUTE_REPLACING)) {
2453
0
        if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2454
0
          zlog_debug(
2455
0
            "%s: match %p (%pNG) not installed or being Route Replaced",
2456
0
            __func__, match, match->nhe);
2457
2458
0
        goto done_with_match;
2459
0
      }
2460
2461
      /* Examine installed nexthops; note that there
2462
       * may not be any installed primary nexthops if
2463
       * only backups are installed.
2464
       */
2465
0
      nhg = rib_get_fib_nhg(match);
2466
0
      for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
2467
0
        if (!nexthop_valid_resolve(nexthop, newhop))
2468
0
          continue;
2469
2470
0
        if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2471
0
          zlog_debug(
2472
0
            "%s: RECURSIVE match %p (%pNG), newhop %pNHv",
2473
0
            __func__, match, match->nhe,
2474
0
            newhop);
2475
2476
0
        SET_FLAG(nexthop->flags,
2477
0
           NEXTHOP_FLAG_RECURSIVE);
2478
0
        resolver = nexthop_set_resolved(afi, newhop,
2479
0
                nexthop, NULL);
2480
0
        resolved = 1;
2481
2482
        /* If there are backup nexthops, capture
2483
         * that info with the resolving nexthop.
2484
         */
2485
0
        if (resolver && newhop->backup_num > 0) {
2486
0
          resolve_backup_nexthops(newhop,
2487
0
                match->nhe,
2488
0
                resolver, nhe,
2489
0
                &map);
2490
0
        }
2491
0
      }
2492
2493
      /* Examine installed backup nexthops, if any. There
2494
       * are only installed backups *if* there is a
2495
       * dedicated fib list. The UI can also control use
2496
       * of backups for resolution.
2497
       */
2498
0
      nhg = rib_get_fib_backup_nhg(match);
2499
0
      if (!use_recursive_backups ||
2500
0
          nhg == NULL || nhg->nexthop == NULL)
2501
0
        goto done_with_match;
2502
2503
0
      for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
2504
0
        if (!nexthop_valid_resolve(nexthop, newhop))
2505
0
          continue;
2506
2507
0
        if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2508
0
          zlog_debug(
2509
0
            "%s: RECURSIVE match backup %p (%pNG), newhop %pNHv",
2510
0
            __func__, match, match->nhe,
2511
0
            newhop);
2512
2513
0
        SET_FLAG(nexthop->flags,
2514
0
           NEXTHOP_FLAG_RECURSIVE);
2515
0
        nexthop_set_resolved(afi, newhop, nexthop,
2516
0
                 NULL);
2517
0
        resolved = 1;
2518
0
      }
2519
2520
0
done_with_match:
2521
      /* Capture resolving mtu */
2522
0
      if (resolved) {
2523
0
        if (pmtu)
2524
0
          *pmtu = match->mtu;
2525
2526
0
      } else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2527
0
        zlog_debug(
2528
0
          "        %s: Recursion failed to find",
2529
0
          __func__);
2530
2531
0
      return resolved;
2532
0
    } else {
2533
0
      if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
2534
0
        zlog_debug(
2535
0
          "        %s: Route Type %s has not turned on recursion",
2536
0
          __func__, zebra_route_string(type));
2537
0
        if (type == ZEBRA_ROUTE_BGP
2538
0
            && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP))
2539
0
          zlog_debug(
2540
0
            "        EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
2541
0
      }
2542
0
      return 0;
2543
0
    }
2544
0
  }
2545
0
  if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2546
0
    zlog_debug("        %s: Nexthop did not lookup in table",
2547
0
         __func__);
2548
0
  return 0;
2549
0
}
2550
2551
/* This function verifies reachability of one given nexthop, which can be
2552
 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
2553
 * in nexthop->flags field. The nexthop->ifindex will be updated
2554
 * appropriately as well.
2555
 *
2556
 * An existing route map can turn an otherwise active nexthop into inactive,
2557
 * but not vice versa.
2558
 *
2559
 * The return value is the final value of 'ACTIVE' flag.
2560
 */
2561
static unsigned nexthop_active_check(struct route_node *rn,
2562
             struct route_entry *re,
2563
             struct nexthop *nexthop,
2564
             struct nhg_hash_entry *nhe)
2565
0
{
2566
0
  route_map_result_t ret = RMAP_PERMITMATCH;
2567
0
  afi_t family;
2568
0
  const struct prefix *p, *src_p;
2569
0
  struct zebra_vrf *zvrf;
2570
0
  uint32_t mtu = 0;
2571
0
  vrf_id_t vrf_id;
2572
2573
0
  srcdest_rnode_prefixes(rn, &p, &src_p);
2574
2575
0
  if (rn->p.family == AF_INET)
2576
0
    family = AFI_IP;
2577
0
  else if (rn->p.family == AF_INET6)
2578
0
    family = AFI_IP6;
2579
0
  else
2580
0
    family = AF_UNSPEC;
2581
2582
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2583
0
    zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop);
2584
2585
0
  vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn)));
2586
2587
  /*
2588
   * If this is a kernel route, then if the interface is *up* then
2589
   * by golly gee whiz it's a good route.
2590
   */
2591
0
  if (re->type == ZEBRA_ROUTE_KERNEL || re->type == ZEBRA_ROUTE_SYSTEM) {
2592
0
    struct interface *ifp;
2593
2594
0
    ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
2595
2596
0
    if (ifp && ifp->vrf->vrf_id == vrf_id && if_is_up(ifp)) {
2597
0
      SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2598
0
      goto skip_check;
2599
0
    }
2600
0
  }
2601
2602
0
  switch (nexthop->type) {
2603
0
  case NEXTHOP_TYPE_IFINDEX:
2604
0
    if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
2605
0
           &mtu, vrf_id))
2606
0
      SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2607
0
    else
2608
0
      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2609
0
    break;
2610
0
  case NEXTHOP_TYPE_IPV4:
2611
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
2612
0
    family = AFI_IP;
2613
0
    if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
2614
0
           &mtu, vrf_id))
2615
0
      SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2616
0
    else
2617
0
      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2618
0
    break;
2619
0
  case NEXTHOP_TYPE_IPV6:
2620
0
    family = AFI_IP6;
2621
0
    if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
2622
0
           &mtu, vrf_id))
2623
0
      SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2624
0
    else
2625
0
      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2626
0
    break;
2627
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
2628
    /* RFC 5549, v4 prefix with v6 NH */
2629
0
    if (rn->p.family != AF_INET)
2630
0
      family = AFI_IP6;
2631
2632
0
    if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
2633
0
           &mtu, vrf_id))
2634
0
      SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2635
0
    else
2636
0
      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2637
0
    break;
2638
0
  case NEXTHOP_TYPE_BLACKHOLE:
2639
0
    SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2640
0
    break;
2641
0
  default:
2642
0
    break;
2643
0
  }
2644
2645
0
skip_check:
2646
2647
0
  if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
2648
0
    if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2649
0
      zlog_debug("        %s: Unable to find active nexthop",
2650
0
           __func__);
2651
0
    return 0;
2652
0
  }
2653
2654
  /* Capture recursive nexthop mtu.
2655
   * TODO -- the code used to just reset the re's value to zero
2656
   * for each nexthop, and then jam any resolving route's mtu value in,
2657
   * whether or not that was zero, or lt/gt any existing value? The
2658
   * way this is used appears to be as a floor value, so let's try
2659
   * using it that way here.
2660
   */
2661
0
  if (mtu > 0) {
2662
0
    if (re->nexthop_mtu == 0 || re->nexthop_mtu > mtu)
2663
0
      re->nexthop_mtu = mtu;
2664
0
  }
2665
2666
  /* XXX: What exactly do those checks do? Do we support
2667
   * e.g. IPv4 routes with IPv6 nexthops or vice versa?
2668
   */
2669
0
  if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
2670
0
      || (family == AFI_IP6 && p->family != AF_INET6))
2671
0
    return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2672
2673
  /* The original code didn't determine the family correctly
2674
   * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
2675
   * from the rib_table_info in those cases.
2676
   * Possibly it may be better to use only the rib_table_info
2677
   * in every case.
2678
   */
2679
0
  if (family == 0) {
2680
0
    struct rib_table_info *info;
2681
2682
0
    info = srcdest_rnode_table_info(rn);
2683
0
    family = info->afi;
2684
0
  }
2685
2686
0
  memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
2687
2688
0
  zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
2689
0
  if (!zvrf) {
2690
0
    if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2691
0
      zlog_debug("        %s: zvrf is NULL", __func__);
2692
0
    return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2693
0
  }
2694
2695
  /* It'll get set if required inside */
2696
0
  ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
2697
0
            zvrf, re->tag);
2698
0
  if (ret == RMAP_DENYMATCH) {
2699
0
    if (IS_ZEBRA_DEBUG_RIB) {
2700
0
      zlog_debug(
2701
0
        "%u:%pRN: Filtering out with NH %pNHv due to route map",
2702
0
        re->vrf_id, rn, nexthop);
2703
0
    }
2704
0
    UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2705
0
  }
2706
0
  return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2707
0
}
2708
2709
/* Helper function called after resolution to walk nhg rb trees
2710
 * and toggle the NEXTHOP_GROUP_VALID flag if the nexthop
2711
 * is active on singleton NHEs.
2712
 */
2713
static bool zebra_nhg_set_valid_if_active(struct nhg_hash_entry *nhe)
2714
0
{
2715
0
  struct nhg_connected *rb_node_dep = NULL;
2716
0
  bool valid = false;
2717
2718
0
  if (!zebra_nhg_depends_is_empty(nhe)) {
2719
    /* Is at least one depend valid? */
2720
0
    frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
2721
0
      if (zebra_nhg_set_valid_if_active(rb_node_dep->nhe))
2722
0
        valid = true;
2723
0
    }
2724
2725
0
    goto done;
2726
0
  }
2727
2728
  /* should be fully resolved singleton at this point */
2729
0
  if (CHECK_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE))
2730
0
    valid = true;
2731
2732
0
done:
2733
0
  if (valid)
2734
0
    SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
2735
2736
0
  return valid;
2737
0
}
2738
2739
/* Checks if the first nexthop is EVPN. If not, early return.
2740
 *
2741
 * This is used to determine if there is a mismatch between l3VNI
2742
 * of the route's vrf and the nexthops in use's VNI labels.
2743
 *
2744
 * If there is a mismatch, we keep the labels as these MUST be DVNI nexthops.
2745
 *
2746
 * IF there is no mismatch, we remove the labels and handle the routes as
2747
 * we have traditionally with evpn.
2748
 */
2749
static bool nexthop_list_set_evpn_dvni(struct route_entry *re,
2750
               struct nexthop_group *nhg)
2751
0
{
2752
0
  struct nexthop *nexthop;
2753
0
  vni_t re_vrf_vni;
2754
0
  vni_t nh_vni;
2755
0
  bool use_dvni = false;
2756
2757
0
  nexthop = nhg->nexthop;
2758
2759
0
  if (!nexthop->nh_label || nexthop->nh_label_type != ZEBRA_LSP_EVPN)
2760
0
    return false;
2761
2762
0
  re_vrf_vni = get_l3vni_vni(re->vrf_id);
2763
2764
0
  for (; nexthop; nexthop = nexthop->next) {
2765
0
    if (!nexthop->nh_label ||
2766
0
        nexthop->nh_label_type != ZEBRA_LSP_EVPN)
2767
0
      continue;
2768
2769
0
    nh_vni = label2vni(&nexthop->nh_label->label[0]);
2770
2771
0
    if (nh_vni != re_vrf_vni)
2772
0
      use_dvni = true;
2773
0
  }
2774
2775
  /* Using traditional way, no VNI encap - remove labels */
2776
0
  if (!use_dvni) {
2777
0
    for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next)
2778
0
      nexthop_del_labels(nexthop);
2779
0
  }
2780
2781
0
  return use_dvni;
2782
0
}
2783
2784
/*
2785
 * Process a list of nexthops, given an nhe, determining
2786
 * whether each one is ACTIVE/installable at this time.
2787
 */
2788
static uint32_t nexthop_list_active_update(struct route_node *rn,
2789
             struct route_entry *re,
2790
             struct nhg_hash_entry *nhe,
2791
             bool is_backup)
2792
0
{
2793
0
  union g_addr prev_src;
2794
0
  unsigned int prev_active, new_active;
2795
0
  ifindex_t prev_index;
2796
0
  uint32_t counter = 0;
2797
0
  struct nexthop *nexthop;
2798
0
  struct nexthop_group *nhg = &nhe->nhg;
2799
0
  bool vni_removed = false;
2800
2801
0
  nexthop = nhg->nexthop;
2802
2803
  /* Init recursive nh mtu */
2804
0
  re->nexthop_mtu = 0;
2805
2806
  /* Handler for dvni evpn nexthops. Has to be done at nhg level */
2807
0
  vni_removed = !nexthop_list_set_evpn_dvni(re, nhg);
2808
2809
  /* Process nexthops one-by-one */
2810
0
  for ( ; nexthop; nexthop = nexthop->next) {
2811
2812
    /* No protocol daemon provides src and so we're skipping
2813
     * tracking it
2814
     */
2815
0
    prev_src = nexthop->rmap_src;
2816
0
    prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2817
0
    prev_index = nexthop->ifindex;
2818
2819
    /* Include the containing nhe for primary nexthops: if there's
2820
     * recursive resolution, we capture the backup info also.
2821
     */
2822
0
    new_active =
2823
0
      nexthop_active_check(rn, re, nexthop,
2824
0
               (is_backup ? NULL : nhe));
2825
2826
    /*
2827
     * We need to respect the multipath_num here
2828
     * as that what we should be able to install from
2829
     * a multipath perspective should not be a data plane
2830
     * decision point.
2831
     */
2832
0
    if (new_active && counter >= zrouter.multipath_num) {
2833
0
      struct nexthop *nh;
2834
2835
      /* Set it and its resolved nexthop as inactive. */
2836
0
      for (nh = nexthop; nh; nh = nh->resolved)
2837
0
        UNSET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
2838
2839
0
      new_active = 0;
2840
0
    }
2841
2842
0
    if (new_active)
2843
0
      counter++;
2844
2845
    /* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */
2846
0
    if (prev_active != new_active ||
2847
0
        prev_index != nexthop->ifindex ||
2848
0
        ((nexthop->type >= NEXTHOP_TYPE_IFINDEX &&
2849
0
          nexthop->type < NEXTHOP_TYPE_IPV6) &&
2850
0
         prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr) ||
2851
0
        ((nexthop->type >= NEXTHOP_TYPE_IPV6 &&
2852
0
          nexthop->type < NEXTHOP_TYPE_BLACKHOLE) &&
2853
0
         !(IPV6_ADDR_SAME(&prev_src.ipv6,
2854
0
              &nexthop->rmap_src.ipv6))) ||
2855
0
        CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED) ||
2856
0
        vni_removed)
2857
0
      SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2858
0
  }
2859
2860
0
  return counter;
2861
0
}
2862
2863
2864
static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg)
2865
0
{
2866
0
  struct nexthop *nh;
2867
0
  uint32_t curr_active = 0;
2868
2869
  /* Assume all active for now */
2870
2871
0
  for (nh = nhg->nexthop; nh; nh = nh->next) {
2872
0
    SET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
2873
0
    curr_active++;
2874
0
  }
2875
2876
0
  return curr_active;
2877
0
}
2878
2879
/*
2880
 * Iterate over all nexthops of the given RIB entry and refresh their
2881
 * ACTIVE flag.  If any nexthop is found to toggle the ACTIVE flag,
2882
 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
2883
 *
2884
 * Return value is the new number of active nexthops.
2885
 */
2886
int nexthop_active_update(struct route_node *rn, struct route_entry *re)
2887
0
{
2888
0
  struct nhg_hash_entry *curr_nhe;
2889
0
  uint32_t curr_active = 0, backup_active = 0;
2890
2891
0
  if (PROTO_OWNED(re->nhe))
2892
0
    return proto_nhg_nexthop_active_update(&re->nhe->nhg);
2893
2894
0
  afi_t rt_afi = family2afi(rn->p.family);
2895
2896
0
  UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2897
2898
  /* Make a local copy of the existing nhe, so we don't work on/modify
2899
   * the shared nhe.
2900
   */
2901
0
  curr_nhe = zebra_nhe_copy(re->nhe, re->nhe->id);
2902
2903
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2904
0
    zlog_debug("%s: re %p nhe %p (%pNG), curr_nhe %p", __func__, re,
2905
0
         re->nhe, re->nhe, curr_nhe);
2906
2907
  /* Clear the existing id, if any: this will avoid any confusion
2908
   * if the id exists, and will also force the creation
2909
   * of a new nhe reflecting the changes we may make in this local copy.
2910
   */
2911
0
  curr_nhe->id = 0;
2912
2913
  /* Process nexthops */
2914
0
  curr_active = nexthop_list_active_update(rn, re, curr_nhe, false);
2915
2916
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2917
0
    zlog_debug("%s: re %p curr_active %u", __func__, re,
2918
0
         curr_active);
2919
2920
  /* If there are no backup nexthops, we are done */
2921
0
  if (zebra_nhg_get_backup_nhg(curr_nhe) == NULL)
2922
0
    goto backups_done;
2923
2924
0
  backup_active = nexthop_list_active_update(
2925
0
    rn, re, curr_nhe->backup_info->nhe, true /*is_backup*/);
2926
2927
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2928
0
    zlog_debug("%s: re %p backup_active %u", __func__, re,
2929
0
         backup_active);
2930
2931
0
backups_done:
2932
2933
  /*
2934
   * Ref or create an nhe that matches the current state of the
2935
   * nexthop(s).
2936
   */
2937
0
  if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
2938
0
    struct nhg_hash_entry *new_nhe = NULL;
2939
2940
0
    new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi);
2941
2942
0
    if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2943
0
      zlog_debug(
2944
0
        "%s: re %p CHANGED: nhe %p (%pNG) => new_nhe %p (%pNG)",
2945
0
        __func__, re, re->nhe, re->nhe, new_nhe,
2946
0
        new_nhe);
2947
2948
0
    route_entry_update_nhe(re, new_nhe);
2949
0
  }
2950
2951
2952
  /* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID
2953
   * flag where appropriate.
2954
   */
2955
0
  if (curr_active)
2956
0
    zebra_nhg_set_valid_if_active(re->nhe);
2957
2958
  /*
2959
   * Do not need the old / copied nhe anymore since it
2960
   * was either copied over into a new nhe or not
2961
   * used at all.
2962
   */
2963
0
  zebra_nhg_free(curr_nhe);
2964
0
  return curr_active;
2965
0
}
2966
2967
/* Recursively construct a grp array of fully resolved IDs.
2968
 *
2969
 * This function allows us to account for groups within groups,
2970
 * by converting them into a flat array of IDs.
2971
 *
2972
 * nh_grp is modified at every level of recursion to append
2973
 * to it the next unique, fully resolved ID from the entire tree.
2974
 *
2975
 *
2976
 * Note:
2977
 * I'm pretty sure we only allow ONE level of group within group currently.
2978
 * But making this recursive just in case that ever changes.
2979
 */
2980
static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp,
2981
            uint8_t curr_index,
2982
            struct nhg_hash_entry *nhe,
2983
            int max_num)
2984
0
{
2985
0
  struct nhg_connected *rb_node_dep = NULL;
2986
0
  struct nhg_hash_entry *depend = NULL;
2987
0
  uint8_t i = curr_index;
2988
2989
0
  frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
2990
0
    bool duplicate = false;
2991
2992
0
    if (i >= max_num)
2993
0
      goto done;
2994
2995
0
    depend = rb_node_dep->nhe;
2996
2997
    /*
2998
     * If its recursive, use its resolved nhe in the group
2999
     */
3000
0
    if (CHECK_FLAG(depend->flags, NEXTHOP_GROUP_RECURSIVE)) {
3001
0
      depend = zebra_nhg_resolve(depend);
3002
0
      if (!depend) {
3003
0
        flog_err(
3004
0
          EC_ZEBRA_NHG_FIB_UPDATE,
3005
0
          "Failed to recursively resolve Nexthop Hash Entry in the group id=%pNG",
3006
0
          nhe);
3007
0
        continue;
3008
0
      }
3009
0
    }
3010
3011
0
    if (!zebra_nhg_depends_is_empty(depend)) {
3012
      /* This is a group within a group */
3013
0
      i = zebra_nhg_nhe2grp_internal(grp, i, depend, max_num);
3014
0
    } else {
3015
0
      if (!CHECK_FLAG(depend->flags, NEXTHOP_GROUP_VALID)) {
3016
0
        if (IS_ZEBRA_DEBUG_RIB_DETAILED
3017
0
            || IS_ZEBRA_DEBUG_NHG)
3018
0
          zlog_debug(
3019
0
            "%s: Nexthop ID (%u) not valid, not appending to dataplane install group",
3020
0
            __func__, depend->id);
3021
0
        continue;
3022
0
      }
3023
3024
      /* If the nexthop not installed/queued for install don't
3025
       * put in the ID array.
3026
       */
3027
0
      if (!(CHECK_FLAG(depend->flags, NEXTHOP_GROUP_INSTALLED)
3028
0
            || CHECK_FLAG(depend->flags,
3029
0
              NEXTHOP_GROUP_QUEUED))) {
3030
0
        if (IS_ZEBRA_DEBUG_RIB_DETAILED
3031
0
            || IS_ZEBRA_DEBUG_NHG)
3032
0
          zlog_debug(
3033
0
            "%s: Nexthop ID (%u) not installed or queued for install, not appending to dataplane install group",
3034
0
            __func__, depend->id);
3035
0
        continue;
3036
0
      }
3037
3038
      /* Check for duplicate IDs, ignore if found. */
3039
0
      for (int j = 0; j < i; j++) {
3040
0
        if (depend->id == grp[j].id) {
3041
0
          duplicate = true;
3042
0
          break;
3043
0
        }
3044
0
      }
3045
3046
0
      if (duplicate) {
3047
0
        if (IS_ZEBRA_DEBUG_RIB_DETAILED
3048
0
            || IS_ZEBRA_DEBUG_NHG)
3049
0
          zlog_debug(
3050
0
            "%s: Nexthop ID (%u) is duplicate, not appending to dataplane install group",
3051
0
            __func__, depend->id);
3052
0
        continue;
3053
0
      }
3054
3055
0
      grp[i].id = depend->id;
3056
0
      grp[i].weight = depend->nhg.nexthop->weight;
3057
0
      i++;
3058
0
    }
3059
0
  }
3060
3061
0
  if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL)
3062
0
    goto done;
3063
3064
  /* TODO -- For now, we are not trying to use or install any
3065
   * backup info in this nexthop-id path: we aren't prepared
3066
   * to use the backups here yet. We're just debugging what we find.
3067
   */
3068
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3069
0
    zlog_debug("%s: skipping backup nhe",  __func__);
3070
3071
0
done:
3072
0
  return i;
3073
0
}
3074
3075
/* Convert a nhe into a group array */
3076
uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
3077
        int max_num)
3078
0
{
3079
  /* Call into the recursive function */
3080
0
  return zebra_nhg_nhe2grp_internal(grp, 0, nhe, max_num);
3081
0
}
3082
3083
void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
3084
0
{
3085
0
  struct nhg_connected *rb_node_dep = NULL;
3086
3087
  /* Resolve it first */
3088
0
  nhe = zebra_nhg_resolve(nhe);
3089
3090
0
  if (zebra_nhg_set_valid_if_active(nhe)) {
3091
0
    if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3092
0
      zlog_debug("%s: valid flag set for nh %pNG", __func__,
3093
0
           nhe);
3094
0
  }
3095
3096
  /* Make sure all depends are installed/queued */
3097
0
  frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
3098
0
    zebra_nhg_install_kernel(rb_node_dep->nhe);
3099
0
  }
3100
3101
0
  if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)
3102
0
      && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
3103
0
      && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
3104
    /* Change its type to us since we are installing it */
3105
0
    if (!ZEBRA_NHG_CREATED(nhe))
3106
0
      nhe->type = ZEBRA_ROUTE_NHG;
3107
3108
0
    int ret = dplane_nexthop_add(nhe);
3109
3110
0
    switch (ret) {
3111
0
    case ZEBRA_DPLANE_REQUEST_QUEUED:
3112
0
      SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
3113
0
      break;
3114
0
    case ZEBRA_DPLANE_REQUEST_FAILURE:
3115
0
      flog_err(
3116
0
        EC_ZEBRA_DP_INSTALL_FAIL,
3117
0
        "Failed to install Nexthop ID (%pNG) into the kernel",
3118
0
        nhe);
3119
0
      break;
3120
0
    case ZEBRA_DPLANE_REQUEST_SUCCESS:
3121
0
      SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
3122
0
      zebra_nhg_handle_install(nhe, false);
3123
0
      break;
3124
0
    }
3125
0
  }
3126
0
}
3127
3128
void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
3129
0
{
3130
0
  if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
3131
0
    int ret = dplane_nexthop_delete(nhe);
3132
3133
0
    switch (ret) {
3134
0
    case ZEBRA_DPLANE_REQUEST_QUEUED:
3135
0
      SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
3136
0
      break;
3137
0
    case ZEBRA_DPLANE_REQUEST_FAILURE:
3138
0
      flog_err(
3139
0
        EC_ZEBRA_DP_DELETE_FAIL,
3140
0
        "Failed to uninstall Nexthop ID (%pNG) from the kernel",
3141
0
        nhe);
3142
0
      break;
3143
0
    case ZEBRA_DPLANE_REQUEST_SUCCESS:
3144
0
      UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
3145
0
      break;
3146
0
    }
3147
0
  }
3148
3149
0
  zebra_nhg_handle_uninstall(nhe);
3150
0
}
3151
3152
void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
3153
0
{
3154
0
  enum dplane_op_e op;
3155
0
  enum zebra_dplane_result status;
3156
0
  uint32_t id = 0;
3157
0
  struct nhg_hash_entry *nhe = NULL;
3158
3159
0
  op = dplane_ctx_get_op(ctx);
3160
0
  status = dplane_ctx_get_status(ctx);
3161
3162
0
  id = dplane_ctx_get_nhe_id(ctx);
3163
3164
0
  if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_NHG_DETAIL)
3165
0
    zlog_debug(
3166
0
      "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
3167
0
      ctx, dplane_op2str(op), id, dplane_res2str(status));
3168
3169
0
  switch (op) {
3170
0
  case DPLANE_OP_NH_DELETE:
3171
0
    if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
3172
0
      flog_err(
3173
0
        EC_ZEBRA_DP_DELETE_FAIL,
3174
0
        "Failed to uninstall Nexthop ID (%u) from the kernel",
3175
0
        id);
3176
3177
    /* We already free'd the data, nothing to do */
3178
0
    break;
3179
0
  case DPLANE_OP_NH_INSTALL:
3180
0
  case DPLANE_OP_NH_UPDATE:
3181
0
    nhe = zebra_nhg_lookup_id(id);
3182
3183
0
    if (!nhe) {
3184
0
      if (IS_ZEBRA_DEBUG_NHG)
3185
0
        zlog_debug(
3186
0
          "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
3187
0
          dplane_op2str(op), id);
3188
3189
0
      break;
3190
0
    }
3191
3192
0
    UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
3193
0
    if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
3194
0
      SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
3195
0
      SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
3196
0
      zebra_nhg_handle_install(nhe, true);
3197
3198
      /* If daemon nhg, send it an update */
3199
0
      if (PROTO_OWNED(nhe))
3200
0
        zsend_nhg_notify(nhe->type, nhe->zapi_instance,
3201
0
             nhe->zapi_session, nhe->id,
3202
0
             ZAPI_NHG_INSTALLED);
3203
0
    } else {
3204
      /* If daemon nhg, send it an update */
3205
0
      if (PROTO_OWNED(nhe))
3206
0
        zsend_nhg_notify(nhe->type, nhe->zapi_instance,
3207
0
             nhe->zapi_session, nhe->id,
3208
0
             ZAPI_NHG_FAIL_INSTALL);
3209
3210
0
      if (!(zebra_nhg_proto_nexthops_only() &&
3211
0
            !PROTO_OWNED(nhe)))
3212
0
        flog_err(
3213
0
          EC_ZEBRA_DP_INSTALL_FAIL,
3214
0
          "Failed to install Nexthop (%pNG) into the kernel",
3215
0
          nhe);
3216
0
    }
3217
0
    break;
3218
3219
0
  case DPLANE_OP_ROUTE_INSTALL:
3220
0
  case DPLANE_OP_ROUTE_UPDATE:
3221
0
  case DPLANE_OP_ROUTE_DELETE:
3222
0
  case DPLANE_OP_ROUTE_NOTIFY:
3223
0
  case DPLANE_OP_LSP_INSTALL:
3224
0
  case DPLANE_OP_LSP_UPDATE:
3225
0
  case DPLANE_OP_LSP_DELETE:
3226
0
  case DPLANE_OP_LSP_NOTIFY:
3227
0
  case DPLANE_OP_PW_INSTALL:
3228
0
  case DPLANE_OP_PW_UNINSTALL:
3229
0
  case DPLANE_OP_SYS_ROUTE_ADD:
3230
0
  case DPLANE_OP_SYS_ROUTE_DELETE:
3231
0
  case DPLANE_OP_ADDR_INSTALL:
3232
0
  case DPLANE_OP_ADDR_UNINSTALL:
3233
0
  case DPLANE_OP_MAC_INSTALL:
3234
0
  case DPLANE_OP_MAC_DELETE:
3235
0
  case DPLANE_OP_NEIGH_INSTALL:
3236
0
  case DPLANE_OP_NEIGH_UPDATE:
3237
0
  case DPLANE_OP_NEIGH_DELETE:
3238
0
  case DPLANE_OP_NEIGH_IP_INSTALL:
3239
0
  case DPLANE_OP_NEIGH_IP_DELETE:
3240
0
  case DPLANE_OP_VTEP_ADD:
3241
0
  case DPLANE_OP_VTEP_DELETE:
3242
0
  case DPLANE_OP_RULE_ADD:
3243
0
  case DPLANE_OP_RULE_DELETE:
3244
0
  case DPLANE_OP_RULE_UPDATE:
3245
0
  case DPLANE_OP_NEIGH_DISCOVER:
3246
0
  case DPLANE_OP_BR_PORT_UPDATE:
3247
0
  case DPLANE_OP_NONE:
3248
0
  case DPLANE_OP_IPTABLE_ADD:
3249
0
  case DPLANE_OP_IPTABLE_DELETE:
3250
0
  case DPLANE_OP_IPSET_ADD:
3251
0
  case DPLANE_OP_IPSET_DELETE:
3252
0
  case DPLANE_OP_IPSET_ENTRY_ADD:
3253
0
  case DPLANE_OP_IPSET_ENTRY_DELETE:
3254
0
  case DPLANE_OP_NEIGH_TABLE_UPDATE:
3255
0
  case DPLANE_OP_GRE_SET:
3256
0
  case DPLANE_OP_INTF_ADDR_ADD:
3257
0
  case DPLANE_OP_INTF_ADDR_DEL:
3258
0
  case DPLANE_OP_INTF_NETCONFIG:
3259
0
  case DPLANE_OP_INTF_INSTALL:
3260
0
  case DPLANE_OP_INTF_UPDATE:
3261
0
  case DPLANE_OP_INTF_DELETE:
3262
0
  case DPLANE_OP_TC_QDISC_INSTALL:
3263
0
  case DPLANE_OP_TC_QDISC_UNINSTALL:
3264
0
  case DPLANE_OP_TC_CLASS_ADD:
3265
0
  case DPLANE_OP_TC_CLASS_DELETE:
3266
0
  case DPLANE_OP_TC_CLASS_UPDATE:
3267
0
  case DPLANE_OP_TC_FILTER_ADD:
3268
0
  case DPLANE_OP_TC_FILTER_DELETE:
3269
0
  case DPLANE_OP_TC_FILTER_UPDATE:
3270
0
    break;
3271
0
  }
3272
0
}
3273
3274
static int zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
3275
0
{
3276
0
  struct nhg_hash_entry *nhe = NULL;
3277
3278
0
  nhe = (struct nhg_hash_entry *)bucket->data;
3279
3280
  /*
3281
   * same logic as with routes.
3282
   *
3283
   * If older than startup time, we know we read them in from the
3284
   * kernel and have not gotten and update for them since startup
3285
   * from an upper level proto.
3286
   */
3287
0
  if (zrouter.startup_time < nhe->uptime)
3288
0
    return HASHWALK_CONTINUE;
3289
3290
  /*
3291
   * If it's proto-owned and not being used by a route, remove it since
3292
   * we haven't gotten an update about it from the proto since startup.
3293
   * This means that either the config for it was removed or the daemon
3294
   * didn't get started. This handles graceful restart & retain scenario.
3295
   */
3296
0
  if (PROTO_OWNED(nhe) && nhe->refcnt == 1) {
3297
0
    zebra_nhg_decrement_ref(nhe);
3298
0
    return HASHWALK_ABORT;
3299
0
  }
3300
3301
  /*
3302
   * If its being ref'd by routes, just let it be uninstalled via a route
3303
   * removal.
3304
   */
3305
0
  if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0) {
3306
0
    zebra_nhg_uninstall_kernel(nhe);
3307
0
    return HASHWALK_ABORT;
3308
0
  }
3309
3310
0
  return HASHWALK_CONTINUE;
3311
0
}
3312
3313
void zebra_nhg_sweep_table(struct hash *hash)
3314
0
{
3315
0
  uint32_t count;
3316
3317
  /*
3318
   * Yes this is extremely odd.  Effectively nhg's have
3319
   * other nexthop groups that depend on them and when you
3320
   * remove them, you can have other entries blown up.
3321
   * our hash code does not work with deleting multiple
3322
   * entries at a time and will possibly cause crashes
3323
   * So what to do?  Whenever zebra_nhg_sweep_entry
3324
   * deletes an entry it will return HASHWALK_ABORT,
3325
   * cause that deletion might have triggered more.
3326
   * then we can just keep sweeping this table
3327
   * until nothing more is found to do.
3328
   */
3329
0
  do {
3330
0
    count = hashcount(hash);
3331
0
    hash_walk(hash, zebra_nhg_sweep_entry, NULL);
3332
0
  } while (count != hashcount(hash));
3333
0
}
3334
3335
static void zebra_nhg_mark_keep_entry(struct hash_bucket *bucket, void *arg)
3336
0
{
3337
0
  struct nhg_hash_entry *nhe = bucket->data;
3338
3339
0
  UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
3340
0
}
3341
3342
/*
3343
 * When we are shutting down and we have retain mode enabled
3344
 * in zebra the process is to mark each vrf that it's
3345
 * routes should not be deleted.  The problem with that
3346
 * is that shutdown actually free's up memory which
3347
 * causes the nexthop group's ref counts to go to zero
3348
 * we need a way to subtly tell the system to not remove
3349
 * the nexthop groups from the kernel at the same time.
3350
 * The easiest just looks like that we should not mark
3351
 * the nhg's as installed any more and when the ref count
3352
 * goes to zero we'll attempt to delete and do nothing
3353
 */
3354
void zebra_nhg_mark_keep(void)
3355
0
{
3356
0
  hash_iterate(zrouter.nhgs_id, zebra_nhg_mark_keep_entry, NULL);
3357
0
}
3358
3359
/* Global control to disable use of kernel nexthops, if available. We can't
3360
 * force the kernel to support nexthop ids, of course, but we can disable
3361
 * zebra's use of them, for testing e.g. By default, if the kernel supports
3362
 * nexthop ids, zebra uses them.
3363
 */
3364
void zebra_nhg_enable_kernel_nexthops(bool set)
3365
0
{
3366
0
  g_nexthops_enabled = set;
3367
0
}
3368
3369
bool zebra_nhg_kernel_nexthops_enabled(void)
3370
0
{
3371
0
  return g_nexthops_enabled;
3372
0
}
3373
3374
/* Global control for use of activated backups for recursive resolution. */
3375
void zebra_nhg_set_recursive_use_backups(bool set)
3376
0
{
3377
0
  use_recursive_backups = set;
3378
0
}
3379
3380
bool zebra_nhg_recursive_use_backups(void)
3381
0
{
3382
0
  return use_recursive_backups;
3383
0
}
3384
3385
/*
3386
 * Global control to only use kernel nexthops for protocol created NHGs.
3387
 * There are some use cases where you may not want zebra to implicitly
3388
 * create kernel nexthops for all routes and only create them for NHGs
3389
 * passed down by upper level protos.
3390
 *
3391
 * Default is off.
3392
 */
3393
void zebra_nhg_set_proto_nexthops_only(bool set)
3394
0
{
3395
0
  proto_nexthops_only = set;
3396
0
}
3397
3398
bool zebra_nhg_proto_nexthops_only(void)
3399
0
{
3400
0
  return proto_nexthops_only;
3401
0
}
3402
3403
/* Add NHE from upper level proto */
3404
struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
3405
             uint16_t instance, uint32_t session,
3406
             struct nexthop_group *nhg, afi_t afi)
3407
0
{
3408
0
  struct nhg_hash_entry lookup;
3409
0
  struct nhg_hash_entry *new, *old;
3410
0
  struct nhg_connected *rb_node_dep = NULL;
3411
0
  struct nexthop *newhop;
3412
0
  bool replace = false;
3413
0
  int ret = 0;
3414
3415
0
  if (!nhg->nexthop) {
3416
0
    if (IS_ZEBRA_DEBUG_NHG)
3417
0
      zlog_debug("%s: id %u, no nexthops passed to add",
3418
0
           __func__, id);
3419
0
    return NULL;
3420
0
  }
3421
3422
3423
  /* Set nexthop list as active, since they wont go through rib
3424
   * processing.
3425
   *
3426
   * Assuming valid/onlink for now.
3427
   *
3428
   * Once resolution is figured out, we won't need this!
3429
   */
3430
0
  for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
3431
0
    if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
3432
0
      if (IS_ZEBRA_DEBUG_NHG)
3433
0
        zlog_debug(
3434
0
          "%s: id %u, backup nexthops not supported",
3435
0
          __func__, id);
3436
0
      return NULL;
3437
0
    }
3438
3439
0
    if (newhop->type == NEXTHOP_TYPE_BLACKHOLE) {
3440
0
      if (IS_ZEBRA_DEBUG_NHG)
3441
0
        zlog_debug(
3442
0
          "%s: id %u, blackhole nexthop not supported",
3443
0
          __func__, id);
3444
0
      return NULL;
3445
0
    }
3446
3447
0
    if (newhop->type == NEXTHOP_TYPE_IFINDEX) {
3448
0
      if (IS_ZEBRA_DEBUG_NHG)
3449
0
        zlog_debug(
3450
0
          "%s: id %u, nexthop without gateway not supported",
3451
0
          __func__, id);
3452
0
      return NULL;
3453
0
    }
3454
3455
0
    if (!newhop->ifindex) {
3456
0
      if (IS_ZEBRA_DEBUG_NHG)
3457
0
        zlog_debug(
3458
0
          "%s: id %u, nexthop without ifindex is not supported",
3459
0
          __func__, id);
3460
0
      return NULL;
3461
0
    }
3462
0
    SET_FLAG(newhop->flags, NEXTHOP_FLAG_ACTIVE);
3463
0
  }
3464
3465
0
  zebra_nhe_init(&lookup, afi, nhg->nexthop);
3466
0
  lookup.nhg.nexthop = nhg->nexthop;
3467
0
  lookup.nhg.nhgr = nhg->nhgr;
3468
0
  lookup.id = id;
3469
0
  lookup.type = type;
3470
3471
0
  old = zebra_nhg_lookup_id(id);
3472
3473
0
  if (old) {
3474
    /*
3475
     * This is a replace, just release NHE from ID for now, The
3476
     * depends/dependents may still be used in the replacement so
3477
     * we don't touch them other than to remove their refs to their
3478
     * old parent.
3479
     */
3480
0
    replace = true;
3481
0
    hash_release(zrouter.nhgs_id, old);
3482
3483
    /* Free all the things */
3484
0
    zebra_nhg_release_all_deps(old);
3485
0
  }
3486
3487
0
  new = zebra_nhg_rib_find_nhe(&lookup, afi);
3488
3489
0
  zebra_nhg_increment_ref(new);
3490
3491
  /* Capture zapi client info */
3492
0
  new->zapi_instance = instance;
3493
0
  new->zapi_session = session;
3494
3495
0
  zebra_nhg_set_valid_if_active(new);
3496
3497
0
  zebra_nhg_install_kernel(new);
3498
3499
0
  if (old) {
3500
    /*
3501
     * Check to handle recving DEL while routes still in use then
3502
     * a replace.
3503
     *
3504
     * In this case we would have decremented the refcnt already
3505
     * but set the FLAG here. Go ahead and increment once to fix
3506
     * the misordering we have been sent.
3507
     */
3508
0
    if (CHECK_FLAG(old->flags, NEXTHOP_GROUP_PROTO_RELEASED))
3509
0
      zebra_nhg_increment_ref(old);
3510
3511
0
    ret = rib_handle_nhg_replace(old, new);
3512
0
    if (ret)
3513
      /*
3514
       * if ret > 0, some previous re->nhe has freed the
3515
       * address to which old_entry is pointing. Hence mark
3516
       * the old NHE as NULL
3517
       */
3518
0
      old = NULL;
3519
0
    else {
3520
      /* We have to decrement its singletons
3521
       * because some might not exist in NEW.
3522
       */
3523
0
      if (!zebra_nhg_depends_is_empty(old)) {
3524
0
        frr_each (nhg_connected_tree, &old->nhg_depends,
3525
0
            rb_node_dep)
3526
0
          zebra_nhg_decrement_ref(
3527
0
            rb_node_dep->nhe);
3528
0
      }
3529
3530
      /* Dont call the dec API, we dont want to uninstall the ID */
3531
0
      old->refcnt = 0;
3532
0
      EVENT_OFF(old->timer);
3533
0
      zebra_nhg_free(old);
3534
0
      old = NULL;
3535
0
    }
3536
0
  }
3537
3538
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3539
0
    zlog_debug("%s: %s nhe %p (%u), vrf %d, type %s", __func__,
3540
0
         (replace ? "replaced" : "added"), new, new->id,
3541
0
         new->vrf_id, zebra_route_string(new->type));
3542
3543
0
  return new;
3544
0
}
3545
3546
/* Delete NHE from upper level proto, caller must decrement ref */
3547
struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id, int type)
3548
0
{
3549
0
  struct nhg_hash_entry *nhe;
3550
3551
0
  nhe = zebra_nhg_lookup_id(id);
3552
3553
0
  if (!nhe) {
3554
0
    if (IS_ZEBRA_DEBUG_NHG)
3555
0
      zlog_debug("%s: id %u, lookup failed", __func__, id);
3556
3557
0
    return NULL;
3558
0
  }
3559
3560
0
  if (type != nhe->type) {
3561
0
    if (IS_ZEBRA_DEBUG_NHG)
3562
0
      zlog_debug(
3563
0
        "%s: id %u, type %s mismatch, sent by %s, ignoring",
3564
0
        __func__, id, zebra_route_string(nhe->type),
3565
0
        zebra_route_string(type));
3566
0
    return NULL;
3567
0
  }
3568
3569
0
  if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_PROTO_RELEASED)) {
3570
0
    if (IS_ZEBRA_DEBUG_NHG)
3571
0
      zlog_debug("%s: id %u, already released", __func__, id);
3572
3573
0
    return NULL;
3574
0
  }
3575
3576
0
  SET_FLAG(nhe->flags, NEXTHOP_GROUP_PROTO_RELEASED);
3577
3578
0
  if (nhe->refcnt > 1) {
3579
0
    if (IS_ZEBRA_DEBUG_NHG)
3580
0
      zlog_debug(
3581
0
        "%s: %pNG, still being used by routes refcnt %u",
3582
0
        __func__, nhe, nhe->refcnt);
3583
0
    return nhe;
3584
0
  }
3585
3586
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3587
0
    zlog_debug("%s: deleted nhe %p (%pNG), vrf %d, type %s",
3588
0
         __func__, nhe, nhe, nhe->vrf_id,
3589
0
         zebra_route_string(nhe->type));
3590
3591
0
  return nhe;
3592
0
}
3593
3594
struct nhg_score_proto_iter {
3595
  int type;
3596
  struct list *found;
3597
};
3598
3599
static void zebra_nhg_score_proto_entry(struct hash_bucket *bucket, void *arg)
3600
0
{
3601
0
  struct nhg_hash_entry *nhe;
3602
0
  struct nhg_score_proto_iter *iter;
3603
3604
0
  nhe = (struct nhg_hash_entry *)bucket->data;
3605
0
  iter = arg;
3606
3607
  /* Needs to match type and outside zebra ID space */
3608
0
  if (nhe->type == iter->type && PROTO_OWNED(nhe)) {
3609
0
    if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3610
0
      zlog_debug(
3611
0
        "%s: found nhe %p (%pNG), vrf %d, type %s after client disconnect",
3612
0
        __func__, nhe, nhe, nhe->vrf_id,
3613
0
        zebra_route_string(nhe->type));
3614
3615
    /* Add to removal list */
3616
0
    listnode_add(iter->found, nhe);
3617
0
  }
3618
0
}
3619
3620
/* Remove specific by proto NHGs */
3621
unsigned long zebra_nhg_score_proto(int type)
3622
267
{
3623
267
  struct nhg_hash_entry *nhe;
3624
267
  struct nhg_score_proto_iter iter = {};
3625
267
  struct listnode *ln;
3626
267
  unsigned long count;
3627
3628
267
  iter.type = type;
3629
267
  iter.found = list_new();
3630
3631
  /* Find matching entries to remove */
3632
267
  hash_iterate(zrouter.nhgs_id, zebra_nhg_score_proto_entry, &iter);
3633
3634
  /* Now remove them */
3635
267
  for (ALL_LIST_ELEMENTS_RO(iter.found, ln, nhe)) {
3636
    /*
3637
     * This should be the last ref if we remove client routes too,
3638
     * and thus should remove and free them.
3639
     */
3640
0
    zebra_nhg_decrement_ref(nhe);
3641
0
  }
3642
3643
267
  count = iter.found->count;
3644
267
  list_delete(&iter.found);
3645
3646
267
  return count;
3647
267
}
3648
3649
printfrr_ext_autoreg_p("NG", printfrr_nhghe);
3650
static ssize_t printfrr_nhghe(struct fbuf *buf, struct printfrr_eargs *ea,
3651
            const void *ptr)
3652
0
{
3653
0
  const struct nhg_hash_entry *nhe = ptr;
3654
0
  const struct nhg_connected *dep;
3655
0
  ssize_t ret = 0;
3656
3657
0
  if (!nhe)
3658
0
    return bputs(buf, "[NULL]");
3659
3660
0
  ret += bprintfrr(buf, "%u[", nhe->id);
3661
0
  if (nhe->ifp)
3662
0
    ret += printfrr_nhs(buf, nhe->nhg.nexthop);
3663
0
  else {
3664
0
    int count = zebra_nhg_depends_count(nhe);
3665
3666
0
    frr_each (nhg_connected_tree_const, &nhe->nhg_depends, dep) {
3667
0
      ret += bprintfrr(buf, "%u", dep->nhe->id);
3668
0
      if (count > 1)
3669
0
        ret += bputs(buf, "/");
3670
0
      count--;
3671
0
    }
3672
0
  }
3673
3674
0
  ret += bputs(buf, "]");
3675
0
  return ret;
3676
0
}
3677
3678
/*
3679
 * On interface add the nexthop that resolves to this intf needs
3680
 * a re-install. There are following scenarios when the nexthop group update
3681
 * gets skipped:
3682
 * 1. When upper level protocol sends removal of NHG, there is
3683
 * timer running to keep NHG for 180 seconds, during this interval, same route
3684
 * with same set of nexthops installation is given , the same NHG is used
3685
 * but since NHG is not reinstalled on interface address add, it is not aware
3686
 * in Dplan/Kernel.
3687
 * 2. Due to a quick port flap due to interface add and delete
3688
 * to be processed in same queue one after another. Zebra believes that
3689
 * there is no change in nhg in this case. Hence this re-install will
3690
 * make sure the nexthop group gets updated to Dplan/Kernel.
3691
 */
3692
void zebra_interface_nhg_reinstall(struct interface *ifp)
3693
0
{
3694
0
  struct nhg_connected *rb_node_dep = NULL;
3695
0
  struct zebra_if *zif = ifp->info;
3696
0
  struct nexthop *nh;
3697
3698
0
  if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3699
0
    zlog_debug(
3700
0
      "%s: Installing interface %s associated NHGs into kernel",
3701
0
      __func__, ifp->name);
3702
3703
0
  frr_each (nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) {
3704
0
    nh = rb_node_dep->nhe->nhg.nexthop;
3705
0
    if (zebra_nhg_set_valid_if_active(rb_node_dep->nhe)) {
3706
0
      if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3707
0
        zlog_debug(
3708
0
          "%s: Setting the valid flag for nhe %pNG, interface: %s",
3709
0
          __func__, rb_node_dep->nhe, ifp->name);
3710
0
    }
3711
    /* Check for singleton NHG associated to interface */
3712
0
    if (nexthop_is_ifindex_type(nh) &&
3713
0
        zebra_nhg_depends_is_empty(rb_node_dep->nhe)) {
3714
0
      struct nhg_connected *rb_node_dependent;
3715
3716
0
      if (IS_ZEBRA_DEBUG_NHG)
3717
0
        zlog_debug(
3718
0
          "%s install nhe %pNG nh type %u flags 0x%x",
3719
0
          __func__, rb_node_dep->nhe, nh->type,
3720
0
          rb_node_dep->nhe->flags);
3721
0
      zebra_nhg_install_kernel(rb_node_dep->nhe);
3722
3723
      /* mark depedent uninstall, when interface associated
3724
       * singleton is installed, install depedent
3725
       */
3726
0
      frr_each_safe (nhg_connected_tree,
3727
0
               &rb_node_dep->nhe->nhg_dependents,
3728
0
               rb_node_dependent) {
3729
0
        if (IS_ZEBRA_DEBUG_NHG)
3730
0
          zlog_debug(
3731
0
            "%s dependent nhe %pNG unset installed flag",
3732
0
            __func__,
3733
0
            rb_node_dependent->nhe);
3734
0
        UNSET_FLAG(rb_node_dependent->nhe->flags,
3735
0
             NEXTHOP_GROUP_INSTALLED);
3736
0
      }
3737
0
    }
3738
0
  }
3739
0
}