]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap.c
Merge pull request #941 from dwalton76/bgpd-peer-group-rebind
[mirror_frr.git] / lib / routemap.c
CommitLineData
718e3744 1/* Route map function.
896014f4
DL
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
718e3744 20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "memory.h"
25#include "vector.h"
26#include "prefix.h"
82f97584 27#include "vty.h"
718e3744 28#include "routemap.h"
29#include "command.h"
fee0f4c6 30#include "log.h"
518f0eb1 31#include "hash.h"
b85120bc 32#include "libfrr.h"
6b0655a2 33
d62a17ae 34DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map")
35DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name")
36DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index")
37DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule")
4a1ab8e4 38DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str")
d62a17ae 39DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled")
40DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency")
4a1ab8e4 41
e80e7cce
DL
42DEFINE_QOBJ_TYPE(route_map_index)
43DEFINE_QOBJ_TYPE(route_map)
44
718e3744 45/* Vector for route match rules. */
46static vector route_match_vec;
47
48/* Vector for route set rules. */
49static vector route_set_vec;
50
d62a17ae 51struct route_map_match_set_hooks {
52 /* match interface */
53 int (*match_interface)(struct vty *vty, struct route_map_index *index,
54 const char *command, const char *arg,
55 route_map_event_t type);
56
57 /* no match interface */
58 int (*no_match_interface)(struct vty *vty,
59 struct route_map_index *index,
60 const char *command, const char *arg,
61 route_map_event_t type);
62
63 /* match ip address */
64 int (*match_ip_address)(struct vty *vty, struct route_map_index *index,
65 const char *command, const char *arg,
66 route_map_event_t type);
67
68 /* no match ip address */
69 int (*no_match_ip_address)(struct vty *vty,
70 struct route_map_index *index,
71 const char *command, const char *arg,
72 route_map_event_t type);
73
74 /* match ip address prefix list */
75 int (*match_ip_address_prefix_list)(struct vty *vty,
76 struct route_map_index *index,
77 const char *command,
78 const char *arg,
79 route_map_event_t type);
80
81 /* no match ip address prefix list */
82 int (*no_match_ip_address_prefix_list)(struct vty *vty,
83 struct route_map_index *index,
84 const char *command,
85 const char *arg,
86 route_map_event_t type);
87
88 /* match ip next hop */
89 int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index,
90 const char *command, const char *arg,
91 route_map_event_t type);
92
93 /* no match ip next hop */
94 int (*no_match_ip_next_hop)(struct vty *vty,
95 struct route_map_index *index,
96 const char *command, const char *arg,
97 route_map_event_t type);
98
99 /* match ip next hop prefix list */
100 int (*match_ip_next_hop_prefix_list)(struct vty *vty,
101 struct route_map_index *index,
102 const char *command,
103 const char *arg,
104 route_map_event_t type);
105
106 /* no match ip next hop prefix list */
107 int (*no_match_ip_next_hop_prefix_list)(struct vty *vty,
108 struct route_map_index *index,
109 const char *command,
110 const char *arg,
111 route_map_event_t type);
112
113 /* match ipv6 address */
114 int (*match_ipv6_address)(struct vty *vty,
115 struct route_map_index *index,
116 const char *command, const char *arg,
117 route_map_event_t type);
118
119 /* no match ipv6 address */
120 int (*no_match_ipv6_address)(struct vty *vty,
121 struct route_map_index *index,
122 const char *command, const char *arg,
123 route_map_event_t type);
124
125
126 /* match ipv6 address prefix list */
127 int (*match_ipv6_address_prefix_list)(struct vty *vty,
128 struct route_map_index *index,
129 const char *command,
130 const char *arg,
131 route_map_event_t type);
132
133 /* no match ipv6 address prefix list */
134 int (*no_match_ipv6_address_prefix_list)(struct vty *vty,
135 struct route_map_index *index,
136 const char *command,
137 const char *arg,
138 route_map_event_t type);
139
140 /* match metric */
141 int (*match_metric)(struct vty *vty, struct route_map_index *index,
142 const char *command, const char *arg,
143 route_map_event_t type);
144
145 /* no match metric */
146 int (*no_match_metric)(struct vty *vty, struct route_map_index *index,
147 const char *command, const char *arg,
148 route_map_event_t type);
149
150 /* match tag */
151 int (*match_tag)(struct vty *vty, struct route_map_index *index,
152 const char *command, const char *arg,
153 route_map_event_t type);
154
155 /* no match tag */
156 int (*no_match_tag)(struct vty *vty, struct route_map_index *index,
157 const char *command, const char *arg,
158 route_map_event_t type);
159
160 /* set ip nexthop */
161 int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
162 const char *command, const char *arg);
163
164 /* no set ip nexthop */
165 int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
166 const char *command, const char *arg);
167
168 /* set ipv6 nexthop local */
169 int (*set_ipv6_nexthop_local)(struct vty *vty,
170 struct route_map_index *index,
171 const char *command, const char *arg);
172
173 /* no set ipv6 nexthop local */
174 int (*no_set_ipv6_nexthop_local)(struct vty *vty,
175 struct route_map_index *index,
176 const char *command, const char *arg);
177
178 /* set metric */
179 int (*set_metric)(struct vty *vty, struct route_map_index *index,
180 const char *command, const char *arg);
181
182 /* no set metric */
183 int (*no_set_metric)(struct vty *vty, struct route_map_index *index,
184 const char *command, const char *arg);
185
186 /* set tag */
187 int (*set_tag)(struct vty *vty, struct route_map_index *index,
188 const char *command, const char *arg);
189
190 /* no set tag */
191 int (*no_set_tag)(struct vty *vty, struct route_map_index *index,
192 const char *command, const char *arg);
82f97584
DW
193};
194
195struct route_map_match_set_hooks rmap_match_set_hook;
196
197/* match interface */
d62a17ae 198void route_map_match_interface_hook(int (*func)(
199 struct vty *vty, struct route_map_index *index, const char *command,
200 const char *arg, route_map_event_t type))
82f97584 201{
d62a17ae 202 rmap_match_set_hook.match_interface = func;
82f97584
DW
203}
204
205/* no match interface */
d62a17ae 206void route_map_no_match_interface_hook(int (*func)(
207 struct vty *vty, struct route_map_index *index, const char *command,
208 const char *arg, route_map_event_t type))
82f97584 209{
d62a17ae 210 rmap_match_set_hook.no_match_interface = func;
82f97584
DW
211}
212
213/* match ip address */
d62a17ae 214void route_map_match_ip_address_hook(int (*func)(
215 struct vty *vty, struct route_map_index *index, const char *command,
216 const char *arg, route_map_event_t type))
82f97584 217{
d62a17ae 218 rmap_match_set_hook.match_ip_address = func;
82f97584
DW
219}
220
221/* no match ip address */
d62a17ae 222void route_map_no_match_ip_address_hook(int (*func)(
223 struct vty *vty, struct route_map_index *index, const char *command,
224 const char *arg, route_map_event_t type))
82f97584 225{
d62a17ae 226 rmap_match_set_hook.no_match_ip_address = func;
82f97584
DW
227}
228
229/* match ip address prefix list */
d62a17ae 230void route_map_match_ip_address_prefix_list_hook(int (*func)(
231 struct vty *vty, struct route_map_index *index, const char *command,
232 const char *arg, route_map_event_t type))
82f97584 233{
d62a17ae 234 rmap_match_set_hook.match_ip_address_prefix_list = func;
82f97584
DW
235}
236
237/* no match ip address prefix list */
d62a17ae 238void route_map_no_match_ip_address_prefix_list_hook(int (*func)(
239 struct vty *vty, struct route_map_index *index, const char *command,
240 const char *arg, route_map_event_t type))
82f97584 241{
d62a17ae 242 rmap_match_set_hook.no_match_ip_address_prefix_list = func;
82f97584
DW
243}
244
245/* match ip next hop */
d62a17ae 246void route_map_match_ip_next_hop_hook(int (*func)(
247 struct vty *vty, struct route_map_index *index, const char *command,
248 const char *arg, route_map_event_t type))
82f97584 249{
d62a17ae 250 rmap_match_set_hook.match_ip_next_hop = func;
82f97584
DW
251}
252
253/* no match ip next hop */
d62a17ae 254void route_map_no_match_ip_next_hop_hook(int (*func)(
255 struct vty *vty, struct route_map_index *index, const char *command,
256 const char *arg, route_map_event_t type))
82f97584 257{
d62a17ae 258 rmap_match_set_hook.no_match_ip_next_hop = func;
82f97584
DW
259}
260
261/* match ip next hop prefix list */
d62a17ae 262void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
263 struct vty *vty, struct route_map_index *index, const char *command,
264 const char *arg, route_map_event_t type))
82f97584 265{
d62a17ae 266 rmap_match_set_hook.match_ip_next_hop_prefix_list = func;
82f97584
DW
267}
268
269/* no match ip next hop prefix list */
d62a17ae 270void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)(
271 struct vty *vty, struct route_map_index *index, const char *command,
272 const char *arg, route_map_event_t type))
82f97584 273{
d62a17ae 274 rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func;
82f97584
DW
275}
276
277/* match ipv6 address */
d62a17ae 278void route_map_match_ipv6_address_hook(int (*func)(
279 struct vty *vty, struct route_map_index *index, const char *command,
280 const char *arg, route_map_event_t type))
82f97584 281{
d62a17ae 282 rmap_match_set_hook.match_ipv6_address = func;
82f97584
DW
283}
284
285/* no match ipv6 address */
d62a17ae 286void route_map_no_match_ipv6_address_hook(int (*func)(
287 struct vty *vty, struct route_map_index *index, const char *command,
288 const char *arg, route_map_event_t type))
82f97584 289{
d62a17ae 290 rmap_match_set_hook.no_match_ipv6_address = func;
82f97584
DW
291}
292
293
294/* match ipv6 address prefix list */
d62a17ae 295void route_map_match_ipv6_address_prefix_list_hook(int (*func)(
296 struct vty *vty, struct route_map_index *index, const char *command,
297 const char *arg, route_map_event_t type))
82f97584 298{
d62a17ae 299 rmap_match_set_hook.match_ipv6_address_prefix_list = func;
82f97584
DW
300}
301
302/* no match ipv6 address prefix list */
d62a17ae 303void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)(
304 struct vty *vty, struct route_map_index *index, const char *command,
305 const char *arg, route_map_event_t type))
82f97584 306{
d62a17ae 307 rmap_match_set_hook.no_match_ipv6_address_prefix_list = func;
82f97584
DW
308}
309
310/* match metric */
d62a17ae 311void route_map_match_metric_hook(int (*func)(
312 struct vty *vty, struct route_map_index *index, const char *command,
313 const char *arg, route_map_event_t type))
82f97584 314{
d62a17ae 315 rmap_match_set_hook.match_metric = func;
82f97584
DW
316}
317
318/* no match metric */
d62a17ae 319void route_map_no_match_metric_hook(int (*func)(
320 struct vty *vty, struct route_map_index *index, const char *command,
321 const char *arg, route_map_event_t type))
82f97584 322{
d62a17ae 323 rmap_match_set_hook.no_match_metric = func;
82f97584
DW
324}
325
326/* match tag */
d62a17ae 327void route_map_match_tag_hook(int (*func)(struct vty *vty,
328 struct route_map_index *index,
329 const char *command, const char *arg,
330 route_map_event_t type))
82f97584 331{
d62a17ae 332 rmap_match_set_hook.match_tag = func;
82f97584
DW
333}
334
335/* no match tag */
d62a17ae 336void route_map_no_match_tag_hook(int (*func)(
337 struct vty *vty, struct route_map_index *index, const char *command,
338 const char *arg, route_map_event_t type))
82f97584 339{
d62a17ae 340 rmap_match_set_hook.no_match_tag = func;
82f97584
DW
341}
342
343/* set ip nexthop */
d62a17ae 344void route_map_set_ip_nexthop_hook(int (*func)(struct vty *vty,
345 struct route_map_index *index,
346 const char *command,
347 const char *arg))
82f97584 348{
d62a17ae 349 rmap_match_set_hook.set_ip_nexthop = func;
82f97584
DW
350}
351
352/* no set ip nexthop */
d62a17ae 353void route_map_no_set_ip_nexthop_hook(int (*func)(struct vty *vty,
354 struct route_map_index *index,
355 const char *command,
356 const char *arg))
82f97584 357{
d62a17ae 358 rmap_match_set_hook.no_set_ip_nexthop = func;
82f97584
DW
359}
360
361/* set ipv6 nexthop local */
d62a17ae 362void route_map_set_ipv6_nexthop_local_hook(
363 int (*func)(struct vty *vty, struct route_map_index *index,
364 const char *command, const char *arg))
82f97584 365{
d62a17ae 366 rmap_match_set_hook.set_ipv6_nexthop_local = func;
82f97584
DW
367}
368
369/* no set ipv6 nexthop local */
d62a17ae 370void route_map_no_set_ipv6_nexthop_local_hook(
371 int (*func)(struct vty *vty, struct route_map_index *index,
372 const char *command, const char *arg))
82f97584 373{
d62a17ae 374 rmap_match_set_hook.no_set_ipv6_nexthop_local = func;
82f97584
DW
375}
376
377/* set metric */
d62a17ae 378void route_map_set_metric_hook(int (*func)(struct vty *vty,
379 struct route_map_index *index,
380 const char *command,
381 const char *arg))
82f97584 382{
d62a17ae 383 rmap_match_set_hook.set_metric = func;
82f97584
DW
384}
385
386/* no set metric */
d62a17ae 387void route_map_no_set_metric_hook(int (*func)(struct vty *vty,
388 struct route_map_index *index,
389 const char *command,
390 const char *arg))
82f97584 391{
d62a17ae 392 rmap_match_set_hook.no_set_metric = func;
82f97584
DW
393}
394
395/* set tag */
d62a17ae 396void route_map_set_tag_hook(int (*func)(struct vty *vty,
397 struct route_map_index *index,
398 const char *command, const char *arg))
82f97584 399{
d62a17ae 400 rmap_match_set_hook.set_tag = func;
82f97584
DW
401}
402
403/* no set tag */
d62a17ae 404void route_map_no_set_tag_hook(int (*func)(struct vty *vty,
405 struct route_map_index *index,
406 const char *command,
407 const char *arg))
408{
409 rmap_match_set_hook.no_set_tag = func;
82f97584
DW
410}
411
d62a17ae 412int generic_match_add(struct vty *vty, struct route_map_index *index,
413 const char *command, const char *arg,
414 route_map_event_t type)
415{
416 int ret;
417
418 ret = route_map_add_match(index, command, arg);
419 if (ret) {
420 switch (ret) {
421 case RMAP_RULE_MISSING:
422 vty_out(vty, "%% [%s] Can't find rule.\n",
423 frr_protonameinst);
424 return CMD_WARNING_CONFIG_FAILED;
425 case RMAP_COMPILE_ERROR:
426 vty_out(vty,
427 "%% [%s] Argument form is unsupported or malformed.\n",
428 frr_protonameinst);
429 return CMD_WARNING_CONFIG_FAILED;
430 }
431 }
82f97584 432
d62a17ae 433 if (type != RMAP_EVENT_MATCH_ADDED) {
434 route_map_upd8_dependency(type, arg, index->map->name);
435 }
436 return CMD_SUCCESS;
437}
438
439int generic_match_delete(struct vty *vty, struct route_map_index *index,
440 const char *command, const char *arg,
441 route_map_event_t type)
442{
443 int ret;
444 char *dep_name = NULL;
445 const char *tmpstr;
446 char *rmap_name = NULL;
447
448 if (type != RMAP_EVENT_MATCH_DELETED) {
449 /* ignore the mundane, the types without any dependency */
450 if (arg == NULL) {
451 if ((tmpstr = route_map_get_match_arg(index, command))
452 != NULL)
453 dep_name =
454 XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
455 } else {
456 dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
457 }
458 rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
459 }
460
461 ret = route_map_delete_match(index, command, dep_name);
462 if (ret) {
463 switch (ret) {
464 case RMAP_RULE_MISSING:
465 vty_out(vty, "%% [%s] Can't find rule.\n",
466 frr_protonameinst);
467 break;
468 case RMAP_COMPILE_ERROR:
469 vty_out(vty,
470 "%% [%s] Argument form is unsupported or malformed.\n",
471 frr_protonameinst);
472 break;
473 }
474 if (dep_name)
475 XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
476 if (rmap_name)
477 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
478 return CMD_WARNING_CONFIG_FAILED;
479 }
480
481 if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
482 route_map_upd8_dependency(type, dep_name, rmap_name);
483
484 if (dep_name)
485 XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
486 if (rmap_name)
487 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
488
489 return CMD_SUCCESS;
490}
491
492int generic_set_add(struct vty *vty, struct route_map_index *index,
493 const char *command, const char *arg)
718e3744 494{
d62a17ae 495 int ret;
496
497 ret = route_map_add_set(index, command, arg);
498 if (ret) {
499 switch (ret) {
500 case RMAP_RULE_MISSING:
501 vty_out(vty, "%% [%s] Can't find rule.\n",
502 frr_protonameinst);
503 return CMD_WARNING_CONFIG_FAILED;
504 case RMAP_COMPILE_ERROR:
505 vty_out(vty,
506 "%% [%s] Argument form is unsupported or malformed.\n",
507 frr_protonameinst);
508 return CMD_WARNING_CONFIG_FAILED;
509 }
510 }
511 return CMD_SUCCESS;
512}
513
514int generic_set_delete(struct vty *vty, struct route_map_index *index,
515 const char *command, const char *arg)
516{
517 int ret;
518
519 ret = route_map_delete_set(index, command, arg);
520 if (ret) {
521 switch (ret) {
522 case RMAP_RULE_MISSING:
523 vty_out(vty, "%% [%s] Can't find rule.\n",
524 frr_protonameinst);
525 return CMD_WARNING_CONFIG_FAILED;
526 case RMAP_COMPILE_ERROR:
527 vty_out(vty,
528 "%% [%s] Argument form is unsupported or malformed.\n",
529 frr_protonameinst);
530 return CMD_WARNING_CONFIG_FAILED;
531 }
532 }
533 return CMD_SUCCESS;
534}
535
536
537/* Route map rule. This rule has both `match' rule and `set' rule. */
538struct route_map_rule {
539 /* Rule type. */
540 struct route_map_rule_cmd *cmd;
718e3744 541
d62a17ae 542 /* For pretty printing. */
543 char *rule_str;
718e3744 544
d62a17ae 545 /* Pre-compiled match rule. */
546 void *value;
718e3744 547
d62a17ae 548 /* Linked list. */
549 struct route_map_rule *next;
550 struct route_map_rule *prev;
718e3744 551};
552
553/* Making route map list. */
d62a17ae 554struct route_map_list {
555 struct route_map *head;
556 struct route_map *tail;
718e3744 557
d62a17ae 558 void (*add_hook)(const char *);
559 void (*delete_hook)(const char *);
560 void (*event_hook)(route_map_event_t, const char *);
718e3744 561};
562
563/* Master list of route map. */
d62a17ae 564static struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
a6e0d253
DW
565struct hash *route_map_master_hash = NULL;
566
d62a17ae 567static unsigned int route_map_hash_key_make(void *p)
a6e0d253 568{
d62a17ae 569 const struct route_map *map = p;
570 return string_hash_make(map->name);
a6e0d253
DW
571}
572
d62a17ae 573static int route_map_hash_cmp(const void *p1, const void *p2)
a6e0d253 574{
d62a17ae 575 const struct route_map *map1 = p1;
576 const struct route_map *map2 = p2;
a6e0d253 577
d62a17ae 578 if (map1->deleted == map2->deleted) {
579 if (map1->name && map2->name) {
580 if (!strcmp(map1->name, map2->name)) {
581 return 1;
582 }
583 } else if (!map1->name && !map2->name) {
584 return 1;
585 }
586 }
a6e0d253 587
d62a17ae 588 return 0;
a6e0d253 589}
518f0eb1 590
d62a17ae 591enum route_map_upd8_type {
592 ROUTE_MAP_ADD = 1,
593 ROUTE_MAP_DEL,
594};
518f0eb1
DS
595
596/* all possible route-map dependency types */
d62a17ae 597enum route_map_dep_type {
598 ROUTE_MAP_DEP_RMAP = 1,
599 ROUTE_MAP_DEP_CLIST,
600 ROUTE_MAP_DEP_ECLIST,
601 ROUTE_MAP_DEP_LCLIST,
602 ROUTE_MAP_DEP_PLIST,
603 ROUTE_MAP_DEP_ASPATH,
604 ROUTE_MAP_DEP_FILTER,
605 ROUTE_MAP_DEP_MAX,
606};
607
608struct route_map_dep {
609 char *dep_name;
610 struct hash *dep_rmap_hash;
611 struct hash *this_hash; /* ptr to the hash structure this is part of */
518f0eb1 612};
718e3744 613
518f0eb1
DS
614/* Hashes maintaining dependency between various sublists used by route maps */
615struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
616
d62a17ae 617static unsigned int route_map_dep_hash_make_key(void *p);
618static int route_map_dep_hash_cmp(const void *p1, const void *p2);
619static void route_map_clear_all_references(char *rmap_name);
620static void route_map_rule_delete(struct route_map_rule_list *,
621 struct route_map_rule *);
518f0eb1 622static int rmap_debug = 0;
718e3744 623
d62a17ae 624static void route_map_index_delete(struct route_map_index *, int);
6b0655a2 625
718e3744 626/* New route map allocation. Please note route map's name must be
627 specified. */
d62a17ae 628static struct route_map *route_map_new(const char *name)
718e3744 629{
d62a17ae 630 struct route_map *new;
718e3744 631
d62a17ae 632 new = XCALLOC(MTYPE_ROUTE_MAP, sizeof(struct route_map));
633 new->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
634 QOBJ_REG(new, route_map);
635 return new;
718e3744 636}
637
638/* Add new name to route_map. */
d62a17ae 639static struct route_map *route_map_add(const char *name)
640{
641 struct route_map *map;
642 struct route_map_list *list;
643
644 map = route_map_new(name);
645 list = &route_map_master;
646
647 /* Add map to the hash */
648 hash_get(route_map_master_hash, map, hash_alloc_intern);
649
650 /* Add new entry to the head of the list to match how it is added in the
651 * hash table. This is to ensure that if the same route-map has been
652 * created more than once and then marked for deletion (which can happen
653 * if prior deletions haven't completed as BGP hasn't yet done the
654 * route-map processing), the order of the entities is the same in both
655 * the list and the hash table. Otherwise, since there is nothing to
656 * distinguish between the two entries, the wrong entry could get freed.
657 * TODO: This needs to be re-examined to handle it better - e.g., revive
658 * a deleted entry if the route-map is created again.
659 */
660 map->prev = NULL;
661 map->next = list->head;
662 if (list->head)
663 list->head->prev = map;
664 list->head = map;
665 if (!list->tail)
666 list->tail = map;
667
668 /* Execute hook. */
669 if (route_map_master.add_hook) {
670 (*route_map_master.add_hook)(name);
671 route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
672 }
673 return map;
718e3744 674}
675
518f0eb1
DS
676/* this is supposed to be called post processing by
677 * the delete hook function. Don't invoke delete_hook
678 * again in this routine.
679 */
d62a17ae 680static void route_map_free_map(struct route_map *map)
718e3744 681{
d62a17ae 682 struct route_map_list *list;
683 struct route_map_index *index;
518f0eb1 684
d62a17ae 685 if (map == NULL)
686 return;
a31ff449 687
d62a17ae 688 while ((index = map->head) != NULL)
689 route_map_index_delete(index, 0);
718e3744 690
d62a17ae 691 list = &route_map_master;
718e3744 692
d62a17ae 693 QOBJ_UNREG(map);
e80e7cce 694
d62a17ae 695 if (map->next)
696 map->next->prev = map->prev;
697 else
698 list->tail = map->prev;
718e3744 699
d62a17ae 700 if (map->prev)
701 map->prev->next = map->next;
702 else
703 list->head = map->next;
718e3744 704
d62a17ae 705 hash_release(route_map_master_hash, map);
706 XFREE(MTYPE_ROUTE_MAP_NAME, map->name);
707 XFREE(MTYPE_ROUTE_MAP, map);
518f0eb1 708}
718e3744 709
518f0eb1 710/* Route map delete from list. */
d62a17ae 711static void route_map_delete(struct route_map *map)
518f0eb1 712{
d62a17ae 713 struct route_map_index *index;
714 char *name;
518f0eb1 715
d62a17ae 716 while ((index = map->head) != NULL)
717 route_map_index_delete(index, 0);
518f0eb1 718
d62a17ae 719 name = map->name;
720 map->head = NULL;
518f0eb1 721
d62a17ae 722 /* Clear all dependencies */
723 route_map_clear_all_references(name);
724 map->deleted = 1;
725 /* Execute deletion hook. */
726 if (route_map_master.delete_hook) {
727 (*route_map_master.delete_hook)(name);
728 route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
729 }
718e3744 730
d62a17ae 731 if (!map->to_be_processed) {
732 route_map_free_map(map);
733 }
718e3744 734}
735
736/* Lookup route map by route map name string. */
d62a17ae 737struct route_map *route_map_lookup_by_name(const char *name)
718e3744 738{
d62a17ae 739 struct route_map *map;
740 struct route_map tmp_map;
718e3744 741
d62a17ae 742 if (!name)
743 return NULL;
518f0eb1 744
d62a17ae 745 // map.deleted is 0 via memset
746 memset(&tmp_map, 0, sizeof(struct route_map));
747 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
748 map = hash_lookup(route_map_master_hash, &tmp_map);
749 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
750 return map;
718e3744 751}
752
d62a17ae 753int route_map_mark_updated(const char *name, int del_later)
518f0eb1 754{
d62a17ae 755 struct route_map *map;
756 int ret = -1;
757 struct route_map tmp_map;
518f0eb1 758
d62a17ae 759 if (!name)
760 return (ret);
a6e0d253 761
d62a17ae 762 map = route_map_lookup_by_name(name);
a6e0d253 763
d62a17ae 764 /* If we did not find the routemap with deleted=0 try again
765 * with deleted=1
766 */
767 if (!map) {
768 memset(&tmp_map, 0, sizeof(struct route_map));
769 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
770 tmp_map.deleted = 1;
771 map = hash_lookup(route_map_master_hash, &tmp_map);
772 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
773 }
a6e0d253 774
d62a17ae 775 if (map) {
776 map->to_be_processed = 1;
777 ret = 0;
778 }
518f0eb1 779
d62a17ae 780 return (ret);
518f0eb1
DS
781}
782
d62a17ae 783int route_map_clear_updated(struct route_map *map)
518f0eb1 784{
d62a17ae 785 int ret = -1;
518f0eb1 786
d62a17ae 787 if (map) {
788 map->to_be_processed = 0;
789 if (map->deleted)
790 route_map_free_map(map);
791 }
518f0eb1 792
d62a17ae 793 return (ret);
518f0eb1
DS
794}
795
718e3744 796/* Lookup route map. If there isn't route map create one and return
797 it. */
d62a17ae 798static struct route_map *route_map_get(const char *name)
718e3744 799{
d62a17ae 800 struct route_map *map;
718e3744 801
d62a17ae 802 map = route_map_lookup_by_name(name);
803 if (map == NULL)
804 map = route_map_add(name);
518f0eb1 805
d62a17ae 806 return map;
718e3744 807}
808
d62a17ae 809void route_map_walk_update_list(int (*route_map_update_fn)(char *name))
518f0eb1 810{
d62a17ae 811 struct route_map *node;
812 struct route_map *nnode = NULL;
518f0eb1 813
d62a17ae 814 for (node = route_map_master.head; node; node = nnode) {
815 if (node->to_be_processed) {
816 /* DD: Should we add any thread yield code here */
817 route_map_update_fn(node->name);
818 nnode = node->next;
819 route_map_clear_updated(node);
820 } else
821 nnode = node->next;
518f0eb1 822 }
518f0eb1
DS
823}
824
718e3744 825/* Return route map's type string. */
d62a17ae 826static const char *route_map_type_str(enum route_map_type type)
827{
828 switch (type) {
829 case RMAP_PERMIT:
830 return "permit";
831 break;
832 case RMAP_DENY:
833 return "deny";
834 break;
835 default:
836 return "";
837 break;
838 }
718e3744 839}
840
d62a17ae 841static int route_map_empty(struct route_map *map)
718e3744 842{
d62a17ae 843 if (map->head == NULL && map->tail == NULL)
844 return 1;
845 else
846 return 0;
718e3744 847}
848
5510e83b 849/* show route-map */
d62a17ae 850static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
851{
852 struct route_map_index *index;
853 struct route_map_rule *rule;
854
855 vty_out(vty, "%s:\n", frr_protonameinst);
856
857 for (index = map->head; index; index = index->next) {
858 vty_out(vty, "route-map %s, %s, sequence %d\n", map->name,
859 route_map_type_str(index->type), index->pref);
860
861 /* Description */
862 if (index->description)
863 vty_out(vty, " Description:\n %s\n",
864 index->description);
865
866 /* Match clauses */
867 vty_out(vty, " Match clauses:\n");
868 for (rule = index->match_list.head; rule; rule = rule->next)
869 vty_out(vty, " %s %s\n", rule->cmd->str,
870 rule->rule_str);
871
872 vty_out(vty, " Set clauses:\n");
873 for (rule = index->set_list.head; rule; rule = rule->next)
874 vty_out(vty, " %s %s\n", rule->cmd->str,
875 rule->rule_str);
876
877 /* Call clause */
878 vty_out(vty, " Call clause:\n");
879 if (index->nextrm)
880 vty_out(vty, " Call %s\n", index->nextrm);
881
882 /* Exit Policy */
883 vty_out(vty, " Action:\n");
884 if (index->exitpolicy == RMAP_GOTO)
885 vty_out(vty, " Goto %d\n", index->nextpref);
886 else if (index->exitpolicy == RMAP_NEXT)
887 vty_out(vty, " Continue to next entry\n");
888 else if (index->exitpolicy == RMAP_EXIT)
889 vty_out(vty, " Exit routemap\n");
890 }
891}
892
893static int vty_show_route_map(struct vty *vty, const char *name)
894{
895 struct route_map *map;
896
897 if (name) {
898 map = route_map_lookup_by_name(name);
899
900 if (map) {
901 vty_show_route_map_entry(vty, map);
902 return CMD_SUCCESS;
903 } else {
904 vty_out(vty, "%s: 'route-map %s' not found\n",
905 frr_protonameinst, name);
906 return CMD_SUCCESS;
907 }
908 } else {
909 for (map = route_map_master.head; map; map = map->next)
910 if (!map->deleted)
911 vty_show_route_map_entry(vty, map);
912 }
913 return CMD_SUCCESS;
5510e83b 914}
915
916
718e3744 917/* New route map allocation. Please note route map's name must be
918 specified. */
d62a17ae 919static struct route_map_index *route_map_index_new(void)
718e3744 920{
d62a17ae 921 struct route_map_index *new;
718e3744 922
d62a17ae 923 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
924 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
925 QOBJ_REG(new, route_map_index);
926 return new;
718e3744 927}
928
929/* Free route map index. */
d62a17ae 930static void route_map_index_delete(struct route_map_index *index, int notify)
718e3744 931{
d62a17ae 932 struct route_map_rule *rule;
718e3744 933
d62a17ae 934 QOBJ_UNREG(index);
e80e7cce 935
d62a17ae 936 /* Free route match. */
937 while ((rule = index->match_list.head) != NULL)
938 route_map_rule_delete(&index->match_list, rule);
718e3744 939
d62a17ae 940 /* Free route set. */
941 while ((rule = index->set_list.head) != NULL)
942 route_map_rule_delete(&index->set_list, rule);
718e3744 943
d62a17ae 944 /* Remove index from route map list. */
945 if (index->next)
946 index->next->prev = index->prev;
947 else
948 index->map->tail = index->prev;
718e3744 949
d62a17ae 950 if (index->prev)
951 index->prev->next = index->next;
952 else
953 index->map->head = index->next;
718e3744 954
d62a17ae 955 /* Free 'char *nextrm' if not NULL */
956 if (index->nextrm)
957 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
fee0f4c6 958
d62a17ae 959 /* Execute event hook. */
960 if (route_map_master.event_hook && notify) {
961 (*route_map_master.event_hook)(RMAP_EVENT_INDEX_DELETED,
962 index->map->name);
963 route_map_notify_dependencies(index->map->name,
964 RMAP_EVENT_CALL_ADDED);
965 }
966 XFREE(MTYPE_ROUTE_MAP_INDEX, index);
718e3744 967}
968
969/* Lookup index from route map. */
d62a17ae 970static struct route_map_index *route_map_index_lookup(struct route_map *map,
971 enum route_map_type type,
972 int pref)
718e3744 973{
d62a17ae 974 struct route_map_index *index;
718e3744 975
d62a17ae 976 for (index = map->head; index; index = index->next)
977 if ((index->type == type || type == RMAP_ANY)
978 && index->pref == pref)
979 return index;
980 return NULL;
718e3744 981}
982
983/* Add new index to route map. */
8cc4198f 984static struct route_map_index *
d62a17ae 985route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
986{
987 struct route_map_index *index;
988 struct route_map_index *point;
989
990 /* Allocate new route map inex. */
991 index = route_map_index_new();
992 index->map = map;
993 index->type = type;
994 index->pref = pref;
995
996 /* Compare preference. */
997 for (point = map->head; point; point = point->next)
998 if (point->pref >= pref)
999 break;
1000
1001 if (map->head == NULL) {
1002 map->head = map->tail = index;
1003 } else if (point == NULL) {
1004 index->prev = map->tail;
1005 map->tail->next = index;
1006 map->tail = index;
1007 } else if (point == map->head) {
1008 index->next = map->head;
1009 map->head->prev = index;
1010 map->head = index;
1011 } else {
1012 index->next = point;
1013 index->prev = point->prev;
1014 if (point->prev)
1015 point->prev->next = index;
1016 point->prev = index;
1017 }
1018
1019 /* Execute event hook. */
1020 if (route_map_master.event_hook) {
1021 (*route_map_master.event_hook)(RMAP_EVENT_INDEX_ADDED,
1022 map->name);
1023 route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
1024 }
1025 return index;
718e3744 1026}
1027
1028/* Get route map index. */
8cc4198f 1029static struct route_map_index *
d62a17ae 1030route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
718e3744 1031{
d62a17ae 1032 struct route_map_index *index;
718e3744 1033
d62a17ae 1034 index = route_map_index_lookup(map, RMAP_ANY, pref);
1035 if (index && index->type != type) {
1036 /* Delete index from route map. */
1037 route_map_index_delete(index, 1);
1038 index = NULL;
1039 }
1040 if (index == NULL)
1041 index = route_map_index_add(map, type, pref);
1042 return index;
718e3744 1043}
1044
1045/* New route map rule */
d62a17ae 1046static struct route_map_rule *route_map_rule_new(void)
718e3744 1047{
d62a17ae 1048 struct route_map_rule *new;
718e3744 1049
d62a17ae 1050 new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
1051 return new;
718e3744 1052}
6b0655a2 1053
718e3744 1054/* Install rule command to the match list. */
d62a17ae 1055void route_map_install_match(struct route_map_rule_cmd *cmd)
718e3744 1056{
d62a17ae 1057 vector_set(route_match_vec, cmd);
718e3744 1058}
1059
1060/* Install rule command to the set list. */
d62a17ae 1061void route_map_install_set(struct route_map_rule_cmd *cmd)
718e3744 1062{
d62a17ae 1063 vector_set(route_set_vec, cmd);
718e3744 1064}
1065
1066/* Lookup rule command from match list. */
d62a17ae 1067static struct route_map_rule_cmd *route_map_lookup_match(const char *name)
718e3744 1068{
d62a17ae 1069 unsigned int i;
1070 struct route_map_rule_cmd *rule;
718e3744 1071
d62a17ae 1072 for (i = 0; i < vector_active(route_match_vec); i++)
1073 if ((rule = vector_slot(route_match_vec, i)) != NULL)
1074 if (strcmp(rule->str, name) == 0)
1075 return rule;
1076 return NULL;
718e3744 1077}
1078
1079/* Lookup rule command from set list. */
d62a17ae 1080static struct route_map_rule_cmd *route_map_lookup_set(const char *name)
718e3744 1081{
d62a17ae 1082 unsigned int i;
1083 struct route_map_rule_cmd *rule;
718e3744 1084
d62a17ae 1085 for (i = 0; i < vector_active(route_set_vec); i++)
1086 if ((rule = vector_slot(route_set_vec, i)) != NULL)
1087 if (strcmp(rule->str, name) == 0)
1088 return rule;
1089 return NULL;
718e3744 1090}
1091
1092/* Add match and set rule to rule list. */
d62a17ae 1093static void route_map_rule_add(struct route_map_rule_list *list,
1094 struct route_map_rule *rule)
718e3744 1095{
d62a17ae 1096 rule->next = NULL;
1097 rule->prev = list->tail;
1098 if (list->tail)
1099 list->tail->next = rule;
1100 else
1101 list->head = rule;
1102 list->tail = rule;
718e3744 1103}
1104
1105/* Delete rule from rule list. */
d62a17ae 1106static void route_map_rule_delete(struct route_map_rule_list *list,
1107 struct route_map_rule *rule)
718e3744 1108{
d62a17ae 1109 if (rule->cmd->func_free)
1110 (*rule->cmd->func_free)(rule->value);
718e3744 1111
d62a17ae 1112 if (rule->rule_str)
1113 XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
718e3744 1114
d62a17ae 1115 if (rule->next)
1116 rule->next->prev = rule->prev;
1117 else
1118 list->tail = rule->prev;
1119 if (rule->prev)
1120 rule->prev->next = rule->next;
1121 else
1122 list->head = rule->next;
718e3744 1123
d62a17ae 1124 XFREE(MTYPE_ROUTE_MAP_RULE, rule);
718e3744 1125}
1126
1127/* strcmp wrapper function which don't crush even argument is NULL. */
d62a17ae 1128static int rulecmp(const char *dst, const char *src)
1129{
1130 if (dst == NULL) {
1131 if (src == NULL)
1132 return 0;
1133 else
1134 return 1;
1135 } else {
1136 if (src == NULL)
1137 return 1;
1138 else
1139 return strcmp(dst, src);
1140 }
718e3744 1141 return 1;
718e3744 1142}
1143
518f0eb1
DS
1144/* Use this to return the already specified argument for this match. This is
1145 * useful to get the specified argument with a route map match rule when the
1146 * rule is being deleted and the argument is not provided.
1147 */
d62a17ae 1148const char *route_map_get_match_arg(struct route_map_index *index,
1149 const char *match_name)
518f0eb1 1150{
d62a17ae 1151 struct route_map_rule *rule;
1152 struct route_map_rule_cmd *cmd;
518f0eb1 1153
d62a17ae 1154 /* First lookup rule for add match statement. */
1155 cmd = route_map_lookup_match(match_name);
1156 if (cmd == NULL)
1157 return NULL;
518f0eb1 1158
d62a17ae 1159 for (rule = index->match_list.head; rule; rule = rule->next)
1160 if (rule->cmd == cmd && rule->rule_str != NULL)
1161 return (rule->rule_str);
518f0eb1 1162
d62a17ae 1163 return (NULL);
518f0eb1
DS
1164}
1165
718e3744 1166/* Add match statement to route map. */
d62a17ae 1167int route_map_add_match(struct route_map_index *index, const char *match_name,
1168 const char *match_arg)
1169{
1170 struct route_map_rule *rule;
1171 struct route_map_rule *next;
1172 struct route_map_rule_cmd *cmd;
1173 void *compile;
1174 int replaced = 0;
1175
1176 /* First lookup rule for add match statement. */
1177 cmd = route_map_lookup_match(match_name);
1178 if (cmd == NULL)
1179 return RMAP_RULE_MISSING;
1180
1181 /* Next call compile function for this match statement. */
1182 if (cmd->func_compile) {
1183 compile = (*cmd->func_compile)(match_arg);
1184 if (compile == NULL)
1185 return RMAP_COMPILE_ERROR;
1186 } else
1187 compile = NULL;
1188
1189 /* If argument is completely same ignore it. */
1190 for (rule = index->match_list.head; rule; rule = next) {
1191 next = rule->next;
1192 if (rule->cmd == cmd) {
1193 route_map_rule_delete(&index->match_list, rule);
1194 replaced = 1;
1195 }
718e3744 1196 }
718e3744 1197
d62a17ae 1198 /* Add new route map match rule. */
1199 rule = route_map_rule_new();
1200 rule->cmd = cmd;
1201 rule->value = compile;
1202 if (match_arg)
1203 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1204 else
1205 rule->rule_str = NULL;
718e3744 1206
d62a17ae 1207 /* Add new route match rule to linked list. */
1208 route_map_rule_add(&index->match_list, rule);
718e3744 1209
d62a17ae 1210 /* Execute event hook. */
1211 if (route_map_master.event_hook) {
1212 (*route_map_master.event_hook)(
1213 replaced ? RMAP_EVENT_MATCH_REPLACED
1214 : RMAP_EVENT_MATCH_ADDED,
1215 index->map->name);
1216 route_map_notify_dependencies(index->map->name,
1217 RMAP_EVENT_CALL_ADDED);
1218 }
718e3744 1219
d62a17ae 1220 return 0;
718e3744 1221}
1222
1223/* Delete specified route match rule. */
d62a17ae 1224int route_map_delete_match(struct route_map_index *index,
1225 const char *match_name, const char *match_arg)
1226{
1227 struct route_map_rule *rule;
1228 struct route_map_rule_cmd *cmd;
1229
1230 cmd = route_map_lookup_match(match_name);
1231 if (cmd == NULL)
1232 return 1;
1233
1234 for (rule = index->match_list.head; rule; rule = rule->next)
9d303b37
DL
1235 if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1236 || match_arg == NULL)) {
d62a17ae 1237 route_map_rule_delete(&index->match_list, rule);
1238 /* Execute event hook. */
1239 if (route_map_master.event_hook) {
1240 (*route_map_master.event_hook)(
1241 RMAP_EVENT_MATCH_DELETED,
1242 index->map->name);
1243 route_map_notify_dependencies(
1244 index->map->name,
1245 RMAP_EVENT_CALL_ADDED);
1246 }
1247 return 0;
1248 }
1249 /* Can't find matched rule. */
1250 return 1;
718e3744 1251}
1252
1253/* Add route-map set statement to the route map. */
d62a17ae 1254int route_map_add_set(struct route_map_index *index, const char *set_name,
1255 const char *set_arg)
1256{
1257 struct route_map_rule *rule;
1258 struct route_map_rule *next;
1259 struct route_map_rule_cmd *cmd;
1260 void *compile;
1261 int replaced = 0;
1262
1263 cmd = route_map_lookup_set(set_name);
1264 if (cmd == NULL)
1265 return RMAP_RULE_MISSING;
1266
1267 /* Next call compile function for this match statement. */
1268 if (cmd->func_compile) {
1269 compile = (*cmd->func_compile)(set_arg);
1270 if (compile == NULL)
1271 return RMAP_COMPILE_ERROR;
1272 } else
1273 compile = NULL;
1274
1275 /* Add by WJL. if old set command of same kind exist, delete it first
1276 to ensure only one set command of same kind exist under a
1277 route_map_index. */
1278 for (rule = index->set_list.head; rule; rule = next) {
1279 next = rule->next;
1280 if (rule->cmd == cmd) {
1281 route_map_rule_delete(&index->set_list, rule);
1282 replaced = 1;
1283 }
1284 }
1285
1286 /* Add new route map match rule. */
1287 rule = route_map_rule_new();
1288 rule->cmd = cmd;
1289 rule->value = compile;
1290 if (set_arg)
1291 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1292 else
1293 rule->rule_str = NULL;
1294
1295 /* Add new route match rule to linked list. */
1296 route_map_rule_add(&index->set_list, rule);
1297
1298 /* Execute event hook. */
1299 if (route_map_master.event_hook) {
1300 (*route_map_master.event_hook)(replaced
1301 ? RMAP_EVENT_SET_REPLACED
1302 : RMAP_EVENT_SET_ADDED,
1303 index->map->name);
1304 route_map_notify_dependencies(index->map->name,
1305 RMAP_EVENT_CALL_ADDED);
718e3744 1306 }
d62a17ae 1307 return 0;
718e3744 1308}
1309
1310/* Delete route map set rule. */
d62a17ae 1311int route_map_delete_set(struct route_map_index *index, const char *set_name,
1312 const char *set_arg)
1313{
1314 struct route_map_rule *rule;
1315 struct route_map_rule_cmd *cmd;
1316
1317 cmd = route_map_lookup_set(set_name);
1318 if (cmd == NULL)
1319 return 1;
1320
1321 for (rule = index->set_list.head; rule; rule = rule->next)
9d303b37
DL
1322 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1323 || set_arg == NULL)) {
d62a17ae 1324 route_map_rule_delete(&index->set_list, rule);
1325 /* Execute event hook. */
1326 if (route_map_master.event_hook) {
1327 (*route_map_master.event_hook)(
1328 RMAP_EVENT_SET_DELETED,
1329 index->map->name);
1330 route_map_notify_dependencies(
1331 index->map->name,
1332 RMAP_EVENT_CALL_ADDED);
1333 }
1334 return 0;
1335 }
1336 /* Can't find matched rule. */
1337 return 1;
718e3744 1338}
1339
3bf1c917 1340/* Apply route map's each index to the object.
1341
1342 The matrix for a route-map looks like this:
1343 (note, this includes the description for the "NEXT"
1344 and "GOTO" frobs now
d62a17ae 1345
1346 Match | No Match
1347 |
3bf1c917 1348 permit action | cont
d62a17ae 1349 |
3bf1c917 1350 ------------------+---------------
d62a17ae 1351 |
3bf1c917 1352 deny deny | cont
d62a17ae 1353 |
1354
fee0f4c6 1355 action)
1356 -Apply Set statements, accept route
1357 -If Call statement is present jump to the specified route-map, if it
d62a17ae 1358 denies the route we finish.
fee0f4c6 1359 -If NEXT is specified, goto NEXT statement
1360 -If GOTO is specified, goto the first clause where pref > nextpref
1361 -If nothing is specified, do as Cisco and finish
1362 deny)
1363 -Route is denied by route-map.
1364 cont)
1365 -Goto Next index
d62a17ae 1366
3bf1c917 1367 If we get no matches after we've processed all updates, then the route
1368 is dropped too.
d62a17ae 1369
fee0f4c6 1370 Some notes on the new "CALL", "NEXT" and "GOTO"
1371 call WORD - If this clause is matched, then the set statements
d62a17ae 1372 are executed and then we jump to route-map 'WORD'. If
1373 this route-map denies the route, we finish, in other
1374 case we
1375 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
3bf1c917 1376 on-match next - If this clause is matched, then the set statements
d62a17ae 1377 are executed and then we drop through to the next clause
3bf1c917 1378 on-match goto n - If this clause is matched, then the set statments
d62a17ae 1379 are executed and then we goto the nth clause, or the
1380 first clause greater than this. In order to ensure
1381 route-maps *always* exit, you cannot jump backwards.
1382 Sorry ;)
1383
3bf1c917 1384 We need to make sure our route-map processing matches the above
718e3744 1385*/
3bf1c917 1386
8cc4198f 1387static route_map_result_t
d62a17ae 1388route_map_apply_match(struct route_map_rule_list *match_list,
1389 struct prefix *prefix, route_map_object_t type,
1390 void *object)
1391{
1392 route_map_result_t ret = RMAP_NOMATCH;
1393 struct route_map_rule *match;
1394
1395
1396 /* Check all match rule and if there is no match rule, go to the
1397 set statement. */
1398 if (!match_list->head)
1399 ret = RMAP_MATCH;
1400 else {
1401 for (match = match_list->head; match; match = match->next) {
1402 /* Try each match statement in turn, If any do not
1403 return
1404 RMAP_MATCH, return, otherwise continue on to next
1405 match
1406 statement. All match statements must match for
1407 end-result
1408 to be a match. */
1409 ret = (*match->cmd->func_apply)(match->value, prefix,
1410 type, object);
1411 if (ret != RMAP_MATCH)
1412 return ret;
1413 }
1414 }
1415 return ret;
718e3744 1416}
1417
1418/* Apply route map to the object. */
d62a17ae 1419route_map_result_t route_map_apply(struct route_map *map, struct prefix *prefix,
1420 route_map_object_t type, void *object)
1421{
1422 static int recursion = 0;
1423 int ret = 0;
1424 struct route_map_index *index;
1425 struct route_map_rule *set;
1426
1427 if (recursion > RMAP_RECURSION_LIMIT) {
1428 zlog_warn(
1429 "route-map recursion limit (%d) reached, discarding route",
1430 RMAP_RECURSION_LIMIT);
1431 recursion = 0;
1432 return RMAP_DENYMATCH;
1433 }
1434
1435 if (map == NULL)
1436 return RMAP_DENYMATCH;
1437
1438 for (index = map->head; index; index = index->next) {
1439 /* Apply this index. */
1440 ret = route_map_apply_match(&index->match_list, prefix, type,
1441 object);
1442
1443 /* Now we apply the matrix from above */
1444 if (ret == RMAP_NOMATCH)
1445 /* 'cont' from matrix - continue to next route-map
1446 * sequence */
1447 continue;
1448 else if (ret == RMAP_MATCH) {
1449 if (index->type == RMAP_PERMIT)
1450 /* 'action' */
1451 {
1452 /* permit+match must execute sets */
1453 for (set = index->set_list.head; set;
1454 set = set->next)
1455 ret = (*set->cmd->func_apply)(
1456 set->value, prefix, type,
1457 object);
1458
1459 /* Call another route-map if available */
1460 if (index->nextrm) {
1461 struct route_map *nextrm =
1462 route_map_lookup_by_name(
1463 index->nextrm);
1464
1465 if (nextrm) /* Target route-map found,
1466 jump to it */
1467 {
1468 recursion++;
1469 ret = route_map_apply(
1470 nextrm, prefix, type,
1471 object);
1472 recursion--;
1473 }
1474
1475 /* If nextrm returned 'deny', finish. */
1476 if (ret == RMAP_DENYMATCH)
1477 return ret;
1478 }
1479
1480 switch (index->exitpolicy) {
1481 case RMAP_EXIT:
1482 return ret;
1483 case RMAP_NEXT:
1484 continue;
1485 case RMAP_GOTO: {
1486 /* Find the next clause to jump to */
1487 struct route_map_index *next =
1488 index->next;
1489 int nextpref = index->nextpref;
1490
1491 while (next && next->pref < nextpref) {
1492 index = next;
1493 next = next->next;
1494 }
1495 if (next == NULL) {
1496 /* No clauses match! */
1497 return ret;
1498 }
1499 }
1500 }
1501 } else if (index->type == RMAP_DENY)
1502 /* 'deny' */
1503 {
1504 return RMAP_DENYMATCH;
1505 }
1506 }
1507 }
1508 /* Finally route-map does not match at all. */
1509 return RMAP_DENYMATCH;
1510}
1511
1512void route_map_add_hook(void (*func)(const char *))
1513{
1514 route_map_master.add_hook = func;
1515}
1516
1517void route_map_delete_hook(void (*func)(const char *))
1518{
1519 route_map_master.delete_hook = func;
1520}
1521
1522void route_map_event_hook(void (*func)(route_map_event_t, const char *))
1523{
1524 route_map_master.event_hook = func;
718e3744 1525}
1526
518f0eb1 1527/* Routines for route map dependency lists and dependency processing */
d62a17ae 1528static int route_map_rmap_hash_cmp(const void *p1, const void *p2)
518f0eb1 1529{
d62a17ae 1530 return (strcmp((const char *)p1, (const char *)p2) == 0);
518f0eb1
DS
1531}
1532
d62a17ae 1533static int route_map_dep_hash_cmp(const void *p1, const void *p2)
518f0eb1
DS
1534{
1535
d62a17ae 1536 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
1537 (const char *)p2)
1538 == 0);
518f0eb1
DS
1539}
1540
d62a17ae 1541static void route_map_clear_reference(struct hash_backet *backet, void *arg)
518f0eb1 1542{
d62a17ae 1543 struct route_map_dep *dep = (struct route_map_dep *)backet->data;
1544 char *rmap_name;
518f0eb1 1545
d62a17ae 1546 if (dep && arg) {
1547 rmap_name =
1548 (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
1549 if (rmap_name) {
1550 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
1551 }
1552 if (!dep->dep_rmap_hash->count) {
1553 dep = hash_release(dep->this_hash,
1554 (void *)dep->dep_name);
1555 hash_free(dep->dep_rmap_hash);
1556 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1557 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1558 }
518f0eb1 1559 }
d62a17ae 1560}
1561
1562static void route_map_clear_all_references(char *rmap_name)
1563{
1564 int i;
1565
1566 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
1567 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1568 (void *)rmap_name);
518f0eb1 1569 }
518f0eb1
DS
1570}
1571
d62a17ae 1572static void *route_map_dep_hash_alloc(void *p)
518f0eb1 1573{
d62a17ae 1574 char *dep_name = (char *)p;
1575 struct route_map_dep *dep_entry;
1576
1577 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1578 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1579 dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
1580 route_map_rmap_hash_cmp, NULL);
1581 dep_entry->this_hash = NULL;
1582
1583 return ((void *)dep_entry);
1584}
518f0eb1 1585
d62a17ae 1586static void *route_map_name_hash_alloc(void *p)
1587{
1588 return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (const char *)p));
518f0eb1
DS
1589}
1590
d62a17ae 1591static unsigned int route_map_dep_hash_make_key(void *p)
518f0eb1 1592{
d62a17ae 1593 return (string_hash_make((char *)p));
1594}
518f0eb1 1595
d62a17ae 1596static void route_map_print_dependency(struct hash_backet *backet, void *data)
1597{
1598 char *rmap_name = (char *)backet->data;
1599 char *dep_name = (char *)data;
518f0eb1 1600
d62a17ae 1601 if (rmap_name)
1602 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name,
1603 rmap_name);
518f0eb1
DS
1604}
1605
d62a17ae 1606static int route_map_dep_update(struct hash *dephash, const char *dep_name,
1607 const char *rmap_name, route_map_event_t type)
518f0eb1 1608{
d62a17ae 1609 struct route_map_dep *dep = NULL;
1610 char *ret_map_name;
1611 char *dname, *rname;
1612 int ret = 0;
1613
1614 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1615 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1616
1617 switch (type) {
1618 case RMAP_EVENT_PLIST_ADDED:
1619 case RMAP_EVENT_CLIST_ADDED:
1620 case RMAP_EVENT_ECLIST_ADDED:
1621 case RMAP_EVENT_ASLIST_ADDED:
1622 case RMAP_EVENT_LLIST_ADDED:
1623 case RMAP_EVENT_CALL_ADDED:
1624 case RMAP_EVENT_FILTER_ADDED:
1625 if (rmap_debug)
1626 zlog_debug("%s: Adding dependency for %s in %s",
1627 __FUNCTION__, dep_name, rmap_name);
1628 dep = (struct route_map_dep *)hash_get(
1629 dephash, dname, route_map_dep_hash_alloc);
1630 if (!dep) {
1631 ret = -1;
1632 goto out;
1633 }
1634
1635 if (!dep->this_hash)
1636 dep->this_hash = dephash;
1637
1638 hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
1639 break;
1640 case RMAP_EVENT_PLIST_DELETED:
1641 case RMAP_EVENT_CLIST_DELETED:
1642 case RMAP_EVENT_ECLIST_DELETED:
1643 case RMAP_EVENT_ASLIST_DELETED:
1644 case RMAP_EVENT_LLIST_DELETED:
1645 case RMAP_EVENT_CALL_DELETED:
1646 case RMAP_EVENT_FILTER_DELETED:
1647 if (rmap_debug)
1648 zlog_debug("%s: Deleting dependency for %s in %s",
1649 __FUNCTION__, dep_name, rmap_name);
1650 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
1651 if (!dep) {
1652 goto out;
1653 }
1654
1655 ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
1656 if (ret_map_name)
1657 XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
1658
1659 if (!dep->dep_rmap_hash->count) {
1660 dep = hash_release(dephash, dname);
1661 hash_free(dep->dep_rmap_hash);
1662 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1663 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1664 dep = NULL;
1665 }
1666 break;
1667 default:
1668 break;
1669 }
1670
1671 if (dep) {
1672 if (rmap_debug)
1673 hash_iterate(dep->dep_rmap_hash,
1674 route_map_print_dependency, dname);
1675 }
1676
1677out:
1678 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1679 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1680 return ret;
1681}
1682
1683static struct hash *route_map_get_dep_hash(route_map_event_t event)
1684{
1685 struct hash *upd8_hash = NULL;
1686
1687 switch (event) {
1688 case RMAP_EVENT_PLIST_ADDED:
1689 case RMAP_EVENT_PLIST_DELETED:
1690 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1691 break;
1692 case RMAP_EVENT_CLIST_ADDED:
1693 case RMAP_EVENT_CLIST_DELETED:
1694 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1695 break;
1696 case RMAP_EVENT_ECLIST_ADDED:
1697 case RMAP_EVENT_ECLIST_DELETED:
1698 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1699 break;
1700 case RMAP_EVENT_ASLIST_ADDED:
1701 case RMAP_EVENT_ASLIST_DELETED:
1702 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1703 break;
1704 case RMAP_EVENT_LLIST_ADDED:
1705 case RMAP_EVENT_LLIST_DELETED:
1706 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1707 break;
1708 case RMAP_EVENT_CALL_ADDED:
1709 case RMAP_EVENT_CALL_DELETED:
1710 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
1711 break;
1712 case RMAP_EVENT_FILTER_ADDED:
1713 case RMAP_EVENT_FILTER_DELETED:
1714 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
1715 break;
1716 default:
1717 upd8_hash = NULL;
1718 break;
1719 }
1720 return (upd8_hash);
518f0eb1
DS
1721}
1722
d62a17ae 1723static void route_map_process_dependency(struct hash_backet *backet, void *data)
518f0eb1 1724{
d62a17ae 1725 char *rmap_name;
1726 route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
1727
1728 rmap_name = (char *)backet->data;
1729
1730 if (rmap_name) {
1731 if (rmap_debug)
1732 zlog_debug("%s: Notifying %s of dependency",
1733 __FUNCTION__, rmap_name);
1734 if (route_map_master.event_hook)
1735 (*route_map_master.event_hook)(type, rmap_name);
1736 }
518f0eb1
DS
1737}
1738
d62a17ae 1739void route_map_upd8_dependency(route_map_event_t type, const char *arg,
1740 const char *rmap_name)
518f0eb1 1741{
d62a17ae 1742 struct hash *upd8_hash = NULL;
518f0eb1 1743
d62a17ae 1744 if ((upd8_hash = route_map_get_dep_hash(type)))
1745 route_map_dep_update(upd8_hash, arg, rmap_name, type);
518f0eb1
DS
1746}
1747
d62a17ae 1748void route_map_notify_dependencies(const char *affected_name,
1749 route_map_event_t event)
518f0eb1 1750{
d62a17ae 1751 struct route_map_dep *dep;
1752 struct hash *upd8_hash;
1753 char *name;
1754
1755 if (!affected_name)
1756 return;
1757
1758 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
1759
1760 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
1761 XFREE(MTYPE_ROUTE_MAP_NAME, name);
1762 return;
518f0eb1 1763 }
d62a17ae 1764
1765 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
1766 if (dep) {
1767 if (!dep->this_hash)
1768 dep->this_hash = upd8_hash;
1769
1770 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
1771 (void *)event);
1772 }
1773
1774 XFREE(MTYPE_ROUTE_MAP_NAME, name);
518f0eb1
DS
1775}
1776
82f97584 1777
718e3744 1778/* VTY related functions. */
82f97584
DW
1779DEFUN (match_interface,
1780 match_interface_cmd,
1781 "match interface WORD",
1782 MATCH_STR
1783 "match first hop interface of route\n"
1784 "Interface name\n")
1785{
d62a17ae 1786 int idx_word = 2;
1787 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 1788
d62a17ae 1789 if (rmap_match_set_hook.match_interface)
1790 return rmap_match_set_hook.match_interface(
1791 vty, index, "interface", argv[idx_word]->arg,
1792 RMAP_EVENT_MATCH_ADDED);
1793 return CMD_SUCCESS;
82f97584
DW
1794}
1795
1796DEFUN (no_match_interface,
1797 no_match_interface_cmd,
70d44c5c 1798 "no match interface [WORD]",
82f97584
DW
1799 NO_STR
1800 MATCH_STR
1801 "Match first hop interface of route\n"
1802 "Interface name\n")
1803{
d62a17ae 1804 char *iface = (argc == 4) ? argv[3]->arg : NULL;
1805 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 1806
d62a17ae 1807 if (rmap_match_set_hook.no_match_interface)
1808 return rmap_match_set_hook.no_match_interface(
1809 vty, index, "interface", iface,
1810 RMAP_EVENT_MATCH_DELETED);
1811 return CMD_SUCCESS;
82f97584
DW
1812}
1813
1814
1815DEFUN (match_ip_address,
1816 match_ip_address_cmd,
1817 "match ip address <(1-199)|(1300-2699)|WORD>",
1818 MATCH_STR
1819 IP_STR
1820 "Match address of route\n"
1821 "IP access-list number\n"
1822 "IP access-list number (expanded range)\n"
1823 "IP Access-list name\n")
1824{
d62a17ae 1825 int idx_acl = 3;
1826 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 1827
d62a17ae 1828 if (rmap_match_set_hook.match_ip_address)
1829 return rmap_match_set_hook.match_ip_address(
1830 vty, index, "ip address", argv[idx_acl]->arg,
1831 RMAP_EVENT_FILTER_ADDED);
1832 return CMD_SUCCESS;
82f97584
DW
1833}
1834
1835
1836DEFUN (no_match_ip_address,
1837 no_match_ip_address_cmd,
1838 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
1839 NO_STR
1840 MATCH_STR
1841 IP_STR
1842 "Match address of route\n"
1843 "IP access-list number\n"
1844 "IP access-list number (expanded range)\n"
1845 "IP Access-list name\n")
1846{
d62a17ae 1847 int idx_word = 4;
1848 VTY_DECLVAR_CONTEXT(route_map_index, index);
1849
1850 if (rmap_match_set_hook.no_match_ip_address) {
1851 if (argc <= idx_word)
1852 return rmap_match_set_hook.no_match_ip_address(
1853 vty, index, "ip address", NULL,
1854 RMAP_EVENT_FILTER_DELETED);
1855 return rmap_match_set_hook.no_match_ip_address(
1856 vty, index, "ip address", argv[idx_word]->arg,
1857 RMAP_EVENT_FILTER_DELETED);
1858 }
1859 return CMD_SUCCESS;
82f97584
DW
1860}
1861
1862
1863DEFUN (match_ip_address_prefix_list,
1864 match_ip_address_prefix_list_cmd,
1865 "match ip address prefix-list WORD",
1866 MATCH_STR
1867 IP_STR
1868 "Match address of route\n"
1869 "Match entries of prefix-lists\n"
1870 "IP prefix-list name\n")
1871{
d62a17ae 1872 int idx_word = 4;
1873 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 1874
d62a17ae 1875 if (rmap_match_set_hook.match_ip_address_prefix_list)
1876 return rmap_match_set_hook.match_ip_address_prefix_list(
1877 vty, index, "ip address prefix-list",
1878 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
1879 return CMD_SUCCESS;
82f97584
DW
1880}
1881
1882
1883DEFUN (no_match_ip_address_prefix_list,
1884 no_match_ip_address_prefix_list_cmd,
1885 "no match ip address prefix-list [WORD]",
1886 NO_STR
1887 MATCH_STR
1888 IP_STR
1889 "Match address of route\n"
1890 "Match entries of prefix-lists\n"
1891 "IP prefix-list name\n")
1892{
d62a17ae 1893 int idx_word = 5;
1894 VTY_DECLVAR_CONTEXT(route_map_index, index);
1895
1896 if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
1897 if (argc <= idx_word)
1898 return rmap_match_set_hook
1899 .no_match_ip_address_prefix_list(
1900 vty, index, "ip address prefix-list",
1901 NULL, RMAP_EVENT_PLIST_DELETED);
1902 return rmap_match_set_hook.no_match_ip_address_prefix_list(
1903 vty, index, "ip address prefix-list",
1904 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
1905 }
1906 return CMD_SUCCESS;
82f97584
DW
1907}
1908
1909
1910DEFUN (match_ip_next_hop,
1911 match_ip_next_hop_cmd,
1912 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
1913 MATCH_STR
1914 IP_STR
1915 "Match next-hop address of route\n"
1916 "IP access-list number\n"
1917 "IP access-list number (expanded range)\n"
1918 "IP Access-list name\n")
1919{
d62a17ae 1920 int idx_acl = 3;
1921 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 1922
d62a17ae 1923 if (rmap_match_set_hook.match_ip_next_hop)
1924 return rmap_match_set_hook.match_ip_next_hop(
1925 vty, index, "ip next-hop", argv[idx_acl]->arg,
1926 RMAP_EVENT_FILTER_ADDED);
1927 return CMD_SUCCESS;
82f97584
DW
1928}
1929
1930
1931DEFUN (no_match_ip_next_hop,
1932 no_match_ip_next_hop_cmd,
1933 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
1934 NO_STR
1935 MATCH_STR
1936 IP_STR
1937 "Match next-hop address of route\n"
1938 "IP access-list number\n"
1939 "IP access-list number (expanded range)\n"
1940 "IP Access-list name\n")
1941{
d62a17ae 1942 int idx_word = 4;
1943 VTY_DECLVAR_CONTEXT(route_map_index, index);
1944
1945 if (rmap_match_set_hook.no_match_ip_next_hop) {
1946 if (argc <= idx_word)
1947 return rmap_match_set_hook.no_match_ip_next_hop(
1948 vty, index, "ip next-hop", NULL,
1949 RMAP_EVENT_FILTER_DELETED);
1950 return rmap_match_set_hook.no_match_ip_next_hop(
1951 vty, index, "ip next-hop", argv[idx_word]->arg,
1952 RMAP_EVENT_FILTER_DELETED);
1953 }
1954 return CMD_SUCCESS;
82f97584
DW
1955}
1956
1957
1958DEFUN (match_ip_next_hop_prefix_list,
1959 match_ip_next_hop_prefix_list_cmd,
1960 "match ip next-hop prefix-list WORD",
1961 MATCH_STR
1962 IP_STR
1963 "Match next-hop address of route\n"
1964 "Match entries of prefix-lists\n"
1965 "IP prefix-list name\n")
1966{
d62a17ae 1967 int idx_word = 4;
1968 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 1969
d62a17ae 1970 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
1971 return rmap_match_set_hook.match_ip_next_hop_prefix_list(
1972 vty, index, "ip next-hop prefix-list",
1973 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
1974 return CMD_SUCCESS;
82f97584
DW
1975}
1976
1977DEFUN (no_match_ip_next_hop_prefix_list,
1978 no_match_ip_next_hop_prefix_list_cmd,
1979 "no match ip next-hop prefix-list [WORD]",
1980 NO_STR
1981 MATCH_STR
1982 IP_STR
1983 "Match next-hop address of route\n"
1984 "Match entries of prefix-lists\n"
1985 "IP prefix-list name\n")
1986{
d62a17ae 1987 int idx_word = 5;
1988 VTY_DECLVAR_CONTEXT(route_map_index, index);
1989
1990 if (rmap_match_set_hook.no_match_ip_next_hop) {
1991 if (argc <= idx_word)
1992 return rmap_match_set_hook.no_match_ip_next_hop(
1993 vty, index, "ip next-hop prefix-list", NULL,
1994 RMAP_EVENT_PLIST_DELETED);
1995 return rmap_match_set_hook.no_match_ip_next_hop(
1996 vty, index, "ip next-hop prefix-list",
1997 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
1998 }
1999 return CMD_SUCCESS;
82f97584
DW
2000}
2001
2002
2003DEFUN (match_ipv6_address,
2004 match_ipv6_address_cmd,
2005 "match ipv6 address WORD",
2006 MATCH_STR
2007 IPV6_STR
2008 "Match IPv6 address of route\n"
2009 "IPv6 access-list name\n")
2010{
d62a17ae 2011 int idx_word = 3;
2012 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2013
d62a17ae 2014 if (rmap_match_set_hook.match_ipv6_address)
2015 return rmap_match_set_hook.match_ipv6_address(
2016 vty, index, "ipv6 address", argv[idx_word]->arg,
2017 RMAP_EVENT_FILTER_ADDED);
2018 return CMD_SUCCESS;
82f97584
DW
2019}
2020
2021DEFUN (no_match_ipv6_address,
2022 no_match_ipv6_address_cmd,
2023 "no match ipv6 address WORD",
2024 NO_STR
2025 MATCH_STR
2026 IPV6_STR
2027 "Match IPv6 address of route\n"
2028 "IPv6 access-list name\n")
2029{
d62a17ae 2030 int idx_word = 4;
2031 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2032
d62a17ae 2033 if (rmap_match_set_hook.no_match_ipv6_address)
2034 return rmap_match_set_hook.no_match_ipv6_address(
2035 vty, index, "ipv6 address", argv[idx_word]->arg,
2036 RMAP_EVENT_FILTER_DELETED);
2037 return CMD_SUCCESS;
82f97584
DW
2038}
2039
2040
2041DEFUN (match_ipv6_address_prefix_list,
2042 match_ipv6_address_prefix_list_cmd,
2043 "match ipv6 address prefix-list WORD",
2044 MATCH_STR
2045 IPV6_STR
2046 "Match address of route\n"
2047 "Match entries of prefix-lists\n"
2048 "IP prefix-list name\n")
2049{
d62a17ae 2050 int idx_word = 4;
2051 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2052
d62a17ae 2053 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
2054 return rmap_match_set_hook.match_ipv6_address_prefix_list(
2055 vty, index, "ipv6 address prefix-list",
2056 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2057 return CMD_SUCCESS;
82f97584
DW
2058}
2059
2060DEFUN (no_match_ipv6_address_prefix_list,
2061 no_match_ipv6_address_prefix_list_cmd,
2062 "no match ipv6 address prefix-list WORD",
2063 NO_STR
2064 MATCH_STR
2065 IPV6_STR
2066 "Match address of route\n"
2067 "Match entries of prefix-lists\n"
2068 "IP prefix-list name\n")
2069{
d62a17ae 2070 int idx_word = 5;
2071 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2072
d62a17ae 2073 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
2074 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
2075 vty, index, "ipv6 address prefix-list",
2076 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2077 return CMD_SUCCESS;
82f97584
DW
2078}
2079
2080
2081DEFUN (match_metric,
2082 match_metric_cmd,
2083 "match metric (0-4294967295)",
2084 MATCH_STR
2085 "Match metric of route\n"
2086 "Metric value\n")
2087{
d62a17ae 2088 int idx_number = 2;
2089 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2090
d62a17ae 2091 if (rmap_match_set_hook.match_metric)
2092 return rmap_match_set_hook.match_metric(vty, index, "metric",
2093 argv[idx_number]->arg,
2094 RMAP_EVENT_MATCH_ADDED);
2095 return CMD_SUCCESS;
82f97584
DW
2096}
2097
2098
2099DEFUN (no_match_metric,
2100 no_match_metric_cmd,
2101 "no match metric [(0-4294967295)]",
2102 NO_STR
2103 MATCH_STR
2104 "Match metric of route\n"
2105 "Metric value\n")
2106{
d62a17ae 2107 int idx_number = 3;
2108 VTY_DECLVAR_CONTEXT(route_map_index, index);
2109
2110 if (rmap_match_set_hook.no_match_metric) {
2111 if (argc <= idx_number)
2112 return rmap_match_set_hook.no_match_metric(
2113 vty, index, "metric", NULL,
2114 RMAP_EVENT_MATCH_DELETED);
2115 return rmap_match_set_hook.no_match_metric(
2116 vty, index, "metric", argv[idx_number]->arg,
2117 RMAP_EVENT_MATCH_DELETED);
2118 }
2119 return CMD_SUCCESS;
82f97584
DW
2120}
2121
2122
2123DEFUN (match_tag,
2124 match_tag_cmd,
e52702f2 2125 "match tag (1-4294967295)",
82f97584
DW
2126 MATCH_STR
2127 "Match tag of route\n"
2128 "Tag value\n")
2129{
d62a17ae 2130 int idx_number = 2;
2131 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2132
d62a17ae 2133 if (rmap_match_set_hook.match_tag)
2134 return rmap_match_set_hook.match_tag(vty, index, "tag",
2135 argv[idx_number]->arg,
2136 RMAP_EVENT_MATCH_ADDED);
2137 return CMD_SUCCESS;
82f97584
DW
2138}
2139
2140
2141DEFUN (no_match_tag,
2142 no_match_tag_cmd,
e52702f2 2143 "no match tag [(1-4294967295)]",
82f97584
DW
2144 NO_STR
2145 MATCH_STR
2146 "Match tag of route\n"
2147 "Tag value\n")
2148{
d62a17ae 2149 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2150
d62a17ae 2151 int idx = 0;
2152 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2153 ? argv[idx]->arg
2154 : NULL;
0d702986 2155
d62a17ae 2156 if (rmap_match_set_hook.no_match_tag)
2157 return rmap_match_set_hook.no_match_tag(
2158 vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
2159 return CMD_SUCCESS;
82f97584
DW
2160}
2161
2162
2163DEFUN (set_ip_nexthop,
2164 set_ip_nexthop_cmd,
2165 "set ip next-hop A.B.C.D",
2166 SET_STR
2167 IP_STR
2168 "Next hop address\n"
2169 "IP address of next hop\n")
2170{
d62a17ae 2171 int idx_ipv4 = 3;
2172 union sockunion su;
2173 int ret;
2174 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2175
d62a17ae 2176 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
2177 if (ret < 0) {
2178 vty_out(vty, "%% Malformed nexthop address\n");
2179 return CMD_WARNING_CONFIG_FAILED;
2180 }
2181 if (su.sin.sin_addr.s_addr == 0
2182 || IPV4_CLASS_DE(su.sin.sin_addr.s_addr)) {
2183 vty_out(vty,
2184 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2185 return CMD_WARNING_CONFIG_FAILED;
2186 }
82f97584 2187
d62a17ae 2188 if (rmap_match_set_hook.set_ip_nexthop)
2189 return rmap_match_set_hook.set_ip_nexthop(
2190 vty, index, "ip next-hop", argv[idx_ipv4]->arg);
2191 return CMD_SUCCESS;
82f97584
DW
2192}
2193
2194
2195DEFUN (no_set_ip_nexthop,
2196 no_set_ip_nexthop_cmd,
2197 "no set ip next-hop [<peer-address|A.B.C.D>]",
2198 NO_STR
2199 SET_STR
3a2d747c 2200 IP_STR
82f97584
DW
2201 "Next hop address\n"
2202 "Use peer address (for BGP only)\n"
2203 "IP address of next hop\n")
2204{
d62a17ae 2205 int idx_peer = 4;
2206 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2207
d62a17ae 2208 if (rmap_match_set_hook.no_set_ip_nexthop) {
2209 if (argc <= idx_peer)
2210 return rmap_match_set_hook.no_set_ip_nexthop(
2211 vty, index, "ip next-hop", NULL);
2212 return rmap_match_set_hook.no_set_ip_nexthop(
2213 vty, index, "ip next-hop", argv[idx_peer]->arg);
2214 }
2215 return CMD_SUCCESS;
82f97584
DW
2216}
2217
2218
2219DEFUN (set_ipv6_nexthop_local,
2220 set_ipv6_nexthop_local_cmd,
2221 "set ipv6 next-hop local X:X::X:X",
2222 SET_STR
2223 IPV6_STR
2224 "IPv6 next-hop address\n"
2225 "IPv6 local address\n"
2226 "IPv6 address of next hop\n")
2227{
d62a17ae 2228 int idx_ipv6 = 4;
2229 struct in6_addr addr;
2230 int ret;
2231 VTY_DECLVAR_CONTEXT(route_map_index, index);
82f97584 2232
d62a17ae 2233 ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
2234 if (!ret) {
2235 vty_out(vty, "%% Malformed nexthop address\n");
2236 return CMD_WARNING_CONFIG_FAILED;
2237 }
2238 if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
2239 vty_out(vty, "%% Invalid link-local nexthop address\n");
2240 return CMD_WARNING_CONFIG_FAILED;
2241 }
82f97584 2242
d62a17ae 2243 if (rmap_match_set_hook.set_ipv6_nexthop_local)
2244 return rmap_match_set_hook.set_ipv6_nexthop_local(
2245 vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
2246 return CMD_SUCCESS;
82f97584
DW
2247}
2248
2249
2250DEFUN (no_set_ipv6_nexthop_local,
2251 no_set_ipv6_nexthop_local_cmd,
2252 "no set ipv6 next-hop local [X:X::X:X]",
2253 NO_STR
2254 SET_STR
2255 IPV6_STR
2256 "IPv6 next-hop address\n"
2257 "IPv6 local address\n"
2258 "IPv6 address of next hop\n")
2259{
d62a17ae 2260 int idx_ipv6 = 5;
2261 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2262
d62a17ae 2263 if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
2264 if (argc <= idx_ipv6)
2265 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2266 vty, index, "ipv6 next-hop local", NULL);
2267 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2268 vty, index, "ipv6 next-hop local", argv[5]->arg);
2269 }
2270 return CMD_SUCCESS;
82f97584
DW
2271}
2272
2273DEFUN (set_metric,
2274 set_metric_cmd,
2275 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2276 SET_STR
2277 "Metric value for destination routing protocol\n"
2278 "Metric value\n"
2279 "Assign round trip time\n"
2280 "Add round trip time\n"
2281 "Subtract round trip time\n"
2282 "Add metric\n"
2283 "Subtract metric\n")
2284{
d62a17ae 2285 int idx_number = 2;
2286 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2287
d62a17ae 2288 const char *pass = (argv[idx_number]->type == RANGE_TKN)
2289 ? argv[idx_number]->arg
2290 : argv[idx_number]->text;
af3346ec 2291
d62a17ae 2292 if (rmap_match_set_hook.set_metric)
2293 return rmap_match_set_hook.set_metric(vty, index, "metric",
2294 pass);
2295 return CMD_SUCCESS;
82f97584
DW
2296}
2297
2298
2299DEFUN (no_set_metric,
2300 no_set_metric_cmd,
2301 "no set metric [(0-4294967295)]",
2302 NO_STR
2303 SET_STR
2304 "Metric value for destination routing protocol\n"
2305 "Metric value\n")
2306{
d62a17ae 2307 int idx_number = 3;
2308 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2309
d62a17ae 2310 if (rmap_match_set_hook.no_set_metric) {
2311 if (argc <= idx_number)
2312 return rmap_match_set_hook.no_set_metric(
2313 vty, index, "metric", NULL);
2314 return rmap_match_set_hook.no_set_metric(vty, index, "metric",
2315 argv[idx_number]->arg);
2316 }
2317 return CMD_SUCCESS;
82f97584
DW
2318}
2319
2320
2321DEFUN (set_tag,
2322 set_tag_cmd,
e52702f2 2323 "set tag (1-4294967295)",
82f97584
DW
2324 SET_STR
2325 "Tag value for routing protocol\n"
2326 "Tag value\n")
2327{
d62a17ae 2328 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2329
d62a17ae 2330 int idx_number = 2;
2331 if (rmap_match_set_hook.set_tag)
2332 return rmap_match_set_hook.set_tag(vty, index, "tag",
2333 argv[idx_number]->arg);
2334 return CMD_SUCCESS;
82f97584
DW
2335}
2336
2337
2338DEFUN (no_set_tag,
2339 no_set_tag_cmd,
e52702f2 2340 "no set tag [(1-4294967295)]",
82f97584
DW
2341 NO_STR
2342 SET_STR
2343 "Tag value for routing protocol\n"
2344 "Tag value\n")
2345{
d62a17ae 2346 VTY_DECLVAR_CONTEXT(route_map_index, index);
e52702f2 2347
d62a17ae 2348 int idx_number = 3;
2349 if (rmap_match_set_hook.no_set_tag) {
2350 if (argc <= idx_number)
2351 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2352 NULL);
2353 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2354 argv[idx_number]->arg);
2355 }
2356 return CMD_SUCCESS;
82f97584
DW
2357}
2358
2359
505e5056 2360DEFUN_NOSH (route_map,
718e3744 2361 route_map_cmd,
7fcbbdae 2362 "route-map WORD <deny|permit> (1-65535)",
718e3744 2363 "Create route-map or enter route-map command mode\n"
2364 "Route map tag\n"
2365 "Route map denies set operations\n"
2366 "Route map permits set operations\n"
2367 "Sequence to insert to/delete from existing route-map entry\n")
2368{
d62a17ae 2369 int idx_word = 1;
2370 int idx_permit_deny = 2;
2371 int idx_number = 3;
2372 struct route_map *map;
2373 struct route_map_index *index;
2374 char *endptr = NULL;
2375 int permit =
2376 argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2377 unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
2378 const char *mapname = argv[idx_word]->arg;
718e3744 2379
d62a17ae 2380 /* Get route map. */
2381 map = route_map_get(mapname);
2382 index = route_map_index_get(map, permit, pref);
718e3744 2383
d62a17ae 2384 VTY_PUSH_CONTEXT(RMAP_NODE, index);
2385 return CMD_SUCCESS;
718e3744 2386}
2387
2388DEFUN (no_route_map_all,
2389 no_route_map_all_cmd,
2390 "no route-map WORD",
2391 NO_STR
2392 "Create route-map or enter route-map command mode\n"
2393 "Route map tag\n")
2394{
d62a17ae 2395 int idx_word = 2;
2396 const char *mapname = argv[idx_word]->arg;
2397 struct route_map *map;
718e3744 2398
d62a17ae 2399 map = route_map_lookup_by_name(mapname);
2400 if (map == NULL) {
2401 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2402 return CMD_WARNING_CONFIG_FAILED;
2403 }
718e3744 2404
d62a17ae 2405 route_map_delete(map);
718e3744 2406
d62a17ae 2407 return CMD_SUCCESS;
718e3744 2408}
2409
2410DEFUN (no_route_map,
2411 no_route_map_cmd,
7fcbbdae 2412 "no route-map WORD <deny|permit> (1-65535)",
718e3744 2413 NO_STR
2414 "Create route-map or enter route-map command mode\n"
2415 "Route map tag\n"
2416 "Route map denies set operations\n"
2417 "Route map permits set operations\n"
2418 "Sequence to insert to/delete from existing route-map entry\n")
2419{
d62a17ae 2420 int idx_word = 2;
2421 int idx_permit_deny = 3;
2422 int idx_number = 4;
2423 struct route_map *map;
2424 struct route_map_index *index;
2425 char *endptr = NULL;
2426 int permit = strmatch(argv[idx_permit_deny]->text, "permit")
2427 ? RMAP_PERMIT
2428 : RMAP_DENY;
2429 const char *prefstr = argv[idx_number]->arg;
2430 const char *mapname = argv[idx_word]->arg;
2431 unsigned long pref = strtoul(prefstr, &endptr, 10);
2432
2433 /* Existence check. */
2434 map = route_map_lookup_by_name(mapname);
2435 if (map == NULL) {
2436 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2437 return CMD_WARNING_CONFIG_FAILED;
2438 }
2439
2440 /* Lookup route map index. */
2441 index = route_map_index_lookup(map, permit, pref);
2442 if (index == NULL) {
2443 vty_out(vty, "%% Could not find route-map entry %s %s\n",
2444 mapname, prefstr);
2445 return CMD_WARNING_CONFIG_FAILED;
2446 }
2447
2448 /* Delete index from route map. */
2449 route_map_index_delete(index, 1);
2450
2451 /* If this route rule is the last one, delete route map itself. */
2452 if (route_map_empty(map))
2453 route_map_delete(map);
2454
2455 return CMD_SUCCESS;
718e3744 2456}
2457
2458DEFUN (rmap_onmatch_next,
2459 rmap_onmatch_next_cmd,
2460 "on-match next",
2461 "Exit policy on matches\n"
2462 "Next clause\n")
2463{
d62a17ae 2464 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2465
2466 if (index) {
2467 if (index->type == RMAP_DENY) {
2468 /* Under a deny clause, match means it's finished. No
2469 * need to set next */
2470 vty_out(vty,
2471 "on-match next not supported under route-map deny\n");
2472 return CMD_WARNING_CONFIG_FAILED;
2473 }
2474 index->exitpolicy = RMAP_NEXT;
2475 }
2476 return CMD_SUCCESS;
718e3744 2477}
2478
2479DEFUN (no_rmap_onmatch_next,
2480 no_rmap_onmatch_next_cmd,
2481 "no on-match next",
2482 NO_STR
2483 "Exit policy on matches\n"
2484 "Next clause\n")
2485{
d62a17ae 2486 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2487
2488 if (index)
2489 index->exitpolicy = RMAP_EXIT;
718e3744 2490
d62a17ae 2491 return CMD_SUCCESS;
718e3744 2492}
2493
2494DEFUN (rmap_onmatch_goto,
2495 rmap_onmatch_goto_cmd,
7fcbbdae 2496 "on-match goto (1-65535)",
718e3744 2497 "Exit policy on matches\n"
2498 "Goto Clause number\n"
2499 "Number\n")
2500{
d62a17ae 2501 int idx = 0;
2502 char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
2503 : NULL;
2504
2505 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2506 int d = 0;
2507
2508 if (index) {
2509 if (index->type == RMAP_DENY) {
2510 /* Under a deny clause, match means it's finished. No
2511 * need to go anywhere */
2512 vty_out(vty,
2513 "on-match goto not supported under route-map deny\n");
2514 return CMD_WARNING_CONFIG_FAILED;
2515 }
2516
2517 if (num)
2518 d = strtoul(num, NULL, 10);
2519 else
2520 d = index->pref + 1;
2521
2522 if (d <= index->pref) {
2523 /* Can't allow you to do that, Dave */
2524 vty_out(vty, "can't jump backwards in route-maps\n");
2525 return CMD_WARNING_CONFIG_FAILED;
2526 } else {
2527 index->exitpolicy = RMAP_GOTO;
2528 index->nextpref = d;
2529 }
718e3744 2530 }
d62a17ae 2531 return CMD_SUCCESS;
718e3744 2532}
2533
2534DEFUN (no_rmap_onmatch_goto,
2535 no_rmap_onmatch_goto_cmd,
2536 "no on-match goto",
2537 NO_STR
2538 "Exit policy on matches\n"
fee0f4c6 2539 "Goto Clause number\n")
718e3744 2540{
d62a17ae 2541 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
718e3744 2542
d62a17ae 2543 if (index)
2544 index->exitpolicy = RMAP_EXIT;
2545
2546 return CMD_SUCCESS;
718e3744 2547}
2548
f667a580
QY
2549/* Cisco/GNU Zebra compatibility aliases */
2550/* ALIAS_FIXME */
2551DEFUN (rmap_continue,
2552 rmap_continue_cmd,
2553 "continue (1-65535)",
2554 "Continue on a different entry within the route-map\n"
2555 "Route-map entry sequence number\n")
2556{
d62a17ae 2557 return rmap_onmatch_goto(self, vty, argc, argv);
f667a580 2558}
5510e83b 2559
f667a580
QY
2560/* ALIAS_FIXME */
2561DEFUN (no_rmap_continue,
2562 no_rmap_continue_cmd,
2563 "no continue [(1-65535)]",
2564 NO_STR
2565 "Continue on a different entry within the route-map\n"
2566 "Route-map entry sequence number\n")
2567{
d62a17ae 2568 return no_rmap_onmatch_goto(self, vty, argc, argv);
f667a580 2569}
f412b39a 2570
5510e83b 2571
6d2729e3 2572DEFUN (rmap_show_name,
5510e83b 2573 rmap_show_name_cmd,
7514fb77 2574 "show route-map [WORD]",
5510e83b 2575 SHOW_STR
2576 "route-map information\n"
2577 "route-map name\n")
2578{
d62a17ae 2579 int idx_word = 2;
2580 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2581 return vty_show_route_map(vty, name);
5510e83b 2582}
2583
fee0f4c6 2584DEFUN (rmap_call,
2585 rmap_call_cmd,
2586 "call WORD",
2587 "Jump to another Route-Map after match+set\n"
2588 "Target route-map name\n")
2589{
d62a17ae 2590 int idx_word = 1;
2591 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2592 const char *rmap = argv[idx_word]->arg;
fee0f4c6 2593
d62a17ae 2594 assert(index);
c01d03a6 2595
d62a17ae 2596 if (index->nextrm) {
2597 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2598 index->nextrm, index->map->name);
2599 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2600 }
2601 index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
518f0eb1 2602
d62a17ae 2603 /* Execute event hook. */
2604 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
2605 index->map->name);
2606 return CMD_SUCCESS;
fee0f4c6 2607}
2608
2609DEFUN (no_rmap_call,
2610 no_rmap_call_cmd,
2611 "no call",
2612 NO_STR
2613 "Jump to another Route-Map after match+set\n")
2614{
d62a17ae 2615 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
fee0f4c6 2616
d62a17ae 2617 if (index->nextrm) {
2618 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
2619 index->nextrm, index->map->name);
2620 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
2621 index->nextrm = NULL;
2622 }
fee0f4c6 2623
d62a17ae 2624 return CMD_SUCCESS;
fee0f4c6 2625}
2626
4a8164e5 2627DEFUN (rmap_description,
2628 rmap_description_cmd,
7fcbbdae 2629 "description LINE...",
4a8164e5 2630 "Route-map comment\n"
2631 "Comment describing this route-map rule\n")
2632{
d62a17ae 2633 int idx_line = 1;
2634 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
4a8164e5 2635
d62a17ae 2636 if (index) {
2637 if (index->description)
2638 XFREE(MTYPE_TMP, index->description);
2639 index->description = argv_concat(argv, argc, idx_line);
2640 }
2641 return CMD_SUCCESS;
4a8164e5 2642}
2643
2644DEFUN (no_rmap_description,
2645 no_rmap_description_cmd,
2646 "no description",
2647 NO_STR
2648 "Route-map comment\n")
2649{
d62a17ae 2650 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
4a8164e5 2651
d62a17ae 2652 if (index) {
2653 if (index->description)
2654 XFREE(MTYPE_TMP, index->description);
2655 index->description = NULL;
2656 }
2657 return CMD_SUCCESS;
4a8164e5 2658}
2659
718e3744 2660/* Configuration write function. */
d62a17ae 2661static int route_map_config_write(struct vty *vty)
2662{
2663 struct route_map *map;
2664 struct route_map_index *index;
2665 struct route_map_rule *rule;
2666 int first = 1;
2667 int write = 0;
2668
2669 for (map = route_map_master.head; map; map = map->next)
2670 for (index = map->head; index; index = index->next) {
2671 if (!first)
2672 vty_out(vty, "!\n");
2673 else
2674 first = 0;
2675
2676 vty_out(vty, "route-map %s %s %d\n", map->name,
2677 route_map_type_str(index->type), index->pref);
2678
2679 if (index->description)
2680 vty_out(vty, " description %s\n",
2681 index->description);
2682
2683 for (rule = index->match_list.head; rule;
2684 rule = rule->next)
2685 vty_out(vty, " match %s %s\n", rule->cmd->str,
2686 rule->rule_str ? rule->rule_str : "");
2687
2688 for (rule = index->set_list.head; rule;
2689 rule = rule->next)
2690 vty_out(vty, " set %s %s\n", rule->cmd->str,
2691 rule->rule_str ? rule->rule_str : "");
2692 if (index->nextrm)
2693 vty_out(vty, " call %s\n", index->nextrm);
2694 if (index->exitpolicy == RMAP_GOTO)
2695 vty_out(vty, " on-match goto %d\n",
2696 index->nextpref);
2697 if (index->exitpolicy == RMAP_NEXT)
2698 vty_out(vty, " on-match next\n");
2699
2700 write++;
2701 }
2702 return write;
718e3744 2703}
2704
2705/* Route map node structure. */
d62a17ae 2706static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
718e3744 2707
dc9ffce8
CF
2708/* Common route map rules */
2709
d62a17ae 2710void *route_map_rule_tag_compile(const char *arg)
dc9ffce8 2711{
d62a17ae 2712 unsigned long int tmp;
2713 char *endptr;
2714 route_tag_t *tag;
dc9ffce8 2715
d62a17ae 2716 errno = 0;
2717 tmp = strtoul(arg, &endptr, 0);
2718 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
2719 return NULL;
dc9ffce8 2720
d62a17ae 2721 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
2722 *tag = tmp;
dc9ffce8 2723
d62a17ae 2724 return tag;
dc9ffce8
CF
2725}
2726
d62a17ae 2727void route_map_rule_tag_free(void *rule)
dc9ffce8 2728{
d62a17ae 2729 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
dc9ffce8
CF
2730}
2731
d62a17ae 2732void route_map_finish(void)
9df78e7c 2733{
d62a17ae 2734 int i;
9df78e7c 2735
d62a17ae 2736 vector_free(route_match_vec);
2737 route_match_vec = NULL;
2738 vector_free(route_set_vec);
2739 route_set_vec = NULL;
9df78e7c 2740
d62a17ae 2741 /* cleanup route_map */
2742 while (route_map_master.head) {
2743 struct route_map *map = route_map_master.head;
2744 map->to_be_processed = 0;
2745 route_map_delete(map);
2746 }
9df78e7c 2747
d62a17ae 2748 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
2749 hash_free(route_map_dep_hash[i]);
2750 route_map_dep_hash[i] = NULL;
2751 }
9df78e7c 2752
d62a17ae 2753 hash_free(route_map_master_hash);
2754 route_map_master_hash = NULL;
9df78e7c
DS
2755}
2756
70d44c5c
DL
2757static void rmap_autocomplete(vector comps, struct cmd_token *token)
2758{
d62a17ae 2759 struct route_map *map;
70d44c5c 2760
d62a17ae 2761 for (map = route_map_master.head; map; map = map->next)
2762 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
70d44c5c
DL
2763}
2764
2765static const struct cmd_variable_handler rmap_var_handlers[] = {
d62a17ae 2766 {/* "route-map WORD" */
2767 .varname = "route_map",
2768 .completions = rmap_autocomplete},
2769 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
2770 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
2771 {.completions = NULL}};
70d44c5c 2772
718e3744 2773/* Initialization of route map vector. */
d62a17ae 2774void route_map_init(void)
718e3744 2775{
d62a17ae 2776 int i;
2777
2778 /* Make vector for match and set. */
2779 route_match_vec = vector_init(1);
2780 route_set_vec = vector_init(1);
2781 route_map_master_hash =
2782 hash_create(route_map_hash_key_make, route_map_hash_cmp, NULL);
2783
2784 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
2785 route_map_dep_hash[i] =
2786 hash_create(route_map_dep_hash_make_key,
2787 route_map_dep_hash_cmp, NULL);
b2575bc0 2788
d62a17ae 2789 cmd_variable_handler_register(rmap_var_handlers);
b2575bc0 2790
d62a17ae 2791 /* Install route map top node. */
2792 install_node(&rmap_node, route_map_config_write);
518f0eb1 2793
d62a17ae 2794 /* Install route map commands. */
2795 install_default(RMAP_NODE);
2796 install_element(CONFIG_NODE, &route_map_cmd);
2797 install_element(CONFIG_NODE, &no_route_map_cmd);
2798 install_element(CONFIG_NODE, &no_route_map_all_cmd);
70d44c5c 2799
d62a17ae 2800 /* Install the on-match stuff */
2801 install_element(RMAP_NODE, &route_map_cmd);
2802 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
2803 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
2804 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
2805 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
2806 install_element(RMAP_NODE, &rmap_continue_cmd);
2807 install_element(RMAP_NODE, &no_rmap_continue_cmd);
718e3744 2808
d62a17ae 2809 /* Install the continue stuff (ALIAS of on-match). */
718e3744 2810
d62a17ae 2811 /* Install the call stuff. */
2812 install_element(RMAP_NODE, &rmap_call_cmd);
2813 install_element(RMAP_NODE, &no_rmap_call_cmd);
4a8164e5 2814
d62a17ae 2815 /* Install description commands. */
2816 install_element(RMAP_NODE, &rmap_description_cmd);
2817 install_element(RMAP_NODE, &no_rmap_description_cmd);
82f97584 2818
d62a17ae 2819 /* Install show command */
2820 install_element(ENABLE_NODE, &rmap_show_name_cmd);
82f97584 2821
d62a17ae 2822 install_element(RMAP_NODE, &match_interface_cmd);
2823 install_element(RMAP_NODE, &no_match_interface_cmd);
82f97584 2824
d62a17ae 2825 install_element(RMAP_NODE, &match_ip_address_cmd);
2826 install_element(RMAP_NODE, &no_match_ip_address_cmd);
82f97584 2827
d62a17ae 2828 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
2829 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
82f97584 2830
d62a17ae 2831 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
2832 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
82f97584 2833
d62a17ae 2834 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
2835 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
82f97584 2836
d62a17ae 2837 install_element(RMAP_NODE, &match_ipv6_address_cmd);
2838 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
82f97584 2839
d62a17ae 2840 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
2841 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
82f97584 2842
d62a17ae 2843 install_element(RMAP_NODE, &match_metric_cmd);
2844 install_element(RMAP_NODE, &no_match_metric_cmd);
82f97584 2845
d62a17ae 2846 install_element(RMAP_NODE, &match_tag_cmd);
2847 install_element(RMAP_NODE, &no_match_tag_cmd);
82f97584 2848
d62a17ae 2849 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
2850 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
82f97584 2851
d62a17ae 2852 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
2853 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
82f97584 2854
d62a17ae 2855 install_element(RMAP_NODE, &set_metric_cmd);
2856 install_element(RMAP_NODE, &no_set_metric_cmd);
82f97584 2857
d62a17ae 2858 install_element(RMAP_NODE, &set_tag_cmd);
2859 install_element(RMAP_NODE, &no_set_tag_cmd);
718e3744 2860}