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