Initial revision
diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c
new file mode 100644
index 0000000..f237e6b
--- /dev/null
+++ b/ripngd/ripng_routemap.c
@@ -0,0 +1,342 @@
+/* RIPng routemap.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "memory.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "command.h"
+
+#include "ripngd/ripngd.h"
+
+#if 0
+/* `match interface IFNAME' */
+route_map_result_t
+route_match_interface (void *rule, struct prefix *prefix,
+		       route_map_object_t type, void *object)
+{
+  struct ripng_info *rinfo;
+  struct interface *ifp;
+  char *ifname;
+
+  if (type == ROUTE_MAP_RIPNG)
+    {
+      ifname = rule;
+      ifp = if_lookup_by_name(ifname);
+
+      if (!ifp)
+	return RM_NOMATCH;
+
+      rinfo = object;
+
+      if (rinfo->ifindex == ifp->ifindex)
+	return RM_MATCH;
+      else
+	return RM_NOMATCH;
+    }
+  return RM_NOMATCH;
+}
+
+void *
+route_match_interface_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_interface_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+  "interface",
+  route_match_interface,
+  route_match_interface_compile,
+  route_match_interface_free
+};
+#endif /* 0 */
+
+struct rip_metric_modifier
+{
+  enum 
+  {
+    metric_increment,
+    metric_decrement,
+    metric_absolute
+  } type;
+
+  u_char metric;
+};
+
+route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix, 
+		  route_map_object_t type, void *object)
+{
+  if (type == RMAP_RIPNG)
+    {
+      struct rip_metric_modifier *mod;
+      struct ripng_info *rinfo;
+
+      mod = rule;
+      rinfo = object;
+
+      if (mod->type == metric_increment)
+	rinfo->metric += mod->metric;
+      else if (mod->type == metric_decrement)
+	rinfo->metric -= mod->metric;
+      else if (mod->type == metric_absolute)
+	rinfo->metric = mod->metric;
+
+      if (rinfo->metric < 1)
+	rinfo->metric = 1;
+      if (rinfo->metric > RIPNG_METRIC_INFINITY)
+	rinfo->metric = RIPNG_METRIC_INFINITY;
+
+      rinfo->metric_set = 1;
+    }
+  return RMAP_OKAY;
+}
+
+void *
+route_set_metric_compile (char *arg)
+{
+  int len;
+  char *pnt;
+  int type;
+  long metric;
+  char *endptr = NULL;
+  struct rip_metric_modifier *mod;
+
+  len = strlen (arg);
+  pnt = arg;
+
+  if (len == 0)
+    return NULL;
+
+  /* Examine first character. */
+  if (arg[0] == '+')
+    {
+      type = metric_increment;
+      pnt++;
+    }
+  else if (arg[0] == '-')
+    {
+      type = metric_decrement;
+      pnt++;
+    }
+  else
+    type = metric_absolute;
+
+  /* Check beginning with digit string. */
+  if (*pnt < '0' || *pnt > '9')
+    return NULL;
+
+  /* Convert string to integer. */
+  metric = strtol (pnt, &endptr, 10);
+
+  if (metric == LONG_MAX || *endptr != '\0')
+    return NULL;
+  if (metric < 0 || metric > RIPNG_METRIC_INFINITY)
+    return NULL;
+
+  mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, 
+		 sizeof (struct rip_metric_modifier));
+  mod->type = type;
+  mod->metric = metric;
+
+  return mod;
+}
+
+void
+route_set_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_set_metric_cmd = 
+{
+  "metric",
+  route_set_metric,
+  route_set_metric_compile,
+  route_set_metric_free,
+};
+
+int
+ripng_route_match_add (struct vty *vty, struct route_map_index *index,
+		       char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+	{
+	case RMAP_RULE_MISSING:
+	  vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	case RMAP_COMPILE_ERROR:
+	  vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+int
+ripng_route_match_delete (struct vty *vty, struct route_map_index *index,
+			  char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+	{
+	case RMAP_RULE_MISSING:
+	  vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	case RMAP_COMPILE_ERROR:
+	  vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+int
+ripng_route_set_add (struct vty *vty, struct route_map_index *index,
+		     char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+	{
+	case RMAP_RULE_MISSING:
+	  vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	case RMAP_COMPILE_ERROR:
+	  vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+int
+ripng_route_set_delete (struct vty *vty, struct route_map_index *index,
+			char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+	{
+	case RMAP_RULE_MISSING:
+	  vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	case RMAP_COMPILE_ERROR:
+	  vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+#if 0
+DEFUN (match_interface,
+       match_interface_cmd,
+       "match interface WORD",
+       "Match value\n"
+       "Interface\n"
+       "Interface name\n")
+{
+  return ripng_route_match_add (vty, vty->index, "interface", argv[0]);
+}
+
+DEFUN (no_match_interface,
+       no_match_interface_cmd,
+       "no match interface WORD",
+       NO_STR
+       "Match value\n"
+       "Interface\n"
+       "Interface name\n")
+{
+  return ripng_route_match_delete (vty, vty->index, "interface", argv[0]);
+}
+#endif /* 0 */
+
+DEFUN (set_metric,
+       set_metric_cmd,
+       "set metric <0-4294967295>",
+       "Set value\n"
+       "Metric\n"
+       "METRIC value\n")
+{
+  return ripng_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_set_metric,
+       no_set_metric_cmd,
+       "no set metric <0-4294967295>",
+       NO_STR
+       "Set value\n"
+       "Metric\n"
+       "METRIC value\n")
+{
+  return ripng_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+void
+ripng_route_map_init ()
+{
+  route_map_init ();
+  route_map_init_vty ();
+
+  /* route_map_install_match (&route_match_interface_cmd); */
+  route_map_install_set (&route_set_metric_cmd);
+
+  /*
+  install_element (RMAP_NODE, &match_interface_cmd);
+  install_element (RMAP_NODE, &no_match_interface_cmd);
+  */
+
+  install_element (RMAP_NODE, &set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_cmd);
+}