]> git.proxmox.com Git - mirror_frr.git/blob - ripd/rip_routemap.c
Merge pull request #5412 from opensourcerouting/bfdd-vrf-fix
[mirror_frr.git] / ripd / rip_routemap.c
1 /* RIPv2 routemap.
2 * Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
3 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <zebra.h>
23
24 #include "memory.h"
25 #include "prefix.h"
26 #include "vty.h"
27 #include "routemap.h"
28 #include "command.h"
29 #include "filter.h"
30 #include "log.h"
31 #include "sockunion.h" /* for inet_aton () */
32 #include "plist.h"
33 #include "vrf.h"
34
35 #include "ripd/ripd.h"
36
37 struct rip_metric_modifier {
38 enum { metric_increment, metric_decrement, metric_absolute } type;
39 bool used;
40 uint8_t metric;
41 };
42
43 /* `match metric METRIC' */
44 /* Match function return 1 if match is success else return zero. */
45 static enum route_map_cmd_result_t
46 route_match_metric(void *rule, const struct prefix *prefix,
47 route_map_object_t type, void *object)
48 {
49 uint32_t *metric;
50 uint32_t check;
51 struct rip_info *rinfo;
52
53 if (type == RMAP_RIP) {
54 metric = rule;
55 rinfo = object;
56
57 /* If external metric is available, the route-map should
58 work on this one (for redistribute purpose) */
59 check = (rinfo->external_metric) ? rinfo->external_metric
60 : rinfo->metric;
61 if (check == *metric)
62 return RMAP_MATCH;
63 else
64 return RMAP_NOMATCH;
65 }
66 return RMAP_NOMATCH;
67 }
68
69 /* Route map `match metric' match statement. `arg' is METRIC value */
70 static void *route_match_metric_compile(const char *arg)
71 {
72 uint32_t *metric;
73
74 metric = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
75 *metric = atoi(arg);
76
77 if (*metric > 0)
78 return metric;
79
80 XFREE(MTYPE_ROUTE_MAP_COMPILED, metric);
81 return NULL;
82 }
83
84 /* Free route map's compiled `match metric' value. */
85 static void route_match_metric_free(void *rule)
86 {
87 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
88 }
89
90 /* Route map commands for metric matching. */
91 static const struct route_map_rule_cmd route_match_metric_cmd = {
92 "metric",
93 route_match_metric,
94 route_match_metric_compile,
95 route_match_metric_free
96 };
97
98 /* `match interface IFNAME' */
99 /* Match function return 1 if match is success else return zero. */
100 static enum route_map_cmd_result_t
101 route_match_interface(void *rule, const struct prefix *prefix,
102 route_map_object_t type, void *object)
103 {
104 struct rip_info *rinfo;
105 struct interface *ifp;
106 char *ifname;
107
108 if (type == RMAP_RIP) {
109 ifname = rule;
110 ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
111
112 if (!ifp)
113 return RMAP_NOMATCH;
114
115 rinfo = object;
116
117 if (rinfo->ifindex_out == ifp->ifindex
118 || rinfo->nh.ifindex == ifp->ifindex)
119 return RMAP_MATCH;
120 else
121 return RMAP_NOMATCH;
122 }
123 return RMAP_NOMATCH;
124 }
125
126 /* Route map `match interface' match statement. `arg' is IFNAME value */
127 /* XXX I don`t know if I need to check does interface exist? */
128 static void *route_match_interface_compile(const char *arg)
129 {
130 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
131 }
132
133 /* Free route map's compiled `match interface' value. */
134 static void route_match_interface_free(void *rule)
135 {
136 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
137 }
138
139 /* Route map commands for interface matching. */
140 static const struct route_map_rule_cmd route_match_interface_cmd = {
141 "interface",
142 route_match_interface,
143 route_match_interface_compile,
144 route_match_interface_free
145 };
146
147 /* `match ip next-hop IP_ACCESS_LIST' */
148
149 /* Match function return 1 if match is success else return zero. */
150 static enum route_map_cmd_result_t
151 route_match_ip_next_hop(void *rule, const struct prefix *prefix,
152 route_map_object_t type, void *object)
153 {
154 struct access_list *alist;
155 struct rip_info *rinfo;
156 struct prefix_ipv4 p;
157
158 if (type == RMAP_RIP) {
159 rinfo = object;
160 p.family = AF_INET;
161 p.prefix = (rinfo->nh.gate.ipv4.s_addr) ? rinfo->nh.gate.ipv4
162 : rinfo->from;
163 p.prefixlen = IPV4_MAX_BITLEN;
164
165 alist = access_list_lookup(AFI_IP, (char *)rule);
166 if (alist == NULL)
167 return RMAP_NOMATCH;
168
169 return (access_list_apply(alist, &p) == FILTER_DENY
170 ? RMAP_NOMATCH
171 : RMAP_MATCH);
172 }
173 return RMAP_NOMATCH;
174 }
175
176 /* Route map `ip next-hop' match statement. `arg' should be
177 access-list name. */
178 static void *route_match_ip_next_hop_compile(const char *arg)
179 {
180 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
181 }
182
183 /* Free route map's compiled `. */
184 static void route_match_ip_next_hop_free(void *rule)
185 {
186 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
187 }
188
189 /* Route map commands for ip next-hop matching. */
190 static const struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
191 "ip next-hop",
192 route_match_ip_next_hop,
193 route_match_ip_next_hop_compile,
194 route_match_ip_next_hop_free
195 };
196
197 /* `match ip next-hop prefix-list PREFIX_LIST' */
198
199 static enum route_map_cmd_result_t
200 route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
201 route_map_object_t type, void *object)
202 {
203 struct prefix_list *plist;
204 struct rip_info *rinfo;
205 struct prefix_ipv4 p;
206
207 if (type == RMAP_RIP) {
208 rinfo = object;
209 p.family = AF_INET;
210 p.prefix = (rinfo->nh.gate.ipv4.s_addr) ? rinfo->nh.gate.ipv4
211 : rinfo->from;
212 p.prefixlen = IPV4_MAX_BITLEN;
213
214 plist = prefix_list_lookup(AFI_IP, (char *)rule);
215 if (plist == NULL)
216 return RMAP_NOMATCH;
217
218 return (prefix_list_apply(plist, &p) == PREFIX_DENY
219 ? RMAP_NOMATCH
220 : RMAP_MATCH);
221 }
222 return RMAP_NOMATCH;
223 }
224
225 static void *route_match_ip_next_hop_prefix_list_compile(const char *arg)
226 {
227 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
228 }
229
230 static void route_match_ip_next_hop_prefix_list_free(void *rule)
231 {
232 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
233 }
234
235 static const struct route_map_rule_cmd
236 route_match_ip_next_hop_prefix_list_cmd = {
237 "ip next-hop prefix-list",
238 route_match_ip_next_hop_prefix_list,
239 route_match_ip_next_hop_prefix_list_compile,
240 route_match_ip_next_hop_prefix_list_free
241 };
242
243 /* `match ip next-hop type <blackhole>' */
244
245 static enum route_map_cmd_result_t
246 route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
247 route_map_object_t type, void *object)
248 {
249 struct rip_info *rinfo;
250
251 if (type == RMAP_RIP && prefix->family == AF_INET) {
252 rinfo = (struct rip_info *)object;
253 if (!rinfo)
254 return RMAP_NOMATCH;
255
256 if (rinfo->nh.type == NEXTHOP_TYPE_BLACKHOLE)
257 return RMAP_MATCH;
258 }
259 return RMAP_NOMATCH;
260 }
261
262 static void *route_match_ip_next_hop_type_compile(const char *arg)
263 {
264 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
265 }
266
267 static void route_match_ip_next_hop_type_free(void *rule)
268 {
269 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
270 }
271
272 static const struct route_map_rule_cmd
273 route_match_ip_next_hop_type_cmd = {
274 "ip next-hop type",
275 route_match_ip_next_hop_type,
276 route_match_ip_next_hop_type_compile,
277 route_match_ip_next_hop_type_free
278 };
279
280 /* `match ip address IP_ACCESS_LIST' */
281
282 /* Match function should return 1 if match is success else return
283 zero. */
284 static enum route_map_cmd_result_t
285 route_match_ip_address(void *rule, const struct prefix *prefix,
286 route_map_object_t type, void *object)
287 {
288 struct access_list *alist;
289
290 if (type == RMAP_RIP) {
291 alist = access_list_lookup(AFI_IP, (char *)rule);
292 if (alist == NULL)
293 return RMAP_NOMATCH;
294
295 return (access_list_apply(alist, prefix) == FILTER_DENY
296 ? RMAP_NOMATCH
297 : RMAP_MATCH);
298 }
299 return RMAP_NOMATCH;
300 }
301
302 /* Route map `ip address' match statement. `arg' should be
303 access-list name. */
304 static void *route_match_ip_address_compile(const char *arg)
305 {
306 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
307 }
308
309 /* Free route map's compiled `ip address' value. */
310 static void route_match_ip_address_free(void *rule)
311 {
312 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
313 }
314
315 /* Route map commands for ip address matching. */
316 static const struct route_map_rule_cmd route_match_ip_address_cmd = {
317 "ip address",
318 route_match_ip_address,
319 route_match_ip_address_compile,
320 route_match_ip_address_free
321 };
322
323 /* `match ip address prefix-list PREFIX_LIST' */
324
325 static enum route_map_cmd_result_t
326 route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
327 route_map_object_t type, void *object)
328 {
329 struct prefix_list *plist;
330
331 if (type == RMAP_RIP) {
332 plist = prefix_list_lookup(AFI_IP, (char *)rule);
333 if (plist == NULL)
334 return RMAP_NOMATCH;
335
336 return (prefix_list_apply(plist, prefix) == PREFIX_DENY
337 ? RMAP_NOMATCH
338 : RMAP_MATCH);
339 }
340 return RMAP_NOMATCH;
341 }
342
343 static void *route_match_ip_address_prefix_list_compile(const char *arg)
344 {
345 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
346 }
347
348 static void route_match_ip_address_prefix_list_free(void *rule)
349 {
350 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
351 }
352
353 static const struct route_map_rule_cmd
354 route_match_ip_address_prefix_list_cmd = {
355 "ip address prefix-list",
356 route_match_ip_address_prefix_list,
357 route_match_ip_address_prefix_list_compile,
358 route_match_ip_address_prefix_list_free
359 };
360
361 /* `match tag TAG' */
362 /* Match function return 1 if match is success else return zero. */
363 static enum route_map_cmd_result_t
364 route_match_tag(void *rule, const struct prefix *p, route_map_object_t type,
365 void *object)
366 {
367 route_tag_t *tag;
368 struct rip_info *rinfo;
369 route_tag_t rinfo_tag;
370
371 if (type == RMAP_RIP) {
372 tag = rule;
373 rinfo = object;
374
375 /* The information stored by rinfo is host ordered. */
376 rinfo_tag = rinfo->tag;
377 if (rinfo_tag == *tag)
378 return RMAP_MATCH;
379 else
380 return RMAP_NOMATCH;
381 }
382 return RMAP_NOMATCH;
383 }
384
385 /* Route map commands for tag matching. */
386 static const struct route_map_rule_cmd route_match_tag_cmd = {
387 "tag",
388 route_match_tag,
389 route_map_rule_tag_compile,
390 route_map_rule_tag_free,
391 };
392
393 /* `set metric METRIC' */
394
395 /* Set metric to attribute. */
396 static enum route_map_cmd_result_t
397 route_set_metric(void *rule, const struct prefix *prefix,
398 route_map_object_t type, void *object)
399 {
400 if (type == RMAP_RIP) {
401 struct rip_metric_modifier *mod;
402 struct rip_info *rinfo;
403
404 mod = rule;
405 rinfo = object;
406
407 if (!mod->used)
408 return RMAP_OKAY;
409
410 if (mod->type == metric_increment)
411 rinfo->metric_out += mod->metric;
412 else if (mod->type == metric_decrement)
413 rinfo->metric_out -= mod->metric;
414 else if (mod->type == metric_absolute)
415 rinfo->metric_out = mod->metric;
416
417 if ((signed int)rinfo->metric_out < 1)
418 rinfo->metric_out = 1;
419 if (rinfo->metric_out > RIP_METRIC_INFINITY)
420 rinfo->metric_out = RIP_METRIC_INFINITY;
421
422 rinfo->metric_set = 1;
423 }
424 return RMAP_OKAY;
425 }
426
427 /* set metric compilation. */
428 static void *route_set_metric_compile(const char *arg)
429 {
430 int len;
431 const char *pnt;
432 long metric;
433 char *endptr = NULL;
434 struct rip_metric_modifier *mod;
435
436 mod = XMALLOC(MTYPE_ROUTE_MAP_COMPILED,
437 sizeof(struct rip_metric_modifier));
438 mod->used = false;
439
440 len = strlen(arg);
441 pnt = arg;
442
443 if (len == 0)
444 return mod;
445
446 /* Examine first character. */
447 if (arg[0] == '+') {
448 mod->type = metric_increment;
449 pnt++;
450 } else if (arg[0] == '-') {
451 mod->type = metric_decrement;
452 pnt++;
453 } else
454 mod->type = metric_absolute;
455
456 /* Check beginning with digit string. */
457 if (*pnt < '0' || *pnt > '9')
458 return mod;
459
460 /* Convert string to integer. */
461 metric = strtol(pnt, &endptr, 10);
462
463 if (*endptr != '\0' || metric < 0) {
464 return mod;
465 }
466 if (metric > RIP_METRIC_INFINITY) {
467 zlog_info(
468 "%s: Metric specified: %ld is greater than RIP_METRIC_INFINITY, using INFINITY instead",
469 __PRETTY_FUNCTION__, metric);
470 mod->metric = RIP_METRIC_INFINITY;
471 } else
472 mod->metric = metric;
473
474 mod->used = true;
475
476 return mod;
477 }
478
479 /* Free route map's compiled `set metric' value. */
480 static void route_set_metric_free(void *rule)
481 {
482 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
483 }
484
485 /* Set metric rule structure. */
486 static const struct route_map_rule_cmd route_set_metric_cmd = {
487 "metric",
488 route_set_metric,
489 route_set_metric_compile,
490 route_set_metric_free,
491 };
492
493 /* `set ip next-hop IP_ADDRESS' */
494
495 /* Set nexthop to object. ojbect must be pointer to struct attr. */
496 static enum route_map_cmd_result_t route_set_ip_nexthop(void *rule,
497 const struct prefix *prefix,
498 route_map_object_t type,
499 void *object)
500 {
501 struct in_addr *address;
502 struct rip_info *rinfo;
503
504 if (type == RMAP_RIP) {
505 /* Fetch routemap's rule information. */
506 address = rule;
507 rinfo = object;
508
509 /* Set next hop value. */
510 rinfo->nexthop_out = *address;
511 }
512
513 return RMAP_OKAY;
514 }
515
516 /* Route map `ip nexthop' compile function. Given string is converted
517 to struct in_addr structure. */
518 static void *route_set_ip_nexthop_compile(const char *arg)
519 {
520 int ret;
521 struct in_addr *address;
522
523 address = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct in_addr));
524
525 ret = inet_aton(arg, address);
526
527 if (ret == 0) {
528 XFREE(MTYPE_ROUTE_MAP_COMPILED, address);
529 return NULL;
530 }
531
532 return address;
533 }
534
535 /* Free route map's compiled `ip nexthop' value. */
536 static void route_set_ip_nexthop_free(void *rule)
537 {
538 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
539 }
540
541 /* Route map commands for ip nexthop set. */
542 static const struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
543 "ip next-hop",
544 route_set_ip_nexthop,
545 route_set_ip_nexthop_compile,
546 route_set_ip_nexthop_free
547 };
548
549 /* `set tag TAG' */
550
551 /* Set tag to object. ojbect must be pointer to struct attr. */
552 static enum route_map_cmd_result_t
553 route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
554 void *object)
555 {
556 route_tag_t *tag;
557 struct rip_info *rinfo;
558
559 if (type == RMAP_RIP) {
560 /* Fetch routemap's rule information. */
561 tag = rule;
562 rinfo = object;
563
564 /* Set next hop value. */
565 rinfo->tag_out = *tag;
566 }
567
568 return RMAP_OKAY;
569 }
570
571 /* Route map commands for tag set. */
572 static const struct route_map_rule_cmd route_set_tag_cmd = {
573 "tag",
574 route_set_tag,
575 route_map_rule_tag_compile,
576 route_map_rule_tag_free
577 };
578
579 #define MATCH_STR "Match values from routing table\n"
580 #define SET_STR "Set values in destination routing protocol\n"
581
582 /* Route-map init */
583 void rip_route_map_init(void)
584 {
585 route_map_init();
586
587 route_map_match_interface_hook(generic_match_add);
588 route_map_no_match_interface_hook(generic_match_delete);
589
590 route_map_match_ip_address_hook(generic_match_add);
591 route_map_no_match_ip_address_hook(generic_match_delete);
592
593 route_map_match_ip_address_prefix_list_hook(generic_match_add);
594 route_map_no_match_ip_address_prefix_list_hook(generic_match_delete);
595
596 route_map_match_ip_next_hop_hook(generic_match_add);
597 route_map_no_match_ip_next_hop_hook(generic_match_delete);
598
599 route_map_match_ip_next_hop_prefix_list_hook(generic_match_add);
600 route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete);
601
602 route_map_match_ip_next_hop_type_hook(generic_match_add);
603 route_map_no_match_ip_next_hop_type_hook(generic_match_delete);
604
605 route_map_match_metric_hook(generic_match_add);
606 route_map_no_match_metric_hook(generic_match_delete);
607
608 route_map_match_tag_hook(generic_match_add);
609 route_map_no_match_tag_hook(generic_match_delete);
610
611 route_map_set_ip_nexthop_hook(generic_set_add);
612 route_map_no_set_ip_nexthop_hook(generic_set_delete);
613
614 route_map_set_metric_hook(generic_set_add);
615 route_map_no_set_metric_hook(generic_set_delete);
616
617 route_map_set_tag_hook(generic_set_add);
618 route_map_no_set_tag_hook(generic_set_delete);
619
620 route_map_install_match(&route_match_metric_cmd);
621 route_map_install_match(&route_match_interface_cmd);
622 route_map_install_match(&route_match_ip_next_hop_cmd);
623 route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
624 route_map_install_match(&route_match_ip_next_hop_type_cmd);
625 route_map_install_match(&route_match_ip_address_cmd);
626 route_map_install_match(&route_match_ip_address_prefix_list_cmd);
627 route_map_install_match(&route_match_tag_cmd);
628
629 route_map_install_set(&route_set_metric_cmd);
630 route_map_install_set(&route_set_ip_nexthop_cmd);
631 route_map_install_set(&route_set_tag_cmd);
632 }