]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap.c
Merge pull request #4300 from adharkar/frr-master-rmap_debug
[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 bool rmap_debug;
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
743 if (rmap_debug)
744 zlog_debug("Add route-map %s", name);
745 return map;
746 }
747
748 /* this is supposed to be called post processing by
749 * the delete hook function. Don't invoke delete_hook
750 * again in this routine.
751 */
752 static void route_map_free_map(struct route_map *map)
753 {
754 struct route_map_list *list;
755 struct route_map_index *index;
756
757 if (map == NULL)
758 return;
759
760 while ((index = map->head) != NULL)
761 route_map_index_delete(index, 0);
762
763 if (rmap_debug)
764 zlog_debug("Deleting route-map %s", map->name);
765
766 list = &route_map_master;
767
768 QOBJ_UNREG(map);
769
770 if (map->next)
771 map->next->prev = map->prev;
772 else
773 list->tail = map->prev;
774
775 if (map->prev)
776 map->prev->next = map->next;
777 else
778 list->head = map->next;
779
780 hash_release(route_map_master_hash, map);
781 XFREE(MTYPE_ROUTE_MAP_NAME, map->name);
782 XFREE(MTYPE_ROUTE_MAP, map);
783 }
784
785 /* Route map delete from list. */
786 static void route_map_delete(struct route_map *map)
787 {
788 struct route_map_index *index;
789 char *name;
790
791 while ((index = map->head) != NULL)
792 route_map_index_delete(index, 0);
793
794 name = map->name;
795 map->head = NULL;
796
797 /* Clear all dependencies */
798 route_map_clear_all_references(name);
799 map->deleted = true;
800 /* Execute deletion hook. */
801 if (route_map_master.delete_hook) {
802 (*route_map_master.delete_hook)(name);
803 route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
804 }
805
806 if (!map->to_be_processed) {
807 route_map_free_map(map);
808 }
809 }
810
811 /* Lookup route map by route map name string. */
812 struct route_map *route_map_lookup_by_name(const char *name)
813 {
814 struct route_map *map;
815 struct route_map tmp_map;
816
817 if (!name)
818 return NULL;
819
820 // map.deleted is 0 via memset
821 memset(&tmp_map, 0, sizeof(struct route_map));
822 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
823 map = hash_lookup(route_map_master_hash, &tmp_map);
824 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
825 return map;
826 }
827
828 /* Simple helper to warn if route-map does not exist. */
829 struct route_map *route_map_lookup_warn_noexist(struct vty *vty, const char *name)
830 {
831 struct route_map *route_map = route_map_lookup_by_name(name);
832
833 if (!route_map)
834 if (vty_shell_serv(vty))
835 vty_out(vty, "The route-map '%s' does not exist.\n", name);
836
837 return route_map;
838 }
839
840 int route_map_mark_updated(const char *name)
841 {
842 struct route_map *map;
843 int ret = -1;
844 struct route_map tmp_map;
845
846 if (!name)
847 return (ret);
848
849 map = route_map_lookup_by_name(name);
850
851 /* If we did not find the routemap with deleted=false try again
852 * with deleted=true
853 */
854 if (!map) {
855 memset(&tmp_map, 0, sizeof(struct route_map));
856 tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
857 tmp_map.deleted = true;
858 map = hash_lookup(route_map_master_hash, &tmp_map);
859 XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name);
860 }
861
862 if (map) {
863 map->to_be_processed = true;
864 ret = 0;
865 }
866
867 return (ret);
868 }
869
870 static int route_map_clear_updated(struct route_map *map)
871 {
872 int ret = -1;
873
874 if (map) {
875 map->to_be_processed = false;
876 if (map->deleted)
877 route_map_free_map(map);
878 }
879
880 return (ret);
881 }
882
883 /* Lookup route map. If there isn't route map create one and return
884 it. */
885 static struct route_map *route_map_get(const char *name)
886 {
887 struct route_map *map;
888
889 map = route_map_lookup_by_name(name);
890 if (map == NULL)
891 map = route_map_add(name);
892
893 return map;
894 }
895
896 void route_map_walk_update_list(void (*route_map_update_fn)(char *name))
897 {
898 struct route_map *node;
899 struct route_map *nnode = NULL;
900
901 for (node = route_map_master.head; node; node = nnode) {
902 if (node->to_be_processed) {
903 /* DD: Should we add any thread yield code here */
904 route_map_update_fn(node->name);
905 nnode = node->next;
906 route_map_clear_updated(node);
907 } else
908 nnode = node->next;
909 }
910 }
911
912 /* Return route map's type string. */
913 static const char *route_map_type_str(enum route_map_type type)
914 {
915 switch (type) {
916 case RMAP_PERMIT:
917 return "permit";
918 break;
919 case RMAP_DENY:
920 return "deny";
921 break;
922 case RMAP_ANY:
923 return "";
924 break;
925 }
926
927 return "";
928 }
929
930 static const char *route_map_result_str(route_map_result_t res)
931 {
932 switch (res) {
933 case RMAP_MATCH:
934 return "match";
935 case RMAP_DENYMATCH:
936 return "deny";
937 case RMAP_NOMATCH:
938 return "no match";
939 case RMAP_ERROR:
940 return "error";
941 case RMAP_OKAY:
942 return "okay";
943 }
944
945 return "invalid";
946 }
947
948 static int route_map_empty(struct route_map *map)
949 {
950 if (map->head == NULL && map->tail == NULL)
951 return 1;
952 else
953 return 0;
954 }
955
956 /* show route-map */
957 static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
958 {
959 struct route_map_index *index;
960 struct route_map_rule *rule;
961
962 vty_out(vty, "route-map: %s Invoked: %" PRIu64 "\n",
963 map->name, map->applied);
964
965 for (index = map->head; index; index = index->next) {
966 vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
967 route_map_type_str(index->type), index->pref,
968 index->applied);
969
970 /* Description */
971 if (index->description)
972 vty_out(vty, " Description:\n %s\n",
973 index->description);
974
975 /* Match clauses */
976 vty_out(vty, " Match clauses:\n");
977 for (rule = index->match_list.head; rule; rule = rule->next)
978 vty_out(vty, " %s %s\n", rule->cmd->str,
979 rule->rule_str);
980
981 vty_out(vty, " Set clauses:\n");
982 for (rule = index->set_list.head; rule; rule = rule->next)
983 vty_out(vty, " %s %s\n", rule->cmd->str,
984 rule->rule_str);
985
986 /* Call clause */
987 vty_out(vty, " Call clause:\n");
988 if (index->nextrm)
989 vty_out(vty, " Call %s\n", index->nextrm);
990
991 /* Exit Policy */
992 vty_out(vty, " Action:\n");
993 if (index->exitpolicy == RMAP_GOTO)
994 vty_out(vty, " Goto %d\n", index->nextpref);
995 else if (index->exitpolicy == RMAP_NEXT)
996 vty_out(vty, " Continue to next entry\n");
997 else if (index->exitpolicy == RMAP_EXIT)
998 vty_out(vty, " Exit routemap\n");
999 }
1000 }
1001
1002 static int sort_route_map(const void **map1, const void **map2)
1003 {
1004 const struct route_map *m1 = *map1;
1005 const struct route_map *m2 = *map2;
1006
1007 return strcmp(m1->name, m2->name);
1008 }
1009
1010 static int vty_show_route_map(struct vty *vty, const char *name)
1011 {
1012 struct route_map *map;
1013
1014 vty_out(vty, "%s:\n", frr_protonameinst);
1015
1016 if (name) {
1017 map = route_map_lookup_by_name(name);
1018
1019 if (map) {
1020 vty_show_route_map_entry(vty, map);
1021 return CMD_SUCCESS;
1022 } else {
1023 vty_out(vty, "%s: 'route-map %s' not found\n",
1024 frr_protonameinst, name);
1025 return CMD_SUCCESS;
1026 }
1027 } else {
1028
1029 struct list *maplist = list_new();
1030 struct listnode *ln;
1031
1032 for (map = route_map_master.head; map; map = map->next)
1033 listnode_add(maplist, map);
1034
1035 list_sort(maplist, sort_route_map);
1036
1037 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
1038 vty_show_route_map_entry(vty, map);
1039
1040 list_delete(&maplist);
1041 }
1042 return CMD_SUCCESS;
1043 }
1044
1045 /* Unused route map details */
1046 static int vty_show_unused_route_map(struct vty *vty)
1047 {
1048 struct list *maplist = list_new();
1049 struct listnode *ln;
1050 struct route_map *map;
1051
1052 for (map = route_map_master.head; map; map = map->next) {
1053 /* If use_count is zero, No protocol is using this routemap.
1054 * so adding to the list.
1055 */
1056 if (!map->use_count)
1057 listnode_add(maplist, map);
1058 }
1059
1060 if (maplist->count > 0) {
1061 vty_out(vty, "\n%s:\n", frr_protonameinst);
1062 list_sort(maplist, sort_route_map);
1063
1064 for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
1065 vty_show_route_map_entry(vty, map);
1066 } else {
1067 vty_out(vty, "\n%s: None\n", frr_protonameinst);
1068 }
1069
1070 list_delete(&maplist);
1071 return CMD_SUCCESS;
1072 }
1073
1074 /* New route map allocation. Please note route map's name must be
1075 specified. */
1076 static struct route_map_index *route_map_index_new(void)
1077 {
1078 struct route_map_index *new;
1079
1080 new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
1081 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
1082 QOBJ_REG(new, route_map_index);
1083 return new;
1084 }
1085
1086 /* Free route map index. */
1087 static void route_map_index_delete(struct route_map_index *index, int notify)
1088 {
1089 struct route_map_rule *rule;
1090
1091 QOBJ_UNREG(index);
1092
1093 if (rmap_debug)
1094 zlog_debug("Deleting route-map %s sequence %d",
1095 index->map->name, index->pref);
1096
1097 /* Free route match. */
1098 while ((rule = index->match_list.head) != NULL)
1099 route_map_rule_delete(&index->match_list, rule);
1100
1101 /* Free route set. */
1102 while ((rule = index->set_list.head) != NULL)
1103 route_map_rule_delete(&index->set_list, rule);
1104
1105 /* Remove index from route map list. */
1106 if (index->next)
1107 index->next->prev = index->prev;
1108 else
1109 index->map->tail = index->prev;
1110
1111 if (index->prev)
1112 index->prev->next = index->next;
1113 else
1114 index->map->head = index->next;
1115
1116 /* Free 'char *nextrm' if not NULL */
1117 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
1118
1119 /* Execute event hook. */
1120 if (route_map_master.event_hook && notify) {
1121 (*route_map_master.event_hook)(index->map->name);
1122 route_map_notify_dependencies(index->map->name,
1123 RMAP_EVENT_CALL_ADDED);
1124 }
1125 XFREE(MTYPE_ROUTE_MAP_INDEX, index);
1126 }
1127
1128 /* Lookup index from route map. */
1129 static struct route_map_index *route_map_index_lookup(struct route_map *map,
1130 enum route_map_type type,
1131 int pref)
1132 {
1133 struct route_map_index *index;
1134
1135 for (index = map->head; index; index = index->next)
1136 if ((index->type == type || type == RMAP_ANY)
1137 && index->pref == pref)
1138 return index;
1139 return NULL;
1140 }
1141
1142 /* Add new index to route map. */
1143 static struct route_map_index *
1144 route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
1145 {
1146 struct route_map_index *index;
1147 struct route_map_index *point;
1148
1149 /* Allocate new route map inex. */
1150 index = route_map_index_new();
1151 index->map = map;
1152 index->type = type;
1153 index->pref = pref;
1154
1155 /* Compare preference. */
1156 for (point = map->head; point; point = point->next)
1157 if (point->pref >= pref)
1158 break;
1159
1160 if (map->head == NULL) {
1161 map->head = map->tail = index;
1162 } else if (point == NULL) {
1163 index->prev = map->tail;
1164 map->tail->next = index;
1165 map->tail = index;
1166 } else if (point == map->head) {
1167 index->next = map->head;
1168 map->head->prev = index;
1169 map->head = index;
1170 } else {
1171 index->next = point;
1172 index->prev = point->prev;
1173 if (point->prev)
1174 point->prev->next = index;
1175 point->prev = index;
1176 }
1177
1178 /* Execute event hook. */
1179 if (route_map_master.event_hook) {
1180 (*route_map_master.event_hook)(map->name);
1181 route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
1182 }
1183
1184 if (rmap_debug)
1185 zlog_debug("Route-map %s add sequence %d, type: %s",
1186 map->name, pref, route_map_type_str(type));
1187
1188 return index;
1189 }
1190
1191 /* Get route map index. */
1192 static struct route_map_index *
1193 route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
1194 {
1195 struct route_map_index *index;
1196
1197 index = route_map_index_lookup(map, RMAP_ANY, pref);
1198 if (index && index->type != type) {
1199 /* Delete index from route map. */
1200 route_map_index_delete(index, 1);
1201 index = NULL;
1202 }
1203 if (index == NULL)
1204 index = route_map_index_add(map, type, pref);
1205 return index;
1206 }
1207
1208 /* New route map rule */
1209 static struct route_map_rule *route_map_rule_new(void)
1210 {
1211 struct route_map_rule *new;
1212
1213 new = XCALLOC(MTYPE_ROUTE_MAP_RULE, sizeof(struct route_map_rule));
1214 return new;
1215 }
1216
1217 /* Install rule command to the match list. */
1218 void route_map_install_match(struct route_map_rule_cmd *cmd)
1219 {
1220 vector_set(route_match_vec, cmd);
1221 }
1222
1223 /* Install rule command to the set list. */
1224 void route_map_install_set(struct route_map_rule_cmd *cmd)
1225 {
1226 vector_set(route_set_vec, cmd);
1227 }
1228
1229 /* Lookup rule command from match list. */
1230 static struct route_map_rule_cmd *route_map_lookup_match(const char *name)
1231 {
1232 unsigned int i;
1233 struct route_map_rule_cmd *rule;
1234
1235 for (i = 0; i < vector_active(route_match_vec); i++)
1236 if ((rule = vector_slot(route_match_vec, i)) != NULL)
1237 if (strcmp(rule->str, name) == 0)
1238 return rule;
1239 return NULL;
1240 }
1241
1242 /* Lookup rule command from set list. */
1243 static struct route_map_rule_cmd *route_map_lookup_set(const char *name)
1244 {
1245 unsigned int i;
1246 struct route_map_rule_cmd *rule;
1247
1248 for (i = 0; i < vector_active(route_set_vec); i++)
1249 if ((rule = vector_slot(route_set_vec, i)) != NULL)
1250 if (strcmp(rule->str, name) == 0)
1251 return rule;
1252 return NULL;
1253 }
1254
1255 /* Add match and set rule to rule list. */
1256 static void route_map_rule_add(struct route_map_rule_list *list,
1257 struct route_map_rule *rule)
1258 {
1259 rule->next = NULL;
1260 rule->prev = list->tail;
1261 if (list->tail)
1262 list->tail->next = rule;
1263 else
1264 list->head = rule;
1265 list->tail = rule;
1266 }
1267
1268 /* Delete rule from rule list. */
1269 static void route_map_rule_delete(struct route_map_rule_list *list,
1270 struct route_map_rule *rule)
1271 {
1272 if (rule->cmd->func_free)
1273 (*rule->cmd->func_free)(rule->value);
1274
1275 XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
1276
1277 if (rule->next)
1278 rule->next->prev = rule->prev;
1279 else
1280 list->tail = rule->prev;
1281 if (rule->prev)
1282 rule->prev->next = rule->next;
1283 else
1284 list->head = rule->next;
1285
1286 XFREE(MTYPE_ROUTE_MAP_RULE, rule);
1287 }
1288
1289 /* strcmp wrapper function which don't crush even argument is NULL. */
1290 static int rulecmp(const char *dst, const char *src)
1291 {
1292 if (dst == NULL) {
1293 if (src == NULL)
1294 return 0;
1295 else
1296 return 1;
1297 } else {
1298 if (src == NULL)
1299 return 1;
1300 else
1301 return strcmp(dst, src);
1302 }
1303 return 1;
1304 }
1305
1306 /* Use this to return the already specified argument for this match. This is
1307 * useful to get the specified argument with a route map match rule when the
1308 * rule is being deleted and the argument is not provided.
1309 */
1310 const char *route_map_get_match_arg(struct route_map_index *index,
1311 const char *match_name)
1312 {
1313 struct route_map_rule *rule;
1314 struct route_map_rule_cmd *cmd;
1315
1316 /* First lookup rule for add match statement. */
1317 cmd = route_map_lookup_match(match_name);
1318 if (cmd == NULL)
1319 return NULL;
1320
1321 for (rule = index->match_list.head; rule; rule = rule->next)
1322 if (rule->cmd == cmd && rule->rule_str != NULL)
1323 return (rule->rule_str);
1324
1325 return (NULL);
1326 }
1327
1328 static route_map_event_t get_route_map_delete_event(route_map_event_t type)
1329 {
1330 switch (type) {
1331 case RMAP_EVENT_CALL_ADDED:
1332 return RMAP_EVENT_CALL_DELETED;
1333 case RMAP_EVENT_PLIST_ADDED:
1334 return RMAP_EVENT_PLIST_DELETED;
1335 case RMAP_EVENT_CLIST_ADDED:
1336 return RMAP_EVENT_CLIST_DELETED;
1337 case RMAP_EVENT_ECLIST_ADDED:
1338 return RMAP_EVENT_ECLIST_DELETED;
1339 case RMAP_EVENT_LLIST_ADDED:
1340 return RMAP_EVENT_LLIST_DELETED;
1341 case RMAP_EVENT_ASLIST_ADDED:
1342 return RMAP_EVENT_ASLIST_DELETED;
1343 case RMAP_EVENT_FILTER_ADDED:
1344 return RMAP_EVENT_FILTER_DELETED;
1345 case RMAP_EVENT_SET_ADDED:
1346 case RMAP_EVENT_SET_DELETED:
1347 case RMAP_EVENT_SET_REPLACED:
1348 case RMAP_EVENT_MATCH_ADDED:
1349 case RMAP_EVENT_MATCH_DELETED:
1350 case RMAP_EVENT_MATCH_REPLACED:
1351 case RMAP_EVENT_INDEX_ADDED:
1352 case RMAP_EVENT_INDEX_DELETED:
1353 case RMAP_EVENT_CALL_DELETED:
1354 case RMAP_EVENT_PLIST_DELETED:
1355 case RMAP_EVENT_CLIST_DELETED:
1356 case RMAP_EVENT_ECLIST_DELETED:
1357 case RMAP_EVENT_LLIST_DELETED:
1358 case RMAP_EVENT_ASLIST_DELETED:
1359 case RMAP_EVENT_FILTER_DELETED:
1360 /* This function returns the appropriate 'deleted' event type
1361 * for every 'added' event type passed to this function.
1362 * This is done only for named entities used in the
1363 * route-map match commands.
1364 * This function is not to be invoked for any of the other event
1365 * types.
1366 */
1367 assert(0);
1368 }
1369
1370 assert(0);
1371 /*
1372 * Return to make c happy but if we get here something has gone
1373 * terribly terribly wrong, so yes this return makes no sense.
1374 */
1375 return RMAP_EVENT_CALL_ADDED;
1376 }
1377
1378 /* Add match statement to route map. */
1379 int route_map_add_match(struct route_map_index *index, const char *match_name,
1380 const char *match_arg, route_map_event_t type)
1381 {
1382 struct route_map_rule *rule;
1383 struct route_map_rule *next;
1384 struct route_map_rule_cmd *cmd;
1385 void *compile;
1386 int8_t delete_rmap_event_type = 0;
1387
1388 /* First lookup rule for add match statement. */
1389 cmd = route_map_lookup_match(match_name);
1390 if (cmd == NULL)
1391 return RMAP_RULE_MISSING;
1392
1393 /* Next call compile function for this match statement. */
1394 if (cmd->func_compile) {
1395 compile = (*cmd->func_compile)(match_arg);
1396 if (compile == NULL)
1397 return RMAP_COMPILE_ERROR;
1398 } else
1399 compile = NULL;
1400
1401 /* If argument is completely same ignore it. */
1402 for (rule = index->match_list.head; rule; rule = next) {
1403 next = rule->next;
1404 if (rule->cmd == cmd) {
1405 /* If the configured route-map match rule is exactly
1406 * the same as the existing configuration then,
1407 * ignore the duplicate configuration.
1408 */
1409 if (strcmp(match_arg, rule->rule_str) == 0) {
1410 if (cmd->func_free)
1411 (*cmd->func_free)(compile);
1412
1413 return RMAP_DUPLICATE_RULE;
1414 }
1415
1416 /* Remove the dependency of the route-map on the rule
1417 * that is being replaced.
1418 */
1419 if (type >= RMAP_EVENT_CALL_ADDED) {
1420 delete_rmap_event_type =
1421 get_route_map_delete_event(type);
1422 route_map_upd8_dependency(
1423 delete_rmap_event_type,
1424 rule->rule_str,
1425 index->map->name);
1426 }
1427
1428 route_map_rule_delete(&index->match_list, rule);
1429 }
1430 }
1431
1432 /* Add new route map match rule. */
1433 rule = route_map_rule_new();
1434 rule->cmd = cmd;
1435 rule->value = compile;
1436 if (match_arg)
1437 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, match_arg);
1438 else
1439 rule->rule_str = NULL;
1440
1441 /* Add new route match rule to linked list. */
1442 route_map_rule_add(&index->match_list, rule);
1443
1444 /* Execute event hook. */
1445 if (route_map_master.event_hook) {
1446 (*route_map_master.event_hook)(index->map->name);
1447 route_map_notify_dependencies(index->map->name,
1448 RMAP_EVENT_CALL_ADDED);
1449 }
1450
1451 return RMAP_COMPILE_SUCCESS;
1452 }
1453
1454 /* Delete specified route match rule. */
1455 int route_map_delete_match(struct route_map_index *index,
1456 const char *match_name, const char *match_arg)
1457 {
1458 struct route_map_rule *rule;
1459 struct route_map_rule_cmd *cmd;
1460
1461 cmd = route_map_lookup_match(match_name);
1462 if (cmd == NULL)
1463 return 1;
1464
1465 for (rule = index->match_list.head; rule; rule = rule->next)
1466 if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
1467 || match_arg == NULL)) {
1468 route_map_rule_delete(&index->match_list, rule);
1469 /* Execute event hook. */
1470 if (route_map_master.event_hook) {
1471 (*route_map_master.event_hook)(index->map->name);
1472 route_map_notify_dependencies(
1473 index->map->name,
1474 RMAP_EVENT_CALL_ADDED);
1475 }
1476 return 0;
1477 }
1478 /* Can't find matched rule. */
1479 return 1;
1480 }
1481
1482 /* Add route-map set statement to the route map. */
1483 int route_map_add_set(struct route_map_index *index, const char *set_name,
1484 const char *set_arg)
1485 {
1486 struct route_map_rule *rule;
1487 struct route_map_rule *next;
1488 struct route_map_rule_cmd *cmd;
1489 void *compile;
1490
1491 cmd = route_map_lookup_set(set_name);
1492 if (cmd == NULL)
1493 return RMAP_RULE_MISSING;
1494
1495 /* Next call compile function for this match statement. */
1496 if (cmd->func_compile) {
1497 compile = (*cmd->func_compile)(set_arg);
1498 if (compile == NULL)
1499 return RMAP_COMPILE_ERROR;
1500 } else
1501 compile = NULL;
1502
1503 /* Add by WJL. if old set command of same kind exist, delete it first
1504 to ensure only one set command of same kind exist under a
1505 route_map_index. */
1506 for (rule = index->set_list.head; rule; rule = next) {
1507 next = rule->next;
1508 if (rule->cmd == cmd)
1509 route_map_rule_delete(&index->set_list, rule);
1510 }
1511
1512 /* Add new route map match rule. */
1513 rule = route_map_rule_new();
1514 rule->cmd = cmd;
1515 rule->value = compile;
1516 if (set_arg)
1517 rule->rule_str = XSTRDUP(MTYPE_ROUTE_MAP_RULE_STR, set_arg);
1518 else
1519 rule->rule_str = NULL;
1520
1521 /* Add new route match rule to linked list. */
1522 route_map_rule_add(&index->set_list, rule);
1523
1524 /* Execute event hook. */
1525 if (route_map_master.event_hook) {
1526 (*route_map_master.event_hook)(index->map->name);
1527 route_map_notify_dependencies(index->map->name,
1528 RMAP_EVENT_CALL_ADDED);
1529 }
1530 return RMAP_COMPILE_SUCCESS;
1531 }
1532
1533 /* Delete route map set rule. */
1534 int route_map_delete_set(struct route_map_index *index, const char *set_name,
1535 const char *set_arg)
1536 {
1537 struct route_map_rule *rule;
1538 struct route_map_rule_cmd *cmd;
1539
1540 cmd = route_map_lookup_set(set_name);
1541 if (cmd == NULL)
1542 return 1;
1543
1544 for (rule = index->set_list.head; rule; rule = rule->next)
1545 if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
1546 || set_arg == NULL)) {
1547 route_map_rule_delete(&index->set_list, rule);
1548 /* Execute event hook. */
1549 if (route_map_master.event_hook) {
1550 (*route_map_master.event_hook)(index->map->name);
1551 route_map_notify_dependencies(
1552 index->map->name,
1553 RMAP_EVENT_CALL_ADDED);
1554 }
1555 return 0;
1556 }
1557 /* Can't find matched rule. */
1558 return 1;
1559 }
1560
1561 /* Apply route map's each index to the object.
1562
1563 The matrix for a route-map looks like this:
1564 (note, this includes the description for the "NEXT"
1565 and "GOTO" frobs now
1566
1567 Match | No Match
1568 |
1569 permit action | cont
1570 |
1571 ------------------+---------------
1572 |
1573 deny deny | cont
1574 |
1575
1576 action)
1577 -Apply Set statements, accept route
1578 -If Call statement is present jump to the specified route-map, if it
1579 denies the route we finish.
1580 -If NEXT is specified, goto NEXT statement
1581 -If GOTO is specified, goto the first clause where pref > nextpref
1582 -If nothing is specified, do as Cisco and finish
1583 deny)
1584 -Route is denied by route-map.
1585 cont)
1586 -Goto Next index
1587
1588 If we get no matches after we've processed all updates, then the route
1589 is dropped too.
1590
1591 Some notes on the new "CALL", "NEXT" and "GOTO"
1592 call WORD - If this clause is matched, then the set statements
1593 are executed and then we jump to route-map 'WORD'. If
1594 this route-map denies the route, we finish, in other
1595 case we
1596 do whatever the exit policy (EXIT, NEXT or GOTO) tells.
1597 on-match next - If this clause is matched, then the set statements
1598 are executed and then we drop through to the next clause
1599 on-match goto n - If this clause is matched, then the set statments
1600 are executed and then we goto the nth clause, or the
1601 first clause greater than this. In order to ensure
1602 route-maps *always* exit, you cannot jump backwards.
1603 Sorry ;)
1604
1605 We need to make sure our route-map processing matches the above
1606 */
1607
1608 static route_map_result_t
1609 route_map_apply_match(struct route_map_rule_list *match_list,
1610 const struct prefix *prefix, route_map_object_t type,
1611 void *object)
1612 {
1613 route_map_result_t ret = RMAP_NOMATCH;
1614 struct route_map_rule *match;
1615
1616
1617 /* Check all match rule and if there is no match rule, go to the
1618 set statement. */
1619 if (!match_list->head)
1620 ret = RMAP_MATCH;
1621 else {
1622 for (match = match_list->head; match; match = match->next) {
1623 /* Try each match statement in turn, If any do not
1624 return
1625 RMAP_MATCH, return, otherwise continue on to next
1626 match
1627 statement. All match statements must match for
1628 end-result
1629 to be a match. */
1630 ret = (*match->cmd->func_apply)(match->value, prefix,
1631 type, object);
1632 if (ret != RMAP_MATCH)
1633 return ret;
1634 }
1635 }
1636 return ret;
1637 }
1638
1639 /* Apply route map to the object. */
1640 route_map_result_t route_map_apply(struct route_map *map,
1641 const struct prefix *prefix,
1642 route_map_object_t type, void *object)
1643 {
1644 static int recursion = 0;
1645 int ret = 0;
1646 struct route_map_index *index;
1647 struct route_map_rule *set;
1648 char buf[PREFIX_STRLEN];
1649
1650 if (recursion > RMAP_RECURSION_LIMIT) {
1651 flog_warn(
1652 EC_LIB_RMAP_RECURSION_LIMIT,
1653 "route-map recursion limit (%d) reached, discarding route",
1654 RMAP_RECURSION_LIMIT);
1655 recursion = 0;
1656 return RMAP_DENYMATCH;
1657 }
1658
1659 if (map == NULL) {
1660 ret = RMAP_DENYMATCH;
1661 goto route_map_apply_end;
1662 }
1663
1664 map->applied++;
1665 for (index = map->head; index; index = index->next) {
1666 /* Apply this index. */
1667 index->applied++;
1668 ret = route_map_apply_match(&index->match_list, prefix, type,
1669 object);
1670
1671 if (rmap_debug) {
1672 zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
1673 map->name, index->pref,
1674 prefix2str(prefix, buf, sizeof(buf)),
1675 route_map_result_str(ret));
1676 }
1677
1678 /* Now we apply the matrix from above */
1679 if (ret == RMAP_NOMATCH)
1680 /* 'cont' from matrix - continue to next route-map
1681 * sequence */
1682 continue;
1683 else if (ret == RMAP_MATCH) {
1684 if (index->type == RMAP_PERMIT)
1685 /* 'action' */
1686 {
1687 /* permit+match must execute sets */
1688 for (set = index->set_list.head; set;
1689 set = set->next)
1690 ret = (*set->cmd->func_apply)(
1691 set->value, prefix, type,
1692 object);
1693
1694 /* Call another route-map if available */
1695 if (index->nextrm) {
1696 struct route_map *nextrm =
1697 route_map_lookup_by_name(
1698 index->nextrm);
1699
1700 if (nextrm) /* Target route-map found,
1701 jump to it */
1702 {
1703 recursion++;
1704 ret = route_map_apply(
1705 nextrm, prefix, type,
1706 object);
1707 recursion--;
1708 }
1709
1710 /* If nextrm returned 'deny', finish. */
1711 if (ret == RMAP_DENYMATCH)
1712 goto route_map_apply_end;
1713 }
1714
1715 switch (index->exitpolicy) {
1716 case RMAP_EXIT:
1717 goto route_map_apply_end;
1718 case RMAP_NEXT:
1719 continue;
1720 case RMAP_GOTO: {
1721 /* Find the next clause to jump to */
1722 struct route_map_index *next =
1723 index->next;
1724 int nextpref = index->nextpref;
1725
1726 while (next && next->pref < nextpref) {
1727 index = next;
1728 next = next->next;
1729 }
1730 if (next == NULL) {
1731 /* No clauses match! */
1732 goto route_map_apply_end;
1733 }
1734 }
1735 }
1736 } else if (index->type == RMAP_DENY)
1737 /* 'deny' */
1738 {
1739 ret = RMAP_DENYMATCH;
1740 goto route_map_apply_end;
1741 }
1742 }
1743 }
1744 /* Finally route-map does not match at all. */
1745 ret = RMAP_DENYMATCH;
1746
1747 route_map_apply_end:
1748 if (rmap_debug) {
1749 zlog_debug("Route-map: %s, prefix: %s, result: %s",
1750 (map ? map->name : "null"),
1751 prefix2str(prefix, buf, sizeof(buf)),
1752 route_map_result_str(ret));
1753 }
1754
1755 return (ret);
1756 }
1757
1758 void route_map_add_hook(void (*func)(const char *))
1759 {
1760 route_map_master.add_hook = func;
1761 }
1762
1763 void route_map_delete_hook(void (*func)(const char *))
1764 {
1765 route_map_master.delete_hook = func;
1766 }
1767
1768 void route_map_event_hook(void (*func)(const char *name))
1769 {
1770 route_map_master.event_hook = func;
1771 }
1772
1773 /* Routines for route map dependency lists and dependency processing */
1774 static bool route_map_rmap_hash_cmp(const void *p1, const void *p2)
1775 {
1776 return strcmp(((const struct route_map_dep_data *)p1)->rname,
1777 ((const struct route_map_dep_data *)p2)->rname)
1778 == 0;
1779 }
1780
1781 static bool route_map_dep_hash_cmp(const void *p1, const void *p2)
1782 {
1783
1784 return (strcmp(((const struct route_map_dep *)p1)->dep_name,
1785 (const char *)p2)
1786 == 0);
1787 }
1788
1789 static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
1790 {
1791 struct route_map_dep *dep = bucket->data;
1792 struct route_map_dep_data *dep_data = NULL, tmp_dep_data;
1793
1794 if (arg) {
1795 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1796 tmp_dep_data.rname = arg;
1797 dep_data = hash_release(dep->dep_rmap_hash,
1798 &tmp_dep_data);
1799 if (dep_data) {
1800 XFREE(MTYPE_ROUTE_MAP_NAME, dep_data->rname);
1801 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, dep_data);
1802 }
1803 if (!dep->dep_rmap_hash->count) {
1804 dep = hash_release(dep->this_hash,
1805 (void *)dep->dep_name);
1806 hash_free(dep->dep_rmap_hash);
1807 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1808 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1809 }
1810 }
1811 }
1812
1813 static void route_map_clear_all_references(char *rmap_name)
1814 {
1815 int i;
1816
1817 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
1818 hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
1819 (void *)rmap_name);
1820 }
1821 }
1822
1823 static unsigned int route_map_dep_data_hash_make_key(const void *p)
1824 {
1825 const struct route_map_dep_data *dep_data = p;
1826
1827 return string_hash_make(dep_data->rname);
1828 }
1829
1830 static void *route_map_dep_hash_alloc(void *p)
1831 {
1832 char *dep_name = (char *)p;
1833 struct route_map_dep *dep_entry;
1834
1835 dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
1836 dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1837 dep_entry->dep_rmap_hash =
1838 hash_create_size(8, route_map_dep_data_hash_make_key,
1839 route_map_rmap_hash_cmp, "Route Map Dep Hash");
1840 dep_entry->this_hash = NULL;
1841
1842 return dep_entry;
1843 }
1844
1845 static void *route_map_name_hash_alloc(void *p)
1846 {
1847 struct route_map_dep_data *dep_data = NULL, *tmp_dep_data = NULL;
1848
1849 dep_data = XCALLOC(MTYPE_ROUTE_MAP_DEP_DATA,
1850 sizeof(struct route_map_dep_data));
1851 tmp_dep_data = p;
1852 dep_data->rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, tmp_dep_data->rname);
1853 return dep_data;
1854 }
1855
1856 static unsigned int route_map_dep_hash_make_key(const void *p)
1857 {
1858 return (string_hash_make((char *)p));
1859 }
1860
1861 static void route_map_print_dependency(struct hash_bucket *bucket, void *data)
1862 {
1863 struct route_map_dep_data *dep_data = bucket->data;
1864 char *rmap_name = dep_data->rname;
1865 char *dep_name = data;
1866
1867 zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name,
1868 rmap_name);
1869 }
1870
1871 static int route_map_dep_update(struct hash *dephash, const char *dep_name,
1872 const char *rmap_name, route_map_event_t type)
1873 {
1874 struct route_map_dep *dep = NULL;
1875 char *dname, *rname;
1876 int ret = 0;
1877 struct route_map_dep_data *dep_data = NULL, *ret_dep_data = NULL;
1878 struct route_map_dep_data tmp_dep_data;
1879
1880 dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
1881 rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
1882
1883 switch (type) {
1884 case RMAP_EVENT_PLIST_ADDED:
1885 case RMAP_EVENT_CLIST_ADDED:
1886 case RMAP_EVENT_ECLIST_ADDED:
1887 case RMAP_EVENT_ASLIST_ADDED:
1888 case RMAP_EVENT_LLIST_ADDED:
1889 case RMAP_EVENT_CALL_ADDED:
1890 case RMAP_EVENT_FILTER_ADDED:
1891 if (rmap_debug)
1892 zlog_debug("Adding dependency for filter %s in route-map %s",
1893 dep_name, rmap_name);
1894 dep = (struct route_map_dep *)hash_get(
1895 dephash, dname, route_map_dep_hash_alloc);
1896 if (!dep) {
1897 ret = -1;
1898 goto out;
1899 }
1900
1901 if (!dep->this_hash)
1902 dep->this_hash = dephash;
1903
1904 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1905 tmp_dep_data.rname = rname;
1906 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
1907 if (!dep_data)
1908 dep_data = hash_get(dep->dep_rmap_hash, &tmp_dep_data,
1909 route_map_name_hash_alloc);
1910
1911 dep_data->refcnt++;
1912 break;
1913 case RMAP_EVENT_PLIST_DELETED:
1914 case RMAP_EVENT_CLIST_DELETED:
1915 case RMAP_EVENT_ECLIST_DELETED:
1916 case RMAP_EVENT_ASLIST_DELETED:
1917 case RMAP_EVENT_LLIST_DELETED:
1918 case RMAP_EVENT_CALL_DELETED:
1919 case RMAP_EVENT_FILTER_DELETED:
1920 if (rmap_debug)
1921 zlog_debug("Deleting dependency for filter %s in route-map %s",
1922 dep_name, rmap_name);
1923 dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
1924 if (!dep) {
1925 goto out;
1926 }
1927
1928 memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
1929 tmp_dep_data.rname = rname;
1930 dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
1931 dep_data->refcnt--;
1932
1933 if (!dep_data->refcnt) {
1934 ret_dep_data = hash_release(dep->dep_rmap_hash,
1935 &tmp_dep_data);
1936 if (ret_dep_data) {
1937 XFREE(MTYPE_ROUTE_MAP_NAME,
1938 ret_dep_data->rname);
1939 XFREE(MTYPE_ROUTE_MAP_DEP_DATA, ret_dep_data);
1940 }
1941 }
1942
1943 if (!dep->dep_rmap_hash->count) {
1944 dep = hash_release(dephash, dname);
1945 hash_free(dep->dep_rmap_hash);
1946 XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
1947 XFREE(MTYPE_ROUTE_MAP_DEP, dep);
1948 dep = NULL;
1949 }
1950 break;
1951 case RMAP_EVENT_SET_ADDED:
1952 case RMAP_EVENT_SET_DELETED:
1953 case RMAP_EVENT_SET_REPLACED:
1954 case RMAP_EVENT_MATCH_ADDED:
1955 case RMAP_EVENT_MATCH_DELETED:
1956 case RMAP_EVENT_MATCH_REPLACED:
1957 case RMAP_EVENT_INDEX_ADDED:
1958 case RMAP_EVENT_INDEX_DELETED:
1959 break;
1960 }
1961
1962 if (dep) {
1963 if (rmap_debug)
1964 hash_iterate(dep->dep_rmap_hash,
1965 route_map_print_dependency, dname);
1966 }
1967
1968 out:
1969 XFREE(MTYPE_ROUTE_MAP_NAME, rname);
1970 XFREE(MTYPE_ROUTE_MAP_NAME, dname);
1971 return ret;
1972 }
1973
1974 static struct hash *route_map_get_dep_hash(route_map_event_t event)
1975 {
1976 struct hash *upd8_hash = NULL;
1977
1978 switch (event) {
1979 case RMAP_EVENT_PLIST_ADDED:
1980 case RMAP_EVENT_PLIST_DELETED:
1981 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
1982 break;
1983 case RMAP_EVENT_CLIST_ADDED:
1984 case RMAP_EVENT_CLIST_DELETED:
1985 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
1986 break;
1987 case RMAP_EVENT_ECLIST_ADDED:
1988 case RMAP_EVENT_ECLIST_DELETED:
1989 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
1990 break;
1991 case RMAP_EVENT_ASLIST_ADDED:
1992 case RMAP_EVENT_ASLIST_DELETED:
1993 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
1994 break;
1995 case RMAP_EVENT_LLIST_ADDED:
1996 case RMAP_EVENT_LLIST_DELETED:
1997 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
1998 break;
1999 case RMAP_EVENT_CALL_ADDED:
2000 case RMAP_EVENT_CALL_DELETED:
2001 case RMAP_EVENT_MATCH_ADDED:
2002 case RMAP_EVENT_MATCH_DELETED:
2003 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
2004 break;
2005 case RMAP_EVENT_FILTER_ADDED:
2006 case RMAP_EVENT_FILTER_DELETED:
2007 upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
2008 break;
2009 /*
2010 * Should we actually be ignoring these?
2011 * I am not sure but at this point in time, let
2012 * us get them into this switch and we can peel
2013 * them into the appropriate place in the future
2014 */
2015 case RMAP_EVENT_SET_ADDED:
2016 case RMAP_EVENT_SET_DELETED:
2017 case RMAP_EVENT_SET_REPLACED:
2018 case RMAP_EVENT_MATCH_REPLACED:
2019 case RMAP_EVENT_INDEX_ADDED:
2020 case RMAP_EVENT_INDEX_DELETED:
2021 upd8_hash = NULL;
2022 break;
2023 }
2024 return (upd8_hash);
2025 }
2026
2027 static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
2028 {
2029 struct route_map_dep_data *dep_data = NULL;
2030 char *rmap_name = NULL;
2031
2032 dep_data = bucket->data;
2033 rmap_name = dep_data->rname;
2034
2035 if (rmap_debug)
2036 zlog_debug("Notifying %s of dependency", rmap_name);
2037 if (route_map_master.event_hook)
2038 (*route_map_master.event_hook)(rmap_name);
2039 }
2040
2041 void route_map_upd8_dependency(route_map_event_t type, const char *arg,
2042 const char *rmap_name)
2043 {
2044 struct hash *upd8_hash = NULL;
2045
2046 if ((upd8_hash = route_map_get_dep_hash(type))) {
2047 route_map_dep_update(upd8_hash, arg, rmap_name, type);
2048
2049 if (type == RMAP_EVENT_CALL_ADDED) {
2050 /* Execute hook. */
2051 if (route_map_master.add_hook)
2052 (*route_map_master.add_hook)(rmap_name);
2053 } else if (type == RMAP_EVENT_CALL_DELETED) {
2054 /* Execute hook. */
2055 if (route_map_master.delete_hook)
2056 (*route_map_master.delete_hook)(rmap_name);
2057 }
2058 }
2059 }
2060
2061 void route_map_notify_dependencies(const char *affected_name,
2062 route_map_event_t event)
2063 {
2064 struct route_map_dep *dep;
2065 struct hash *upd8_hash;
2066 char *name;
2067
2068 if (!affected_name)
2069 return;
2070
2071 name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, affected_name);
2072
2073 if ((upd8_hash = route_map_get_dep_hash(event)) == NULL) {
2074 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2075 return;
2076 }
2077
2078 dep = (struct route_map_dep *)hash_get(upd8_hash, name, NULL);
2079 if (dep) {
2080 if (!dep->this_hash)
2081 dep->this_hash = upd8_hash;
2082
2083 if (rmap_debug)
2084 zlog_debug("Filter %s updated", dep->dep_name);
2085 hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
2086 (void *)event);
2087 }
2088
2089 XFREE(MTYPE_ROUTE_MAP_NAME, name);
2090 }
2091
2092
2093 /* VTY related functions. */
2094 DEFUN (match_interface,
2095 match_interface_cmd,
2096 "match interface WORD",
2097 MATCH_STR
2098 "match first hop interface of route\n"
2099 "Interface name\n")
2100 {
2101 int idx_word = 2;
2102 VTY_DECLVAR_CONTEXT(route_map_index, index);
2103
2104 if (rmap_match_set_hook.match_interface)
2105 return rmap_match_set_hook.match_interface(
2106 vty, index, "interface", argv[idx_word]->arg,
2107 RMAP_EVENT_MATCH_ADDED);
2108 return CMD_SUCCESS;
2109 }
2110
2111 DEFUN (no_match_interface,
2112 no_match_interface_cmd,
2113 "no match interface [WORD]",
2114 NO_STR
2115 MATCH_STR
2116 "Match first hop interface of route\n"
2117 "Interface name\n")
2118 {
2119 char *iface = (argc == 4) ? argv[3]->arg : NULL;
2120 VTY_DECLVAR_CONTEXT(route_map_index, index);
2121
2122 if (rmap_match_set_hook.no_match_interface)
2123 return rmap_match_set_hook.no_match_interface(
2124 vty, index, "interface", iface,
2125 RMAP_EVENT_MATCH_DELETED);
2126 return CMD_SUCCESS;
2127 }
2128
2129
2130 DEFUN (match_ip_address,
2131 match_ip_address_cmd,
2132 "match ip address <(1-199)|(1300-2699)|WORD>",
2133 MATCH_STR
2134 IP_STR
2135 "Match address of route\n"
2136 "IP access-list number\n"
2137 "IP access-list number (expanded range)\n"
2138 "IP Access-list name\n")
2139 {
2140 int idx_acl = 3;
2141 VTY_DECLVAR_CONTEXT(route_map_index, index);
2142
2143 if (rmap_match_set_hook.match_ip_address)
2144 return rmap_match_set_hook.match_ip_address(
2145 vty, index, "ip address", argv[idx_acl]->arg,
2146 RMAP_EVENT_FILTER_ADDED);
2147 return CMD_SUCCESS;
2148 }
2149
2150
2151 DEFUN (no_match_ip_address,
2152 no_match_ip_address_cmd,
2153 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
2154 NO_STR
2155 MATCH_STR
2156 IP_STR
2157 "Match address of route\n"
2158 "IP access-list number\n"
2159 "IP access-list number (expanded range)\n"
2160 "IP Access-list name\n")
2161 {
2162 int idx_word = 4;
2163 VTY_DECLVAR_CONTEXT(route_map_index, index);
2164
2165 if (rmap_match_set_hook.no_match_ip_address) {
2166 if (argc <= idx_word)
2167 return rmap_match_set_hook.no_match_ip_address(
2168 vty, index, "ip address", NULL,
2169 RMAP_EVENT_FILTER_DELETED);
2170 return rmap_match_set_hook.no_match_ip_address(
2171 vty, index, "ip address", argv[idx_word]->arg,
2172 RMAP_EVENT_FILTER_DELETED);
2173 }
2174 return CMD_SUCCESS;
2175 }
2176
2177
2178 DEFUN (match_ip_address_prefix_list,
2179 match_ip_address_prefix_list_cmd,
2180 "match ip address prefix-list WORD",
2181 MATCH_STR
2182 IP_STR
2183 "Match address of route\n"
2184 "Match entries of prefix-lists\n"
2185 "IP prefix-list name\n")
2186 {
2187 int idx_word = 4;
2188 VTY_DECLVAR_CONTEXT(route_map_index, index);
2189
2190 if (rmap_match_set_hook.match_ip_address_prefix_list)
2191 return rmap_match_set_hook.match_ip_address_prefix_list(
2192 vty, index, "ip address prefix-list",
2193 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2194 return CMD_SUCCESS;
2195 }
2196
2197
2198 DEFUN (no_match_ip_address_prefix_list,
2199 no_match_ip_address_prefix_list_cmd,
2200 "no match ip address prefix-list [WORD]",
2201 NO_STR
2202 MATCH_STR
2203 IP_STR
2204 "Match address of route\n"
2205 "Match entries of prefix-lists\n"
2206 "IP prefix-list name\n")
2207 {
2208 int idx_word = 5;
2209 VTY_DECLVAR_CONTEXT(route_map_index, index);
2210
2211 if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
2212 if (argc <= idx_word)
2213 return rmap_match_set_hook
2214 .no_match_ip_address_prefix_list(
2215 vty, index, "ip address prefix-list",
2216 NULL, RMAP_EVENT_PLIST_DELETED);
2217 return rmap_match_set_hook.no_match_ip_address_prefix_list(
2218 vty, index, "ip address prefix-list",
2219 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2220 }
2221 return CMD_SUCCESS;
2222 }
2223
2224
2225 DEFUN (match_ip_next_hop,
2226 match_ip_next_hop_cmd,
2227 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
2228 MATCH_STR
2229 IP_STR
2230 "Match next-hop address of route\n"
2231 "IP access-list number\n"
2232 "IP access-list number (expanded range)\n"
2233 "IP Access-list name\n")
2234 {
2235 int idx_acl = 3;
2236 VTY_DECLVAR_CONTEXT(route_map_index, index);
2237
2238 if (rmap_match_set_hook.match_ip_next_hop)
2239 return rmap_match_set_hook.match_ip_next_hop(
2240 vty, index, "ip next-hop", argv[idx_acl]->arg,
2241 RMAP_EVENT_FILTER_ADDED);
2242 return CMD_SUCCESS;
2243 }
2244
2245
2246 DEFUN (no_match_ip_next_hop,
2247 no_match_ip_next_hop_cmd,
2248 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
2249 NO_STR
2250 MATCH_STR
2251 IP_STR
2252 "Match next-hop address of route\n"
2253 "IP access-list number\n"
2254 "IP access-list number (expanded range)\n"
2255 "IP Access-list name\n")
2256 {
2257 int idx_word = 4;
2258 VTY_DECLVAR_CONTEXT(route_map_index, index);
2259
2260 if (rmap_match_set_hook.no_match_ip_next_hop) {
2261 if (argc <= idx_word)
2262 return rmap_match_set_hook.no_match_ip_next_hop(
2263 vty, index, "ip next-hop", NULL,
2264 RMAP_EVENT_FILTER_DELETED);
2265 return rmap_match_set_hook.no_match_ip_next_hop(
2266 vty, index, "ip next-hop", argv[idx_word]->arg,
2267 RMAP_EVENT_FILTER_DELETED);
2268 }
2269 return CMD_SUCCESS;
2270 }
2271
2272
2273 DEFUN (match_ip_next_hop_prefix_list,
2274 match_ip_next_hop_prefix_list_cmd,
2275 "match ip next-hop prefix-list WORD",
2276 MATCH_STR
2277 IP_STR
2278 "Match next-hop address of route\n"
2279 "Match entries of prefix-lists\n"
2280 "IP prefix-list name\n")
2281 {
2282 int idx_word = 4;
2283 VTY_DECLVAR_CONTEXT(route_map_index, index);
2284
2285 if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
2286 return rmap_match_set_hook.match_ip_next_hop_prefix_list(
2287 vty, index, "ip next-hop prefix-list",
2288 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2289 return CMD_SUCCESS;
2290 }
2291
2292 DEFUN (no_match_ip_next_hop_prefix_list,
2293 no_match_ip_next_hop_prefix_list_cmd,
2294 "no match ip next-hop prefix-list [WORD]",
2295 NO_STR
2296 MATCH_STR
2297 IP_STR
2298 "Match next-hop address of route\n"
2299 "Match entries of prefix-lists\n"
2300 "IP prefix-list name\n")
2301 {
2302 int idx_word = 5;
2303 VTY_DECLVAR_CONTEXT(route_map_index, index);
2304
2305 if (rmap_match_set_hook.no_match_ip_next_hop) {
2306 if (argc <= idx_word)
2307 return rmap_match_set_hook.no_match_ip_next_hop(
2308 vty, index, "ip next-hop prefix-list", NULL,
2309 RMAP_EVENT_PLIST_DELETED);
2310 return rmap_match_set_hook.no_match_ip_next_hop(
2311 vty, index, "ip next-hop prefix-list",
2312 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2313 }
2314 return CMD_SUCCESS;
2315 }
2316
2317 DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd,
2318 "match ip next-hop type <blackhole>",
2319 MATCH_STR IP_STR
2320 "Match next-hop address of route\n"
2321 "Match entries by type\n"
2322 "Blackhole\n")
2323 {
2324 int idx_word = 4;
2325 VTY_DECLVAR_CONTEXT(route_map_index, index);
2326
2327 if (rmap_match_set_hook.match_ip_next_hop_type)
2328 return rmap_match_set_hook.match_ip_next_hop_type(
2329 vty, index, "ip next-hop type", argv[idx_word]->arg,
2330 RMAP_EVENT_MATCH_ADDED);
2331 return CMD_SUCCESS;
2332 }
2333
2334 DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
2335 "no match ip next-hop type [<blackhole>]",
2336 NO_STR MATCH_STR IP_STR
2337 "Match next-hop address of route\n"
2338 "Match entries by type\n"
2339 "Blackhole\n")
2340 {
2341 int idx_word = 5;
2342 VTY_DECLVAR_CONTEXT(route_map_index, index);
2343
2344 if (rmap_match_set_hook.no_match_ip_next_hop) {
2345 if (argc <= idx_word)
2346 return rmap_match_set_hook.no_match_ip_next_hop(
2347 vty, index, "ip next-hop type", NULL,
2348 RMAP_EVENT_MATCH_DELETED);
2349 return rmap_match_set_hook.no_match_ip_next_hop(
2350 vty, index, "ip next-hop type", argv[idx_word]->arg,
2351 RMAP_EVENT_MATCH_DELETED);
2352 }
2353 return CMD_SUCCESS;
2354 }
2355
2356
2357 DEFUN (match_ipv6_address,
2358 match_ipv6_address_cmd,
2359 "match ipv6 address WORD",
2360 MATCH_STR
2361 IPV6_STR
2362 "Match IPv6 address of route\n"
2363 "IPv6 access-list name\n")
2364 {
2365 int idx_word = 3;
2366 VTY_DECLVAR_CONTEXT(route_map_index, index);
2367
2368 if (rmap_match_set_hook.match_ipv6_address)
2369 return rmap_match_set_hook.match_ipv6_address(
2370 vty, index, "ipv6 address", argv[idx_word]->arg,
2371 RMAP_EVENT_FILTER_ADDED);
2372 return CMD_SUCCESS;
2373 }
2374
2375 DEFUN (no_match_ipv6_address,
2376 no_match_ipv6_address_cmd,
2377 "no match ipv6 address WORD",
2378 NO_STR
2379 MATCH_STR
2380 IPV6_STR
2381 "Match IPv6 address of route\n"
2382 "IPv6 access-list name\n")
2383 {
2384 int idx_word = 4;
2385 VTY_DECLVAR_CONTEXT(route_map_index, index);
2386
2387 if (rmap_match_set_hook.no_match_ipv6_address)
2388 return rmap_match_set_hook.no_match_ipv6_address(
2389 vty, index, "ipv6 address", argv[idx_word]->arg,
2390 RMAP_EVENT_FILTER_DELETED);
2391 return CMD_SUCCESS;
2392 }
2393
2394
2395 DEFUN (match_ipv6_address_prefix_list,
2396 match_ipv6_address_prefix_list_cmd,
2397 "match ipv6 address prefix-list WORD",
2398 MATCH_STR
2399 IPV6_STR
2400 "Match address of route\n"
2401 "Match entries of prefix-lists\n"
2402 "IP prefix-list name\n")
2403 {
2404 int idx_word = 4;
2405 VTY_DECLVAR_CONTEXT(route_map_index, index);
2406
2407 if (rmap_match_set_hook.match_ipv6_address_prefix_list)
2408 return rmap_match_set_hook.match_ipv6_address_prefix_list(
2409 vty, index, "ipv6 address prefix-list",
2410 argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
2411 return CMD_SUCCESS;
2412 }
2413
2414 DEFUN (no_match_ipv6_address_prefix_list,
2415 no_match_ipv6_address_prefix_list_cmd,
2416 "no match ipv6 address prefix-list WORD",
2417 NO_STR
2418 MATCH_STR
2419 IPV6_STR
2420 "Match address of route\n"
2421 "Match entries of prefix-lists\n"
2422 "IP prefix-list name\n")
2423 {
2424 int idx_word = 5;
2425 VTY_DECLVAR_CONTEXT(route_map_index, index);
2426
2427 if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
2428 return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
2429 vty, index, "ipv6 address prefix-list",
2430 argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
2431 return CMD_SUCCESS;
2432 }
2433
2434 DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
2435 "match ipv6 next-hop type <blackhole>",
2436 MATCH_STR IPV6_STR
2437 "Match address of route\n"
2438 "Match entries by type\n"
2439 "Blackhole\n")
2440 {
2441 int idx_word = 4;
2442 VTY_DECLVAR_CONTEXT(route_map_index, index);
2443
2444 if (rmap_match_set_hook.match_ipv6_next_hop_type)
2445 return rmap_match_set_hook.match_ipv6_next_hop_type(
2446 vty, index, "ipv6 next-hop type", argv[idx_word]->arg,
2447 RMAP_EVENT_MATCH_ADDED);
2448 return CMD_SUCCESS;
2449 }
2450
2451 DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
2452 "no match ipv6 next-hop type [<blackhole>]",
2453 NO_STR MATCH_STR IPV6_STR
2454 "Match address of route\n"
2455 "Match entries by type\n"
2456 "Blackhole\n")
2457 {
2458 int idx_word = 5;
2459 VTY_DECLVAR_CONTEXT(route_map_index, index);
2460
2461 if (rmap_match_set_hook.no_match_ipv6_next_hop_type)
2462 return rmap_match_set_hook.no_match_ipv6_next_hop_type(
2463 vty, index, "ipv6 next-hop type",
2464 (argc <= idx_word) ? NULL : argv[idx_word]->arg,
2465 RMAP_EVENT_MATCH_DELETED);
2466 return CMD_SUCCESS;
2467 }
2468
2469 DEFUN (match_metric,
2470 match_metric_cmd,
2471 "match metric (0-4294967295)",
2472 MATCH_STR
2473 "Match metric of route\n"
2474 "Metric value\n")
2475 {
2476 int idx_number = 2;
2477 VTY_DECLVAR_CONTEXT(route_map_index, index);
2478
2479 if (rmap_match_set_hook.match_metric)
2480 return rmap_match_set_hook.match_metric(vty, index, "metric",
2481 argv[idx_number]->arg,
2482 RMAP_EVENT_MATCH_ADDED);
2483 return CMD_SUCCESS;
2484 }
2485
2486
2487 DEFUN (no_match_metric,
2488 no_match_metric_cmd,
2489 "no match metric [(0-4294967295)]",
2490 NO_STR
2491 MATCH_STR
2492 "Match metric of route\n"
2493 "Metric value\n")
2494 {
2495 int idx_number = 3;
2496 VTY_DECLVAR_CONTEXT(route_map_index, index);
2497
2498 if (rmap_match_set_hook.no_match_metric) {
2499 if (argc <= idx_number)
2500 return rmap_match_set_hook.no_match_metric(
2501 vty, index, "metric", NULL,
2502 RMAP_EVENT_MATCH_DELETED);
2503 return rmap_match_set_hook.no_match_metric(
2504 vty, index, "metric", argv[idx_number]->arg,
2505 RMAP_EVENT_MATCH_DELETED);
2506 }
2507 return CMD_SUCCESS;
2508 }
2509
2510
2511 DEFUN (match_tag,
2512 match_tag_cmd,
2513 "match tag (1-4294967295)",
2514 MATCH_STR
2515 "Match tag of route\n"
2516 "Tag value\n")
2517 {
2518 int idx_number = 2;
2519 VTY_DECLVAR_CONTEXT(route_map_index, index);
2520
2521 if (rmap_match_set_hook.match_tag)
2522 return rmap_match_set_hook.match_tag(vty, index, "tag",
2523 argv[idx_number]->arg,
2524 RMAP_EVENT_MATCH_ADDED);
2525 return CMD_SUCCESS;
2526 }
2527
2528
2529 DEFUN (no_match_tag,
2530 no_match_tag_cmd,
2531 "no match tag [(1-4294967295)]",
2532 NO_STR
2533 MATCH_STR
2534 "Match tag of route\n"
2535 "Tag value\n")
2536 {
2537 VTY_DECLVAR_CONTEXT(route_map_index, index);
2538
2539 int idx = 0;
2540 char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
2541 ? argv[idx]->arg
2542 : NULL;
2543
2544 if (rmap_match_set_hook.no_match_tag)
2545 return rmap_match_set_hook.no_match_tag(
2546 vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
2547 return CMD_SUCCESS;
2548 }
2549
2550
2551 DEFUN (set_ip_nexthop,
2552 set_ip_nexthop_cmd,
2553 "set ip next-hop A.B.C.D",
2554 SET_STR
2555 IP_STR
2556 "Next hop address\n"
2557 "IP address of next hop\n")
2558 {
2559 int idx_ipv4 = 3;
2560 union sockunion su;
2561 int ret;
2562 VTY_DECLVAR_CONTEXT(route_map_index, index);
2563
2564 ret = str2sockunion(argv[idx_ipv4]->arg, &su);
2565 if (ret < 0) {
2566 vty_out(vty, "%% Malformed nexthop address\n");
2567 return CMD_WARNING_CONFIG_FAILED;
2568 }
2569 if (su.sin.sin_addr.s_addr == 0
2570 || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
2571 vty_out(vty,
2572 "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
2573 return CMD_WARNING_CONFIG_FAILED;
2574 }
2575
2576 if (rmap_match_set_hook.set_ip_nexthop)
2577 return rmap_match_set_hook.set_ip_nexthop(
2578 vty, index, "ip next-hop", argv[idx_ipv4]->arg);
2579 return CMD_SUCCESS;
2580 }
2581
2582
2583 DEFUN (no_set_ip_nexthop,
2584 no_set_ip_nexthop_cmd,
2585 "no set ip next-hop [A.B.C.D]",
2586 NO_STR
2587 SET_STR
2588 IP_STR
2589 "Next hop address\n"
2590 "IP address of next hop\n")
2591 {
2592 int idx = 0;
2593 VTY_DECLVAR_CONTEXT(route_map_index, index);
2594 const char *arg = NULL;
2595
2596 if (argv_find(argv, argc, "A.B.C.D", &idx))
2597 arg = argv[idx]->arg;
2598
2599 if (rmap_match_set_hook.no_set_ip_nexthop)
2600 return rmap_match_set_hook.no_set_ip_nexthop(
2601 vty, index, "ip next-hop", arg);
2602
2603 return CMD_SUCCESS;
2604 }
2605
2606
2607 DEFUN (set_ipv6_nexthop_local,
2608 set_ipv6_nexthop_local_cmd,
2609 "set ipv6 next-hop local X:X::X:X",
2610 SET_STR
2611 IPV6_STR
2612 "IPv6 next-hop address\n"
2613 "IPv6 local address\n"
2614 "IPv6 address of next hop\n")
2615 {
2616 int idx_ipv6 = 4;
2617 struct in6_addr addr;
2618 int ret;
2619 VTY_DECLVAR_CONTEXT(route_map_index, index);
2620
2621 ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
2622 if (!ret) {
2623 vty_out(vty, "%% Malformed nexthop address\n");
2624 return CMD_WARNING_CONFIG_FAILED;
2625 }
2626 if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
2627 vty_out(vty, "%% Invalid link-local nexthop address\n");
2628 return CMD_WARNING_CONFIG_FAILED;
2629 }
2630
2631 if (rmap_match_set_hook.set_ipv6_nexthop_local)
2632 return rmap_match_set_hook.set_ipv6_nexthop_local(
2633 vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
2634 return CMD_SUCCESS;
2635 }
2636
2637
2638 DEFUN (no_set_ipv6_nexthop_local,
2639 no_set_ipv6_nexthop_local_cmd,
2640 "no set ipv6 next-hop local [X:X::X:X]",
2641 NO_STR
2642 SET_STR
2643 IPV6_STR
2644 "IPv6 next-hop address\n"
2645 "IPv6 local address\n"
2646 "IPv6 address of next hop\n")
2647 {
2648 int idx_ipv6 = 5;
2649 VTY_DECLVAR_CONTEXT(route_map_index, index);
2650
2651 if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
2652 if (argc <= idx_ipv6)
2653 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2654 vty, index, "ipv6 next-hop local", NULL);
2655 return rmap_match_set_hook.no_set_ipv6_nexthop_local(
2656 vty, index, "ipv6 next-hop local", argv[5]->arg);
2657 }
2658 return CMD_SUCCESS;
2659 }
2660
2661 DEFUN (set_metric,
2662 set_metric_cmd,
2663 "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
2664 SET_STR
2665 "Metric value for destination routing protocol\n"
2666 "Metric value\n"
2667 "Assign round trip time\n"
2668 "Add round trip time\n"
2669 "Subtract round trip time\n"
2670 "Add metric\n"
2671 "Subtract metric\n")
2672 {
2673 int idx_number = 2;
2674 VTY_DECLVAR_CONTEXT(route_map_index, index);
2675
2676 const char *pass = (argv[idx_number]->type == RANGE_TKN)
2677 ? argv[idx_number]->arg
2678 : argv[idx_number]->text;
2679
2680 if (rmap_match_set_hook.set_metric)
2681 return rmap_match_set_hook.set_metric(vty, index, "metric",
2682 pass);
2683 return CMD_SUCCESS;
2684 }
2685
2686
2687 DEFUN (no_set_metric,
2688 no_set_metric_cmd,
2689 "no set metric [(0-4294967295)]",
2690 NO_STR
2691 SET_STR
2692 "Metric value for destination routing protocol\n"
2693 "Metric value\n")
2694 {
2695 int idx_number = 3;
2696 VTY_DECLVAR_CONTEXT(route_map_index, index);
2697
2698 if (rmap_match_set_hook.no_set_metric) {
2699 if (argc <= idx_number)
2700 return rmap_match_set_hook.no_set_metric(
2701 vty, index, "metric", NULL);
2702 return rmap_match_set_hook.no_set_metric(vty, index, "metric",
2703 argv[idx_number]->arg);
2704 }
2705 return CMD_SUCCESS;
2706 }
2707
2708
2709 DEFUN (set_tag,
2710 set_tag_cmd,
2711 "set tag (1-4294967295)",
2712 SET_STR
2713 "Tag value for routing protocol\n"
2714 "Tag value\n")
2715 {
2716 VTY_DECLVAR_CONTEXT(route_map_index, index);
2717
2718 int idx_number = 2;
2719 if (rmap_match_set_hook.set_tag)
2720 return rmap_match_set_hook.set_tag(vty, index, "tag",
2721 argv[idx_number]->arg);
2722 return CMD_SUCCESS;
2723 }
2724
2725
2726 DEFUN (no_set_tag,
2727 no_set_tag_cmd,
2728 "no set tag [(1-4294967295)]",
2729 NO_STR
2730 SET_STR
2731 "Tag value for routing protocol\n"
2732 "Tag value\n")
2733 {
2734 VTY_DECLVAR_CONTEXT(route_map_index, index);
2735
2736 int idx_number = 3;
2737 if (rmap_match_set_hook.no_set_tag) {
2738 if (argc <= idx_number)
2739 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2740 NULL);
2741 return rmap_match_set_hook.no_set_tag(vty, index, "tag",
2742 argv[idx_number]->arg);
2743 }
2744 return CMD_SUCCESS;
2745 }
2746
2747
2748 DEFUN_NOSH (route_map,
2749 route_map_cmd,
2750 "route-map WORD <deny|permit> (1-65535)",
2751 "Create route-map or enter route-map command mode\n"
2752 "Route map tag\n"
2753 "Route map denies set operations\n"
2754 "Route map permits set operations\n"
2755 "Sequence to insert to/delete from existing route-map entry\n")
2756 {
2757 int idx_word = 1;
2758 int idx_permit_deny = 2;
2759 int idx_number = 3;
2760 struct route_map *map;
2761 struct route_map_index *index;
2762 char *endptr = NULL;
2763 int permit =
2764 argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
2765 unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
2766 const char *mapname = argv[idx_word]->arg;
2767
2768 /* Get route map. */
2769 map = route_map_get(mapname);
2770 index = route_map_index_get(map, permit, pref);
2771
2772 VTY_PUSH_CONTEXT(RMAP_NODE, index);
2773 return CMD_SUCCESS;
2774 }
2775
2776 DEFUN (no_route_map_all,
2777 no_route_map_all_cmd,
2778 "no route-map WORD",
2779 NO_STR
2780 "Create route-map or enter route-map command mode\n"
2781 "Route map tag\n")
2782 {
2783 int idx_word = 2;
2784 const char *mapname = argv[idx_word]->arg;
2785 struct route_map *map;
2786
2787 map = route_map_lookup_by_name(mapname);
2788 if (map == NULL) {
2789 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2790 return CMD_WARNING_CONFIG_FAILED;
2791 }
2792
2793 route_map_delete(map);
2794
2795 return CMD_SUCCESS;
2796 }
2797
2798 DEFUN (no_route_map,
2799 no_route_map_cmd,
2800 "no route-map WORD <deny|permit> (1-65535)",
2801 NO_STR
2802 "Create route-map or enter route-map command mode\n"
2803 "Route map tag\n"
2804 "Route map denies set operations\n"
2805 "Route map permits set operations\n"
2806 "Sequence to insert to/delete from existing route-map entry\n")
2807 {
2808 int idx_word = 2;
2809 int idx_permit_deny = 3;
2810 int idx_number = 4;
2811 struct route_map *map;
2812 struct route_map_index *index;
2813 char *endptr = NULL;
2814 int permit = strmatch(argv[idx_permit_deny]->text, "permit")
2815 ? RMAP_PERMIT
2816 : RMAP_DENY;
2817 const char *prefstr = argv[idx_number]->arg;
2818 const char *mapname = argv[idx_word]->arg;
2819 unsigned long pref = strtoul(prefstr, &endptr, 10);
2820
2821 /* Existence check. */
2822 map = route_map_lookup_by_name(mapname);
2823 if (map == NULL) {
2824 vty_out(vty, "%% Could not find route-map %s\n", mapname);
2825 return CMD_WARNING_CONFIG_FAILED;
2826 }
2827
2828 /* Lookup route map index. */
2829 index = route_map_index_lookup(map, permit, pref);
2830 if (index == NULL) {
2831 vty_out(vty, "%% Could not find route-map entry %s %s\n",
2832 mapname, prefstr);
2833 return CMD_WARNING_CONFIG_FAILED;
2834 }
2835
2836 /* Delete index from route map. */
2837 route_map_index_delete(index, 1);
2838
2839 /* If this route rule is the last one, delete route map itself. */
2840 if (route_map_empty(map))
2841 route_map_delete(map);
2842
2843 return CMD_SUCCESS;
2844 }
2845
2846 DEFUN (rmap_onmatch_next,
2847 rmap_onmatch_next_cmd,
2848 "on-match next",
2849 "Exit policy on matches\n"
2850 "Next clause\n")
2851 {
2852 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2853
2854 if (index) {
2855 if (index->type == RMAP_DENY) {
2856 /* Under a deny clause, match means it's finished. No
2857 * need to set next */
2858 vty_out(vty,
2859 "on-match next not supported under route-map deny\n");
2860 return CMD_WARNING_CONFIG_FAILED;
2861 }
2862 index->exitpolicy = RMAP_NEXT;
2863 }
2864 return CMD_SUCCESS;
2865 }
2866
2867 DEFUN (no_rmap_onmatch_next,
2868 no_rmap_onmatch_next_cmd,
2869 "no on-match next",
2870 NO_STR
2871 "Exit policy on matches\n"
2872 "Next clause\n")
2873 {
2874 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2875
2876 if (index)
2877 index->exitpolicy = RMAP_EXIT;
2878
2879 return CMD_SUCCESS;
2880 }
2881
2882 DEFUN (rmap_onmatch_goto,
2883 rmap_onmatch_goto_cmd,
2884 "on-match goto (1-65535)",
2885 "Exit policy on matches\n"
2886 "Goto Clause number\n"
2887 "Number\n")
2888 {
2889 int idx = 0;
2890 char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
2891 : NULL;
2892
2893 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2894 int d = 0;
2895
2896 if (index) {
2897 if (index->type == RMAP_DENY) {
2898 /* Under a deny clause, match means it's finished. No
2899 * need to go anywhere */
2900 vty_out(vty,
2901 "on-match goto not supported under route-map deny\n");
2902 return CMD_WARNING_CONFIG_FAILED;
2903 }
2904
2905 if (num)
2906 d = strtoul(num, NULL, 10);
2907 else
2908 d = index->pref + 1;
2909
2910 if (d <= index->pref) {
2911 /* Can't allow you to do that, Dave */
2912 vty_out(vty, "can't jump backwards in route-maps\n");
2913 return CMD_WARNING_CONFIG_FAILED;
2914 } else {
2915 index->exitpolicy = RMAP_GOTO;
2916 index->nextpref = d;
2917 }
2918 }
2919 return CMD_SUCCESS;
2920 }
2921
2922 DEFUN (no_rmap_onmatch_goto,
2923 no_rmap_onmatch_goto_cmd,
2924 "no on-match goto",
2925 NO_STR
2926 "Exit policy on matches\n"
2927 "Goto Clause number\n")
2928 {
2929 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2930
2931 if (index)
2932 index->exitpolicy = RMAP_EXIT;
2933
2934 return CMD_SUCCESS;
2935 }
2936
2937 /* Cisco/GNU Zebra compatibility aliases */
2938 /* ALIAS_FIXME */
2939 DEFUN (rmap_continue,
2940 rmap_continue_cmd,
2941 "continue (1-65535)",
2942 "Continue on a different entry within the route-map\n"
2943 "Route-map entry sequence number\n")
2944 {
2945 return rmap_onmatch_goto(self, vty, argc, argv);
2946 }
2947
2948 /* ALIAS_FIXME */
2949 DEFUN (no_rmap_continue,
2950 no_rmap_continue_cmd,
2951 "no continue [(1-65535)]",
2952 NO_STR
2953 "Continue on a different entry within the route-map\n"
2954 "Route-map entry sequence number\n")
2955 {
2956 return no_rmap_onmatch_goto(self, vty, argc, argv);
2957 }
2958
2959
2960 DEFUN (rmap_show_name,
2961 rmap_show_name_cmd,
2962 "show route-map [WORD]",
2963 SHOW_STR
2964 "route-map information\n"
2965 "route-map name\n")
2966 {
2967 int idx_word = 2;
2968 const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
2969 return vty_show_route_map(vty, name);
2970 }
2971
2972 DEFUN (rmap_show_unused,
2973 rmap_show_unused_cmd,
2974 "show route-map-unused",
2975 SHOW_STR
2976 "unused route-map information\n")
2977 {
2978 return vty_show_unused_route_map(vty);
2979 }
2980
2981 DEFUN (rmap_call,
2982 rmap_call_cmd,
2983 "call WORD",
2984 "Jump to another Route-Map after match+set\n"
2985 "Target route-map name\n")
2986 {
2987 int idx_word = 1;
2988 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
2989 const char *rmap = argv[idx_word]->arg;
2990
2991 assert(index);
2992
2993 /* If "call" is invoked with the same route-map name as
2994 * the one previously configured then, ignore the duplicate
2995 * configuration.
2996 */
2997 if (index->nextrm && (strcmp(index->nextrm, rmap) == 0))
2998 return CMD_SUCCESS;
2999
3000 if (index->nextrm) {
3001 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
3002 index->nextrm, index->map->name);
3003 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
3004 }
3005 index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
3006
3007 /* Execute event hook. */
3008 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
3009 index->map->name);
3010 return CMD_SUCCESS;
3011 }
3012
3013 DEFUN (no_rmap_call,
3014 no_rmap_call_cmd,
3015 "no call",
3016 NO_STR
3017 "Jump to another Route-Map after match+set\n")
3018 {
3019 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
3020
3021 if (index->nextrm) {
3022 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
3023 index->nextrm, index->map->name);
3024 XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
3025 index->nextrm = NULL;
3026 }
3027
3028 return CMD_SUCCESS;
3029 }
3030
3031 DEFUN (rmap_description,
3032 rmap_description_cmd,
3033 "description LINE...",
3034 "Route-map comment\n"
3035 "Comment describing this route-map rule\n")
3036 {
3037 int idx_line = 1;
3038 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
3039
3040 if (index) {
3041 if (index->description)
3042 XFREE(MTYPE_TMP, index->description);
3043 index->description = argv_concat(argv, argc, idx_line);
3044 }
3045 return CMD_SUCCESS;
3046 }
3047
3048 DEFUN (no_rmap_description,
3049 no_rmap_description_cmd,
3050 "no description",
3051 NO_STR
3052 "Route-map comment\n")
3053 {
3054 struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
3055
3056 if (index) {
3057 if (index->description)
3058 XFREE(MTYPE_TMP, index->description);
3059 index->description = NULL;
3060 }
3061 return CMD_SUCCESS;
3062 }
3063
3064 DEFUN (debug_rmap,
3065 debug_rmap_cmd,
3066 "debug route-map",
3067 DEBUG_STR
3068 "Debug option set for route-maps\n")
3069 {
3070 rmap_debug = true;
3071 return CMD_SUCCESS;
3072 }
3073
3074 DEFUN (no_debug_rmap,
3075 no_debug_rmap_cmd,
3076 "no debug route-map",
3077 NO_STR
3078 DEBUG_STR
3079 "Debug option set for route-maps\n")
3080 {
3081 rmap_debug = false;
3082 return CMD_SUCCESS;
3083 }
3084
3085 /* Debug node. */
3086 static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1};
3087
3088 /* Configuration write function. */
3089 static int route_map_config_write(struct vty *vty)
3090 {
3091 struct route_map *map;
3092 struct route_map_index *index;
3093 struct route_map_rule *rule;
3094 int first = 1;
3095 int write = 0;
3096
3097 for (map = route_map_master.head; map; map = map->next)
3098 for (index = map->head; index; index = index->next) {
3099 if (!first)
3100 vty_out(vty, "!\n");
3101 else
3102 first = 0;
3103
3104 vty_out(vty, "route-map %s %s %d\n", map->name,
3105 route_map_type_str(index->type), index->pref);
3106
3107 if (index->description)
3108 vty_out(vty, " description %s\n",
3109 index->description);
3110
3111 for (rule = index->match_list.head; rule;
3112 rule = rule->next)
3113 vty_out(vty, " match %s %s\n", rule->cmd->str,
3114 rule->rule_str ? rule->rule_str : "");
3115
3116 for (rule = index->set_list.head; rule;
3117 rule = rule->next)
3118 vty_out(vty, " set %s %s\n", rule->cmd->str,
3119 rule->rule_str ? rule->rule_str : "");
3120 if (index->nextrm)
3121 vty_out(vty, " call %s\n", index->nextrm);
3122 if (index->exitpolicy == RMAP_GOTO)
3123 vty_out(vty, " on-match goto %d\n",
3124 index->nextpref);
3125 if (index->exitpolicy == RMAP_NEXT)
3126 vty_out(vty, " on-match next\n");
3127
3128 write++;
3129 }
3130 return write;
3131 }
3132
3133 static int rmap_config_write_debug(struct vty *vty)
3134 {
3135 int write = 0;
3136
3137 if (rmap_debug) {
3138 vty_out(vty, "debug route-map\n");
3139 write++;
3140 }
3141
3142 return write;
3143 }
3144
3145 /* Route map node structure. */
3146 static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
3147
3148 /* Common route map rules */
3149
3150 void *route_map_rule_tag_compile(const char *arg)
3151 {
3152 unsigned long int tmp;
3153 char *endptr;
3154 route_tag_t *tag;
3155
3156 errno = 0;
3157 tmp = strtoul(arg, &endptr, 0);
3158 if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX)
3159 return NULL;
3160
3161 tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag));
3162 *tag = tmp;
3163
3164 return tag;
3165 }
3166
3167 void route_map_rule_tag_free(void *rule)
3168 {
3169 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
3170 }
3171
3172 void route_map_finish(void)
3173 {
3174 int i;
3175
3176 vector_free(route_match_vec);
3177 route_match_vec = NULL;
3178 vector_free(route_set_vec);
3179 route_set_vec = NULL;
3180
3181 /*
3182 * All protocols are setting these to NULL
3183 * by default on shutdown( route_map_finish )
3184 * Why are we making them do this work?
3185 */
3186 route_map_master.add_hook = NULL;
3187 route_map_master.delete_hook = NULL;
3188 route_map_master.event_hook = NULL;
3189
3190 /* cleanup route_map */
3191 while (route_map_master.head) {
3192 struct route_map *map = route_map_master.head;
3193 map->to_be_processed = false;
3194 route_map_delete(map);
3195 }
3196
3197 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
3198 hash_free(route_map_dep_hash[i]);
3199 route_map_dep_hash[i] = NULL;
3200 }
3201
3202 hash_free(route_map_master_hash);
3203 route_map_master_hash = NULL;
3204 }
3205
3206 static void rmap_autocomplete(vector comps, struct cmd_token *token)
3207 {
3208 struct route_map *map;
3209
3210 for (map = route_map_master.head; map; map = map->next)
3211 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
3212 }
3213
3214 /* Increment the use_count counter while attaching the route map */
3215 void route_map_counter_increment(struct route_map *map)
3216 {
3217 if (map)
3218 map->use_count++;
3219 }
3220
3221 /* Decrement the use_count counter while detaching the route map. */
3222 void route_map_counter_decrement(struct route_map *map)
3223 {
3224 if (map) {
3225 if (map->use_count <= 0)
3226 return;
3227 map->use_count--;
3228 }
3229 }
3230
3231 static const struct cmd_variable_handler rmap_var_handlers[] = {
3232 {/* "route-map WORD" */
3233 .varname = "route_map",
3234 .completions = rmap_autocomplete},
3235 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
3236 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
3237 {.completions = NULL}};
3238
3239 /* Initialization of route map vector. */
3240 void route_map_init(void)
3241 {
3242 int i;
3243
3244 /* Make vector for match and set. */
3245 route_match_vec = vector_init(1);
3246 route_set_vec = vector_init(1);
3247 route_map_master_hash =
3248 hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
3249 "Route Map Master Hash");
3250
3251 for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
3252 route_map_dep_hash[i] = hash_create_size(
3253 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
3254 "Route Map Dep Hash");
3255
3256 cmd_variable_handler_register(rmap_var_handlers);
3257
3258 rmap_debug = false;
3259
3260 /* Install route map top node. */
3261 install_node(&rmap_node, route_map_config_write);
3262
3263 install_node(&rmap_debug_node, rmap_config_write_debug);
3264
3265 /* Install route map commands. */
3266 install_default(RMAP_NODE);
3267 install_element(CONFIG_NODE, &route_map_cmd);
3268 install_element(CONFIG_NODE, &no_route_map_cmd);
3269 install_element(CONFIG_NODE, &no_route_map_all_cmd);
3270
3271 install_element(CONFIG_NODE, &debug_rmap_cmd);
3272 install_element(CONFIG_NODE, &no_debug_rmap_cmd);
3273
3274 /* Install the on-match stuff */
3275 install_element(RMAP_NODE, &route_map_cmd);
3276 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
3277 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
3278 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
3279 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
3280 install_element(RMAP_NODE, &rmap_continue_cmd);
3281 install_element(RMAP_NODE, &no_rmap_continue_cmd);
3282
3283 /* Install the continue stuff (ALIAS of on-match). */
3284
3285 /* Install the call stuff. */
3286 install_element(RMAP_NODE, &rmap_call_cmd);
3287 install_element(RMAP_NODE, &no_rmap_call_cmd);
3288
3289 /* Install description commands. */
3290 install_element(RMAP_NODE, &rmap_description_cmd);
3291 install_element(RMAP_NODE, &no_rmap_description_cmd);
3292
3293 /* Install show command */
3294 install_element(ENABLE_NODE, &rmap_show_name_cmd);
3295 install_element(ENABLE_NODE, &rmap_show_unused_cmd);
3296
3297 install_element(ENABLE_NODE, &debug_rmap_cmd);
3298 install_element(ENABLE_NODE, &no_debug_rmap_cmd);
3299
3300 install_element(RMAP_NODE, &match_interface_cmd);
3301 install_element(RMAP_NODE, &no_match_interface_cmd);
3302
3303 install_element(RMAP_NODE, &match_ip_address_cmd);
3304 install_element(RMAP_NODE, &no_match_ip_address_cmd);
3305
3306 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
3307 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
3308
3309 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
3310 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
3311
3312 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
3313 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
3314
3315 install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
3316 install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
3317
3318 install_element(RMAP_NODE, &match_ipv6_address_cmd);
3319 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
3320
3321 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
3322 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
3323
3324 install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
3325 install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
3326
3327 install_element(RMAP_NODE, &match_metric_cmd);
3328 install_element(RMAP_NODE, &no_match_metric_cmd);
3329
3330 install_element(RMAP_NODE, &match_tag_cmd);
3331 install_element(RMAP_NODE, &no_match_tag_cmd);
3332
3333 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
3334 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
3335
3336 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
3337 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
3338
3339 install_element(RMAP_NODE, &set_metric_cmd);
3340 install_element(RMAP_NODE, &no_set_metric_cmd);
3341
3342 install_element(RMAP_NODE, &set_tag_cmd);
3343 install_element(RMAP_NODE, &no_set_tag_cmd);
3344 }