Coverage Report

Created: 2026-01-01 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/lib/plist.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Prefix list functions.
3
 * Copyright (C) 1999 Kunihiro Ishiguro
4
 */
5
6
#include <zebra.h>
7
8
#include "prefix.h"
9
#include "command.h"
10
#include "memory.h"
11
#include "plist.h"
12
#include "sockunion.h"
13
#include "buffer.h"
14
#include "log.h"
15
#include "routemap.h"
16
#include "lib/json.h"
17
#include "libfrr.h"
18
19
#include <typesafe.h>
20
#include "plist_int.h"
21
22
8
DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST, "Prefix List");
23
8
DEFINE_MTYPE_STATIC(LIB, MPREFIX_LIST_STR, "Prefix List Str");
24
8
DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_ENTRY, "Prefix List Entry");
25
8
DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table");
26
8
27
8
/* not currently changeable, code assumes bytes further down */
28
254k
#define PLC_BITS  8
29
211k
#define PLC_LEN   (1 << PLC_BITS)
30
#define PLC_MAXLEVELV4  2 /* /24 for IPv4 */
31
#define PLC_MAXLEVELV6  4 /* /48 for IPv6 */
32
#define PLC_MAXLEVEL  4 /* max(v4,v6) */
33
34
struct pltrie_entry {
35
  union {
36
    struct pltrie_table *next_table;
37
    struct prefix_list_entry *final_chain;
38
  };
39
40
  struct prefix_list_entry *up_chain;
41
};
42
43
struct pltrie_table {
44
  struct pltrie_entry entries[PLC_LEN];
45
};
46
47
/* Master structure of prefix_list. */
48
struct prefix_master {
49
  /* The latest update. */
50
  struct prefix_list *recent;
51
52
  /* Hook function which is executed when new prefix_list is added. */
53
  void (*add_hook)(struct prefix_list *);
54
55
  /* Hook function which is executed when prefix_list is deleted. */
56
  void (*delete_hook)(struct prefix_list *);
57
58
  /* number of bytes that have a trie level */
59
  size_t trie_depth;
60
61
  struct plist_head str;
62
};
63
static int prefix_list_compare_func(const struct prefix_list *a,
64
            const struct prefix_list *b);
65
5.51k
DECLARE_RBTREE_UNIQ(plist, struct prefix_list, plist_item,
plist.c:plist_const_find
Line
Count
Source
65
DECLARE_RBTREE_UNIQ(plist, struct prefix_list, plist_item,
plist.c:plist_add
Line
Count
Source
65
DECLARE_RBTREE_UNIQ(plist, struct prefix_list, plist_item,
Unexecuted instantiation: plist.c:plist_del
66
        prefix_list_compare_func);
67
68
/* Static structure of IPv4 prefix_list's master. */
69
static struct prefix_master prefix_master_ipv4 = {
70
  NULL, NULL, NULL, PLC_MAXLEVELV4,
71
};
72
73
/* Static structure of IPv6 prefix-list's master. */
74
static struct prefix_master prefix_master_ipv6 = {
75
  NULL, NULL, NULL, PLC_MAXLEVELV6,
76
};
77
78
/* Static structure of BGP ORF prefix_list's master. */
79
static struct prefix_master prefix_master_orf_v4 = {
80
  NULL, NULL, NULL, PLC_MAXLEVELV4,
81
};
82
83
/* Static structure of BGP ORF prefix_list's master. */
84
static struct prefix_master prefix_master_orf_v6 = {
85
  NULL, NULL, NULL, PLC_MAXLEVELV6,
86
};
87
88
static struct prefix_master *prefix_master_get(afi_t afi, int orf)
89
6.79k
{
90
6.79k
  if (afi == AFI_IP)
91
2.39k
    return orf ? &prefix_master_orf_v4 : &prefix_master_ipv4;
92
4.39k
  if (afi == AFI_IP6)
93
3.94k
    return orf ? &prefix_master_orf_v6 : &prefix_master_ipv6;
94
452
  return NULL;
95
4.39k
}
96
97
const char *prefix_list_name(struct prefix_list *plist)
98
0
{
99
0
  return plist->name;
100
0
}
101
102
afi_t prefix_list_afi(struct prefix_list *plist)
103
0
{
104
0
  if (plist->master == &prefix_master_ipv4
105
0
      || plist->master == &prefix_master_orf_v4)
106
0
    return AFI_IP;
107
0
  return AFI_IP6;
108
0
}
109
110
static int prefix_list_compare_func(const struct prefix_list *a,
111
            const struct prefix_list *b)
112
3.29k
{
113
3.29k
  return strcmp(a->name, b->name);
114
3.29k
}
115
116
/* Lookup prefix_list from list of prefix_list by name. */
117
static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf,
118
             const char *name)
119
5.86k
{
120
5.86k
  struct prefix_list *plist, lookup;
121
5.86k
  struct prefix_master *master;
122
123
5.86k
  if (name == NULL)
124
0
    return NULL;
125
126
5.86k
  master = prefix_master_get(afi, orf);
127
5.86k
  if (master == NULL)
128
349
    return NULL;
129
130
5.51k
  lookup.name = XSTRDUP(MTYPE_TMP, name);
131
5.51k
  plist = plist_find(&master->str, &lookup);
132
5.51k
  XFREE(MTYPE_TMP, lookup.name);
133
5.51k
  return plist;
134
5.86k
}
135
136
struct prefix_list *prefix_list_lookup(afi_t afi, const char *name)
137
0
{
138
0
  return prefix_list_lookup_do(afi, 0, name);
139
0
}
140
141
struct prefix_list *prefix_bgp_orf_lookup(afi_t afi, const char *name)
142
2.61k
{
143
2.61k
  return prefix_list_lookup_do(afi, 1, name);
144
2.61k
}
145
146
static struct prefix_list *prefix_list_new(void)
147
830
{
148
830
  struct prefix_list *new;
149
150
830
  new = XCALLOC(MTYPE_PREFIX_LIST, sizeof(struct prefix_list));
151
830
  return new;
152
830
}
153
154
static void prefix_list_free(struct prefix_list *plist)
155
829
{
156
829
  XFREE(MTYPE_PREFIX_LIST, plist);
157
829
}
158
159
struct prefix_list_entry *prefix_list_entry_new(void)
160
3.03k
{
161
3.03k
  struct prefix_list_entry *new;
162
163
3.03k
  new = XCALLOC(MTYPE_PREFIX_LIST_ENTRY,
164
3.03k
          sizeof(struct prefix_list_entry));
165
3.03k
  return new;
166
3.03k
}
167
168
void prefix_list_entry_free(struct prefix_list_entry *pentry)
169
3.03k
{
170
3.03k
  XFREE(MTYPE_PREFIX_LIST_ENTRY, pentry);
171
3.03k
}
172
173
/* Insert new prefix list to list of prefix_list.  Each prefix_list
174
   is sorted by the name. */
175
static struct prefix_list *prefix_list_insert(afi_t afi, int orf,
176
                const char *name)
177
933
{
178
933
  struct prefix_list *plist;
179
933
  struct prefix_master *master;
180
181
933
  master = prefix_master_get(afi, orf);
182
933
  if (master == NULL)
183
103
    return NULL;
184
185
  /* Allocate new prefix_list and copy given name. */
186
830
  plist = prefix_list_new();
187
830
  plist->name = XSTRDUP(MTYPE_MPREFIX_LIST_STR, name);
188
830
  plist->master = master;
189
830
  plist->trie =
190
830
    XCALLOC(MTYPE_PREFIX_LIST_TRIE, sizeof(struct pltrie_table));
191
192
830
  plist_add(&master->str, plist);
193
194
830
  return plist;
195
933
}
196
197
struct prefix_list *prefix_list_get(afi_t afi, int orf, const char *name)
198
3.24k
{
199
3.24k
  struct prefix_list *plist;
200
201
3.24k
  plist = prefix_list_lookup_do(afi, orf, name);
202
203
3.24k
  if (plist == NULL)
204
933
    plist = prefix_list_insert(afi, orf, name);
205
3.24k
  return plist;
206
3.24k
}
207
208
static void prefix_list_trie_del(struct prefix_list *plist,
209
         struct prefix_list_entry *pentry);
210
211
/* Delete prefix-list from prefix_list_master and free it. */
212
void prefix_list_delete(struct prefix_list *plist)
213
829
{
214
829
  struct prefix_master *master;
215
829
  struct prefix_list_entry *pentry;
216
829
  struct prefix_list_entry *next;
217
218
  /* If prefix-list contain prefix_list_entry free all of it. */
219
2.37k
  for (pentry = plist->head; pentry; pentry = next) {
220
1.54k
    route_map_notify_pentry_dependencies(plist->name, pentry,
221
1.54k
                 RMAP_EVENT_PLIST_DELETED);
222
1.54k
    next = pentry->next;
223
1.54k
    prefix_list_trie_del(plist, pentry);
224
1.54k
    prefix_list_entry_free(pentry);
225
1.54k
    plist->count--;
226
1.54k
  }
227
228
829
  master = plist->master;
229
230
829
  plist_del(&master->str, plist);
231
232
829
  XFREE(MTYPE_TMP, plist->desc);
233
234
  /* Make sure master's recent changed prefix-list information is
235
     cleared. */
236
829
  master->recent = NULL;
237
238
829
  route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
239
240
829
  if (master->delete_hook)
241
0
    (*master->delete_hook)(plist);
242
243
829
  XFREE(MTYPE_MPREFIX_LIST_STR, plist->name);
244
245
829
  XFREE(MTYPE_PREFIX_LIST_TRIE, plist->trie);
246
247
829
  prefix_list_free(plist);
248
829
}
249
250
static struct prefix_list_entry *
251
prefix_list_entry_make(struct prefix *prefix, enum prefix_list_type type,
252
           int64_t seq, int le, int ge, bool any)
253
3.03k
{
254
3.03k
  struct prefix_list_entry *pentry;
255
256
3.03k
  pentry = prefix_list_entry_new();
257
258
3.03k
  if (any)
259
0
    pentry->any = true;
260
261
3.03k
  prefix_copy(&pentry->prefix, prefix);
262
3.03k
  pentry->type = type;
263
3.03k
  pentry->seq = seq;
264
3.03k
  pentry->le = le;
265
3.03k
  pentry->ge = ge;
266
267
3.03k
  return pentry;
268
3.03k
}
269
270
/* Add hook function. */
271
void prefix_list_add_hook(void (*func)(struct prefix_list *plist))
272
3
{
273
3
  prefix_master_ipv4.add_hook = func;
274
3
  prefix_master_ipv6.add_hook = func;
275
3
}
276
277
/* Delete hook function. */
278
void prefix_list_delete_hook(void (*func)(struct prefix_list *plist))
279
3
{
280
3
  prefix_master_ipv4.delete_hook = func;
281
3
  prefix_master_ipv6.delete_hook = func;
282
3
}
283
284
/* Calculate new sequential number. */
285
int64_t prefix_new_seq_get(struct prefix_list *plist)
286
0
{
287
0
  int64_t maxseq;
288
0
  int64_t newseq;
289
0
  struct prefix_list_entry *pentry;
290
291
0
  maxseq = 0;
292
293
0
  for (pentry = plist->head; pentry; pentry = pentry->next) {
294
0
    if (maxseq < pentry->seq)
295
0
      maxseq = pentry->seq;
296
0
  }
297
298
0
  newseq = ((maxseq / 5) * 5) + 5;
299
300
0
  return (newseq > UINT_MAX) ? UINT_MAX : newseq;
301
0
}
302
303
/* Return prefix list entry which has same seq number. */
304
static struct prefix_list_entry *prefix_seq_check(struct prefix_list *plist,
305
              int64_t seq)
306
2.85k
{
307
2.85k
  struct prefix_list_entry *pentry;
308
309
11.0k
  for (pentry = plist->head; pentry; pentry = pentry->next)
310
9.58k
    if (pentry->seq == seq)
311
1.38k
      return pentry;
312
1.46k
  return NULL;
313
2.85k
}
314
315
struct prefix_list_entry *
316
prefix_list_entry_lookup(struct prefix_list *plist, struct prefix *prefix,
317
       enum prefix_list_type type, int64_t seq,
318
       int le, int ge)
319
104
{
320
104
  struct prefix_list_entry *pentry;
321
322
361
  for (pentry = plist->head; pentry; pentry = pentry->next)
323
315
    if (prefix_same(&pentry->prefix, prefix)
324
184
        && pentry->type == type) {
325
139
      if (seq >= 0 && pentry->seq != seq)
326
55
        continue;
327
328
84
      if (pentry->le != le)
329
9
        continue;
330
75
      if (pentry->ge != ge)
331
17
        continue;
332
333
58
      return pentry;
334
75
    }
335
336
46
  return NULL;
337
104
}
338
339
static bool
340
prefix_list_entry_lookup_prefix(struct prefix_list *plist,
341
        struct prefix_list_entry *plist_entry)
342
1.44k
{
343
1.44k
  struct prefix_list_entry *pentry = NULL;
344
345
5.25k
  for (pentry = plist->head; pentry; pentry = pentry->next) {
346
4.85k
    if (pentry == plist_entry)
347
1.16k
      continue;
348
3.69k
    if (prefix_same(&pentry->prefix, &plist_entry->prefix))
349
1.04k
      return true;
350
3.69k
  }
351
352
399
  return false;
353
1.44k
}
354
355
static void trie_walk_affected(size_t validbits, struct pltrie_table *table,
356
             uint8_t byte, struct prefix_list_entry *object,
357
             void (*fn)(struct prefix_list_entry *object,
358
            struct prefix_list_entry **updptr))
359
5.99k
{
360
5.99k
  uint8_t mask;
361
5.99k
  uint16_t bwalk;
362
363
5.99k
  if (validbits > PLC_BITS) {
364
1.23k
    fn(object, &table->entries[byte].final_chain);
365
1.23k
    return;
366
1.23k
  }
367
368
4.75k
  mask = (1 << (8 - validbits)) - 1;
369
1.02M
  for (bwalk = byte & ~mask; bwalk <= byte + mask; bwalk++) {
370
1.01M
    fn(object, &table->entries[bwalk].up_chain);
371
1.01M
  }
372
4.75k
}
373
374
static void trie_uninstall_fn(struct prefix_list_entry *object,
375
            struct prefix_list_entry **updptr)
376
510k
{
377
784k
  for (; *updptr; updptr = &(*updptr)->next_best)
378
747k
    if (*updptr == object) {
379
473k
      *updptr = object->next_best;
380
473k
      break;
381
473k
    }
382
510k
}
383
384
static int trie_table_empty(struct pltrie_table *table)
385
1.99k
{
386
1.99k
  size_t i;
387
211k
  for (i = 0; i < PLC_LEN; i++)
388
210k
    if (table->entries[i].next_table || table->entries[i].up_chain)
389
1.35k
      return 0;
390
637
  return 1;
391
1.99k
}
392
393
static void prefix_list_trie_del(struct prefix_list *plist,
394
         struct prefix_list_entry *pentry)
395
2.99k
{
396
2.99k
  size_t depth, maxdepth = plist->master->trie_depth;
397
2.99k
  uint8_t *bytes = pentry->prefix.u.val;
398
2.99k
  size_t validbits = pentry->prefix.prefixlen;
399
2.99k
  struct pltrie_table *table, **tables[PLC_MAXLEVEL];
400
401
2.99k
  table = plist->trie;
402
4.98k
  for (depth = 0; validbits > PLC_BITS && depth < maxdepth - 1; depth++) {
403
1.99k
    uint8_t byte = bytes[depth];
404
1.99k
    assert(table->entries[byte].next_table);
405
406
1.99k
    tables[depth + 1] = &table->entries[byte].next_table;
407
1.99k
    table = table->entries[byte].next_table;
408
409
1.99k
    validbits -= PLC_BITS;
410
1.99k
  }
411
412
2.99k
  trie_walk_affected(validbits, table, bytes[depth], pentry,
413
2.99k
         trie_uninstall_fn);
414
415
4.98k
  for (; depth > 0; depth--)
416
1.99k
    if (trie_table_empty(*tables[depth])) {
417
637
      XFREE(MTYPE_PREFIX_LIST_TRIE, *tables[depth]);
418
637
    }
419
2.99k
}
420
421
422
void prefix_list_entry_delete(struct prefix_list *plist,
423
            struct prefix_list_entry *pentry, int update_list)
424
1.44k
{
425
1.44k
  bool duplicate = false;
426
427
1.44k
  if (plist == NULL || pentry == NULL)
428
0
    return;
429
430
1.44k
  if (prefix_list_entry_lookup_prefix(plist, pentry))
431
1.04k
    duplicate = true;
432
433
1.44k
  prefix_list_trie_del(plist, pentry);
434
435
1.44k
  if (pentry->prev)
436
612
    pentry->prev->next = pentry->next;
437
835
  else
438
835
    plist->head = pentry->next;
439
1.44k
  if (pentry->next)
440
1.19k
    pentry->next->prev = pentry->prev;
441
255
  else
442
255
    plist->tail = pentry->prev;
443
444
1.44k
  if (!duplicate)
445
399
    route_map_notify_pentry_dependencies(plist->name, pentry,
446
399
                 RMAP_EVENT_PLIST_DELETED);
447
448
1.44k
  prefix_list_entry_free(pentry);
449
450
1.44k
  plist->count--;
451
452
1.44k
  if (update_list) {
453
58
    route_map_notify_dependencies(plist->name,
454
58
                RMAP_EVENT_PLIST_DELETED);
455
58
    if (plist->master->delete_hook)
456
0
      (*plist->master->delete_hook)(plist);
457
458
58
    if (plist->head == NULL && plist->tail == NULL
459
14
        && plist->desc == NULL)
460
14
      prefix_list_delete(plist);
461
44
    else
462
44
      plist->master->recent = plist;
463
58
  }
464
1.44k
}
465
466
static void trie_install_fn(struct prefix_list_entry *object,
467
          struct prefix_list_entry **updptr)
468
510k
{
469
790k
  while (*updptr) {
470
557k
    if (*updptr == object)
471
82.0k
      return;
472
475k
    if ((*updptr)->prefix.prefixlen < object->prefix.prefixlen)
473
1.68k
      break;
474
473k
    if ((*updptr)->prefix.prefixlen == object->prefix.prefixlen
475
451k
        && (*updptr)->seq > object->seq)
476
193k
      break;
477
279k
    updptr = &(*updptr)->next_best;
478
279k
  }
479
480
428k
  if (!object->next_best)
481
234k
    object->next_best = *updptr;
482
193k
  else
483
193k
    assert(object->next_best == *updptr || !*updptr);
484
485
428k
  *updptr = object;
486
428k
}
487
488
static void prefix_list_trie_add(struct prefix_list *plist,
489
         struct prefix_list_entry *pentry)
490
2.99k
{
491
2.99k
  size_t depth = plist->master->trie_depth;
492
2.99k
  uint8_t *bytes = pentry->prefix.u.val;
493
2.99k
  size_t validbits = pentry->prefix.prefixlen;
494
2.99k
  struct pltrie_table *table;
495
496
2.99k
  table = plist->trie;
497
4.99k
  while (validbits > PLC_BITS && depth > 1) {
498
1.99k
    if (!table->entries[*bytes].next_table)
499
638
      table->entries[*bytes].next_table =
500
638
        XCALLOC(MTYPE_PREFIX_LIST_TRIE,
501
1.99k
          sizeof(struct pltrie_table));
502
1.99k
    table = table->entries[*bytes].next_table;
503
1.99k
    bytes++;
504
1.99k
    depth--;
505
1.99k
    validbits -= PLC_BITS;
506
1.99k
  }
507
508
2.99k
  trie_walk_affected(validbits, table, *bytes, pentry, trie_install_fn);
509
2.99k
}
510
511
static void prefix_list_entry_add(struct prefix_list *plist,
512
          struct prefix_list_entry *pentry)
513
2.99k
{
514
2.99k
  struct prefix_list_entry *replace;
515
2.99k
  struct prefix_list_entry *point;
516
517
  /* Automatic asignment of seq no. */
518
2.99k
  if (pentry->seq == -1)
519
0
    pentry->seq = prefix_new_seq_get(plist);
520
521
2.99k
  if (plist->tail && pentry->seq > plist->tail->seq)
522
139
    point = NULL;
523
2.85k
  else {
524
    /* Is there any same seq prefix list entry? */
525
2.85k
    replace = prefix_seq_check(plist, pentry->seq);
526
2.85k
    if (replace)
527
1.38k
      prefix_list_entry_delete(plist, replace, 0);
528
529
    /* Check insert point. */
530
8.22k
    for (point = plist->head; point; point = point->next)
531
7.15k
      if (point->seq >= pentry->seq)
532
1.79k
        break;
533
2.85k
  }
534
535
  /* In case of this is the first element of the list. */
536
2.99k
  pentry->next = point;
537
538
2.99k
  if (point) {
539
1.79k
    if (point->prev)
540
859
      point->prev->next = pentry;
541
935
    else
542
935
      plist->head = pentry;
543
544
1.79k
    pentry->prev = point->prev;
545
1.79k
    point->prev = pentry;
546
1.79k
  } else {
547
1.20k
    if (plist->tail)
548
317
      plist->tail->next = pentry;
549
886
    else
550
886
      plist->head = pentry;
551
552
1.20k
    pentry->prev = plist->tail;
553
1.20k
    plist->tail = pentry;
554
1.20k
  }
555
556
2.99k
  prefix_list_trie_add(plist, pentry);
557
558
  /* Increment count. */
559
2.99k
  plist->count++;
560
561
2.99k
  route_map_notify_pentry_dependencies(plist->name, pentry,
562
2.99k
               RMAP_EVENT_PLIST_ADDED);
563
564
  /* Run hook function. */
565
2.99k
  if (plist->master->add_hook)
566
0
    (*plist->master->add_hook)(plist);
567
568
2.99k
  route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_ADDED);
569
2.99k
  plist->master->recent = plist;
570
2.99k
}
571
572
/**
573
 * Prefix list entry update start procedure:
574
 * Remove entry from previosly installed master list, tries and notify
575
 * observers.
576
 *
577
 * \param[in] ple prefix list entry.
578
 */
579
void prefix_list_entry_update_start(struct prefix_list_entry *ple)
580
0
{
581
0
  struct prefix_list *pl = ple->pl;
582
0
  bool duplicate = false;
583
584
  /* Not installed, nothing to do. */
585
0
  if (!ple->installed)
586
0
    return;
587
588
0
  if (prefix_list_entry_lookup_prefix(pl, ple))
589
0
    duplicate = true;
590
591
0
  prefix_list_trie_del(pl, ple);
592
593
  /* List manipulation: shameless copy from `prefix_list_entry_delete`. */
594
0
  if (ple->prev)
595
0
    ple->prev->next = ple->next;
596
0
  else
597
0
    pl->head = ple->next;
598
0
  if (ple->next)
599
0
    ple->next->prev = ple->prev;
600
0
  else
601
0
    pl->tail = ple->prev;
602
603
0
  if (!duplicate)
604
0
    route_map_notify_pentry_dependencies(pl->name, ple,
605
0
                 RMAP_EVENT_PLIST_DELETED);
606
0
  pl->count--;
607
608
0
  route_map_notify_dependencies(pl->name, RMAP_EVENT_PLIST_DELETED);
609
0
  if (pl->master->delete_hook)
610
0
    (*pl->master->delete_hook)(pl);
611
612
0
  if (pl->head || pl->tail || pl->desc)
613
0
    pl->master->recent = pl;
614
615
0
  ple->next_best = NULL;
616
0
  ple->installed = false;
617
0
}
618
619
/**
620
 * Prefix list entry update finish procedure:
621
 * Add entry back master list, to the trie, notify observers and call master
622
 * hook.
623
 *
624
 * \param[in] ple prefix list entry.
625
 */
626
void prefix_list_entry_update_finish(struct prefix_list_entry *ple)
627
0
{
628
0
  struct prefix_list *pl = ple->pl;
629
0
  struct prefix_list_entry *point;
630
631
  /* Already installed, nothing to do. */
632
0
  if (ple->installed)
633
0
    return;
634
635
  /*
636
   * Check if the entry is installable:
637
   * We can only install entry if at least the prefix is provided (IPv4
638
   * or IPv6).
639
   */
640
0
  if (ple->prefix.family != AF_INET && ple->prefix.family != AF_INET6)
641
0
    return;
642
643
  /* List manipulation: shameless copy from `prefix_list_entry_add`. */
644
0
  if (pl->tail && ple->seq > pl->tail->seq)
645
0
    point = NULL;
646
0
  else {
647
    /* Check insert point. */
648
0
    for (point = pl->head; point; point = point->next)
649
0
      if (point->seq >= ple->seq)
650
0
        break;
651
0
  }
652
653
  /* In case of this is the first element of the list. */
654
0
  ple->next = point;
655
656
0
  if (point) {
657
0
    if (point->prev)
658
0
      point->prev->next = ple;
659
0
    else
660
0
      pl->head = ple;
661
662
0
    ple->prev = point->prev;
663
0
    point->prev = ple;
664
0
  } else {
665
0
    if (pl->tail)
666
0
      pl->tail->next = ple;
667
0
    else
668
0
      pl->head = ple;
669
670
0
    ple->prev = pl->tail;
671
0
    pl->tail = ple;
672
0
  }
673
674
0
  prefix_list_trie_add(pl, ple);
675
0
  pl->count++;
676
677
0
  route_map_notify_pentry_dependencies(pl->name, ple,
678
0
               RMAP_EVENT_PLIST_ADDED);
679
680
  /* Run hook function. */
681
0
  if (pl->master->add_hook)
682
0
    (*pl->master->add_hook)(pl);
683
684
0
  route_map_notify_dependencies(pl->name, RMAP_EVENT_PLIST_ADDED);
685
0
  pl->master->recent = pl;
686
687
0
  ple->installed = true;
688
0
}
689
690
/**
691
 * Same as `prefix_list_entry_delete` but without `free()`ing the list if its
692
 * empty.
693
 *
694
 * \param[in] ple prefix list entry.
695
 */
696
void prefix_list_entry_delete2(struct prefix_list_entry *ple)
697
0
{
698
  /* Does the boiler plate list removal and entry removal notification. */
699
0
  prefix_list_entry_update_start(ple);
700
701
  /* Effective `free()` memory. */
702
0
  prefix_list_entry_free(ple);
703
0
}
704
705
/* Return string of prefix_list_type. */
706
static const char *prefix_list_type_str(struct prefix_list_entry *pentry)
707
0
{
708
0
  switch (pentry->type) {
709
0
  case PREFIX_PERMIT:
710
0
    return "permit";
711
0
  case PREFIX_DENY:
712
0
    return "deny";
713
0
  default:
714
0
    return "";
715
0
  }
716
0
}
717
718
static int prefix_list_entry_match(struct prefix_list_entry *pentry,
719
           const struct prefix *p, bool address_mode)
720
0
{
721
0
  int ret;
722
723
0
  if (pentry->prefix.family != p->family)
724
0
    return 0;
725
726
0
  ret = prefix_match(&pentry->prefix, p);
727
0
  if (!ret)
728
0
    return 0;
729
730
0
  if (address_mode)
731
0
    return 1;
732
733
  /* In case of le nor ge is specified, exact match is performed. */
734
0
  if (!pentry->le && !pentry->ge) {
735
0
    if (pentry->prefix.prefixlen != p->prefixlen)
736
0
      return 0;
737
0
  } else {
738
0
    if (pentry->le)
739
0
      if (p->prefixlen > pentry->le)
740
0
        return 0;
741
742
0
    if (pentry->ge)
743
0
      if (p->prefixlen < pentry->ge)
744
0
        return 0;
745
0
  }
746
0
  return 1;
747
0
}
748
749
enum prefix_list_type prefix_list_apply_ext(
750
  struct prefix_list *plist,
751
  const struct prefix_list_entry **which,
752
  union prefixconstptr object,
753
  bool address_mode)
754
0
{
755
0
  struct prefix_list_entry *pentry, *pbest = NULL;
756
757
0
  const struct prefix *p = object.p;
758
0
  const uint8_t *byte = p->u.val;
759
0
  size_t depth;
760
0
  size_t validbits = p->prefixlen;
761
0
  struct pltrie_table *table;
762
763
0
  if (plist == NULL) {
764
0
    if (which)
765
0
      *which = NULL;
766
0
    return PREFIX_DENY;
767
0
  }
768
769
0
  if (plist->count == 0) {
770
0
    if (which)
771
0
      *which = NULL;
772
0
    return PREFIX_PERMIT;
773
0
  }
774
775
0
  depth = plist->master->trie_depth;
776
0
  table = plist->trie;
777
0
  while (1) {
778
0
    for (pentry = table->entries[*byte].up_chain; pentry;
779
0
         pentry = pentry->next_best) {
780
0
      if (pbest && pbest->seq < pentry->seq)
781
0
        continue;
782
0
      if (prefix_list_entry_match(pentry, p, address_mode))
783
0
        pbest = pentry;
784
0
    }
785
786
0
    if (validbits <= PLC_BITS)
787
0
      break;
788
0
    validbits -= PLC_BITS;
789
790
0
    if (--depth) {
791
0
      if (!table->entries[*byte].next_table)
792
0
        break;
793
794
0
      table = table->entries[*byte].next_table;
795
0
      byte++;
796
0
      continue;
797
0
    }
798
799
0
    for (pentry = table->entries[*byte].final_chain; pentry;
800
0
         pentry = pentry->next_best) {
801
0
      if (pbest && pbest->seq < pentry->seq)
802
0
        continue;
803
0
      if (prefix_list_entry_match(pentry, p, address_mode))
804
0
        pbest = pentry;
805
0
    }
806
0
    break;
807
0
  }
808
809
0
  if (which) {
810
0
    if (pbest)
811
0
      *which = pbest;
812
0
    else
813
0
      *which = NULL;
814
0
  }
815
816
0
  if (pbest == NULL)
817
0
    return PREFIX_DENY;
818
819
0
  pbest->hitcnt++;
820
0
  return pbest->type;
821
0
}
822
823
static void __attribute__((unused)) prefix_list_print(struct prefix_list *plist)
824
0
{
825
0
  struct prefix_list_entry *pentry;
826
0
827
0
  if (plist == NULL)
828
0
    return;
829
0
830
0
  printf("ip prefix-list %s: %d entries\n", plist->name, plist->count);
831
0
832
0
  for (pentry = plist->head; pentry; pentry = pentry->next) {
833
0
    if (pentry->any)
834
0
      printf("any %s\n", prefix_list_type_str(pentry));
835
0
    else {
836
0
      struct prefix *p;
837
0
838
0
      p = &pentry->prefix;
839
0
840
0
      printf("  seq %lld %s %pFX", (long long)pentry->seq,
841
0
             prefix_list_type_str(pentry), p);
842
0
      if (pentry->ge)
843
0
        printf(" ge %d", pentry->ge);
844
0
      if (pentry->le)
845
0
        printf(" le %d", pentry->le);
846
0
      printf("\n");
847
0
    }
848
0
  }
849
0
}
850
851
/* Return 1 when plist already include pentry policy. */
852
static struct prefix_list_entry *
853
prefix_entry_dup_check(struct prefix_list *plist, struct prefix_list_entry *new)
854
3.03k
{
855
3.03k
  size_t depth, maxdepth = plist->master->trie_depth;
856
3.03k
  uint8_t byte, *bytes = new->prefix.u.val;
857
3.03k
  size_t validbits = new->prefix.prefixlen;
858
3.03k
  struct pltrie_table *table;
859
3.03k
  struct prefix_list_entry *pentry;
860
3.03k
  int64_t seq = 0;
861
862
3.03k
  if (new->seq == -1)
863
0
    seq = prefix_new_seq_get(plist);
864
3.03k
  else
865
3.03k
    seq = new->seq;
866
867
3.03k
  table = plist->trie;
868
4.49k
  for (depth = 0; validbits > PLC_BITS && depth < maxdepth - 1; depth++) {
869
1.74k
    byte = bytes[depth];
870
1.74k
    if (!table->entries[byte].next_table)
871
292
      return NULL;
872
873
1.45k
    table = table->entries[byte].next_table;
874
1.45k
    validbits -= PLC_BITS;
875
1.45k
  }
876
877
2.74k
  byte = bytes[depth];
878
2.74k
  if (validbits > PLC_BITS)
879
477
    pentry = table->entries[byte].final_chain;
880
2.27k
  else
881
2.27k
    pentry = table->entries[byte].up_chain;
882
883
12.2k
  for (; pentry; pentry = pentry->next_best) {
884
9.56k
    if (prefix_same(&pentry->prefix, &new->prefix)
885
8.00k
        && pentry->type == new->type && pentry->le == new->le
886
2.38k
        && pentry->ge == new->ge && pentry->seq != seq)
887
42
      return pentry;
888
9.56k
  }
889
2.70k
  return NULL;
890
2.74k
}
891
892
enum display_type {
893
  normal_display,
894
  summary_display,
895
  detail_display,
896
  sequential_display,
897
  longer_display,
898
  first_match_display
899
};
900
901
static void vty_show_prefix_entry(struct vty *vty, json_object *json, afi_t afi,
902
          struct prefix_list *plist,
903
          struct prefix_master *master,
904
          enum display_type dtype, int seqnum)
905
0
{
906
0
  struct prefix_list_entry *pentry;
907
0
  json_object *json_pl = NULL;
908
909
  /* Print the name of the protocol */
910
0
  if (json) {
911
0
    json_pl = json_object_new_object();
912
0
    json_object_object_add(json, plist->name, json_pl);
913
0
  } else
914
0
    vty_out(vty, "%s: ", frr_protoname);
915
916
0
  if (dtype == normal_display) {
917
0
    if (json) {
918
0
      json_object_string_add(json_pl, "addressFamily",
919
0
                 afi2str(afi));
920
0
      json_object_int_add(json_pl, "entries", plist->count);
921
0
      if (plist->desc)
922
0
        json_object_string_add(json_pl, "description",
923
0
                   plist->desc);
924
0
    } else {
925
0
      vty_out(vty, "ip%s prefix-list %s: %d entries\n",
926
0
        afi == AFI_IP ? "" : "v6", plist->name,
927
0
        plist->count);
928
0
      if (plist->desc)
929
0
        vty_out(vty, "   Description: %s\n",
930
0
          plist->desc);
931
0
    }
932
0
  } else if (dtype == summary_display || dtype == detail_display) {
933
0
    if (json) {
934
0
      json_object_string_add(json_pl, "addressFamily",
935
0
                 afi2str(afi));
936
0
      if (plist->desc)
937
0
        json_object_string_add(json_pl, "description",
938
0
                   plist->desc);
939
0
      json_object_int_add(json_pl, "count", plist->count);
940
0
      json_object_int_add(json_pl, "rangeEntries",
941
0
              plist->rangecount);
942
0
      json_object_int_add(json_pl, "sequenceStart",
943
0
              plist->head ? plist->head->seq : 0);
944
0
      json_object_int_add(json_pl, "sequenceEnd",
945
0
              plist->tail ? plist->tail->seq : 0);
946
0
    } else {
947
0
      vty_out(vty, "ip%s prefix-list %s:\n",
948
0
        afi == AFI_IP ? "" : "v6", plist->name);
949
950
0
      if (plist->desc)
951
0
        vty_out(vty, "   Description: %s\n",
952
0
          plist->desc);
953
954
0
      vty_out(vty,
955
0
        "   count: %d, range entries: %d, sequences: %" PRId64
956
0
        " - %" PRId64 "\n",
957
0
        plist->count, plist->rangecount,
958
0
        plist->head ? plist->head->seq : 0,
959
0
        plist->tail ? plist->tail->seq : 0);
960
0
    }
961
0
  }
962
963
0
  if (dtype != summary_display) {
964
0
    json_object *json_entries = NULL;
965
966
0
    if (json) {
967
0
      json_entries = json_object_new_array();
968
0
      json_object_object_add(json_pl, "entries",
969
0
                 json_entries);
970
0
    }
971
972
0
    for (pentry = plist->head; pentry; pentry = pentry->next) {
973
0
      if (dtype == sequential_display
974
0
          && pentry->seq != seqnum)
975
0
        continue;
976
977
0
      if (json) {
978
0
        json_object *json_entry;
979
980
0
        json_entry = json_object_new_object();
981
0
        json_object_array_add(json_entries, json_entry);
982
983
0
        json_object_int_add(json_entry,
984
0
                "sequenceNumber",
985
0
                pentry->seq);
986
0
        json_object_string_add(
987
0
          json_entry, "type",
988
0
          prefix_list_type_str(pentry));
989
0
        json_object_string_addf(json_entry, "prefix",
990
0
              "%pFX",
991
0
              &pentry->prefix);
992
993
0
        if (pentry->ge)
994
0
          json_object_int_add(
995
0
            json_entry,
996
0
            "minimumPrefixLength",
997
0
            pentry->ge);
998
0
        if (pentry->le)
999
0
          json_object_int_add(
1000
0
            json_entry,
1001
0
            "maximumPrefixLength",
1002
0
            pentry->le);
1003
1004
0
        if (dtype == detail_display
1005
0
            || dtype == sequential_display) {
1006
0
          json_object_int_add(json_entry,
1007
0
                  "hitCount",
1008
0
                  pentry->hitcnt);
1009
0
          json_object_int_add(json_entry,
1010
0
                  "referenceCount",
1011
0
                  pentry->refcnt);
1012
0
        }
1013
0
      } else {
1014
0
        vty_out(vty, "   ");
1015
1016
0
        vty_out(vty, "seq %" PRId64 " ", pentry->seq);
1017
1018
0
        vty_out(vty, "%s ",
1019
0
          prefix_list_type_str(pentry));
1020
1021
0
        if (pentry->any)
1022
0
          vty_out(vty, "any");
1023
0
        else {
1024
0
          struct prefix *p = &pentry->prefix;
1025
1026
0
          vty_out(vty, "%pFX", p);
1027
1028
0
          if (pentry->ge)
1029
0
            vty_out(vty, " ge %d",
1030
0
              pentry->ge);
1031
0
          if (pentry->le)
1032
0
            vty_out(vty, " le %d",
1033
0
              pentry->le);
1034
0
        }
1035
1036
0
        if (dtype == detail_display
1037
0
            || dtype == sequential_display)
1038
0
          vty_out(vty,
1039
0
            " (hit count: %ld, refcount: %ld)",
1040
0
            pentry->hitcnt, pentry->refcnt);
1041
1042
0
        vty_out(vty, "\n");
1043
0
      }
1044
0
    }
1045
0
  }
1046
0
}
1047
1048
static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name,
1049
        const char *seq, enum display_type dtype,
1050
        bool uj)
1051
0
{
1052
0
  struct prefix_list *plist;
1053
0
  struct prefix_master *master;
1054
0
  int64_t seqnum = 0;
1055
0
  json_object *json = NULL;
1056
0
  json_object *json_proto = NULL;
1057
1058
0
  master = prefix_master_get(afi, 0);
1059
0
  if (master == NULL)
1060
0
    return CMD_WARNING;
1061
1062
0
  if (uj) {
1063
0
    json = json_object_new_object();
1064
0
    json_proto = json_object_new_object();
1065
0
    json_object_object_add(json, frr_protoname, json_proto);
1066
0
  }
1067
1068
0
  if (seq)
1069
0
    seqnum = (int64_t)atol(seq);
1070
1071
0
  if (name) {
1072
0
    plist = prefix_list_lookup(afi, name);
1073
0
    if (!plist) {
1074
0
      if (!uj)
1075
0
        vty_out(vty,
1076
0
          "%% Can't find specified prefix-list\n");
1077
0
      return CMD_WARNING;
1078
0
    }
1079
0
    vty_show_prefix_entry(vty, json_proto, afi, plist, master,
1080
0
              dtype, seqnum);
1081
0
  } else {
1082
0
    if (dtype == detail_display || dtype == summary_display) {
1083
0
      if (master->recent && !uj)
1084
0
        vty_out(vty,
1085
0
          "Prefix-list with the last deletion/insertion: %s\n",
1086
0
          master->recent->name);
1087
0
    }
1088
1089
0
    frr_each (plist, &master->str, plist)
1090
0
      vty_show_prefix_entry(vty, json_proto, afi, plist,
1091
0
                master, dtype, seqnum);
1092
0
  }
1093
1094
0
  return vty_json(vty, json);
1095
0
}
1096
1097
static int vty_show_prefix_list_prefix(struct vty *vty, afi_t afi,
1098
               const char *name, const char *prefix,
1099
               enum display_type type)
1100
0
{
1101
0
  struct prefix_list *plist;
1102
0
  struct prefix_list_entry *pentry;
1103
0
  struct prefix p;
1104
0
  int ret;
1105
0
  int match;
1106
1107
0
  plist = prefix_list_lookup(afi, name);
1108
0
  if (!plist) {
1109
0
    vty_out(vty, "%% Can't find specified prefix-list\n");
1110
0
    return CMD_WARNING;
1111
0
  }
1112
1113
0
  ret = str2prefix(prefix, &p);
1114
0
  if (ret <= 0) {
1115
0
    vty_out(vty, "%% prefix is malformed\n");
1116
0
    return CMD_WARNING;
1117
0
  }
1118
1119
0
  for (pentry = plist->head; pentry; pentry = pentry->next) {
1120
0
    match = 0;
1121
1122
0
    if (type == normal_display || type == first_match_display)
1123
0
      if (prefix_same(&p, &pentry->prefix))
1124
0
        match = 1;
1125
1126
0
    if (type == longer_display) {
1127
0
      if ((p.family == pentry->prefix.family)
1128
0
          && (prefix_match(&p, &pentry->prefix)))
1129
0
        match = 1;
1130
0
    }
1131
1132
0
    if (match) {
1133
0
      vty_out(vty, "   seq %" PRId64 " %s ", pentry->seq,
1134
0
        prefix_list_type_str(pentry));
1135
1136
0
      if (pentry->any)
1137
0
        vty_out(vty, "any");
1138
0
      else {
1139
0
        struct prefix *pf = &pentry->prefix;
1140
1141
0
        vty_out(vty, "%pFX", pf);
1142
1143
0
        if (pentry->ge)
1144
0
          vty_out(vty, " ge %d", pentry->ge);
1145
0
        if (pentry->le)
1146
0
          vty_out(vty, " le %d", pentry->le);
1147
0
      }
1148
1149
0
      if (type == normal_display
1150
0
          || type == first_match_display)
1151
0
        vty_out(vty, " (hit count: %ld, refcount: %ld)",
1152
0
          pentry->hitcnt, pentry->refcnt);
1153
1154
0
      vty_out(vty, "\n");
1155
1156
0
      if (type == first_match_display)
1157
0
        return CMD_SUCCESS;
1158
0
    }
1159
0
  }
1160
0
  return CMD_SUCCESS;
1161
0
}
1162
1163
static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name,
1164
         const char *prefix)
1165
0
{
1166
0
  struct prefix_master *master;
1167
0
  struct prefix_list *plist;
1168
0
  struct prefix_list_entry *pentry;
1169
0
  int ret;
1170
0
  struct prefix p;
1171
1172
0
  master = prefix_master_get(afi, 0);
1173
0
  if (master == NULL)
1174
0
    return CMD_WARNING;
1175
1176
0
  if (name == NULL && prefix == NULL) {
1177
0
    frr_each (plist, &master->str, plist)
1178
0
      for (pentry = plist->head; pentry;
1179
0
           pentry = pentry->next)
1180
0
        pentry->hitcnt = 0;
1181
0
  } else {
1182
0
    plist = prefix_list_lookup(afi, name);
1183
0
    if (!plist) {
1184
0
      vty_out(vty, "%% Can't find specified prefix-list\n");
1185
0
      return CMD_WARNING;
1186
0
    }
1187
1188
0
    if (prefix) {
1189
0
      ret = str2prefix(prefix, &p);
1190
0
      if (ret <= 0) {
1191
0
        vty_out(vty, "%% prefix is malformed\n");
1192
0
        return CMD_WARNING;
1193
0
      }
1194
0
    }
1195
1196
0
    for (pentry = plist->head; pentry; pentry = pentry->next) {
1197
0
      if (prefix) {
1198
0
        if (pentry->prefix.family == p.family
1199
0
            && prefix_match(&pentry->prefix, &p))
1200
0
          pentry->hitcnt = 0;
1201
0
      } else
1202
0
        pentry->hitcnt = 0;
1203
0
    }
1204
0
  }
1205
0
  return CMD_SUCCESS;
1206
0
}
1207
1208
#include "lib/plist_clippy.c"
1209
1210
DEFPY (show_ip_prefix_list,
1211
       show_ip_prefix_list_cmd,
1212
       "show ip prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
1213
       SHOW_STR
1214
       IP_STR
1215
       PREFIX_LIST_STR
1216
       "Name of a prefix list\n"
1217
       "sequence number of an entry\n"
1218
       "Sequence number\n"
1219
       JSON_STR)
1220
0
{
1221
0
  enum display_type dtype = normal_display;
1222
0
  if (dseq)
1223
0
    dtype = sequential_display;
1224
1225
0
  return vty_show_prefix_list(vty, AFI_IP, prefix_list, arg_str, dtype,
1226
0
            !!uj);
1227
0
}
1228
1229
DEFPY (show_ip_prefix_list_prefix,
1230
       show_ip_prefix_list_prefix_cmd,
1231
       "show ip prefix-list WORD A.B.C.D/M$prefix [longer$dl|first-match$dfm]",
1232
       SHOW_STR
1233
       IP_STR
1234
       PREFIX_LIST_STR
1235
       "Name of a prefix list\n"
1236
       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1237
       "Lookup longer prefix\n"
1238
       "First matched prefix\n")
1239
0
{
1240
0
  enum display_type dtype = normal_display;
1241
0
  if (dl)
1242
0
    dtype = longer_display;
1243
0
  else if (dfm)
1244
0
    dtype = first_match_display;
1245
1246
0
  return vty_show_prefix_list_prefix(vty, AFI_IP, prefix_list, prefix_str,
1247
0
             dtype);
1248
0
}
1249
1250
DEFPY (show_ip_prefix_list_summary,
1251
       show_ip_prefix_list_summary_cmd,
1252
       "show ip prefix-list summary [WORD$prefix_list] [json$uj]",
1253
       SHOW_STR
1254
       IP_STR
1255
       PREFIX_LIST_STR
1256
       "Summary of prefix lists\n"
1257
       "Name of a prefix list\n"
1258
       JSON_STR)
1259
0
{
1260
0
  return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL,
1261
0
            summary_display, !!uj);
1262
0
}
1263
1264
DEFPY (show_ip_prefix_list_detail,
1265
       show_ip_prefix_list_detail_cmd,
1266
       "show ip prefix-list detail [WORD$prefix_list] [json$uj]",
1267
       SHOW_STR
1268
       IP_STR
1269
       PREFIX_LIST_STR
1270
       "Detail of prefix lists\n"
1271
       "Name of a prefix list\n"
1272
       JSON_STR)
1273
0
{
1274
0
  return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL,
1275
0
            detail_display, !!uj);
1276
0
}
1277
1278
DEFPY (clear_ip_prefix_list,
1279
       clear_ip_prefix_list_cmd,
1280
       "clear ip prefix-list [WORD [A.B.C.D/M$prefix]]",
1281
       CLEAR_STR
1282
       IP_STR
1283
       PREFIX_LIST_STR
1284
       "Name of a prefix list\n"
1285
       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
1286
0
{
1287
0
  return vty_clear_prefix_list(vty, AFI_IP, prefix_list, prefix_str);
1288
0
}
1289
1290
DEFPY (show_ipv6_prefix_list,
1291
       show_ipv6_prefix_list_cmd,
1292
       "show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
1293
       SHOW_STR
1294
       IPV6_STR
1295
       PREFIX_LIST_STR
1296
       "Name of a prefix list\n"
1297
       "sequence number of an entry\n"
1298
       "Sequence number\n"
1299
       JSON_STR)
1300
0
{
1301
0
  enum display_type dtype = normal_display;
1302
0
  if (dseq)
1303
0
    dtype = sequential_display;
1304
1305
0
  return vty_show_prefix_list(vty, AFI_IP6, prefix_list, arg_str, dtype,
1306
0
            !!uj);
1307
0
}
1308
1309
DEFPY (show_ipv6_prefix_list_prefix,
1310
       show_ipv6_prefix_list_prefix_cmd,
1311
       "show ipv6 prefix-list WORD X:X::X:X/M$prefix [longer$dl|first-match$dfm]",
1312
       SHOW_STR
1313
       IPV6_STR
1314
       PREFIX_LIST_STR
1315
       "Name of a prefix list\n"
1316
       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1317
       "Lookup longer prefix\n"
1318
       "First matched prefix\n")
1319
0
{
1320
0
  enum display_type dtype = normal_display;
1321
0
  if (dl)
1322
0
    dtype = longer_display;
1323
0
  else if (dfm)
1324
0
    dtype = first_match_display;
1325
1326
0
  return vty_show_prefix_list_prefix(vty, AFI_IP6, prefix_list,
1327
0
             prefix_str, dtype);
1328
0
}
1329
1330
DEFPY (show_ipv6_prefix_list_summary,
1331
       show_ipv6_prefix_list_summary_cmd,
1332
       "show ipv6 prefix-list summary [WORD$prefix-list] [json$uj]",
1333
       SHOW_STR
1334
       IPV6_STR
1335
       PREFIX_LIST_STR
1336
       "Summary of prefix lists\n"
1337
       "Name of a prefix list\n"
1338
       JSON_STR)
1339
0
{
1340
0
  return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL,
1341
0
            summary_display, !!uj);
1342
0
}
1343
1344
DEFPY (show_ipv6_prefix_list_detail,
1345
       show_ipv6_prefix_list_detail_cmd,
1346
       "show ipv6 prefix-list detail [WORD$prefix-list] [json$uj]",
1347
       SHOW_STR
1348
       IPV6_STR
1349
       PREFIX_LIST_STR
1350
       "Detail of prefix lists\n"
1351
       "Name of a prefix list\n"
1352
       JSON_STR)
1353
0
{
1354
0
  return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL,
1355
0
            detail_display, !!uj);
1356
0
}
1357
1358
DEFPY (clear_ipv6_prefix_list,
1359
       clear_ipv6_prefix_list_cmd,
1360
       "clear ipv6 prefix-list [WORD [X:X::X:X/M$prefix]]",
1361
       CLEAR_STR
1362
       IPV6_STR
1363
       PREFIX_LIST_STR
1364
       "Name of a prefix list\n"
1365
       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
1366
0
{
1367
0
  return vty_clear_prefix_list(vty, AFI_IP6, prefix_list, prefix_str);
1368
0
}
1369
1370
DEFPY (debug_prefix_list_match,
1371
       debug_prefix_list_match_cmd,
1372
       "debug prefix-list WORD$prefix-list match <A.B.C.D/M|X:X::X:X/M>"
1373
       " [address-mode$addr_mode]",
1374
       DEBUG_STR
1375
       "Prefix-list test access\n"
1376
       "Name of a prefix list\n"
1377
       "Test prefix for prefix list result\n"
1378
       "Prefix to test in ip prefix-list\n"
1379
       "Prefix to test in ipv6 prefix-list\n"
1380
       "Use address matching mode (PIM RP)\n")
1381
0
{
1382
0
  struct prefix_list *plist;
1383
0
  const struct prefix_list_entry *entry = NULL;
1384
0
  enum prefix_list_type ret;
1385
1386
0
  plist = prefix_list_lookup(family2afi(match->family), prefix_list);
1387
0
  if (!plist) {
1388
0
    vty_out(vty, "%% no prefix list named %s for AFI %s\n",
1389
0
      prefix_list, afi2str(family2afi(match->family)));
1390
0
    return CMD_WARNING;
1391
0
  }
1392
1393
0
  ret = prefix_list_apply_ext(plist, &entry, match, !!addr_mode);
1394
1395
0
  vty_out(vty, "%s prefix list %s yields %s for %pFX, ",
1396
0
    afi2str(family2afi(match->family)), prefix_list,
1397
0
    ret == PREFIX_DENY ? "DENY" : "PERMIT", match);
1398
1399
0
  if (!entry)
1400
0
    vty_out(vty, "no match found\n");
1401
0
  else {
1402
0
    vty_out(vty, "matching entry #%"PRId64": %pFX", entry->seq,
1403
0
      &entry->prefix);
1404
0
    if (entry->ge)
1405
0
      vty_out(vty, " ge %d", entry->ge);
1406
0
    if (entry->le)
1407
0
      vty_out(vty, " le %d", entry->le);
1408
0
    vty_out(vty, "\n");
1409
0
  }
1410
1411
  /* allow using this in scripts for quick prefix-list member tests */
1412
0
  return (ret == PREFIX_PERMIT) ? CMD_SUCCESS : CMD_WARNING;
1413
0
}
1414
1415
struct stream *prefix_bgp_orf_entry(struct stream *s, struct prefix_list *plist,
1416
            uint8_t init_flag, uint8_t permit_flag,
1417
            uint8_t deny_flag)
1418
0
{
1419
0
  struct prefix_list_entry *pentry;
1420
1421
0
  if (!plist)
1422
0
    return s;
1423
1424
0
  for (pentry = plist->head; pentry; pentry = pentry->next) {
1425
0
    uint8_t flag = init_flag;
1426
0
    struct prefix *p = &pentry->prefix;
1427
1428
0
    flag |= (pentry->type == PREFIX_PERMIT ? permit_flag
1429
0
                   : deny_flag);
1430
0
    stream_putc(s, flag);
1431
0
    stream_putl(s, (uint32_t)pentry->seq);
1432
0
    stream_putc(s, (uint8_t)pentry->ge);
1433
0
    stream_putc(s, (uint8_t)pentry->le);
1434
0
    stream_put_prefix(s, p);
1435
0
  }
1436
1437
0
  return s;
1438
0
}
1439
1440
int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp,
1441
           int permit, int set)
1442
3.40k
{
1443
3.40k
  struct prefix_list *plist;
1444
3.40k
  struct prefix_list_entry *pentry;
1445
1446
  /* ge and le value check */
1447
3.40k
  if (orfp->ge && orfp->ge < orfp->p.prefixlen)
1448
68
    return CMD_WARNING_CONFIG_FAILED;
1449
3.34k
  if (orfp->le && orfp->le < orfp->p.prefixlen)
1450
3
    return CMD_WARNING_CONFIG_FAILED;
1451
3.33k
  if (orfp->le && orfp->ge > orfp->le)
1452
92
    return CMD_WARNING_CONFIG_FAILED;
1453
1454
3.24k
  if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128))
1455
50
    orfp->le = 0;
1456
1457
3.24k
  plist = prefix_list_get(afi, 1, name);
1458
3.24k
  if (!plist)
1459
103
    return CMD_WARNING_CONFIG_FAILED;
1460
1461
3.14k
  apply_mask(&orfp->p);
1462
1463
3.14k
  if (set) {
1464
3.03k
    pentry = prefix_list_entry_make(
1465
3.03k
      &orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY),
1466
3.03k
      orfp->seq, orfp->le, orfp->ge, false);
1467
1468
3.03k
    if (prefix_entry_dup_check(plist, pentry)) {
1469
42
      prefix_list_entry_free(pentry);
1470
42
      return CMD_WARNING_CONFIG_FAILED;
1471
42
    }
1472
1473
2.99k
    prefix_list_entry_add(plist, pentry);
1474
2.99k
  } else {
1475
104
    pentry = prefix_list_entry_lookup(
1476
104
      plist, &orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY),
1477
104
      orfp->seq, orfp->le, orfp->ge);
1478
1479
104
    if (!pentry)
1480
46
      return CMD_WARNING_CONFIG_FAILED;
1481
1482
58
    prefix_list_entry_delete(plist, pentry, 1);
1483
58
  }
1484
1485
3.05k
  return CMD_SUCCESS;
1486
3.14k
}
1487
1488
void prefix_bgp_orf_remove_all(afi_t afi, char *name)
1489
1.22k
{
1490
1.22k
  struct prefix_list *plist;
1491
1492
1.22k
  plist = prefix_bgp_orf_lookup(afi, name);
1493
1.22k
  if (plist)
1494
815
    prefix_list_delete(plist);
1495
1.22k
}
1496
1497
/* return prefix count */
1498
int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name,
1499
        bool use_json)
1500
0
{
1501
0
  struct prefix_list *plist;
1502
0
  struct prefix_list_entry *pentry;
1503
0
  json_object *json = NULL;
1504
0
  json_object *json_prefix = NULL;
1505
0
  json_object *json_list = NULL;
1506
1507
0
  plist = prefix_bgp_orf_lookup(afi, name);
1508
0
  if (!plist)
1509
0
    return 0;
1510
1511
0
  if (!vty)
1512
0
    return plist->count;
1513
1514
0
  if (use_json) {
1515
0
    json = json_object_new_object();
1516
0
    json_prefix = json_object_new_object();
1517
0
    json_list = json_object_new_object();
1518
1519
0
    json_object_int_add(json_prefix, "prefixListCounter",
1520
0
            plist->count);
1521
0
    json_object_string_add(json_prefix, "prefixListName",
1522
0
               plist->name);
1523
1524
0
    for (pentry = plist->head; pentry; pentry = pentry->next) {
1525
0
      struct prefix *p = &pentry->prefix;
1526
0
      char buf_a[BUFSIZ];
1527
1528
0
      snprintf(buf_a, sizeof(buf_a), "%pFX", p);
1529
1530
0
      json_object_int_add(json_list, "seq", pentry->seq);
1531
0
      json_object_string_add(json_list, "seqPrefixListType",
1532
0
                 prefix_list_type_str(pentry));
1533
1534
0
      if (pentry->ge)
1535
0
        json_object_int_add(json_list, "ge",
1536
0
                pentry->ge);
1537
0
      if (pentry->le)
1538
0
        json_object_int_add(json_list, "le",
1539
0
                pentry->le);
1540
1541
0
      json_object_object_add(json_prefix, buf_a, json_list);
1542
0
    }
1543
0
    if (afi == AFI_IP)
1544
0
      json_object_object_add(json, "ipPrefixList",
1545
0
                 json_prefix);
1546
0
    else
1547
0
      json_object_object_add(json, "ipv6PrefixList",
1548
0
                 json_prefix);
1549
1550
0
    vty_json(vty, json);
1551
0
  } else {
1552
0
    vty_out(vty, "ip%s prefix-list %s: %d entries\n",
1553
0
      afi == AFI_IP ? "" : "v6", plist->name, plist->count);
1554
1555
0
    for (pentry = plist->head; pentry; pentry = pentry->next) {
1556
0
      struct prefix *p = &pentry->prefix;
1557
1558
0
      vty_out(vty, "   seq %" PRId64 " %s %pFX", pentry->seq,
1559
0
        prefix_list_type_str(pentry), p);
1560
1561
0
      if (pentry->ge)
1562
0
        vty_out(vty, " ge %d", pentry->ge);
1563
0
      if (pentry->le)
1564
0
        vty_out(vty, " le %d", pentry->le);
1565
1566
0
      vty_out(vty, "\n");
1567
0
    }
1568
0
  }
1569
0
  return plist->count;
1570
0
}
1571
1572
static void prefix_list_reset_afi(afi_t afi, int orf)
1573
0
{
1574
0
  struct prefix_list *plist;
1575
0
  struct prefix_master *master;
1576
1577
0
  master = prefix_master_get(afi, orf);
1578
0
  if (master == NULL)
1579
0
    return;
1580
1581
0
  while ((plist = plist_first(&master->str))) {
1582
0
    prefix_list_delete(plist);
1583
0
  }
1584
1585
0
  master->recent = NULL;
1586
0
}
1587
1588
/* Prefix-list node. */
1589
static struct cmd_node prefix_node = {
1590
  .name = "ipv4 prefix list",
1591
  .node = PREFIX_NODE,
1592
  .prompt = "",
1593
};
1594
1595
static void plist_autocomplete_afi(afi_t afi, vector comps,
1596
           struct cmd_token *token)
1597
0
{
1598
0
  struct prefix_list *plist;
1599
0
  struct prefix_master *master;
1600
1601
0
  master = prefix_master_get(afi, 0);
1602
0
  if (master == NULL)
1603
0
    return;
1604
1605
0
  frr_each (plist, &master->str, plist)
1606
0
    vector_set(comps, XSTRDUP(MTYPE_COMPLETION, plist->name));
1607
0
}
1608
1609
static void plist_autocomplete(vector comps, struct cmd_token *token)
1610
0
{
1611
0
  plist_autocomplete_afi(AFI_IP, comps, token);
1612
0
  plist_autocomplete_afi(AFI_IP6, comps, token);
1613
0
}
1614
1615
static const struct cmd_variable_handler plist_var_handlers[] = {
1616
  {/* "prefix-list WORD" */
1617
   .varname = "prefix_list",
1618
   .completions = plist_autocomplete},
1619
  {.tokenname = "PREFIXLIST_NAME",
1620
   .completions = plist_autocomplete},
1621
  {.completions = NULL}};
1622
1623
1624
static void prefix_list_init_ipv4(void)
1625
4
{
1626
4
  install_node(&prefix_node);
1627
1628
4
  install_element(VIEW_NODE, &show_ip_prefix_list_cmd);
1629
4
  install_element(VIEW_NODE, &show_ip_prefix_list_prefix_cmd);
1630
4
  install_element(VIEW_NODE, &show_ip_prefix_list_summary_cmd);
1631
4
  install_element(VIEW_NODE, &show_ip_prefix_list_detail_cmd);
1632
1633
4
  install_element(ENABLE_NODE, &clear_ip_prefix_list_cmd);
1634
4
}
1635
1636
/* Prefix-list node. */
1637
static struct cmd_node prefix_ipv6_node = {
1638
  .name = "ipv6 prefix list",
1639
  .node = PREFIX_IPV6_NODE,
1640
  .prompt = "",
1641
};
1642
1643
static void prefix_list_init_ipv6(void)
1644
4
{
1645
4
  install_node(&prefix_ipv6_node);
1646
1647
4
  install_element(VIEW_NODE, &show_ipv6_prefix_list_cmd);
1648
4
  install_element(VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd);
1649
4
  install_element(VIEW_NODE, &show_ipv6_prefix_list_summary_cmd);
1650
4
  install_element(VIEW_NODE, &show_ipv6_prefix_list_detail_cmd);
1651
4
  install_element(VIEW_NODE, &debug_prefix_list_match_cmd);
1652
1653
4
  install_element(ENABLE_NODE, &clear_ipv6_prefix_list_cmd);
1654
4
}
1655
1656
void prefix_list_init(void)
1657
4
{
1658
4
  plist_init(&prefix_master_ipv4.str);
1659
4
  plist_init(&prefix_master_orf_v4.str);
1660
4
  plist_init(&prefix_master_ipv6.str);
1661
4
  plist_init(&prefix_master_orf_v6.str);
1662
1663
4
  cmd_variable_handler_register(plist_var_handlers);
1664
1665
4
  prefix_list_init_ipv4();
1666
4
  prefix_list_init_ipv6();
1667
4
}
1668
1669
void prefix_list_reset(void)
1670
0
{
1671
0
  prefix_list_reset_afi(AFI_IP, 0);
1672
0
  prefix_list_reset_afi(AFI_IP6, 0);
1673
0
  prefix_list_reset_afi(AFI_IP, 1);
1674
0
  prefix_list_reset_afi(AFI_IP6, 1);
1675
0
}