Coverage Report

Created: 2025-08-28 06:29

/src/frr/zebra/zebra_routemap.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* zebra routemap.
3
 * Copyright (C) 2006 IBM Corporation
4
 */
5
6
#include <zebra.h>
7
8
#include "memory.h"
9
#include "prefix.h"
10
#include "rib.h"
11
#include "vty.h"
12
#include "routemap.h"
13
#include "command.h"
14
#include "filter.h"
15
#include "plist.h"
16
#include "nexthop.h"
17
#include "northbound_cli.h"
18
#include "lib/route_types.h"
19
#include "vrf.h"
20
#include "frrstr.h"
21
22
#include "zebra/zebra_router.h"
23
#include "zebra/redistribute.h"
24
#include "zebra/debug.h"
25
#include "zebra/zebra_rnh.h"
26
#include "zebra/zebra_routemap.h"
27
28
#include "zebra/zebra_routemap_clippy.c"
29
30
static uint32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER;
31
static struct event *zebra_t_rmap_update = NULL;
32
char *zebra_import_table_routemap[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX];
33
34
struct nh_rmap_obj {
35
  struct nexthop *nexthop;
36
  vrf_id_t vrf_id;
37
  uint32_t source_protocol;
38
  uint8_t instance;
39
  int metric;
40
  route_tag_t tag;
41
};
42
43
static void zebra_route_map_set_delay_timer(uint32_t value);
44
45
/* 'match tag TAG'
46
 * Match function return 1 if match is success else return 0
47
 */
48
static enum route_map_cmd_result_t
49
route_match_tag(void *rule, const struct prefix *prefix, void *object)
50
0
{
51
0
  route_tag_t *tag;
52
0
  struct nh_rmap_obj *nh_data;
53
54
0
  tag = rule;
55
0
  nh_data = object;
56
57
0
  if (nh_data->tag == *tag)
58
0
    return RMAP_MATCH;
59
60
0
  return RMAP_NOMATCH;
61
0
}
62
63
/* Route map commands for tag matching */
64
static const struct route_map_rule_cmd route_match_tag_cmd = {
65
  "tag",
66
  route_match_tag,
67
  route_map_rule_tag_compile,
68
  route_map_rule_tag_free,
69
};
70
71
72
/* `match interface IFNAME' */
73
/* Match function return 1 if match is success else return zero. */
74
static enum route_map_cmd_result_t
75
route_match_interface(void *rule, const struct prefix *prefix, void *object)
76
0
{
77
0
  struct nh_rmap_obj *nh_data;
78
0
  char *ifname = rule;
79
0
  ifindex_t ifindex;
80
81
0
  if (strcasecmp(ifname, "any") == 0)
82
0
    return RMAP_MATCH;
83
0
  nh_data = object;
84
0
  if (!nh_data || !nh_data->nexthop)
85
0
    return RMAP_NOMATCH;
86
0
  ifindex = ifname2ifindex(ifname, nh_data->vrf_id);
87
0
  if (ifindex == 0)
88
0
    return RMAP_NOMATCH;
89
0
  if (nh_data->nexthop->ifindex == ifindex)
90
0
    return RMAP_MATCH;
91
92
0
  return RMAP_NOMATCH;
93
0
}
94
95
/* Route map `match interface' match statement. `arg' is IFNAME value */
96
static void *route_match_interface_compile(const char *arg)
97
0
{
98
0
  return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
99
0
}
100
101
/* Free route map's compiled `match interface' value. */
102
static void route_match_interface_free(void *rule)
103
0
{
104
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
105
0
}
106
107
static void show_vrf_proto_rm(struct vty *vty, struct zebra_vrf *zvrf,
108
            int af_type)
109
0
{
110
0
  int i;
111
112
0
  vty_out(vty, "Protocol                  : route-map\n");
113
0
  vty_out(vty, "-------------------------------------\n");
114
115
0
  for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
116
0
    if (PROTO_RM_NAME(zvrf, af_type, i))
117
0
      vty_out(vty, "%-24s  : %-10s\n", zebra_route_string(i),
118
0
        PROTO_RM_NAME(zvrf, af_type, i));
119
0
    else
120
0
      vty_out(vty, "%-24s  : none\n", zebra_route_string(i));
121
0
  }
122
123
0
  if (PROTO_RM_NAME(zvrf, af_type, i))
124
0
    vty_out(vty, "%-24s  : %-10s\n", "any",
125
0
      PROTO_RM_NAME(zvrf, af_type, i));
126
0
  else
127
0
    vty_out(vty, "%-24s  : none\n", "any");
128
0
}
129
130
static void show_vrf_nht_rm(struct vty *vty, struct zebra_vrf *zvrf,
131
          int af_type, json_object *json)
132
0
{
133
0
  int i;
134
135
0
  if (!json) {
136
0
    vty_out(vty, "Protocol                  : route-map\n");
137
0
    vty_out(vty, "-------------------------------------\n");
138
0
  }
139
140
0
  for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
141
0
    if (json) {
142
0
      if (NHT_RM_NAME(zvrf, af_type, i))
143
0
        json_object_string_add(
144
0
          json, zebra_route_string(i),
145
0
          NHT_RM_NAME(zvrf, af_type, i));
146
0
      else
147
0
        json_object_string_add(
148
0
          json, zebra_route_string(i), "none");
149
0
    } else {
150
0
      if (NHT_RM_NAME(zvrf, af_type, i))
151
0
        vty_out(vty, "%-24s  : %-10s\n",
152
0
          zebra_route_string(i),
153
0
          NHT_RM_NAME(zvrf, af_type, i));
154
0
      else
155
0
        vty_out(vty, "%-24s  : none\n",
156
0
          zebra_route_string(i));
157
0
    }
158
0
  }
159
160
0
  if (json) {
161
0
    if (NHT_RM_NAME(zvrf, af_type, i))
162
0
      json_object_string_add(json, "any",
163
0
                 NHT_RM_NAME(zvrf, af_type, i));
164
0
    else
165
0
      json_object_string_add(json, "any", "none");
166
0
  } else {
167
0
    if (NHT_RM_NAME(zvrf, af_type, i))
168
0
      vty_out(vty, "%-24s  : %-10s\n", "any",
169
0
        NHT_RM_NAME(zvrf, af_type, i));
170
0
    else
171
0
      vty_out(vty, "%-24s  : none\n", "any");
172
0
  }
173
0
}
174
175
static int show_proto_rm(struct vty *vty, int af_type, const char *vrf_all,
176
       const char *vrf_name)
177
0
{
178
0
  struct zebra_vrf *zvrf;
179
180
0
  if (vrf_all) {
181
0
    struct vrf *vrf;
182
183
0
    RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
184
0
      zvrf = (struct zebra_vrf *)vrf->info;
185
0
      if (zvrf == NULL)
186
0
        continue;
187
0
      vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
188
0
      show_vrf_proto_rm(vty, zvrf, af_type);
189
0
    }
190
0
  } else {
191
0
    vrf_id_t vrf_id = VRF_DEFAULT;
192
193
0
    if (vrf_name)
194
0
      VRF_GET_ID(vrf_id, vrf_name, false);
195
196
0
    zvrf = zebra_vrf_lookup_by_id(vrf_id);
197
0
    if (!zvrf)
198
0
      return CMD_SUCCESS;
199
200
0
    vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
201
0
    show_vrf_proto_rm(vty, zvrf, af_type);
202
0
  }
203
204
0
  return CMD_SUCCESS;
205
0
}
206
207
static int show_nht_rm(struct vty *vty, int af_type, const char *vrf_all,
208
           const char *vrf_name, bool use_json)
209
0
{
210
0
  struct zebra_vrf *zvrf;
211
0
  json_object *json = NULL;
212
0
  json_object *json_vrfs = NULL;
213
214
0
  if (use_json) {
215
0
    json = json_object_new_object();
216
0
    json_vrfs = json_object_new_object();
217
0
    json_object_string_add(json, "afi",
218
0
               (af_type == AFI_IP) ? "ipv4" : "ipv6");
219
0
  }
220
221
0
  if (vrf_all) {
222
0
    struct vrf *vrf;
223
224
0
    if (use_json)
225
0
      json_object_object_add(json, "vrfs", json_vrfs);
226
227
0
    RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
228
0
      zvrf = (struct zebra_vrf *)vrf->info;
229
0
      if (zvrf == NULL)
230
0
        continue;
231
232
0
      if (use_json) {
233
0
        json_object *json_proto = NULL;
234
0
        json_object *json_vrf = NULL;
235
0
        json_vrf = json_object_new_object();
236
0
        json_object_object_add(
237
0
          json_vrfs, zvrf->vrf->name, json_vrf);
238
0
        json_proto = json_object_new_object();
239
0
        json_object_object_add(json_vrf, "protocols",
240
0
                   json_proto);
241
0
        show_vrf_nht_rm(vty, zvrf, af_type, json_proto);
242
0
      } else {
243
0
        vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
244
0
        show_vrf_nht_rm(vty, zvrf, af_type, NULL);
245
0
      }
246
0
    }
247
0
  } else {
248
0
    json_object *json_proto = NULL;
249
0
    json_object *json_vrf = NULL;
250
0
    vrf_id_t vrf_id = VRF_DEFAULT;
251
252
0
    if (vrf_name)
253
0
      VRF_GET_ID(vrf_id, vrf_name, false);
254
255
0
    zvrf = zebra_vrf_lookup_by_id(vrf_id);
256
0
    if (!zvrf) {
257
0
      json_object_free(json);
258
0
      json_object_free(json_vrfs);
259
0
      return CMD_SUCCESS;
260
0
    }
261
262
0
    if (use_json) {
263
0
      json_object_object_add(json, "vrfs", json_vrfs);
264
0
      json_vrf = json_object_new_object();
265
0
      json_object_object_add(json_vrfs, zvrf->vrf->name,
266
0
                 json_vrf);
267
0
      json_proto = json_object_new_object();
268
0
      json_object_object_add(json_vrf, "protocols",
269
0
                 json_proto);
270
0
      show_vrf_nht_rm(vty, zvrf, af_type, json_proto);
271
0
    } else {
272
0
      vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
273
0
      show_vrf_nht_rm(vty, zvrf, af_type, NULL);
274
0
    }
275
0
  }
276
277
0
  if (use_json)
278
0
    vty_json(vty, json);
279
280
0
  return CMD_SUCCESS;
281
0
}
282
283
/* Route map commands for interface matching */
284
static const struct route_map_rule_cmd route_match_interface_cmd = {
285
  "interface",
286
  route_match_interface,
287
  route_match_interface_compile,
288
  route_match_interface_free
289
};
290
291
static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap,
292
            int rtype, afi_t afi, safi_t safi)
293
0
{
294
0
  struct route_table *table;
295
296
0
  if (PROTO_RM_NAME(zvrf, afi, rtype)) {
297
0
    if (strcmp(PROTO_RM_NAME(zvrf, afi, rtype), rmap) == 0)
298
0
      return CMD_SUCCESS;
299
300
0
    XFREE(MTYPE_ROUTE_MAP_NAME, PROTO_RM_NAME(zvrf, afi, rtype));
301
0
  }
302
0
  route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype));
303
0
  PROTO_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
304
0
  PROTO_RM_MAP(zvrf, afi, rtype) =
305
0
    route_map_lookup_by_name(PROTO_RM_NAME(zvrf, afi, rtype));
306
0
  route_map_counter_increment(PROTO_RM_MAP(zvrf, afi, rtype));
307
308
0
  if (PROTO_RM_MAP(zvrf, afi, rtype)) {
309
310
0
    if (IS_ZEBRA_DEBUG_RIB_DETAILED)
311
0
      zlog_debug(
312
0
        "%u: IPv4 Routemap config for protocol %d scheduling RIB processing",
313
0
        zvrf->vrf->vrf_id, rtype);
314
    /* Process routes of interested address-families. */
315
0
    table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id);
316
0
    if (table)
317
0
      rib_update_table(table, RIB_UPDATE_RMAP_CHANGE,
318
0
           rtype);
319
0
  }
320
321
0
  return CMD_SUCCESS;
322
0
}
323
324
static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap,
325
            int rtype, afi_t afi, safi_t safi)
326
0
{
327
0
  struct route_table *table;
328
329
0
  if (!PROTO_RM_NAME(zvrf, afi, rtype))
330
0
    return CMD_SUCCESS;
331
332
0
  if (!rmap || strcmp(rmap, PROTO_RM_NAME(zvrf, afi, rtype)) == 0) {
333
334
0
    route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype));
335
0
    if (PROTO_RM_MAP(zvrf, afi, rtype)) {
336
0
      if (IS_ZEBRA_DEBUG_RIB_DETAILED)
337
0
        zlog_debug(
338
0
          "%u: IPv4 Routemap unconfig for protocol %d, scheduling RIB processing",
339
0
          zvrf->vrf->vrf_id, rtype);
340
0
      PROTO_RM_MAP(zvrf, afi, rtype) = NULL;
341
342
      /* Process routes of interested address-families. */
343
0
      table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id);
344
0
      if (table)
345
0
        rib_update_table(table, RIB_UPDATE_RMAP_CHANGE,
346
0
             rtype);
347
0
    }
348
0
    XFREE(MTYPE_ROUTE_MAP_NAME, PROTO_RM_NAME(zvrf, afi, rtype));
349
0
  }
350
0
  return CMD_SUCCESS;
351
0
}
352
353
static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype,
354
       int afi)
355
0
{
356
357
0
  if (NHT_RM_NAME(zvrf, afi, rtype)) {
358
0
    if (strcmp(NHT_RM_NAME(zvrf, afi, rtype), rmap) == 0)
359
0
      return CMD_SUCCESS;
360
361
0
    XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype));
362
0
  }
363
0
  route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype));
364
0
  NHT_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
365
0
  NHT_RM_MAP(zvrf, afi, rtype) =
366
0
    route_map_lookup_by_name(NHT_RM_NAME(zvrf, afi, rtype));
367
0
  route_map_counter_increment(NHT_RM_MAP(zvrf, afi, rtype));
368
369
0
  if (NHT_RM_MAP(zvrf, afi, rtype))
370
0
    zebra_evaluate_rnh(zvrf, afi, 1, NULL, SAFI_UNICAST);
371
372
0
  return CMD_SUCCESS;
373
0
}
374
375
static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype,
376
       int afi)
377
0
{
378
379
0
  if (!NHT_RM_NAME(zvrf, afi, rtype))
380
0
    return CMD_SUCCESS;
381
382
0
  if (!rmap || strcmp(rmap, NHT_RM_NAME(zvrf, afi, rtype)) == 0) {
383
0
    route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype));
384
0
    if (NHT_RM_MAP(zvrf, afi, rtype)) {
385
0
      if (IS_ZEBRA_DEBUG_RIB_DETAILED)
386
0
        zlog_debug(
387
0
          "%u: IPv4 Routemap unconfig for protocol %d, scheduling RIB processing",
388
0
          zvrf->vrf->vrf_id, rtype);
389
0
      NHT_RM_MAP(zvrf, afi, rtype) = NULL;
390
391
0
      zebra_evaluate_rnh(zvrf, afi, 1, NULL, SAFI_UNICAST);
392
0
    }
393
0
    XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype));
394
0
  }
395
0
  return CMD_SUCCESS;
396
0
}
397
398
DEFPY_YANG(
399
  match_ip_address_prefix_len, match_ip_address_prefix_len_cmd,
400
  "match ip address prefix-len (0-32)$length",
401
  MATCH_STR
402
  IP_STR
403
  "Match prefix length of IP address\n"
404
  "Match prefix length of IP address\n"
405
  "Prefix length\n")
406
0
{
407
0
  const char *xpath =
408
0
    "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']";
409
0
  char xpath_value[XPATH_MAXLEN];
410
411
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
412
0
  snprintf(
413
0
    xpath_value, sizeof(xpath_value),
414
0
    "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length",
415
0
    xpath);
416
0
  nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str);
417
418
0
  return nb_cli_apply_changes(vty, NULL);
419
0
}
420
421
DEFPY_YANG(
422
  no_match_ip_address_prefix_len, no_match_ip_address_prefix_len_cmd,
423
  "no match ip address prefix-len [(0-32)]",
424
  NO_STR
425
  MATCH_STR
426
  IP_STR
427
  "Match prefix length of IP address\n"
428
  "Match prefix length of IP address\n"
429
  "Prefix length\n")
430
0
{
431
0
  const char *xpath =
432
0
    "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']";
433
434
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
435
436
0
  return nb_cli_apply_changes(vty, NULL);
437
0
}
438
439
DEFPY_YANG(
440
  match_ipv6_address_prefix_len, match_ipv6_address_prefix_len_cmd,
441
  "match ipv6 address prefix-len (0-128)$length",
442
  MATCH_STR
443
  IPV6_STR
444
  "Match prefix length of IPv6 address\n"
445
  "Match prefix length of IPv6 address\n"
446
  "Prefix length\n")
447
0
{
448
0
  const char *xpath =
449
0
    "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']";
450
0
  char xpath_value[XPATH_MAXLEN];
451
452
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
453
0
  snprintf(
454
0
    xpath_value, sizeof(xpath_value),
455
0
    "%s/rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length",
456
0
    xpath);
457
0
  nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str);
458
459
0
  return nb_cli_apply_changes(vty, NULL);
460
0
}
461
462
DEFPY_YANG(
463
  no_match_ipv6_address_prefix_len, no_match_ipv6_address_prefix_len_cmd,
464
  "no match ipv6 address prefix-len [(0-128)]",
465
  NO_STR
466
  MATCH_STR
467
  IPV6_STR
468
  "Match prefix length of IPv6 address\n"
469
  "Match prefix length of IPv6 address\n"
470
  "Prefix length\n")
471
0
{
472
0
  const char *xpath =
473
0
    "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']";
474
475
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
476
477
0
  return nb_cli_apply_changes(vty, NULL);
478
0
}
479
480
DEFPY_YANG(
481
  match_ip_nexthop_prefix_len, match_ip_nexthop_prefix_len_cmd,
482
  "match ip next-hop prefix-len (0-32)$length",
483
  MATCH_STR
484
  IP_STR
485
  "Match prefixlen of nexthop IP address\n"
486
  "Match prefixlen of given nexthop\n"
487
  "Prefix length\n")
488
0
{
489
0
  const char *xpath =
490
0
    "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']";
491
0
  char xpath_value[XPATH_MAXLEN];
492
493
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
494
0
  snprintf(
495
0
    xpath_value, sizeof(xpath_value),
496
0
    "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length",
497
0
    xpath);
498
0
  nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str);
499
500
0
  return nb_cli_apply_changes(vty, NULL);
501
0
}
502
503
DEFPY_YANG(
504
  no_match_ip_nexthop_prefix_len, no_match_ip_nexthop_prefix_len_cmd,
505
  "no match ip next-hop prefix-len [(0-32)]",
506
  NO_STR
507
  MATCH_STR
508
  IP_STR
509
  "Match prefixlen of nexthop IP address\n"
510
  "Match prefix length of nexthop\n"
511
  "Prefix length\n")
512
0
{
513
0
  const char *xpath =
514
0
    "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']";
515
516
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
517
518
0
  return nb_cli_apply_changes(vty, NULL);
519
0
}
520
521
DEFPY_YANG(
522
  match_source_protocol, match_source_protocol_cmd,
523
  "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto",
524
  MATCH_STR
525
  "Match protocol via which the route was learnt\n"
526
  FRR_REDIST_HELP_STR_ZEBRA)
527
0
{
528
0
  const char *xpath =
529
0
    "./match-condition[condition='frr-zebra-route-map:source-protocol']";
530
0
  char xpath_value[XPATH_MAXLEN];
531
532
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
533
0
  snprintf(xpath_value, sizeof(xpath_value),
534
0
     "%s/rmap-match-condition/frr-zebra-route-map:source-protocol",
535
0
     xpath);
536
0
  nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto);
537
538
0
  return nb_cli_apply_changes(vty, NULL);
539
0
}
540
541
DEFPY_YANG(
542
  no_match_source_protocol, no_match_source_protocol_cmd,
543
  "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]",
544
  NO_STR
545
  MATCH_STR
546
  "Match protocol via which the route was learnt\n"
547
  FRR_REDIST_HELP_STR_ZEBRA)
548
0
{
549
0
  const char *xpath =
550
0
    "./match-condition[condition='frr-zebra-route-map:source-protocol']";
551
552
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
553
554
0
  return nb_cli_apply_changes(vty, NULL);
555
0
}
556
557
DEFPY_YANG(
558
  match_source_instance, match_source_instance_cmd,
559
  "match source-instance (0-255)$instance",
560
  MATCH_STR
561
  "Match the protocol's instance number\n"
562
  "The instance number\n")
563
0
{
564
0
  const char *xpath =
565
0
    "./match-condition[condition='frr-zebra-route-map:source-instance']";
566
0
  char xpath_value[XPATH_MAXLEN];
567
568
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
569
0
  snprintf(xpath_value, sizeof(xpath_value),
570
0
     "%s/rmap-match-condition/frr-zebra-route-map:source-instance",
571
0
     xpath);
572
0
  nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str);
573
574
0
  return nb_cli_apply_changes(vty, NULL);
575
0
}
576
577
DEFPY_YANG(
578
  no_match_source_instance, no_match_source_instance_cmd,
579
  "no match source-instance [(0-255)]",
580
  NO_STR MATCH_STR
581
  "Match the protocol's instance number\n"
582
  "The instance number\n")
583
0
{
584
0
  const char *xpath =
585
0
    "./match-condition[condition='frr-zebra-route-map:source-instance']";
586
587
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
588
589
0
  return nb_cli_apply_changes(vty, NULL);
590
0
}
591
592
/* set functions */
593
594
DEFPY_YANG(
595
  set_src, set_src_cmd,
596
  "set src <A.B.C.D$addrv4|X:X::X:X$addrv6>",
597
  SET_STR
598
  "src address for route\n"
599
  "IPv4 src address\n"
600
  "IPv6 src address\n")
601
0
{
602
0
  const char *xpath =
603
0
    "./set-action[action='frr-zebra-route-map:src-address']";
604
0
  char xpath_value[XPATH_MAXLEN];
605
606
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
607
0
  if (addrv4_str) {
608
0
    snprintf(
609
0
      xpath_value, sizeof(xpath_value),
610
0
      "%s/rmap-set-action/frr-zebra-route-map:ipv4-src-address",
611
0
      xpath);
612
0
    nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
613
0
              addrv4_str);
614
0
  } else {
615
0
    snprintf(
616
0
      xpath_value, sizeof(xpath_value),
617
0
      "%s/rmap-set-action/frr-zebra-route-map:ipv6-src-address",
618
0
      xpath);
619
0
    nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
620
0
              addrv6_str);
621
0
  }
622
623
0
  return nb_cli_apply_changes(vty, NULL);
624
0
}
625
626
DEFPY_YANG(
627
  no_set_src, no_set_src_cmd,
628
  "no set src [<A.B.C.D|X:X::X:X>]",
629
  NO_STR
630
  SET_STR
631
  "Source address for route\n"
632
  "IPv4 address\n"
633
  "IPv6 address\n")
634
0
{
635
0
  const char *xpath =
636
0
    "./set-action[action='frr-zebra-route-map:src-address']";
637
638
0
  nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
639
640
0
  return nb_cli_apply_changes(vty, NULL);
641
0
}
642
643
DEFUN_YANG (zebra_route_map_timer,
644
       zebra_route_map_timer_cmd,
645
       "zebra route-map delay-timer (0-600)",
646
       ZEBRA_STR
647
       "Set route-map parameters\n"
648
       "Time to wait before route-map updates are processed\n"
649
       "0 means route-map changes are run immediately instead of delaying\n")
650
0
{
651
0
  int idx_number = 3;
652
0
  uint32_t rmap_delay_timer;
653
654
0
  rmap_delay_timer = strtoul(argv[idx_number]->arg, NULL, 10);
655
0
  zebra_route_map_set_delay_timer(rmap_delay_timer);
656
657
0
  return (CMD_SUCCESS);
658
0
}
659
660
DEFUN_YANG (no_zebra_route_map_timer,
661
       no_zebra_route_map_timer_cmd,
662
       "no zebra route-map delay-timer [(0-600)]",
663
       NO_STR
664
       ZEBRA_STR
665
       "Set route-map parameters\n"
666
       "Reset delay-timer to default value, 30 secs\n"
667
       "0 means route-map changes are run immediately instead of delaying\n")
668
0
{
669
0
  zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER);
670
671
0
  return (CMD_SUCCESS);
672
0
}
673
674
DEFPY_YANG (ip_protocol,
675
       ip_protocol_cmd,
676
       "ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA
677
       " $proto route-map ROUTE-MAP$rmap",
678
       IP_STR
679
       "Filter routing info exchanged between zebra and protocol\n"
680
       FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
681
       "Specify route-map\n"
682
       "Route map name\n")
683
0
{
684
0
  int ret, rtype;
685
686
0
  assert(proto);
687
0
  assert(rmap);
688
689
0
  ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
690
691
0
  if (!zvrf)
692
0
    return CMD_WARNING;
693
694
0
  if (strcasecmp(proto, "any") == 0)
695
0
    rtype = ZEBRA_ROUTE_MAX;
696
0
  else
697
0
    rtype = proto_name2num(proto);
698
0
  if (rtype < 0) {
699
0
    vty_out(vty, "invalid protocol name \"%s\"\n", proto);
700
0
    return CMD_WARNING_CONFIG_FAILED;
701
0
  }
702
703
0
  ret = ip_protocol_rm_add(zvrf, rmap, rtype, AFI_IP, SAFI_UNICAST);
704
705
0
  return ret;
706
0
}
707
708
DEFPY_YANG (no_ip_protocol,
709
       no_ip_protocol_cmd,
710
       "no ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA
711
       " $proto [route-map ROUTE-MAP$rmap]",
712
       NO_STR
713
       IP_STR
714
       "Stop filtering routing info between zebra and protocol\n"
715
       FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
716
       "Specify route-map\n"
717
       "Route map name\n")
718
0
{
719
0
  int ret, rtype;
720
721
0
  assert(proto);
722
723
0
  ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
724
725
0
  if (!zvrf)
726
0
    return CMD_WARNING;
727
728
0
  if (strcasecmp(proto, "any") == 0)
729
0
    rtype = ZEBRA_ROUTE_MAX;
730
0
  else
731
0
    rtype = proto_name2num(proto);
732
0
  if (rtype < 0) {
733
0
    vty_out(vty, "invalid protocol name \"%s\"\n", proto);
734
0
    return CMD_WARNING_CONFIG_FAILED;
735
0
  }
736
737
0
  ret = ip_protocol_rm_del(zvrf, rmap, rtype, AFI_IP, SAFI_UNICAST);
738
739
0
  return ret;
740
0
}
741
742
DEFPY_YANG (show_ip_protocol,
743
       show_ip_protocol_cmd,
744
       "show ip protocol [vrf <NAME$vrf_name|all$vrf_all>]",
745
       SHOW_STR
746
       IP_STR
747
       "IP protocol filtering status\n"
748
       VRF_FULL_CMD_HELP_STR)
749
0
{
750
0
  int ret = show_proto_rm(vty, AFI_IP, vrf_all, vrf_name);
751
752
0
  return ret;
753
0
}
754
755
DEFPY_YANG (ipv6_protocol,
756
       ipv6_protocol_cmd,
757
       "ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA
758
       " $proto route-map ROUTE-MAP$rmap",
759
       IP6_STR
760
       "Filter IPv6 routing info exchanged between zebra and protocol\n"
761
       FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
762
       "Specify route-map\n"
763
       "Route map name\n")
764
0
{
765
0
  int ret, rtype;
766
767
0
  assert(rmap);
768
0
  assert(proto);
769
770
0
  ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
771
772
0
  if (!zvrf)
773
0
    return CMD_WARNING;
774
775
0
  if (strcasecmp(proto, "any") == 0)
776
0
    rtype = ZEBRA_ROUTE_MAX;
777
0
  else
778
0
    rtype = proto_name2num(proto);
779
0
  if (rtype < 0) {
780
0
    vty_out(vty, "invalid protocol name \"%s\"\n", proto);
781
0
    return CMD_WARNING_CONFIG_FAILED;
782
0
  }
783
784
0
  ret = ip_protocol_rm_add(zvrf, rmap, rtype, AFI_IP6, SAFI_UNICAST);
785
786
0
  return ret;
787
0
}
788
789
DEFPY_YANG (no_ipv6_protocol,
790
       no_ipv6_protocol_cmd,
791
       "no ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA
792
       " $proto [route-map ROUTE-MAP$rmap]",
793
       NO_STR
794
       IP6_STR
795
       "Stop filtering IPv6 routing info between zebra and protocol\n"
796
       FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
797
       "Specify route-map\n"
798
       "Route map name\n")
799
0
{
800
0
  int ret, rtype;
801
802
0
  assert(proto);
803
804
0
  ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
805
806
0
  if (!zvrf)
807
0
    return CMD_WARNING;
808
809
0
  if (strcasecmp(proto, "any") == 0)
810
0
    rtype = ZEBRA_ROUTE_MAX;
811
0
  else
812
0
    rtype = proto_name2num(proto);
813
0
  if (rtype < 0) {
814
0
    vty_out(vty, "invalid protocol name \"%s\"\n", proto);
815
0
    return CMD_WARNING_CONFIG_FAILED;
816
0
  }
817
818
0
  ret = ip_protocol_rm_del(zvrf, rmap, rtype, AFI_IP6, SAFI_UNICAST);
819
820
0
  return ret;
821
0
}
822
823
DEFPY_YANG (show_ipv6_protocol,
824
       show_ipv6_protocol_cmd,
825
       "show ipv6 protocol [vrf <NAME$vrf_name|all$vrf_all>]",
826
       SHOW_STR
827
       IP6_STR
828
       "IPv6 protocol filtering status\n"
829
       VRF_FULL_CMD_HELP_STR)
830
0
{
831
0
  int ret = show_proto_rm(vty, AFI_IP6, vrf_all, vrf_name);
832
833
0
  return ret;
834
0
}
835
836
DEFPY_YANG (ip_protocol_nht_rmap,
837
       ip_protocol_nht_rmap_cmd,
838
       "ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA
839
       " $proto route-map ROUTE-MAP$rmap",
840
       IP_STR
841
       "Filter Next Hop tracking route resolution\n"
842
       FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
843
       "Specify route map\n"
844
       "Route map name\n")
845
0
{
846
847
0
  int ret, rtype;
848
849
0
  assert(proto);
850
0
  assert(rmap);
851
852
0
  ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
853
854
0
  if (!zvrf)
855
0
    return CMD_WARNING;
856
857
0
  if (strcasecmp(proto, "any") == 0)
858
0
    rtype = ZEBRA_ROUTE_MAX;
859
0
  else
860
0
    rtype = proto_name2num(proto);
861
0
  if (rtype < 0) {
862
0
    vty_out(vty, "invalid protocol name \"%s\"\n", proto);
863
0
    return CMD_WARNING_CONFIG_FAILED;
864
0
  }
865
866
0
  ret = ip_nht_rm_add(zvrf, rmap, rtype, AFI_IP);
867
868
0
  return ret;
869
0
}
870
871
DEFPY_YANG (no_ip_protocol_nht_rmap,
872
       no_ip_protocol_nht_rmap_cmd,
873
       "no ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA
874
       " $proto route-map [ROUTE-MAP$rmap]",
875
       NO_STR
876
       IP_STR
877
       "Filter Next Hop tracking route resolution\n"
878
       FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
879
       "Specify route map\n"
880
       "Route map name\n")
881
0
{
882
0
  int ret, rtype;
883
884
0
  assert(proto);
885
886
0
  ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
887
888
0
  if (!zvrf)
889
0
    return CMD_WARNING;
890
891
0
  if (strcasecmp(proto, "any") == 0)
892
0
    rtype = ZEBRA_ROUTE_MAX;
893
0
  else
894
0
    rtype = proto_name2num(proto);
895
0
  if (rtype < 0) {
896
0
    vty_out(vty, "invalid protocol name \"%s\"\n", proto);
897
0
    return CMD_WARNING_CONFIG_FAILED;
898
0
  }
899
900
0
  ret = ip_nht_rm_del(zvrf, rmap, rtype, AFI_IP);
901
902
0
  return ret;
903
0
}
904
905
DEFPY_YANG (show_ip_protocol_nht,
906
       show_ip_protocol_nht_cmd,
907
       "show ip nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]",
908
       SHOW_STR
909
       IP_STR
910
       "IPv4 nexthop tracking table\n"
911
       "IPv4 Next Hop tracking filtering status\n"
912
       VRF_CMD_HELP_STR
913
       "All VRFs\n"
914
       JSON_STR)
915
0
{
916
0
  int ret;
917
0
  bool uj = use_json(argc, argv);
918
919
0
  ret = show_nht_rm(vty, AFI_IP, vrf_all, vrf_name, uj);
920
921
0
  return ret;
922
0
}
923
924
DEFPY_YANG (ipv6_protocol_nht_rmap,
925
       ipv6_protocol_nht_rmap_cmd,
926
       "ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA
927
       " $proto route-map ROUTE-MAP$rmap",
928
       IP6_STR
929
       "Filter Next Hop tracking route resolution\n"
930
       FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
931
       "Specify route map\n"
932
       "Route map name\n")
933
0
{
934
0
  int ret, rtype;
935
936
0
  assert(rmap);
937
0
  assert(proto);
938
939
0
  ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
940
941
0
  if (!zvrf)
942
0
    return CMD_WARNING;
943
944
0
  if (strcasecmp(proto, "any") == 0)
945
0
    rtype = ZEBRA_ROUTE_MAX;
946
0
  else
947
0
    rtype = proto_name2num(proto);
948
0
  if (rtype < 0) {
949
0
    vty_out(vty, "invalid protocol name \"%s\"\n", proto);
950
0
    return CMD_WARNING_CONFIG_FAILED;
951
0
  }
952
953
0
  ret = ip_nht_rm_add(zvrf, rmap, rtype, AFI_IP6);
954
955
0
  return ret;
956
0
}
957
958
DEFPY_YANG (no_ipv6_protocol_nht_rmap,
959
       no_ipv6_protocol_nht_rmap_cmd,
960
       "no ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA
961
       " $proto [route-map ROUTE-MAP$rmap]",
962
       NO_STR
963
       IP6_STR
964
       "Filter Next Hop tracking route resolution\n"
965
       FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
966
       "Specify route map\n"
967
       "Route map name\n")
968
0
{
969
0
  int ret, rtype;
970
971
0
  assert(proto);
972
973
0
  ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
974
975
0
  if (!zvrf)
976
0
    return CMD_WARNING;
977
978
0
  if (strcasecmp(proto, "any") == 0)
979
0
    rtype = ZEBRA_ROUTE_MAX;
980
0
  else
981
0
    rtype = proto_name2num(proto);
982
0
  if (rtype < 0) {
983
0
    vty_out(vty, "invalid protocol name \"%s\"\n", proto);
984
0
    return CMD_WARNING_CONFIG_FAILED;
985
0
  }
986
987
0
  ret = ip_nht_rm_del(zvrf, rmap, rtype, AFI_IP6);
988
989
0
  return ret;
990
0
}
991
992
DEFPY_YANG (show_ipv6_protocol_nht,
993
       show_ipv6_protocol_nht_cmd,
994
       "show ipv6 nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]",
995
       SHOW_STR
996
       IP6_STR
997
       "IPv6 nexthop tracking table\n"
998
       "IPv6 Next Hop tracking filtering status\n"
999
       VRF_CMD_HELP_STR
1000
       "All VRFs\n"
1001
       JSON_STR)
1002
0
{
1003
0
  int ret;
1004
0
  bool uj = use_json(argc, argv);
1005
1006
0
  ret = show_nht_rm(vty, AFI_IP6, vrf_all, vrf_name, uj);
1007
1008
0
  return ret;
1009
0
}
1010
1011
/*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
1012
1013
/* `match ip next-hop IP_ACCESS_LIST' */
1014
1015
/* Match function return 1 if match is success else return zero. */
1016
static enum route_map_cmd_result_t
1017
route_match_ip_next_hop(void *rule, const struct prefix *prefix, void *object)
1018
0
{
1019
0
  struct access_list *alist;
1020
0
  struct nh_rmap_obj *nh_data;
1021
0
  struct prefix_ipv4 p;
1022
1023
0
  nh_data = object;
1024
0
  if (!nh_data)
1025
0
    return RMAP_NOMATCH;
1026
1027
0
  switch (nh_data->nexthop->type) {
1028
0
  case NEXTHOP_TYPE_IFINDEX:
1029
    /* Interface routes can't match ip next-hop */
1030
0
    return RMAP_NOMATCH;
1031
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1032
0
  case NEXTHOP_TYPE_IPV4:
1033
0
    p.family = AF_INET;
1034
0
    p.prefix = nh_data->nexthop->gate.ipv4;
1035
0
    p.prefixlen = IPV4_MAX_BITLEN;
1036
0
    break;
1037
0
  case NEXTHOP_TYPE_IPV6:
1038
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1039
0
  case NEXTHOP_TYPE_BLACKHOLE:
1040
0
    return RMAP_NOMATCH;
1041
0
  }
1042
0
  alist = access_list_lookup(AFI_IP, (char *)rule);
1043
0
  if (alist == NULL) {
1044
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL)))
1045
0
      zlog_debug(
1046
0
        "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
1047
0
        __func__, (char *)rule);
1048
0
    return RMAP_NOMATCH;
1049
0
  }
1050
1051
0
  return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH
1052
0
                  : RMAP_MATCH);
1053
0
}
1054
1055
/* Route map `ip next-hop' match statement.  `arg' should be
1056
   access-list name. */
1057
static void *route_match_ip_next_hop_compile(const char *arg)
1058
0
{
1059
0
  return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1060
0
}
1061
1062
/* Free route map's compiled `. */
1063
static void route_match_ip_next_hop_free(void *rule)
1064
0
{
1065
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1066
0
}
1067
1068
/* Route map commands for ip next-hop matching. */
1069
static const struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
1070
  "ip next-hop",
1071
  route_match_ip_next_hop,
1072
  route_match_ip_next_hop_compile,
1073
  route_match_ip_next_hop_free
1074
};
1075
1076
/* `match ip next-hop prefix-list PREFIX_LIST' */
1077
1078
static enum route_map_cmd_result_t
1079
route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
1080
            void *object)
1081
0
{
1082
0
  struct prefix_list *plist;
1083
0
  struct nh_rmap_obj *nh_data;
1084
0
  struct prefix_ipv4 p;
1085
1086
0
  nh_data = (struct nh_rmap_obj *)object;
1087
0
  if (!nh_data)
1088
0
    return RMAP_NOMATCH;
1089
1090
0
  switch (nh_data->nexthop->type) {
1091
0
  case NEXTHOP_TYPE_IFINDEX:
1092
    /* Interface routes can't match ip next-hop */
1093
0
    return RMAP_NOMATCH;
1094
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1095
0
  case NEXTHOP_TYPE_IPV4:
1096
0
    p.family = AF_INET;
1097
0
    p.prefix = nh_data->nexthop->gate.ipv4;
1098
0
    p.prefixlen = IPV4_MAX_BITLEN;
1099
0
    break;
1100
0
  case NEXTHOP_TYPE_IPV6:
1101
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1102
0
  case NEXTHOP_TYPE_BLACKHOLE:
1103
0
    return RMAP_NOMATCH;
1104
0
  }
1105
0
  plist = prefix_list_lookup(AFI_IP, (char *)rule);
1106
0
  if (plist == NULL) {
1107
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL)))
1108
0
      zlog_debug(
1109
0
        "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
1110
0
        __func__, (char *)rule);
1111
0
    return RMAP_NOMATCH;
1112
0
  }
1113
1114
0
  return (prefix_list_apply(plist, &p) == PREFIX_DENY ? RMAP_NOMATCH
1115
0
                  : RMAP_MATCH);
1116
0
}
1117
1118
static void *route_match_ip_next_hop_prefix_list_compile(const char *arg)
1119
0
{
1120
0
  return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1121
0
}
1122
1123
static void route_match_ip_next_hop_prefix_list_free(void *rule)
1124
0
{
1125
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1126
0
}
1127
1128
static const struct route_map_rule_cmd
1129
    route_match_ip_next_hop_prefix_list_cmd = {
1130
  "ip next-hop prefix-list",
1131
  route_match_ip_next_hop_prefix_list,
1132
  route_match_ip_next_hop_prefix_list_compile,
1133
  route_match_ip_next_hop_prefix_list_free
1134
};
1135
1136
/* `match ip address IP_ACCESS_LIST' */
1137
1138
/* Match function should return 1 if match is success else return
1139
   zero. */
1140
static enum route_map_cmd_result_t
1141
route_match_address(afi_t afi, void *rule, const struct prefix *prefix,
1142
        void *object)
1143
0
{
1144
0
  struct access_list *alist;
1145
1146
0
  alist = access_list_lookup(afi, (char *)rule);
1147
0
  if (alist == NULL) {
1148
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL)))
1149
0
      zlog_debug(
1150
0
        "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
1151
0
        __func__, (char *)rule);
1152
0
    return RMAP_NOMATCH;
1153
0
  }
1154
1155
0
  return (access_list_apply(alist, prefix) == FILTER_DENY ? RMAP_NOMATCH
1156
0
                : RMAP_MATCH);
1157
0
}
1158
1159
static enum route_map_cmd_result_t
1160
route_match_ip_address(void *rule, const struct prefix *prefix, void *object)
1161
0
{
1162
0
  return route_match_address(AFI_IP, rule, prefix, object);
1163
0
}
1164
1165
static enum route_map_cmd_result_t
1166
route_match_ipv6_address(void *rule, const struct prefix *prefix, void *object)
1167
0
{
1168
0
  return route_match_address(AFI_IP6, rule, prefix, object);
1169
0
}
1170
1171
/* Route map `ip address' match statement.  `arg' should be
1172
   access-list name. */
1173
static void *route_match_address_compile(const char *arg)
1174
0
{
1175
0
  return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1176
0
}
1177
1178
/* Free route map's compiled `ip address' value. */
1179
static void route_match_address_free(void *rule)
1180
0
{
1181
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1182
0
}
1183
1184
/* Route map commands for ip address matching. */
1185
static const struct route_map_rule_cmd route_match_ip_address_cmd = {
1186
  "ip address",
1187
  route_match_ip_address,
1188
  route_match_address_compile,
1189
  route_match_address_free
1190
};
1191
1192
/* Route map commands for ipv6 address matching. */
1193
static const struct route_map_rule_cmd route_match_ipv6_address_cmd = {
1194
  "ipv6 address",
1195
  route_match_ipv6_address,
1196
  route_match_address_compile,
1197
  route_match_address_free
1198
};
1199
1200
/* `match ip address prefix-list PREFIX_LIST' */
1201
1202
static enum route_map_cmd_result_t
1203
route_match_address_prefix_list(void *rule, const struct prefix *prefix,
1204
        void *object, afi_t afi)
1205
0
{
1206
0
  struct prefix_list *plist;
1207
1208
0
  plist = prefix_list_lookup(afi, (char *)rule);
1209
0
  if (plist == NULL) {
1210
0
    if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL)))
1211
0
      zlog_debug(
1212
0
        "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
1213
0
        __func__, (char *)rule);
1214
0
    return RMAP_NOMATCH;
1215
0
  }
1216
1217
0
  return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
1218
0
                : RMAP_MATCH);
1219
0
}
1220
1221
static enum route_map_cmd_result_t
1222
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
1223
           void *object)
1224
0
{
1225
0
  return (route_match_address_prefix_list(rule, prefix, object, AFI_IP));
1226
0
}
1227
1228
static void *route_match_address_prefix_list_compile(const char *arg)
1229
0
{
1230
0
  return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1231
0
}
1232
1233
static void route_match_address_prefix_list_free(void *rule)
1234
0
{
1235
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1236
0
}
1237
1238
static const struct route_map_rule_cmd
1239
    route_match_ip_address_prefix_list_cmd = {
1240
  "ip address prefix-list",
1241
  route_match_ip_address_prefix_list,
1242
  route_match_address_prefix_list_compile,
1243
  route_match_address_prefix_list_free
1244
};
1245
1246
static enum route_map_cmd_result_t
1247
route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
1248
             void *object)
1249
0
{
1250
0
  return (route_match_address_prefix_list(rule, prefix, object, AFI_IP6));
1251
0
}
1252
1253
static const struct route_map_rule_cmd
1254
    route_match_ipv6_address_prefix_list_cmd = {
1255
  "ipv6 address prefix-list",
1256
  route_match_ipv6_address_prefix_list,
1257
  route_match_address_prefix_list_compile,
1258
  route_match_address_prefix_list_free
1259
};
1260
1261
/* `match ipv6 next-hop type <TYPE>' */
1262
1263
static enum route_map_cmd_result_t
1264
route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
1265
             void *object)
1266
0
{
1267
0
  struct nh_rmap_obj *nh_data;
1268
1269
0
  if (prefix->family == AF_INET6) {
1270
0
    nh_data = (struct nh_rmap_obj *)object;
1271
0
    if (!nh_data)
1272
0
      return RMAP_NOMATCH;
1273
1274
0
    if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
1275
0
      return RMAP_MATCH;
1276
0
  }
1277
1278
0
  return RMAP_NOMATCH;
1279
0
}
1280
1281
static void *route_match_ipv6_next_hop_type_compile(const char *arg)
1282
0
{
1283
0
  return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1284
0
}
1285
1286
static void route_match_ipv6_next_hop_type_free(void *rule)
1287
0
{
1288
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1289
0
}
1290
1291
static const struct route_map_rule_cmd
1292
    route_match_ipv6_next_hop_type_cmd = {
1293
  "ipv6 next-hop type",
1294
  route_match_ipv6_next_hop_type,
1295
  route_match_ipv6_next_hop_type_compile,
1296
  route_match_ipv6_next_hop_type_free
1297
};
1298
1299
/* `match ip address prefix-len PREFIXLEN' */
1300
1301
static enum route_map_cmd_result_t
1302
route_match_address_prefix_len(void *rule, const struct prefix *prefix,
1303
             void *object)
1304
0
{
1305
0
  uint32_t *prefixlen = (uint32_t *)rule;
1306
1307
0
  return ((prefix->prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH);
1308
0
}
1309
1310
static void *route_match_address_prefix_len_compile(const char *arg)
1311
0
{
1312
0
  uint32_t *prefix_len;
1313
0
  char *endptr = NULL;
1314
0
  unsigned long tmpval;
1315
1316
  /* prefix len value shoud be integer. */
1317
0
  if (!all_digit(arg))
1318
0
    return NULL;
1319
1320
0
  errno = 0;
1321
0
  tmpval = strtoul(arg, &endptr, 10);
1322
0
  if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
1323
0
    return NULL;
1324
1325
0
  prefix_len = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
1326
1327
0
  *prefix_len = tmpval;
1328
0
  return prefix_len;
1329
0
}
1330
1331
static void route_match_address_prefix_len_free(void *rule)
1332
0
{
1333
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1334
0
}
1335
1336
static const struct route_map_rule_cmd
1337
    route_match_ip_address_prefix_len_cmd = {
1338
  "ip address prefix-len",
1339
  route_match_address_prefix_len,
1340
  route_match_address_prefix_len_compile,
1341
  route_match_address_prefix_len_free
1342
};
1343
1344
static const struct route_map_rule_cmd
1345
    route_match_ipv6_address_prefix_len_cmd = {
1346
  "ipv6 address prefix-len",
1347
  route_match_address_prefix_len,
1348
  route_match_address_prefix_len_compile,
1349
  route_match_address_prefix_len_free
1350
};
1351
1352
/* `match ip nexthop prefix-len PREFIXLEN' */
1353
1354
static enum route_map_cmd_result_t
1355
route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix,
1356
          void *object)
1357
0
{
1358
0
  uint32_t *prefixlen = (uint32_t *)rule;
1359
0
  struct nh_rmap_obj *nh_data;
1360
0
  struct prefix_ipv4 p;
1361
1362
0
  nh_data = (struct nh_rmap_obj *)object;
1363
0
  if (!nh_data || !nh_data->nexthop)
1364
0
    return RMAP_NOMATCH;
1365
1366
0
  switch (nh_data->nexthop->type) {
1367
0
  case NEXTHOP_TYPE_IFINDEX:
1368
    /* Interface routes can't match ip next-hop */
1369
0
    return RMAP_NOMATCH;
1370
0
  case NEXTHOP_TYPE_IPV4_IFINDEX:
1371
0
  case NEXTHOP_TYPE_IPV4:
1372
0
    p.family = AF_INET;
1373
0
    p.prefix = nh_data->nexthop->gate.ipv4;
1374
0
    p.prefixlen = IPV4_MAX_BITLEN;
1375
0
    break;
1376
0
  case NEXTHOP_TYPE_IPV6:
1377
0
  case NEXTHOP_TYPE_IPV6_IFINDEX:
1378
0
  case NEXTHOP_TYPE_BLACKHOLE:
1379
0
    return RMAP_NOMATCH;
1380
0
  }
1381
0
  return ((p.prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH);
1382
0
}
1383
1384
static const struct route_map_rule_cmd
1385
    route_match_ip_nexthop_prefix_len_cmd = {
1386
  "ip next-hop prefix-len",
1387
  route_match_ip_nexthop_prefix_len,
1388
  route_match_address_prefix_len_compile, /* reuse */
1389
  route_match_address_prefix_len_free     /* reuse */
1390
};
1391
1392
/* `match ip next-hop type <blackhole>' */
1393
1394
static enum route_map_cmd_result_t
1395
route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
1396
           void *object)
1397
0
{
1398
0
  struct nh_rmap_obj *nh_data;
1399
1400
0
  if (prefix->family == AF_INET) {
1401
0
    nh_data = (struct nh_rmap_obj *)object;
1402
0
    if (!nh_data)
1403
0
      return RMAP_NOMATCH;
1404
1405
0
    if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
1406
0
      return RMAP_MATCH;
1407
0
  }
1408
1409
0
  return RMAP_NOMATCH;
1410
0
}
1411
1412
static void *route_match_ip_next_hop_type_compile(const char *arg)
1413
0
{
1414
0
  return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1415
0
}
1416
1417
static void route_match_ip_next_hop_type_free(void *rule)
1418
0
{
1419
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1420
0
}
1421
1422
static const struct route_map_rule_cmd
1423
    route_match_ip_next_hop_type_cmd = {
1424
  "ip next-hop type",
1425
  route_match_ip_next_hop_type,
1426
  route_match_ip_next_hop_type_compile,
1427
  route_match_ip_next_hop_type_free
1428
};
1429
1430
/* `match source-protocol PROTOCOL' */
1431
1432
static enum route_map_cmd_result_t
1433
route_match_source_protocol(void *rule, const struct prefix *p, void *object)
1434
0
{
1435
0
  uint32_t *rib_type = (uint32_t *)rule;
1436
0
  struct nh_rmap_obj *nh_data;
1437
1438
0
  nh_data = (struct nh_rmap_obj *)object;
1439
0
  if (!nh_data)
1440
0
    return RMAP_NOMATCH;
1441
1442
0
  return ((nh_data->source_protocol == *rib_type) ? RMAP_MATCH
1443
0
              : RMAP_NOMATCH);
1444
0
}
1445
1446
static void *route_match_source_protocol_compile(const char *arg)
1447
0
{
1448
0
  uint32_t *rib_type;
1449
0
  int i;
1450
1451
0
  i = proto_name2num(arg);
1452
0
  rib_type = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
1453
1454
0
  *rib_type = i;
1455
1456
0
  return rib_type;
1457
0
}
1458
1459
static void route_match_source_protocol_free(void *rule)
1460
0
{
1461
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1462
0
}
1463
1464
static const struct route_map_rule_cmd route_match_source_protocol_cmd = {
1465
  "source-protocol",
1466
  route_match_source_protocol,
1467
  route_match_source_protocol_compile,
1468
  route_match_source_protocol_free
1469
};
1470
1471
/* `source-instance` */
1472
static enum route_map_cmd_result_t
1473
route_match_source_instance(void *rule, const struct prefix *p, void *object)
1474
0
{
1475
0
  uint8_t *instance = (uint8_t *)rule;
1476
0
  struct nh_rmap_obj *nh_data;
1477
1478
0
  nh_data = (struct nh_rmap_obj *)object;
1479
0
  if (!nh_data)
1480
0
    return RMAP_NOMATCH;
1481
1482
0
  return (nh_data->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH;
1483
0
}
1484
1485
static void *route_match_source_instance_compile(const char *arg)
1486
0
{
1487
0
  uint8_t *instance;
1488
0
  int i;
1489
1490
0
  i = atoi(arg);
1491
0
  instance = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t));
1492
1493
0
  *instance = i;
1494
1495
0
  return instance;
1496
0
}
1497
1498
static void route_match_source_instance_free(void *rule)
1499
0
{
1500
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1501
0
}
1502
1503
static const struct route_map_rule_cmd route_match_source_instance_cmd = {
1504
  "source-instance",
1505
  route_match_source_instance,
1506
  route_match_source_instance_compile,
1507
  route_match_source_instance_free
1508
};
1509
1510
/* `set src A.B.C.D' */
1511
1512
/* Set src. */
1513
static enum route_map_cmd_result_t
1514
route_set_src(void *rule, const struct prefix *prefix, void *object)
1515
0
{
1516
0
  struct nh_rmap_obj *nh_data;
1517
1518
0
  nh_data = (struct nh_rmap_obj *)object;
1519
0
  nh_data->nexthop->rmap_src = *(union g_addr *)rule;
1520
1521
0
  return RMAP_OKAY;
1522
0
}
1523
1524
/* set src compilation. */
1525
static void *route_set_src_compile(const char *arg)
1526
0
{
1527
0
  union g_addr src, *psrc;
1528
1529
0
  if ((inet_pton(AF_INET6, arg, &src.ipv6) == 1)
1530
0
      || (inet_pton(AF_INET, arg, &src.ipv4) == 1)) {
1531
0
    psrc = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(union g_addr));
1532
0
    *psrc = src;
1533
0
    return psrc;
1534
0
  }
1535
0
  return NULL;
1536
0
}
1537
1538
/* Free route map's compiled `set src' value. */
1539
static void route_set_src_free(void *rule)
1540
0
{
1541
0
  XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1542
0
}
1543
1544
/* Set src rule structure. */
1545
static const struct route_map_rule_cmd route_set_src_cmd = {
1546
  "src",
1547
  route_set_src,
1548
  route_set_src_compile,
1549
  route_set_src_free,
1550
};
1551
1552
/* The function checks if the changed routemap specified by parameter rmap
1553
 * matches the configured protocol routemaps in proto_rm table. If there is
1554
 * a match then rib_update_table() to process the routes.
1555
 */
1556
static void zebra_rib_table_rm_update(const char *rmap)
1557
0
{
1558
0
  int i = 0;
1559
0
  struct route_table *table;
1560
0
  struct vrf *vrf = NULL;
1561
0
  struct zebra_vrf *zvrf = NULL;
1562
0
  char *rmap_name;
1563
0
  struct route_map *old = NULL;
1564
1565
0
  RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1566
0
    zvrf = vrf->info;
1567
0
    if (!zvrf)
1568
0
      continue;
1569
0
    for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) {
1570
0
      rmap_name = PROTO_RM_NAME(zvrf, AFI_IP, i);
1571
0
      if (rmap_name && (strcmp(rmap_name, rmap) == 0)) {
1572
0
        if (IS_ZEBRA_DEBUG_EVENT)
1573
0
          zlog_debug(
1574
0
            "%s : AFI_IP rmap %s, route type %s",
1575
0
            __func__, rmap,
1576
0
            zebra_route_string(i));
1577
1578
0
        old = PROTO_RM_MAP(zvrf, AFI_IP, i);
1579
1580
0
        PROTO_RM_MAP(zvrf, AFI_IP, i) =
1581
0
          route_map_lookup_by_name(rmap_name);
1582
        /* old is NULL. i.e Route map creation event.
1583
         * So update applied_counter.
1584
         * If Old is not NULL, i.e It may be routemap
1585
         * updation or deletion.
1586
         * So no need to update the counter.
1587
         */
1588
0
        if (!old)
1589
0
          route_map_counter_increment(
1590
0
            PROTO_RM_MAP(zvrf, AFI_IP, i));
1591
        /* There is single rib table for all protocols
1592
         */
1593
0
        table = zvrf->table[AFI_IP][SAFI_UNICAST];
1594
0
        if (table) {
1595
0
          rib_update_table(
1596
0
            table,
1597
0
            RIB_UPDATE_RMAP_CHANGE,
1598
0
            i);
1599
0
        }
1600
0
      }
1601
0
      rmap_name = PROTO_RM_NAME(zvrf, AFI_IP6, i);
1602
0
      if (rmap_name && (strcmp(rmap_name, rmap) == 0)) {
1603
0
        if (IS_ZEBRA_DEBUG_EVENT)
1604
0
          zlog_debug(
1605
0
            "%s : AFI_IP6 rmap %s, route type %s",
1606
0
            __func__, rmap,
1607
0
            zebra_route_string(i));
1608
1609
0
        old = PROTO_RM_MAP(zvrf, AFI_IP6, i);
1610
1611
0
        PROTO_RM_MAP(zvrf, AFI_IP6, i) =
1612
0
          route_map_lookup_by_name(rmap_name);
1613
0
        if (!old)
1614
0
          route_map_counter_increment(
1615
0
            PROTO_RM_MAP(zvrf, AFI_IP6, i));
1616
        /* There is single rib table for all protocols
1617
         */
1618
0
        table = zvrf->table[AFI_IP6][SAFI_UNICAST];
1619
0
        if (table) {
1620
0
          rib_update_table(
1621
0
            table,
1622
0
            RIB_UPDATE_RMAP_CHANGE,
1623
0
            i);
1624
0
        }
1625
0
      }
1626
0
    }
1627
0
  }
1628
0
}
1629
1630
/* The function checks if the changed routemap specified by parameter rmap
1631
 * matches the configured protocol routemaps in nht_rm table. If there is
1632
 * a match then zebra_evaluate_rnh() to process the nexthops.
1633
 */
1634
static void zebra_nht_rm_update(const char *rmap)
1635
0
{
1636
0
  int i = 0;
1637
0
  struct route_table *table;
1638
0
  struct vrf *vrf = NULL;
1639
0
  struct zebra_vrf *zvrf = NULL;
1640
0
  char *rmap_name;
1641
0
  char afi_ip = 0;
1642
0
  char afi_ipv6 = 0;
1643
0
  struct route_map *old = NULL;
1644
1645
0
  RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1646
0
    zvrf = vrf->info;
1647
0
    if (!zvrf)
1648
0
      continue;
1649
0
    for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) {
1650
0
      rmap_name = NHT_RM_NAME(zvrf, AFI_IP, i);
1651
0
      if (rmap_name && (strcmp(rmap_name, rmap) == 0)) {
1652
0
        if (IS_ZEBRA_DEBUG_EVENT)
1653
0
          zlog_debug(
1654
0
            "%s : AFI_IP rmap %s, route type %s",
1655
0
            __func__, rmap,
1656
0
            zebra_route_string(i));
1657
1658
0
        old = NHT_RM_MAP(zvrf, AFI_IP, i);
1659
1660
0
        NHT_RM_MAP(zvrf, AFI_IP, i) =
1661
0
          route_map_lookup_by_name(rmap_name);
1662
0
        if (!old)
1663
0
          route_map_counter_increment(
1664
0
            NHT_RM_MAP(zvrf, AFI_IP, i));
1665
        /* There is single rib table for all protocols
1666
         */
1667
0
        if (afi_ip == 0) {
1668
0
          table = zvrf->table[AFI_IP]
1669
0
                 [SAFI_UNICAST];
1670
0
          if (table) {
1671
1672
0
            afi_ip = 1;
1673
1674
0
            zebra_evaluate_rnh(
1675
0
              zvrf, AFI_IP, 1, NULL,
1676
0
              SAFI_UNICAST);
1677
0
          }
1678
0
        }
1679
0
      }
1680
1681
0
      rmap_name = NHT_RM_NAME(zvrf, AFI_IP6, i);
1682
0
      if (rmap_name && (strcmp(rmap_name, rmap) == 0)) {
1683
0
        if (IS_ZEBRA_DEBUG_EVENT)
1684
0
          zlog_debug(
1685
0
            "%s : AFI_IP6 rmap %s, route type %s",
1686
0
            __func__, rmap,
1687
0
            zebra_route_string(i));
1688
1689
0
        old = NHT_RM_MAP(zvrf, AFI_IP6, i);
1690
1691
0
        NHT_RM_MAP(zvrf, AFI_IP6, i) =
1692
0
          route_map_lookup_by_name(rmap_name);
1693
0
        if (!old)
1694
0
          route_map_counter_increment(
1695
0
            NHT_RM_MAP(zvrf, AFI_IP6, i));
1696
        /* There is single rib table for all protocols
1697
         */
1698
0
        if (afi_ipv6 == 0) {
1699
0
          table = zvrf->table[AFI_IP6]
1700
0
                 [SAFI_UNICAST];
1701
0
          if (table) {
1702
1703
0
            afi_ipv6 = 1;
1704
1705
0
            zebra_evaluate_rnh(
1706
0
              zvrf, AFI_IP6, 1, NULL,
1707
0
              SAFI_UNICAST);
1708
0
          }
1709
0
        }
1710
0
      }
1711
0
    }
1712
0
  }
1713
0
}
1714
1715
static void zebra_route_map_process_update_cb(char *rmap_name)
1716
0
{
1717
0
  if (IS_ZEBRA_DEBUG_EVENT)
1718
0
    zlog_debug("Event handler for route-map: %s",
1719
0
         rmap_name);
1720
0
  zebra_import_table_rm_update(rmap_name);
1721
0
  zebra_rib_table_rm_update(rmap_name);
1722
0
  zebra_nht_rm_update(rmap_name);
1723
0
}
1724
1725
static void zebra_route_map_update_timer(struct event *thread)
1726
0
{
1727
0
  if (IS_ZEBRA_DEBUG_EVENT)
1728
0
    zlog_debug("Event driven route-map update triggered");
1729
1730
0
  if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1731
0
    zlog_debug(
1732
0
      "%u: Routemap update-timer fired, scheduling RIB processing",
1733
0
      VRF_DEFAULT);
1734
1735
0
  route_map_walk_update_list(zebra_route_map_process_update_cb);
1736
1737
  /*
1738
   * This code needs to be updated to be:
1739
   * 1) VRF Aware <sigh>
1740
   * 2) Route-map aware
1741
   */
1742
0
}
1743
1744
static void zebra_route_map_set_delay_timer(uint32_t value)
1745
0
{
1746
0
  zebra_rmap_update_timer = value;
1747
0
  if (!value && zebra_t_rmap_update) {
1748
    /* Event driven route map updates is being disabled */
1749
    /* But there's a pending timer. Fire it off now */
1750
0
    EVENT_OFF(zebra_t_rmap_update);
1751
0
    zebra_route_map_update_timer(NULL);
1752
0
  }
1753
0
}
1754
1755
void zebra_routemap_finish(void)
1756
0
{
1757
  /* Set zebra_rmap_update_timer to 0 so that it wont schedule again */
1758
0
  zebra_rmap_update_timer = 0;
1759
  /* Thread off if any scheduled already */
1760
0
  EVENT_OFF(zebra_t_rmap_update);
1761
0
  route_map_finish();
1762
0
}
1763
1764
route_map_result_t
1765
zebra_route_map_check(afi_t family, int rib_type, uint8_t instance,
1766
          const struct prefix *p, struct nexthop *nexthop,
1767
          struct zebra_vrf *zvrf, route_tag_t tag)
1768
0
{
1769
0
  struct route_map *rmap = NULL;
1770
0
  char *rm_name;
1771
0
  route_map_result_t ret = RMAP_PERMITMATCH;
1772
0
  struct nh_rmap_obj nh_obj;
1773
1774
0
  nh_obj.nexthop = nexthop;
1775
0
  nh_obj.vrf_id = nexthop->vrf_id;
1776
0
  nh_obj.source_protocol = rib_type;
1777
0
  nh_obj.instance = instance;
1778
0
  nh_obj.metric = 0;
1779
0
  nh_obj.tag = tag;
1780
1781
0
  if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX) {
1782
0
    rm_name = PROTO_RM_NAME(zvrf, family, rib_type);
1783
0
    rmap = PROTO_RM_MAP(zvrf, family, rib_type);
1784
1785
0
    if (rm_name && !rmap)
1786
0
      return RMAP_DENYMATCH;
1787
0
  }
1788
0
  if (!rmap) {
1789
0
    rm_name = PROTO_RM_NAME(zvrf, family, ZEBRA_ROUTE_MAX);
1790
0
    rmap = PROTO_RM_MAP(zvrf, family, ZEBRA_ROUTE_MAX);
1791
1792
0
    if (rm_name && !rmap)
1793
0
      return RMAP_DENYMATCH;
1794
0
  }
1795
0
  if (rmap) {
1796
0
    ret = route_map_apply(rmap, p, &nh_obj);
1797
0
  }
1798
1799
0
  return (ret);
1800
0
}
1801
1802
char *zebra_get_import_table_route_map(afi_t afi, uint32_t table)
1803
0
{
1804
0
  return zebra_import_table_routemap[afi][table];
1805
0
}
1806
1807
void zebra_add_import_table_route_map(afi_t afi, const char *rmap_name,
1808
              uint32_t table)
1809
0
{
1810
0
  zebra_import_table_routemap[afi][table] =
1811
0
    XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1812
0
}
1813
1814
void zebra_del_import_table_route_map(afi_t afi, uint32_t table)
1815
0
{
1816
0
  XFREE(MTYPE_ROUTE_MAP_NAME, zebra_import_table_routemap[afi][table]);
1817
0
}
1818
1819
route_map_result_t
1820
zebra_import_table_route_map_check(int family, int re_type, uint8_t instance,
1821
           const struct prefix *p,
1822
           struct nexthop *nexthop,
1823
           vrf_id_t vrf_id, route_tag_t tag,
1824
           const char *rmap_name)
1825
0
{
1826
0
  struct route_map *rmap = NULL;
1827
0
  route_map_result_t ret = RMAP_DENYMATCH;
1828
0
  struct nh_rmap_obj nh_obj;
1829
1830
0
  nh_obj.nexthop = nexthop;
1831
0
  nh_obj.vrf_id = vrf_id;
1832
0
  nh_obj.source_protocol = re_type;
1833
0
  nh_obj.instance = instance;
1834
0
  nh_obj.metric = 0;
1835
0
  nh_obj.tag = tag;
1836
1837
0
  if (re_type >= 0 && re_type < ZEBRA_ROUTE_MAX)
1838
0
    rmap = route_map_lookup_by_name(rmap_name);
1839
0
  if (rmap) {
1840
0
    ret = route_map_apply(rmap, p, &nh_obj);
1841
0
  }
1842
1843
0
  return (ret);
1844
0
}
1845
1846
route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto,
1847
               const struct prefix *p,
1848
               struct zebra_vrf *zvrf,
1849
               struct route_entry *re,
1850
               struct nexthop *nexthop)
1851
0
{
1852
0
  struct route_map *rmap = NULL;
1853
0
  route_map_result_t ret = RMAP_PERMITMATCH;
1854
0
  struct nh_rmap_obj nh_obj;
1855
1856
0
  nh_obj.nexthop = nexthop;
1857
0
  nh_obj.vrf_id = nexthop->vrf_id;
1858
0
  nh_obj.source_protocol = re->type;
1859
0
  nh_obj.instance = re->instance;
1860
0
  nh_obj.metric = re->metric;
1861
0
  nh_obj.tag = re->tag;
1862
1863
0
  if (client_proto >= 0 && client_proto < ZEBRA_ROUTE_MAX)
1864
0
    rmap = NHT_RM_MAP(zvrf, afi, client_proto);
1865
0
  if (!rmap && NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX))
1866
0
    rmap = NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX);
1867
0
  if (rmap)
1868
0
    ret = route_map_apply(rmap, p, &nh_obj);
1869
1870
0
  return ret;
1871
0
}
1872
1873
static void zebra_route_map_mark_update(const char *rmap_name)
1874
0
{
1875
  /* rmap_update_timer of 0 means don't do route updates */
1876
0
  if (zebra_rmap_update_timer)
1877
0
    EVENT_OFF(zebra_t_rmap_update);
1878
1879
0
  event_add_timer(zrouter.master, zebra_route_map_update_timer, NULL,
1880
0
      zebra_rmap_update_timer, &zebra_t_rmap_update);
1881
0
}
1882
1883
static void zebra_route_map_add(const char *rmap_name)
1884
0
{
1885
0
  if (route_map_mark_updated(rmap_name) == 0)
1886
0
    zebra_route_map_mark_update(rmap_name);
1887
1888
0
  route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
1889
0
}
1890
1891
static void zebra_route_map_delete(const char *rmap_name)
1892
0
{
1893
0
  if (route_map_mark_updated(rmap_name) == 0)
1894
0
    zebra_route_map_mark_update(rmap_name);
1895
1896
0
  route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
1897
0
}
1898
1899
static void zebra_route_map_event(const char *rmap_name)
1900
0
{
1901
0
  if (route_map_mark_updated(rmap_name) == 0)
1902
0
    zebra_route_map_mark_update(rmap_name);
1903
1904
0
  route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
1905
0
}
1906
1907
void zebra_routemap_vrf_delete(struct zebra_vrf *zvrf)
1908
0
{
1909
0
  afi_t afi;
1910
0
  uint8_t type;
1911
1912
0
  for (afi = AFI_IP; afi < AFI_MAX; afi++) {
1913
0
    for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
1914
0
      if (PROTO_RM_NAME(zvrf, afi, type))
1915
0
        XFREE(MTYPE_ROUTE_MAP_NAME,
1916
0
              PROTO_RM_NAME(zvrf, afi, type));
1917
0
      if (NHT_RM_NAME(zvrf, afi, type))
1918
0
        XFREE(MTYPE_ROUTE_MAP_NAME,
1919
0
              NHT_RM_NAME(zvrf, afi, type));
1920
0
    }
1921
0
  }
1922
0
}
1923
1924
/* ip protocol configuration write function */
1925
void zebra_routemap_config_write_protocol(struct vty *vty,
1926
            struct zebra_vrf *zvrf)
1927
0
{
1928
0
  int i;
1929
0
  char space[2];
1930
1931
0
  memset(space, 0, sizeof(space));
1932
1933
0
  if (zvrf_id(zvrf) != VRF_DEFAULT)
1934
0
    snprintf(space, sizeof(space), "%s", " ");
1935
1936
0
  for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
1937
0
    if (PROTO_RM_NAME(zvrf, AFI_IP, i))
1938
0
      vty_out(vty, "%sip protocol %s route-map %s\n", space,
1939
0
        zebra_route_string(i),
1940
0
        PROTO_RM_NAME(zvrf, AFI_IP, i));
1941
1942
0
    if (PROTO_RM_NAME(zvrf, AFI_IP6, i))
1943
0
      vty_out(vty, "%sipv6 protocol %s route-map %s\n", space,
1944
0
        zebra_route_string(i),
1945
0
        PROTO_RM_NAME(zvrf, AFI_IP6, i));
1946
1947
0
    if (NHT_RM_NAME(zvrf, AFI_IP, i))
1948
0
      vty_out(vty, "%sip nht %s route-map %s\n", space,
1949
0
        zebra_route_string(i),
1950
0
        NHT_RM_NAME(zvrf, AFI_IP, i));
1951
1952
0
    if (NHT_RM_NAME(zvrf, AFI_IP6, i))
1953
0
      vty_out(vty, "%sipv6 nht %s route-map %s\n", space,
1954
0
        zebra_route_string(i),
1955
0
        NHT_RM_NAME(zvrf, AFI_IP6, i));
1956
0
  }
1957
1958
0
  if (PROTO_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX))
1959
0
    vty_out(vty, "%sip protocol %s route-map %s\n", space, "any",
1960
0
      PROTO_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX));
1961
1962
0
  if (PROTO_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX))
1963
0
    vty_out(vty, "%sipv6 protocol %s route-map %s\n", space, "any",
1964
0
      PROTO_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX));
1965
1966
0
  if (NHT_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX))
1967
0
    vty_out(vty, "%sip nht %s route-map %s\n", space, "any",
1968
0
      NHT_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX));
1969
1970
0
  if (NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX))
1971
0
    vty_out(vty, "%sipv6 nht %s route-map %s\n", space, "any",
1972
0
      NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX));
1973
1974
0
  if (zvrf_id(zvrf) == VRF_DEFAULT
1975
0
      && zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)
1976
0
    vty_out(vty, "zebra route-map delay-timer %d\n",
1977
0
      zebra_rmap_update_timer);
1978
0
}
1979
1980
void zebra_route_map_init(void)
1981
0
{
1982
0
  install_element(CONFIG_NODE, &ip_protocol_cmd);
1983
0
  install_element(CONFIG_NODE, &no_ip_protocol_cmd);
1984
0
  install_element(VRF_NODE, &ip_protocol_cmd);
1985
0
  install_element(VRF_NODE, &no_ip_protocol_cmd);
1986
0
  install_element(VIEW_NODE, &show_ip_protocol_cmd);
1987
0
  install_element(CONFIG_NODE, &ipv6_protocol_cmd);
1988
0
  install_element(CONFIG_NODE, &no_ipv6_protocol_cmd);
1989
0
  install_element(VRF_NODE, &ipv6_protocol_cmd);
1990
0
  install_element(VRF_NODE, &no_ipv6_protocol_cmd);
1991
0
  install_element(VIEW_NODE, &show_ipv6_protocol_cmd);
1992
0
  install_element(CONFIG_NODE, &ip_protocol_nht_rmap_cmd);
1993
0
  install_element(CONFIG_NODE, &no_ip_protocol_nht_rmap_cmd);
1994
0
  install_element(VRF_NODE, &ip_protocol_nht_rmap_cmd);
1995
0
  install_element(VRF_NODE, &no_ip_protocol_nht_rmap_cmd);
1996
0
  install_element(VIEW_NODE, &show_ip_protocol_nht_cmd);
1997
0
  install_element(CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd);
1998
0
  install_element(CONFIG_NODE, &no_ipv6_protocol_nht_rmap_cmd);
1999
0
  install_element(VRF_NODE, &ipv6_protocol_nht_rmap_cmd);
2000
0
  install_element(VRF_NODE, &no_ipv6_protocol_nht_rmap_cmd);
2001
0
  install_element(VIEW_NODE, &show_ipv6_protocol_nht_cmd);
2002
0
  install_element(CONFIG_NODE, &zebra_route_map_timer_cmd);
2003
0
  install_element(CONFIG_NODE, &no_zebra_route_map_timer_cmd);
2004
2005
0
  route_map_init();
2006
2007
0
  route_map_add_hook(zebra_route_map_add);
2008
0
  route_map_delete_hook(zebra_route_map_delete);
2009
0
  route_map_event_hook(zebra_route_map_event);
2010
2011
0
  route_map_match_interface_hook(generic_match_add);
2012
0
  route_map_no_match_interface_hook(generic_match_delete);
2013
2014
0
  route_map_match_ip_address_hook(generic_match_add);
2015
0
  route_map_no_match_ip_address_hook(generic_match_delete);
2016
2017
0
  route_map_match_ip_address_prefix_list_hook(generic_match_add);
2018
0
  route_map_no_match_ip_address_prefix_list_hook(generic_match_delete);
2019
2020
0
  route_map_match_ip_next_hop_hook(generic_match_add);
2021
0
  route_map_no_match_ip_next_hop_hook(generic_match_delete);
2022
2023
0
  route_map_match_ip_next_hop_prefix_list_hook(generic_match_add);
2024
0
  route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete);
2025
2026
0
  route_map_match_ip_next_hop_type_hook(generic_match_add);
2027
0
  route_map_no_match_ip_next_hop_type_hook(generic_match_delete);
2028
2029
0
  route_map_match_tag_hook(generic_match_add);
2030
0
  route_map_no_match_tag_hook(generic_match_delete);
2031
2032
0
  route_map_match_ipv6_address_hook(generic_match_add);
2033
0
  route_map_no_match_ipv6_address_hook(generic_match_delete);
2034
2035
0
  route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
2036
0
  route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
2037
2038
0
  route_map_match_ipv6_next_hop_type_hook(generic_match_add);
2039
0
  route_map_no_match_ipv6_next_hop_type_hook(generic_match_delete);
2040
2041
0
  route_map_install_match(&route_match_tag_cmd);
2042
0
  route_map_install_match(&route_match_interface_cmd);
2043
0
  route_map_install_match(&route_match_ip_next_hop_cmd);
2044
0
  route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
2045
0
  route_map_install_match(&route_match_ip_address_cmd);
2046
0
  route_map_install_match(&route_match_ipv6_address_cmd);
2047
0
  route_map_install_match(&route_match_ip_address_prefix_list_cmd);
2048
0
  route_map_install_match(&route_match_ipv6_address_prefix_list_cmd);
2049
0
  route_map_install_match(&route_match_ip_address_prefix_len_cmd);
2050
0
  route_map_install_match(&route_match_ipv6_address_prefix_len_cmd);
2051
0
  route_map_install_match(&route_match_ip_nexthop_prefix_len_cmd);
2052
0
  route_map_install_match(&route_match_ip_next_hop_type_cmd);
2053
0
  route_map_install_match(&route_match_ipv6_next_hop_type_cmd);
2054
0
  route_map_install_match(&route_match_source_protocol_cmd);
2055
0
  route_map_install_match(&route_match_source_instance_cmd);
2056
2057
  /* */
2058
0
  route_map_install_set(&route_set_src_cmd);
2059
  /* */
2060
0
  install_element(RMAP_NODE, &match_ip_nexthop_prefix_len_cmd);
2061
0
  install_element(RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd);
2062
0
  install_element(RMAP_NODE, &match_ip_address_prefix_len_cmd);
2063
0
  install_element(RMAP_NODE, &match_ipv6_address_prefix_len_cmd);
2064
0
  install_element(RMAP_NODE, &no_match_ipv6_address_prefix_len_cmd);
2065
0
  install_element(RMAP_NODE, &no_match_ip_address_prefix_len_cmd);
2066
0
  install_element(RMAP_NODE, &match_source_protocol_cmd);
2067
0
  install_element(RMAP_NODE, &no_match_source_protocol_cmd);
2068
0
  install_element(RMAP_NODE, &match_source_instance_cmd);
2069
0
  install_element(RMAP_NODE, &no_match_source_instance_cmd);
2070
2071
  /* */
2072
0
  install_element(RMAP_NODE, &set_src_cmd);
2073
0
  install_element(RMAP_NODE, &no_set_src_cmd);
2074
0
}