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
ripng_route_match_add(struct vty * vty,struct route_map_index * index,const char * command,const char * arg)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
ripng_route_match_delete(struct vty * vty,struct route_map_index * index,const char * command,const char * arg)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
ripng_route_set_add(struct vty * vty,struct route_map_index * index,const char * command,const char * arg)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
ripng_route_set_delete(struct vty * vty,struct route_map_index * index,const char * command,const char * arg)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
route_match_metric(void * rule,struct prefix * prefix,route_map_object_t type,void * object)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 *
route_match_metric_compile(const char * arg)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
route_match_metric_free(void * rule)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
route_match_interface(void * rule,struct prefix * prefix,route_map_object_t type,void * object)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 *
route_match_interface_compile(const char * arg)218 route_match_interface_compile (const char *arg)
219 {
220   return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
221 }
222 
223 static void
route_match_interface_free(void * rule)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
route_match_tag(void * rule,struct prefix * prefix,route_map_object_t type,void * object)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
route_set_metric(void * rule,struct prefix * prefix,route_map_object_t type,void * object)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 *
route_set_metric_compile(const char * arg)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
route_set_metric_free(void * rule)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
route_set_ipv6_nexthop_local(void * rule,struct prefix * prefix,route_map_object_t type,void * object)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 *
route_set_ipv6_nexthop_local_compile(const char * arg)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
route_set_ipv6_nexthop_local_free(void * rule)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
route_set_tag(void * rule,struct prefix * prefix,route_map_object_t type,void * object)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
ripng_route_map_reset()668 ripng_route_map_reset ()
669 {
670   /* XXX ??? */
671   ;
672 }
673 
674 void
ripng_route_map_init()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 }
708