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