ospf6d: implement admin distance

Until today the admin distance cannot be configured for any IPv6
routing protocol. This patch implements it for ospf6.

Signed-off-by: Maitane Zotes <maz@open.ch>
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 7fffba8..1288bc7 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -150,6 +150,8 @@
 
   o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH;
 
+  o->distance_table = route_table_init ();
+
   return o;
 }
 
@@ -176,6 +178,9 @@
   ospf6_route_table_delete (o->external_table);
   route_table_finish (o->external_id_table);
 
+  ospf6_distance_reset (o);
+  route_table_finish (o->distance_table);
+
   XFREE (MTYPE_OSPF6_TOP, o);
 }
 
@@ -401,6 +406,435 @@
   return CMD_SUCCESS;
 }
 
+DEFUN (ospf6_distance,
+       ospf6_distance_cmd,
+       "distance <1-255>",
+       NO_STR
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_all = atoi (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_distance,
+       no_ospf6_distance_cmd,
+       "no distance <1-255>",
+       NO_STR
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_all = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_distance_ospf6,
+       no_ospf6_distance_ospf6_cmd,
+       "no distance ospf6",
+       NO_STR
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "OSPF6 Distance\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_intra = 0;
+  o->distance_inter = 0;
+  o->distance_external = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_intra,
+       ospf6_distance_ospf6_intra_cmd,
+       "distance ospf6 intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_intra = atoi (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_intra_inter,
+       ospf6_distance_ospf6_intra_inter_cmd,
+       "distance ospf6 intra-area <1-255> inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_intra = atoi (argv[0]);
+  o->distance_inter = atoi (argv[1]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_intra_external,
+       ospf6_distance_ospf6_intra_external_cmd,
+       "distance ospf6 intra-area <1-255> external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_intra = atoi (argv[0]);
+  o->distance_external = atoi (argv[1]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_intra_inter_external,
+       ospf6_distance_ospf6_intra_inter_external_cmd,
+       "distance ospf6 intra-area <1-255> inter-area <1-255> external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_intra = atoi (argv[0]);
+  o->distance_inter = atoi (argv[1]);
+  o->distance_external = atoi (argv[2]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_intra_external_inter,
+       ospf6_distance_ospf6_intra_external_inter_cmd,
+       "distance ospf6 intra-area <1-255> external <1-255> inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_intra = atoi (argv[0]);
+  o->distance_external = atoi (argv[1]);
+  o->distance_inter = atoi (argv[2]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_inter,
+       ospf6_distance_ospf6_inter_cmd,
+       "distance ospf6 inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_inter = atoi (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_inter_intra,
+       ospf6_distance_ospf6_inter_intra_cmd,
+       "distance ospf6 inter-area <1-255> intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_inter = atoi (argv[0]);
+  o->distance_intra = atoi (argv[1]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_inter_external,
+       ospf6_distance_ospf6_inter_external_cmd,
+       "distance ospf6 inter-area <1-255> external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_inter = atoi (argv[0]);
+  o->distance_external = atoi (argv[1]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_inter_intra_external,
+       ospf6_distance_ospf6_inter_intra_external_cmd,
+       "distance ospf6 inter-area <1-255> intra-area <1-255> external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_inter = atoi (argv[0]);
+  o->distance_intra = atoi (argv[1]);
+  o->distance_external = atoi (argv[2]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_inter_external_intra,
+       ospf6_distance_ospf6_inter_external_intra_cmd,
+       "distance ospf6 inter-area <1-255> external <1-255> intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_inter = atoi (argv[0]);
+  o->distance_external = atoi (argv[1]);
+  o->distance_intra = atoi (argv[2]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_external,
+       ospf6_distance_ospf6_external_cmd,
+       "distance ospf6 external <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_external = atoi (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_external_intra,
+       ospf6_distance_ospf6_external_intra_cmd,
+       "distance ospf6 external <1-255> intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_external = atoi (argv[0]);
+  o->distance_intra = atoi (argv[1]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_external_inter,
+       ospf6_distance_ospf6_external_inter_cmd,
+       "distance ospf6 external <1-255> inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_external = atoi (argv[0]);
+  o->distance_inter = atoi (argv[1]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_external_intra_inter,
+       ospf6_distance_ospf6_external_intra_inter_cmd,
+       "distance ospf6 external <1-255> intra-area <1-255> inter-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_external = atoi (argv[0]);
+  o->distance_intra = atoi (argv[1]);
+  o->distance_inter = atoi (argv[2]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_ospf6_external_inter_intra,
+       ospf6_distance_ospf6_external_inter_intra_cmd,
+       "distance ospf6 external <1-255> inter-area <1-255> intra-area <1-255>",
+       "Define an administrative distance\n"
+       "OSPF6 Administrative distance\n"
+       "External routes\n"
+       "Distance for external routes\n"
+       "Inter-area routes\n"
+       "Distance for inter-area routes\n"
+       "Intra-area routes\n"
+       "Distance for intra-area routes\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  o->distance_external = atoi (argv[0]);
+  o->distance_inter = atoi (argv[1]);
+  o->distance_intra = atoi (argv[2]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_source,
+       ospf6_distance_source_cmd,
+       "distance <1-255> X:X::X:X/M",
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  ospf6_distance_set (vty, o, argv[0], argv[1], NULL);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_distance_source,
+       no_ospf6_distance_source_cmd,
+       "no distance <1-255> X:X::X:X/M",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+  
+  /* XXX: distance arg seems to be irrelevant */
+  ospf6_distance_unset (vty, o, argv[1], NULL);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_distance_source_access_list,
+       ospf6_distance_source_access_list_cmd,
+       "distance <1-255> X:X::X:X/M WORD",
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  ospf6_distance_set (vty, o, argv[0], argv[1], argv[2]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_distance_source_access_list,
+       no_ospf6_distance_source_access_list_cmd,
+       "no distance <1-255> X:X::X:X/M WORD",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  ospf6_distance_unset (vty, o, argv[1], argv[2]);
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (ospf6_interface_area,
        ospf6_interface_area_cmd,
        "interface IFNAME area A.B.C.D",
@@ -864,6 +1298,43 @@
     return;
 }
 
+static int
+ospf6_distance_config_write (struct vty *vty)
+{
+  struct route_node *rn;
+  struct ospf6_distance *odistance;
+
+  if (ospf6->distance_all)
+    vty_out (vty, " distance %d%s", ospf6->distance_all, VTY_NEWLINE);
+
+  if (ospf6->distance_intra
+      || ospf6->distance_inter
+      || ospf6->distance_external)
+    {
+      vty_out (vty, " distance ospf6");
+
+      if (ospf6->distance_intra)
+        vty_out (vty, " intra-area %d", ospf6->distance_intra);
+      if (ospf6->distance_inter)
+        vty_out (vty, " inter-area %d", ospf6->distance_inter);
+      if (ospf6->distance_external)
+        vty_out (vty, " external %d", ospf6->distance_external);
+
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+
+  for (rn = route_top (ospf6->distance_table); rn; rn = route_next (rn))
+    if ((odistance = rn->info) != NULL)
+      {
+        char pstr[128];
+        vty_out (vty, " distance %d %s %s%s", odistance->distance,
+                 prefix2str (&rn->p, pstr, sizeof(pstr)),
+                 odistance->access_list ? odistance->access_list : "",
+                 VTY_NEWLINE);
+      }
+  return 0;
+}
+
 /* OSPF configuration write function. */
 static int
 config_write_ospf6 (struct vty *vty)
@@ -899,6 +1370,7 @@
   ospf6_redistribute_config_write (vty);
   ospf6_area_config_write (vty);
   ospf6_spf_config_write (vty);
+  ospf6_distance_config_write (vty);
 
   for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, j, oa))
     {
@@ -963,6 +1435,30 @@
   install_element (OSPF6_NODE, &ospf6_stub_router_shutdown_cmd);
   install_element (OSPF6_NODE, &no_ospf6_stub_router_shutdown_cmd);
   */
+
+  install_element (OSPF6_NODE, &ospf6_distance_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_distance_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_distance_ospf6_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_inter_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_external_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_inter_external_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_external_inter_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_intra_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_external_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_intra_external_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_external_intra_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_intra_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_inter_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_intra_inter_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_inter_intra_cmd);
+
+  install_element (OSPF6_NODE, &ospf6_distance_source_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_distance_source_cmd);
+  install_element (OSPF6_NODE, &ospf6_distance_source_access_list_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_distance_source_access_list_cmd);
 }