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