]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_routemap.c
Merge pull request #8841 from volta-networks/fix_ospf6_bad_seqnum
[mirror_frr.git] / ospfd / ospf_routemap.c
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 static void ospf_route_map_update(const char *name)
48 {
49 struct ospf *ospf;
50 int type;
51 struct listnode *n1 = NULL;
52
53 /* If OSPF instatnce does not exist, return right now. */
54 if (listcount(om->ospf) == 0)
55 return;
56
57 for (ALL_LIST_ELEMENTS_RO(om->ospf, n1, ospf)) {
58 /* Update route-map */
59 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
60 struct list *red_list;
61 struct listnode *node;
62 struct ospf_redist *red;
63
64 red_list = ospf->redist[type];
65 if (!red_list)
66 continue;
67
68 for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
69 if (ROUTEMAP_NAME(red)
70 && strcmp(ROUTEMAP_NAME(red), name) == 0) {
71 /* Keep old route-map. */
72 struct route_map *old = ROUTEMAP(red);
73
74 ROUTEMAP(red) =
75 route_map_lookup_by_name(
76 ROUTEMAP_NAME(red));
77
78 if (!old)
79 route_map_counter_increment(
80 ROUTEMAP(red));
81
82 /* No update for this distribute type.
83 */
84 if (old == NULL
85 && ROUTEMAP(red) == NULL)
86 continue;
87
88 ospf_distribute_list_update(
89 ospf, type, red->instance);
90 }
91 }
92 }
93 }
94 }
95
96 static void ospf_route_map_event(const char *name)
97 {
98 struct ospf *ospf;
99 int type;
100 struct listnode *n1 = NULL;
101
102 for (ALL_LIST_ELEMENTS_RO(om->ospf, n1, ospf)) {
103 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
104 struct list *red_list;
105 struct listnode *node;
106 struct ospf_redist *red;
107
108 red_list = ospf->redist[type];
109 if (!red_list)
110 continue;
111
112 for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
113 if (ROUTEMAP_NAME(red) && ROUTEMAP(red)
114 && !strcmp(ROUTEMAP_NAME(red), name)) {
115 ospf_distribute_list_update(
116 ospf, type, red->instance);
117 }
118 }
119 }
120 }
121 }
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 route_match_ip_nexthop(void *rule, const struct prefix *prefix, void *object)
127 {
128 struct access_list *alist;
129 struct external_info *ei = object;
130 struct prefix_ipv4 p;
131
132 p.family = AF_INET;
133 p.prefix = ei->nexthop;
134 p.prefixlen = IPV4_MAX_BITLEN;
135
136 alist = access_list_lookup(AFI_IP, (char *)rule);
137 if (alist == NULL)
138 return RMAP_NOMATCH;
139
140 return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH
141 : RMAP_MATCH);
142 }
143
144 /* Route map `ip next-hop' match statement. `arg' should be
145 access-list name. */
146 static void *route_match_ip_nexthop_compile(const char *arg)
147 {
148 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
149 }
150
151 /* Free route map's compiled `ip address' value. */
152 static void route_match_ip_nexthop_free(void *rule)
153 {
154 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
155 }
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 route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
169 void *object)
170 {
171 struct prefix_list *plist;
172 struct external_info *ei = object;
173 struct prefix_ipv4 p;
174
175 p.family = AF_INET;
176 p.prefix = ei->nexthop;
177 p.prefixlen = IPV4_MAX_BITLEN;
178
179 plist = prefix_list_lookup(AFI_IP, (char *)rule);
180 if (plist == NULL)
181 return RMAP_NOMATCH;
182
183 return (prefix_list_apply(plist, &p) == PREFIX_DENY ? RMAP_NOMATCH
184 : RMAP_MATCH);
185 }
186
187 static void *route_match_ip_next_hop_prefix_list_compile(const char *arg)
188 {
189 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
190 }
191
192 static void route_match_ip_next_hop_prefix_list_free(void *rule)
193 {
194 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
195 }
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 route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
209 void *object)
210 {
211 struct external_info *ei = object;
212
213 if (prefix->family == AF_INET) {
214 ei = (struct external_info *)object;
215 if (!ei)
216 return RMAP_NOMATCH;
217
218 if (ei->nexthop.s_addr == INADDR_ANY && !ei->ifindex)
219 return RMAP_MATCH;
220 }
221 return RMAP_NOMATCH;
222 }
223
224 static void *route_match_ip_next_hop_type_compile(const char *arg)
225 {
226 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
227 }
228
229 static void route_match_ip_next_hop_type_free(void *rule)
230 {
231 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
232 }
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 route_match_ip_address(void *rule, const struct prefix *prefix, void *object)
247 {
248 struct access_list *alist;
249 /* struct prefix_ipv4 match; */
250
251 alist = access_list_lookup(AFI_IP, (char *)rule);
252 if (alist == NULL)
253 return RMAP_NOMATCH;
254
255 return (access_list_apply(alist, prefix) == FILTER_DENY ? RMAP_NOMATCH
256 : RMAP_MATCH);
257 }
258
259 /* Route map `ip address' match statement. `arg' should be
260 access-list name. */
261 static void *route_match_ip_address_compile(const char *arg)
262 {
263 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
264 }
265
266 /* Free route map's compiled `ip address' value. */
267 static void route_match_ip_address_free(void *rule)
268 {
269 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
270 }
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 route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
283 void *object)
284 {
285 struct prefix_list *plist;
286
287 plist = prefix_list_lookup(AFI_IP, (char *)rule);
288 if (plist == NULL)
289 return RMAP_NOMATCH;
290
291 return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
292 : RMAP_MATCH);
293 }
294
295 static void *route_match_ip_address_prefix_list_compile(const char *arg)
296 {
297 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
298 }
299
300 static void route_match_ip_address_prefix_list_free(void *rule)
301 {
302 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
303 }
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 route_match_interface(void *rule, const struct prefix *prefix, void *object)
318 {
319 struct interface *ifp;
320 struct external_info *ei;
321
322 ei = object;
323 ifp = if_lookup_by_name_all_vrf((char *)rule);
324
325 if (ifp == NULL || ifp->ifindex != ei->ifindex)
326 return RMAP_NOMATCH;
327
328 return RMAP_MATCH;
329 }
330
331 /* Route map `interface' match statement. `arg' should be
332 interface name. */
333 static void *route_match_interface_compile(const char *arg)
334 {
335 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
336 }
337
338 /* Free route map's compiled `interface' value. */
339 static void route_match_interface_free(void *rule)
340 {
341 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
342 }
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 route_match_tag(void *rule, const struct prefix *prefix, void *object)
355 {
356 route_tag_t *tag;
357 struct external_info *ei;
358
359 tag = rule;
360 ei = object;
361
362 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 route_set_metric(void *rule, const struct prefix *prefix, void *object)
383 {
384 struct ospf_metric *metric;
385 struct external_info *ei;
386
387 /* Fetch routemap's rule information. */
388 metric = rule;
389 ei = object;
390
391 /* Set metric out value. */
392 if (!metric->used)
393 return RMAP_OKAY;
394
395 ei->route_map_set.metric = DEFAULT_DEFAULT_METRIC;
396
397 if (metric->type == metric_increment)
398 ei->route_map_set.metric += metric->metric;
399 else if (metric->type == metric_decrement)
400 ei->route_map_set.metric -= metric->metric;
401 else if (metric->type == metric_absolute)
402 ei->route_map_set.metric = metric->metric;
403
404 if (ei->route_map_set.metric > OSPF_LS_INFINITY)
405 ei->route_map_set.metric = OSPF_LS_INFINITY;
406
407 return RMAP_OKAY;
408 }
409
410 /* set metric compilation. */
411 static void *route_set_metric_compile(const char *arg)
412 {
413 struct ospf_metric *metric;
414
415 metric = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*metric));
416 metric->used = false;
417
418 if (all_digit(arg))
419 metric->type = metric_absolute;
420
421 if (strmatch(arg, "+rtt") || strmatch(arg, "-rtt")) {
422 flog_warn(EC_OSPF_SET_METRIC_PLUS,
423 "OSPF does not support 'set metric +rtt / -rtt'");
424 return metric;
425 }
426
427 if ((arg[0] == '+') && all_digit(arg + 1)) {
428 metric->type = metric_increment;
429 arg++;
430 }
431
432 if ((arg[0] == '-') && all_digit(arg + 1)) {
433 metric->type = metric_decrement;
434 arg++;
435 }
436
437 metric->metric = strtoul(arg, NULL, 10);
438
439 if (metric->metric)
440 metric->used = true;
441
442 return metric;
443 }
444
445 /* Free route map's compiled `set metric' value. */
446 static void route_set_metric_free(void *rule)
447 {
448 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
449 }
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 route_set_metric_type(void *rule, const struct prefix *prefix, void *object)
463 {
464 uint32_t *metric_type;
465 struct external_info *ei;
466
467 /* Fetch routemap's rule information. */
468 metric_type = rule;
469 ei = object;
470
471 /* Set metric out value. */
472 ei->route_map_set.metric_type = *metric_type;
473
474 return RMAP_OKAY;
475 }
476
477 /* set metric-type compilation. */
478 static void *route_set_metric_type_compile(const char *arg)
479 {
480 uint32_t *metric_type;
481
482 metric_type = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
483 if (strcmp(arg, "type-1") == 0)
484 *metric_type = EXTERNAL_METRIC_TYPE_1;
485 else if (strcmp(arg, "type-2") == 0)
486 *metric_type = EXTERNAL_METRIC_TYPE_2;
487
488 if (*metric_type == EXTERNAL_METRIC_TYPE_1
489 || *metric_type == EXTERNAL_METRIC_TYPE_2)
490 return metric_type;
491
492 XFREE(MTYPE_ROUTE_MAP_COMPILED, metric_type);
493 return NULL;
494 }
495
496 /* Free route map's compiled `set metric-type' value. */
497 static void route_set_metric_type_free(void *rule)
498 {
499 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
500 }
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 route_set_tag(void *rule, const struct prefix *prefix, void *object)
512 {
513 route_tag_t *tag;
514 struct external_info *ei;
515
516 tag = rule;
517 ei = object;
518
519 /* Set tag value */
520 ei->tag = *tag;
521
522 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 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 char *ext = argv[2]->text;
542
543 const char *xpath =
544 "./set-action[action='frr-ospf-route-map:metric-type']";
545 char xpath_value[XPATH_MAXLEN];
546
547 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
548 snprintf(xpath_value, sizeof(xpath_value),
549 "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath);
550 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ext);
551 return nb_cli_apply_changes(vty, NULL);
552 }
553
554 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 const char *xpath =
564 "./set-action[action='frr-ospf-route-map:metric-type']";
565
566 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
567 return nb_cli_apply_changes(vty, NULL);
568 }
569
570 /* Route-map init */
571 void ospf_route_map_init(void)
572 {
573 route_map_init();
574
575 route_map_add_hook(ospf_route_map_update);
576 route_map_delete_hook(ospf_route_map_update);
577 route_map_event_hook(ospf_route_map_event);
578
579 route_map_set_metric_hook(generic_set_add);
580 route_map_no_set_metric_hook(generic_set_delete);
581
582 route_map_match_ip_next_hop_hook(generic_match_add);
583 route_map_no_match_ip_next_hop_hook(generic_match_delete);
584
585 route_map_match_interface_hook(generic_match_add);
586 route_map_no_match_interface_hook(generic_match_delete);
587
588 route_map_match_ip_address_hook(generic_match_add);
589 route_map_no_match_ip_address_hook(generic_match_delete);
590
591 route_map_match_ip_address_prefix_list_hook(generic_match_add);
592 route_map_no_match_ip_address_prefix_list_hook(generic_match_delete);
593
594 route_map_match_ip_next_hop_prefix_list_hook(generic_match_add);
595 route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete);
596
597 route_map_match_ip_next_hop_type_hook(generic_match_add);
598 route_map_no_match_ip_next_hop_type_hook(generic_match_delete);
599
600 route_map_match_tag_hook(generic_match_add);
601 route_map_no_match_tag_hook(generic_match_delete);
602
603 route_map_set_metric_hook(generic_set_add);
604 route_map_no_set_metric_hook(generic_set_delete);
605
606 route_map_set_tag_hook(generic_set_add);
607 route_map_no_set_tag_hook(generic_set_delete);
608
609 route_map_install_match(&route_match_ip_nexthop_cmd);
610 route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
611 route_map_install_match(&route_match_ip_address_cmd);
612 route_map_install_match(&route_match_ip_address_prefix_list_cmd);
613 route_map_install_match(&route_match_ip_next_hop_type_cmd);
614 route_map_install_match(&route_match_interface_cmd);
615 route_map_install_match(&route_match_tag_cmd);
616
617 route_map_install_set(&route_set_metric_cmd);
618 route_map_install_set(&route_set_metric_type_cmd);
619 route_map_install_set(&route_set_tag_cmd);
620
621 install_element(RMAP_NODE, &set_metric_type_cmd);
622 install_element(RMAP_NODE, &no_set_metric_type_cmd);
623 }