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