Line data Source code
1 : /*
2 : * Route map function of ospfd.
3 : * Copyright (C) 2000 IP Infusion Inc.
4 : *
5 : * Written by Toshiaki Takada.
6 : *
7 : * This file is part of GNU Zebra.
8 : *
9 : * GNU Zebra is free software; you can redistribute it and/or modify it
10 : * under the terms of the GNU General Public License as published by the
11 : * Free Software Foundation; either version 2, or (at your option) any
12 : * later version.
13 : *
14 : * GNU Zebra is distributed in the hope that it will be useful, but
15 : * WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : * General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License along
20 : * with this program; see the file COPYING; if not, write to the Free Software
21 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 : */
23 :
24 : #include <zebra.h>
25 :
26 : #include "memory.h"
27 : #include "prefix.h"
28 : #include "table.h"
29 : #include "vty.h"
30 : #include "routemap.h"
31 : #include "command.h"
32 : #include "log.h"
33 : #include "plist.h"
34 : #include "vrf.h"
35 : #include "frrstr.h"
36 : #include "northbound_cli.h"
37 :
38 : #include "ospfd/ospfd.h"
39 : #include "ospfd/ospf_asbr.h"
40 : #include "ospfd/ospf_interface.h"
41 : #include "ospfd/ospf_lsa.h"
42 : #include "ospfd/ospf_route.h"
43 : #include "ospfd/ospf_zebra.h"
44 : #include "ospfd/ospf_errors.h"
45 :
46 : /* Hook function for updating route_map assignment. */
47 0 : static void ospf_route_map_update(const char *name)
48 : {
49 0 : struct ospf *ospf;
50 0 : int type;
51 0 : struct listnode *n1 = NULL;
52 :
53 : /* If OSPF instatnce does not exist, return right now. */
54 0 : if (listcount(om->ospf) == 0)
55 : return;
56 :
57 0 : for (ALL_LIST_ELEMENTS_RO(om->ospf, n1, ospf)) {
58 : /* Update route-map */
59 0 : for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
60 0 : struct list *red_list;
61 0 : struct listnode *node;
62 0 : struct ospf_redist *red;
63 :
64 0 : red_list = ospf->redist[type];
65 0 : if (!red_list)
66 0 : continue;
67 :
68 0 : for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
69 0 : if (ROUTEMAP_NAME(red)
70 0 : && strcmp(ROUTEMAP_NAME(red), name) == 0) {
71 : /* Keep old route-map. */
72 0 : struct route_map *old = ROUTEMAP(red);
73 :
74 0 : ROUTEMAP(red) =
75 0 : route_map_lookup_by_name(
76 : ROUTEMAP_NAME(red));
77 :
78 0 : if (!old)
79 0 : route_map_counter_increment(
80 : ROUTEMAP(red));
81 :
82 : /* No update for this distribute type.
83 : */
84 0 : if (old == NULL
85 0 : && ROUTEMAP(red) == NULL)
86 0 : continue;
87 :
88 0 : ospf_distribute_list_update(
89 0 : ospf, type, red->instance);
90 : }
91 : }
92 : }
93 : }
94 : }
95 :
96 0 : static void ospf_route_map_event(const char *name)
97 : {
98 0 : struct ospf *ospf;
99 0 : int type;
100 0 : struct listnode *n1 = NULL;
101 :
102 0 : for (ALL_LIST_ELEMENTS_RO(om->ospf, n1, ospf)) {
103 0 : for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
104 0 : struct list *red_list;
105 0 : struct listnode *node;
106 0 : struct ospf_redist *red;
107 :
108 0 : red_list = ospf->redist[type];
109 0 : if (!red_list)
110 0 : continue;
111 :
112 0 : for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
113 0 : if (ROUTEMAP_NAME(red) && ROUTEMAP(red)
114 0 : && !strcmp(ROUTEMAP_NAME(red), name)) {
115 0 : ospf_distribute_list_update(
116 0 : ospf, type, red->instance);
117 : }
118 : }
119 : }
120 : }
121 0 : }
122 :
123 : /* `match ip netxthop ' */
124 : /* Match function return 1 if match is success else return zero. */
125 : static enum route_map_cmd_result_t
126 0 : route_match_ip_nexthop(void *rule, const struct prefix *prefix, void *object)
127 : {
128 0 : struct access_list *alist;
129 0 : struct external_info *ei = object;
130 0 : struct prefix_ipv4 p;
131 :
132 0 : p.family = AF_INET;
133 0 : p.prefix = ei->nexthop;
134 0 : p.prefixlen = IPV4_MAX_BITLEN;
135 :
136 0 : alist = access_list_lookup(AFI_IP, (char *)rule);
137 0 : if (alist == NULL)
138 : return RMAP_NOMATCH;
139 :
140 0 : return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH
141 0 : : RMAP_MATCH);
142 : }
143 :
144 : /* Route map `ip next-hop' match statement. `arg' should be
145 : access-list name. */
146 0 : static void *route_match_ip_nexthop_compile(const char *arg)
147 : {
148 0 : return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
149 : }
150 :
151 : /* Free route map's compiled `ip address' value. */
152 0 : static void route_match_ip_nexthop_free(void *rule)
153 : {
154 0 : XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
155 0 : }
156 :
157 : /* Route map commands for metric matching. */
158 : static const struct route_map_rule_cmd route_match_ip_nexthop_cmd = {
159 : "ip next-hop",
160 : route_match_ip_nexthop,
161 : route_match_ip_nexthop_compile,
162 : route_match_ip_nexthop_free
163 : };
164 :
165 : /* `match ip next-hop prefix-list PREFIX_LIST' */
166 :
167 : static enum route_map_cmd_result_t
168 0 : route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
169 : void *object)
170 : {
171 0 : struct prefix_list *plist;
172 0 : struct external_info *ei = object;
173 0 : struct prefix_ipv4 p;
174 :
175 0 : p.family = AF_INET;
176 0 : p.prefix = ei->nexthop;
177 0 : p.prefixlen = IPV4_MAX_BITLEN;
178 :
179 0 : plist = prefix_list_lookup(AFI_IP, (char *)rule);
180 0 : if (plist == NULL)
181 : return RMAP_NOMATCH;
182 :
183 0 : return (prefix_list_apply(plist, &p) == PREFIX_DENY ? RMAP_NOMATCH
184 0 : : RMAP_MATCH);
185 : }
186 :
187 0 : static void *route_match_ip_next_hop_prefix_list_compile(const char *arg)
188 : {
189 0 : return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
190 : }
191 :
192 0 : static void route_match_ip_next_hop_prefix_list_free(void *rule)
193 : {
194 0 : XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
195 0 : }
196 :
197 : static const struct route_map_rule_cmd
198 : route_match_ip_next_hop_prefix_list_cmd = {
199 : "ip next-hop prefix-list",
200 : route_match_ip_next_hop_prefix_list,
201 : route_match_ip_next_hop_prefix_list_compile,
202 : route_match_ip_next_hop_prefix_list_free
203 : };
204 :
205 : /* `match ip next-hop type <blackhole>' */
206 :
207 : static enum route_map_cmd_result_t
208 0 : route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
209 : void *object)
210 : {
211 0 : struct external_info *ei = object;
212 :
213 0 : if (prefix->family == AF_INET) {
214 0 : ei = (struct external_info *)object;
215 0 : if (!ei)
216 : return RMAP_NOMATCH;
217 :
218 0 : if (ei->nexthop.s_addr == INADDR_ANY && !ei->ifindex)
219 0 : return RMAP_MATCH;
220 : }
221 : return RMAP_NOMATCH;
222 : }
223 :
224 0 : static void *route_match_ip_next_hop_type_compile(const char *arg)
225 : {
226 0 : return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
227 : }
228 :
229 0 : static void route_match_ip_next_hop_type_free(void *rule)
230 : {
231 0 : XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
232 0 : }
233 :
234 : static const struct route_map_rule_cmd
235 : route_match_ip_next_hop_type_cmd = {
236 : "ip next-hop type",
237 : route_match_ip_next_hop_type,
238 : route_match_ip_next_hop_type_compile,
239 : route_match_ip_next_hop_type_free
240 : };
241 :
242 : /* `match ip address IP_ACCESS_LIST' */
243 : /* Match function should return 1 if match is success else return
244 : zero. */
245 : static enum route_map_cmd_result_t
246 0 : route_match_ip_address(void *rule, const struct prefix *prefix, void *object)
247 : {
248 0 : struct access_list *alist;
249 : /* struct prefix_ipv4 match; */
250 :
251 0 : alist = access_list_lookup(AFI_IP, (char *)rule);
252 0 : if (alist == NULL)
253 : return RMAP_NOMATCH;
254 :
255 0 : return (access_list_apply(alist, prefix) == FILTER_DENY ? RMAP_NOMATCH
256 0 : : RMAP_MATCH);
257 : }
258 :
259 : /* Route map `ip address' match statement. `arg' should be
260 : access-list name. */
261 0 : static void *route_match_ip_address_compile(const char *arg)
262 : {
263 0 : return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
264 : }
265 :
266 : /* Free route map's compiled `ip address' value. */
267 0 : static void route_match_ip_address_free(void *rule)
268 : {
269 0 : XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
270 0 : }
271 :
272 : /* Route map commands for ip address matching. */
273 : static const struct route_map_rule_cmd route_match_ip_address_cmd = {
274 : "ip address",
275 : route_match_ip_address,
276 : route_match_ip_address_compile,
277 : route_match_ip_address_free
278 : };
279 :
280 : /* `match ip address prefix-list PREFIX_LIST' */
281 : static enum route_map_cmd_result_t
282 0 : route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
283 : void *object)
284 : {
285 0 : struct prefix_list *plist;
286 :
287 0 : plist = prefix_list_lookup(AFI_IP, (char *)rule);
288 0 : if (plist == NULL)
289 : return RMAP_NOMATCH;
290 :
291 0 : return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
292 0 : : RMAP_MATCH);
293 : }
294 :
295 0 : static void *route_match_ip_address_prefix_list_compile(const char *arg)
296 : {
297 0 : return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
298 : }
299 :
300 0 : static void route_match_ip_address_prefix_list_free(void *rule)
301 : {
302 0 : XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
303 0 : }
304 :
305 : static const struct route_map_rule_cmd
306 : route_match_ip_address_prefix_list_cmd = {
307 : "ip address prefix-list",
308 : route_match_ip_address_prefix_list,
309 : route_match_ip_address_prefix_list_compile,
310 : route_match_ip_address_prefix_list_free
311 : };
312 :
313 : /* `match interface IFNAME' */
314 : /* Match function should return 1 if match is success else return
315 : zero. */
316 : static enum route_map_cmd_result_t
317 0 : route_match_interface(void *rule, const struct prefix *prefix, void *object)
318 : {
319 0 : struct interface *ifp;
320 0 : struct external_info *ei;
321 :
322 0 : ei = object;
323 0 : ifp = if_lookup_by_name((char *)rule, ei->ospf->vrf_id);
324 :
325 0 : if (ifp == NULL || ifp->ifindex != ei->ifindex)
326 0 : return RMAP_NOMATCH;
327 :
328 : return RMAP_MATCH;
329 : }
330 :
331 : /* Route map `interface' match statement. `arg' should be
332 : interface name. */
333 0 : static void *route_match_interface_compile(const char *arg)
334 : {
335 0 : return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
336 : }
337 :
338 : /* Free route map's compiled `interface' value. */
339 0 : static void route_match_interface_free(void *rule)
340 : {
341 0 : XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
342 0 : }
343 :
344 : /* Route map commands for ip address matching. */
345 : static const struct route_map_rule_cmd route_match_interface_cmd = {
346 : "interface",
347 : route_match_interface,
348 : route_match_interface_compile,
349 : route_match_interface_free
350 : };
351 :
352 : /* Match function return 1 if match is success else return zero. */
353 : static enum route_map_cmd_result_t
354 0 : route_match_tag(void *rule, const struct prefix *prefix, void *object)
355 : {
356 0 : route_tag_t *tag;
357 0 : struct external_info *ei;
358 :
359 0 : tag = rule;
360 0 : ei = object;
361 :
362 0 : return ((ei->tag == *tag) ? RMAP_MATCH : RMAP_NOMATCH);
363 : }
364 :
365 : /* Route map commands for tag matching. */
366 : static const struct route_map_rule_cmd route_match_tag_cmd = {
367 : "tag",
368 : route_match_tag,
369 : route_map_rule_tag_compile,
370 : route_map_rule_tag_free,
371 : };
372 :
373 : struct ospf_metric {
374 : enum { metric_increment, metric_decrement, metric_absolute } type;
375 : bool used;
376 : uint32_t metric;
377 : };
378 :
379 : /* `set metric METRIC' */
380 : /* Set metric to attribute. */
381 : static enum route_map_cmd_result_t
382 0 : route_set_metric(void *rule, const struct prefix *prefix, void *object)
383 : {
384 0 : struct ospf_metric *metric;
385 0 : struct external_info *ei;
386 :
387 : /* Fetch routemap's rule information. */
388 0 : metric = rule;
389 0 : ei = object;
390 :
391 : /* Set metric out value. */
392 0 : if (!metric->used)
393 : return RMAP_OKAY;
394 :
395 0 : ei->route_map_set.metric = DEFAULT_DEFAULT_METRIC;
396 :
397 0 : if (metric->type == metric_increment)
398 0 : ei->route_map_set.metric += metric->metric;
399 0 : else if (metric->type == metric_decrement)
400 0 : ei->route_map_set.metric -= metric->metric;
401 0 : else if (metric->type == metric_absolute)
402 0 : ei->route_map_set.metric = metric->metric;
403 :
404 0 : if (ei->route_map_set.metric > OSPF_LS_INFINITY)
405 0 : ei->route_map_set.metric = OSPF_LS_INFINITY;
406 :
407 : return RMAP_OKAY;
408 : }
409 :
410 : /* set metric compilation. */
411 0 : static void *route_set_metric_compile(const char *arg)
412 : {
413 0 : struct ospf_metric *metric;
414 :
415 0 : metric = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*metric));
416 0 : metric->used = false;
417 :
418 0 : if (all_digit(arg))
419 0 : metric->type = metric_absolute;
420 :
421 0 : if (strmatch(arg, "+rtt") || strmatch(arg, "-rtt")) {
422 0 : flog_warn(EC_OSPF_SET_METRIC_PLUS,
423 : "OSPF does not support 'set metric +rtt / -rtt'");
424 0 : return metric;
425 : }
426 :
427 0 : if ((arg[0] == '+') && all_digit(arg + 1)) {
428 0 : metric->type = metric_increment;
429 0 : arg++;
430 : }
431 :
432 0 : if ((arg[0] == '-') && all_digit(arg + 1)) {
433 0 : metric->type = metric_decrement;
434 0 : arg++;
435 : }
436 :
437 0 : metric->metric = strtoul(arg, NULL, 10);
438 :
439 0 : if (metric->metric)
440 0 : metric->used = true;
441 :
442 : return metric;
443 : }
444 :
445 : /* Free route map's compiled `set metric' value. */
446 0 : static void route_set_metric_free(void *rule)
447 : {
448 0 : XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
449 0 : }
450 :
451 : /* Set metric rule structure. */
452 : static const struct route_map_rule_cmd route_set_metric_cmd = {
453 : "metric",
454 : route_set_metric,
455 : route_set_metric_compile,
456 : route_set_metric_free,
457 : };
458 :
459 : /* `set metric-type TYPE' */
460 : /* Set metric-type to attribute. */
461 : static enum route_map_cmd_result_t
462 0 : route_set_metric_type(void *rule, const struct prefix *prefix, void *object)
463 : {
464 0 : uint32_t *metric_type;
465 0 : struct external_info *ei;
466 :
467 : /* Fetch routemap's rule information. */
468 0 : metric_type = rule;
469 0 : ei = object;
470 :
471 : /* Set metric out value. */
472 0 : ei->route_map_set.metric_type = *metric_type;
473 :
474 0 : return RMAP_OKAY;
475 : }
476 :
477 : /* set metric-type compilation. */
478 0 : static void *route_set_metric_type_compile(const char *arg)
479 : {
480 0 : uint32_t *metric_type;
481 :
482 0 : metric_type = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
483 0 : if (strcmp(arg, "type-1") == 0)
484 0 : *metric_type = EXTERNAL_METRIC_TYPE_1;
485 0 : else if (strcmp(arg, "type-2") == 0)
486 0 : *metric_type = EXTERNAL_METRIC_TYPE_2;
487 :
488 0 : if (*metric_type == EXTERNAL_METRIC_TYPE_1
489 : || *metric_type == EXTERNAL_METRIC_TYPE_2)
490 : return metric_type;
491 :
492 0 : XFREE(MTYPE_ROUTE_MAP_COMPILED, metric_type);
493 0 : return NULL;
494 : }
495 :
496 : /* Free route map's compiled `set metric-type' value. */
497 0 : static void route_set_metric_type_free(void *rule)
498 : {
499 0 : XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
500 0 : }
501 :
502 : /* Set metric rule structure. */
503 : static const struct route_map_rule_cmd route_set_metric_type_cmd = {
504 : "metric-type",
505 : route_set_metric_type,
506 : route_set_metric_type_compile,
507 : route_set_metric_type_free,
508 : };
509 :
510 : static enum route_map_cmd_result_t
511 0 : route_set_tag(void *rule, const struct prefix *prefix, void *object)
512 : {
513 0 : route_tag_t *tag;
514 0 : struct external_info *ei;
515 :
516 0 : tag = rule;
517 0 : ei = object;
518 :
519 : /* Set tag value */
520 0 : ei->tag = *tag;
521 :
522 0 : return RMAP_OKAY;
523 : }
524 :
525 : /* Route map commands for tag set. */
526 : static const struct route_map_rule_cmd route_set_tag_cmd = {
527 : "tag",
528 : route_set_tag,
529 : route_map_rule_tag_compile,
530 : route_map_rule_tag_free,
531 : };
532 :
533 0 : DEFUN_YANG (set_metric_type,
534 : set_metric_type_cmd,
535 : "set metric-type <type-1|type-2>",
536 : SET_STR
537 : "Type of metric for destination routing protocol\n"
538 : "OSPF[6] external type 1 metric\n"
539 : "OSPF[6] external type 2 metric\n")
540 : {
541 0 : char *ext = argv[2]->text;
542 :
543 0 : const char *xpath =
544 : "./set-action[action='frr-ospf-route-map:metric-type']";
545 0 : char xpath_value[XPATH_MAXLEN];
546 :
547 0 : nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
548 0 : snprintf(xpath_value, sizeof(xpath_value),
549 : "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath);
550 0 : nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ext);
551 0 : return nb_cli_apply_changes(vty, NULL);
552 : }
553 :
554 0 : DEFUN_YANG (no_set_metric_type,
555 : no_set_metric_type_cmd,
556 : "no set metric-type [<type-1|type-2>]",
557 : NO_STR
558 : SET_STR
559 : "Type of metric for destination routing protocol\n"
560 : "OSPF[6] external type 1 metric\n"
561 : "OSPF[6] external type 2 metric\n")
562 : {
563 0 : const char *xpath =
564 : "./set-action[action='frr-ospf-route-map:metric-type']";
565 :
566 0 : nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
567 0 : return nb_cli_apply_changes(vty, NULL);
568 : }
569 :
570 : /* Route-map init */
571 4 : void ospf_route_map_init(void)
572 : {
573 4 : route_map_init();
574 :
575 4 : route_map_add_hook(ospf_route_map_update);
576 4 : route_map_delete_hook(ospf_route_map_update);
577 4 : route_map_event_hook(ospf_route_map_event);
578 :
579 4 : route_map_set_metric_hook(generic_set_add);
580 4 : route_map_no_set_metric_hook(generic_set_delete);
581 :
582 4 : route_map_match_ip_next_hop_hook(generic_match_add);
583 4 : route_map_no_match_ip_next_hop_hook(generic_match_delete);
584 :
585 4 : route_map_match_interface_hook(generic_match_add);
586 4 : route_map_no_match_interface_hook(generic_match_delete);
587 :
588 4 : route_map_match_ip_address_hook(generic_match_add);
589 4 : route_map_no_match_ip_address_hook(generic_match_delete);
590 :
591 4 : route_map_match_ip_address_prefix_list_hook(generic_match_add);
592 4 : route_map_no_match_ip_address_prefix_list_hook(generic_match_delete);
593 :
594 4 : route_map_match_ip_next_hop_prefix_list_hook(generic_match_add);
595 4 : route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete);
596 :
597 4 : route_map_match_ip_next_hop_type_hook(generic_match_add);
598 4 : route_map_no_match_ip_next_hop_type_hook(generic_match_delete);
599 :
600 4 : route_map_match_tag_hook(generic_match_add);
601 4 : route_map_no_match_tag_hook(generic_match_delete);
602 :
603 4 : route_map_set_metric_hook(generic_set_add);
604 4 : route_map_no_set_metric_hook(generic_set_delete);
605 :
606 4 : route_map_set_tag_hook(generic_set_add);
607 4 : route_map_no_set_tag_hook(generic_set_delete);
608 :
609 4 : route_map_install_match(&route_match_ip_nexthop_cmd);
610 4 : route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
611 4 : route_map_install_match(&route_match_ip_address_cmd);
612 4 : route_map_install_match(&route_match_ip_address_prefix_list_cmd);
613 4 : route_map_install_match(&route_match_ip_next_hop_type_cmd);
614 4 : route_map_install_match(&route_match_interface_cmd);
615 4 : route_map_install_match(&route_match_tag_cmd);
616 :
617 4 : route_map_install_set(&route_set_metric_cmd);
618 4 : route_map_install_set(&route_set_metric_type_cmd);
619 4 : route_map_install_set(&route_set_tag_cmd);
620 :
621 4 : install_element(RMAP_NODE, &set_metric_type_cmd);
622 4 : install_element(RMAP_NODE, &no_set_metric_type_cmd);
623 4 : }
|