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