Import Upstream version 1.2.2
[quagga-debian.git] / ripngd / ripng_routemap.c
1 /* RIPng routemap.
2  * Copyright (C) 1999 Kunihiro Ishiguro
3  *
4  * This file is part of GNU Zebra.
5  *
6  * GNU Zebra is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2, or (at your option) any
9  * later version.
10  *
11  * GNU Zebra is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
18  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.  
20  */
21
22 #include <zebra.h>
23
24 #include "if.h"
25 #include "memory.h"
26 #include "prefix.h"
27 #include "routemap.h"
28 #include "command.h"
29 #include "sockunion.h"
30
31 #include "ripngd/ripngd.h"
32
33 struct rip_metric_modifier
34 {
35   enum 
36   {
37     metric_increment,
38     metric_decrement,
39     metric_absolute
40   } type;
41
42   u_char metric;
43 };
44
45
46 static int
47 ripng_route_match_add (struct vty *vty, struct route_map_index *index,
48                        const char *command, const char *arg)
49 {
50   int ret;
51
52   ret = route_map_add_match (index, command, arg);
53   if (ret)
54     {
55       switch (ret)
56         {
57         case RMAP_RULE_MISSING:
58           vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE);
59           return CMD_WARNING;
60         case RMAP_COMPILE_ERROR:
61           vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE);
62           return CMD_WARNING;
63         }
64     }
65   return CMD_SUCCESS;
66 }
67
68 static int
69 ripng_route_match_delete (struct vty *vty, struct route_map_index *index,
70                           const char *command, const char *arg)
71 {
72   int ret;
73
74   ret = route_map_delete_match (index, command, arg);
75   if (ret)
76     {
77       switch (ret)
78         {
79         case RMAP_RULE_MISSING:
80           vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE);
81           return CMD_WARNING;
82         case RMAP_COMPILE_ERROR:
83           vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE);
84           return CMD_WARNING;
85         }
86     }
87   return CMD_SUCCESS;
88 }
89
90 static int
91 ripng_route_set_add (struct vty *vty, struct route_map_index *index,
92                      const char *command, const char *arg)
93 {
94   int ret;
95
96   ret = route_map_add_set (index, command, arg);
97   if (ret)
98     {
99       switch (ret)
100         {
101         case RMAP_RULE_MISSING:
102           vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE);
103           return CMD_WARNING;
104         case RMAP_COMPILE_ERROR:
105           vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE);
106           return CMD_WARNING;
107         }
108     }
109   return CMD_SUCCESS;
110 }
111
112 static int
113 ripng_route_set_delete (struct vty *vty, struct route_map_index *index,
114                         const char *command, const char *arg)
115 {
116   int ret;
117
118   ret = route_map_delete_set (index, command, arg);
119   if (ret)
120     {
121       switch (ret)
122         {
123         case RMAP_RULE_MISSING:
124           vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE);
125           return CMD_WARNING;
126         case RMAP_COMPILE_ERROR:
127           vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE);
128           return CMD_WARNING;
129         }
130     }
131   return CMD_SUCCESS;
132 }
133
134 /* `match metric METRIC' */
135 /* Match function return 1 if match is success else return zero. */
136 static route_map_result_t
137 route_match_metric (void *rule, struct prefix *prefix, 
138                     route_map_object_t type, void *object)
139 {
140   u_int32_t *metric;
141   struct ripng_info *rinfo;
142
143   if (type == RMAP_RIPNG)
144     {
145       metric = rule;
146       rinfo = object;
147     
148       if (rinfo->metric == *metric)
149         return RMAP_MATCH;
150       else
151         return RMAP_NOMATCH;
152     }
153   return RMAP_NOMATCH;
154 }
155
156 /* Route map `match metric' match statement. `arg' is METRIC value */
157 static void *
158 route_match_metric_compile (const char *arg)
159 {
160   u_int32_t *metric;
161
162   metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
163   *metric = atoi (arg);
164
165   if(*metric > 0)
166     return metric;
167
168   XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
169   return NULL;
170 }
171
172 /* Free route map's compiled `match metric' value. */
173 static void
174 route_match_metric_free (void *rule)
175 {
176   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
177 }
178
179 /* Route map commands for metric matching. */
180 static struct route_map_rule_cmd route_match_metric_cmd =
181 {
182   "metric",
183   route_match_metric,
184   route_match_metric_compile,
185   route_match_metric_free
186 };
187
188 /* `match interface IFNAME' */
189 /* Match function return 1 if match is success else return zero. */
190 static route_map_result_t
191 route_match_interface (void *rule, struct prefix *prefix,
192                        route_map_object_t type, void *object)
193 {
194   struct ripng_info *rinfo;
195   struct interface *ifp;
196   char *ifname;
197
198   if (type == RMAP_RIPNG)
199     {
200       ifname = rule;
201       ifp = if_lookup_by_name(ifname);
202
203       if (!ifp)
204         return RMAP_NOMATCH;
205
206       rinfo = object;
207
208       if (rinfo->ifindex == ifp->ifindex)
209         return RMAP_MATCH;
210       else
211         return RMAP_NOMATCH;
212     }
213   return RMAP_NOMATCH;
214 }
215
216 /* Route map `match interface' match statement. `arg' is IFNAME value */
217 static void *
218 route_match_interface_compile (const char *arg)
219 {
220   return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
221 }
222
223 static void
224 route_match_interface_free (void *rule)
225 {
226   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
227 }
228
229 static struct route_map_rule_cmd route_match_interface_cmd =
230 {
231   "interface",
232   route_match_interface,
233   route_match_interface_compile,
234   route_match_interface_free
235 };
236
237 /* `match tag TAG' */
238 /* Match function return 1 if match is success else return zero. */
239 static route_map_result_t
240 route_match_tag (void *rule, struct prefix *prefix, 
241                     route_map_object_t type, void *object)
242 {
243   route_tag_t *tag;
244   struct ripng_info *rinfo;
245
246   if (type == RMAP_RIPNG)
247     {
248       tag = rule;
249       rinfo = object;
250
251       /* The information stored by rinfo is host ordered. */
252       if (rinfo->tag == *tag)
253         return RMAP_MATCH;
254       else
255         return RMAP_NOMATCH;
256     }
257   return RMAP_NOMATCH;
258 }
259
260 static struct route_map_rule_cmd route_match_tag_cmd =
261 {
262   "tag",
263   route_match_tag,
264   route_map_rule_tag_compile,
265   route_map_rule_tag_free,
266 };
267
268 /* `set metric METRIC' */
269
270 /* Set metric to attribute. */
271 static route_map_result_t
272 route_set_metric (void *rule, struct prefix *prefix, 
273                   route_map_object_t type, void *object)
274 {
275   if (type == RMAP_RIPNG)
276     {
277       struct rip_metric_modifier *mod;
278       struct ripng_info *rinfo;
279
280       mod = rule;
281       rinfo = object;
282
283       if (mod->type == metric_increment)
284         rinfo->metric_out += mod->metric;
285       else if (mod->type == metric_decrement)
286         rinfo->metric_out-= mod->metric;
287       else if (mod->type == metric_absolute)
288         rinfo->metric_out = mod->metric;
289
290       if (rinfo->metric_out < 1)
291         rinfo->metric_out = 1;
292       if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
293         rinfo->metric_out = RIPNG_METRIC_INFINITY;
294
295       rinfo->metric_set = 1;
296     }
297   return RMAP_OKAY;
298 }
299
300 /* set metric compilation. */
301 static void *
302 route_set_metric_compile (const char *arg)
303 {
304   int len;
305   const char *pnt;
306   int type;
307   long metric;
308   char *endptr = NULL;
309   struct rip_metric_modifier *mod;
310
311   len = strlen (arg);
312   pnt = arg;
313
314   if (len == 0)
315     return NULL;
316
317   /* Examine first character. */
318   if (arg[0] == '+')
319     {
320       type = metric_increment;
321       pnt++;
322     }
323   else if (arg[0] == '-')
324     {
325       type = metric_decrement;
326       pnt++;
327     }
328   else
329     type = metric_absolute;
330
331   /* Check beginning with digit string. */
332   if (*pnt < '0' || *pnt > '9')
333     return NULL;
334
335   /* Convert string to integer. */
336   metric = strtol (pnt, &endptr, 10);
337
338   if (metric == LONG_MAX || *endptr != '\0')
339     return NULL;
340   /* Commented out by Hasso Tepper, to avoid problems in vtysh. */
341   /* if (metric < 0 || metric > RIPNG_METRIC_INFINITY) */
342   if (metric < 0)
343     return NULL;
344
345   mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, 
346                  sizeof (struct rip_metric_modifier));
347   mod->type = type;
348   mod->metric = metric;
349
350   return mod;
351 }
352
353 /* Free route map's compiled `set metric' value. */
354 static void
355 route_set_metric_free (void *rule)
356 {
357   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
358 }
359
360 static struct route_map_rule_cmd route_set_metric_cmd = 
361 {
362   "metric",
363   route_set_metric,
364   route_set_metric_compile,
365   route_set_metric_free,
366 };
367
368 /* `set ipv6 next-hop local IP_ADDRESS' */
369
370 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
371 static route_map_result_t
372 route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix, 
373                       route_map_object_t type, void *object)
374 {
375   struct in6_addr *address;
376   struct ripng_info *rinfo;
377
378   if(type == RMAP_RIPNG)
379     {
380       /* Fetch routemap's rule information. */
381       address = rule;
382       rinfo = object;
383     
384       /* Set next hop value. */ 
385       rinfo->nexthop_out = *address;
386     }
387
388   return RMAP_OKAY;
389 }
390
391 /* Route map `ipv6 nexthop local' compile function.  Given string is converted
392    to struct in6_addr structure. */
393 static void *
394 route_set_ipv6_nexthop_local_compile (const char *arg)
395 {
396   int ret;
397   struct in6_addr *address;
398
399   address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr));
400
401   ret = inet_pton (AF_INET6, arg, address);
402
403   if (ret == 0)
404     {
405       XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
406       return NULL;
407     }
408
409   return address;
410 }
411
412 /* Free route map's compiled `ipv6 nexthop local' value. */
413 static void
414 route_set_ipv6_nexthop_local_free (void *rule)
415 {
416   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
417 }
418
419 /* Route map commands for ipv6 nexthop local set. */
420 static struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd =
421 {
422   "ipv6 next-hop local",
423   route_set_ipv6_nexthop_local,
424   route_set_ipv6_nexthop_local_compile,
425   route_set_ipv6_nexthop_local_free
426 };
427
428 /* `set tag TAG' */
429
430 /* Set tag to object.  ojbect must be pointer to struct attr. */
431 static route_map_result_t
432 route_set_tag (void *rule, struct prefix *prefix, 
433                       route_map_object_t type, void *object)
434 {
435   route_tag_t *tag;
436   struct ripng_info *rinfo;
437
438   if(type == RMAP_RIPNG)
439     {
440       /* Fetch routemap's rule information. */
441       tag = rule;
442       rinfo = object;
443
444       /* Set next hop value. */ 
445       rinfo->tag_out = *tag;
446     }
447
448   return RMAP_OKAY;
449 }
450
451 /* Route map commands for tag set. */
452 static struct route_map_rule_cmd route_set_tag_cmd =
453 {
454   "tag",
455   route_set_tag,
456   route_map_rule_tag_compile,
457   route_map_rule_tag_free
458 };
459
460 #define MATCH_STR "Match values from routing table\n"
461 #define SET_STR "Set values in destination routing protocol\n"
462
463 DEFUN (match_metric, 
464        match_metric_cmd,
465        "match metric <0-4294967295>",
466        MATCH_STR
467        "Match metric of route\n"
468        "Metric value\n")
469 {
470   return ripng_route_match_add (vty, vty->index, "metric", argv[0]);
471 }
472
473 DEFUN (no_match_metric,
474        no_match_metric_cmd,
475        "no match metric",
476        NO_STR
477        MATCH_STR
478        "Match metric of route\n")
479 {
480   if (argc == 0)
481     return ripng_route_match_delete (vty, vty->index, "metric", NULL);
482
483   return ripng_route_match_delete (vty, vty->index, "metric", argv[0]);
484 }
485
486 ALIAS (no_match_metric,
487        no_match_metric_val_cmd,
488        "no match metric <0-4294967295>",
489        NO_STR
490        MATCH_STR
491        "Match metric of route\n"
492        "Metric value\n")
493
494 DEFUN (match_interface,
495        match_interface_cmd,
496        "match interface WORD",
497        MATCH_STR
498        "Match first hop interface of route\n"
499        "Interface name\n")
500 {
501   return ripng_route_match_add (vty, vty->index, "interface", argv[0]);
502 }
503
504 DEFUN (no_match_interface,
505        no_match_interface_cmd,
506        "no match interface",
507        NO_STR
508        MATCH_STR
509        "Match first hop interface of route\n")
510 {
511   if (argc == 0)
512     return ripng_route_match_delete (vty, vty->index, "interface", NULL);
513
514   return ripng_route_match_delete (vty, vty->index, "interface", argv[0]);
515 }
516
517 ALIAS (no_match_interface,
518        no_match_interface_val_cmd,
519        "no match interface WORD",
520        NO_STR
521        MATCH_STR
522        "Match first hop interface of route\n"
523        "Interface name\n")
524
525 DEFUN (match_tag,
526        match_tag_cmd,
527        "match tag <1-4294967295>",
528        MATCH_STR
529        "Match tag of route\n"
530        "Metric value\n")
531 {
532   return ripng_route_match_add (vty, vty->index, "tag", argv[0]);
533 }
534
535 DEFUN (no_match_tag,
536        no_match_tag_cmd,
537        "no match tag",
538        NO_STR
539        MATCH_STR
540        "Match tag of route\n")
541 {
542   if (argc == 0)
543     return ripng_route_match_delete (vty, vty->index, "tag", NULL);
544
545   return ripng_route_match_delete (vty, vty->index, "tag", argv[0]);
546 }
547
548 ALIAS (no_match_tag,
549        no_match_tag_val_cmd,
550        "no match tag <1-4294967295>",
551        NO_STR
552        MATCH_STR
553        "Match tag of route\n"
554        "Metric value\n")
555
556 /* set functions */
557
558 DEFUN (set_metric,
559        set_metric_cmd,
560        "set metric <0-4294967295>",
561        "Set value\n"
562        "Metric value for destination routing protocol\n"
563        "Metric value\n")
564 {
565   return ripng_route_set_add (vty, vty->index, "metric", argv[0]);
566 }
567
568 DEFUN (no_set_metric,
569        no_set_metric_cmd,
570        "no set metric",
571        NO_STR
572        SET_STR
573        "Metric value for destination routing protocol\n")
574 {
575   if (argc == 0)
576     return ripng_route_set_delete (vty, vty->index, "metric", NULL);
577
578   return ripng_route_set_delete (vty, vty->index, "metric", argv[0]);
579 }
580
581 ALIAS (no_set_metric,
582        no_set_metric_val_cmd,
583        "no set metric <0-4294967295>",
584        NO_STR
585        SET_STR
586        "Metric value for destination routing protocol\n"
587        "Metric value\n")
588
589 DEFUN (set_ipv6_nexthop_local,
590        set_ipv6_nexthop_local_cmd,
591        "set ipv6 next-hop local X:X::X:X",
592        SET_STR
593        IPV6_STR
594        "IPv6 next-hop address\n"
595        "IPv6 local address\n"
596        "IPv6 address of next hop\n")
597 {
598   union sockunion su;
599   int ret;
600
601   ret = str2sockunion (argv[0], &su);
602   if (ret < 0)
603     {
604       vty_out (vty, "%% Malformed next-hop local address%s", VTY_NEWLINE);
605       return CMD_WARNING;
606     }
607
608   return ripng_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]);
609 }
610
611 DEFUN (no_set_ipv6_nexthop_local,
612        no_set_ipv6_nexthop_local_cmd,
613        "no set ipv6 next-hop local",
614        NO_STR
615        SET_STR
616        IPV6_STR
617        "IPv6 next-hop address\n"
618        "IPv6 local address\n")
619 {
620   if (argc == 0)
621     return ripng_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL);
622
623   return ripng_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]);
624 }
625
626 ALIAS (no_set_ipv6_nexthop_local,
627        no_set_ipv6_nexthop_local_val_cmd,
628        "no set ipv6 next-hop local X:X::X:X",
629        NO_STR
630        SET_STR
631        IPV6_STR
632        "IPv6 next-hop address\n"
633        "IPv6 local address\n"
634        "IPv6 address of next hop\n")
635
636 DEFUN (set_tag,
637        set_tag_cmd,
638        "set tag <1-4294967295>",
639        SET_STR
640        "Tag value for routing protocol\n"
641        "Tag value\n")
642 {
643   return ripng_route_set_add (vty, vty->index, "tag", argv[0]);
644 }
645
646 DEFUN (no_set_tag,
647        no_set_tag_cmd,
648        "no set tag",
649        NO_STR
650        SET_STR
651        "Tag value for routing protocol\n")
652 {
653   if (argc == 0)
654     return ripng_route_set_delete (vty, vty->index, "tag", NULL);
655
656   return ripng_route_set_delete (vty, vty->index, "tag", argv[0]);
657 }
658
659 ALIAS (no_set_tag,
660        no_set_tag_val_cmd,
661        "no set tag <1-4294967295>",
662        NO_STR
663        SET_STR
664        "Tag value for routing protocol\n"
665        "Tag value\n")
666
667 void
668 ripng_route_map_reset ()
669 {
670   /* XXX ??? */
671   ;
672 }
673
674 void
675 ripng_route_map_init ()
676 {
677   route_map_init ();
678   route_map_init_vty ();
679
680   route_map_install_match (&route_match_metric_cmd);
681   route_map_install_match (&route_match_interface_cmd);
682   route_map_install_match (&route_match_tag_cmd);
683
684   route_map_install_set (&route_set_metric_cmd);
685   route_map_install_set (&route_set_ipv6_nexthop_local_cmd);
686   route_map_install_set (&route_set_tag_cmd);
687
688   install_element (RMAP_NODE, &match_metric_cmd);
689   install_element (RMAP_NODE, &no_match_metric_cmd);
690   install_element (RMAP_NODE, &no_match_metric_val_cmd);
691   install_element (RMAP_NODE, &match_interface_cmd);
692   install_element (RMAP_NODE, &no_match_interface_cmd);
693   install_element (RMAP_NODE, &no_match_interface_val_cmd);
694   install_element (RMAP_NODE, &match_tag_cmd);
695   install_element (RMAP_NODE, &no_match_tag_cmd);
696   install_element (RMAP_NODE, &no_match_tag_val_cmd);
697
698   install_element (RMAP_NODE, &set_metric_cmd);
699   install_element (RMAP_NODE, &no_set_metric_cmd);
700   install_element (RMAP_NODE, &no_set_metric_val_cmd);
701   install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd);
702   install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
703   install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd);
704   install_element (RMAP_NODE, &set_tag_cmd);
705   install_element (RMAP_NODE, &no_set_tag_cmd);
706   install_element (RMAP_NODE, &no_set_tag_val_cmd);
707 }