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