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