]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_routemap.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[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
37 #include "ospfd/ospfd.h"
38 #include "ospfd/ospf_asbr.h"
39 #include "ospfd/ospf_interface.h"
40 #include "ospfd/ospf_lsa.h"
41 #include "ospfd/ospf_route.h"
42 #include "ospfd/ospf_zebra.h"
43 #include "ospfd/ospf_errors.h"
44
45 /* Hook function for updating route_map assignment. */
46 static void ospf_route_map_update(const char *name)
47 {
48 struct ospf *ospf;
49 int type;
50 struct listnode *n1 = NULL;
51
52 /* If OSPF instatnce does not exist, return right now. */
53 if (listcount(om->ospf) == 0)
54 return;
55
56 for (ALL_LIST_ELEMENTS_RO(om->ospf, n1, ospf)) {
57 /* Update route-map */
58 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
59 struct list *red_list;
60 struct listnode *node;
61 struct ospf_redist *red;
62
63 red_list = ospf->redist[type];
64 if (!red_list)
65 continue;
66
67 for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
68 if (ROUTEMAP_NAME(red)
69 && strcmp(ROUTEMAP_NAME(red), name) == 0) {
70 /* Keep old route-map. */
71 struct route_map *old = ROUTEMAP(red);
72
73 /* Update route-map. */
74 ROUTEMAP(red) =
75 route_map_lookup_by_name(
76 ROUTEMAP_NAME(red));
77
78 /* No update for this distribute type.
79 */
80 if (old == NULL
81 && ROUTEMAP(red) == NULL)
82 continue;
83
84 ospf_distribute_list_update(
85 ospf, type, red->instance);
86 }
87 }
88 }
89 }
90 }
91
92 static void ospf_route_map_event(route_map_event_t event, const char *name)
93 {
94 struct ospf *ospf;
95 int type;
96 struct listnode *n1 = NULL;
97
98 for (ALL_LIST_ELEMENTS_RO(om->ospf, n1, ospf)) {
99 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
100 struct list *red_list;
101 struct listnode *node;
102 struct ospf_redist *red;
103
104 red_list = ospf->redist[type];
105 if (!red_list)
106 continue;
107
108 for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
109 if (ROUTEMAP_NAME(red) && ROUTEMAP(red)
110 && !strcmp(ROUTEMAP_NAME(red), name)) {
111 ospf_distribute_list_update(
112 ospf, type, red->instance);
113 }
114 }
115 }
116 }
117 }
118
119 /* `match ip netxthop ' */
120 /* Match function return 1 if match is success else return zero. */
121 static route_map_result_t route_match_ip_nexthop(void *rule,
122 const struct prefix *prefix,
123 route_map_object_t type,
124 void *object)
125 {
126 struct access_list *alist;
127 struct external_info *ei = object;
128 struct prefix_ipv4 p;
129
130 if (type == RMAP_OSPF) {
131 p.family = AF_INET;
132 p.prefix = ei->nexthop;
133 p.prefixlen = IPV4_MAX_BITLEN;
134
135 alist = access_list_lookup(AFI_IP, (char *)rule);
136 if (alist == NULL)
137 return RMAP_NOMATCH;
138
139 return (access_list_apply(alist, &p) == FILTER_DENY
140 ? RMAP_NOMATCH
141 : RMAP_MATCH);
142 }
143 return RMAP_NOMATCH;
144 }
145
146 /* Route map `ip next-hop' match statement. `arg' should be
147 access-list name. */
148 static void *route_match_ip_nexthop_compile(const char *arg)
149 {
150 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
151 }
152
153 /* Free route map's compiled `ip address' value. */
154 static void route_match_ip_nexthop_free(void *rule)
155 {
156 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
157 }
158
159 /* Route map commands for metric matching. */
160 struct route_map_rule_cmd route_match_ip_nexthop_cmd = {
161 "ip next-hop", route_match_ip_nexthop, route_match_ip_nexthop_compile,
162 route_match_ip_nexthop_free};
163
164 /* `match ip next-hop prefix-list PREFIX_LIST' */
165
166 static route_map_result_t
167 route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
168 route_map_object_t type, void *object)
169 {
170 struct prefix_list *plist;
171 struct external_info *ei = object;
172 struct prefix_ipv4 p;
173
174 if (type == RMAP_OSPF) {
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
184 ? RMAP_NOMATCH
185 : RMAP_MATCH);
186 }
187 return RMAP_NOMATCH;
188 }
189
190 static void *route_match_ip_next_hop_prefix_list_compile(const char *arg)
191 {
192 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
193 }
194
195 static void route_match_ip_next_hop_prefix_list_free(void *rule)
196 {
197 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
198 }
199
200 struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
201 "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list,
202 route_match_ip_next_hop_prefix_list_compile,
203 route_match_ip_next_hop_prefix_list_free};
204
205 /* `match ip address IP_ACCESS_LIST' */
206 /* Match function should return 1 if match is success else return
207 zero. */
208 static route_map_result_t route_match_ip_address(void *rule,
209 const struct prefix *prefix,
210 route_map_object_t type,
211 void *object)
212 {
213 struct access_list *alist;
214 /* struct prefix_ipv4 match; */
215
216 if (type == RMAP_OSPF) {
217 alist = access_list_lookup(AFI_IP, (char *)rule);
218 if (alist == NULL)
219 return RMAP_NOMATCH;
220
221 return (access_list_apply(alist, prefix) == FILTER_DENY
222 ? RMAP_NOMATCH
223 : RMAP_MATCH);
224 }
225 return RMAP_NOMATCH;
226 }
227
228 /* Route map `ip address' match statement. `arg' should be
229 access-list name. */
230 static void *route_match_ip_address_compile(const char *arg)
231 {
232 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
233 }
234
235 /* Free route map's compiled `ip address' value. */
236 static void route_match_ip_address_free(void *rule)
237 {
238 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
239 }
240
241 /* Route map commands for ip address matching. */
242 struct route_map_rule_cmd route_match_ip_address_cmd = {
243 "ip address", route_match_ip_address, route_match_ip_address_compile,
244 route_match_ip_address_free};
245
246 /* `match ip address prefix-list PREFIX_LIST' */
247 static route_map_result_t
248 route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
249 route_map_object_t type, void *object)
250 {
251 struct prefix_list *plist;
252
253 if (type == RMAP_OSPF) {
254 plist = prefix_list_lookup(AFI_IP, (char *)rule);
255 if (plist == NULL)
256 return RMAP_NOMATCH;
257
258 return (prefix_list_apply(plist, prefix) == PREFIX_DENY
259 ? RMAP_NOMATCH
260 : RMAP_MATCH);
261 }
262 return RMAP_NOMATCH;
263 }
264
265 static void *route_match_ip_address_prefix_list_compile(const char *arg)
266 {
267 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
268 }
269
270 static void route_match_ip_address_prefix_list_free(void *rule)
271 {
272 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
273 }
274
275 struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
276 "ip address prefix-list", route_match_ip_address_prefix_list,
277 route_match_ip_address_prefix_list_compile,
278 route_match_ip_address_prefix_list_free};
279
280 /* `match interface IFNAME' */
281 /* Match function should return 1 if match is success else return
282 zero. */
283 static route_map_result_t route_match_interface(void *rule,
284 const struct prefix *prefix,
285 route_map_object_t type,
286 void *object)
287 {
288 struct interface *ifp;
289 struct external_info *ei;
290
291 if (type == RMAP_OSPF) {
292 ei = object;
293 ifp = if_lookup_by_name_all_vrf((char *)rule);
294
295 if (ifp == NULL || ifp->ifindex != ei->ifindex)
296 return RMAP_NOMATCH;
297
298 return RMAP_MATCH;
299 }
300 return RMAP_NOMATCH;
301 }
302
303 /* Route map `interface' match statement. `arg' should be
304 interface name. */
305 static void *route_match_interface_compile(const char *arg)
306 {
307 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
308 }
309
310 /* Free route map's compiled `interface' value. */
311 static void route_match_interface_free(void *rule)
312 {
313 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
314 }
315
316 /* Route map commands for ip address matching. */
317 struct route_map_rule_cmd route_match_interface_cmd = {
318 "interface", route_match_interface, route_match_interface_compile,
319 route_match_interface_free};
320
321 /* Match function return 1 if match is success else return zero. */
322 static route_map_result_t route_match_tag(void *rule,
323 const struct prefix *prefix,
324 route_map_object_t type, void *object)
325 {
326 route_tag_t *tag;
327 struct external_info *ei;
328
329 if (type == RMAP_OSPF) {
330 tag = rule;
331 ei = object;
332
333 return ((ei->tag == *tag) ? RMAP_MATCH : RMAP_NOMATCH);
334 }
335
336 return RMAP_NOMATCH;
337 }
338
339 /* Route map commands for tag matching. */
340 static struct route_map_rule_cmd route_match_tag_cmd = {
341 "tag", route_match_tag, route_map_rule_tag_compile,
342 route_map_rule_tag_free,
343 };
344
345 struct ospf_metric {
346 enum { metric_increment, metric_decrement, metric_absolute } type;
347 bool used;
348 uint32_t metric;
349 };
350
351 /* `set metric METRIC' */
352 /* Set metric to attribute. */
353 static route_map_result_t route_set_metric(void *rule,
354 const struct prefix *prefix,
355 route_map_object_t type,
356 void *object)
357 {
358 struct ospf_metric *metric;
359 struct external_info *ei;
360
361 if (type == RMAP_OSPF) {
362 /* Fetch routemap's rule information. */
363 metric = rule;
364 ei = object;
365
366 /* Set metric out value. */
367 if (!metric->used)
368 return RMAP_OKAY;
369 if (metric->type == metric_increment)
370 ei->route_map_set.metric += metric->metric;
371 if (metric->type == metric_decrement)
372 ei->route_map_set.metric -= metric->metric;
373 if (metric->type == metric_absolute)
374 ei->route_map_set.metric = metric->metric;
375
376 if ((signed int)ei->route_map_set.metric < 1)
377 ei->route_map_set.metric = -1;
378 if (ei->route_map_set.metric > OSPF_LS_INFINITY)
379 ei->route_map_set.metric = OSPF_LS_INFINITY;
380 }
381 return RMAP_OKAY;
382 }
383
384 /* set metric compilation. */
385 static void *route_set_metric_compile(const char *arg)
386 {
387 struct ospf_metric *metric;
388
389 metric = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
390 metric->used = false;
391
392 if (all_digit(arg))
393 metric->type = metric_absolute;
394
395 if (strmatch(arg, "+rtt") || strmatch(arg, "-rtt")) {
396 flog_warn(EC_OSPF_SET_METRIC_PLUS,
397 "OSPF does not support 'set metric +rtt / -rtt'");
398 return metric;
399 }
400
401 if ((arg[0] == '+') && all_digit(arg + 1)) {
402 metric->type = metric_increment;
403 arg++;
404 }
405
406 if ((arg[0] == '-') && all_digit(arg + 1)) {
407 metric->type = metric_decrement;
408 arg++;
409 }
410
411 metric->metric = strtoul(arg, NULL, 10);
412
413 if (metric->metric)
414 metric->used = true;
415
416 return metric;
417 }
418
419 /* Free route map's compiled `set metric' value. */
420 static void route_set_metric_free(void *rule)
421 {
422 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
423 }
424
425 /* Set metric rule structure. */
426 struct route_map_rule_cmd route_set_metric_cmd = {
427 "metric", route_set_metric, route_set_metric_compile,
428 route_set_metric_free,
429 };
430
431 /* `set metric-type TYPE' */
432 /* Set metric-type to attribute. */
433 static route_map_result_t route_set_metric_type(void *rule,
434 const struct prefix *prefix,
435 route_map_object_t type,
436 void *object)
437 {
438 uint32_t *metric_type;
439 struct external_info *ei;
440
441 if (type == RMAP_OSPF) {
442 /* Fetch routemap's rule information. */
443 metric_type = rule;
444 ei = object;
445
446 /* Set metric out value. */
447 ei->route_map_set.metric_type = *metric_type;
448 }
449 return RMAP_OKAY;
450 }
451
452 /* set metric-type compilation. */
453 static void *route_set_metric_type_compile(const char *arg)
454 {
455 uint32_t *metric_type;
456
457 metric_type = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
458 if (strcmp(arg, "type-1") == 0)
459 *metric_type = EXTERNAL_METRIC_TYPE_1;
460 else if (strcmp(arg, "type-2") == 0)
461 *metric_type = EXTERNAL_METRIC_TYPE_2;
462
463 if (*metric_type == EXTERNAL_METRIC_TYPE_1
464 || *metric_type == EXTERNAL_METRIC_TYPE_2)
465 return metric_type;
466
467 XFREE(MTYPE_ROUTE_MAP_COMPILED, metric_type);
468 return NULL;
469 }
470
471 /* Free route map's compiled `set metric-type' value. */
472 static void route_set_metric_type_free(void *rule)
473 {
474 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
475 }
476
477 /* Set metric rule structure. */
478 struct route_map_rule_cmd route_set_metric_type_cmd = {
479 "metric-type", route_set_metric_type, route_set_metric_type_compile,
480 route_set_metric_type_free,
481 };
482
483 static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix,
484 route_map_object_t type, void *object)
485 {
486 route_tag_t *tag;
487 struct external_info *ei;
488
489 if (type == RMAP_OSPF) {
490 tag = rule;
491 ei = object;
492
493 /* Set tag value */
494 ei->tag = *tag;
495 }
496
497 return RMAP_OKAY;
498 }
499
500 /* Route map commands for tag set. */
501 static struct route_map_rule_cmd route_set_tag_cmd = {
502 "tag", route_set_tag, route_map_rule_tag_compile,
503 route_map_rule_tag_free,
504 };
505
506 DEFUN (set_metric_type,
507 set_metric_type_cmd,
508 "set metric-type <type-1|type-2>",
509 SET_STR
510 "Type of metric for destination routing protocol\n"
511 "OSPF[6] external type 1 metric\n"
512 "OSPF[6] external type 2 metric\n")
513 {
514 char *ext = argv[2]->text;
515 return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
516 "metric-type", ext);
517 }
518
519 DEFUN (no_set_metric_type,
520 no_set_metric_type_cmd,
521 "no set metric-type [<type-1|type-2>]",
522 NO_STR
523 SET_STR
524 "Type of metric for destination routing protocol\n"
525 "OSPF[6] external type 1 metric\n"
526 "OSPF[6] external type 2 metric\n")
527 {
528 char *ext = (argc == 4) ? argv[3]->text : NULL;
529 return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
530 "metric-type", ext);
531 }
532
533 /* Route-map init */
534 void ospf_route_map_init(void)
535 {
536 route_map_init();
537
538 route_map_add_hook(ospf_route_map_update);
539 route_map_delete_hook(ospf_route_map_update);
540 route_map_event_hook(ospf_route_map_event);
541
542 route_map_set_metric_hook(generic_set_add);
543 route_map_no_set_metric_hook(generic_set_delete);
544
545 route_map_match_ip_next_hop_hook(generic_match_add);
546 route_map_no_match_ip_next_hop_hook(generic_match_delete);
547
548 route_map_match_interface_hook(generic_match_add);
549 route_map_no_match_interface_hook(generic_match_delete);
550
551 route_map_match_ip_address_hook(generic_match_add);
552 route_map_no_match_ip_address_hook(generic_match_delete);
553
554 route_map_match_ip_address_prefix_list_hook(generic_match_add);
555 route_map_no_match_ip_address_prefix_list_hook(generic_match_delete);
556
557 route_map_match_ip_next_hop_prefix_list_hook(generic_match_add);
558 route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete);
559
560 route_map_match_tag_hook(generic_match_add);
561 route_map_no_match_tag_hook(generic_match_delete);
562
563 route_map_set_metric_hook(generic_set_add);
564 route_map_no_set_metric_hook(generic_set_delete);
565
566 route_map_set_tag_hook(generic_set_add);
567 route_map_no_set_tag_hook(generic_set_delete);
568
569 route_map_install_match(&route_match_ip_nexthop_cmd);
570 route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
571 route_map_install_match(&route_match_ip_address_cmd);
572 route_map_install_match(&route_match_ip_address_prefix_list_cmd);
573 route_map_install_match(&route_match_interface_cmd);
574 route_map_install_match(&route_match_tag_cmd);
575
576 route_map_install_set(&route_set_metric_cmd);
577 route_map_install_set(&route_set_metric_type_cmd);
578 route_map_install_set(&route_set_tag_cmd);
579
580 install_element(RMAP_NODE, &set_metric_type_cmd);
581 install_element(RMAP_NODE, &no_set_metric_type_cmd);
582 }