]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_routemap.c
Merge pull request #2034 from vincentbernat/fix/rfc8365-auto-rt
[mirror_frr.git] / zebra / zebra_routemap.c
CommitLineData
5921ef9a
PJ
1/* zebra routemap.
2 * Copyright (C) 2006 IBM Corporation
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 *
896014f4
DL
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
5921ef9a
PJ
19 */
20
21#include <zebra.h>
22
23#include "memory.h"
4a1ab8e4 24#include "zebra_memory.h"
5921ef9a
PJ
25#include "prefix.h"
26#include "rib.h"
82f97584 27#include "vty.h"
5921ef9a
PJ
28#include "routemap.h"
29#include "command.h"
30#include "filter.h"
31#include "plist.h"
fb018d25 32#include "nexthop.h"
0032dd59 33#include "vrf.h"
5921ef9a
PJ
34
35#include "zebra/zserv.h"
8902474b 36#include "zebra/redistribute.h"
518f0eb1 37#include "zebra/debug.h"
9f0ea7d4 38#include "zebra/zebra_rnh.h"
6baf7bb8 39#include "zebra/zebra_routemap.h"
518f0eb1 40
d7c0a89a 41static uint32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER;
518f0eb1 42static struct thread *zebra_t_rmap_update = NULL;
d62a17ae 43char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX + 1]; /* "any" == ZEBRA_ROUTE_MAX */
9f0ea7d4 44/* NH Tracking route map */
d62a17ae 45char *nht_rm[AFI_MAX][ZEBRA_ROUTE_MAX + 1]; /* "any" == ZEBRA_ROUTE_MAX */
8902474b 46char *zebra_import_table_routemap[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX];
518f0eb1 47
d62a17ae 48struct nh_rmap_obj {
49 struct nexthop *nexthop;
50 vrf_id_t vrf_id;
d7c0a89a 51 uint32_t source_protocol;
d62a17ae 52 int metric;
53 route_tag_t tag;
9f0ea7d4
DS
54};
55
d7c0a89a 56static void zebra_route_map_set_delay_timer(uint32_t value);
5921ef9a 57
82f97584 58
5921ef9a 59/* Add zebra route map rule */
d62a17ae 60static int zebra_route_match_add(struct vty *vty, const char *command,
61 const char *arg, route_map_event_t type)
62{
63 VTY_DECLVAR_CONTEXT(route_map_index, index);
64 int ret;
9ca25fed 65 int retval = CMD_SUCCESS;
d62a17ae 66
67 ret = route_map_add_match(index, command, arg);
9ca25fed
DS
68 switch (ret) {
69 case RMAP_RULE_MISSING:
70 vty_out(vty, "%% Zebra Can't find rule.\n");
71 retval = CMD_WARNING_CONFIG_FAILED;
72 break;
73 case RMAP_COMPILE_ERROR:
74 vty_out(vty, "%% Zebra Argument is malformed.\n");
75 retval = CMD_WARNING_CONFIG_FAILED;
76 break;
77 case RMAP_COMPILE_SUCCESS:
78 if (type != RMAP_EVENT_MATCH_ADDED) {
79 route_map_upd8_dependency(type, arg, index->map->name);
d62a17ae 80 }
9ca25fed 81 break;
5921ef9a 82 }
518f0eb1 83
9ca25fed 84 return retval;
5921ef9a
PJ
85}
86
87/* Delete zebra route map rule. */
d62a17ae 88static int zebra_route_match_delete(struct vty *vty, const char *command,
89 const char *arg, route_map_event_t type)
90{
91 VTY_DECLVAR_CONTEXT(route_map_index, index);
92 int ret;
9ca25fed 93 int retval = CMD_SUCCESS;
d62a17ae 94 char *dep_name = NULL;
95 const char *tmpstr;
96 char *rmap_name = NULL;
97
98 if (type != RMAP_EVENT_MATCH_DELETED) {
99 /* ignore the mundane, the types without any dependency */
100 if (arg == NULL) {
101 if ((tmpstr = route_map_get_match_arg(index, command))
102 != NULL)
103 dep_name =
104 XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
105 } else {
106 dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
107 }
108 rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
4e3afb14 109 }
5921ef9a 110
d62a17ae 111 ret = route_map_delete_match(index, command, arg);
9ca25fed
DS
112 switch (ret) {
113 case RMAP_RULE_MISSING:
114 vty_out(vty, "%% Zebra Can't find rule.\n");
115 retval = CMD_WARNING_CONFIG_FAILED;
116 break;
117 case RMAP_COMPILE_ERROR:
118 vty_out(vty, "%% Zebra Argument is malformed.\n");
119 retval = CMD_WARNING_CONFIG_FAILED;
120 break;
121 case RMAP_COMPILE_SUCCESS:
122 if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
123 route_map_upd8_dependency(type, dep_name, rmap_name);
124 break;
5921ef9a 125 }
518f0eb1 126
d62a17ae 127 if (dep_name)
128 XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
129 if (rmap_name)
130 XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
518f0eb1 131
9ca25fed 132 return retval;
5921ef9a
PJ
133}
134
ca84c8ef
DS
135/* 'match tag TAG'
136 * Match function return 1 if match is success else return 0
137 */
d62a17ae 138static route_map_result_t route_match_tag(void *rule, struct prefix *prefix,
139 route_map_object_t type, void *object)
ca84c8ef 140{
d62a17ae 141 route_tag_t *tag;
142 struct nh_rmap_obj *nh_data;
ca84c8ef 143
d62a17ae 144 if (type == RMAP_ZEBRA) {
145 tag = rule;
146 nh_data = object;
ca84c8ef 147
d62a17ae 148 if (nh_data->tag == *tag)
149 return RMAP_MATCH;
150 }
151 return RMAP_NOMATCH;
ca84c8ef
DS
152}
153
ca84c8ef 154/* Route map commands for tag matching */
d62a17ae 155static struct route_map_rule_cmd route_match_tag_cmd = {
9d303b37 156 "tag", route_match_tag, route_map_rule_tag_compile,
d62a17ae 157 route_map_rule_tag_free,
ca84c8ef
DS
158};
159
6b0655a2 160
5921ef9a
PJ
161/* `match interface IFNAME' */
162/* Match function return 1 if match is success else return zero. */
d62a17ae 163static route_map_result_t route_match_interface(void *rule,
164 struct prefix *prefix,
165 route_map_object_t type,
166 void *object)
167{
168 struct nh_rmap_obj *nh_data;
169 char *ifname = rule;
170 ifindex_t ifindex;
171
172 if (type == RMAP_ZEBRA) {
173 if (strcasecmp(ifname, "any") == 0)
174 return RMAP_MATCH;
175 nh_data = object;
176 if (!nh_data || !nh_data->nexthop)
177 return RMAP_NOMATCH;
178 ifindex = ifname2ifindex(ifname, nh_data->vrf_id);
179 if (ifindex == 0)
180 return RMAP_NOMATCH;
181 if (nh_data->nexthop->ifindex == ifindex)
182 return RMAP_MATCH;
183 }
0032dd59 184 return RMAP_NOMATCH;
5921ef9a
PJ
185}
186
187/* Route map `match interface' match statement. `arg' is IFNAME value */
d62a17ae 188static void *route_match_interface_compile(const char *arg)
5921ef9a 189{
d62a17ae 190 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
5921ef9a
PJ
191}
192
193/* Free route map's compiled `match interface' value. */
d62a17ae 194static void route_match_interface_free(void *rule)
5921ef9a 195{
d62a17ae 196 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
5921ef9a
PJ
197}
198
199/* Route map commands for interface matching */
d62a17ae 200struct route_map_rule_cmd route_match_interface_cmd = {
201 "interface", route_match_interface, route_match_interface_compile,
202 route_match_interface_free};
5921ef9a 203
9f0ea7d4
DS
204DEFUN (match_ip_address_prefix_len,
205 match_ip_address_prefix_len_cmd,
7757e5e1 206 "match ip address prefix-len (0-32)",
9f0ea7d4
DS
207 MATCH_STR
208 IP_STR
209 "Match prefix length of ip address\n"
210 "Match prefix length of ip address\n"
211 "Prefix length\n")
212{
d62a17ae 213 return zebra_route_match_add(vty, "ip address prefix-len", argv[4]->arg,
214 RMAP_EVENT_MATCH_ADDED);
9f0ea7d4
DS
215}
216
217DEFUN (no_match_ip_address_prefix_len,
218 no_match_ip_address_prefix_len_cmd,
7757e5e1 219 "no match ip address prefix-len [(0-32)]",
9f0ea7d4
DS
220 NO_STR
221 MATCH_STR
222 IP_STR
16cedbb0
QY
223 "Match prefix length of ip address\n"
224 "Match prefix length of ip address\n"
7757e5e1 225 "Prefix length\n")
9f0ea7d4 226{
d62a17ae 227 char *plen = (argc == 6) ? argv[5]->arg : NULL;
228 return zebra_route_match_delete(vty, "ip address prefix-len", plen,
229 RMAP_EVENT_MATCH_DELETED);
9f0ea7d4
DS
230}
231
5165d46f
DS
232DEFUN (match_ipv6_address_prefix_len,
233 match_ipv6_address_prefix_len_cmd,
234 "match ipv6 address prefix-len (0-128)",
235 MATCH_STR
236 IPV6_STR
237 "Match prefix length of ipv6 address\n"
238 "Match prefix length of ipv6 address\n"
239 "Prefix length\n")
240{
996c9314
LB
241 return zebra_route_match_add(vty, "ipv6 address prefix-len",
242 argv[4]->arg, RMAP_EVENT_MATCH_ADDED);
5165d46f
DS
243}
244
245DEFUN (no_match_ipv6_address_prefix_len,
246 no_match_ipv6_address_prefix_len_cmd,
247 "no match ipv6 address prefix-len [(0-128)]",
248 NO_STR
249 MATCH_STR
250 IPV6_STR
251 "Match prefix length of ip address\n"
252 "Match prefix length of ip address\n"
253 "Prefix length\n")
254{
255 char *plen = (argc == 6) ? argv[5]->arg : NULL;
256 return zebra_route_match_delete(vty, "ipv6 address prefix-len", plen,
257 RMAP_EVENT_MATCH_DELETED);
258}
9f0ea7d4
DS
259
260DEFUN (match_ip_nexthop_prefix_len,
261 match_ip_nexthop_prefix_len_cmd,
7757e5e1 262 "match ip next-hop prefix-len (0-32)",
9f0ea7d4
DS
263 MATCH_STR
264 IP_STR
265 "Match prefixlen of nexthop ip address\n"
266 "Match prefixlen of given nexthop\n"
267 "Prefix length\n")
268{
d62a17ae 269 return zebra_route_match_add(vty, "ip next-hop prefix-len",
270 argv[4]->arg, RMAP_EVENT_MATCH_ADDED);
9f0ea7d4
DS
271}
272
273DEFUN (no_match_ip_nexthop_prefix_len,
274 no_match_ip_nexthop_prefix_len_cmd,
7757e5e1 275 "no match ip next-hop prefix-len [(0-32)]",
9f0ea7d4
DS
276 NO_STR
277 MATCH_STR
278 IP_STR
279 "Match prefixlen of nexthop ip address\n"
7757e5e1
QY
280 "Match prefix length of nexthop\n"
281 "Prefix length\n")
9f0ea7d4 282{
d62a17ae 283 char *plen = (argc == 6) ? argv[5]->arg : NULL;
284 return zebra_route_match_delete(vty, "ip next-hop prefix-len", plen,
285 RMAP_EVENT_MATCH_DELETED);
9f0ea7d4
DS
286}
287
9f0ea7d4
DS
288DEFUN (match_source_protocol,
289 match_source_protocol_cmd,
5b9471f9 290 "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>",
9f0ea7d4 291 MATCH_STR
16cedbb0
QY
292 "Match protocol via which the route was learnt\n"
293 "BGP protocol\n"
294 "OSPF protocol\n"
295 "RIP protocol\n"
296 "RIPNG protocol\n"
297 "ISIS protocol\n"
298 "OSPF6 protocol\n"
5b9471f9
JB
299 "PIM protocol\n"
300 "NHRP protocol\n"
301 "EIGRP protocol\n"
302 "BABEL protocol\n"
16cedbb0
QY
303 "Routes from directly connected peer\n"
304 "Routes from system configuration\n"
305 "Routes from kernel\n"
306 "Statically configured routes\n")
9f0ea7d4 307{
d62a17ae 308 char *proto = argv[2]->text;
309 int i;
9f0ea7d4 310
d62a17ae 311 i = proto_name2num(proto);
312 if (i < 0) {
313 vty_out(vty, "invalid protocol name \"%s\"\n", proto);
314 return CMD_WARNING_CONFIG_FAILED;
315 }
316 return zebra_route_match_add(vty, "source-protocol", proto,
317 RMAP_EVENT_MATCH_ADDED);
9f0ea7d4
DS
318}
319
320DEFUN (no_match_source_protocol,
321 no_match_source_protocol_cmd,
5b9471f9 322 "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>]",
9f0ea7d4
DS
323 NO_STR
324 MATCH_STR
7757e5e1 325 "No match protocol via which the route was learnt\n"
16cedbb0
QY
326 "BGP protocol\n"
327 "OSPF protocol\n"
328 "RIP protocol\n"
329 "RIPNG protocol\n"
330 "ISIS protocol\n"
331 "OSPF6 protocol\n"
5b9471f9
JB
332 "PIM protocol\n"
333 "NHRP protocol\n"
334 "EIGRP protocol\n"
335 "BABEL protocol\n"
16cedbb0
QY
336 "Routes from directly connected peer\n"
337 "Routes from system configuration\n"
338 "Routes from kernel\n"
339 "Statically configured routes\n")
9f0ea7d4 340{
d62a17ae 341 char *proto = (argc == 4) ? argv[3]->text : NULL;
342 return zebra_route_match_delete(vty, "source-protocol", proto,
343 RMAP_EVENT_MATCH_DELETED);
9f0ea7d4
DS
344}
345
5921ef9a
PJ
346/* set functions */
347
348DEFUN (set_src,
349 set_src_cmd,
6147e2c6 350 "set src <A.B.C.D|X:X::X:X>",
5921ef9a
PJ
351 SET_STR
352 "src address for route\n"
16cedbb0
QY
353 "IPv4 src address\n"
354 "IPv6 src address\n")
5921ef9a 355{
d62a17ae 356 int idx_ip = 2;
357 union g_addr src;
358 struct interface *pif = NULL;
359 int family;
360 struct prefix p;
361 struct vrf *vrf;
362
363 if (inet_pton(AF_INET, argv[idx_ip]->arg, &src.ipv4) != 1) {
364 if (inet_pton(AF_INET6, argv[idx_ip]->arg, &src.ipv6) != 1) {
365 vty_out(vty, "%% not a valid IPv4/v6 address\n");
366 return CMD_WARNING_CONFIG_FAILED;
367 }
368
369 p.family = family = AF_INET6;
370 p.u.prefix6 = src.ipv6;
371 p.prefixlen = IPV6_MAX_BITLEN;
372 } else {
373 p.family = family = AF_INET;
374 p.u.prefix4 = src.ipv4;
375 p.prefixlen = IPV4_MAX_BITLEN;
376 }
377
378 if (!zebra_check_addr(&p)) {
379 vty_out(vty, "%% not a valid source IPv4/v6 address\n");
380 return CMD_WARNING_CONFIG_FAILED;
381 }
5921ef9a 382
a2addae8 383 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
d62a17ae 384 if (family == AF_INET)
385 pif = if_lookup_exact_address((void *)&src.ipv4,
386 AF_INET, vrf->vrf_id);
387 else if (family == AF_INET6)
388 pif = if_lookup_exact_address((void *)&src.ipv6,
389 AF_INET6, vrf->vrf_id);
390
391 if (pif != NULL)
392 break;
0aabccc0
DD
393 }
394
d62a17ae 395 if (!pif) {
396 vty_out(vty, "%% not a local address\n");
397 return CMD_WARNING_CONFIG_FAILED;
398 }
399
400 VTY_DECLVAR_CONTEXT(route_map_index, index);
401 return generic_set_add(vty, index, "src", argv[idx_ip]->arg);
5921ef9a
PJ
402}
403
404DEFUN (no_set_src,
405 no_set_src_cmd,
7757e5e1 406 "no set src [<A.B.C.D|X:X::X:X>]",
5921ef9a
PJ
407 NO_STR
408 SET_STR
3a2d747c
QY
409 "Source address for route\n"
410 "IPv4 address\n"
411 "IPv6 address\n")
5921ef9a 412{
d62a17ae 413 char *ip = (argc == 4) ? argv[3]->arg : NULL;
414 VTY_DECLVAR_CONTEXT(route_map_index, index);
415 return generic_set_delete(vty, index, "src", ip);
5921ef9a
PJ
416}
417
518f0eb1
DS
418DEFUN (zebra_route_map_timer,
419 zebra_route_map_timer_cmd,
6147e2c6 420 "zebra route-map delay-timer (0-600)",
41e7fb80 421 ZEBRA_STR
16cedbb0 422 "Set route-map parameters\n"
9f0ea7d4
DS
423 "Time to wait before route-map updates are processed\n"
424 "0 means event-driven updates are disabled\n")
518f0eb1 425{
d62a17ae 426 int idx_number = 3;
d7c0a89a 427 uint32_t rmap_delay_timer;
518f0eb1 428
d62a17ae 429 rmap_delay_timer = strtoul(argv[idx_number]->arg, NULL, 10);
430 zebra_route_map_set_delay_timer(rmap_delay_timer);
518f0eb1 431
d62a17ae 432 return (CMD_SUCCESS);
518f0eb1
DS
433}
434
435DEFUN (no_zebra_route_map_timer,
436 no_zebra_route_map_timer_cmd,
7757e5e1 437 "no zebra route-map delay-timer [(0-600)]",
518f0eb1 438 NO_STR
41e7fb80 439 ZEBRA_STR
16cedbb0 440 "Set route-map parameters\n"
7757e5e1
QY
441 "Reset delay-timer to default value, 30 secs\n"
442 "0 means event-driven updates are disabled\n")
518f0eb1 443{
d62a17ae 444 zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER);
518f0eb1 445
d62a17ae 446 return (CMD_SUCCESS);
518f0eb1
DS
447}
448
813d4307 449
518f0eb1
DS
450DEFUN (ip_protocol,
451 ip_protocol_cmd,
40d1cbfb 452 "ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
9f0ea7d4
DS
453 IP_STR
454 "Filter routing info exchanged between zebra and protocol\n"
ab0181ee 455 FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
7757e5e1 456 "Specify route-map\n"
518f0eb1
DS
457 "Route map name\n")
458{
d62a17ae 459 char *proto = argv[2]->text;
460 char *rmap = argv[4]->arg;
461 int i;
462
463 if (strcasecmp(proto, "any") == 0)
464 i = ZEBRA_ROUTE_MAX;
465 else
466 i = proto_name2num(proto);
467 if (i < 0) {
468 vty_out(vty, "invalid protocol name \"%s\"\n", proto);
469 return CMD_WARNING_CONFIG_FAILED;
470 }
471 if (proto_rm[AFI_IP][i]) {
472 if (strcmp(proto_rm[AFI_IP][i], rmap) == 0)
473 return CMD_SUCCESS;
518f0eb1 474
d62a17ae 475 XFREE(MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
476 }
477 proto_rm[AFI_IP][i] = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
b84c7253 478
d62a17ae 479 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
480 zlog_debug(
481 "%u: IPv4 Routemap config for protocol %s, scheduling RIB processing",
482 VRF_DEFAULT, proto);
b84c7253 483
d62a17ae 484 rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
485 return CMD_SUCCESS;
518f0eb1
DS
486}
487
488DEFUN (no_ip_protocol,
489 no_ip_protocol_cmd,
40d1cbfb 490 "no ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA " [route-map ROUTE-MAP]",
518f0eb1 491 NO_STR
9f0ea7d4
DS
492 IP_STR
493 "Stop filtering routing info between zebra and protocol\n"
ab0181ee 494 FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
7757e5e1
QY
495 "Specify route map\n"
496 "Route map name\n")
518f0eb1 497{
d62a17ae 498 char *proto = argv[3]->text;
499 char *rmap = (argc == 6) ? argv[5]->arg : NULL;
500 int i;
518f0eb1 501
d62a17ae 502 if (strcasecmp(proto, "any") == 0)
503 i = ZEBRA_ROUTE_MAX;
504 else
505 i = proto_name2num(proto);
7757e5e1 506
d62a17ae 507 if (i < 0) {
508 vty_out(vty, "invalid protocol name \"%s\"\n", proto);
509 return CMD_WARNING_CONFIG_FAILED;
510 }
7757e5e1 511
d62a17ae 512 if (!proto_rm[AFI_IP][i])
513 return CMD_SUCCESS;
518f0eb1 514
d62a17ae 515 if (!rmap || strcmp(rmap, proto_rm[AFI_IP][i]) == 0) {
516 XFREE(MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
517 proto_rm[AFI_IP][i] = NULL;
b84c7253 518
d62a17ae 519 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
520 zlog_debug(
521 "%u: IPv4 Routemap unconfig for protocol %s, scheduling RIB processing",
522 VRF_DEFAULT, proto);
523 rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
524 }
525 return CMD_SUCCESS;
518f0eb1
DS
526}
527
528DEFUN (show_ip_protocol,
529 show_ip_protocol_cmd,
530 "show ip protocol",
531 SHOW_STR
532 IP_STR
533 "IP protocol filtering status\n")
534{
d62a17ae 535 int i;
518f0eb1 536
d62a17ae 537 vty_out(vty, "Protocol : route-map \n");
538 vty_out(vty, "------------------------\n");
539 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
540 if (proto_rm[AFI_IP][i])
541 vty_out(vty, "%-10s : %-10s\n", zebra_route_string(i),
542 proto_rm[AFI_IP][i]);
543 else
544 vty_out(vty, "%-10s : none\n", zebra_route_string(i));
545 }
546 if (proto_rm[AFI_IP][i])
547 vty_out(vty, "%-10s : %-10s\n", "any", proto_rm[AFI_IP][i]);
548 else
549 vty_out(vty, "%-10s : none\n", "any");
518f0eb1 550
d62a17ae 551 return CMD_SUCCESS;
518f0eb1
DS
552}
553
0aabccc0
DD
554DEFUN (ipv6_protocol,
555 ipv6_protocol_cmd,
40d1cbfb 556 "ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
0aabccc0
DD
557 IP6_STR
558 "Filter IPv6 routing info exchanged between zebra and protocol\n"
ab0181ee 559 FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
7757e5e1 560 "Specify route map\n"
0aabccc0
DD
561 "Route map name\n")
562{
d62a17ae 563 char *proto = argv[2]->text;
564 char *rmap = argv[4]->arg;
565 int i;
566
567 if (strcasecmp(proto, "any") == 0)
568 i = ZEBRA_ROUTE_MAX;
569 else
570 i = proto_name2num(proto);
571 if (i < 0) {
572 vty_out(vty, "invalid protocol name \"%s\"\n", proto);
573 return CMD_WARNING_CONFIG_FAILED;
574 }
575 if (proto_rm[AFI_IP6][i]) {
576 if (strcmp(proto_rm[AFI_IP6][i], rmap) == 0)
577 return CMD_SUCCESS;
0aabccc0 578
d62a17ae 579 XFREE(MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP6][i]);
580 }
581 proto_rm[AFI_IP6][i] = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
b84c7253 582
d62a17ae 583 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
584 zlog_debug(
585 "%u: IPv6 Routemap config for protocol %s, scheduling RIB processing",
586 VRF_DEFAULT, proto);
b84c7253 587
d62a17ae 588 rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
589 return CMD_SUCCESS;
0aabccc0
DD
590}
591
592DEFUN (no_ipv6_protocol,
593 no_ipv6_protocol_cmd,
40d1cbfb 594 "no ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA " [route-map ROUTE-MAP]",
0aabccc0
DD
595 NO_STR
596 IP6_STR
597 "Stop filtering IPv6 routing info between zebra and protocol\n"
ab0181ee 598 FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
7757e5e1
QY
599 "Specify route map\n"
600 "Route map name\n")
0aabccc0 601{
d62a17ae 602 const char *proto = argv[3]->text;
603 const char *rmap = (argc == 6) ? argv[5]->arg : NULL;
604 int i;
605
606 if (strcasecmp(proto, "any") == 0)
607 i = ZEBRA_ROUTE_MAX;
608 else
609 i = proto_name2num(proto);
610 if (i < 0) {
611 vty_out(vty, "invalid protocol name \"%s\"\n", proto);
612 return CMD_WARNING_CONFIG_FAILED;
613 }
614 if (!proto_rm[AFI_IP6][i])
615 return CMD_SUCCESS;
0aabccc0 616
d62a17ae 617 if (!rmap || strcmp(rmap, proto_rm[AFI_IP6][i]) == 0) {
618 XFREE(MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP6][i]);
619 proto_rm[AFI_IP6][i] = NULL;
b84c7253 620
d62a17ae 621 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
622 zlog_debug(
623 "%u: IPv6 Routemap unconfig for protocol %s, scheduling RIB processing",
624 VRF_DEFAULT, proto);
b84c7253 625
d62a17ae 626 rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
627 }
628 return CMD_SUCCESS;
0aabccc0
DD
629}
630
0aabccc0
DD
631DEFUN (show_ipv6_protocol,
632 show_ipv6_protocol_cmd,
633 "show ipv6 protocol",
634 SHOW_STR
635 IP6_STR
636 "IPv6 protocol filtering status\n")
637{
d62a17ae 638 int i;
0aabccc0 639
d62a17ae 640 vty_out(vty, "Protocol : route-map \n");
641 vty_out(vty, "------------------------\n");
642 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
643 if (proto_rm[AFI_IP6][i])
644 vty_out(vty, "%-10s : %-10s\n", zebra_route_string(i),
645 proto_rm[AFI_IP6][i]);
646 else
647 vty_out(vty, "%-10s : none\n", zebra_route_string(i));
648 }
649 if (proto_rm[AFI_IP6][i])
650 vty_out(vty, "%-10s : %-10s\n", "any", proto_rm[AFI_IP6][i]);
651 else
652 vty_out(vty, "%-10s : none\n", "any");
0aabccc0 653
d62a17ae 654 return CMD_SUCCESS;
0aabccc0
DD
655}
656
9f0ea7d4
DS
657DEFUN (ip_protocol_nht_rmap,
658 ip_protocol_nht_rmap_cmd,
40d1cbfb 659 "ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
9f0ea7d4
DS
660 IP_STR
661 "Filter Next Hop tracking route resolution\n"
ab0181ee 662 FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
7757e5e1 663 "Specify route map\n"
9f0ea7d4
DS
664 "Route map name\n")
665{
d62a17ae 666 char *proto = argv[2]->text;
667 char *rmap = argv[4]->arg;
668 int i;
669
670 if (strcasecmp(proto, "any") == 0)
671 i = ZEBRA_ROUTE_MAX;
672 else
673 i = proto_name2num(proto);
674 if (i < 0) {
675 vty_out(vty, "invalid protocol name \"%s\"\n", proto);
676 return CMD_WARNING_CONFIG_FAILED;
677 }
678 if (nht_rm[AFI_IP][i]) {
679 if (strcmp(nht_rm[AFI_IP][i], rmap) == 0)
680 return CMD_SUCCESS;
9f0ea7d4 681
d62a17ae 682 XFREE(MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]);
683 }
9f0ea7d4 684
d62a17ae 685 nht_rm[AFI_IP][i] = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
686 zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
9f0ea7d4 687
d62a17ae 688 return CMD_SUCCESS;
9f0ea7d4
DS
689}
690
691DEFUN (no_ip_protocol_nht_rmap,
692 no_ip_protocol_nht_rmap_cmd,
40d1cbfb 693 "no ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA " [route-map ROUTE-MAP]",
9f0ea7d4
DS
694 NO_STR
695 IP_STR
696 "Filter Next Hop tracking route resolution\n"
3b14d86e 697 FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
7757e5e1
QY
698 "Specify route map\n"
699 "Route map name\n")
9f0ea7d4 700{
d62a17ae 701 int idx = 0;
702 char *proto = argv[3]->text;
703 char *rmap = argv_find(argv, argc, "ROUTE-MAP", &idx) ? argv[idx]->arg
704 : NULL;
55cb6743 705
d62a17ae 706 int i = strmatch(proto, "any") ? ZEBRA_ROUTE_MAX
707 : proto_name2num(proto);
9f0ea7d4 708
d62a17ae 709 if (i < 0) {
710 vty_out(vty, "invalid protocol name \"%s\"\n", proto);
711 return CMD_WARNING_CONFIG_FAILED;
712 }
55cb6743 713
d62a17ae 714 if (!nht_rm[AFI_IP][i])
715 return CMD_SUCCESS;
9f0ea7d4 716
d62a17ae 717 if (!rmap || strcmp(rmap, nht_rm[AFI_IP][i]) == 0) {
718 XFREE(MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]);
719 nht_rm[AFI_IP][i] = NULL;
720 zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
721 }
722 return CMD_SUCCESS;
9f0ea7d4
DS
723}
724
9f0ea7d4
DS
725DEFUN (show_ip_protocol_nht,
726 show_ip_protocol_nht_cmd,
727 "show ip nht route-map",
3a2d747c
QY
728 SHOW_STR
729 IP_STR
730 "IP nexthop tracking table\n"
9f0ea7d4
DS
731 "IP Next Hop tracking filtering status\n")
732{
d62a17ae 733 int i;
9f0ea7d4 734
d62a17ae 735 vty_out(vty, "Protocol : route-map \n");
736 vty_out(vty, "------------------------\n");
737 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
738 if (nht_rm[AFI_IP][i])
739 vty_out(vty, "%-10s : %-10s\n", zebra_route_string(i),
740 nht_rm[AFI_IP][i]);
741 else
742 vty_out(vty, "%-10s : none\n", zebra_route_string(i));
743 }
744 if (nht_rm[AFI_IP][i])
745 vty_out(vty, "%-10s : %-10s\n", "any", nht_rm[AFI_IP][i]);
746 else
747 vty_out(vty, "%-10s : none\n", "any");
9f0ea7d4 748
d62a17ae 749 return CMD_SUCCESS;
9f0ea7d4
DS
750}
751
752DEFUN (ipv6_protocol_nht_rmap,
753 ipv6_protocol_nht_rmap_cmd,
40d1cbfb 754 "ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
9f0ea7d4
DS
755 IP6_STR
756 "Filter Next Hop tracking route resolution\n"
ab0181ee 757 FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
7757e5e1 758 "Specify route map\n"
9f0ea7d4
DS
759 "Route map name\n")
760{
d62a17ae 761 char *proto = argv[2]->text;
762 char *rmap = argv[4]->arg;
763 int i;
764
765 if (strcasecmp(proto, "any") == 0)
766 i = ZEBRA_ROUTE_MAX;
767 else
768 i = proto_name2num(proto);
769 if (i < 0) {
770 vty_out(vty, "invalid protocol name \"%s\"\n", proto);
771 return CMD_WARNING_CONFIG_FAILED;
772 }
773 if (nht_rm[AFI_IP6][i])
774 XFREE(MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
775 nht_rm[AFI_IP6][i] = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
776 zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
9f0ea7d4 777
d62a17ae 778 return CMD_SUCCESS;
9f0ea7d4
DS
779}
780
781DEFUN (no_ipv6_protocol_nht_rmap,
782 no_ipv6_protocol_nht_rmap_cmd,
40d1cbfb 783 "no ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA " [route-map ROUTE-MAP]",
9f0ea7d4
DS
784 NO_STR
785 IP6_STR
786 "Filter Next Hop tracking route resolution\n"
3b14d86e 787 FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
7757e5e1
QY
788 "Specify route map\n"
789 "Route map name\n")
9f0ea7d4 790{
d62a17ae 791 char *proto = argv[3]->text;
792 char *rmap = (argc == 6) ? argv[5]->arg : NULL;
793 int i;
794
795 if (strcasecmp(proto, "any") == 0)
796 i = ZEBRA_ROUTE_MAX;
797 else
798 i = proto_name2num(proto);
799 if (i < 0) {
800 vty_out(vty, "invalid protocol name \"%s\"\n", proto);
801 return CMD_WARNING_CONFIG_FAILED;
802 }
9f0ea7d4 803
d62a17ae 804 if (nht_rm[AFI_IP6][i] && rmap && strcmp(rmap, nht_rm[AFI_IP6][i])) {
805 vty_out(vty, "invalid route-map \"%s\"\n", rmap);
806 return CMD_WARNING_CONFIG_FAILED;
807 }
813d4307 808
d62a17ae 809 if (nht_rm[AFI_IP6][i]) {
810 XFREE(MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
811 nht_rm[AFI_IP6][i] = NULL;
812 }
9f0ea7d4 813
d62a17ae 814 zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
813d4307 815
d62a17ae 816 return CMD_SUCCESS;
9f0ea7d4
DS
817}
818
9f0ea7d4
DS
819DEFUN (show_ipv6_protocol_nht,
820 show_ipv6_protocol_nht_cmd,
821 "show ipv6 nht route-map",
3a2d747c
QY
822 SHOW_STR
823 IP6_STR
824 "Next Hop filtering status\n"
825 "Route-map\n")
9f0ea7d4 826{
d62a17ae 827 int i;
9f0ea7d4 828
d62a17ae 829 vty_out(vty, "Protocol : route-map \n");
830 vty_out(vty, "------------------------\n");
831 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
832 if (nht_rm[AFI_IP6][i])
833 vty_out(vty, "%-10s : %-10s\n", zebra_route_string(i),
834 nht_rm[AFI_IP6][i]);
835 else
836 vty_out(vty, "%-10s : none\n", zebra_route_string(i));
837 }
838 if (nht_rm[AFI_IP][i])
839 vty_out(vty, "%-10s : %-10s\n", "any", nht_rm[AFI_IP6][i]);
840 else
841 vty_out(vty, "%-10s : none\n", "any");
9f0ea7d4 842
d62a17ae 843 return CMD_SUCCESS;
9f0ea7d4
DS
844}
845
5921ef9a
PJ
846/*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
847
848/* `match ip next-hop IP_ACCESS_LIST' */
849
850/* Match function return 1 if match is success else return zero. */
d62a17ae 851static route_map_result_t route_match_ip_next_hop(void *rule,
852 struct prefix *prefix,
853 route_map_object_t type,
854 void *object)
855{
856 struct access_list *alist;
857 struct nh_rmap_obj *nh_data;
858 struct prefix_ipv4 p;
859
860 if (type == RMAP_ZEBRA) {
861 nh_data = object;
862 if (!nh_data)
863 return RMAP_DENYMATCH;
864
865 switch (nh_data->nexthop->type) {
866 case NEXTHOP_TYPE_IFINDEX:
867 /* Interface routes can't match ip next-hop */
868 return RMAP_NOMATCH;
869 case NEXTHOP_TYPE_IPV4_IFINDEX:
870 case NEXTHOP_TYPE_IPV4:
871 p.family = AF_INET;
872 p.prefix = nh_data->nexthop->gate.ipv4;
873 p.prefixlen = IPV4_MAX_BITLEN;
874 break;
875 default:
876 return RMAP_NOMATCH;
877 }
878 alist = access_list_lookup(AFI_IP, (char *)rule);
879 if (alist == NULL)
880 return RMAP_NOMATCH;
881
882 return (access_list_apply(alist, &p) == FILTER_DENY
883 ? RMAP_NOMATCH
884 : RMAP_MATCH);
885 }
5921ef9a 886 return RMAP_NOMATCH;
5921ef9a
PJ
887}
888
889/* Route map `ip next-hop' match statement. `arg' should be
890 access-list name. */
d62a17ae 891static void *route_match_ip_next_hop_compile(const char *arg)
5921ef9a 892{
d62a17ae 893 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
5921ef9a
PJ
894}
895
896/* Free route map's compiled `. */
d62a17ae 897static void route_match_ip_next_hop_free(void *rule)
5921ef9a 898{
d62a17ae 899 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
5921ef9a
PJ
900}
901
902/* Route map commands for ip next-hop matching. */
d62a17ae 903static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
904 "ip next-hop", route_match_ip_next_hop, route_match_ip_next_hop_compile,
905 route_match_ip_next_hop_free};
6b0655a2 906
5921ef9a
PJ
907/* `match ip next-hop prefix-list PREFIX_LIST' */
908
909static route_map_result_t
d62a17ae 910route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix,
911 route_map_object_t type, void *object)
5921ef9a 912{
d62a17ae 913 struct prefix_list *plist;
914 struct nh_rmap_obj *nh_data;
915 struct prefix_ipv4 p;
916
917 if (type == RMAP_ZEBRA) {
918 nh_data = (struct nh_rmap_obj *)object;
919 if (!nh_data)
920 return RMAP_DENYMATCH;
921
922 switch (nh_data->nexthop->type) {
923 case NEXTHOP_TYPE_IFINDEX:
924 /* Interface routes can't match ip next-hop */
925 return RMAP_NOMATCH;
926 case NEXTHOP_TYPE_IPV4_IFINDEX:
927 case NEXTHOP_TYPE_IPV4:
928 p.family = AF_INET;
929 p.prefix = nh_data->nexthop->gate.ipv4;
930 p.prefixlen = IPV4_MAX_BITLEN;
931 break;
932 default:
933 return RMAP_NOMATCH;
934 }
935 plist = prefix_list_lookup(AFI_IP, (char *)rule);
936 if (plist == NULL)
937 return RMAP_NOMATCH;
938
939 return (prefix_list_apply(plist, &p) == PREFIX_DENY
940 ? RMAP_NOMATCH
941 : RMAP_MATCH);
942 }
943 return RMAP_NOMATCH;
5921ef9a
PJ
944}
945
d62a17ae 946static void *route_match_ip_next_hop_prefix_list_compile(const char *arg)
5921ef9a 947{
d62a17ae 948 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
5921ef9a
PJ
949}
950
d62a17ae 951static void route_match_ip_next_hop_prefix_list_free(void *rule)
5921ef9a 952{
d62a17ae 953 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
5921ef9a
PJ
954}
955
d62a17ae 956static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
957 "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list,
958 route_match_ip_next_hop_prefix_list_compile,
959 route_match_ip_next_hop_prefix_list_free};
6b0655a2 960
5921ef9a
PJ
961/* `match ip address IP_ACCESS_LIST' */
962
963/* Match function should return 1 if match is success else return
964 zero. */
d62a17ae 965static route_map_result_t route_match_ip_address(void *rule,
966 struct prefix *prefix,
967 route_map_object_t type,
968 void *object)
5921ef9a 969{
d62a17ae 970 struct access_list *alist;
971
972 if (type == RMAP_ZEBRA) {
973 alist = access_list_lookup(AFI_IP, (char *)rule);
974 if (alist == NULL)
975 return RMAP_NOMATCH;
5921ef9a 976
d62a17ae 977 return (access_list_apply(alist, prefix) == FILTER_DENY
978 ? RMAP_NOMATCH
979 : RMAP_MATCH);
980 }
5921ef9a 981 return RMAP_NOMATCH;
5921ef9a
PJ
982}
983
984/* Route map `ip address' match statement. `arg' should be
985 access-list name. */
d62a17ae 986static void *route_match_ip_address_compile(const char *arg)
5921ef9a 987{
d62a17ae 988 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
5921ef9a
PJ
989}
990
991/* Free route map's compiled `ip address' value. */
d62a17ae 992static void route_match_ip_address_free(void *rule)
5921ef9a 993{
d62a17ae 994 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
5921ef9a
PJ
995}
996
997/* Route map commands for ip address matching. */
d62a17ae 998static struct route_map_rule_cmd route_match_ip_address_cmd = {
999 "ip address", route_match_ip_address, route_match_ip_address_compile,
1000 route_match_ip_address_free};
6b0655a2 1001
5921ef9a
PJ
1002/* `match ip address prefix-list PREFIX_LIST' */
1003
1004static route_map_result_t
d62a17ae 1005route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
1006 route_map_object_t type, void *object)
5921ef9a 1007{
d62a17ae 1008 struct prefix_list *plist;
1009
1010 if (type == RMAP_ZEBRA) {
1011 plist = prefix_list_lookup(AFI_IP, (char *)rule);
1012 if (plist == NULL)
1013 return RMAP_NOMATCH;
5921ef9a 1014
d62a17ae 1015 return (prefix_list_apply(plist, prefix) == PREFIX_DENY
1016 ? RMAP_NOMATCH
1017 : RMAP_MATCH);
1018 }
5921ef9a 1019 return RMAP_NOMATCH;
5921ef9a
PJ
1020}
1021
d62a17ae 1022static void *route_match_ip_address_prefix_list_compile(const char *arg)
5921ef9a 1023{
d62a17ae 1024 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
5921ef9a
PJ
1025}
1026
d62a17ae 1027static void route_match_ip_address_prefix_list_free(void *rule)
5921ef9a 1028{
d62a17ae 1029 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
5921ef9a
PJ
1030}
1031
d62a17ae 1032static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
1033 "ip address prefix-list", route_match_ip_address_prefix_list,
1034 route_match_ip_address_prefix_list_compile,
1035 route_match_ip_address_prefix_list_free};
5921ef9a 1036
6b0655a2 1037
9f0ea7d4
DS
1038/* `match ip address prefix-len PREFIXLEN' */
1039
1040static route_map_result_t
5165d46f
DS
1041route_match_address_prefix_len(void *rule, struct prefix *prefix,
1042 route_map_object_t type, void *object)
9f0ea7d4 1043{
d7c0a89a 1044 uint32_t *prefixlen = (uint32_t *)rule;
9f0ea7d4 1045
d62a17ae 1046 if (type == RMAP_ZEBRA) {
1047 return ((prefix->prefixlen == *prefixlen) ? RMAP_MATCH
1048 : RMAP_NOMATCH);
1049 }
1050 return RMAP_NOMATCH;
9f0ea7d4
DS
1051}
1052
5165d46f 1053static void *route_match_address_prefix_len_compile(const char *arg)
9f0ea7d4 1054{
d7c0a89a 1055 uint32_t *prefix_len;
d62a17ae 1056 char *endptr = NULL;
1057 unsigned long tmpval;
9f0ea7d4 1058
d62a17ae 1059 /* prefix len value shoud be integer. */
1060 if (!all_digit(arg))
1061 return NULL;
9f0ea7d4 1062
d62a17ae 1063 errno = 0;
1064 tmpval = strtoul(arg, &endptr, 10);
1065 if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
1066 return NULL;
9f0ea7d4 1067
d7c0a89a 1068 prefix_len = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
9f0ea7d4 1069
d62a17ae 1070 if (!prefix_len)
1071 return prefix_len;
9f0ea7d4 1072
d62a17ae 1073 *prefix_len = tmpval;
1074 return prefix_len;
9f0ea7d4
DS
1075}
1076
5165d46f 1077static void route_match_address_prefix_len_free(void *rule)
9f0ea7d4 1078{
d62a17ae 1079 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
9f0ea7d4
DS
1080}
1081
d62a17ae 1082static struct route_map_rule_cmd route_match_ip_address_prefix_len_cmd = {
5165d46f
DS
1083 "ip address prefix-len", route_match_address_prefix_len,
1084 route_match_address_prefix_len_compile,
1085 route_match_address_prefix_len_free};
9f0ea7d4 1086
5165d46f
DS
1087static struct route_map_rule_cmd route_match_ipv6_address_prefix_len_cmd = {
1088 "ipv6 address prefix-len", route_match_address_prefix_len,
1089 route_match_address_prefix_len_compile,
1090 route_match_address_prefix_len_free};
9f0ea7d4
DS
1091
1092/* `match ip nexthop prefix-len PREFIXLEN' */
1093
1094static route_map_result_t
d62a17ae 1095route_match_ip_nexthop_prefix_len(void *rule, struct prefix *prefix,
1096 route_map_object_t type, void *object)
1097{
d7c0a89a 1098 uint32_t *prefixlen = (uint32_t *)rule;
d62a17ae 1099 struct nh_rmap_obj *nh_data;
1100 struct prefix_ipv4 p;
1101
1102 if (type == RMAP_ZEBRA) {
1103 nh_data = (struct nh_rmap_obj *)object;
1104 if (!nh_data || !nh_data->nexthop)
1105 return RMAP_DENYMATCH;
1106
1107 switch (nh_data->nexthop->type) {
1108 case NEXTHOP_TYPE_IFINDEX:
1109 /* Interface routes can't match ip next-hop */
1110 return RMAP_NOMATCH;
1111 case NEXTHOP_TYPE_IPV4_IFINDEX:
1112 case NEXTHOP_TYPE_IPV4:
1113 p.family = AF_INET;
1114 p.prefix = nh_data->nexthop->gate.ipv4;
1115 p.prefixlen = IPV4_MAX_BITLEN;
1116 break;
1117 default:
1118 return RMAP_NOMATCH;
1119 }
1120 return ((p.prefixlen == *prefixlen) ? RMAP_MATCH
1121 : RMAP_NOMATCH);
1122 }
1123 return RMAP_NOMATCH;
1124}
1125
1126static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd = {
1127 "ip next-hop prefix-len", route_match_ip_nexthop_prefix_len,
5165d46f
DS
1128 route_match_address_prefix_len_compile, /* reuse */
1129 route_match_address_prefix_len_free /* reuse */
9f0ea7d4
DS
1130};
1131
1132/* `match source-protocol PROTOCOL' */
1133
d62a17ae 1134static route_map_result_t route_match_source_protocol(void *rule,
1135 struct prefix *prefix,
1136 route_map_object_t type,
1137 void *object)
9f0ea7d4 1138{
d7c0a89a 1139 uint32_t *rib_type = (uint32_t *)rule;
d62a17ae 1140 struct nh_rmap_obj *nh_data;
9f0ea7d4 1141
d62a17ae 1142 if (type == RMAP_ZEBRA) {
1143 nh_data = (struct nh_rmap_obj *)object;
1144 if (!nh_data)
1145 return RMAP_DENYMATCH;
9f0ea7d4 1146
d62a17ae 1147 return ((nh_data->source_protocol == *rib_type) ? RMAP_MATCH
1148 : RMAP_NOMATCH);
1149 }
1150 return RMAP_NOMATCH;
9f0ea7d4
DS
1151}
1152
d62a17ae 1153static void *route_match_source_protocol_compile(const char *arg)
9f0ea7d4 1154{
d7c0a89a 1155 uint32_t *rib_type;
d62a17ae 1156 int i;
9f0ea7d4 1157
d62a17ae 1158 i = proto_name2num(arg);
d7c0a89a 1159 rib_type = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
9f0ea7d4 1160
d62a17ae 1161 *rib_type = i;
9f0ea7d4 1162
d62a17ae 1163 return rib_type;
9f0ea7d4
DS
1164}
1165
d62a17ae 1166static void route_match_source_protocol_free(void *rule)
9f0ea7d4 1167{
d62a17ae 1168 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
9f0ea7d4
DS
1169}
1170
d62a17ae 1171static struct route_map_rule_cmd route_match_source_protocol_cmd = {
1172 "source-protocol", route_match_source_protocol,
1173 route_match_source_protocol_compile, route_match_source_protocol_free};
9f0ea7d4 1174
5921ef9a
PJ
1175/* `set src A.B.C.D' */
1176
1177/* Set src. */
d62a17ae 1178static route_map_result_t route_set_src(void *rule, struct prefix *prefix,
1179 route_map_object_t type, void *object)
5921ef9a 1180{
d62a17ae 1181 struct nh_rmap_obj *nh_data;
9f0ea7d4 1182
d62a17ae 1183 if (type == RMAP_ZEBRA) {
1184 nh_data = (struct nh_rmap_obj *)object;
1185 nh_data->nexthop->rmap_src = *(union g_addr *)rule;
1186 }
1187 return RMAP_OKAY;
5921ef9a
PJ
1188}
1189
1190/* set src compilation. */
d62a17ae 1191static void *route_set_src_compile(const char *arg)
5921ef9a 1192{
d62a17ae 1193 union g_addr src, *psrc;
5921ef9a 1194
d62a17ae 1195 if ((inet_pton(AF_INET6, arg, &src.ipv6) == 1)
17a21721 1196 || (inet_pton(AF_INET, arg, &src.ipv4) == 1)) {
d62a17ae 1197 psrc = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(union g_addr));
1198 *psrc = src;
1199 return psrc;
1200 }
1201 return NULL;
5921ef9a
PJ
1202}
1203
1204/* Free route map's compiled `set src' value. */
d62a17ae 1205static void route_set_src_free(void *rule)
5921ef9a 1206{
d62a17ae 1207 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
5921ef9a
PJ
1208}
1209
1210/* Set src rule structure. */
d62a17ae 1211static struct route_map_rule_cmd route_set_src_cmd = {
9d303b37 1212 "src", route_set_src, route_set_src_compile, route_set_src_free,
5921ef9a
PJ
1213};
1214
d62a17ae 1215static int zebra_route_map_update_timer(struct thread *thread)
518f0eb1 1216{
d62a17ae 1217 zebra_t_rmap_update = NULL;
518f0eb1 1218
d62a17ae 1219 if (IS_ZEBRA_DEBUG_EVENT)
1220 zlog_debug("Event driven route-map update triggered");
518f0eb1 1221
d62a17ae 1222 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1223 zlog_debug(
1224 "%u: Routemap update-timer fired, scheduling RIB processing",
1225 VRF_DEFAULT);
b84c7253 1226
d62a17ae 1227 zebra_import_table_rm_update();
1228 rib_update(VRF_DEFAULT, RIB_UPDATE_RMAP_CHANGE);
1229 zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
1230 zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
9f0ea7d4 1231
d62a17ae 1232 return (0);
518f0eb1
DS
1233}
1234
d7c0a89a 1235static void zebra_route_map_set_delay_timer(uint32_t value)
518f0eb1 1236{
d62a17ae 1237 zebra_rmap_update_timer = value;
1238 if (!value && zebra_t_rmap_update) {
1239 /* Event driven route map updates is being disabled */
1240 /* But there's a pending timer. Fire it off now */
1241 thread_cancel(zebra_t_rmap_update);
1242 zebra_route_map_update_timer(zebra_t_rmap_update);
1243 }
518f0eb1
DS
1244}
1245
d62a17ae 1246void zebra_route_map_write_delay_timer(struct vty *vty)
518f0eb1 1247{
d62a17ae 1248 if (vty && (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER))
1249 vty_out(vty, "zebra route-map delay-timer %d\n",
1250 zebra_rmap_update_timer);
1251 return;
518f0eb1
DS
1252}
1253
d62a17ae 1254route_map_result_t zebra_route_map_check(int family, int rib_type,
1255 struct prefix *p,
1256 struct nexthop *nexthop,
1257 vrf_id_t vrf_id, route_tag_t tag)
518f0eb1 1258{
d62a17ae 1259 struct route_map *rmap = NULL;
1260 route_map_result_t ret = RMAP_MATCH;
1261 struct nh_rmap_obj nh_obj;
9f0ea7d4 1262
d62a17ae 1263 nh_obj.nexthop = nexthop;
1264 nh_obj.vrf_id = vrf_id;
1265 nh_obj.source_protocol = rib_type;
1266 nh_obj.metric = 0;
1267 nh_obj.tag = tag;
518f0eb1 1268
d62a17ae 1269 if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX)
1270 rmap = route_map_lookup_by_name(proto_rm[family][rib_type]);
1271 if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
1272 rmap = route_map_lookup_by_name(
1273 proto_rm[family][ZEBRA_ROUTE_MAX]);
1274 if (rmap) {
1275 ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
1276 }
9f0ea7d4 1277
d62a17ae 1278 return (ret);
9f0ea7d4
DS
1279}
1280
d62a17ae 1281char *zebra_get_import_table_route_map(afi_t afi, uint32_t table)
8902474b 1282{
d62a17ae 1283 return zebra_import_table_routemap[afi][table];
8902474b
DS
1284}
1285
d62a17ae 1286void zebra_add_import_table_route_map(afi_t afi, const char *rmap_name,
1287 uint32_t table)
8902474b 1288{
d62a17ae 1289 zebra_import_table_routemap[afi][table] =
1290 XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
8902474b
DS
1291}
1292
d62a17ae 1293void zebra_del_import_table_route_map(afi_t afi, uint32_t table)
8902474b 1294{
d62a17ae 1295 XFREE(MTYPE_ROUTE_MAP_NAME, zebra_import_table_routemap[afi][table]);
8902474b
DS
1296}
1297
1298route_map_result_t
d62a17ae 1299zebra_import_table_route_map_check(int family, int re_type, struct prefix *p,
1300 struct nexthop *nexthop, vrf_id_t vrf_id,
1301 route_tag_t tag, const char *rmap_name)
1302{
1303 struct route_map *rmap = NULL;
1304 route_map_result_t ret = RMAP_DENYMATCH;
1305 struct nh_rmap_obj nh_obj;
1306
1307 nh_obj.nexthop = nexthop;
1308 nh_obj.vrf_id = vrf_id;
1309 nh_obj.source_protocol = re_type;
1310 nh_obj.metric = 0;
1311 nh_obj.tag = tag;
1312
1313 if (re_type >= 0 && re_type < ZEBRA_ROUTE_MAX)
1314 rmap = route_map_lookup_by_name(rmap_name);
1315 if (rmap) {
1316 ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
1317 }
8902474b 1318
d62a17ae 1319 return (ret);
8902474b
DS
1320}
1321
d62a17ae 1322route_map_result_t zebra_nht_route_map_check(int family, int client_proto,
1323 struct prefix *p,
1324 struct route_entry *re,
1325 struct nexthop *nexthop)
9f0ea7d4 1326{
d62a17ae 1327 struct route_map *rmap = NULL;
1328 route_map_result_t ret = RMAP_MATCH;
1329 struct nh_rmap_obj nh_obj;
9f0ea7d4 1330
d62a17ae 1331 nh_obj.nexthop = nexthop;
4a7371e9 1332 nh_obj.vrf_id = nexthop->vrf_id;
d62a17ae 1333 nh_obj.source_protocol = re->type;
1334 nh_obj.metric = re->metric;
1335 nh_obj.tag = re->tag;
9f0ea7d4 1336
d62a17ae 1337 if (client_proto >= 0 && client_proto < ZEBRA_ROUTE_MAX)
1338 rmap = route_map_lookup_by_name(nht_rm[family][client_proto]);
1339 if (!rmap && nht_rm[family][ZEBRA_ROUTE_MAX])
1340 rmap = route_map_lookup_by_name(
1341 nht_rm[family][ZEBRA_ROUTE_MAX]);
1342 if (rmap) {
1343 ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
1344 }
518f0eb1 1345
d62a17ae 1346 return (ret);
518f0eb1
DS
1347}
1348
d62a17ae 1349static void zebra_route_map_mark_update(const char *rmap_name)
518f0eb1 1350{
d62a17ae 1351 /* rmap_update_timer of 0 means don't do route updates */
1352 if (zebra_rmap_update_timer && !zebra_t_rmap_update) {
1353 zebra_t_rmap_update = NULL;
1354 thread_add_timer(zebrad.master, zebra_route_map_update_timer,
1355 NULL, zebra_rmap_update_timer,
1356 &zebra_t_rmap_update);
1357 }
518f0eb1
DS
1358}
1359
d62a17ae 1360static void zebra_route_map_add(const char *rmap_name)
518f0eb1 1361{
d62a17ae 1362 zebra_route_map_mark_update(rmap_name);
1363 route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
518f0eb1
DS
1364}
1365
d62a17ae 1366static void zebra_route_map_delete(const char *rmap_name)
518f0eb1 1367{
d62a17ae 1368 zebra_route_map_mark_update(rmap_name);
1369 route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
518f0eb1
DS
1370}
1371
d62a17ae 1372static void zebra_route_map_event(route_map_event_t event,
1373 const char *rmap_name)
518f0eb1 1374{
d62a17ae 1375 zebra_route_map_mark_update(rmap_name);
1376 route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
518f0eb1
DS
1377}
1378
1379/* ip protocol configuration write function */
d62a17ae 1380void zebra_routemap_config_write_protocol(struct vty *vty)
1381{
1382 int i;
1383
1384 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
1385 if (proto_rm[AFI_IP][i])
1386 vty_out(vty, "ip protocol %s route-map %s\n",
1387 zebra_route_string(i), proto_rm[AFI_IP][i]);
1388
1389 if (proto_rm[AFI_IP6][i])
1390 vty_out(vty, "ipv6 protocol %s route-map %s\n",
1391 zebra_route_string(i), proto_rm[AFI_IP6][i]);
1392
1393 if (nht_rm[AFI_IP][i])
1394 vty_out(vty, "ip nht %s route-map %s\n",
1395 zebra_route_string(i), nht_rm[AFI_IP][i]);
1396
1397 if (nht_rm[AFI_IP6][i])
1398 vty_out(vty, "ipv6 nht %s route-map %s\n",
1399 zebra_route_string(i), nht_rm[AFI_IP6][i]);
1400 }
1401
1402 if (proto_rm[AFI_IP][ZEBRA_ROUTE_MAX])
1403 vty_out(vty, "ip protocol %s route-map %s\n", "any",
1404 proto_rm[AFI_IP][ZEBRA_ROUTE_MAX]);
1405
1406 if (proto_rm[AFI_IP6][ZEBRA_ROUTE_MAX])
1407 vty_out(vty, "ipv6 protocol %s route-map %s\n", "any",
1408 proto_rm[AFI_IP6][ZEBRA_ROUTE_MAX]);
1409
1410 if (nht_rm[AFI_IP][ZEBRA_ROUTE_MAX])
1411 vty_out(vty, "ip nht %s route-map %s\n", "any",
1412 nht_rm[AFI_IP][ZEBRA_ROUTE_MAX]);
1413
1414 if (nht_rm[AFI_IP6][ZEBRA_ROUTE_MAX])
1415 vty_out(vty, "ipv6 nht %s route-map %s\n", "any",
1416 nht_rm[AFI_IP6][ZEBRA_ROUTE_MAX]);
1417
1418 if (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)
1419 vty_out(vty, "zebra route-map delay-timer %d\n",
1420 zebra_rmap_update_timer);
1421}
1422
1423void zebra_route_map_init()
1424{
1425 install_element(CONFIG_NODE, &ip_protocol_cmd);
1426 install_element(CONFIG_NODE, &no_ip_protocol_cmd);
1427 install_element(VIEW_NODE, &show_ip_protocol_cmd);
1428 install_element(CONFIG_NODE, &ipv6_protocol_cmd);
1429 install_element(CONFIG_NODE, &no_ipv6_protocol_cmd);
1430 install_element(VIEW_NODE, &show_ipv6_protocol_cmd);
1431 install_element(CONFIG_NODE, &ip_protocol_nht_rmap_cmd);
1432 install_element(CONFIG_NODE, &no_ip_protocol_nht_rmap_cmd);
1433 install_element(VIEW_NODE, &show_ip_protocol_nht_cmd);
1434 install_element(CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd);
1435 install_element(CONFIG_NODE, &no_ipv6_protocol_nht_rmap_cmd);
1436 install_element(VIEW_NODE, &show_ipv6_protocol_nht_cmd);
1437 install_element(CONFIG_NODE, &zebra_route_map_timer_cmd);
1438 install_element(CONFIG_NODE, &no_zebra_route_map_timer_cmd);
1439
1440 route_map_init();
1441
1442 route_map_add_hook(zebra_route_map_add);
1443 route_map_delete_hook(zebra_route_map_delete);
1444 route_map_event_hook(zebra_route_map_event);
1445
1446 route_map_match_interface_hook(generic_match_add);
1447 route_map_no_match_interface_hook(generic_match_delete);
1448
1449 route_map_match_ip_address_hook(generic_match_add);
1450 route_map_no_match_ip_address_hook(generic_match_delete);
1451
1452 route_map_match_ip_address_prefix_list_hook(generic_match_add);
1453 route_map_no_match_ip_address_prefix_list_hook(generic_match_delete);
1454
1455 route_map_match_ip_next_hop_hook(generic_match_add);
1456 route_map_no_match_ip_next_hop_hook(generic_match_delete);
1457
1458 route_map_match_ip_next_hop_prefix_list_hook(generic_match_add);
1459 route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete);
1460
1461 route_map_match_tag_hook(generic_match_add);
1462 route_map_no_match_tag_hook(generic_match_delete);
1463
1464 route_map_install_match(&route_match_tag_cmd);
1465 route_map_install_match(&route_match_interface_cmd);
1466 route_map_install_match(&route_match_ip_next_hop_cmd);
1467 route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
1468 route_map_install_match(&route_match_ip_address_cmd);
1469 route_map_install_match(&route_match_ip_address_prefix_list_cmd);
1470 route_map_install_match(&route_match_ip_address_prefix_len_cmd);
5165d46f 1471 route_map_install_match(&route_match_ipv6_address_prefix_len_cmd);
d62a17ae 1472 route_map_install_match(&route_match_ip_nexthop_prefix_len_cmd);
1473 route_map_install_match(&route_match_source_protocol_cmd);
1474 /* */
1475 route_map_install_set(&route_set_src_cmd);
1476 /* */
1477 install_element(RMAP_NODE, &match_ip_nexthop_prefix_len_cmd);
1478 install_element(RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd);
1479 install_element(RMAP_NODE, &match_ip_address_prefix_len_cmd);
5165d46f
DS
1480 install_element(RMAP_NODE, &match_ipv6_address_prefix_len_cmd);
1481 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_len_cmd);
d62a17ae 1482 install_element(RMAP_NODE, &no_match_ip_address_prefix_len_cmd);
1483 install_element(RMAP_NODE, &match_source_protocol_cmd);
1484 install_element(RMAP_NODE, &no_match_source_protocol_cmd);
1485 /* */
1486 install_element(RMAP_NODE, &set_src_cmd);
1487 install_element(RMAP_NODE, &no_set_src_cmd);
5921ef9a 1488}