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