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