Coverage Report

Created: 2026-01-21 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/lib/routemap.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Route map function.
3
 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
4
 */
5
6
#include <zebra.h>
7
8
#include "linklist.h"
9
#include "memory.h"
10
#include "command.h"
11
#include "vector.h"
12
#include "prefix.h"
13
#include "vty.h"
14
#include "routemap.h"
15
#include "command.h"
16
#include "log.h"
17
#include "hash.h"
18
#include "libfrr.h"
19
#include "lib_errors.h"
20
#include "table.h"
21
#include "json.h"
22
#include "jhash.h"
23
24
#include "lib/routemap_clippy.c"
25
26
8
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map");
27
8
DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name");
28
8
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index");
29
8
DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule");
30
8
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str");
31
8
DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled");
32
8
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency");
33
8
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data");
34
8
35
8
DEFINE_QOBJ_TYPE(route_map_index);
36
8
DEFINE_QOBJ_TYPE(route_map);
37
8
38
8
static int rmap_cmd_name_cmp(const struct route_map_rule_cmd_proxy *a,
39
8
           const struct route_map_rule_cmd_proxy *b)
40
8
{
41
2
  return strcmp(a->cmd->str, b->cmd->str);
42
2
}
43
44
static uint32_t rmap_cmd_name_hash(const struct route_map_rule_cmd_proxy *item)
45
99
{
46
99
  return jhash(item->cmd->str, strlen(item->cmd->str), 0xbfd69320);
47
99
}
48
49
99
DECLARE_HASH(rmap_cmd_name, struct route_map_rule_cmd_proxy, itm,
routemap.c:rmap_cmd_name_add
Line
Count
Source
49
DECLARE_HASH(rmap_cmd_name, struct route_map_rule_cmd_proxy, itm,
Unexecuted instantiation: routemap.c:rmap_cmd_name_fini
50
       rmap_cmd_name_cmp, rmap_cmd_name_hash);
51
52
static struct rmap_cmd_name_head rmap_match_cmds[1] = {
53
  INIT_HASH(rmap_match_cmds[0]),
54
};
55
static struct rmap_cmd_name_head rmap_set_cmds[1] = {
56
  INIT_HASH(rmap_set_cmds[0]),
57
};
58
59
0
#define IPv4_PREFIX_LIST "ip address prefix-list"
60
0
#define IPv6_PREFIX_LIST "ipv6 address prefix-list"
61
62
#define IS_RULE_IPv4_PREFIX_LIST(S)                                            \
63
0
  (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0)
64
#define IS_RULE_IPv6_PREFIX_LIST(S)                                            \
65
0
  (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0)
66
67
struct route_map_pentry_dep {
68
  struct prefix_list_entry *pentry;
69
  const char *plist_name;
70
  route_map_event_t event;
71
};
72
73
static void route_map_pfx_tbl_update(route_map_event_t event,
74
             struct route_map_index *index, afi_t afi,
75
             const char *plist_name);
76
static void route_map_pfx_table_add_default(afi_t afi,
77
              struct route_map_index *index);
78
static void route_map_pfx_table_del_default(afi_t afi,
79
              struct route_map_index *index);
80
static void route_map_add_plist_entries(afi_t afi,
81
          struct route_map_index *index,
82
          const char *plist_name,
83
          struct prefix_list_entry *entry);
84
static void route_map_del_plist_entries(afi_t afi,
85
          struct route_map_index *index,
86
          const char *plist_name,
87
          struct prefix_list_entry *entry);
88
89
static struct hash *route_map_get_dep_hash(route_map_event_t event);
90
static void route_map_free_map(struct route_map *map);
91
92
struct route_map_match_set_hooks rmap_match_set_hook;
93
94
/* match interface */
95
void route_map_match_interface_hook(int (*func)(
96
  struct route_map_index *index, const char *command,
97
  const char *arg, route_map_event_t type,
98
  char *errmsg, size_t errmsg_len))
99
3
{
100
3
  rmap_match_set_hook.match_interface = func;
101
3
}
102
103
/* no match interface */
104
void route_map_no_match_interface_hook(int (*func)(
105
  struct route_map_index *index, const char *command,
106
  const char *arg, route_map_event_t type,
107
  char *errmsg, size_t errmsg_len))
108
3
{
109
3
  rmap_match_set_hook.no_match_interface = func;
110
3
}
111
112
/* match ip address */
113
void route_map_match_ip_address_hook(int (*func)(
114
  struct route_map_index *index, const char *command,
115
  const char *arg, route_map_event_t type,
116
  char *errmsg, size_t errmsg_len))
117
3
{
118
3
  rmap_match_set_hook.match_ip_address = func;
119
3
}
120
121
/* no match ip address */
122
void route_map_no_match_ip_address_hook(int (*func)(
123
  struct route_map_index *index, const char *command,
124
  const char *arg, route_map_event_t type,
125
  char *errmsg, size_t errmsg_len))
126
3
{
127
3
  rmap_match_set_hook.no_match_ip_address = func;
128
3
}
129
130
/* match ip address prefix list */
131
void route_map_match_ip_address_prefix_list_hook(int (*func)(
132
  struct route_map_index *index, const char *command,
133
  const char *arg, route_map_event_t type,
134
  char *errmsg, size_t errmsg_len))
135
3
{
136
3
  rmap_match_set_hook.match_ip_address_prefix_list = func;
137
3
}
138
139
/* no match ip address prefix list */
140
void route_map_no_match_ip_address_prefix_list_hook(int (*func)(
141
  struct route_map_index *index, const char *command,
142
  const char *arg, route_map_event_t type,
143
  char *errmsg, size_t errmsg_len))
144
3
{
145
3
  rmap_match_set_hook.no_match_ip_address_prefix_list = func;
146
3
}
147
148
/* match ip next hop */
149
void route_map_match_ip_next_hop_hook(int (*func)(
150
  struct route_map_index *index, const char *command,
151
  const char *arg, route_map_event_t type,
152
  char *errmsg, size_t errmsg_len))
153
3
{
154
3
  rmap_match_set_hook.match_ip_next_hop = func;
155
3
}
156
157
/* no match ip next hop */
158
void route_map_no_match_ip_next_hop_hook(int (*func)(
159
  struct route_map_index *index, const char *command,
160
  const char *arg, route_map_event_t type,
161
  char *errmsg, size_t errmsg_len))
162
3
{
163
3
  rmap_match_set_hook.no_match_ip_next_hop = func;
164
3
}
165
166
/* match ipv6 next-hop */
167
void route_map_match_ipv6_next_hop_hook(int (*func)(
168
  struct route_map_index *index, const char *command, const char *arg,
169
  route_map_event_t type, char *errmsg, size_t errmsg_len))
170
1
{
171
1
  rmap_match_set_hook.match_ipv6_next_hop = func;
172
1
}
173
174
/* no match ipv6 next-hop */
175
void route_map_no_match_ipv6_next_hop_hook(int (*func)(
176
  struct route_map_index *index, const char *command, const char *arg,
177
  route_map_event_t type, char *errmsg, size_t errmsg_len))
178
1
{
179
1
  rmap_match_set_hook.no_match_ipv6_next_hop = func;
180
1
}
181
182
/* match ip next hop prefix list */
183
void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
184
  struct route_map_index *index, const char *command,
185
  const char *arg, route_map_event_t type,
186
  char *errmsg, size_t errmsg_len))
187
3
{
188
3
  rmap_match_set_hook.match_ip_next_hop_prefix_list = func;
189
3
}
190
191
/* no match ip next hop prefix list */
192
void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)(
193
  struct route_map_index *index, const char *command,
194
  const char *arg, route_map_event_t type,
195
  char *errmsg, size_t errmsg_len))
196
3
{
197
3
  rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func;
198
3
}
199
200
/* match ip next-hop type */
201
void route_map_match_ip_next_hop_type_hook(int (*func)(
202
  struct route_map_index *index, const char *command,
203
  const char *arg, route_map_event_t type,
204
  char *errmsg, size_t errmsg_len))
205
3
{
206
3
  rmap_match_set_hook.match_ip_next_hop_type = func;
207
3
}
208
209
/* no match ip next-hop type */
210
void route_map_no_match_ip_next_hop_type_hook(int (*func)(
211
  struct route_map_index *index, const char *command,
212
  const char *arg, route_map_event_t type,
213
  char *errmsg, size_t errmsg_len))
214
3
{
215
3
  rmap_match_set_hook.no_match_ip_next_hop_type = func;
216
3
}
217
218
/* match ipv6 address */
219
void route_map_match_ipv6_address_hook(int (*func)(
220
  struct route_map_index *index, const char *command,
221
  const char *arg, route_map_event_t type,
222
  char *errmsg, size_t errmsg_len))
223
2
{
224
2
  rmap_match_set_hook.match_ipv6_address = func;
225
2
}
226
227
/* no match ipv6 address */
228
void route_map_no_match_ipv6_address_hook(int (*func)(
229
  struct route_map_index *index, const char *command,
230
  const char *arg, route_map_event_t type,
231
  char *errmsg, size_t errmsg_len))
232
2
{
233
2
  rmap_match_set_hook.no_match_ipv6_address = func;
234
2
}
235
236
237
/* match ipv6 address prefix list */
238
void route_map_match_ipv6_address_prefix_list_hook(int (*func)(
239
  struct route_map_index *index, const char *command,
240
  const char *arg, route_map_event_t type,
241
  char *errmsg, size_t errmsg_len))
242
2
{
243
2
  rmap_match_set_hook.match_ipv6_address_prefix_list = func;
244
2
}
245
246
/* no match ipv6 address prefix list */
247
void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)(
248
  struct route_map_index *index, const char *command,
249
  const char *arg, route_map_event_t type,
250
  char *errmsg, size_t errmsg_len))
251
2
{
252
2
  rmap_match_set_hook.no_match_ipv6_address_prefix_list = func;
253
2
}
254
255
/* match ipv6 next-hop type */
256
void route_map_match_ipv6_next_hop_type_hook(int (*func)(
257
  struct route_map_index *index, const char *command,
258
  const char *arg, route_map_event_t type,
259
  char *errmsg, size_t errmsg_len))
260
2
{
261
2
  rmap_match_set_hook.match_ipv6_next_hop_type = func;
262
2
}
263
264
/* no match ipv6 next-hop type */
265
void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
266
  struct route_map_index *index, const char *command,
267
  const char *arg, route_map_event_t type,
268
  char *errmsg, size_t errmsg_len))
269
2
{
270
2
  rmap_match_set_hook.no_match_ipv6_next_hop_type = func;
271
2
}
272
273
/* match ipv6 next-hop prefix-list */
274
void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func)(
275
  struct route_map_index *index, const char *command, const char *arg,
276
  route_map_event_t type, char *errmsg, size_t errmsg_len))
277
1
{
278
1
  rmap_match_set_hook.match_ipv6_next_hop_prefix_list = func;
279
1
}
280
281
/* no match ipv6 next-hop prefix-list */
282
void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func)(
283
  struct route_map_index *index, const char *command, const char *arg,
284
  route_map_event_t type, char *errmsg, size_t errmsg_len))
285
1
{
286
1
  rmap_match_set_hook.no_match_ipv6_next_hop_prefix_list = func;
287
1
}
288
289
/* match metric */
290
void route_map_match_metric_hook(int (*func)(
291
  struct route_map_index *index, const char *command,
292
  const char *arg, route_map_event_t type,
293
  char *errmsg, size_t errmsg_len))
294
1
{
295
1
  rmap_match_set_hook.match_metric = func;
296
1
}
297
298
/* no match metric */
299
void route_map_no_match_metric_hook(int (*func)(
300
  struct route_map_index *index, const char *command,
301
  const char *arg, route_map_event_t type,
302
  char *errmsg, size_t errmsg_len))
303
1
{
304
1
  rmap_match_set_hook.no_match_metric = func;
305
1
}
306
307
/* match tag */
308
void route_map_match_tag_hook(int (*func)(struct route_map_index *index,
309
            const char *command, const char *arg,
310
            route_map_event_t type,
311
            char *errmsg, size_t errmsg_len))
312
3
{
313
3
  rmap_match_set_hook.match_tag = func;
314
3
}
315
316
/* no match tag */
317
void route_map_no_match_tag_hook(int (*func)(
318
  struct route_map_index *index, const char *command,
319
  const char *arg, route_map_event_t type,
320
  char *errmsg, size_t errmsg_len))
321
3
{
322
3
  rmap_match_set_hook.no_match_tag = func;
323
3
}
324
325
/* set sr-te color */
326
void route_map_set_srte_color_hook(int (*func)(struct route_map_index *index,
327
                 const char *command,
328
                 const char *arg,
329
                 char *errmsg, size_t errmsg_len))
330
1
{
331
1
  rmap_match_set_hook.set_srte_color = func;
332
1
}
333
334
/* no set sr-te color */
335
void route_map_no_set_srte_color_hook(int (*func)(struct route_map_index *index,
336
              const char *command,
337
              const char *arg,
338
              char *errmsg, size_t errmsg_len))
339
1
{
340
1
  rmap_match_set_hook.no_set_srte_color = func;
341
1
}
342
343
/* set ip nexthop */
344
void route_map_set_ip_nexthop_hook(int (*func)(struct route_map_index *index,
345
                 const char *command,
346
                 const char *arg,
347
                 char *errmsg, size_t errmsg_len))
348
1
{
349
1
  rmap_match_set_hook.set_ip_nexthop = func;
350
1
}
351
352
/* no set ip nexthop */
353
void route_map_no_set_ip_nexthop_hook(int (*func)(struct route_map_index *index,
354
              const char *command,
355
              const char *arg,
356
              char *errmsg,
357
              size_t errmsg_len))
358
1
{
359
1
  rmap_match_set_hook.no_set_ip_nexthop = func;
360
1
}
361
362
/* set ipv6 nexthop local */
363
void route_map_set_ipv6_nexthop_local_hook(
364
  int (*func)(struct route_map_index *index,
365
        const char *command, const char *arg,
366
        char *errmsg, size_t errmsg_len))
367
1
{
368
1
  rmap_match_set_hook.set_ipv6_nexthop_local = func;
369
1
}
370
371
/* no set ipv6 nexthop local */
372
void route_map_no_set_ipv6_nexthop_local_hook(
373
  int (*func)(struct route_map_index *index,
374
        const char *command, const char *arg,
375
        char *errmsg, size_t errmsg_len))
376
1
{
377
1
  rmap_match_set_hook.no_set_ipv6_nexthop_local = func;
378
1
}
379
380
/* set metric */
381
void route_map_set_metric_hook(int (*func)(struct route_map_index *index,
382
             const char *command,
383
             const char *arg,
384
             char *errmsg, size_t errmsg_len))
385
2
{
386
2
  rmap_match_set_hook.set_metric = func;
387
2
}
388
389
/* no set metric */
390
void route_map_no_set_metric_hook(int (*func)(struct route_map_index *index,
391
                const char *command,
392
                const char *arg,
393
                char *errmsg, size_t errmsg_len))
394
2
{
395
2
  rmap_match_set_hook.no_set_metric = func;
396
2
}
397
/* set min-metric */
398
void route_map_set_min_metric_hook(int (*func)(struct route_map_index *index,
399
                 const char *command,
400
                 const char *arg, char *errmsg,
401
                 size_t errmsg_len))
402
1
{
403
1
  rmap_match_set_hook.set_min_metric = func;
404
1
}
405
406
/* no set min-metric */
407
void route_map_no_set_min_metric_hook(int (*func)(struct route_map_index *index,
408
              const char *command,
409
              const char *arg, char *errmsg,
410
              size_t errmsg_len))
411
1
{
412
1
  rmap_match_set_hook.no_set_min_metric = func;
413
1
}
414
/* set max-metric */
415
void route_map_set_max_metric_hook(int (*func)(struct route_map_index *index,
416
                 const char *command,
417
                 const char *arg, char *errmsg,
418
                 size_t errmsg_len))
419
1
{
420
1
  rmap_match_set_hook.set_max_metric = func;
421
1
}
422
423
/* no set max-metric */
424
void route_map_no_set_max_metric_hook(int (*func)(struct route_map_index *index,
425
              const char *command,
426
              const char *arg, char *errmsg,
427
              size_t errmsg_len))
428
1
{
429
1
  rmap_match_set_hook.no_set_max_metric = func;
430
1
}
431
432
/* set tag */
433
void route_map_set_tag_hook(int (*func)(struct route_map_index *index,
434
          const char *command, const char *arg,
435
          char *errmsg, size_t errmsg_len))
436
2
{
437
2
  rmap_match_set_hook.set_tag = func;
438
2
}
439
440
/* no set tag */
441
void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index,
442
             const char *command,
443
             const char *arg,
444
             char *errmsg, size_t errmsg_len))
445
2
{
446
2
  rmap_match_set_hook.no_set_tag = func;
447
2
}
448
449
int generic_match_add(struct route_map_index *index,
450
          const char *command, const char *arg,
451
          route_map_event_t type,
452
          char *errmsg, size_t errmsg_len)
453
0
{
454
0
  enum rmap_compile_rets ret;
455
456
0
  ret = route_map_add_match(index, command, arg, type);
457
0
  switch (ret) {
458
0
  case RMAP_RULE_MISSING:
459
0
    snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
460
0
       frr_protonameinst);
461
0
    return CMD_WARNING_CONFIG_FAILED;
462
0
  case RMAP_COMPILE_ERROR:
463
0
    snprintf(errmsg, errmsg_len,
464
0
       "%% [%s] Argument form is unsupported or malformed.",
465
0
       frr_protonameinst);
466
0
    return CMD_WARNING_CONFIG_FAILED;
467
0
  case RMAP_COMPILE_SUCCESS:
468
    /*
469
     * Nothing to do here move along
470
     */
471
0
    break;
472
0
  }
473
474
0
  return CMD_SUCCESS;
475
0
}
476
477
int generic_match_delete(struct route_map_index *index,
478
       const char *command, const char *arg,
479
       route_map_event_t type,
480
       char *errmsg, size_t errmsg_len)
481
0
{
482
0
  enum rmap_compile_rets ret;
483
0
  int retval = CMD_SUCCESS;
484
0
  char *dep_name = NULL;
485
0
  const char *tmpstr;
486
0
  char *rmap_name = NULL;
487
488
0
  if (type != RMAP_EVENT_MATCH_DELETED) {
489
    /* ignore the mundane, the types without any dependency */
490
0
    if (arg == NULL) {
491
0
      if ((tmpstr = route_map_get_match_arg(index, command))
492
0
          != NULL)
493
0
        dep_name =
494
0
          XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
495
0
    } else {
496
0
      dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
497
0
    }
498
0
    rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
499
0
  }
500
501
0
  ret = route_map_delete_match(index, command, dep_name, type);
502
0
  switch (ret) {
503
0
  case RMAP_RULE_MISSING:
504
0
    snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
505
0
       frr_protonameinst);
506
0
    retval = CMD_WARNING_CONFIG_FAILED;
507
0
    break;
508
0
  case RMAP_COMPILE_ERROR:
509
0
    snprintf(errmsg, errmsg_len,
510
0
       "%% [%s] Argument form is unsupported or malformed.",
511
0
       frr_protonameinst);
512
0
    retval = CMD_WARNING_CONFIG_FAILED;
513
0
    break;
514
0
  case RMAP_COMPILE_SUCCESS:
515
    /*
516
     * Nothing to do here
517
     */
518
0
    break;
519
0
  }
520
521
0
  XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
522
0
  XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
523
524
0
  return retval;
525
0
}
526
527
int generic_set_add(struct route_map_index *index,
528
        const char *command, const char *arg,
529
        char *errmsg, size_t errmsg_len)
530
0
{
531
0
  enum rmap_compile_rets ret;
532
533
0
  ret = route_map_add_set(index, command, arg);
534
0
  switch (ret) {
535
0
  case RMAP_RULE_MISSING:
536
0
    snprintf(errmsg, errmsg_len,
537
0
       "%% [%s] Can't find rule.", frr_protonameinst);
538
0
    return CMD_WARNING_CONFIG_FAILED;
539
0
  case RMAP_COMPILE_ERROR:
540
0
    snprintf(errmsg, errmsg_len,
541
0
       "%% [%s] Argument form is unsupported or malformed.",
542
0
      frr_protonameinst);
543
0
    return CMD_WARNING_CONFIG_FAILED;
544
0
  case RMAP_COMPILE_SUCCESS:
545
0
    break;
546
0
  }
547
548
0
  return CMD_SUCCESS;
549
0
}
550
551
int generic_set_delete(struct route_map_index *index,
552
           const char *command, const char *arg,
553
           char *errmsg, size_t errmsg_len)
554
0
{
555
0
  enum rmap_compile_rets ret;
556
557
0
  ret = route_map_delete_set(index, command, arg);
558
0
  switch (ret) {
559
0
  case RMAP_RULE_MISSING:
560
0
      snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.",
561
0
         frr_protonameinst);
562
0
    return CMD_WARNING_CONFIG_FAILED;
563
0
  case RMAP_COMPILE_ERROR:
564
0
      snprintf(errmsg, errmsg_len,
565
0
         "%%  [%s] Argument form is unsupported or malformed.",
566
0
         frr_protonameinst);
567
0
    return CMD_WARNING_CONFIG_FAILED;
568
0
  case RMAP_COMPILE_SUCCESS:
569
0
    break;
570
0
  }
571
572
0
  return CMD_SUCCESS;
573
0
}
574
575
576
/* Master list of route map. */
577
struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
578
struct hash *route_map_master_hash = NULL;
579
580
static unsigned int route_map_hash_key_make(const void *p)
581
0
{
582
0
  const struct route_map *map = p;
583
0
  return string_hash_make(map->name);
584
0
}
585
586
static bool route_map_hash_cmp(const void *p1, const void *p2)
587
0
{
588
0
  const struct route_map *map1 = p1;
589
0
  const struct route_map *map2 = p2;
590
591
0
  if (!strcmp(map1->name, map2->name))
592
0
    return true;
593
594
0
  return false;
595
0
}
596
597
enum route_map_upd8_type {
598
  ROUTE_MAP_ADD = 1,
599
  ROUTE_MAP_DEL,
600
};
601
602
/* all possible route-map dependency types */
603
enum route_map_dep_type {
604
  ROUTE_MAP_DEP_RMAP = 1,
605
  ROUTE_MAP_DEP_CLIST,
606
  ROUTE_MAP_DEP_ECLIST,
607
  ROUTE_MAP_DEP_LCLIST,
608
  ROUTE_MAP_DEP_PLIST,
609
  ROUTE_MAP_DEP_ASPATH,
610
  ROUTE_MAP_DEP_FILTER,
611
  ROUTE_MAP_DEP_MAX,
612
};
613
614
struct route_map_dep {
615
  char *dep_name;
616
  struct hash *dep_rmap_hash;
617
  struct hash *this_hash; /* ptr to the hash structure this is part of */
618
};
619
620
struct route_map_dep_data {
621
  /* Route-map name.
622
   */
623
  char *rname;
624
  /* Count of number of sequences of this
625
   * route-map that depend on the same entity.
626
   */
627
  uint16_t  refcnt;
628
};
629
630
/* Hashes maintaining dependency between various sublists used by route maps */
631
static struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
632
633
static unsigned int route_map_dep_hash_make_key(const void *p);
634
static void route_map_clear_all_references(char *rmap_name);
635
static void route_map_rule_delete(struct route_map_rule_list *,
636
          struct route_map_rule *);
637
638
uint32_t rmap_debug;
639
640
/* New route map allocation. Please note route map's name must be
641
   specified. */
642
static struct route_map *route_map_new(const char *name)
643
0
{
644
0
  struct route_map *new;
645
646
0
  new = XCALLOC(MTYPE_ROUTE_MAP, sizeof(struct route_map));
647
0
  new->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
648
0
  QOBJ_REG(new, route_map);
649
0
  return new;
650
0
}
651
652
/* Add new name to route_map. */
653
static struct route_map *route_map_add(const char *name)
654
0
{
655
0
  struct route_map *map, *exist;
656
0
  struct route_map_list *list;
657
658
0
  map = route_map_new(name);
659
0
  list = &route_map_master;
660
661
  /*
662
   * Add map to the hash
663
   *
664
   * If the map already exists in the hash, then we know that
665
   * FRR is now in a sequence of delete/create.
666
   * All FRR needs to do here is set the to_be_processed
667
   * bit (to inherit from the old one
668
   */
669
0
  exist = hash_release(route_map_master_hash, map);
670
0
  if (exist) {
671
0
    map->to_be_processed = exist->to_be_processed;
672
0
    route_map_free_map(exist);
673
0
  }
674
0
  hash_get(route_map_master_hash, map, hash_alloc_intern);
675
676
  /* Add new entry to the head of the list to match how it is added in the
677
   * hash table. This is to ensure that if the same route-map has been
678
   * created more than once and then marked for deletion (which can happen
679
   * if prior deletions haven't completed as BGP hasn't yet done the
680
   * route-map processing), the order of the entities is the same in both
681
   * the list and the hash table. Otherwise, since there is nothing to
682
   * distinguish between the two entries, the wrong entry could get freed.
683
   * TODO: This needs to be re-examined to handle it better - e.g., revive
684
   * a deleted entry if the route-map is created again.
685
   */
686
0
  map->prev = NULL;
687
0
  map->next = list->head;
688
0
  if (list->head)
689
0
    list->head->prev = map;
690
0
  list->head = map;
691
0
  if (!list->tail)
692
0
    list->tail = map;
693
694
  /* Execute hook. */
695
0
  if (route_map_master.add_hook) {
696
0
    (*route_map_master.add_hook)(name);
697
0
    route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
698
0
  }
699
700
0
  if (!map->ipv4_prefix_table)
701
0
    map->ipv4_prefix_table = route_table_init();
702
703
0
  if (!map->ipv6_prefix_table)
704
0
    map->ipv6_prefix_table = route_table_init();
705
706
0
  if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
707
0
    zlog_debug("Add route-map %s", name);
708
0
  return map;
709
0
}
710
711
/* this is supposed to be called post processing by
712
 * the delete hook function. Don't invoke delete_hook
713
 * again in this routine.
714
 */
715
static void route_map_free_map(struct route_map *map)
716
0
{
717
0
  struct route_map_list *list;
718
0
  struct route_map_index *index;
719
720
0
  if (map == NULL)
721
0
    return;
722
723
0
  while ((index = map->head) != NULL)
724
0
    route_map_index_delete(index, 0);
725
726
0
  if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
727
0
    zlog_debug("Deleting route-map %s", map->name);
728
729
0
  list = &route_map_master;
730
731
0
  QOBJ_UNREG(map);
732
733
0
  if (map->next)
734
0
    map->next->prev = map->prev;
735
0
  else
736
0
    list->tail = map->prev;
737
738
0
  if (map->prev)
739
0
    map->prev->next = map->next;
740
0
  else
741
0
    list->head = map->next;
742
743
0
  route_table_finish(map->ipv4_prefix_table);
744
0
  route_table_finish(map->ipv6_prefix_table);
745
746
0
  hash_release(route_map_master_hash, map);
747
0
  XFREE(MTYPE_ROUTE_MAP_NAME, map->name);
748
0
  XFREE(MTYPE_ROUTE_MAP, map);
749
0
}
750
751
/* Route map delete from list. */
752
void route_map_delete(struct route_map *map)
753
0
{
754
0
  struct route_map_index *index;
755
0
  char *name;
756
757
0
  while ((index = map->head) != NULL)
758
0
    route_map_index_delete(index, 0);
759
760
0
  name = map->name;
761
0
  map->head = NULL;
762
763
  /* Clear all dependencies */
764
0
  route_map_clear_all_references(name);
765
0
  map->deleted = true;
766
  /* Execute deletion hook. */
767
0
  if (route_map_master.delete_hook) {
768
0
    (*route_map_master.delete_hook)(name);
769
0
    route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
770
0
  }
771
772
0
  if (!map->to_be_processed) {
773
0
    route_map_free_map(map);
774
0
  }
775
0
}
776
777
/* Lookup route map by route map name string. */
778
struct route_map *route_map_lookup_by_name(const char *name)
779
0
{
780
0
  struct route_map *map;
781
0
  struct route_map tmp_map;
782
783
0
  if (!name)
784
0
    return NULL;
785
786
  // map.deleted is false via memset
787
0
  memset(&tmp_map, 0, sizeof(tmp_map));
788
0
  tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
789
0
  map = hash_lookup(route_map_master_hash, &tmp_map);
790
0
  XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
791
792
0
  if (map && map->deleted)
793
0
    return NULL;
794
795
0
  return map;
796
0
}
797
798
/* Simple helper to warn if route-map does not exist. */
799
struct route_map *route_map_lookup_warn_noexist(struct vty *vty, const char *name)
800
0
{
801
0
  struct route_map *route_map = route_map_lookup_by_name(name);
802
803
0
  if (!route_map)
804
0
    if (vty_shell_serv(vty))
805
0
      vty_out(vty, "The route-map '%s' does not exist.\n", name);
806
807
0
  return route_map;
808
0
}
809
810
int route_map_mark_updated(const char *name)
811
0
{
812
0
  struct route_map *map;
813
0
  int ret = -1;
814
0
  struct route_map tmp_map;
815
816
0
  if (!name)
817
0
    return (ret);
818
819
0
  map = route_map_lookup_by_name(name);
820
821
  /* If we did not find the routemap with deleted=false try again
822
   * with deleted=true
823
   */
824
0
  if (!map) {
825
0
    memset(&tmp_map, 0, sizeof(tmp_map));
826
0
    tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
827
0
    tmp_map.deleted = true;
828
0
    map = hash_lookup(route_map_master_hash, &tmp_map);
829
0
    XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
830
0
  }
831
832
0
  if (map) {
833
0
    map->to_be_processed = true;
834
0
    ret = 0;
835
0
  }
836
837
0
  return (ret);
838
0
}
839
840
static void route_map_clear_updated(struct route_map *map)
841
0
{
842
0
  if (map) {
843
0
    map->to_be_processed = false;
844
0
    if (map->deleted)
845
0
      route_map_free_map(map);
846
0
  }
847
0
}
848
849
/* Lookup route map.  If there isn't route map create one and return
850
   it. */
851
struct route_map *route_map_get(const char *name)
852
0
{
853
0
  struct route_map *map;
854
855
0
  map = route_map_lookup_by_name(name);
856
0
  if (map == NULL)
857
0
    map = route_map_add(name);
858
859
0
  return map;
860
0
}
861
862
void route_map_walk_update_list(void (*route_map_update_fn)(char *name))
863
0
{
864
0
  struct route_map *node;
865
0
  struct route_map *nnode = NULL;
866
867
0
  for (node = route_map_master.head; node; node = nnode) {
868
0
    if (node->to_be_processed) {
869
      /* DD: Should we add any thread yield code here */
870
0
      route_map_update_fn(node->name);
871
0
      nnode = node->next;
872
0
      route_map_clear_updated(node);
873
0
    } else
874
0
      nnode = node->next;
875
0
  }
876
0
}
877
878
/* Return route map's type string. */
879
static const char *route_map_type_str(enum route_map_type type)
880
0
{
881
0
  switch (type) {
882
0
  case RMAP_PERMIT:
883
0
    return "permit";
884
0
  case RMAP_DENY:
885
0
    return "deny";
886
0
  case RMAP_ANY:
887
0
    return "";
888
0
  }
889
890
0
  return "";
891
0
}
892
893
static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res)
894
0
{
895
0
  switch (res) {
896
0
  case RMAP_MATCH:
897
0
    return "match";
898
0
  case RMAP_NOMATCH:
899
0
    return "no match";
900
0
  case RMAP_NOOP:
901
0
    return "noop";
902
0
  case RMAP_ERROR:
903
0
    return "error";
904
0
  case RMAP_OKAY:
905
0
    return "okay";
906
0
  }
907
0
908
0
  return "invalid";
909
0
}
910
911
static const char *route_map_result_str(route_map_result_t res)
912
0
{
913
0
  switch (res) {
914
0
  case RMAP_DENYMATCH:
915
0
    return "deny";
916
0
  case RMAP_PERMITMATCH:
917
0
    return "permit";
918
0
  }
919
0
920
0
  return "invalid";
921
0
}
922
923
/* show route-map */
924
static void vty_show_route_map_entry(struct vty *vty, struct route_map *map,
925
             json_object *json)
926
0
{
927
0
  struct route_map_index *index;
928
0
  struct route_map_rule *rule;
929
0
  json_object *json_rmap = NULL;
930
0
  json_object *json_rules = NULL;
931
932
0
  if (json) {
933
0
    json_rmap = json_object_new_object();
934
0
    json_object_object_add(json, map->name, json_rmap);
935
936
0
    json_rules = json_object_new_array();
937
0
    json_object_int_add(json_rmap, "invoked",
938
0
            map->applied - map->applied_clear);
939
0
    json_object_boolean_add(json_rmap, "disabledOptimization",
940
0
          map->optimization_disabled);
941
0
    json_object_boolean_add(json_rmap, "processedChange",
942
0
          map->to_be_processed);
943
0
    json_object_object_add(json_rmap, "rules", json_rules);
944
0
  } else {
945
0
    vty_out(vty,
946
0
      "route-map: %s Invoked: %" PRIu64
947
0
      " Optimization: %s Processed Change: %s\n",
948
0
      map->name, map->applied - map->applied_clear,
949
0
      map->optimization_disabled ? "disabled" : "enabled",
950
0
      map->to_be_processed ? "true" : "false");
951
0
  }
952
953
0
  for (index = map->head; index; index = index->next) {
954
0
    if (json) {
955
0
      json_object *json_rule;
956
0
      json_object *json_matches;
957
0
      json_object *json_sets;
958
0
      char action[BUFSIZ] = {};
959
960
0
      json_rule = json_object_new_object();
961
0
      json_object_array_add(json_rules, json_rule);
962
963
0
      json_object_int_add(json_rule, "sequenceNumber",
964
0
              index->pref);
965
0
      json_object_string_add(json_rule, "type",
966
0
                 route_map_type_str(index->type));
967
0
      json_object_int_add(json_rule, "invoked",
968
0
              index->applied
969
0
                - index->applied_clear);
970
971
      /* Description */
972
0
      if (index->description)
973
0
        json_object_string_add(json_rule, "description",
974
0
                   index->description);
975
976
      /* Match clauses */
977
0
      json_matches = json_object_new_array();
978
0
      json_object_object_add(json_rule, "matchClauses",
979
0
                 json_matches);
980
0
      for (rule = index->match_list.head; rule;
981
0
           rule = rule->next) {
982
0
        char buf[BUFSIZ];
983
984
0
        snprintf(buf, sizeof(buf), "%s %s",
985
0
           rule->cmd->str, rule->rule_str);
986
0
        json_array_string_add(json_matches, buf);
987
0
      }
988
989
      /* Set clauses */
990
0
      json_sets = json_object_new_array();
991
0
      json_object_object_add(json_rule, "setClauses",
992
0
                 json_sets);
993
0
      for (rule = index->set_list.head; rule;
994
0
           rule = rule->next) {
995
0
        char buf[BUFSIZ];
996
997
0
        snprintf(buf, sizeof(buf), "%s %s",
998
0
           rule->cmd->str, rule->rule_str);
999
0
        json_array_string_add(json_sets, buf);
1000
0
      }
1001
1002
      /* Call clause */
1003
0
      if (index->nextrm)
1004
0
        json_object_string_add(json_rule, "callClause",
1005
0
                   index->nextrm);
1006
1007
      /* Exit Policy */
1008
0
      if (index->exitpolicy == RMAP_GOTO)
1009
0
        snprintf(action, sizeof(action), "Goto %d",
1010
0
           index->nextpref);
1011
0
      else if (index->exitpolicy == RMAP_NEXT)
1012
0
        snprintf(action, sizeof(action),
1013
0
           "Continue to next entry");
1014
0
      else if (index->exitpolicy == RMAP_EXIT)
1015
0
        snprintf(action, sizeof(action),
1016
0
           "Exit routemap");
1017
0
      if (action[0] != '\0')
1018
0
        json_object_string_add(json_rule, "action",
1019
0
                   action);
1020
0
    } else {
1021
0
      vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
1022
0
        route_map_type_str(index->type), index->pref,
1023
0
        index->applied - index->applied_clear);
1024
1025
      /* Description */
1026
0
      if (index->description)
1027
0
        vty_out(vty, "  Description:\n    %s\n",
1028
0
          index->description);
1029
1030
      /* Match clauses */
1031
0
      vty_out(vty, "  Match clauses:\n");
1032
0
      for (rule = index->match_list.head; rule;
1033
0
           rule = rule->next)
1034
0
        vty_out(vty, "    %s %s\n", rule->cmd->str,
1035
0
          rule->rule_str);
1036
1037
      /* Set clauses */
1038
0
      vty_out(vty, "  Set clauses:\n");
1039
0
      for (rule = index->set_list.head; rule;
1040
0
           rule = rule->next)
1041
0
        vty_out(vty, "    %s %s\n", rule->cmd->str,
1042
0
          rule->rule_str);
1043
1044
      /* Call clause */
1045
0
      vty_out(vty, "  Call clause:\n");
1046
0
      if (index->nextrm)
1047
0
        vty_out(vty, "    Call %s\n", index->nextrm);
1048
1049
      /* Exit Policy */
1050
0
      vty_out(vty, "  Action:\n");
1051
0
      if (index->exitpolicy == RMAP_GOTO)
1052
0
        vty_out(vty, "    Goto %d\n", index->nextpref);
1053
0
      else if (index->exitpolicy == RMAP_NEXT)
1054
0
        vty_out(vty, "    Continue to next entry\n");
1055
0
      else if (index->exitpolicy == RMAP_EXIT)
1056
0
        vty_out(vty, "    Exit routemap\n");
1057
0
    }
1058
0
  }
1059
0
}
1060
1061
static int sort_route_map(const void **map1, const void **map2)
1062
0
{
1063
0
  const struct route_map *m1 = *map1;
1064
0
  const struct route_map *m2 = *map2;
1065
1066
0
  return strcmp(m1->name, m2->name);
1067
0
}
1068
1069
static int vty_show_route_map(struct vty *vty, const char *name, bool use_json)
1070
0
{
1071
0
  struct route_map *map;
1072
0
  json_object *json = NULL;
1073
0
  json_object *json_proto = NULL;
1074
1075
0
  if (use_json) {
1076
0
    json = json_object_new_object();
1077
0
    json_proto = json_object_new_object();
1078
0
    json_object_object_add(json, frr_protonameinst, json_proto);
1079
0
  } else
1080
0
    vty_out(vty, "%s:\n", frr_protonameinst);
1081
1082
0
  if (name) {
1083
0
    map = route_map_lookup_by_name(name);
1084
1085
0
    if (map) {
1086
0
      vty_show_route_map_entry(vty, map, json_proto);
1087
0
    } else if (!use_json) {
1088
0
      vty_out(vty, "%s: 'route-map %s' not found\n",
1089
0
        frr_protonameinst, name);
1090
0
    }
1091
0
  } else {
1092
1093
0
    struct list *maplist = list_new();
1094
0
    struct listnode *ln;
1095
1096
0
    for (map = route_map_master.head; map; map = map->next)
1097
0
      listnode_add(maplist, map);
1098
1099
0
    list_sort(maplist, sort_route_map);
1100
1101
0
    for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
1102
0
      vty_show_route_map_entry(vty, map, json_proto);
1103
1104
0
    list_delete(&maplist);
1105
0
  }
1106
1107
0
  return vty_json(vty, json);
1108
0
}
1109
1110
/* Unused route map details */
1111
static int vty_show_unused_route_map(struct vty *vty)
1112
0
{
1113
0
  struct list *maplist = list_new();
1114
0
  struct listnode *ln;
1115
0
  struct route_map *map;
1116
1117
0
  for (map = route_map_master.head; map; map = map->next) {
1118
    /* If use_count is zero, No protocol is using this routemap.
1119
     * so adding to the list.
1120
     */
1121
0
    if (!map->use_count)
1122
0
      listnode_add(maplist, map);
1123
0
  }
1124
1125
0
  if (maplist->count > 0) {
1126
0
    vty_out(vty, "\n%s:\n", frr_protonameinst);
1127
0
    list_sort(maplist, sort_route_map);
1128
1129
0
    for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
1130
0
      vty_show_route_map_entry(vty, map, NULL);
1131
0
  } else {
1132
0
    vty_out(vty, "\n%s: None\n", frr_protonameinst);
1133
0
  }
1134
1135
0
  list_delete(&maplist);
1136
0
  return CMD_SUCCESS;
1137
0
}
1138
1139
/* New route map allocation. Please note route map's name must be
1140
   specified. */
1141
static struct route_map_index *route_map_index_new(void)
1142
0
{
1143
0
  struct route_map_index *new;
1144
1145
0
  new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
1146
0
  new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
1147
0
  TAILQ_INIT(&new->rhclist);
1148
0
  QOBJ_REG(new, route_map_index);
1149
0
  return new;
1150
0
}
1151
1152
/* Free route map index. */
1153
void route_map_index_delete(struct route_map_index *index, int notify)
1154
0
{
1155
0
  struct routemap_hook_context *rhc;
1156
0
  struct route_map_rule *rule;
1157
1158
0
  QOBJ_UNREG(index);
1159
1160
0
  if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
1161
0
    zlog_debug("Deleting route-map %s sequence %d",
1162
0
         index->map->name, index->pref);
1163
1164
  /* Free route map entry description. */
1165
0
  XFREE(MTYPE_TMP, index->description);
1166
1167
  /* Free route map northbound hook contexts. */
1168
0
  while ((rhc = TAILQ_FIRST(&index->rhclist)) != NULL)
1169
0
    routemap_hook_context_free(rhc);
1170
1171
  /* Free route match. */
1172
0
  while ((rule = index->match_list.head) != NULL) {
1173
0
    if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
1174
0
      route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED,
1175
0
             index, AFI_IP, rule->rule_str);
1176
0
    else if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
1177
0
      route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED,
1178
0
             index, AFI_IP6,
1179
0
             rule->rule_str);
1180
1181
0
    route_map_rule_delete(&index->match_list, rule);
1182
0
  }
1183
1184
  /* Free route set. */
1185
0
  while ((rule = index->set_list.head) != NULL)
1186
0
    route_map_rule_delete(&index->set_list, rule);
1187
1188
  /* Remove index from route map list. */
1189
0
  if (index->next)
1190
0
    index->next->prev = index->prev;
1191
0
  else
1192
0
    index->map->tail = index->prev;
1193
1194
0
  if (index->prev)
1195
0
    index->prev->next = index->next;
1196
0
  else
1197
0
    index->map->head = index->next;
1198
1199
  /* Free 'char *nextrm' if not NULL */
1200
0
  XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
1201
1202
0
  route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED, index, 0, NULL);
1203
1204
  /* Execute event hook. */
1205
0
  if (route_map_master.event_hook && notify) {
1206
0
    (*route_map_master.event_hook)(index->map->name);
1207
0
    route_map_notify_dependencies(index->map->name,
1208
0
                RMAP_EVENT_CALL_ADDED);
1209
0
  }
1210
0
  XFREE(MTYPE_ROUTE_MAP_INDEX, index);
1211
0
}
1212
1213
/* Lookup index from route map. */
1214
static struct route_map_index *route_map_index_lookup(struct route_map *map,
1215
                  enum route_map_type type,
1216
                  int pref)
1217
0
{
1218
0
  struct route_map_index *index;
1219
1220
0
  for (index = map->head; index; index = index->next)
1221
0
    if ((index->type == type || type == RMAP_ANY)
1222
0
        && index->pref == pref)
1223
0
      return index;
1224
0
  return NULL;
1225
0
}
1226
1227
/* Add new index to route map. */
1228
static struct route_map_index *
1229
route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
1230
0
{
1231
0
  struct route_map_index *index;
1232
0
  struct route_map_index *point;
1233
1234
  /* Allocate new route map inex. */
1235
0
  index = route_map_index_new();
1236
0
  index->map = map;
1237
0
  index->type = type;
1238
0
  index->pref = pref;
1239
1240
  /* Compare preference. */
1241
0
  for (point = map->head; point; point = point->next)
1242
0
    if (point->pref >= pref)
1243
0
      break;
1244
1245
0
  if (map->head == NULL) {
1246
0
    map->head = map->tail = index;
1247
0
  } else if (point == NULL) {
1248
0
    index->prev = map->tail;
1249
0
    map->tail->next = index;
1250
0
    map->tail = index;
1251
0
  } else if (point == map->head) {
1252
0
    index->next = map->head;
1253
0
    map->head->prev = index;
1254
0
    map->head = index;
1255
0
  } else {
1256
0
    index->next = point;
1257
0
    index->prev = point->prev;
1258
0
    if (point->prev)
1259
0
      point->prev->next = index;
1260
0
    point->prev = index;
1261
0
  }
1262
1263
0
  route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED, index, 0, NULL);
1264
1265
  /* Execute event hook. */
1266
0
  if (route_map_master.event_hook) {
1267
0
    (*route_map_master.event_hook)(map->name);
1268
0
    route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
1269
0
  }
1270
1271
0
  if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
1272
0
    zlog_debug("Route-map %s add sequence %d, type: %s",
1273
0
         map->name, pref, route_map_type_str(type));
1274
1275
0
  return index;
1276
0
}
1277
1278
/* Get route map index. */
1279
struct route_map_index *
1280
route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
1281
0
{
1282
0
  struct route_map_index *index;
1283
1284
0
  index = route_map_index_lookup(map, RMAP_ANY, pref);
1285
0
  if (index && index->type != type) {
1286
    /* Delete index from route map. */
1287
0
    route_map_index_delete(index, 1);
1288
0
    index = NULL;
1289
0
  }
1290
0
  if (index == NULL)
1291
0
    index = route_map_index_add(map, type, pref);
1292
0
  return index;
1293
0
}
1294
1295
/* New route map rule */
1296
static struct route_map_rule *route_map_rule_new(void)
1297
0
{
1298
0
  struct route_map_rule *new;
1299
1300
0
  new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
1301
0
  return new;
1302
0
}
1303
1304
/* Install rule command to the match list. */
1305
void _route_map_install_match(struct route_map_rule_cmd_proxy *proxy)
1306
57
{
1307
57
  rmap_cmd_name_add(rmap_match_cmds, proxy);
1308
57
}
1309
1310
/* Install rule command to the set list. */
1311
void _route_map_install_set(struct route_map_rule_cmd_proxy *proxy)
1312
42
{
1313
42
  rmap_cmd_name_add(rmap_set_cmds, proxy);
1314
42
}
1315
1316
/* Lookup rule command from match list. */
1317
static const struct route_map_rule_cmd *route_map_lookup_match(const char *name)
1318
0
{
1319
0
  struct route_map_rule_cmd refcmd = {.str = name};
1320
0
  struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd};
1321
0
  struct route_map_rule_cmd_proxy *res;
1322
1323
0
  res = rmap_cmd_name_find(rmap_match_cmds, &ref);
1324
0
  if (res)
1325
0
    return res->cmd;
1326
0
  return NULL;
1327
0
}
1328
1329
/* Lookup rule command from set list. */
1330
static const struct route_map_rule_cmd *route_map_lookup_set(const char *name)
1331
0
{
1332
0
  struct route_map_rule_cmd refcmd = {.str = name};
1333
0
  struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd};
1334
0
  struct route_map_rule_cmd_proxy *res;
1335
1336
0
  res = rmap_cmd_name_find(rmap_set_cmds, &ref);
1337
0
  if (res)
1338
0
    return res->cmd;
1339
0
  return NULL;
1340
0
}
1341
1342
/* Add match and set rule to rule list. */
1343
static void route_map_rule_add(struct route_map_rule_list *list,
1344
             struct route_map_rule *rule)
1345
0
{
1346
0
  rule->next = NULL;
1347
0
  rule->prev = list->tail;
1348
0
  if (list->tail)
1349
0
    list->tail->next = rule;
1350
0
  else
1351
0
    list->head = rule;
1352
0
  list->tail = rule;
1353
0
}
1354
1355
/* Delete rule from rule list. */
1356
static void route_map_rule_delete(struct route_map_rule_list *list,
1357
          struct route_map_rule *rule)
1358
0
{
1359
0
  if (rule->cmd->func_free)
1360
0
    (*rule->cmd->func_free)(rule->value);
1361
1362
0
  XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
1363
1364
0
  if (rule->next)
1365
0
    rule->next->prev = rule->prev;
1366
0
  else
1367
0
    list->tail = rule->prev;
1368
0
  if (rule->prev)
1369
0
    rule->prev->next = rule->next;
1370
0
  else
1371
0
    list->head = rule->next;
1372
1373
0
  XFREE(MTYPE_ROUTE_MAP_RULE, rule);
1374
0
}
1375
1376
/* strcmp wrapper function which don't crush even argument is NULL. */
1377
static int rulecmp(const char *dst, const char *src)
1378
0
{
1379
0
  if (dst == NULL) {
1380
0
    if (src == NULL)
1381
0
      return 0;
1382
0
    else
1383
0
      return 1;
1384
0
  } else {
1385
0
    if (src == NULL)
1386
0
      return 1;
1387
0
    else
1388
0
      return strcmp(dst, src);
1389
0
  }
1390
0
  return 1;
1391
0
}
1392
1393
/* Use this to return the already specified argument for this match. This is
1394
 * useful to get the specified argument with a route map match rule when the
1395
 * rule is being deleted and the argument is not provided.
1396
 */
1397
const char *route_map_get_match_arg(struct route_map_index *index,
1398
            const char *match_name)
1399
0
{
1400
0
  struct route_map_rule *rule;
1401
0
  const struct route_map_rule_cmd *cmd;
1402
1403
  /* First lookup rule for add match statement. */
1404
0
  cmd = route_map_lookup_match(match_name);
1405
0
  if (cmd == NULL)
1406
0
    return NULL;
1407
1408
0
  for (rule = index->match_list.head; rule; rule = rule->next)
1409
0
    if (rule->cmd == cmd && rule->rule_str != NULL)
1410
0
      return (rule->rule_str);
1411
1412
0
  return NULL;
1413
0
}
1414
1415
static route_map_event_t get_route_map_delete_event(route_map_event_t type)
1416
0
{
1417
0
  switch (type) {
1418
0
  case RMAP_EVENT_CALL_ADDED:
1419
0
    return RMAP_EVENT_CALL_DELETED;
1420
0
  case RMAP_EVENT_PLIST_ADDED:
1421
0
    return RMAP_EVENT_PLIST_DELETED;
1422
0
  case RMAP_EVENT_CLIST_ADDED:
1423
0
    return RMAP_EVENT_CLIST_DELETED;
1424
0
  case RMAP_EVENT_ECLIST_ADDED:
1425
0
    return RMAP_EVENT_ECLIST_DELETED;
1426
0
  case RMAP_EVENT_LLIST_ADDED:
1427
0
    return RMAP_EVENT_LLIST_DELETED;
1428
0
  case RMAP_EVENT_ASLIST_ADDED:
1429
0
    return RMAP_EVENT_ASLIST_DELETED;
1430
0
  case RMAP_EVENT_FILTER_ADDED:
1431
0
    return RMAP_EVENT_FILTER_DELETED;
1432
0
  case RMAP_EVENT_SET_ADDED:
1433
0
  case RMAP_EVENT_SET_DELETED:
1434
0
  case RMAP_EVENT_SET_REPLACED:
1435
0
  case RMAP_EVENT_MATCH_ADDED:
1436
0
  case RMAP_EVENT_MATCH_DELETED:
1437
0
  case RMAP_EVENT_MATCH_REPLACED:
1438
0
  case RMAP_EVENT_INDEX_ADDED:
1439
0
  case RMAP_EVENT_INDEX_DELETED:
1440
0
  case RMAP_EVENT_CALL_DELETED:
1441
0
  case RMAP_EVENT_PLIST_DELETED:
1442
0
  case RMAP_EVENT_CLIST_DELETED:
1443
0
  case RMAP_EVENT_ECLIST_DELETED:
1444
0
  case RMAP_EVENT_LLIST_DELETED:
1445
0
  case RMAP_EVENT_ASLIST_DELETED:
1446
0
  case RMAP_EVENT_FILTER_DELETED:
1447
    /* This function returns the appropriate 'deleted' event type
1448
     * for every 'added' event type passed to this function.
1449
     * This is done only for named entities used in the
1450
     * route-map match commands.
1451
     * This function is not to be invoked for any of the other event
1452
     * types.
1453
     */
1454
0
    assert(0);
1455
0
  }
1456
1457
0
  assert(0);
1458
  /*
1459
   * Return to make c happy but if we get here something has gone
1460
   * terribly terribly wrong, so yes this return makes no sense.
1461
   */
1462
0
  return RMAP_EVENT_CALL_ADDED;
1463
0
}
1464
1465
/* Add match statement to route map. */
1466
enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
1467
             const char *match_name,
1468
             const char *match_arg,
1469
             route_map_event_t type)
1470
0
{
1471
0
  struct route_map_rule *rule;
1472
0
  struct route_map_rule *next;
1473
0
  const struct route_map_rule_cmd *cmd;
1474
0
  void *compile;
1475
0
  int8_t delete_rmap_event_type = 0;
1476
0
  const char *rule_key;
1477
1478
  /* First lookup rule for add match statement. */
1479
0
  cmd = route_map_lookup_match(match_name);
1480
0
  if (cmd == NULL)
1481
0
    return RMAP_RULE_MISSING;
1482
1483
  /* Next call compile function for this match statement. */
1484
0
  if (cmd->func_compile) {
1485
0
    compile = (*cmd->func_compile)(match_arg);
1486
0
    if (compile == NULL)
1487
0
      return RMAP_COMPILE_ERROR;
1488
0
  } else
1489
0
    compile = NULL;
1490
  /* use the compiled results if applicable */
1491
0
  if (compile && cmd->func_get_rmap_rule_key)
1492
0
    rule_key = (*cmd->func_get_rmap_rule_key)
1493
0
         (compile);
1494
0
  else
1495
0
    rule_key = match_arg;
1496
1497
  /* If argument is completely same ignore it. */
1498
0
  for (rule = index->match_list.head; rule; rule = next) {
1499
0
    next = rule->next;
1500
0
    if (rule->cmd == cmd) {
1501
      /* If the configured route-map match rule is exactly
1502
       * the same as the existing configuration then,
1503
       * ignore the duplicate configuration.
1504
       */
1505
0
      if (rulecmp(match_arg, rule->rule_str) == 0) {
1506
0
        if (cmd->func_free)
1507
0
          (*cmd->func_free)(compile);
1508
1509
0
        return RMAP_COMPILE_SUCCESS;
1510
0
      }
1511
1512
      /* If IPv4 or IPv6 prefix-list match criteria
1513
       * has been delete to the route-map index, update
1514
       * the route-map's prefix table.
1515
       */
1516
0
      if (IS_RULE_IPv4_PREFIX_LIST(match_name))
1517
0
        route_map_pfx_tbl_update(
1518
0
          RMAP_EVENT_PLIST_DELETED, index, AFI_IP,
1519
0
          rule->rule_str);
1520
0
      else if (IS_RULE_IPv6_PREFIX_LIST(match_name))
1521
0
        route_map_pfx_tbl_update(
1522
0
          RMAP_EVENT_PLIST_DELETED, index,
1523
0
          AFI_IP6, rule->rule_str);
1524
1525
      /* Remove the dependency of the route-map on the rule
1526
       * that is being replaced.
1527
       */
1528
0
      if (type >= RMAP_EVENT_CALL_ADDED) {
1529
0
        delete_rmap_event_type =
1530
0
          get_route_map_delete_event(type);
1531
0
        route_map_upd8_dependency(
1532
0
              delete_rmap_event_type,
1533
0
              rule->rule_str,
1534
0
              index->map->name);
1535
0
      }
1536
1537
0
      route_map_rule_delete(&index->match_list, rule);
1538
0
    }
1539
0
  }
1540
1541
  /* Add new route map match rule. */
1542
0
  rule = route_map_rule_new();
1543
0
  rule->cmd = cmd;
1544
0
  rule->value = compile;
1545
0
  if (match_arg)
1546
0
    rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1547
0
  else
1548
0
    rule->rule_str = NULL;
1549
1550
  /* Add new route match rule to linked list. */
1551
0
  route_map_rule_add(&index->match_list, rule);
1552
1553
  /* If IPv4 or IPv6 prefix-list match criteria
1554
   * has been added to the route-map index, update
1555
   * the route-map's prefix table.
1556
   */
1557
0
  if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
1558
0
    route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP,
1559
0
           match_arg);
1560
0
  } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
1561
0
    route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP6,
1562
0
           match_arg);
1563
0
  }
1564
1565
  /* Execute event hook. */
1566
0
  if (route_map_master.event_hook) {
1567
0
    (*route_map_master.event_hook)(index->map->name);
1568
0
    route_map_notify_dependencies(index->map->name,
1569
0
                RMAP_EVENT_CALL_ADDED);
1570
0
  }
1571
0
  if (type != RMAP_EVENT_MATCH_ADDED)
1572
0
    route_map_upd8_dependency(type, rule_key, index->map->name);
1573
1574
0
  return RMAP_COMPILE_SUCCESS;
1575
0
}
1576
1577
/* Delete specified route match rule. */
1578
enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
1579
                const char *match_name,
1580
                const char *match_arg,
1581
                route_map_event_t type)
1582
0
{
1583
0
  struct route_map_rule *rule;
1584
0
  const struct route_map_rule_cmd *cmd;
1585
0
  const char *rule_key;
1586
1587
0
  cmd = route_map_lookup_match(match_name);
1588
0
  if (cmd == NULL)
1589
0
    return RMAP_RULE_MISSING;
1590
1591
0
  for (rule = index->match_list.head; rule; rule = rule->next)
1592
0
    if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1593
0
           || match_arg == NULL)) {
1594
      /* Execute event hook. */
1595
0
      if (route_map_master.event_hook) {
1596
0
        (*route_map_master.event_hook)(index->map->name);
1597
0
        route_map_notify_dependencies(
1598
0
          index->map->name,
1599
0
          RMAP_EVENT_CALL_ADDED);
1600
0
      }
1601
0
      if (cmd->func_get_rmap_rule_key)
1602
0
        rule_key = (*cmd->func_get_rmap_rule_key)
1603
0
             (rule->value);
1604
0
      else
1605
0
        rule_key = match_arg;
1606
1607
0
      if (type != RMAP_EVENT_MATCH_DELETED && rule_key)
1608
0
        route_map_upd8_dependency(type, rule_key,
1609
0
            index->map->name);
1610
1611
0
      route_map_rule_delete(&index->match_list, rule);
1612
1613
      /* If IPv4 or IPv6 prefix-list match criteria
1614
       * has been delete from the route-map index, update
1615
       * the route-map's prefix table.
1616
       */
1617
0
      if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
1618
0
        route_map_pfx_tbl_update(
1619
0
          RMAP_EVENT_PLIST_DELETED, index, AFI_IP,
1620
0
          match_arg);
1621
0
      } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
1622
0
        route_map_pfx_tbl_update(
1623
0
          RMAP_EVENT_PLIST_DELETED, index,
1624
0
          AFI_IP6, match_arg);
1625
0
      }
1626
1627
0
      return RMAP_COMPILE_SUCCESS;
1628
0
    }
1629
  /* Can't find matched rule. */
1630
0
  return RMAP_RULE_MISSING;
1631
0
}
1632
1633
/* Add route-map set statement to the route map. */
1634
enum rmap_compile_rets route_map_add_set(struct route_map_index *index,
1635
           const char *set_name,
1636
           const char *set_arg)
1637
0
{
1638
0
  struct route_map_rule *rule;
1639
0
  struct route_map_rule *next;
1640
0
  const struct route_map_rule_cmd *cmd;
1641
0
  void *compile;
1642
1643
0
  cmd = route_map_lookup_set(set_name);
1644
0
  if (cmd == NULL)
1645
0
    return RMAP_RULE_MISSING;
1646
1647
  /* Next call compile function for this match statement. */
1648
0
  if (cmd->func_compile) {
1649
0
    compile = (*cmd->func_compile)(set_arg);
1650
0
    if (compile == NULL)
1651
0
      return RMAP_COMPILE_ERROR;
1652
0
  } else
1653
0
    compile = NULL;
1654
1655
  /* Add by WJL. if old set command of same kind exist, delete it first
1656
     to ensure only one set command of same kind exist under a
1657
     route_map_index. */
1658
0
  for (rule = index->set_list.head; rule; rule = next) {
1659
0
    next = rule->next;
1660
0
    if (rule->cmd == cmd)
1661
0
      route_map_rule_delete(&index->set_list, rule);
1662
0
  }
1663
1664
  /* Add new route map match rule. */
1665
0
  rule = route_map_rule_new();
1666
0
  rule->cmd = cmd;
1667
0
  rule->value = compile;
1668
0
  if (set_arg)
1669
0
    rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1670
0
  else
1671
0
    rule->rule_str = NULL;
1672
1673
  /* Add new route match rule to linked list. */
1674
0
  route_map_rule_add(&index->set_list, rule);
1675
1676
  /* Execute event hook. */
1677
0
  if (route_map_master.event_hook) {
1678
0
    (*route_map_master.event_hook)(index->map->name);
1679
0
    route_map_notify_dependencies(index->map->name,
1680
0
                RMAP_EVENT_CALL_ADDED);
1681
0
  }
1682
0
  return RMAP_COMPILE_SUCCESS;
1683
0
}
1684
1685
/* Delete route map set rule. */
1686
enum rmap_compile_rets route_map_delete_set(struct route_map_index *index,
1687
              const char *set_name,
1688
              const char *set_arg)
1689
0
{
1690
0
  struct route_map_rule *rule;
1691
0
  const struct route_map_rule_cmd *cmd;
1692
1693
0
  cmd = route_map_lookup_set(set_name);
1694
0
  if (cmd == NULL)
1695
0
    return RMAP_RULE_MISSING;
1696
1697
0
  for (rule = index->set_list.head; rule; rule = rule->next)
1698
0
    if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1699
0
             || set_arg == NULL)) {
1700
0
      route_map_rule_delete(&index->set_list, rule);
1701
      /* Execute event hook. */
1702
0
      if (route_map_master.event_hook) {
1703
0
        (*route_map_master.event_hook)(index->map->name);
1704
0
        route_map_notify_dependencies(
1705
0
          index->map->name,
1706
0
          RMAP_EVENT_CALL_ADDED);
1707
0
      }
1708
0
      return RMAP_COMPILE_SUCCESS;
1709
0
    }
1710
  /* Can't find matched rule. */
1711
0
  return RMAP_RULE_MISSING;
1712
0
}
1713
1714
static enum route_map_cmd_result_t
1715
route_map_apply_match(struct route_map_rule_list *match_list,
1716
          const struct prefix *prefix, void *object)
1717
0
{
1718
0
  enum route_map_cmd_result_t ret = RMAP_NOMATCH;
1719
0
  struct route_map_rule *match;
1720
0
  bool is_matched = false;
1721
1722
1723
  /* Check all match rule and if there is no match rule, go to the
1724
     set statement. */
1725
0
  if (!match_list->head)
1726
0
    ret = RMAP_MATCH;
1727
0
  else {
1728
0
    for (match = match_list->head; match; match = match->next) {
1729
      /*
1730
       * Try each match statement. If any match does not
1731
       * return RMAP_MATCH or RMAP_NOOP, return.
1732
       * Otherwise continue on to next match statement.
1733
       * All match statements must MATCH for
1734
       * end-result to be a match.
1735
       * (Exception:If match stmts result in a mix of
1736
       * MATCH/NOOP, then also end-result is a match)
1737
       * If all result in NOOP, end-result is NOOP.
1738
       */
1739
0
      ret = (*match->cmd->func_apply)(match->value, prefix,
1740
0
              object);
1741
1742
      /*
1743
       * If the consolidated result of func_apply is:
1744
       *   -----------------------------------------------
1745
       *   |  MATCH  | NOMATCH  |  NOOP   |  Final Result |
1746
       *   ------------------------------------------------
1747
       *   |   yes   |   yes    |  yes    |     NOMATCH   |
1748
       *   |   no    |   no     |  yes    |     NOOP      |
1749
       *   |   yes   |   no     |  yes    |     MATCH     |
1750
       *   |   no    |   yes    |  yes    |     NOMATCH   |
1751
       *   |-----------------------------------------------
1752
       *
1753
       *  Traditionally, all rules within route-map
1754
       *  should match for it to MATCH.
1755
       *  If there are noops within the route-map rules,
1756
       *  it follows the above matrix.
1757
       *
1758
       *   Eg: route-map rm1 permit 10
1759
       *         match rule1
1760
       *         match rule2
1761
       *         match rule3
1762
       *         ....
1763
       *       route-map rm1 permit 20
1764
       *         match ruleX
1765
       *         match ruleY
1766
       *         ...
1767
       */
1768
1769
0
      switch (ret) {
1770
0
      case RMAP_MATCH:
1771
0
        is_matched = true;
1772
0
        break;
1773
1774
0
      case RMAP_NOMATCH:
1775
0
        return ret;
1776
1777
0
      case RMAP_NOOP:
1778
0
        if (is_matched)
1779
0
          ret = RMAP_MATCH;
1780
0
        break;
1781
1782
0
      case RMAP_OKAY:
1783
0
      case RMAP_ERROR:
1784
0
        break;
1785
0
      }
1786
1787
0
    }
1788
0
  }
1789
0
  return ret;
1790
0
}
1791
1792
static struct list *route_map_get_index_list(struct route_node **rn,
1793
               const struct prefix *prefix,
1794
               struct route_table *table)
1795
0
{
1796
0
  struct route_node *tmp_rn = NULL;
1797
1798
0
  if (!(*rn)) {
1799
0
    *rn = route_node_match(table, prefix);
1800
1801
0
    if (!(*rn))
1802
0
      return NULL;
1803
1804
0
    if ((*rn)->info)
1805
0
      return (struct list *)((*rn)->info);
1806
1807
    /* If rn->info is NULL, get the parent.
1808
     * Store the rn in tmp_rn and unlock it later.
1809
     */
1810
0
    tmp_rn = *rn;
1811
0
  }
1812
1813
0
  do {
1814
0
    *rn = (*rn)->parent;
1815
0
    if (tmp_rn)
1816
0
      route_unlock_node(tmp_rn);
1817
1818
0
    if (!(*rn))
1819
0
      break;
1820
1821
0
    if ((*rn)->info) {
1822
0
      route_lock_node(*rn);
1823
0
      return (struct list *)((*rn)->info);
1824
0
    }
1825
0
  } while (!(*rn)->info);
1826
1827
0
  return NULL;
1828
0
}
1829
1830
/*
1831
 * This function returns the route-map index that best matches the prefix.
1832
 */
1833
static struct route_map_index *
1834
route_map_get_index(struct route_map *map, const struct prefix *prefix,
1835
        void *object, enum route_map_cmd_result_t *match_ret)
1836
0
{
1837
0
  enum route_map_cmd_result_t ret = RMAP_NOMATCH;
1838
0
  struct list *candidate_rmap_list = NULL;
1839
0
  struct route_node *rn = NULL;
1840
0
  struct listnode *ln = NULL, *nn = NULL;
1841
0
  struct route_map_index *index = NULL, *best_index = NULL;
1842
0
  struct route_map_index *head_index = NULL;
1843
0
  struct route_table *table = NULL;
1844
1845
  /* Route-map optimization relies on LPM lookups of the prefix to reduce
1846
   * the amount of route-map clauses a given prefix needs to be processed
1847
   * against. These LPM trees are IPv4/IPv6-specific and prefix->family
1848
   * must be AF_INET or AF_INET6 in order for the lookup to succeed. So if
1849
   * the AF doesn't line up with the LPM trees, skip the optimization.
1850
   */
1851
0
  if (map->optimization_disabled) {
1852
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL)))
1853
0
      zlog_debug(
1854
0
        "Skipping route-map optimization for route-map: %s, pfx: %pFX, family: %d",
1855
0
        map->name, prefix, prefix->family);
1856
0
    return map->head;
1857
0
  }
1858
1859
0
  if (prefix->family == AF_INET)
1860
0
    table = map->ipv4_prefix_table;
1861
0
  else
1862
0
    table = map->ipv6_prefix_table;
1863
1864
0
  do {
1865
0
    candidate_rmap_list =
1866
0
      route_map_get_index_list(&rn, prefix, table);
1867
0
    if (!rn)
1868
0
      break;
1869
1870
    /* If the index at the head of the list is of seq higher
1871
     * than that in best_index, ignore the list and get the
1872
     * parent node's list.
1873
     */
1874
0
    head_index = (struct route_map_index *)(listgetdata(
1875
0
      listhead(candidate_rmap_list)));
1876
0
    if (best_index && head_index
1877
0
        && (best_index->pref < head_index->pref)) {
1878
0
      route_unlock_node(rn);
1879
0
      continue;
1880
0
    }
1881
1882
0
    for (ALL_LIST_ELEMENTS(candidate_rmap_list, ln, nn, index)) {
1883
      /* If the index is of seq higher than that in
1884
       * best_index, ignore the list and get the parent
1885
       * node's list.
1886
       */
1887
0
      if (best_index && (best_index->pref < index->pref))
1888
0
        break;
1889
1890
0
      ret = route_map_apply_match(&index->match_list, prefix,
1891
0
                object);
1892
1893
0
      if (ret == RMAP_MATCH) {
1894
0
        *match_ret = ret;
1895
0
        best_index = index;
1896
0
        break;
1897
0
      } else if (ret == RMAP_NOOP) {
1898
        /*
1899
         * If match_ret is denymatch, even if we see
1900
         * more noops, we retain this return value and
1901
         * return this eventually if there are no
1902
         * matches.
1903
         * If a best match route-map index already
1904
         * exists, do not reset the match_ret.
1905
         */
1906
0
        if (!best_index && (*match_ret != RMAP_NOMATCH))
1907
0
          *match_ret = ret;
1908
0
      } else {
1909
        /*
1910
         * ret is RMAP_NOMATCH.
1911
         * If a best match route-map index already
1912
         * exists, do not reset the match_ret.
1913
         */
1914
0
        if (!best_index)
1915
0
          *match_ret = ret;
1916
0
      }
1917
0
    }
1918
1919
0
    route_unlock_node(rn);
1920
1921
0
  } while (rn);
1922
1923
0
  return best_index;
1924
0
}
1925
1926
static int route_map_candidate_list_cmp(struct route_map_index *idx1,
1927
          struct route_map_index *idx2)
1928
0
{
1929
0
  return idx1->pref - idx2->pref;
1930
0
}
1931
1932
/*
1933
 * This function adds the route-map index into the default route's
1934
 * route-node in the route-map's IPv4/IPv6 prefix-table.
1935
 */
1936
static void route_map_pfx_table_add_default(afi_t afi,
1937
              struct route_map_index *index)
1938
0
{
1939
0
  struct route_node *rn = NULL;
1940
0
  struct list *rmap_candidate_list = NULL;
1941
0
  struct prefix p;
1942
0
  bool updated_rn = false;
1943
0
  struct route_table *table = NULL;
1944
1945
0
  memset(&p, 0, sizeof(p));
1946
0
  p.family = afi2family(afi);
1947
0
  p.prefixlen = 0;
1948
1949
0
  if (p.family == AF_INET)
1950
0
    table = index->map->ipv4_prefix_table;
1951
0
  else
1952
0
    table = index->map->ipv6_prefix_table;
1953
1954
  /* Add default route to table */
1955
0
  rn = route_node_get(table, &p);
1956
1957
0
  if (!rn)
1958
0
    return;
1959
1960
0
  if (!rn->info) {
1961
0
    rmap_candidate_list = list_new();
1962
0
    rmap_candidate_list->cmp =
1963
0
      (int (*)(void *, void *))route_map_candidate_list_cmp;
1964
0
    rn->info = rmap_candidate_list;
1965
0
  } else {
1966
0
    rmap_candidate_list = (struct list *)rn->info;
1967
0
    updated_rn = true;
1968
0
  }
1969
1970
0
  listnode_add_sort_nodup(rmap_candidate_list, index);
1971
0
  if (updated_rn)
1972
0
    route_unlock_node(rn);
1973
0
}
1974
1975
/*
1976
 * This function removes the route-map index from the default route's
1977
 * route-node in the route-map's IPv4/IPv6 prefix-table.
1978
 */
1979
static void route_map_pfx_table_del_default(afi_t afi,
1980
              struct route_map_index *index)
1981
0
{
1982
0
  struct route_node *rn = NULL;
1983
0
  struct list *rmap_candidate_list = NULL;
1984
0
  struct prefix p;
1985
0
  struct route_table *table = NULL;
1986
1987
0
  memset(&p, 0, sizeof(p));
1988
0
  p.family = afi2family(afi);
1989
0
  p.prefixlen = 0;
1990
1991
0
  if (p.family == AF_INET)
1992
0
    table = index->map->ipv4_prefix_table;
1993
0
  else
1994
0
    table = index->map->ipv6_prefix_table;
1995
1996
  /* Remove RMAP index from default route in table */
1997
0
  rn = route_node_lookup(table, &p);
1998
0
  if (!rn || !rn->info)
1999
0
    return;
2000
2001
0
  rmap_candidate_list = (struct list *)rn->info;
2002
2003
0
  listnode_delete(rmap_candidate_list, index);
2004
2005
0
  if (listcount(rmap_candidate_list) == 0) {
2006
0
    list_delete(&rmap_candidate_list);
2007
0
    rn->info = NULL;
2008
0
    route_unlock_node(rn);
2009
0
  }
2010
0
  route_unlock_node(rn);
2011
0
}
2012
2013
/*
2014
 * This function adds the route-map index to the route-node for
2015
 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2016
 */
2017
static void route_map_pfx_table_add(struct route_table *table,
2018
            struct route_map_index *index,
2019
            struct prefix_list_entry *pentry)
2020
0
{
2021
0
  struct route_node *rn = NULL;
2022
0
  struct list *rmap_candidate_list = NULL;
2023
0
  bool updated_rn = false;
2024
2025
0
  rn = route_node_get(table, &pentry->prefix);
2026
0
  if (!rn)
2027
0
    return;
2028
2029
0
  if (!rn->info) {
2030
0
    rmap_candidate_list = list_new();
2031
0
    rmap_candidate_list->cmp =
2032
0
      (int (*)(void *, void *))route_map_candidate_list_cmp;
2033
0
    rn->info = rmap_candidate_list;
2034
0
  } else {
2035
0
    rmap_candidate_list = (struct list *)rn->info;
2036
0
    updated_rn = true;
2037
0
  }
2038
2039
0
  listnode_add_sort_nodup(rmap_candidate_list, index);
2040
0
  if (updated_rn)
2041
0
    route_unlock_node(rn);
2042
0
}
2043
2044
/*
2045
 * This function removes the route-map index from the route-node for
2046
 * the prefix-entry in the route-map's IPv4/IPv6 prefix-table.
2047
 */
2048
static void route_map_pfx_table_del(struct route_table *table,
2049
            struct route_map_index *index,
2050
            struct prefix_list_entry *pentry)
2051
0
{
2052
0
  struct route_node *rn = NULL;
2053
0
  struct list *rmap_candidate_list = NULL;
2054
2055
0
  rn = route_node_lookup(table, &pentry->prefix);
2056
0
  if (!rn || !rn->info)
2057
0
    return;
2058
2059
0
  rmap_candidate_list = (struct list *)rn->info;
2060
2061
0
  listnode_delete(rmap_candidate_list, index);
2062
2063
0
  if (listcount(rmap_candidate_list) == 0) {
2064
0
    list_delete(&rmap_candidate_list);
2065
0
    rn->info = NULL;
2066
0
    route_unlock_node(rn);
2067
0
  }
2068
0
  route_unlock_node(rn);
2069
0
}
2070
2071
/* This function checks for the presence of an IPv4 prefix-list
2072
 * match rule in the given route-map index.
2073
 */
2074
static bool route_map_is_ip_pfx_list_rule_present(struct route_map_index *index)
2075
0
{
2076
0
  struct route_map_rule_list *match_list = NULL;
2077
0
  struct route_map_rule *rule = NULL;
2078
2079
0
  match_list = &index->match_list;
2080
0
  for (rule = match_list->head; rule; rule = rule->next)
2081
0
    if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
2082
0
      return true;
2083
2084
0
  return false;
2085
0
}
2086
2087
/* This function checks for the presence of an IPv6 prefix-list
2088
 * match rule in the given route-map index.
2089
 */
2090
static bool
2091
route_map_is_ipv6_pfx_list_rule_present(struct route_map_index *index)
2092
0
{
2093
0
  struct route_map_rule_list *match_list = NULL;
2094
0
  struct route_map_rule *rule = NULL;
2095
2096
0
  match_list = &index->match_list;
2097
0
  for (rule = match_list->head; rule; rule = rule->next)
2098
0
    if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
2099
0
      return true;
2100
2101
0
  return false;
2102
0
}
2103
2104
/* This function does the following:
2105
 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2106
 *    match clause (based on the afi passed to this foo) and get the
2107
 *    prefix-list name.
2108
 * 2) Look up the prefix-list using the name.
2109
 * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6
2110
 *    default-route's node in the trie (based on the afi passed to this foo).
2111
 * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6
2112
 *    default-route's node in the trie (based on the afi passed to this foo).
2113
 * 5) If a prefix-entry is passed then, create a route-node for this entry and
2114
 *    add this index to the route-node.
2115
 * 6) If prefix-entry is not passed then, for every prefix-entry in the
2116
 *    prefix-list, create a route-node for this entry and
2117
 *    add this index to the route-node.
2118
 */
2119
static void route_map_add_plist_entries(afi_t afi,
2120
          struct route_map_index *index,
2121
          const char *plist_name,
2122
          struct prefix_list_entry *entry)
2123
0
{
2124
0
  struct route_map_rule_list *match_list = NULL;
2125
0
  struct route_map_rule *match = NULL;
2126
0
  struct prefix_list *plist = NULL;
2127
0
  struct prefix_list_entry *pentry = NULL;
2128
0
  bool plist_rule_is_present = false;
2129
2130
0
  if (!plist_name) {
2131
0
    match_list = &index->match_list;
2132
2133
0
    for (match = match_list->head; match; match = match->next) {
2134
0
      if (afi == AFI_IP) {
2135
0
        if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
2136
0
          plist_rule_is_present = true;
2137
0
          break;
2138
0
        }
2139
0
      } else {
2140
0
        if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
2141
0
          plist_rule_is_present = true;
2142
0
          break;
2143
0
        }
2144
0
      }
2145
0
    }
2146
2147
0
    if (plist_rule_is_present)
2148
0
      plist = prefix_list_lookup(afi, match->rule_str);
2149
0
  } else {
2150
0
    plist = prefix_list_lookup(afi, plist_name);
2151
0
  }
2152
2153
0
  if (!plist) {
2154
0
    route_map_pfx_table_add_default(afi, index);
2155
0
    return;
2156
0
  }
2157
2158
  /* Default entry should be deleted only if the first entry of the
2159
   * prefix-list is created.
2160
   */
2161
0
  if (entry) {
2162
0
    if (plist->count == 1)
2163
0
      route_map_pfx_table_del_default(afi, index);
2164
0
  } else {
2165
0
    route_map_pfx_table_del_default(afi, index);
2166
0
  }
2167
2168
0
  if (entry) {
2169
0
    if (afi == AFI_IP) {
2170
0
      route_map_pfx_table_add(index->map->ipv4_prefix_table,
2171
0
            index, entry);
2172
0
    } else {
2173
0
      route_map_pfx_table_add(index->map->ipv6_prefix_table,
2174
0
            index, entry);
2175
0
    }
2176
0
  } else {
2177
0
    for (pentry = plist->head; pentry; pentry = pentry->next) {
2178
0
      if (afi == AFI_IP) {
2179
0
        route_map_pfx_table_add(
2180
0
          index->map->ipv4_prefix_table, index,
2181
0
          pentry);
2182
0
      } else {
2183
0
        route_map_pfx_table_add(
2184
0
          index->map->ipv6_prefix_table, index,
2185
0
          pentry);
2186
0
      }
2187
0
    }
2188
0
  }
2189
0
}
2190
2191
/* This function does the following:
2192
 * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list
2193
 *    match clause (based on the afi passed to this foo) and get the
2194
 *    prefix-list name.
2195
 * 2) Look up the prefix-list using the name.
2196
 * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6
2197
 *    default-route's node in the trie (based on the afi passed to this foo).
2198
 * 4) If a prefix-entry is passed then, remove this index from the route-node
2199
 *    for the prefix in this prefix-entry.
2200
 * 5) If prefix-entry is not passed then, for every prefix-entry in the
2201
 *    prefix-list, remove this index from the route-node
2202
 *    for the prefix in this prefix-entry.
2203
 */
2204
static void route_map_del_plist_entries(afi_t afi,
2205
          struct route_map_index *index,
2206
          const char *plist_name,
2207
          struct prefix_list_entry *entry)
2208
0
{
2209
0
  struct route_map_rule_list *match_list = NULL;
2210
0
  struct route_map_rule *match = NULL;
2211
0
  struct prefix_list *plist = NULL;
2212
0
  struct prefix_list_entry *pentry = NULL;
2213
0
  bool plist_rule_is_present = false;
2214
2215
0
  if (!plist_name) {
2216
0
    match_list = &index->match_list;
2217
2218
0
    for (match = match_list->head; match; match = match->next) {
2219
0
      if (afi == AFI_IP) {
2220
0
        if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) {
2221
0
          plist_rule_is_present = true;
2222
0
          break;
2223
0
        }
2224
0
      } else {
2225
0
        if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) {
2226
0
          plist_rule_is_present = true;
2227
0
          break;
2228
0
        }
2229
0
      }
2230
0
    }
2231
2232
0
    if (plist_rule_is_present)
2233
0
      plist = prefix_list_lookup(afi, match->rule_str);
2234
0
  } else {
2235
0
    plist = prefix_list_lookup(afi, plist_name);
2236
0
  }
2237
2238
0
  if (!plist) {
2239
0
    route_map_pfx_table_del_default(afi, index);
2240
0
    return;
2241
0
  }
2242
2243
0
  if (entry) {
2244
0
    if (afi == AFI_IP) {
2245
0
      route_map_pfx_table_del(index->map->ipv4_prefix_table,
2246
0
            index, entry);
2247
0
    } else {
2248
0
      route_map_pfx_table_del(index->map->ipv6_prefix_table,
2249
0
            index, entry);
2250
0
    }
2251
0
  } else {
2252
0
    for (pentry = plist->head; pentry; pentry = pentry->next) {
2253
0
      if (afi == AFI_IP) {
2254
0
        route_map_pfx_table_del(
2255
0
          index->map->ipv4_prefix_table, index,
2256
0
          pentry);
2257
0
      } else {
2258
0
        route_map_pfx_table_del(
2259
0
          index->map->ipv6_prefix_table, index,
2260
0
          pentry);
2261
0
      }
2262
0
    }
2263
0
  }
2264
0
}
2265
2266
/*
2267
 * This function handles the cases where a prefix-list is added/removed
2268
 * as a match command from a particular route-map index.
2269
 * It updates the prefix-table of the route-map accordingly.
2270
 */
2271
static void route_map_trie_update(afi_t afi, route_map_event_t event,
2272
          struct route_map_index *index,
2273
          const char *plist_name)
2274
0
{
2275
0
  if (event == RMAP_EVENT_PLIST_ADDED) {
2276
0
    if (afi == AFI_IP) {
2277
0
      if (!route_map_is_ipv6_pfx_list_rule_present(index)) {
2278
0
        route_map_pfx_table_del_default(AFI_IP6, index);
2279
0
        route_map_add_plist_entries(afi, index,
2280
0
                  plist_name, NULL);
2281
0
      } else {
2282
0
        route_map_del_plist_entries(AFI_IP6, index,
2283
0
                  NULL, NULL);
2284
0
      }
2285
0
    } else {
2286
0
      if (!route_map_is_ip_pfx_list_rule_present(index)) {
2287
0
        route_map_pfx_table_del_default(AFI_IP, index);
2288
0
        route_map_add_plist_entries(afi, index,
2289
0
                  plist_name, NULL);
2290
0
      } else {
2291
0
        route_map_del_plist_entries(AFI_IP, index, NULL,
2292
0
                  NULL);
2293
0
      }
2294
0
    }
2295
0
  } else if (event == RMAP_EVENT_PLIST_DELETED) {
2296
0
    if (afi == AFI_IP) {
2297
0
      route_map_del_plist_entries(afi, index, plist_name,
2298
0
                NULL);
2299
2300
      /* If IPv6 prefix-list match rule is not present,
2301
       * add this index to the IPv4 default route's trie
2302
       * node.
2303
       * Also, add this index to the trie nodes created
2304
       * for each of the prefix-entries within the IPv6
2305
       * prefix-list, if the IPv6 prefix-list match rule
2306
       * is present. Else, add this index to the IPv6
2307
       * default route's trie node.
2308
       */
2309
0
      if (!route_map_is_ipv6_pfx_list_rule_present(index))
2310
0
        route_map_pfx_table_add_default(afi, index);
2311
2312
0
      route_map_add_plist_entries(AFI_IP6, index, NULL, NULL);
2313
0
    } else {
2314
0
      route_map_del_plist_entries(afi, index, plist_name,
2315
0
                NULL);
2316
2317
      /* If IPv4 prefix-list match rule is not present,
2318
       * add this index to the IPv6 default route's trie
2319
       * node.
2320
       * Also, add this index to the trie nodes created
2321
       * for each of the prefix-entries within the IPv4
2322
       * prefix-list, if the IPv4 prefix-list match rule
2323
       * is present. Else, add this index to the IPv4
2324
       * default route's trie node.
2325
       */
2326
0
      if (!route_map_is_ip_pfx_list_rule_present(index))
2327
0
        route_map_pfx_table_add_default(afi, index);
2328
2329
0
      route_map_add_plist_entries(AFI_IP, index, NULL, NULL);
2330
0
    }
2331
0
  }
2332
0
}
2333
2334
/*
2335
 * This function handles the cases where a route-map index and
2336
 * prefix-list is added/removed.
2337
 * It updates the prefix-table of the route-map accordingly.
2338
 */
2339
static void route_map_pfx_tbl_update(route_map_event_t event,
2340
             struct route_map_index *index, afi_t afi,
2341
             const char *plist_name)
2342
0
{
2343
0
  if (!index)
2344
0
    return;
2345
2346
0
  if (event == RMAP_EVENT_INDEX_ADDED) {
2347
0
    route_map_pfx_table_add_default(AFI_IP, index);
2348
0
    route_map_pfx_table_add_default(AFI_IP6, index);
2349
0
    return;
2350
0
  }
2351
2352
0
  if (event == RMAP_EVENT_INDEX_DELETED) {
2353
0
    route_map_pfx_table_del_default(AFI_IP, index);
2354
0
    route_map_pfx_table_del_default(AFI_IP6, index);
2355
2356
0
    return;
2357
0
  }
2358
2359
  /* Handle prefix-list match rule addition/deletion.
2360
   */
2361
0
  route_map_trie_update(afi, event, index, plist_name);
2362
0
}
2363
2364
/*
2365
 * This function handles the cases where a new prefix-entry is added to
2366
 * a prefix-list or, an existing prefix-entry is removed from the prefix-list.
2367
 * It updates the prefix-table of the route-map accordingly.
2368
 */
2369
static void route_map_pentry_update(route_map_event_t event,
2370
            const char *plist_name,
2371
            struct route_map_index *index,
2372
            struct prefix_list_entry *pentry)
2373
0
{
2374
0
  struct prefix_list *plist = NULL;
2375
0
  afi_t afi;
2376
0
  unsigned char family = pentry->prefix.family;
2377
2378
0
  if (family == AF_INET) {
2379
0
    afi = AFI_IP;
2380
0
    plist = prefix_list_lookup(AFI_IP, plist_name);
2381
0
  } else {
2382
0
    afi = AFI_IP6;
2383
0
    plist = prefix_list_lookup(AFI_IP6, plist_name);
2384
0
  }
2385
2386
0
  if (event == RMAP_EVENT_PLIST_ADDED) {
2387
0
    if (afi == AFI_IP) {
2388
0
      if (!route_map_is_ipv6_pfx_list_rule_present(index))
2389
0
        route_map_add_plist_entries(afi, index,
2390
0
                  plist_name, pentry);
2391
0
    } else {
2392
0
      if (!route_map_is_ip_pfx_list_rule_present(index))
2393
0
        route_map_add_plist_entries(afi, index,
2394
0
                  plist_name, pentry);
2395
0
    }
2396
0
  } else if (event == RMAP_EVENT_PLIST_DELETED) {
2397
0
    route_map_del_plist_entries(afi, index, plist_name, pentry);
2398
2399
0
    if (plist->count == 1) {
2400
0
      if (afi == AFI_IP) {
2401
0
        if (!route_map_is_ipv6_pfx_list_rule_present(
2402
0
              index))
2403
0
          route_map_pfx_table_add_default(afi,
2404
0
                  index);
2405
0
      } else {
2406
0
        if (!route_map_is_ip_pfx_list_rule_present(
2407
0
              index))
2408
0
          route_map_pfx_table_add_default(afi,
2409
0
                  index);
2410
0
      }
2411
0
    }
2412
0
  }
2413
0
}
2414
2415
static void route_map_pentry_process_dependency(struct hash_bucket *bucket,
2416
            void *data)
2417
0
{
2418
0
  char *rmap_name = NULL;
2419
0
  struct route_map *rmap = NULL;
2420
0
  struct route_map_index *index = NULL;
2421
0
  struct route_map_rule_list *match_list = NULL;
2422
0
  struct route_map_rule *match = NULL;
2423
0
  struct route_map_dep_data *dep_data = NULL;
2424
0
  struct route_map_pentry_dep *pentry_dep =
2425
0
    (struct route_map_pentry_dep *)data;
2426
0
  unsigned char family = pentry_dep->pentry->prefix.family;
2427
2428
0
  dep_data = (struct route_map_dep_data *)bucket->data;
2429
0
  if (!dep_data)
2430
0
    return;
2431
2432
0
  rmap_name = dep_data->rname;
2433
0
  rmap = route_map_lookup_by_name(rmap_name);
2434
0
  if (!rmap || !rmap->head)
2435
0
    return;
2436
2437
0
  for (index = rmap->head; index; index = index->next) {
2438
0
    match_list = &index->match_list;
2439
2440
0
    if (!match_list)
2441
0
      continue;
2442
2443
0
    for (match = match_list->head; match; match = match->next) {
2444
0
      if (strcmp(match->rule_str, pentry_dep->plist_name)
2445
0
          == 0) {
2446
0
        if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)
2447
0
            && family == AF_INET) {
2448
0
          route_map_pentry_update(
2449
0
            pentry_dep->event,
2450
0
            pentry_dep->plist_name, index,
2451
0
            pentry_dep->pentry);
2452
0
        } else if (IS_RULE_IPv6_PREFIX_LIST(
2453
0
               match->cmd->str)
2454
0
             && family == AF_INET6) {
2455
0
          route_map_pentry_update(
2456
0
            pentry_dep->event,
2457
0
            pentry_dep->plist_name, index,
2458
0
            pentry_dep->pentry);
2459
0
        }
2460
0
      }
2461
0
    }
2462
0
  }
2463
0
}
2464
2465
void route_map_notify_pentry_dependencies(const char *affected_name,
2466
            struct prefix_list_entry *pentry,
2467
            route_map_event_t event)
2468
4.21k
{
2469
4.21k
  struct route_map_dep *dep = NULL;
2470
4.21k
  struct hash *upd8_hash = NULL;
2471
4.21k
  struct route_map_pentry_dep pentry_dep;
2472
2473
4.21k
  if (!affected_name || !pentry)
2474
0
    return;
2475
2476
4.21k
  upd8_hash = route_map_get_dep_hash(event);
2477
4.21k
  if (!upd8_hash)
2478
0
    return;
2479
2480
4.21k
  dep = (struct route_map_dep *)hash_get(upd8_hash, (void *)affected_name,
2481
4.21k
                 NULL);
2482
4.21k
  if (dep) {
2483
0
    if (!dep->this_hash)
2484
0
      dep->this_hash = upd8_hash;
2485
2486
0
    memset(&pentry_dep, 0, sizeof(pentry_dep));
2487
0
    pentry_dep.pentry = pentry;
2488
0
    pentry_dep.plist_name = affected_name;
2489
0
    pentry_dep.event = event;
2490
2491
0
    hash_iterate(dep->dep_rmap_hash,
2492
0
           route_map_pentry_process_dependency,
2493
0
           (void *)&pentry_dep);
2494
0
  }
2495
4.21k
}
2496
2497
/* Apply route map's each index to the object.
2498
2499
   The matrix for a route-map looks like this:
2500
   (note, this includes the description for the "NEXT"
2501
   and "GOTO" frobs now
2502
2503
     |   Match   |   No Match   | No op
2504
     |-----------|--------------|-------
2505
    permit |   action  |     cont     | cont.
2506
     |           | default:deny | default:permit
2507
    -------------------+-----------------------
2508
     |   deny    |     cont     | cont.
2509
    deny   |           | default:deny | default:permit
2510
     |-----------|--------------|--------
2511
2512
   action)
2513
      -Apply Set statements, accept route
2514
      -If Call statement is present jump to the specified route-map, if it
2515
   denies the route we finish.
2516
      -If NEXT is specified, goto NEXT statement
2517
      -If GOTO is specified, goto the first clause where pref > nextpref
2518
      -If nothing is specified, do as Cisco and finish
2519
   deny)
2520
      -Route is denied by route-map.
2521
   cont)
2522
      -Goto Next index
2523
2524
   If we get no matches after we've processed all updates, then the route
2525
   is dropped too.
2526
2527
   Some notes on the new "CALL", "NEXT" and "GOTO"
2528
     call WORD        - If this clause is matched, then the set statements
2529
      are executed and then we jump to route-map 'WORD'. If
2530
      this route-map denies the route, we finish, in other
2531
   case we
2532
      do whatever the exit policy (EXIT, NEXT or GOTO) tells.
2533
     on-match next    - If this clause is matched, then the set statements
2534
      are executed and then we drop through to the next clause
2535
     on-match goto n  - If this clause is matched, then the set statements
2536
      are executed and then we goto the nth clause, or the
2537
      first clause greater than this. In order to ensure
2538
      route-maps *always* exit, you cannot jump backwards.
2539
      Sorry ;)
2540
2541
   We need to make sure our route-map processing matches the above
2542
*/
2543
route_map_result_t route_map_apply_ext(struct route_map *map,
2544
               const struct prefix *prefix,
2545
               void *match_object, void *set_object,
2546
               int *pref)
2547
0
{
2548
0
  static int recursion = 0;
2549
0
  enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
2550
0
  route_map_result_t ret = RMAP_PERMITMATCH;
2551
0
  struct route_map_index *index = NULL;
2552
0
  struct route_map_rule *set = NULL;
2553
0
  bool skip_match_clause = false;
2554
0
  struct prefix conv;
2555
2556
0
  if (recursion > RMAP_RECURSION_LIMIT) {
2557
0
    if (map)
2558
0
      map->applied++;
2559
2560
0
    flog_warn(
2561
0
      EC_LIB_RMAP_RECURSION_LIMIT,
2562
0
      "route-map recursion limit (%d) reached, discarding route",
2563
0
      RMAP_RECURSION_LIMIT);
2564
0
    recursion = 0;
2565
0
    return RMAP_DENYMATCH;
2566
0
  }
2567
2568
0
  if (map == NULL || map->head == NULL) {
2569
0
    if (map)
2570
0
      map->applied++;
2571
0
    ret = RMAP_DENYMATCH;
2572
0
    goto route_map_apply_end;
2573
0
  }
2574
2575
0
  map->applied++;
2576
2577
  /*
2578
   * Handling for matching evpn_routes in the prefix table.
2579
   *
2580
   * We convert type2/5 prefix to ipv4/6 prefix to do longest
2581
   * prefix matching on.
2582
   */
2583
0
  if (prefix->family == AF_EVPN) {
2584
0
    if (evpn_prefix2prefix(prefix, &conv) != 0) {
2585
0
      if (unlikely(CHECK_FLAG(rmap_debug,
2586
0
            DEBUG_ROUTEMAP_DETAIL)))
2587
0
        zlog_debug(
2588
0
          "Unable to convert EVPN prefix %pFX into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup",
2589
0
          prefix);
2590
0
    } else {
2591
0
      if (unlikely(CHECK_FLAG(rmap_debug,
2592
0
            DEBUG_ROUTEMAP_DETAIL)))
2593
0
        zlog_debug(
2594
0
          "Converted EVPN prefix %pFX into %pFX for optimized route-map lookup",
2595
0
          prefix, &conv);
2596
2597
0
      prefix = &conv;
2598
0
    }
2599
0
  }
2600
2601
0
  index = route_map_get_index(map, prefix, match_object, &match_ret);
2602
0
  if (index) {
2603
0
    index->applied++;
2604
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
2605
0
      zlog_debug(
2606
0
        "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
2607
0
        map->name, index->pref, prefix,
2608
0
        route_map_cmd_result_str(match_ret));
2609
0
  } else {
2610
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
2611
0
      zlog_debug(
2612
0
        "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
2613
0
        prefix, map->name,
2614
0
        route_map_cmd_result_str(match_ret));
2615
    /*
2616
     * No index matches this prefix. Return deny unless,
2617
     * match_ret = RMAP_NOOP.
2618
     */
2619
0
    if (match_ret == RMAP_NOOP)
2620
0
      ret = RMAP_PERMITMATCH;
2621
0
    else
2622
0
      ret = RMAP_DENYMATCH;
2623
0
    goto route_map_apply_end;
2624
0
  }
2625
0
  skip_match_clause = true;
2626
2627
0
  for (; index; index = index->next) {
2628
0
    if (!skip_match_clause) {
2629
0
      index->applied++;
2630
      /* Apply this index. */
2631
0
      match_ret = route_map_apply_match(&index->match_list,
2632
0
                prefix, match_object);
2633
0
      if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))) {
2634
0
        zlog_debug(
2635
0
          "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
2636
0
          map->name, index->pref, prefix,
2637
0
          route_map_cmd_result_str(match_ret));
2638
0
      }
2639
0
    } else
2640
0
      skip_match_clause = false;
2641
2642
2643
    /* Now we apply the matrix from above */
2644
0
    if (match_ret == RMAP_NOOP)
2645
      /*
2646
       * Do not change the return value. Retain the previous
2647
       * return value. Previous values can be:
2648
       * 1)permitmatch (if a nomatch was never
2649
       * seen before in this route-map.)
2650
       * 2)denymatch (if a nomatch was seen earlier in one
2651
       * of the previous sequences)
2652
       */
2653
2654
      /*
2655
       * 'cont' from matrix - continue to next route-map
2656
       * sequence
2657
       */
2658
0
      continue;
2659
0
    else if (match_ret == RMAP_NOMATCH) {
2660
2661
      /*
2662
       * The return value is now changed to denymatch.
2663
       * So from here on out, even if we see more noops,
2664
       * we retain this return value and return this
2665
       * eventually if there are no matches.
2666
       */
2667
0
      ret = RMAP_DENYMATCH;
2668
2669
      /*
2670
       * 'cont' from matrix - continue to next route-map
2671
       * sequence
2672
       */
2673
0
      continue;
2674
0
    } else if (match_ret == RMAP_MATCH) {
2675
0
      if (index->type == RMAP_PERMIT)
2676
      /* 'action' */
2677
0
      {
2678
        /* Match succeeded, rmap is of type permit */
2679
0
        ret = RMAP_PERMITMATCH;
2680
2681
        /* permit+match must execute sets */
2682
0
        for (set = index->set_list.head; set;
2683
0
             set = set->next)
2684
          /*
2685
           * set cmds return RMAP_OKAY or
2686
           * RMAP_ERROR. We do not care if
2687
           * set succeeded or not. So, ignore
2688
           * return code.
2689
           */
2690
0
          (void)(*set->cmd->func_apply)(
2691
0
            set->value, prefix, set_object);
2692
2693
        /* Call another route-map if available */
2694
0
        if (index->nextrm) {
2695
0
          struct route_map *nextrm =
2696
0
            route_map_lookup_by_name(
2697
0
              index->nextrm);
2698
2699
0
          if (nextrm) /* Target route-map found,
2700
                   jump to it */
2701
0
          {
2702
0
            recursion++;
2703
0
            ret = route_map_apply_ext(
2704
0
              nextrm, prefix,
2705
0
              match_object,
2706
0
              set_object, NULL);
2707
0
            recursion--;
2708
0
          }
2709
2710
          /* If nextrm returned 'deny', finish. */
2711
0
          if (ret == RMAP_DENYMATCH)
2712
0
            goto route_map_apply_end;
2713
0
        }
2714
2715
0
        switch (index->exitpolicy) {
2716
0
        case RMAP_EXIT:
2717
0
          goto route_map_apply_end;
2718
0
        case RMAP_NEXT:
2719
0
          continue;
2720
0
        case RMAP_GOTO: {
2721
          /* Find the next clause to jump to */
2722
0
          struct route_map_index *next =
2723
0
            index->next;
2724
0
          int nextpref = index->nextpref;
2725
2726
0
          while (next && next->pref < nextpref) {
2727
0
            index = next;
2728
0
            next = next->next;
2729
0
          }
2730
0
          if (next == NULL) {
2731
            /* No clauses match! */
2732
0
            goto route_map_apply_end;
2733
0
          }
2734
0
        }
2735
0
        }
2736
0
      } else if (index->type == RMAP_DENY)
2737
      /* 'deny' */
2738
0
      {
2739
0
        ret = RMAP_DENYMATCH;
2740
0
        goto route_map_apply_end;
2741
0
      }
2742
0
    }
2743
0
  }
2744
2745
0
route_map_apply_end:
2746
0
  if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
2747
0
    zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
2748
0
         (map ? map->name : "null"), prefix,
2749
0
         route_map_result_str(ret));
2750
2751
0
  if (pref) {
2752
0
    if (index != NULL && ret == RMAP_PERMITMATCH)
2753
0
      *pref = index->pref;
2754
0
    else
2755
0
      *pref = 65536;
2756
0
  }
2757
2758
0
  return (ret);
2759
0
}
2760
2761
void route_map_add_hook(void (*func)(const char *))
2762
4
{
2763
4
  route_map_master.add_hook = func;
2764
4
}
2765
2766
void route_map_delete_hook(void (*func)(const char *))
2767
4
{
2768
4
  route_map_master.delete_hook = func;
2769
4
}
2770
2771
void route_map_event_hook(void (*func)(const char *name))
2772
4
{
2773
4
  route_map_master.event_hook = func;
2774
4
}
2775
2776
/* Routines for route map dependency lists and dependency processing */
2777
static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
2778
0
{
2779
0
  return strcmp(((const struct route_map_dep_data *)p1)->rname,
2780
0
          ((const struct route_map_dep_data *)p2)->rname)
2781
0
         == 0;
2782
0
}
2783
2784
static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
2785
0
{
2786
2787
0
  return (strcmp(((const struct route_map_dep *)p1)->dep_name,
2788
0
           (const char *)p2)
2789
0
    == 0);
2790
0
}
2791
2792
static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
2793
0
{
2794
0
  struct route_map_dep *dep = bucket->data;
2795
0
  struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
2796
2797
0
  memset(&tmp_dep_data, 0, sizeof(tmp_dep_data));
2798
0
  tmp_dep_data.rname = arg;
2799
0
  dep_data = hash_release(dep->dep_rmap_hash, &tmp_dep_data);
2800
0
  if (dep_data) {
2801
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
2802
0
      zlog_debug("Clearing reference for %s to %s count: %d",
2803
0
           dep->dep_name, tmp_dep_data.rname,
2804
0
           dep_data->refcnt);
2805
2806
0
    XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
2807
0
    XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
2808
0
  }
2809
0
  if (!dep->dep_rmap_hash->count) {
2810
0
    dep = hash_release(dep->this_hash, (void *)dep->dep_name);
2811
0
    hash_free(dep->dep_rmap_hash);
2812
0
    XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2813
0
    XFREE(MTYPE_ROUTE_MAP_DEP, dep);
2814
0
  }
2815
0
}
2816
2817
static void route_map_clear_all_references(char *rmap_name)
2818
0
{
2819
0
  int i;
2820
2821
0
  if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
2822
0
    zlog_debug("Clearing references for %s", rmap_name);
2823
2824
0
  for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2825
0
    hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
2826
0
           (void *)rmap_name);
2827
0
  }
2828
0
}
2829
2830
static unsigned int route_map_dep_data_hash_make_key(const void *p)
2831
0
{
2832
0
  const struct route_map_dep_data *dep_data = p;
2833
2834
0
  return string_hash_make(dep_data->rname);
2835
0
}
2836
2837
static void *route_map_dep_hash_alloc(void *p)
2838
0
{
2839
0
  char *dep_name = (char *)p;
2840
0
  struct route_map_dep *dep_entry;
2841
2842
0
  dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
2843
0
  dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
2844
0
  dep_entry->dep_rmap_hash =
2845
0
    hash_create_size(8, route_map_dep_data_hash_make_key,
2846
0
         route_map_rmap_hash_cmp, "Route Map Dep Hash");
2847
0
  dep_entry->this_hash = NULL;
2848
2849
0
  return dep_entry;
2850
0
}
2851
2852
static void *route_map_name_hash_alloc(void *p)
2853
0
{
2854
0
  struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
2855
2856
0
  dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
2857
0
         sizeof(struct route_map_dep_data));
2858
0
  tmp_dep_data = p;
2859
0
  dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
2860
0
  return dep_data;
2861
0
}
2862
2863
static unsigned int route_map_dep_hash_make_key(const void *p)
2864
0
{
2865
0
  return (string_hash_make((char *)p));
2866
0
}
2867
2868
static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
2869
0
{
2870
0
  struct route_map_dep_data *dep_data = bucket->data;
2871
0
  char *rmap_name = dep_data->rname;
2872
0
  char *dep_name = data;
2873
2874
0
  zlog_debug("%s: Dependency for %s: %s", __func__, dep_name, rmap_name);
2875
0
}
2876
2877
static int route_map_dep_update(struct hash *dephash, const char *dep_name,
2878
        const char *rmap_name, route_map_event_t type)
2879
0
{
2880
0
  struct route_map_dep *dep = NULL;
2881
0
  char *dname, *rname;
2882
0
  int ret = 0;
2883
0
  struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
2884
0
  struct route_map_dep_data tmp_dep_data;
2885
2886
0
  dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
2887
0
  rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
2888
2889
0
  switch (type) {
2890
0
  case RMAP_EVENT_PLIST_ADDED:
2891
0
  case RMAP_EVENT_CLIST_ADDED:
2892
0
  case RMAP_EVENT_ECLIST_ADDED:
2893
0
  case RMAP_EVENT_ASLIST_ADDED:
2894
0
  case RMAP_EVENT_LLIST_ADDED:
2895
0
  case RMAP_EVENT_CALL_ADDED:
2896
0
  case RMAP_EVENT_FILTER_ADDED:
2897
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
2898
0
      zlog_debug("Adding dependency for filter %s in route-map %s",
2899
0
           dep_name, rmap_name);
2900
0
    dep = (struct route_map_dep *)hash_get(
2901
0
      dephash, dname, route_map_dep_hash_alloc);
2902
0
    if (!dep) {
2903
0
      ret = -1;
2904
0
      goto out;
2905
0
    }
2906
2907
0
    if (!dep->this_hash)
2908
0
      dep->this_hash = dephash;
2909
2910
0
    memset(&tmp_dep_data, 0, sizeof(tmp_dep_data));
2911
0
    tmp_dep_data.rname = rname;
2912
0
    dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
2913
0
    if (!dep_data)
2914
0
      dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
2915
0
              route_map_name_hash_alloc);
2916
2917
0
    dep_data->refcnt++;
2918
0
    break;
2919
0
  case RMAP_EVENT_PLIST_DELETED:
2920
0
  case RMAP_EVENT_CLIST_DELETED:
2921
0
  case RMAP_EVENT_ECLIST_DELETED:
2922
0
  case RMAP_EVENT_ASLIST_DELETED:
2923
0
  case RMAP_EVENT_LLIST_DELETED:
2924
0
  case RMAP_EVENT_CALL_DELETED:
2925
0
  case RMAP_EVENT_FILTER_DELETED:
2926
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
2927
0
      zlog_debug("Deleting dependency for filter %s in route-map %s",
2928
0
           dep_name, rmap_name);
2929
0
    dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
2930
0
    if (!dep) {
2931
0
      goto out;
2932
0
    }
2933
2934
0
    memset(&tmp_dep_data, 0, sizeof(tmp_dep_data));
2935
0
    tmp_dep_data.rname = rname;
2936
0
    dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
2937
    /*
2938
     * If dep_data is NULL then something has gone seriously
2939
     * wrong in route-map handling.  Note it and prevent
2940
     * the crash.
2941
     */
2942
0
    if (!dep_data) {
2943
0
      zlog_warn(
2944
0
        "route-map dependency for route-map %s: %s is not correct",
2945
0
        rmap_name, dep_name);
2946
0
      goto out;
2947
0
    }
2948
2949
0
    dep_data->refcnt--;
2950
2951
0
    if (!dep_data->refcnt) {
2952
0
      ret_dep_data = hash_release(dep->dep_rmap_hash,
2953
0
                &tmp_dep_data);
2954
0
      if (ret_dep_data) {
2955
0
        XFREE(MTYPE_ROUTE_MAP_NAME,
2956
0
              ret_dep_data->rname);
2957
0
        XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
2958
0
      }
2959
0
    }
2960
2961
0
    if (!dep->dep_rmap_hash->count) {
2962
0
      dep = hash_release(dephash, dname);
2963
0
      hash_free(dep->dep_rmap_hash);
2964
0
      XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
2965
0
      XFREE(MTYPE_ROUTE_MAP_DEP, dep);
2966
0
    }
2967
0
    break;
2968
0
  case RMAP_EVENT_SET_ADDED:
2969
0
  case RMAP_EVENT_SET_DELETED:
2970
0
  case RMAP_EVENT_SET_REPLACED:
2971
0
  case RMAP_EVENT_MATCH_ADDED:
2972
0
  case RMAP_EVENT_MATCH_DELETED:
2973
0
  case RMAP_EVENT_MATCH_REPLACED:
2974
0
  case RMAP_EVENT_INDEX_ADDED:
2975
0
  case RMAP_EVENT_INDEX_DELETED:
2976
0
    break;
2977
0
  }
2978
2979
0
  if (dep) {
2980
0
    if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
2981
0
      hash_iterate(dep->dep_rmap_hash,
2982
0
             route_map_print_dependency, dname);
2983
0
  }
2984
2985
0
out:
2986
0
  XFREE(MTYPE_ROUTE_MAP_NAME, rname);
2987
0
  XFREE(MTYPE_ROUTE_MAP_NAME, dname);
2988
0
  return ret;
2989
0
}
2990
2991
static struct hash *route_map_get_dep_hash(route_map_event_t event)
2992
7.53k
{
2993
7.53k
  struct hash *upd8_hash = NULL;
2994
2995
7.53k
  switch (event) {
2996
5.12k
  case RMAP_EVENT_PLIST_ADDED:
2997
7.53k
  case RMAP_EVENT_PLIST_DELETED:
2998
7.53k
    upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
2999
7.53k
    break;
3000
0
  case RMAP_EVENT_CLIST_ADDED:
3001
0
  case RMAP_EVENT_CLIST_DELETED:
3002
0
    upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
3003
0
    break;
3004
0
  case RMAP_EVENT_ECLIST_ADDED:
3005
0
  case RMAP_EVENT_ECLIST_DELETED:
3006
0
    upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
3007
0
    break;
3008
0
  case RMAP_EVENT_ASLIST_ADDED:
3009
0
  case RMAP_EVENT_ASLIST_DELETED:
3010
0
    upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
3011
0
    break;
3012
0
  case RMAP_EVENT_LLIST_ADDED:
3013
0
  case RMAP_EVENT_LLIST_DELETED:
3014
0
    upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
3015
0
    break;
3016
0
  case RMAP_EVENT_CALL_ADDED:
3017
0
  case RMAP_EVENT_CALL_DELETED:
3018
0
  case RMAP_EVENT_MATCH_ADDED:
3019
0
  case RMAP_EVENT_MATCH_DELETED:
3020
0
    upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
3021
0
    break;
3022
0
  case RMAP_EVENT_FILTER_ADDED:
3023
0
  case RMAP_EVENT_FILTER_DELETED:
3024
0
    upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
3025
0
    break;
3026
  /*
3027
   * Should we actually be ignoring these?
3028
   * I am not sure but at this point in time, let
3029
   * us get them into this switch and we can peel
3030
   * them into the appropriate place in the future
3031
   */
3032
0
  case RMAP_EVENT_SET_ADDED:
3033
0
  case RMAP_EVENT_SET_DELETED:
3034
0
  case RMAP_EVENT_SET_REPLACED:
3035
0
  case RMAP_EVENT_MATCH_REPLACED:
3036
0
  case RMAP_EVENT_INDEX_ADDED:
3037
0
  case RMAP_EVENT_INDEX_DELETED:
3038
0
    upd8_hash = NULL;
3039
0
    break;
3040
7.53k
  }
3041
7.53k
  return (upd8_hash);
3042
7.53k
}
3043
3044
static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
3045
0
{
3046
0
  struct route_map_dep_data *dep_data = NULL;
3047
0
  char *rmap_name = NULL;
3048
3049
0
  dep_data = bucket->data;
3050
0
  rmap_name = dep_data->rname;
3051
3052
0
  if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
3053
0
    zlog_debug("Notifying %s of dependency", rmap_name);
3054
0
  if (route_map_master.event_hook)
3055
0
    (*route_map_master.event_hook)(rmap_name);
3056
0
}
3057
3058
void route_map_upd8_dependency(route_map_event_t type, const char *arg,
3059
             const char *rmap_name)
3060
0
{
3061
0
  struct hash *upd8_hash = NULL;
3062
3063
0
  if ((upd8_hash = route_map_get_dep_hash(type))) {
3064
0
    route_map_dep_update(upd8_hash, arg, rmap_name, type);
3065
3066
0
    if (type == RMAP_EVENT_CALL_ADDED) {
3067
      /* Execute hook. */
3068
0
      if (route_map_master.add_hook)
3069
0
        (*route_map_master.add_hook)(rmap_name);
3070
0
    } else if (type == RMAP_EVENT_CALL_DELETED) {
3071
      /* Execute hook. */
3072
0
      if (route_map_master.delete_hook)
3073
0
        (*route_map_master.delete_hook)(rmap_name);
3074
0
    }
3075
0
  }
3076
0
}
3077
3078
void route_map_notify_dependencies(const char *affected_name,
3079
           route_map_event_t event)
3080
3.31k
{
3081
3.31k
  struct route_map_dep *dep;
3082
3.31k
  struct hash *upd8_hash;
3083
3.31k
  char *name;
3084
3085
3.31k
  if (!affected_name)
3086
0
    return;
3087
3088
3.31k
  name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
3089
3090
3.31k
  if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
3091
0
    XFREE(MTYPE_ROUTE_MAP_NAME, name);
3092
0
    return;
3093
0
  }
3094
3095
3.31k
  dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
3096
3.31k
  if (dep) {
3097
0
    if (!dep->this_hash)
3098
0
      dep->this_hash = upd8_hash;
3099
3100
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
3101
0
      zlog_debug("Filter %s updated", dep->dep_name);
3102
0
    hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
3103
0
           (void *)event);
3104
0
  }
3105
3106
3.31k
  XFREE(MTYPE_ROUTE_MAP_NAME, name);
3107
3.31k
}
3108
3109
/* VTY related functions. */
3110
static void clear_route_map_helper(struct route_map *map)
3111
0
{
3112
0
  struct route_map_index *index;
3113
3114
0
  map->applied_clear = map->applied;
3115
0
  for (index = map->head; index; index = index->next)
3116
0
    index->applied_clear = index->applied;
3117
0
}
3118
3119
DEFPY (rmap_clear_counters,
3120
       rmap_clear_counters_cmd,
3121
       "clear route-map counters [RMAP_NAME$rmapname]",
3122
       CLEAR_STR
3123
       "route-map information\n"
3124
       "counters associated with the specified route-map\n"
3125
       "route-map name\n")
3126
0
{
3127
0
  struct route_map *map;
3128
3129
0
  if (rmapname) {
3130
0
    map = route_map_lookup_by_name(rmapname);
3131
3132
0
    if (map)
3133
0
      clear_route_map_helper(map);
3134
0
    else {
3135
0
      vty_out(vty, "%s: 'route-map %s' not found\n",
3136
0
        frr_protonameinst, rmapname);
3137
0
      return CMD_SUCCESS;
3138
0
    }
3139
0
  } else {
3140
0
    for (map = route_map_master.head; map; map = map->next)
3141
0
      clear_route_map_helper(map);
3142
0
  }
3143
3144
0
  return CMD_SUCCESS;
3145
3146
0
}
3147
3148
DEFUN (rmap_show_name,
3149
       rmap_show_name_cmd,
3150
       "show route-map [WORD] [json]",
3151
       SHOW_STR
3152
       "route-map information\n"
3153
       "route-map name\n"
3154
       JSON_STR)
3155
0
{
3156
0
  bool uj = use_json(argc, argv);
3157
0
  int idx = 0;
3158
0
  const char *name = NULL;
3159
3160
0
  if (argv_find(argv, argc, "WORD", &idx))
3161
0
    name = argv[idx]->arg;
3162
3163
0
  return vty_show_route_map(vty, name, uj);
3164
0
}
3165
3166
DEFUN (rmap_show_unused,
3167
       rmap_show_unused_cmd,
3168
       "show route-map-unused",
3169
       SHOW_STR
3170
       "unused route-map information\n")
3171
0
{
3172
0
  return vty_show_unused_route_map(vty);
3173
0
}
3174
3175
DEFPY (debug_rmap,
3176
       debug_rmap_cmd,
3177
       "debug route-map [detail]$detail",
3178
       DEBUG_STR
3179
       "Debug option set for route-maps\n"
3180
       "Detailed output\n")
3181
0
{
3182
0
  if (!detail)
3183
0
    SET_FLAG(rmap_debug, DEBUG_ROUTEMAP);
3184
0
  else
3185
0
    SET_FLAG(rmap_debug, DEBUG_ROUTEMAP | DEBUG_ROUTEMAP_DETAIL);
3186
3187
0
  return CMD_SUCCESS;
3188
0
}
3189
3190
DEFPY (no_debug_rmap,
3191
       no_debug_rmap_cmd,
3192
       "no debug route-map [detail]$detail",
3193
       NO_STR
3194
       DEBUG_STR
3195
       "Debug option set for route-maps\n"
3196
       "Detailed output\n")
3197
0
{
3198
0
  if (!detail)
3199
0
    UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP);
3200
0
  else
3201
0
    UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP | DEBUG_ROUTEMAP_DETAIL);
3202
3203
0
  return CMD_SUCCESS;
3204
0
}
3205
3206
/* Debug node. */
3207
static int rmap_config_write_debug(struct vty *vty);
3208
static struct cmd_node rmap_debug_node = {
3209
  .name = "route-map debug",
3210
  .node = RMAP_DEBUG_NODE,
3211
  .prompt = "",
3212
  .config_write = rmap_config_write_debug,
3213
};
3214
3215
void route_map_show_debug(struct vty *vty)
3216
0
{
3217
0
  if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
3218
0
    vty_out(vty, "debug route-map\n");
3219
0
}
3220
3221
/* Configuration write function. */
3222
static int rmap_config_write_debug(struct vty *vty)
3223
0
{
3224
0
  int write = 0;
3225
3226
0
  if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)) {
3227
0
    vty_out(vty, "debug route-map\n");
3228
0
    write++;
3229
0
  }
3230
3231
0
  return write;
3232
0
}
3233
3234
/* Common route map rules */
3235
3236
void *route_map_rule_tag_compile(const char *arg)
3237
0
{
3238
0
  unsigned long int tmp;
3239
0
  char *endptr;
3240
0
  route_tag_t *tag;
3241
3242
0
  errno = 0;
3243
0
  tmp = strtoul(arg, &endptr, 0);
3244
0
  if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
3245
0
    return NULL;
3246
3247
0
  tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
3248
0
  *tag = tmp;
3249
3250
0
  return tag;
3251
0
}
3252
3253
void route_map_rule_tag_free(void *rule)
3254
0
{
3255
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3256
0
}
3257
3258
void route_map_finish(void)
3259
0
{
3260
0
  int i;
3261
0
  struct route_map_rule_cmd_proxy *proxy;
3262
3263
  /* these 2 hash tables have INIT_HASH initializers, so the "default"
3264
   * state is "initialized & empty" => fini() followed by init() to
3265
   * return to that same state
3266
   */
3267
0
  while ((proxy = rmap_cmd_name_pop(rmap_match_cmds)))
3268
0
    (void)proxy;
3269
0
  rmap_cmd_name_fini(rmap_match_cmds);
3270
0
  rmap_cmd_name_init(rmap_match_cmds);
3271
3272
0
  while ((proxy = rmap_cmd_name_pop(rmap_set_cmds)))
3273
0
    (void)proxy;
3274
0
  rmap_cmd_name_fini(rmap_set_cmds);
3275
0
  rmap_cmd_name_init(rmap_set_cmds);
3276
3277
  /*
3278
   * All protocols are setting these to NULL
3279
   * by default on shutdown( route_map_finish )
3280
   * Why are we making them do this work?
3281
   */
3282
0
  route_map_master.add_hook = NULL;
3283
0
  route_map_master.delete_hook = NULL;
3284
0
  route_map_master.event_hook = NULL;
3285
3286
  /* cleanup route_map */
3287
0
  while (route_map_master.head) {
3288
0
    struct route_map *map = route_map_master.head;
3289
0
    map->to_be_processed = false;
3290
0
    route_map_delete(map);
3291
0
  }
3292
3293
0
  for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
3294
0
    hash_free(route_map_dep_hash[i]);
3295
0
    route_map_dep_hash[i] = NULL;
3296
0
  }
3297
3298
0
  hash_free(route_map_master_hash);
3299
0
  route_map_master_hash = NULL;
3300
0
}
3301
3302
/* Increment the use_count counter while attaching the route map */
3303
void route_map_counter_increment(struct route_map *map)
3304
0
{
3305
0
  if (map)
3306
0
    map->use_count++;
3307
0
}
3308
3309
/* Decrement the use_count counter while detaching the route map. */
3310
void route_map_counter_decrement(struct route_map *map)
3311
0
{
3312
0
  if (map) {
3313
0
    if (map->use_count <= 0)
3314
0
      return;
3315
0
    map->use_count--;
3316
0
  }
3317
0
}
3318
3319
DEFUN_HIDDEN(show_route_map_pfx_tbl, show_route_map_pfx_tbl_cmd,
3320
       "show route-map RMAP_NAME prefix-table",
3321
       SHOW_STR
3322
       "route-map\n"
3323
       "route-map name\n"
3324
       "internal prefix-table\n")
3325
0
{
3326
0
  const char *rmap_name = argv[2]->arg;
3327
0
  struct route_map *rmap = NULL;
3328
0
  struct route_table *rm_pfx_tbl4 = NULL;
3329
0
  struct route_table *rm_pfx_tbl6 = NULL;
3330
0
  struct route_node *rn = NULL, *prn = NULL;
3331
0
  struct list *rmap_index_list = NULL;
3332
0
  struct listnode *ln = NULL, *nln = NULL;
3333
0
  struct route_map_index *index = NULL;
3334
0
  uint8_t len = 54;
3335
3336
0
  vty_out(vty, "%s:\n", frr_protonameinst);
3337
0
  rmap = route_map_lookup_by_name(rmap_name);
3338
0
  if (rmap) {
3339
0
    rm_pfx_tbl4 = rmap->ipv4_prefix_table;
3340
0
    if (rm_pfx_tbl4) {
3341
0
      vty_out(vty, "\n%s%43s%s\n", "IPv4 Prefix", "",
3342
0
        "Route-map Index List");
3343
0
      vty_out(vty, "%s%39s%s\n", "_______________", "",
3344
0
        "____________________");
3345
0
      for (rn = route_top(rm_pfx_tbl4); rn;
3346
0
           rn = route_next(rn)) {
3347
0
        vty_out(vty, "    %pRN (%d)\n", rn,
3348
0
          route_node_get_lock_count(rn));
3349
3350
0
        vty_out(vty, "(P) ");
3351
0
        prn = rn->parent;
3352
0
        if (prn) {
3353
0
          vty_out(vty, "%pRN\n", prn);
3354
0
        }
3355
3356
0
        vty_out(vty, "\n");
3357
0
        rmap_index_list = (struct list *)rn->info;
3358
0
        if (!rmap_index_list
3359
0
            || !listcount(rmap_index_list))
3360
0
          vty_out(vty, "%*s%s\n", len, "", "-");
3361
0
        else
3362
0
          for (ALL_LIST_ELEMENTS(rmap_index_list,
3363
0
                     ln, nln,
3364
0
                     index)) {
3365
0
            vty_out(vty, "%*s%s seq %d\n",
3366
0
              len, "",
3367
0
              index->map->name,
3368
0
              index->pref);
3369
0
          }
3370
0
        vty_out(vty, "\n");
3371
0
      }
3372
0
    }
3373
3374
0
    rm_pfx_tbl6 = rmap->ipv6_prefix_table;
3375
0
    if (rm_pfx_tbl6) {
3376
0
      vty_out(vty, "\n%s%43s%s\n", "IPv6 Prefix", "",
3377
0
        "Route-map Index List");
3378
0
      vty_out(vty, "%s%39s%s\n", "_______________", "",
3379
0
        "____________________");
3380
0
      for (rn = route_top(rm_pfx_tbl6); rn;
3381
0
           rn = route_next(rn)) {
3382
0
        vty_out(vty, "    %pRN (%d)\n", rn,
3383
0
          route_node_get_lock_count(rn));
3384
3385
0
        vty_out(vty, "(P) ");
3386
0
        prn = rn->parent;
3387
0
        if (prn) {
3388
0
          vty_out(vty, "%pRN\n", prn);
3389
0
        }
3390
3391
0
        vty_out(vty, "\n");
3392
0
        rmap_index_list = (struct list *)rn->info;
3393
0
        if (!rmap_index_list
3394
0
            || !listcount(rmap_index_list))
3395
0
          vty_out(vty, "%*s%s\n", len, "", "-");
3396
0
        else
3397
0
          for (ALL_LIST_ELEMENTS(rmap_index_list,
3398
0
                     ln, nln,
3399
0
                     index)) {
3400
0
            vty_out(vty, "%*s%s seq %d\n",
3401
0
              len, "",
3402
0
              index->map->name,
3403
0
              index->pref);
3404
0
          }
3405
0
        vty_out(vty, "\n");
3406
0
      }
3407
0
    }
3408
0
  }
3409
3410
0
  vty_out(vty, "\n");
3411
0
  return CMD_SUCCESS;
3412
0
}
3413
3414
/* Initialization of route map vector. */
3415
void route_map_init(void)
3416
4
{
3417
4
  int i;
3418
3419
4
  route_map_master_hash =
3420
4
    hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
3421
4
         "Route Map Master Hash");
3422
3423
32
  for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
3424
28
    route_map_dep_hash[i] = hash_create_size(
3425
28
      8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3426
28
      "Route Map Dep Hash");
3427
3428
4
  UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP);
3429
3430
4
  route_map_cli_init();
3431
3432
  /* Install route map top node. */
3433
4
  install_node(&rmap_debug_node);
3434
3435
  /* Install route map commands. */
3436
4
  install_element(CONFIG_NODE, &debug_rmap_cmd);
3437
4
  install_element(CONFIG_NODE, &no_debug_rmap_cmd);
3438
3439
  /* Install show command */
3440
4
  install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
3441
3442
4
  install_element(ENABLE_NODE, &rmap_show_name_cmd);
3443
4
  install_element(ENABLE_NODE, &rmap_show_unused_cmd);
3444
3445
4
  install_element(ENABLE_NODE, &debug_rmap_cmd);
3446
4
  install_element(ENABLE_NODE, &no_debug_rmap_cmd);
3447
3448
4
  install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
3449
4
}