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
33struct 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
46static int
47ripng_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, "Can't find rule.%s", VTY_NEWLINE);
59	  return CMD_WARNING;
60	case RMAP_COMPILE_ERROR:
61	  vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
62	  return CMD_WARNING;
63	}
64    }
65  return CMD_SUCCESS;
66}
67
68static int
69ripng_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, "Can't find rule.%s", VTY_NEWLINE);
81	  return CMD_WARNING;
82	case RMAP_COMPILE_ERROR:
83	  vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
84	  return CMD_WARNING;
85	}
86    }
87  return CMD_SUCCESS;
88}
89
90static int
91ripng_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, "Can't find rule.%s", VTY_NEWLINE);
103	  return CMD_WARNING;
104	case RMAP_COMPILE_ERROR:
105	  vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
106	  return CMD_WARNING;
107	}
108    }
109  return CMD_SUCCESS;
110}
111
112static int
113ripng_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, "Can't find rule.%s", VTY_NEWLINE);
125	  return CMD_WARNING;
126	case RMAP_COMPILE_ERROR:
127	  vty_out (vty, "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. */
136static route_map_result_t
137route_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 */
157static void *
158route_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. */
173static void
174route_match_metric_free (void *rule)
175{
176  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
177}
178
179/* Route map commands for metric matching. */
180static 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. */
190static route_map_result_t
191route_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 */
217static void *
218route_match_interface_compile (const char *arg)
219{
220  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
221}
222
223static void
224route_match_interface_free (void *rule)
225{
226  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
227}
228
229static 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. */
239static route_map_result_t
240route_match_tag (void *rule, struct prefix *prefix,
241		    route_map_object_t type, void *object)
242{
243  u_short *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/* Route map `match tag' match statement. `arg' is TAG value */
261static void *
262route_match_tag_compile (const char *arg)
263{
264  u_short *tag;
265
266  tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
267  *tag = atoi (arg);
268
269  return tag;
270}
271
272/* Free route map's compiled `match tag' value. */
273static void
274route_match_tag_free (void *rule)
275{
276  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
277}
278
279/* Route map commands for tag matching. */
280static struct route_map_rule_cmd route_match_tag_cmd =
281{
282  "tag",
283  route_match_tag,
284  route_match_tag_compile,
285  route_match_tag_free
286};
287
288/* `set metric METRIC' */
289
290/* Set metric to attribute. */
291static route_map_result_t
292route_set_metric (void *rule, struct prefix *prefix,
293		  route_map_object_t type, void *object)
294{
295  if (type == RMAP_RIPNG)
296    {
297      struct rip_metric_modifier *mod;
298      struct ripng_info *rinfo;
299
300      mod = rule;
301      rinfo = object;
302
303      if (mod->type == metric_increment)
304	rinfo->metric_out += mod->metric;
305      else if (mod->type == metric_decrement)
306	rinfo->metric_out-= mod->metric;
307      else if (mod->type == metric_absolute)
308	rinfo->metric_out = mod->metric;
309
310      if (rinfo->metric_out < 1)
311	rinfo->metric_out = 1;
312      if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
313	rinfo->metric_out = RIPNG_METRIC_INFINITY;
314
315      rinfo->metric_set = 1;
316    }
317  return RMAP_OKAY;
318}
319
320/* set metric compilation. */
321static void *
322route_set_metric_compile (const char *arg)
323{
324  int len;
325  const char *pnt;
326  int type;
327  long metric;
328  char *endptr = NULL;
329  struct rip_metric_modifier *mod;
330
331  len = strlen (arg);
332  pnt = arg;
333
334  if (len == 0)
335    return NULL;
336
337  /* Examine first character. */
338  if (arg[0] == '+')
339    {
340      type = metric_increment;
341      pnt++;
342    }
343  else if (arg[0] == '-')
344    {
345      type = metric_decrement;
346      pnt++;
347    }
348  else
349    type = metric_absolute;
350
351  /* Check beginning with digit string. */
352  if (*pnt < '0' || *pnt > '9')
353    return NULL;
354
355  /* Convert string to integer. */
356  metric = strtol (pnt, &endptr, 10);
357
358  if (metric == LONG_MAX || *endptr != '\0')
359    return NULL;
360  /* Commented out by Hasso Tepper, to avoid problems in vtysh. */
361  /* if (metric < 0 || metric > RIPNG_METRIC_INFINITY) */
362  if (metric < 0)
363    return NULL;
364
365  mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED,
366		 sizeof (struct rip_metric_modifier));
367  mod->type = type;
368  mod->metric = metric;
369
370  return mod;
371}
372
373/* Free route map's compiled `set metric' value. */
374static void
375route_set_metric_free (void *rule)
376{
377  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
378}
379
380static struct route_map_rule_cmd route_set_metric_cmd =
381{
382  "metric",
383  route_set_metric,
384  route_set_metric_compile,
385  route_set_metric_free,
386};
387
388/* `set ipv6 next-hop local IP_ADDRESS' */
389
390/* Set nexthop to object.  ojbect must be pointer to struct attr. */
391static route_map_result_t
392route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix,
393		      route_map_object_t type, void *object)
394{
395  struct in6_addr *address;
396  struct ripng_info *rinfo;
397
398  if(type == RMAP_RIPNG)
399    {
400      /* Fetch routemap's rule information. */
401      address = rule;
402      rinfo = object;
403
404      /* Set next hop value. */
405      rinfo->nexthop_out = *address;
406    }
407
408  return RMAP_OKAY;
409}
410
411/* Route map `ipv6 nexthop local' compile function.  Given string is converted
412   to struct in6_addr structure. */
413static void *
414route_set_ipv6_nexthop_local_compile (const char *arg)
415{
416  int ret;
417  struct in6_addr *address;
418
419  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr));
420
421  ret = inet_pton (AF_INET6, arg, address);
422
423  if (ret == 0)
424    {
425      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
426      return NULL;
427    }
428
429  return address;
430}
431
432/* Free route map's compiled `ipv6 nexthop local' value. */
433static void
434route_set_ipv6_nexthop_local_free (void *rule)
435{
436  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
437}
438
439/* Route map commands for ipv6 nexthop local set. */
440static struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd =
441{
442  "ipv6 next-hop local",
443  route_set_ipv6_nexthop_local,
444  route_set_ipv6_nexthop_local_compile,
445  route_set_ipv6_nexthop_local_free
446};
447
448/* `set tag TAG' */
449
450/* Set tag to object.  ojbect must be pointer to struct attr. */
451static route_map_result_t
452route_set_tag (void *rule, struct prefix *prefix,
453		      route_map_object_t type, void *object)
454{
455  u_short *tag;
456  struct ripng_info *rinfo;
457
458  if(type == RMAP_RIPNG)
459    {
460      /* Fetch routemap's rule information. */
461      tag = rule;
462      rinfo = object;
463
464      /* Set next hop value. */
465      rinfo->tag_out = *tag;
466    }
467
468  return RMAP_OKAY;
469}
470
471/* Route map `tag' compile function.  Given string is converted
472   to u_short. */
473static void *
474route_set_tag_compile (const char *arg)
475{
476  u_short *tag;
477
478  tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
479  *tag = atoi (arg);
480
481  return tag;
482}
483
484/* Free route map's compiled `ip nexthop' value. */
485static void
486route_set_tag_free (void *rule)
487{
488  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
489}
490
491/* Route map commands for tag set. */
492static struct route_map_rule_cmd route_set_tag_cmd =
493{
494  "tag",
495  route_set_tag,
496  route_set_tag_compile,
497  route_set_tag_free
498};
499
500#define MATCH_STR "Match values from routing table\n"
501#define SET_STR "Set values in destination routing protocol\n"
502
503DEFUN (match_metric,
504       match_metric_cmd,
505       "match metric <0-4294967295>",
506       MATCH_STR
507       "Match metric of route\n"
508       "Metric value\n")
509{
510  return ripng_route_match_add (vty, vty->index, "metric", argv[0]);
511}
512
513DEFUN (no_match_metric,
514       no_match_metric_cmd,
515       "no match metric",
516       NO_STR
517       MATCH_STR
518       "Match metric of route\n")
519{
520  if (argc == 0)
521    return ripng_route_match_delete (vty, vty->index, "metric", NULL);
522
523  return ripng_route_match_delete (vty, vty->index, "metric", argv[0]);
524}
525
526ALIAS (no_match_metric,
527       no_match_metric_val_cmd,
528       "no match metric <0-4294967295>",
529       NO_STR
530       MATCH_STR
531       "Match metric of route\n"
532       "Metric value\n")
533
534DEFUN (match_interface,
535       match_interface_cmd,
536       "match interface WORD",
537       MATCH_STR
538       "Match first hop interface of route\n"
539       "Interface name\n")
540{
541  return ripng_route_match_add (vty, vty->index, "interface", argv[0]);
542}
543
544DEFUN (no_match_interface,
545       no_match_interface_cmd,
546       "no match interface",
547       NO_STR
548       MATCH_STR
549       "Match first hop interface of route\n")
550{
551  if (argc == 0)
552    return ripng_route_match_delete (vty, vty->index, "interface", NULL);
553
554  return ripng_route_match_delete (vty, vty->index, "interface", argv[0]);
555}
556
557ALIAS (no_match_interface,
558       no_match_interface_val_cmd,
559       "no match interface WORD",
560       NO_STR
561       MATCH_STR
562       "Match first hop interface of route\n"
563       "Interface name\n")
564
565DEFUN (match_tag,
566       match_tag_cmd,
567       "match tag <0-65535>",
568       MATCH_STR
569       "Match tag of route\n"
570       "Metric value\n")
571{
572  return ripng_route_match_add (vty, vty->index, "tag", argv[0]);
573}
574
575DEFUN (no_match_tag,
576       no_match_tag_cmd,
577       "no match tag",
578       NO_STR
579       MATCH_STR
580       "Match tag of route\n")
581{
582  if (argc == 0)
583    return ripng_route_match_delete (vty, vty->index, "tag", NULL);
584
585  return ripng_route_match_delete (vty, vty->index, "tag", argv[0]);
586}
587
588ALIAS (no_match_tag,
589       no_match_tag_val_cmd,
590       "no match tag <0-65535>",
591       NO_STR
592       MATCH_STR
593       "Match tag of route\n"
594       "Metric value\n")
595
596/* set functions */
597
598DEFUN (set_metric,
599       set_metric_cmd,
600       "set metric <0-4294967295>",
601       "Set value\n"
602       "Metric value for destination routing protocol\n"
603       "Metric value\n")
604{
605  return ripng_route_set_add (vty, vty->index, "metric", argv[0]);
606}
607
608DEFUN (no_set_metric,
609       no_set_metric_cmd,
610       "no set metric",
611       NO_STR
612       SET_STR
613       "Metric value for destination routing protocol\n")
614{
615  if (argc == 0)
616    return ripng_route_set_delete (vty, vty->index, "metric", NULL);
617
618  return ripng_route_set_delete (vty, vty->index, "metric", argv[0]);
619}
620
621ALIAS (no_set_metric,
622       no_set_metric_val_cmd,
623       "no set metric <0-4294967295>",
624       NO_STR
625       SET_STR
626       "Metric value for destination routing protocol\n"
627       "Metric value\n")
628
629DEFUN (set_ipv6_nexthop_local,
630       set_ipv6_nexthop_local_cmd,
631       "set ipv6 next-hop local X:X::X:X",
632       SET_STR
633       IPV6_STR
634       "IPv6 next-hop address\n"
635       "IPv6 local address\n"
636       "IPv6 address of next hop\n")
637{
638  union sockunion su;
639  int ret;
640
641  ret = str2sockunion (argv[0], &su);
642  if (ret < 0)
643    {
644      vty_out (vty, "%% Malformed next-hop local address%s", VTY_NEWLINE);
645      return CMD_WARNING;
646    }
647
648  return ripng_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]);
649}
650
651DEFUN (no_set_ipv6_nexthop_local,
652       no_set_ipv6_nexthop_local_cmd,
653       "no set ipv6 next-hop local",
654       NO_STR
655       SET_STR
656       IPV6_STR
657       "IPv6 next-hop address\n"
658       "IPv6 local address\n")
659{
660  if (argc == 0)
661    return ripng_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL);
662
663  return ripng_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]);
664}
665
666ALIAS (no_set_ipv6_nexthop_local,
667       no_set_ipv6_nexthop_local_val_cmd,
668       "no set ipv6 next-hop local X:X::X:X",
669       NO_STR
670       SET_STR
671       IPV6_STR
672       "IPv6 next-hop address\n"
673       "IPv6 local address\n"
674       "IPv6 address of next hop\n")
675
676DEFUN (set_tag,
677       set_tag_cmd,
678       "set tag <0-65535>",
679       SET_STR
680       "Tag value for routing protocol\n"
681       "Tag value\n")
682{
683  return ripng_route_set_add (vty, vty->index, "tag", argv[0]);
684}
685
686DEFUN (no_set_tag,
687       no_set_tag_cmd,
688       "no set tag",
689       NO_STR
690       SET_STR
691       "Tag value for routing protocol\n")
692{
693  if (argc == 0)
694    return ripng_route_set_delete (vty, vty->index, "tag", NULL);
695
696  return ripng_route_set_delete (vty, vty->index, "tag", argv[0]);
697}
698
699ALIAS (no_set_tag,
700       no_set_tag_val_cmd,
701       "no set tag <0-65535>",
702       NO_STR
703       SET_STR
704       "Tag value for routing protocol\n"
705       "Tag value\n")
706
707void
708ripng_route_map_reset ()
709{
710  /* XXX ??? */
711  ;
712}
713
714void
715ripng_route_map_init ()
716{
717  route_map_init ();
718  route_map_init_vty ();
719
720  route_map_install_match (&route_match_metric_cmd);
721  route_map_install_match (&route_match_interface_cmd);
722  route_map_install_match (&route_match_tag_cmd);
723
724  route_map_install_set (&route_set_metric_cmd);
725  route_map_install_set (&route_set_ipv6_nexthop_local_cmd);
726  route_map_install_set (&route_set_tag_cmd);
727
728  install_element (RMAP_NODE, &match_metric_cmd);
729  install_element (RMAP_NODE, &no_match_metric_cmd);
730  install_element (RMAP_NODE, &no_match_metric_val_cmd);
731  install_element (RMAP_NODE, &match_interface_cmd);
732  install_element (RMAP_NODE, &no_match_interface_cmd);
733  install_element (RMAP_NODE, &no_match_interface_val_cmd);
734  install_element (RMAP_NODE, &match_tag_cmd);
735  install_element (RMAP_NODE, &no_match_tag_cmd);
736  install_element (RMAP_NODE, &no_match_tag_val_cmd);
737
738  install_element (RMAP_NODE, &set_metric_cmd);
739  install_element (RMAP_NODE, &no_set_metric_cmd);
740  install_element (RMAP_NODE, &no_set_metric_val_cmd);
741  install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd);
742  install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
743  install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd);
744  install_element (RMAP_NODE, &set_tag_cmd);
745  install_element (RMAP_NODE, &no_set_tag_cmd);
746  install_element (RMAP_NODE, &no_set_tag_val_cmd);
747}
748