]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_routemap.c
Merge pull request #617 from donaldsharp/bgp_nexthop
[mirror_frr.git] / ospfd / ospf_routemap.c
CommitLineData
718e3744 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 *
896014f4
DL
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
718e3744 22 */
23
24#include <zebra.h>
25
26#include "memory.h"
27#include "prefix.h"
28#include "table.h"
82f97584 29#include "vty.h"
718e3744 30#include "routemap.h"
31#include "command.h"
32#include "log.h"
33#include "plist.h"
1306c09a 34#include "vrf.h"
718e3744 35
36#include "ospfd/ospfd.h"
37#include "ospfd/ospf_asbr.h"
38#include "ospfd/ospf_interface.h"
39#include "ospfd/ospf_lsa.h"
40#include "ospfd/ospf_route.h"
41#include "ospfd/ospf_zebra.h"
42
43/* Hook function for updating route_map assignment. */
4dadc291 44static void
6c835671 45ospf_route_map_update (const char *name)
718e3744 46{
73ffb25b 47 struct ospf *ospf;
718e3744 48 int type;
49
50 /* If OSPF instatnce does not exist, return right now. */
73ffb25b 51 ospf = ospf_lookup ();
52 if (ospf == NULL)
718e3744 53 return;
54
55 /* Update route-map */
56 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
57 {
7c8ff89e
DS
58 struct list *red_list;
59 struct listnode *node;
60 struct ospf_redist *red;
61
62 red_list = ospf->redist[type];
63 if (!red_list)
64 continue;
65
66 for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
67 {
68 if (ROUTEMAP_NAME (red)
69 && strcmp (ROUTEMAP_NAME (red), name) == 0)
70 {
71 /* Keep old route-map. */
72 struct route_map *old = ROUTEMAP (red);
73
74 /* Update route-map. */
75 ROUTEMAP (red) =
76 route_map_lookup_by_name (ROUTEMAP_NAME (red));
77
78 /* No update for this distribute type. */
79 if (old == NULL && ROUTEMAP (red) == NULL)
80 continue;
81
82 ospf_distribute_list_update (ospf, type, red->instance);
83 }
84 }
718e3744 85 }
86}
87
4dadc291 88static void
6c835671 89ospf_route_map_event (route_map_event_t event, const char *name)
718e3744 90{
73ffb25b 91 struct ospf *ospf;
718e3744 92 int type;
93
94 /* If OSPF instatnce does not exist, return right now. */
73ffb25b 95 ospf = ospf_lookup ();
96 if (ospf == NULL)
718e3744 97 return;
98
718e3744 99 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
100 {
7c8ff89e
DS
101 struct list *red_list;
102 struct listnode *node;
103 struct ospf_redist *red;
104
105 red_list = ospf->redist[type];
106 if (!red_list)
107 continue;
108
109 for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
718e3744 110 {
7c8ff89e
DS
111 if (ROUTEMAP_NAME (red) && ROUTEMAP (red)
112 && !strcmp (ROUTEMAP_NAME (red), name))
113 {
114 ospf_distribute_list_update (ospf, type, red->instance);
115 }
718e3744 116 }
117 }
118}
119
120/* Delete rip route map rule. */
4dadc291 121static int
cdc2d765 122ospf_route_match_delete (struct vty *vty,
6c835671 123 const char *command, const char *arg)
718e3744 124{
cdc2d765 125 VTY_DECLVAR_CONTEXT(route_map_index, index);
718e3744 126 int ret;
127
128 ret = route_map_delete_match (index, command, arg);
129 if (ret)
130 {
131 switch (ret)
132 {
133 case RMAP_RULE_MISSING:
5e3edbf5 134 vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE);
718e3744 135 return CMD_WARNING;
718e3744 136 case RMAP_COMPILE_ERROR:
5e3edbf5 137 vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE);
718e3744 138 return CMD_WARNING;
718e3744 139 }
140 }
141
142 return CMD_SUCCESS;
143}
144
4dadc291 145static int
cdc2d765 146ospf_route_match_add (struct vty *vty,
6c835671 147 const char *command, const char *arg)
cdc2d765
DL
148{
149 VTY_DECLVAR_CONTEXT(route_map_index, index);
718e3744 150 int ret;
151
152 ret = route_map_add_match (index, command, arg);
153 if (ret)
154 {
155 switch (ret)
156 {
157 case RMAP_RULE_MISSING:
5e3edbf5 158 vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE);
718e3744 159 return CMD_WARNING;
718e3744 160 case RMAP_COMPILE_ERROR:
5e3edbf5 161 vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE);
718e3744 162 return CMD_WARNING;
718e3744 163 }
164 }
165
166 return CMD_SUCCESS;
167}
168
718e3744 169/* `match ip netxthop ' */
170/* Match function return 1 if match is success else return zero. */
4dadc291 171static route_map_result_t
718e3744 172route_match_ip_nexthop (void *rule, struct prefix *prefix,
173 route_map_object_t type, void *object)
174{
175 struct access_list *alist;
176 struct external_info *ei = object;
177 struct prefix_ipv4 p;
178
179 if (type == RMAP_OSPF)
180 {
181 p.family = AF_INET;
182 p.prefix = ei->nexthop;
183 p.prefixlen = IPV4_MAX_BITLEN;
184
185 alist = access_list_lookup (AFI_IP, (char *) rule);
186 if (alist == NULL)
187 return RMAP_NOMATCH;
188
189 return (access_list_apply (alist, &p) == FILTER_DENY ?
190 RMAP_NOMATCH : RMAP_MATCH);
191 }
192 return RMAP_NOMATCH;
193}
194
195/* Route map `ip next-hop' match statement. `arg' should be
196 access-list name. */
4dadc291 197static void *
6c835671 198route_match_ip_nexthop_compile (const char *arg)
718e3744 199{
200 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
201}
202
203/* Free route map's compiled `ip address' value. */
4dadc291 204static void
718e3744 205route_match_ip_nexthop_free (void *rule)
206{
207 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
208}
209
210/* Route map commands for metric matching. */
211struct route_map_rule_cmd route_match_ip_nexthop_cmd =
212{
213 "ip next-hop",
214 route_match_ip_nexthop,
215 route_match_ip_nexthop_compile,
216 route_match_ip_nexthop_free
217};
218
219/* `match ip next-hop prefix-list PREFIX_LIST' */
220
4dadc291 221static route_map_result_t
718e3744 222route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
223 route_map_object_t type, void *object)
224{
225 struct prefix_list *plist;
226 struct external_info *ei = object;
227 struct prefix_ipv4 p;
228
229 if (type == RMAP_OSPF)
230 {
231 p.family = AF_INET;
232 p.prefix = ei->nexthop;
233 p.prefixlen = IPV4_MAX_BITLEN;
234
235 plist = prefix_list_lookup (AFI_IP, (char *) rule);
236 if (plist == NULL)
237 return RMAP_NOMATCH;
238
239 return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
240 RMAP_NOMATCH : RMAP_MATCH);
241 }
242 return RMAP_NOMATCH;
243}
244
4dadc291 245static void *
6c835671 246route_match_ip_next_hop_prefix_list_compile (const char *arg)
718e3744 247{
248 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
249}
250
4dadc291 251static void
718e3744 252route_match_ip_next_hop_prefix_list_free (void *rule)
253{
254 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
255}
256
257struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
258{
259 "ip next-hop prefix-list",
260 route_match_ip_next_hop_prefix_list,
261 route_match_ip_next_hop_prefix_list_compile,
262 route_match_ip_next_hop_prefix_list_free
263};
264
265/* `match ip address IP_ACCESS_LIST' */
266/* Match function should return 1 if match is success else return
267 zero. */
4dadc291 268static route_map_result_t
718e3744 269route_match_ip_address (void *rule, struct prefix *prefix,
270 route_map_object_t type, void *object)
271{
272 struct access_list *alist;
273 /* struct prefix_ipv4 match; */
274
275 if (type == RMAP_OSPF)
276 {
277 alist = access_list_lookup (AFI_IP, (char *) rule);
278 if (alist == NULL)
279 return RMAP_NOMATCH;
280
281 return (access_list_apply (alist, prefix) == FILTER_DENY ?
282 RMAP_NOMATCH : RMAP_MATCH);
283 }
284 return RMAP_NOMATCH;
285}
286
287/* Route map `ip address' match statement. `arg' should be
288 access-list name. */
4dadc291 289static void *
6c835671 290route_match_ip_address_compile (const char *arg)
718e3744 291{
292 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
293}
294
295/* Free route map's compiled `ip address' value. */
4dadc291 296static void
718e3744 297route_match_ip_address_free (void *rule)
298{
299 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
300}
301
302/* Route map commands for ip address matching. */
303struct route_map_rule_cmd route_match_ip_address_cmd =
304{
305 "ip address",
306 route_match_ip_address,
307 route_match_ip_address_compile,
308 route_match_ip_address_free
309};
310
311/* `match ip address prefix-list PREFIX_LIST' */
4dadc291 312static route_map_result_t
718e3744 313route_match_ip_address_prefix_list (void *rule, struct prefix *prefix,
314 route_map_object_t type, void *object)
315{
316 struct prefix_list *plist;
317
318 if (type == RMAP_OSPF)
319 {
320 plist = prefix_list_lookup (AFI_IP, (char *) rule);
321 if (plist == NULL)
322 return RMAP_NOMATCH;
323
324 return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
325 RMAP_NOMATCH : RMAP_MATCH);
326 }
327 return RMAP_NOMATCH;
328}
329
4dadc291 330static void *
6c835671 331route_match_ip_address_prefix_list_compile (const char *arg)
718e3744 332{
333 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
334}
335
4dadc291 336static void
718e3744 337route_match_ip_address_prefix_list_free (void *rule)
338{
339 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
340}
341
342struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
343{
344 "ip address prefix-list",
345 route_match_ip_address_prefix_list,
346 route_match_ip_address_prefix_list_compile,
347 route_match_ip_address_prefix_list_free
348};
349
350/* `match interface IFNAME' */
351/* Match function should return 1 if match is success else return
352 zero. */
4dadc291 353static route_map_result_t
718e3744 354route_match_interface (void *rule, struct prefix *prefix,
355 route_map_object_t type, void *object)
356{
357 struct interface *ifp;
358 struct external_info *ei;
359
360 if (type == RMAP_OSPF)
361 {
362 ei = object;
1306c09a 363 ifp = if_lookup_by_name ((char *)rule, VRF_DEFAULT);
718e3744 364
365 if (ifp == NULL || ifp->ifindex != ei->ifindex)
366 return RMAP_NOMATCH;
367
368 return RMAP_MATCH;
369 }
370 return RMAP_NOMATCH;
371}
372
373/* Route map `interface' match statement. `arg' should be
374 interface name. */
4dadc291 375static void *
6c835671 376route_match_interface_compile (const char *arg)
718e3744 377{
378 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
379}
380
381/* Free route map's compiled `interface' value. */
4dadc291 382static void
718e3744 383route_match_interface_free (void *rule)
384{
385 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
386}
387
388/* Route map commands for ip address matching. */
389struct route_map_rule_cmd route_match_interface_cmd =
390{
391 "interface",
392 route_match_interface,
393 route_match_interface_compile,
394 route_match_interface_free
395};
396
0d9551dc
DS
397/* Match function return 1 if match is success else return zero. */
398static route_map_result_t
399route_match_tag (void *rule, struct prefix *prefix,
400 route_map_object_t type, void *object)
401{
dc9ffce8 402 route_tag_t *tag;
0d9551dc
DS
403 struct external_info *ei;
404
405 if (type == RMAP_OSPF)
406 {
407 tag = rule;
408 ei = object;
409
410 return ((ei->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH);
411 }
412
413 return RMAP_NOMATCH;
414}
415
0d9551dc 416/* Route map commands for tag matching. */
dc9ffce8 417static struct route_map_rule_cmd route_match_tag_cmd =
0d9551dc
DS
418{
419 "tag",
420 route_match_tag,
dc9ffce8
CF
421 route_map_rule_tag_compile,
422 route_map_rule_tag_free,
0d9551dc
DS
423};
424
425
718e3744 426/* `set metric METRIC' */
427/* Set metric to attribute. */
4dadc291 428static route_map_result_t
718e3744 429route_set_metric (void *rule, struct prefix *prefix,
430 route_map_object_t type, void *object)
431{
432 u_int32_t *metric;
433 struct external_info *ei;
434
435 if (type == RMAP_OSPF)
436 {
437 /* Fetch routemap's rule information. */
438 metric = rule;
439 ei = object;
440
441 /* Set metric out value. */
442 ei->route_map_set.metric = *metric;
443 }
444 return RMAP_OKAY;
445}
446
447/* set metric compilation. */
4dadc291 448static void *
6c835671 449route_set_metric_compile (const char *arg)
718e3744 450{
451 u_int32_t *metric;
fbc043a8 452 int32_t ret;
718e3744 453
5e3edbf5
DS
454 /* OSPF doesn't support the +/- in
455 set metric <+/-metric> check
456 Ignore the +/- component */
457 if (! all_digit (arg))
ed2eb093
DS
458 {
459 if ((strncmp (arg, "+", 1) == 0 || strncmp (arg, "-", 1) == 0) &&
460 all_digit (arg+1))
461 {
462 zlog_warn ("OSPF does not support 'set metric +/-'");
463 arg++;
464 }
465 else
466 {
467 return NULL;
468 }
469 }
718e3744 470 metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
fbc043a8 471 ret = atoi (arg);
718e3744 472
fbc043a8
AC
473 if (ret >= 0)
474 {
475 *metric = (u_int32_t)ret;
476 return metric;
477 }
718e3744 478
479 XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
480 return NULL;
481}
482
483/* Free route map's compiled `set metric' value. */
4dadc291 484static void
718e3744 485route_set_metric_free (void *rule)
486{
487 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
488}
489
490/* Set metric rule structure. */
491struct route_map_rule_cmd route_set_metric_cmd =
492{
493 "metric",
494 route_set_metric,
495 route_set_metric_compile,
496 route_set_metric_free,
497};
498
499/* `set metric-type TYPE' */
500/* Set metric-type to attribute. */
4dadc291 501static route_map_result_t
718e3744 502route_set_metric_type (void *rule, struct prefix *prefix,
503 route_map_object_t type, void *object)
504{
505 u_int32_t *metric_type;
506 struct external_info *ei;
507
508 if (type == RMAP_OSPF)
509 {
510 /* Fetch routemap's rule information. */
511 metric_type = rule;
512 ei = object;
513
514 /* Set metric out value. */
515 ei->route_map_set.metric_type = *metric_type;
516 }
517 return RMAP_OKAY;
518}
519
520/* set metric-type compilation. */
4dadc291 521static void *
6c835671 522route_set_metric_type_compile (const char *arg)
718e3744 523{
524 u_int32_t *metric_type;
525
526 metric_type = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
527 if (strcmp (arg, "type-1") == 0)
528 *metric_type = EXTERNAL_METRIC_TYPE_1;
529 else if (strcmp (arg, "type-2") == 0)
530 *metric_type = EXTERNAL_METRIC_TYPE_2;
531
532 if (*metric_type == EXTERNAL_METRIC_TYPE_1 ||
533 *metric_type == EXTERNAL_METRIC_TYPE_2)
534 return metric_type;
535
536 XFREE (MTYPE_ROUTE_MAP_COMPILED, metric_type);
537 return NULL;
538}
539
540/* Free route map's compiled `set metric-type' value. */
4dadc291 541static void
718e3744 542route_set_metric_type_free (void *rule)
543{
544 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
545}
546
547/* Set metric rule structure. */
548struct route_map_rule_cmd route_set_metric_type_cmd =
549{
550 "metric-type",
551 route_set_metric_type,
552 route_set_metric_type_compile,
553 route_set_metric_type_free,
554};
555
0d9551dc
DS
556static route_map_result_t
557route_set_tag (void *rule, struct prefix *prefix,
558 route_map_object_t type, void *object)
559{
dc9ffce8 560 route_tag_t *tag;
0d9551dc
DS
561 struct external_info *ei;
562
563 if (type == RMAP_OSPF)
564 {
565 tag = rule;
566 ei = object;
567
568 /* Set tag value */
569 ei->tag=*tag;
570 }
571
572 return RMAP_OKAY;
573}
574
0d9551dc 575/* Route map commands for tag set. */
dc9ffce8 576static struct route_map_rule_cmd route_set_tag_cmd =
0d9551dc
DS
577{
578 "tag",
579 route_set_tag,
dc9ffce8
CF
580 route_map_rule_tag_compile,
581 route_map_rule_tag_free,
0d9551dc
DS
582};
583
718e3744 584DEFUN (match_ip_nexthop,
585 match_ip_nexthop_cmd,
6147e2c6 586 "match ip next-hop <(1-199)|(1300-2699)|WORD>",
718e3744 587 MATCH_STR
588 IP_STR
589 "Match next-hop address of route\n"
590 "IP access-list number\n"
591 "IP access-list number (expanded range)\n"
592 "IP access-list name\n")
593{
8d769265 594 int idx_acl = 3;
cdc2d765 595 return ospf_route_match_add (vty, "ip next-hop", argv[idx_acl]->arg);
718e3744 596}
597
598DEFUN (no_match_ip_nexthop,
599 no_match_ip_nexthop_cmd,
692b4c65 600 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
718e3744 601 NO_STR
602 MATCH_STR
603 IP_STR
692b4c65
QY
604 "Match next-hop address of route\n"
605 "IP access-list number\n"
606 "IP access-list number (expanded range)\n"
607 "IP access-list name\n")
718e3744 608{
692b4c65 609 char *al = (argc == 5) ? argv[4]->arg : NULL;
cdc2d765 610 return ospf_route_match_delete (vty, "ip next-hop", al);
718e3744 611}
612
718e3744 613DEFUN (set_metric_type,
614 set_metric_type_cmd,
6147e2c6 615 "set metric-type <type-1|type-2>",
718e3744 616 SET_STR
617 "Type of metric for destination routing protocol\n"
73ffb25b 618 "OSPF[6] external type 1 metric\n"
619 "OSPF[6] external type 2 metric\n")
718e3744 620{
692b4c65 621 char *ext = argv[2]->text;
cdc2d765
DL
622 return generic_set_add (vty, VTY_GET_CONTEXT(route_map_index),
623 "metric-type", ext);
718e3744 624}
625
626DEFUN (no_set_metric_type,
627 no_set_metric_type_cmd,
692b4c65 628 "no set metric-type [<type-1|type-2>]",
718e3744 629 NO_STR
630 SET_STR
ff788d08 631 "Type of metric for destination routing protocol\n"
692b4c65 632 "OSPF[6] external type 1 metric\n"
ff788d08 633 "OSPF[6] external type 2 metric\n")
718e3744 634{
692b4c65 635 char *ext = (argc == 4) ? argv[3]->text : NULL;
cdc2d765
DL
636 return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
637 "metric-type", ext);
0d9551dc
DS
638}
639
718e3744 640/* Route-map init */
641void
642ospf_route_map_init (void)
643{
644 route_map_init ();
718e3744 645
646 route_map_add_hook (ospf_route_map_update);
647 route_map_delete_hook (ospf_route_map_update);
648 route_map_event_hook (ospf_route_map_event);
82f97584
DW
649
650 route_map_match_interface_hook (generic_match_add);
651 route_map_no_match_interface_hook (generic_match_delete);
652
653 route_map_match_ip_address_hook (generic_match_add);
654 route_map_no_match_ip_address_hook (generic_match_delete);
655
656 route_map_match_ip_address_prefix_list_hook (generic_match_add);
657 route_map_no_match_ip_address_prefix_list_hook (generic_match_delete);
658
659 route_map_match_ip_next_hop_prefix_list_hook (generic_match_add);
660 route_map_no_match_ip_next_hop_prefix_list_hook (generic_match_delete);
661
662 route_map_match_tag_hook (generic_match_add);
663 route_map_no_match_tag_hook (generic_match_delete);
664
665 route_map_set_metric_hook (generic_set_add);
666 route_map_no_set_metric_hook (generic_set_delete);
667
668 route_map_set_tag_hook (generic_set_add);
669 route_map_no_set_tag_hook (generic_set_delete);
718e3744 670
671 route_map_install_match (&route_match_ip_nexthop_cmd);
672 route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
673 route_map_install_match (&route_match_ip_address_cmd);
674 route_map_install_match (&route_match_ip_address_prefix_list_cmd);
675 route_map_install_match (&route_match_interface_cmd);
0d9551dc 676 route_map_install_match (&route_match_tag_cmd);
718e3744 677
678 route_map_install_set (&route_set_metric_cmd);
679 route_map_install_set (&route_set_metric_type_cmd);
0d9551dc 680 route_map_install_set (&route_set_tag_cmd);
718e3744 681
682 install_element (RMAP_NODE, &match_ip_nexthop_cmd);
683 install_element (RMAP_NODE, &no_match_ip_nexthop_cmd);
82f97584 684
718e3744 685 install_element (RMAP_NODE, &set_metric_type_cmd);
686 install_element (RMAP_NODE, &no_set_metric_type_cmd);
718e3744 687}